diff --git a/DESCRIPTION b/DESCRIPTION index b9f168a4f..8a029bfc8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: duckdb Title: DBI Package for the DuckDB Database Management System -Version: 1.1.3.9039 +Version: 1.1.3-2 Authors@R: c( person("Hannes", "Mühleisen", , "hannes@cwi.nl", role = "aut", comment = c(ORCID = "0000-0001-8552-0029")), diff --git a/NEWS.md b/NEWS.md index 2ee59f528..50512804f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,149 +1,7 @@ -# duckdb 1.1.3.9039 -## Chore - -- Move internal `duckdb.tar` dependency (#1013). - - -# duckdb 1.1.3.9038 - -## vendor - -- Update vendored sources to duckdb/duckdb@a1c7e9b115788c7cae8e99d946598c49eecec6f9 (#1007). - -- Update vendored sources to duckdb/duckdb@bec4a7b985b030c41f37a57c93a2fdd394ba0212 (#1006). - -- Update vendored sources to duckdb/duckdb@c4d8ab37c430aea372ea08e45e5fead447dfb8fe (#1005). - - -# duckdb 1.1.3.9037 - -## vendor - -- Update vendored sources to duckdb/duckdb@cb8ecb6b96f89790f6ab835084d86e828a1b91b5 (#1003). - -- Update vendored sources to duckdb/duckdb@f8e95f0d66d2dd466d1d2c3a079f5d8c63ac5f21 (#1002). - -- Update vendored sources to duckdb/duckdb@af82bd7158e78256a5f2d7ae37cebb3bfd39f852 (#1001). - -- Update vendored sources to duckdb/duckdb@8dc08b1da039ceb38618a59f2128e5e22d2fb0ac (#1000). - - -# duckdb 1.1.3.9036 - -## vendor - -- Update vendored sources to duckdb/duckdb@d707b4432b74b51f8a176c533b98e24d48f4d165 (#998). - -- Update vendored sources to duckdb/duckdb@d3444ef1413102e5c8246a066b201c59ac5c4c04 (#997). - -- Update vendored sources to duckdb/duckdb@2c203c13b52f8d6073f5e03f3226eaadf0973654 (#996). - -- Update vendored sources to duckdb/duckdb@acea8cde22f802b792adc8cfdeea335103edc5fe (#994). - -- Update vendored sources to duckdb/duckdb@f850786ddef96177354ca8183280bc0de62a66c0 (#992). - -- Update vendored sources to duckdb/duckdb@00cbb18d634352d1ae0cdf4dd42d587d187f5a04 (#991). - -- Update vendored sources to duckdb/duckdb@bdf0f8c7231c44ed17bc2ede63498b3ef8d85d35 (#990). - -- Update vendored sources to duckdb/duckdb@5ec2adafa54af246814bd869bb6f48073a2f660b (#989). - -- Update vendored sources to duckdb/duckdb@b89f77c881fcdb8018bf3562c6de00b9e9849451 (#988). - -- Update vendored sources to duckdb/duckdb@b5393f7d0f8234028f9719889d33178ef793279f (#987). - -- Update vendored sources to duckdb/duckdb@b48222edb439e42517392eaa2e918b625cafd09a (#986). - -- Update vendored sources to duckdb/duckdb@c93ab6e8171b6cba652439cadc91e79d488ffd01 (#985). - -- Update vendored sources to duckdb/duckdb@3b44a57608458b063303d3576b2e21b6f1908a76 (#984). - -- Update vendored sources to duckdb/duckdb@fbc4d92fe6239536948a49d093196534c3492656 (#983). - - -# duckdb 1.1.3.9035 - -## vendor - -- Update vendored sources to duckdb/duckdb@dcb9627543af52e4322de464003259a6b0e7fdb4 (#980). - -- Update vendored sources to duckdb/duckdb@69dff93d1a956c68eb9dc603d24d06719e57749d (#979). - -- Update vendored sources to duckdb/duckdb@ce33de966a521d1a6e86ec9579e133ff2b2534f4 (#978). - -- Update vendored sources to duckdb/duckdb@c8fa9aee7858909c625b5c3abcc3a257c5d9d934 (#977). - - -# duckdb 1.1.3.9034 - -## vendor - -- Update vendored sources to duckdb/duckdb@acdbf60889033d2701a5fef360a19963cafea471 (#974). - -- Update vendored sources to duckdb/duckdb@2edfde3071cdc3ccc6047773e8229fb80238443d (#973). - -- Update vendored sources to duckdb/duckdb@3c0db29b2bf182105c1537ddf2fa8b12d186941d (#972). - -- Update vendored sources to duckdb/duckdb@5705d13dbf1d4f3db3e4f36d3194f669aaf99bc0 (#971). - -- Update vendored sources to duckdb/duckdb@41d13ad1612b3e91ff7a9a5c17edd6fdf51073f1 (#970). - -- Update vendored sources to duckdb/duckdb@52032a5b00d4f11376f4ba106753629aea87c0a8 (#969). - -- Update vendored sources to duckdb/duckdb@add512094d022fec50354208f908c3d60f3755a5 (#968). - -- Update vendored sources to duckdb/duckdb@d42c34cbd62061e5088fc1b81ced0c1008fa58ea (#967). - -- Update vendored sources to duckdb/duckdb@35bf611cc4832ceb2f20ec70a2597d0765618610 (duckdb/duckdb#15526, #966). - -- Update vendored sources to duckdb/duckdb@22de1ef5310136803f2caab0c9cc063b4fad52e5 (#965). - -- Update vendored sources to duckdb/duckdb@a3636bdd6203f4e4c47c5191264b9209e4f2a516 (#964). - -- Update vendored sources to duckdb/duckdb@50de06cec8de9c8da1b6fd9fcec3f514694a9b6a (#963). - -- Update vendored sources to duckdb/duckdb@4b163ff7c8cb9693fafe4d822dff54b31cfd2adf (#962). - - -# duckdb 1.1.3.9033 - -## vendor - -- Update vendored sources to duckdb/duckdb@adc6f607a71b87da2d0a7550e90db623e9bea637 (#959). - -- Update vendored sources to duckdb/duckdb@13ba13c121acfb3f4c48c16337297ac705779c19 (#958). - -- Update vendored sources to duckdb/duckdb@45462bcffd761b7d797cc1ab660930be62c110cb (#957). - -- Update vendored sources to duckdb/duckdb@a0a828b712f538a64263dad251d20a5f91f83a80 (#956). - -- Update vendored sources to duckdb/duckdb@2082b55f89fe6e810f982c57dceecbee5ecd40fa (#955). - -- Update vendored sources to duckdb/duckdb@7ee114cea8a43d9cdd0f0442cbde05c63a65a9c3 (#954). - - -# duckdb 1.1.3.9032 - -## vendor - -- Update vendored sources to duckdb/duckdb@4488c61ee780635e67abe1b6164f2cdfadc21b65 (#947). - - -# duckdb 1.1.3.9031 - -## vendor - -- Update vendored sources to duckdb/duckdb@8869b59d17a0b0a40544f0ef9a8e129a51c6bcc1 (#944). - -- Update vendored sources to duckdb/duckdb@61d1e92f27f99ea2142218d0ac4c0dc158622024 (#943). - -- Update vendored sources to duckdb/duckdb@f4bde059af5bec613a2f44d82ea354605e1000ef (#942). - - -# duckdb 1.1.3.9030 +# duckdb 1.1.3-2 ## Bug fixes @@ -153,651 +11,17 @@ - Sync vendoring script with igraph (#936). -## vendor - -- Update vendored sources to duckdb/duckdb@6c4d2a394ff166af23cfd9be499d96f2b1bfb0de (#939). - -- Update vendored sources to duckdb/duckdb@cd286cb51c16c55320143f8fbe6ad4f058bc09c9 (#938). - -- Update vendored sources to duckdb/duckdb@13ff921d7c4c5947dd69eaa6191c3cedad5672b8 (#937). - -- Update vendored sources to duckdb/duckdb@e1db888231f0cbe856d75ee8db6e677a2e19dd4a (#935). - -- Update vendored sources to duckdb/duckdb@b7a133935512bbcba9f98b83ab4a6238a7b776c5 (#934). - -- Update vendored sources to duckdb/duckdb@44074848caa1b2e98850a5e1d4a45295d008861e (#933). - -- Update vendored sources to duckdb/duckdb@8d3319e35abd834a51809422c5253b88c7ad8ce1 (#932). - -- Update vendored sources to duckdb/duckdb@701a39ebc2dacf80249ae3df069bac56e3fb0ba6 (#931). - -- Update vendored sources to duckdb/duckdb@d29c199646ec52f3e84fec4d0058b3aecb3a2156 (#930). - -- Update vendored sources to duckdb/duckdb@21e6acf2669ad56b1809353da2c9ac8e35adffd2 (#929). - -- Update vendored sources to duckdb/duckdb@30c80bb3111b2ac8db37d31d71e971d47768987c (#928). - -- Update vendored sources to duckdb/duckdb@ad6b3f4c4966b0fc0831cbf624847761d8ffee62 (#927). - -- Update vendored sources to duckdb/duckdb@987ea2c40964013cac5e32e47519d7f5ca00148f (#926). - -- Update vendored sources to duckdb/duckdb@342f13856f9b54492597cd25a51a35d29b3a655c (#925). - -- Update vendored sources to duckdb/duckdb@26f483b873b967cc875935cda7c58a9bccbc359e (#924). - - -# duckdb 1.1.3.9029 - -## Bug fixes - -- Argument order. - -## Chore - -- `rethrow_()` variants. - -## vendor - -- Update vendored sources to duckdb/duckdb@ec7be6f00e0dd7fa02d272f126c32aedbff13bb3 (#920). - -- Update vendored sources to duckdb/duckdb@eecb1b42dc481cc8b636ec4168f912ad125c67b8 (#919). - -- Update vendored sources to duckdb/duckdb@e7765f25f1345597e4d0509a0f0248680f68da20 (#918). - -- Update vendored sources to duckdb/duckdb@1eb2cbcc60de4b62661fa9a05c71b17a7d19007b (#917). - -- Update vendored sources to duckdb/duckdb@7b37d47595489f987d695318a8a13bda33a98a05 (#916). - -- Update vendored sources to duckdb/duckdb@1d0c6139f4428fea7ce149e01939f05bcc4e9c31 (#915). - -- Update vendored sources to duckdb/duckdb@8ae1c68392b5a9575e869f57e4c5be81cb3d2210 (#914). - -- Update vendored sources to duckdb/duckdb@093e3323a73554ef121563792e1b2bd08ec6d3f1 (#913). - -- Update vendored sources to duckdb/duckdb@f1cdeed59925bdac8583de0b465dd3319210e333 (#912). - -- Update vendored sources to duckdb/duckdb@9743d9b61657ae0c52ab54ff6c25b49061fd7aa7 (#911). - -- Update vendored sources to duckdb/duckdb@996e8561f5d779c9fe70d71ebb1520dd815321ee (#910). - -- Update vendored sources to duckdb/duckdb@28b421576fb61aa52a7fb60eca37069c1a86acdf (#909). - -- Update vendored sources to duckdb/duckdb@022df4e87e5d3175bfa8cc311e7fa04d2c4371b7 (#908). - -- Update vendored sources to duckdb/duckdb@ed66708578b4ab6b123d3480501bb3b6873d73da (#907). - -- Update vendored sources to duckdb/duckdb@a04385ab02effd78ba3479b176f6f6faa01d6bc0 (#906). - -- Update vendored sources to duckdb/duckdb@14d0a4ca86af5298acec055ab9e4704a09fd19b9 (#905). - -- Update vendored sources to duckdb/duckdb@6396c42f36da123507d891b9768d919ae9c04968 (#904). - -- Update vendored sources to duckdb/duckdb@ab8c90985741ac68cd203c8396022894c1771d4b (#903). - -- Update vendored sources to duckdb/duckdb@e4e50f923c3f5463a31dad5ea31ee30204adaf67 (#902). - -- Update vendored sources to duckdb/duckdb@70d238a7a922d0321564a5acfc3747782c42c4a4 (#901). - -- Update vendored sources to duckdb/duckdb@dd3f65170bc3fbff7bc3c80e179c6e1f69c634fe (#900). - -- Update vendored sources to duckdb/duckdb@f9c7a7c2665ce0a601239863e0bdd6c9a18c9910 (#899). - -- Update vendored sources to duckdb/duckdb@62582045a39653394b2fda409c5e627eecb3ae27 (#898). - -- Update vendored sources to duckdb/duckdb@623178d601aa52ea9789d4f3b054ee6f194fc5fe (#897). - -- Update vendored sources to duckdb/duckdb@ff92dbe95021d1cd7331406662c63b07c420868f (#896). - -- Update vendored sources to duckdb/duckdb@7014b6aaf50b6ffd4f2e656d1a306475d2b21cb8 (#895). - -- Update vendored sources to duckdb/duckdb@3613371116ce1f43eeed6844aa3bc1bb556cb188 (#894). - -- Update vendored sources to duckdb/duckdb@7db48386fd12d8c17854cfc27a3e22545cccfd8c (#893). - -- Update vendored sources to duckdb/duckdb@7f6d8046d5406f6d7272a4d205872bf197b61206 (#892). - -- Update vendored sources to duckdb/duckdb@a98cd9e1a990eacce51d8b8e627a5e7bccda385a (#891). - -- Update vendored sources to duckdb/duckdb@cc4026a110638b97a9f262a25a9a94f14cf8dc93 (#890). - -- Update vendored sources to duckdb/duckdb@2e56c23ab24770e381f116fdfcb53612eb9137f8 (#889). - -- Update vendored sources to duckdb/duckdb@abef2d9c8e2a083b1295d1f20ae6f1a45c3582e5 (#888). - -- Update vendored sources to duckdb/duckdb@815f2f58e5c8c5ed8d380b378219f13e3cb604de (#887). - -- Update vendored sources to duckdb/duckdb@48c9f5e79676d93f0e2bf64197521cd8bc6b2e89 (#886). - -- Update vendored sources to duckdb/duckdb@4033d156b414f853f2309592652068c51228ff1f (#885). - -- Update vendored sources to duckdb/duckdb@965963f881e152bd80cb34fd5a7ebd0f66639e55 (#884). - -- Update vendored sources to duckdb/duckdb@79f36e0cffe4e3a803a6a31388c375fc538a718a (#883). - -- Update vendored sources to duckdb/duckdb@373d3370c792f67079ab2bb0c8081732b039b0c7 (#882). - -- Update vendored sources to duckdb/duckdb@6ce195704a8d3af894766af51e0451955e4fc93d (#881). - -- Update vendored sources to duckdb/duckdb@a5d55eaf1506028b5dc9577e8a92bffc10a2ba3d (#880). - -- Update vendored sources to duckdb/duckdb@f1ccf047d11477e704cfc5dd6b44065dba073f57 (#878). - - -# duckdb 1.1.3.9028 - ## Features - New internal `rapi_rel_to_csv()`,`rapi_rel_to_table()`, and `rapi_rel_insert()`; `rapi_rel_to_parquet()` gains `options` argument (#867). -## vendor - -- Update vendored sources to duckdb/duckdb@abd4759216599b454d89b0d13d3b476eb67df3e1 (#877). - -- Update vendored sources to duckdb/duckdb@d9965a511aa15178af155a4ef8581198e067570b (#876). - -- Update vendored sources to duckdb/duckdb@5302c13337dcd6d87c375e89ab66a28e31862ead (#875). - -- Update vendored sources to duckdb/duckdb@5370afc08e09c953218f6ce65298f93e95ed2952 (#874). - -- Update vendored sources to duckdb/duckdb@7e3dca3b06ab9cc99cf205fa1ae8003841631f81 (#873). - -- Update vendored sources to duckdb/duckdb@4f3a7d585d57f1c17cd261ce0c3c2362cda8b181 (#872). - -- Update vendored sources to duckdb/duckdb@428bff2e564de2cde1e4aa029ce5fe6a041c5749 (#871). - -- Update vendored sources to duckdb/duckdb@80b1684decdae6596877aa1f550f5d7d1c3efbf9 (#870). - -- Update vendored sources to duckdb/duckdb@332c9830b7b0768670b3a7bf35b2fa56f0cbae7b (#869). - -- Update vendored sources to duckdb/duckdb@902331125660f5ead08a870cbd8534572d13536c (#868). - -- Update vendored sources to duckdb/duckdb@a39967c3b67410d165fdede4f12967ff240154c7 (#866). - -- Update vendored sources to duckdb/duckdb@115a8aedcd80706bf776c5993f46e95c1a25d91a (#865). - -- Update vendored sources to duckdb/duckdb@c80d58c16ad1ddacb6aa291d0f99be169019c355 (#864). - -- Update vendored sources to duckdb/duckdb@61dc3243083a7bc4eb5110ab67d76f1704f80ce9 (#863). - -- Update vendored sources to duckdb/duckdb@30e05b95fa999d6d7ca8f78692c5ef8bc851f1a1 (#862). - -- Update vendored sources to duckdb/duckdb@98981b3a33eade1b0d38433d9c924e308cb56511 (duckdb/duckdb#14938, #861). - -- Update vendored sources to duckdb/duckdb@4835faaa9288a75ebbc36811f7142fbb2dd7ed87 (#860). - -- Update vendored sources to duckdb/duckdb@4ca094fa6370d5bc7893ca156db422082b9a5528 (#859). - -- Update vendored sources to duckdb/duckdb@d27b5c188e3ba73d98bddf81f3a95a26e758e208 (#858). - -- Update vendored sources to duckdb/duckdb@dac040e902b5021b0e8a49c0e5f01873e5ad32b5 (duckdb/duckdb#15183, #857). - -- Update vendored sources to duckdb/duckdb@2bec31833360904590a86c5dc59e3523ad39a257 (#856). - -- Update vendored sources to duckdb/duckdb@eadc6168f73e6f85c47597c84438bb8e769c12ae (#855). - -- Update vendored sources to duckdb/duckdb@b0cca8f83bba978071ecf5c0eed5495443ed05b1 (#854). - -- Update vendored sources to duckdb/duckdb@4a8188effcf664085eedf723996a90dc870a7d7e (#853). - -- Update vendored sources to duckdb/duckdb@a52e92d404cbc3e38b48ea65b36ecc928ad318ee (#852). - -- Update vendored sources to duckdb/duckdb@680a21db3923c14452240e8818741327d1b7d64a (#851). - -- Update vendored sources to duckdb/duckdb@18c85f7b7078418ca6c85477ff5225ecda37e63a (#850). - -- Update vendored sources to duckdb/duckdb@9489881191eba8af452b94120d542c09b3ffd0c1 (duckdb/duckdb#15261, #849). - -- Update vendored sources to duckdb/duckdb@04d8f995da72c57b07aa5fca3c3a11cf65263430 (#848). - -- Update vendored sources to duckdb/duckdb@c828cadfc1c5f8df89f94cdb8eb62aba8fdb5e5e (#847). - -- Update vendored sources to duckdb/duckdb@236524b273f1ebaafb9b938018135b64e64ce02f (duckdb/duckdb#15239, #846). - -- Update vendored sources to duckdb/duckdb@3c6182ea20185e93f788399a80bb3ae6c86528d2 (#845). - -- Update vendored sources to duckdb/duckdb@7e9bd28f0010bb82980e1c6c19a25b757ed4c1d7 (#844). - -- Update vendored sources to duckdb/duckdb@12a0e9048732c37102817209fd36b3f7c2815120 (duckdb/duckdb#15012, #843). - -- Update vendored sources to duckdb/duckdb@8ddb090b56cabfe5afc58b4a93d169399afb6324 (#842). - -- Update vendored sources to duckdb/duckdb@1da0ac1eb7cf0d4ec804be8bdb116c6d288c8326 (#841). - -- Update vendored sources to duckdb/duckdb@76ba54844a2b66c2c2457723f60b073bc57db19f (#840). - -- Update vendored sources to duckdb/duckdb@b50ff2aecfb5862c99cccd07a19f6d68c741b5d0 (#839). - -- Update vendored sources to duckdb/duckdb@7ce73e9db7a7f05ae871342751c5621a7ea325af (duckdb/duckdb#15051, #838). - -- Update vendored sources to duckdb/duckdb@6eb3eb68b68ff01be3f5affe93fe90dd7a24808d (duckdb/duckdb#15072, #837). - -- Update vendored sources to duckdb/duckdb@bebfb9ddeb96259ce5b53cf23b46bfc6f5c1a342 (#836). - -- Update vendored sources to duckdb/duckdb@7d9c93ba68eef8512b3d8637f34f5bdc18c8f373 (#835). - -- Update vendored sources to duckdb/duckdb@ce587041dcd60b7be22a5c1dd740c1a6c10674d6 (#834). - -- Update vendored sources to duckdb/duckdb@60e97349f4ca4989ed79cc1272d6c08729dcd75b (#833). - -- Update vendored sources to duckdb/duckdb@067ecb1c7f66a4ecaa1b7f9db33432e8ba896960 (#832). - -- Update vendored sources to duckdb/duckdb@86eed65e6f7c07c8adc8d686e4703a573aca9755 (#831). - -- Update vendored sources to duckdb/duckdb@a3a6909f7f99e384ef0fc1c5acc7a5c878192ec6 (#830). - -- Update vendored sources to duckdb/duckdb@3c8c7f67785342f77efbbdaee1f38a7ed2024bef (duckdb/duckdb#15175, #829). - -- Update vendored sources to duckdb/duckdb@c004f8af0feede375cece18d1aabe68bb054fcd8 (duckdb/duckdb#15177, #828). - -- Update vendored sources to duckdb/duckdb@5c1abcf8cc5ef70ac2eb673e2832552f955ad6c8 (duckdb/duckdb#15221, #827). - -- Update vendored sources to duckdb/duckdb@23dc2bc4dc6d34c3a59d29a43d2351d873675098 (#826). - -- Update vendored sources to duckdb/duckdb@8095a6ecc5e81c2c383050fbdd5876ce1e5ea22f (#825). - -- Update vendored sources to duckdb/duckdb@7f09c98f0022336671aac0197f6820044e065c4f (#823). - - -# duckdb 1.1.3.9027 - -## vendor - -- Update vendored sources to duckdb/duckdb@ed645161037027a0ddc7631a40874d298262bc4f (#822). - -- Update vendored sources to duckdb/duckdb@087d8f34f6d974a1fedfc500fb5c8e269da01c95 (#821). - -- Update vendored sources to duckdb/duckdb@b2cd12758c1b0b3b22408cf883b4a5ebf0e44a94 (#820). - -- Update vendored sources to duckdb/duckdb@1c6eacd28aae3f20337634b991d60ec001187313 (#819). - -- Update vendored sources to duckdb/duckdb@3b5feedfe7fd4354ecae907cf63c02c936e5e699 (#818). - -- Update vendored sources to duckdb/duckdb@2be6f64aedffdc52e81ee197828ac95126b1cc0f (#817). - -- Update vendored sources to duckdb/duckdb@c4a286b6424c56effd31a4ad724a45179ccc76a7 (#816). - -- Update vendored sources to duckdb/duckdb@0cd582b44ea4dc57f6f77730e00368537343f2a5 (#815). - -- Update vendored sources to duckdb/duckdb@1db3def66e16a51f94c90c5cb53d37f3ff910725 (#814). - -- Update vendored sources to duckdb/duckdb@63a971e74270a8ac9db8bc524ba2d5908009da16 (#813). - -- Update vendored sources to duckdb/duckdb@aa3787b0c15ece12e071200e7a82a186d3d712f0 (#812). - -- Update vendored sources to duckdb/duckdb@974954d89efe801fbe36e52422d26481ba7f8bc3 (#811). - -- Update vendored sources to duckdb/duckdb@b18889cae2d6ba5e98a881d9b7e7652373700f3a (#810). - -- Update vendored sources to duckdb/duckdb@9da182a939d8a812484bf7ed0fdc3b3f6cb7a5c7 (#809). - -- Update vendored sources to duckdb/duckdb@87021421a54e9100e5ffeaa3ca142cdd01561766 (#808). - -- Update vendored sources to duckdb/duckdb@46a13e5ccbf6fea5a6468f9278c333a2b2334e8e (#807). - -- Update vendored sources to duckdb/duckdb@858da0bf846a64b7adb81c337c346685b5ca3857 (#806). - -- Update vendored sources to duckdb/duckdb@77c9f1f6ac3a7419183e4aa287e60ef97d0bcb8a (#805). - -- Update vendored sources to duckdb/duckdb@2d123094bbcc375575a538887bcc863d621ba15c (#804). - -- Update vendored sources to duckdb/duckdb@edfa1f2efd36c8d8cf96663b25aa71b81592d16e (#803). - -- Update vendored sources to duckdb/duckdb@4a826fd17dcb461357b121d3d4b75c3fa9851503 (#802). - -- Update vendored sources to duckdb/duckdb@4672042ed535f5ab7e46e782cabe2d3eb49323dc (#801). - -- Update vendored sources to duckdb/duckdb@59b237ad1c9e59c7164be5b2728f2c2ca799bf5e (#800). - -- Update vendored sources to duckdb/duckdb@228b11ce78a8a2750e9d0d248a896545a2569a63 (#799). - -- Update vendored sources to duckdb/duckdb@83822080bfbebd6b073c54e05ae34909f3e6a48c (#798). - -- Update vendored sources to duckdb/duckdb@41c78b1fb0881af9c12d5fbd30ef0385c947f128 (#797). - -- Update vendored sources to duckdb/duckdb@75c349e47fa61d7d48352380743abad6eeee7537 (#796). - -- Update vendored sources to duckdb/duckdb@e0c69c3efcf1e98837fd056937a927ad441bba8b (#795). - -- Update vendored sources to duckdb/duckdb@fc4b8d4794d0dfe62764ae5d03270d34264c005f (#794). - -- Update vendored sources to duckdb/duckdb@a99052476b13e3f796e26c6ddb39786600414398 (#793). - -- Update vendored sources to duckdb/duckdb@c401eb25f75a184a5ada31b29625851c953307b4 (#792). - -- Update vendored sources to duckdb/duckdb@c09482689534ceb57f78e7386f7d47722be1383f (#791). - -- Update vendored sources to duckdb/duckdb@f41f5fa26b05e9f705bb70fb5f7430f283a27f0f (#790). - -- Update vendored sources to duckdb/duckdb@1004fd9cfe69499122ea9f85ec914a380f3b4463 (#789). - -- Update vendored sources to duckdb/duckdb@c3a10d0c66c5fdfe84ec70c54eb073bf810813a9 (#788). - -- Update vendored sources to duckdb/duckdb@a987c5afa621448a1d3e7e02c2ddaaeb4b91855c (#787). - -- Update vendored sources to duckdb/duckdb@f86ed2d4fd096316517aea3db14f172fd990f042 (#786). - -- Update vendored sources to duckdb/duckdb@4a2b8868e7eb8bfaabafff7a166513074640a806 (#785). - -- Update vendored sources to duckdb/duckdb@d9bab0c3593817e3bb9c562351c60bf2294b56ac (#784). - -- Update vendored sources to duckdb/duckdb@405ff1f66f60b2e87bcdc5f1ce4e302d2e9d60b2 (#783). - -- Update vendored sources to duckdb/duckdb@219dc27cfcb73a7829e17a5b5462936427576f46 (#782). - -- Update vendored sources to duckdb/duckdb@b64596b5914fbe811965217811c868b0de3fa05a (#781). - -- Update vendored sources to duckdb/duckdb@6064047fb295f723d55dd3f29aa4422852bd9383 (#780). - -- Update vendored sources to duckdb/duckdb@d52795385f2908ca1de16716e29a0cddc7d90dbe (#779). - -- Update vendored sources to duckdb/duckdb@f039ebe2bdf260170379af40aeca373625b25bd9 (#778). - -- Update vendored sources to duckdb/duckdb@ea8ad42552c8055460ae11bf3d2a882f4e9e1394 (#777). - -- Update vendored sources to duckdb/duckdb@100c581e592f1acd9c654d4f01683dc858621708 (#776). - -- Update vendored sources to duckdb/duckdb@24d5a327497a384dcfeddff05de5e61142b42ed2 (#775). - -- Update vendored sources to duckdb/duckdb@358d7344ebd9977c92cf7501bde94ce3ba2f0ea4 (#774). - -- Update vendored sources to duckdb/duckdb@cbe809291b28394d494aa21472e694e9638cad39 (#772). - - -# duckdb 1.1.3.9026 - ## Testing - Skip tests that are about to fail. -## vendor - -- Update vendored sources to duckdb/duckdb@f5fba86dd1bb6cfded68e71825615759248a145b (#770). - -- Update vendored sources to duckdb/duckdb@cd09b6e41e6efb5dd16e1317070420dfebe3ee0c (#769). - -- Update vendored sources to duckdb/duckdb@547ffc95ff6c0b31cc7df6172296f4739aaacdb0 (#768). - -- Update vendored sources to duckdb/duckdb@b1840cfc161484a5d9a649b5b5ec412f4a4205d9 (#767). - -- Update vendored sources to duckdb/duckdb@81d0d65e8aeffd5b57dd7ebde4af42123e750b6e (duckdb/duckdb#15010, #766). - -- Update vendored sources to duckdb/duckdb@de7da9e4608542d21619306e11139dee6b5fbce3 (#765). - -- Update vendored sources to duckdb/duckdb@f43fbd7527bfe34b879d3a07e2ce4b019a609e45 (#764). - -- Update vendored sources to duckdb/duckdb@440bdb60b75fa8c3bc8cdd50d3d15f7df5279b0a (#763). - -- Update vendored sources to duckdb/duckdb@94da251db914c3c6b2b4793c3490403e2de6ffaa (#762). - -- Update vendored sources to duckdb/duckdb@9e6fd53f3dcf41b554740ed8eb62c8e41e0fdc43 (#761). - -- Update vendored sources to duckdb/duckdb@2d3ff3d571e7644498ff145d414b16b568d5762d (#760). - -- Update vendored sources to duckdb/duckdb@5b5a0b95fccc4eae6995d863c9447e07df60d572 (#759). - -- Update vendored sources to duckdb/duckdb@c9d2be9e84e14b882c7ea5957a2c737325cae9ac (#758). - -- Update vendored sources to duckdb/duckdb@148c8b9a7d32d49a85255215a2e51b646f79747d (#757). - -- Update vendored sources to duckdb/duckdb@a72c6aa7407e39576f0f0a88d84a56d2ab7e98be (#756). - -- Update vendored sources to duckdb/duckdb@ef43a0df34593f61dfaf81a40f92eb7bcbc220d8 (#755). - -- Update vendored sources to duckdb/duckdb@4a22a652cfb1f396b9016daff0204090b97ff390 (#754). - -- Update vendored sources to duckdb/duckdb@3be8f0ba9f8bca47c8a65bdd361bcadb45644e9c (#753). - -- Update vendored sources to duckdb/duckdb@a01f5d538f85f606b93e0681c14788bd975cdb96 (#752). - -- Update vendored sources to duckdb/duckdb@5d48575b112de7ad2759bad4b65bc86dd21185a2 (#751). - -- Update vendored sources to duckdb/duckdb@1ef91baeae8f2b02c7d9dcbcc518ef15d0859827 (#750). - -- Update vendored sources to duckdb/duckdb@1c6f5fd5864e006c9aac5d1966e03a8caa03640d (#748). - -- Update vendored sources to duckdb/duckdb@6762a1ec9952a0162e9f2e105dd7acef14b56d2a (#747). - -- Update vendored sources to duckdb/duckdb@cf1eee68e6f864966ccc60c83cfeabcc43278a34 (#746). - -- Update vendored sources to duckdb/duckdb@bb9582034023a27c174ecf818534312b263173da (#745). - -- Update vendored sources to duckdb/duckdb@8d73ca7c1413a062a31c812507303a15e7653a0d (#744). - -- Update vendored sources to duckdb/duckdb@efdb46ea641c9b09cc9d374f65bde3e4cadf3f6a (#743). - -- Update vendored sources to duckdb/duckdb@89ac252124adc5a09113e3574cd445acd6526959 (#742). - -- Update vendored sources to duckdb/duckdb@a4963a5aeaba37b16c7c8efff1fead7578eddd28 (#741). - -- Update vendored sources to duckdb/duckdb@a73bbc8c5da576d655f6c69a314ed348805d338c (#740). - -- Update vendored sources to duckdb/duckdb@c29caec724909bc1045d92ac453c9808ef7d605b (#739). - -- Update vendored sources to duckdb/duckdb@23f7e0dc487902aee9ba1f35249ff855b7d167d5 (#738). - -- Update vendored sources to duckdb/duckdb@aa2fe677d6b8ec4bb4b35d47b5a521cd8e1a76bf (#737). - -- Update vendored sources to duckdb/duckdb@47490b7f4fb806232077046821e20e9792a7c180 (#736). - -- Update vendored sources to duckdb/duckdb@da2455a15ed26dd5f0c1c20f61f63afc6b3d557f (#735). - -- Update vendored sources to duckdb/duckdb@cafa1712cdf123b888211bb9f518ee44c9e631a4 (#734). - -- Update vendored sources to duckdb/duckdb@ed90e384ef0cf01e9d519bbd26120f1771552b25 (#733). - -- Update vendored sources to duckdb/duckdb@1d4c3d19513d3f4aa152566ba5bf5266fe672755 (#732). - -- Update vendored sources to duckdb/duckdb@fccec3450983bb45c88d386db87398ce37d503de (#731). - -- Update vendored sources to duckdb/duckdb@c563f4f6ace969977ec8801dd5bdd5f9830f11fa (#730). - -- Update vendored sources to duckdb/duckdb@044b919545f70d3850d358795327dc31d6dd14de (#729). - -- Update vendored sources to duckdb/duckdb@68a3ce9d4b5ab8f5033f9c7b27cb2cbc21d1b1ef (#728). - -- Update vendored sources to duckdb/duckdb@38feda3af940ef13baab73033fea35962a583a8a (#727). - -- Update vendored sources to duckdb/duckdb@ae2178ec2c1f1e961761b8dbd895a5d137f20f51 (#726). - -- Update vendored sources to duckdb/duckdb@1a3d614f0eec5a2198af8ba4ea06eb9adee9d5f8 (#725). - -- Update vendored sources to duckdb/duckdb@742e86dce29a84990ffadf6136de840ac177ec6d (#723). - - -# duckdb 1.1.3.9025 - -## vendor - -- Update vendored sources to duckdb/duckdb@e0d1305a33cf1b2c6eaa3ef45b5044ac55ae7bad (#722). - -- Update vendored sources to duckdb/duckdb@79cbfab4cdfbae9a7bd4808f0d808a70267440f0 (#721). - -- Update vendored sources to duckdb/duckdb@c29c67bb971362cd1e9143305acffebb1bc9bd63 (#720). - -- Update vendored sources to duckdb/duckdb@89b6e4f5a528e5f88f4b8fc9cad16b879f2ec53c (duckdb/duckdb#14833, #719). - -- Update vendored sources to duckdb/duckdb@dcb700fef00d6da027c5269d90345ee5dd679d43 (#716). - - -# duckdb 1.1.3.9024 - -## Chore - -- IDE. - - -# duckdb 1.1.3.9023 - -## vendor - -- Update vendored sources to duckdb/duckdb@4ebeb16350eb2f819d682c581490af460dd0c995 (#715). - -- Update vendored sources to duckdb/duckdb@8ca81bab81b00bc8d97a228d57fada526e8f3be7 (#714). - -- Update vendored sources to duckdb/duckdb@eef81b43a7a9f3431b39982cd4816a63d58abf25 (#713). - -- Update vendored sources to duckdb/duckdb@448b46937fcafdc789b053536d093ef22b9105b5 (#712). - -- Update vendored sources to duckdb/duckdb@8e2c944aac9b39b0482569e1a2ada87e035c2d57 (#711). - -- Update vendored sources to duckdb/duckdb@36e3702a633ba2d9008020c3dc776e8d59cc08dd (#710). - -- Update vendored sources to duckdb/duckdb@a0a1e401d7880fa10c781fa47ae495237286cfe5 (#709). - -- Update vendored sources to duckdb/duckdb@d6b08498a1e55b27a373af6172330da25e8b0051 (#708). - -- Update vendored sources to duckdb/duckdb@6cb7cec64751d9ede8919f98afbdfd5a663cae9b (#706). - -- Update vendored sources to duckdb/duckdb@d29642dc9dc922e57f1f12852bf92015a0ea5e68 (#705). - -- Update vendored sources to duckdb/duckdb@376ece5833cf7422a50dda091d7821324ca8fdc2 (#704). - -- Update vendored sources to duckdb/duckdb@4d6ef66b0ecdefb8545159708baa6f910a80c38b (#703). - -- Update vendored sources to duckdb/duckdb@b470dea7ee47dc2debcc37a4e94976f8eff6670c (#702). - -- Update vendored sources to duckdb/duckdb@339435d04709962d3d0aa82faf5f1614d70e7c2b (#701). - -- Update vendored sources to duckdb/duckdb@4982c3f135d0f55cbb896ca35a0cd8dc458fc4ee (#700). - -- Update vendored sources to duckdb/duckdb@46948504b4e9c879cf59ec3f73291b9c6367c84f (#699). - -- Update vendored sources to duckdb/duckdb@24680c5a73c491d9d96920a31440a2912c2f2831 (#695). - - -# duckdb 1.1.3.9022 - -## vendor - -- Update vendored sources to duckdb/duckdb@2dd3d187c15c3fef36bdc4f11f3c63b56a988f6e (#694). - -- Update vendored sources to duckdb/duckdb@810cfa4568ffb4b4019480287ab6a6e414b47cd7 (#693). - -- Update vendored sources to duckdb/duckdb@c92a86dd7e1d30a047cc5ccdc54256f3903f34ec (#692). - -- Update vendored sources to duckdb/duckdb@b6ca9af3ed8fd49a914237ad3368bce248034b9e (#691). - -- Update vendored sources to duckdb/duckdb@3a1ac5a37b4d6facab8a865fbd75fc0d2c39777f (#690). - -- Update vendored sources to duckdb/duckdb@854e879592ae4cd2424831f639bc43d04619bc49 (#689). - -- Update vendored sources to duckdb/duckdb@dd01b20840f687936de23530a45bfee36aa5a3b1 (#688). - -- Update vendored sources to duckdb/duckdb@00e9fb9364a671f458b9461869febe40553648b1 (#687). - -- Update vendored sources to duckdb/duckdb@e5c89d84685debbb6de27d406482972bdcb37b07 (#685). - - -# duckdb 1.1.3.9021 - -## vendor - -- Update vendored sources to duckdb/duckdb@b484c2d96fa8fd4ba34e0a6bec72b2324572b78d (#684). - -- Update vendored sources to duckdb/duckdb@d5d8d8716ddd32fbc9dda7ca684b9f3b1f8ce32b (#683). - -- Update vendored sources to duckdb/duckdb@79646c30f07b32106b80b7f4f0fd5667340b75c5 (#682). - -- Update vendored sources to duckdb/duckdb@50a797c428e7bd59f5793af489d0ca944cf74d69 (#681). - -- Update vendored sources to duckdb/duckdb@5422f9a5313118e0e268513ea21be55d2b8f5908 (#680). - -- Update vendored sources to duckdb/duckdb@ca5af32c331f9d5ea49f7158d5c83a47f25b8b79 (#679). - -- Update vendored sources to duckdb/duckdb@36750753896c3ff0ce49b6d8793744aedcd1bed7 (#678). - -- Update vendored sources to duckdb/duckdb@9e734abdd70e6567b339ce9ec0ce01db3af78c2f (#677). - -- Update vendored sources to duckdb/duckdb@9182be3d86d781e83f6fc854aa9f5cdcc1f65412 (duckdb/duckdb#14540, #676). - -- Update vendored sources to duckdb/duckdb@36c82bf3bf5801bb14f91ae51b5ba98f4a53221e (#675). - -- Update vendored sources to duckdb/duckdb@99e452ba0680875be65c91bc12c381a9c50a0443 (#674). - -- Update vendored sources to duckdb/duckdb@66be5351200ea702f37fd65c527ef3f2172fc670 (#673). - -- Update vendored sources to duckdb/duckdb@a2dce8b1c9fa6039c82e9a32bfcc4c49b03ca871 (#672). - -- Update vendored sources to duckdb/duckdb@1fe66c2ca4d6ae5aa88a46df6b9d4406e19ed35f (#671). - -- Update vendored sources to duckdb/duckdb@b5fea5d7396f055753e50fdc0b321bf57e96219b (#670). - -- Update vendored sources to duckdb/duckdb@df7fb2cae75c8d28e7fe824be33891ee2b572fff (#669). - -- Update vendored sources to duckdb/duckdb@15839cad9cd9381e642948f782ac9746e63e32da (#668). - -- Update vendored sources to duckdb/duckdb@d2fd21da3fe6b710632a304e17298d88656505c0 (#667). - -- Update vendored sources to duckdb/duckdb@fd5de0607d7ab5bdddad62cc1a0225be72dff967 (#666). - -- Update vendored sources to duckdb/duckdb@da7bc7697024273f1cc224b535419ae7ba7095d1 (#665). - -- Update vendored sources to duckdb/duckdb@26754970dbaa9a0dffa45e8d4a0178a10946431d (#664). - -- Update vendored sources to duckdb/duckdb@242d3b85ea9fc7fde6e96babd65e360e9c369c2f (#663). - -- Update vendored sources to duckdb/duckdb@f06cd1203632dc6a473810a4dfcd4a228c014134 (#662). - -- Update vendored sources to duckdb/duckdb@3200280212febd461ee658e61c057229319cbc53 (#661). - -- Update vendored sources to duckdb/duckdb@2d1b7d796d0e49e7a73ede14fd7d3033c1782626 (#660). - -- Update vendored sources to duckdb/duckdb@99a401ba105ea0ef799ebdf9e9ef9a13192a5d38 (#659). - -- Update vendored sources to duckdb/duckdb@fa524d5d522a0657e910988325dab899fe0b0408 (#658). - -- Update vendored sources to duckdb/duckdb@0ccf3c25ccbb25fb90616e77b38f6d138f82950d (#657). - -- Update vendored sources to duckdb/duckdb@ca8d6057ae5cf611a4d921cdb6d0f34097bd8094 (#656). - -- Update vendored sources to duckdb/duckdb@ab29daf31038427696b45942df8c55bd0eafed16 (#655). - -- Update vendored sources to duckdb/duckdb@7ffe7a225f4204760af770ad3c43b10db1645152 (#654). - -- Update vendored sources to duckdb/duckdb@9e446321cdc1482c9750654d6bb4e1a3ac12ed4f (#653). - -- Update vendored sources to duckdb/duckdb@9982a4a0128f02cbb93fb562165e55ce5d2ae033 (#652). - -- Update vendored sources to duckdb/duckdb@564eb25ef0ec700c8a289fe852c16629a19650bd (#650). - - -# duckdb 1.1.3.9020 - -## vendor - -- Update vendored sources to duckdb/duckdb@2fd71f4d61e594f396a7a4911dbb8f56b15dc08a (#649). - -- Update vendored sources to duckdb/duckdb@ec0304403710ca7e87814a042d23058a5ad91f9f (duckdb/duckdb#14701, #648). - -- Update vendored sources to duckdb/duckdb@fc413a0c263a8118ee17a0c27c60c0766d18f2d4 (duckdb/duckdb#14699, #647). - -- Update vendored sources to duckdb/duckdb@131787252cc0506d0fdeb4e8b9de10b68118d156 (#646). - -- Update vendored sources to duckdb/duckdb@059ac75f6225fde78b686bc85f23d2e70af1dbe0 (#603). - - -# duckdb 1.1.3.9019 - -## Testing - - Sync tests. -# duckdb 1.1.3.9018 - -## Continuous integration - -- Avoid failure in fledge workflow if no changes (#639). - -## Uncategorized - -- Merge branch 'cran-1.1.3-1'. - -- Merge branch 'cran-1.1.3-1'. - -- Merge branch 'f-bump'. - - # duckdb 1.1.3-1 ## Features diff --git a/patch/0007-Remove-stderr-for-zstd.patch b/patch/0007-Remove-stderr-for-zstd.patch deleted file mode 100644 index e70afa118..000000000 --- a/patch/0007-Remove-stderr-for-zstd.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 1e6fb864921a6314b5d4a946bbd406ed72de0e30 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Fri, 20 Dec 2024 19:59:12 +0100 -Subject: [PATCH] Remove stderr for zstd - ---- - src/duckdb/third_party/zstd/dict/cover.cpp | 3 +-- - src/duckdb/third_party/zstd/dict/fastcover.cpp | 3 +-- - src/duckdb/third_party/zstd/dict/zdict.cpp | 3 ++- - 3 files changed, 4 insertions(+), 5 deletions(-) - -diff --git a/src/duckdb/third_party/zstd/dict/cover.cpp b/src/duckdb/third_party/zstd/dict/cover.cpp -index 935c96609..4a80eb1c5 100644 ---- a/src/duckdb/third_party/zstd/dict/cover.cpp -+++ b/src/duckdb/third_party/zstd/dict/cover.cpp -@@ -58,10 +58,9 @@ - static int g_displayLevel = 0; - #endif - #undef DISPLAY -+// CRAN does not allow stderr references - #define DISPLAY(...) \ - { \ -- fprintf(stderr, __VA_ARGS__); \ -- fflush(stderr); \ - } - #undef LOCALDISPLAYLEVEL - #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ -diff --git a/src/duckdb/third_party/zstd/dict/fastcover.cpp b/src/duckdb/third_party/zstd/dict/fastcover.cpp -index b3d103125..af4556676 100644 ---- a/src/duckdb/third_party/zstd/dict/fastcover.cpp -+++ b/src/duckdb/third_party/zstd/dict/fastcover.cpp -@@ -55,10 +55,9 @@ namespace duckdb_zstd { - static int g_displayLevel = 0; - #endif - #undef DISPLAY -+// CRAN does not allow stderr references - #define DISPLAY(...) \ - { \ -- fprintf(stderr, __VA_ARGS__); \ -- fflush(stderr); \ - } - #undef LOCALDISPLAYLEVEL - #define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ -diff --git a/src/duckdb/third_party/zstd/dict/zdict.cpp b/src/duckdb/third_party/zstd/dict/zdict.cpp -index 7381e505d..069691d19 100644 ---- a/src/duckdb/third_party/zstd/dict/zdict.cpp -+++ b/src/duckdb/third_party/zstd/dict/zdict.cpp -@@ -75,7 +75,8 @@ static const U32 g_selectivity_default = 9; - * Console display - ***************************************/ - #undef DISPLAY --#define DISPLAY(...) do { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } while (0) -+// CRAN does not allow stderr references -+#define DISPLAY(...) do { } while (0) - #undef DISPLAYLEVEL - #define DISPLAYLEVEL(l, ...) do { if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } } while (0) /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ - --- -2.43.0 - diff --git a/patch/0008-Avoid-pragma-for-zstd.patch b/patch/0008-Avoid-pragma-for-zstd.patch deleted file mode 100644 index 2818226cf..000000000 --- a/patch/0008-Avoid-pragma-for-zstd.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a8efb1ccf35192701564878566a22bc7f014c9c7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Fri, 20 Dec 2024 20:00:18 +0100 -Subject: [PATCH] Avoid pragma for zstd - ---- - src/duckdb/third_party/zstd/dict/divsufsort.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/duckdb/third_party/zstd/dict/divsufsort.cpp b/src/duckdb/third_party/zstd/dict/divsufsort.cpp -index b40901734..d0d00f8ca 100644 ---- a/src/duckdb/third_party/zstd/dict/divsufsort.cpp -+++ b/src/duckdb/third_party/zstd/dict/divsufsort.cpp -@@ -26,7 +26,7 @@ - - /*- Compiler specifics -*/ - #ifdef __clang__ --#pragma clang diagnostic ignored "-Wshorten-64-to-32" -+// CRAN does not allow pragmas - #endif - - #if defined(_MSC_VER) --- -2.43.0 - diff --git a/patch/0009-Remove-stderr-for-zstd.patch b/patch/0009-Remove-stderr-for-zstd.patch deleted file mode 100644 index 4d7af8216..000000000 --- a/patch/0009-Remove-stderr-for-zstd.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 4b2b14d6197ba4dbb9de0afeb974e92f42aa561f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Kirill=20M=C3=BCller?= -Date: Fri, 20 Dec 2024 20:40:37 +0100 -Subject: [PATCH] Remove stderr for zstd - ---- - src/duckdb/third_party/zstd/dict/zdict.cpp | 8 +------- - 1 file changed, 1 insertion(+), 7 deletions(-) - -diff --git a/src/duckdb/third_party/zstd/dict/zdict.cpp b/src/duckdb/third_party/zstd/dict/zdict.cpp -index 069691d19..8529e9442 100644 ---- a/src/duckdb/third_party/zstd/dict/zdict.cpp -+++ b/src/duckdb/third_party/zstd/dict/zdict.cpp -@@ -479,15 +479,9 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize, - clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10; - - # undef DISPLAYUPDATE -+// CRAN does not allow stderr references - # define DISPLAYUPDATE(l, ...) \ - do { \ -- if (notificationLevel>=l) { \ -- if (ZDICT_clockSpan(displayClock) > refreshRate) { \ -- displayClock = clock(); \ -- DISPLAY(__VA_ARGS__); \ -- } \ -- if (notificationLevel>=4) fflush(stderr); \ -- } \ - } while (0) - - /* init */ --- -2.43.0 - diff --git a/rconfigure.py b/rconfigure.py index 62dead6d3..bd08cf851 100644 --- a/rconfigure.py +++ b/rconfigure.py @@ -4,7 +4,7 @@ import subprocess import platform -extensions = ['parquet','core_functions'] +extensions = ['parquet'] # check if there are any additional extensions being requested if 'DUCKDB_R_EXTENSIONS' in os.environ: diff --git a/src/Makevars b/src/Makevars index f25fe8b1f..5c567a237 100644 --- a/src/Makevars +++ b/src/Makevars @@ -16,5 +16,5 @@ include include/sources.mk include Makevars.duckdb CXX_STD = CXX17 -PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/core_functions/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED -DDUCKDB_BUILD_LIBRARY +PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/zstd/include -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY OBJECTS=rfuns.o database.o connection.o statement.o register.o relational.o scan.o signal.o transform.o utils.o reltoaltrep.o types.o cpp11.o $(SOURCES) diff --git a/src/Makevars.win b/src/Makevars.win index 3b1d2adc9..5ea1247ef 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -16,6 +16,6 @@ include include/sources.mk include Makevars.duckdb CXX_STD = CXX17 -PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/zstd/include -Iduckdb/extension/core_functions/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_PLATFORM_RTOOLS=1 +PKG_CPPFLAGS = -Iinclude -I../inst/include -DDUCKDB_DISABLE_PRINT -DDUCKDB_R_BUILD -DBROTLI_ENCODER_CLEANUP_ON_OOM -Iduckdb/src/include -Iduckdb/third_party/concurrentqueue -Iduckdb/third_party/fast_float -Iduckdb/third_party/fastpforlib -Iduckdb/third_party/fmt/include -Iduckdb/third_party/fsst -Iduckdb/third_party/httplib -Iduckdb/third_party/hyperloglog -Iduckdb/third_party/jaro_winkler -Iduckdb/third_party/jaro_winkler/details -Iduckdb/third_party/libpg_query -Iduckdb/third_party/libpg_query/include -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -Iduckdb/third_party/mbedtls/library -Iduckdb/third_party/miniz -Iduckdb/third_party/pcg -Iduckdb/third_party/re2 -Iduckdb/third_party/skiplist -Iduckdb/third_party/tdigest -Iduckdb/third_party/utf8proc -Iduckdb/third_party/utf8proc/include -Iduckdb/third_party/yyjson/include -Iduckdb/extension/parquet/include -Iduckdb/third_party/parquet -Iduckdb/third_party/thrift -Iduckdb/third_party/lz4 -Iduckdb/third_party/brotli/include -Iduckdb/third_party/brotli/common -Iduckdb/third_party/brotli/dec -Iduckdb/third_party/brotli/enc -Iduckdb/third_party/snappy -Iduckdb/third_party/zstd/include -Iduckdb/third_party/mbedtls -Iduckdb/third_party/mbedtls/include -I../inst/include -Iduckdb -DDUCKDB_EXTENSION_PARQUET_LINKED -DDUCKDB_BUILD_LIBRARY -DDUCKDB_PLATFORM_RTOOLS=1 OBJECTS=rfuns.o database.o connection.o statement.o register.o relational.o scan.o signal.o transform.o utils.o reltoaltrep.o types.o cpp11.o $(SOURCES) PKG_LIBS=-lws2_32 -L. -lrstrtmgr diff --git a/src/duckdb/extension/core_functions/core_functions_extension.cpp b/src/duckdb/extension/core_functions/core_functions_extension.cpp deleted file mode 100644 index 8bf09b800..000000000 --- a/src/duckdb/extension/core_functions/core_functions_extension.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#define DUCKDB_EXTENSION_MAIN -#include "core_functions_extension.hpp" - -#include "core_functions/function_list.hpp" -#include "duckdb/main/extension_util.hpp" -#include "duckdb/function/register_function_list_helper.hpp" -#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" - -namespace duckdb { - -template -static void FillExtraInfo(const StaticFunctionDefinition &function, T &info) { - info.internal = true; - FillFunctionDescriptions(function, info); - info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; -} - -void LoadInternal(DuckDB &db) { - auto functions = StaticFunctionDefinition::GetFunctionList(); - for (idx_t i = 0; functions[i].name; i++) { - auto &function = functions[i]; - if (function.get_function || function.get_function_set) { - // scalar function - ScalarFunctionSet result; - if (function.get_function) { - result.AddFunction(function.get_function()); - } else { - result = function.get_function_set(); - } - result.name = function.name; - CreateScalarFunctionInfo info(result); - FillExtraInfo(function, info); - ExtensionUtil::RegisterFunction(*db.instance, std::move(info)); - } else if (function.get_aggregate_function || function.get_aggregate_function_set) { - // aggregate function - AggregateFunctionSet result; - if (function.get_aggregate_function) { - result.AddFunction(function.get_aggregate_function()); - } else { - result = function.get_aggregate_function_set(); - } - result.name = function.name; - CreateAggregateFunctionInfo info(result); - FillExtraInfo(function, info); - ExtensionUtil::RegisterFunction(*db.instance, std::move(info)); - } else { - throw InternalException("Do not know how to register function of this type"); - } - } -} - -void CoreFunctionsExtension::Load(DuckDB &db) { - LoadInternal(db); -} - -std::string CoreFunctionsExtension::Name() { - return "core_functions"; -} - -std::string CoreFunctionsExtension::Version() const { -#ifdef EXT_VERSION_CORE_FUNCTIONS - return EXT_VERSION_CORE_FUNCTIONS; -#else - return ""; -#endif -} - -} // namespace duckdb - -extern "C" { - -DUCKDB_EXTENSION_API void core_functions_init(duckdb::DatabaseInstance &db) { - duckdb::DuckDB db_wrapper(db); - duckdb::LoadInternal(db_wrapper); -} - -DUCKDB_EXTENSION_API const char *core_functions_version() { - return duckdb::DuckDB::LibraryVersion(); -} -} - -#ifndef DUCKDB_EXTENSION_MAIN -#error DUCKDB_EXTENSION_MAIN not defined -#endif diff --git a/src/duckdb/extension/core_functions/include/core_functions_extension.hpp b/src/duckdb/extension/core_functions/include/core_functions_extension.hpp deleted file mode 100644 index e877860f0..000000000 --- a/src/duckdb/extension/core_functions/include/core_functions_extension.hpp +++ /dev/null @@ -1,22 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// core_functions_extension.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb.hpp" - -namespace duckdb { - -class CoreFunctionsExtension : public Extension { -public: - void Load(DuckDB &db) override; - std::string Name() override; - std::string Version() const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/date/current.cpp b/src/duckdb/extension/core_functions/scalar/date/current.cpp deleted file mode 100644 index 3d25ee80a..000000000 --- a/src/duckdb/extension/core_functions/scalar/date/current.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "core_functions/scalar/date_functions.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/common/operator/cast_operators.hpp" -#include "duckdb/common/types/timestamp.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/transaction/meta_transaction.hpp" - -namespace duckdb { - -static timestamp_t GetTransactionTimestamp(ExpressionState &state) { - return MetaTransaction::Get(state.GetContext()).start_timestamp; -} - -static void CurrentTimestampFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 0); - auto ts = GetTransactionTimestamp(state); - auto val = Value::TIMESTAMPTZ(timestamp_tz_t(ts)); - result.Reference(val); -} - -ScalarFunction GetCurrentTimestampFun::GetFunction() { - ScalarFunction current_timestamp({}, LogicalType::TIMESTAMP_TZ, CurrentTimestampFunction); - current_timestamp.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; - return current_timestamp; -} - -} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/string/jaro_winkler.cpp b/src/duckdb/extension/core_functions/scalar/string/jaro_winkler.cpp deleted file mode 100644 index 13db07c79..000000000 --- a/src/duckdb/extension/core_functions/scalar/string/jaro_winkler.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "jaro_winkler.hpp" - -#include "core_functions/scalar/string_functions.hpp" - -namespace duckdb { - -static inline double JaroScalarFunction(const string_t &s1, const string_t &s2, const double_t &score_cutoff = 0.0) { - auto s1_begin = s1.GetData(); - auto s2_begin = s2.GetData(); - return duckdb_jaro_winkler::jaro_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, s2_begin + s2.GetSize(), - score_cutoff); -} - -static inline double JaroWinklerScalarFunction(const string_t &s1, const string_t &s2, - const double_t &score_cutoff = 0.0) { - auto s1_begin = s1.GetData(); - auto s2_begin = s2.GetData(); - return duckdb_jaro_winkler::jaro_winkler_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, - s2_begin + s2.GetSize(), 0.1, score_cutoff); -} - -template -static void CachedFunction(Vector &constant, Vector &other, Vector &result, DataChunk &args) { - auto val = constant.GetValue(0); - idx_t count = args.size(); - if (val.IsNull()) { - auto &result_validity = FlatVector::Validity(result); - result_validity.SetAllInvalid(count); - return; - } - - auto str_val = StringValue::Get(val); - auto cached = CACHED_SIMILARITY(str_val); - - D_ASSERT(args.ColumnCount() == 2 || args.ColumnCount() == 3); - if (args.ColumnCount() == 2) { - UnaryExecutor::Execute(other, result, count, [&](const string_t &other_str) { - auto other_str_begin = other_str.GetData(); - return cached.similarity(other_str_begin, other_str_begin + other_str.GetSize()); - }); - } else { - auto score_cutoff = args.data[2]; - BinaryExecutor::Execute( - other, score_cutoff, result, count, [&](const string_t &other_str, const double_t score_cutoff) { - auto other_str_begin = other_str.GetData(); - return cached.similarity(other_str_begin, other_str_begin + other_str.GetSize(), score_cutoff); - }); - } -} - -template -static void TemplatedJaroWinklerFunction(DataChunk &args, Vector &result, SIMILARITY_FUNCTION fun) { - bool arg0_constant = args.data[0].GetVectorType() == VectorType::CONSTANT_VECTOR; - bool arg1_constant = args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR; - if (!(arg0_constant ^ arg1_constant)) { - // We can't optimize by caching one of the two strings - D_ASSERT(args.ColumnCount() == 2 || args.ColumnCount() == 3); - if (args.ColumnCount() == 2) { - BinaryExecutor::Execute( - args.data[0], args.data[1], result, args.size(), - [&](const string_t &s1, const string_t &s2) { return fun(s1, s2, 0.0); }); - return; - } else { - TernaryExecutor::Execute(args.data[0], args.data[1], args.data[2], - result, args.size(), fun); - return; - } - } - - if (arg0_constant) { - CachedFunction(args.data[0], args.data[1], result, args); - } else { - CachedFunction(args.data[1], args.data[0], result, args); - } -} - -static void JaroFunction(DataChunk &args, ExpressionState &state, Vector &result) { - TemplatedJaroWinklerFunction>(args, result, JaroScalarFunction); -} - -static void JaroWinklerFunction(DataChunk &args, ExpressionState &state, Vector &result) { - TemplatedJaroWinklerFunction>(args, result, - JaroWinklerScalarFunction); -} - -ScalarFunctionSet JaroSimilarityFun::GetFunctions() { - ScalarFunctionSet jaro; - - const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); - auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroFunction); - jaro.AddFunction(fun); - - fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::DOUBLE}, LogicalType::DOUBLE, - JaroFunction); - jaro.AddFunction(fun); - return jaro; -} - -ScalarFunctionSet JaroWinklerSimilarityFun::GetFunctions() { - ScalarFunctionSet jaroWinkler; - - const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); - auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroWinklerFunction); - jaroWinkler.AddFunction(fun); - - fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::DOUBLE}, LogicalType::DOUBLE, - JaroWinklerFunction); - jaroWinkler.AddFunction(fun); - return jaroWinkler; -} - -} // namespace duckdb diff --git a/src/duckdb/extension/parquet/column_reader.cpp b/src/duckdb/extension/parquet/column_reader.cpp index 8a2112c35..1b6d20632 100644 --- a/src/duckdb/extension/parquet/column_reader.cpp +++ b/src/duckdb/extension/parquet/column_reader.cpp @@ -29,11 +29,11 @@ namespace duckdb { -using duckdb_parquet::CompressionCodec; -using duckdb_parquet::ConvertedType; -using duckdb_parquet::Encoding; -using duckdb_parquet::PageType; -using duckdb_parquet::Type; +using duckdb_parquet::format::CompressionCodec; +using duckdb_parquet::format::ConvertedType; +using duckdb_parquet::format::Encoding; +using duckdb_parquet::format::PageType; +using duckdb_parquet::format::Type; const uint64_t ParquetDecodeUtils::BITPACK_MASKS[] = {0, 1, @@ -108,8 +108,7 @@ const uint8_t ParquetDecodeUtils::BITPACK_DLEN = 8; ColumnReader::ColumnReader(ParquetReader &reader, LogicalType type_p, const SchemaElement &schema_p, idx_t file_idx_p, idx_t max_define_p, idx_t max_repeat_p) : schema(schema_p), file_idx(file_idx_p), max_define(max_define_p), max_repeat(max_repeat_p), reader(reader), - type(std::move(type_p)), page_rows_available(0), dictionary_selection_vector(STANDARD_VECTOR_SIZE), - dictionary_size(0) { + type(std::move(type_p)), page_rows_available(0) { // dummies for Skip() dummy_define.resize(reader.allocator, STANDARD_VECTOR_SIZE); @@ -135,14 +134,6 @@ const SchemaElement &ColumnReader::Schema() const { return schema; } -optional_ptr ColumnReader::GetParentSchema() const { - return parent_schema; -} - -void ColumnReader::SetParentSchema(const SchemaElement &parent_schema_p) { - parent_schema = &parent_schema_p; -} - idx_t ColumnReader::FileIdx() const { return file_idx; } @@ -198,10 +189,19 @@ unique_ptr ColumnReader::Stats(idx_t row_group_idx_p, const vect } void ColumnReader::Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, // NOLINT - parquet_filter_t *filter, idx_t result_offset, Vector &result) { + parquet_filter_t &filter, idx_t result_offset, Vector &result) { throw NotImplementedException("Plain"); } +void ColumnReader::Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT + throw NotImplementedException("Dictionary"); +} + +void ColumnReader::Offsets(uint32_t *offsets, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, + idx_t result_offset, Vector &result) { + throw NotImplementedException("Offsets"); +} + void ColumnReader::PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) { throw std::runtime_error("DELTA_LENGTH_BYTE_ARRAY encoding is only supported for text or binary data"); } @@ -215,6 +215,8 @@ void ColumnReader::DeltaByteArray(uint8_t *defines, idx_t num_values, // NOLINT throw NotImplementedException("DeltaByteArray"); } +void ColumnReader::DictReference(Vector &result) { +} void ColumnReader::PlainReference(shared_ptr, Vector &result) { // NOLINT } @@ -245,10 +247,6 @@ void ColumnReader::PrepareRead(parquet_filter_t &filter) { block.reset(); PageHeader page_hdr; reader.Read(page_hdr, *protocol); - // some basic sanity check - if (page_hdr.compressed_page_size < 0 || page_hdr.uncompressed_page_size < 0) { - throw std::runtime_error("Page sizes can't be < 0"); - } switch (page_hdr.type) { case PageType::DATA_PAGE_V2: @@ -259,26 +257,13 @@ void ColumnReader::PrepareRead(parquet_filter_t &filter) { PreparePage(page_hdr); PrepareDataPage(page_hdr); break; - case PageType::DICTIONARY_PAGE: { + case PageType::DICTIONARY_PAGE: PreparePage(page_hdr); if (page_hdr.dictionary_page_header.num_values < 0) { throw std::runtime_error("Invalid dictionary page header (num_values < 0)"); } - auto old_dict_size = dictionary_size; - // we use the first value in the dictionary to keep a NULL - dictionary_size = page_hdr.dictionary_page_header.num_values; - if (!dictionary) { - dictionary = make_uniq(type, dictionary_size + 1); - } else if (dictionary_size > old_dict_size) { - dictionary->Resize(old_dict_size, dictionary_size + 1); - } - dictionary_id = reader.file_name + "_" + schema.name + "_" + std::to_string(chunk_read_offset); - // we use the first entry as a NULL, dictionary vectors don't have a separate validity mask - FlatVector::Validity(*dictionary).SetInvalid(0); - PlainReference(block, *dictionary); - Plain(block, nullptr, dictionary_size, nullptr, 1, *dictionary); + Dictionary(std::move(block), page_hdr.dictionary_page_header.num_values); break; - } default: break; // ignore INDEX page type and any other custom extensions } @@ -290,6 +275,7 @@ void ColumnReader::ResetPage() { void ColumnReader::PreparePageV2(PageHeader &page_hdr) { D_ASSERT(page_hdr.type == PageType::DATA_PAGE_V2); + auto &trans = reinterpret_cast(*protocol->getTransport()); AllocateBlock(page_hdr.uncompressed_page_size + 1); @@ -311,10 +297,6 @@ void ColumnReader::PreparePageV2(PageHeader &page_hdr) { // copy repeats & defines as-is because FOR SOME REASON they are uncompressed auto uncompressed_bytes = page_hdr.data_page_header_v2.repetition_levels_byte_length + page_hdr.data_page_header_v2.definition_levels_byte_length; - if (uncompressed_bytes > page_hdr.uncompressed_page_size) { - throw std::runtime_error("Page header inconsistency, uncompressed_page_size needs to be larger than " - "repetition_levels_byte_length + definition_levels_byte_length"); - } trans.read(block->ptr, uncompressed_bytes); auto compressed_bytes = page_hdr.compressed_page_size - uncompressed_bytes; @@ -503,31 +485,6 @@ void ColumnReader::PrepareDataPage(PageHeader &page_hdr) { } } -void ColumnReader::ConvertDictToSelVec(uint32_t *offsets, uint8_t *defines, parquet_filter_t &filter, idx_t read_now, - idx_t result_offset) { - D_ASSERT(read_now <= STANDARD_VECTOR_SIZE); - idx_t offset_idx = 0; - for (idx_t row_idx = 0; row_idx < read_now; row_idx++) { - if (HasDefines() && defines[row_idx + result_offset] != max_define) { - dictionary_selection_vector.set_index(row_idx, 0); // dictionary entry 0 is NULL - continue; // we don't have a dict entry for NULLs - } - if (filter.test(row_idx + result_offset)) { - auto offset = offsets[offset_idx++]; - if (offset >= dictionary_size) { - throw std::runtime_error("Parquet file is likely corrupted, dictionary offset out of range"); - } - dictionary_selection_vector.set_index(row_idx, offset + 1); - } else { - dictionary_selection_vector.set_index(row_idx, 0); // just set NULL if the filter excludes this row - offset_idx++; - } - } -#ifdef DEBUG - dictionary_selection_vector.Verify(read_now, dictionary_size + 1); -#endif -} - idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr_t define_out, data_ptr_t repeat_out, Vector &result) { // we need to reset the location because multiple column readers share the same protocol @@ -541,7 +498,6 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr idx_t result_offset = 0; auto to_read = num_values; - D_ASSERT(to_read <= STANDARD_VECTOR_SIZE); while (to_read > 0) { while (page_rows_available == 0) { @@ -551,7 +507,7 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr D_ASSERT(block); auto read_now = MinValue(to_read, page_rows_available); - D_ASSERT(read_now + result_offset <= STANDARD_VECTOR_SIZE); + D_ASSERT(read_now <= STANDARD_VECTOR_SIZE); if (HasRepeats()) { D_ASSERT(repeated_decoder); @@ -567,43 +523,30 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr if ((dict_decoder || dbp_decoder || rle_decoder || bss_decoder) && HasDefines()) { // we need the null count because the dictionary offsets have no entries for nulls - for (idx_t i = result_offset; i < result_offset + read_now; i++) { - null_count += (define_out[i] != max_define); + for (idx_t i = 0; i < read_now; i++) { + if (define_out[i + result_offset] != max_define) { + null_count++; + } } } - if (result_offset != 0 && result.GetVectorType() != VectorType::FLAT_VECTOR) { - result.Flatten(result_offset); - result.Resize(result_offset, STANDARD_VECTOR_SIZE); - } - if (dict_decoder) { - if ((!dictionary || dictionary_size == 0) && null_count < read_now) { - throw std::runtime_error("Parquet file is likely corrupted, missing dictionary"); - } offset_buffer.resize(reader.allocator, sizeof(uint32_t) * (read_now - null_count)); dict_decoder->GetBatch(offset_buffer.ptr, read_now - null_count); - ConvertDictToSelVec(reinterpret_cast(offset_buffer.ptr), - reinterpret_cast(define_out), filter, read_now, result_offset); - if (result_offset == 0) { - result.Dictionary(*dictionary, dictionary_size + 1, dictionary_selection_vector, read_now); - DictionaryVector::SetDictionaryId(result, dictionary_id); - D_ASSERT(result.GetVectorType() == VectorType::DICTIONARY_VECTOR); - } else { - D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - VectorOperations::Copy(*dictionary, result, dictionary_selection_vector, read_now, 0, result_offset); - } + DictReference(result); + Offsets(reinterpret_cast(offset_buffer.ptr), define_out, read_now, filter, result_offset, + result); } else if (dbp_decoder) { // TODO keep this in the state auto read_buf = make_shared_ptr(); switch (schema.type) { - case duckdb_parquet::Type::INT32: + case duckdb_parquet::format::Type::INT32: read_buf->resize(reader.allocator, sizeof(int32_t) * (read_now - null_count)); dbp_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; - case duckdb_parquet::Type::INT64: + case duckdb_parquet::format::Type::INT64: read_buf->resize(reader.allocator, sizeof(int64_t) * (read_now - null_count)); dbp_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; @@ -612,14 +555,14 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr throw std::runtime_error("DELTA_BINARY_PACKED should only be INT32 or INT64"); } // Plain() will put NULLs in the right place - Plain(read_buf, define_out, read_now, &filter, result_offset, result); + Plain(read_buf, define_out, read_now, filter, result_offset, result); } else if (rle_decoder) { // RLE encoding for boolean D_ASSERT(type.id() == LogicalTypeId::BOOLEAN); auto read_buf = make_shared_ptr(); read_buf->resize(reader.allocator, sizeof(bool) * (read_now - null_count)); rle_decoder->GetBatch(read_buf->ptr, read_now - null_count); - PlainTemplated>(read_buf, define_out, read_now, &filter, + PlainTemplated>(read_buf, define_out, read_now, filter, result_offset, result); } else if (byte_array_data) { // DELTA_BYTE_ARRAY or DELTA_LENGTH_BYTE_ARRAY @@ -628,11 +571,11 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr auto read_buf = make_shared_ptr(); switch (schema.type) { - case duckdb_parquet::Type::FLOAT: + case duckdb_parquet::format::Type::FLOAT: read_buf->resize(reader.allocator, sizeof(float) * (read_now - null_count)); bss_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; - case duckdb_parquet::Type::DOUBLE: + case duckdb_parquet::format::Type::DOUBLE: read_buf->resize(reader.allocator, sizeof(double) * (read_now - null_count)); bss_decoder->GetBatch(read_buf->ptr, read_now - null_count); break; @@ -640,10 +583,10 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr throw std::runtime_error("BYTE_STREAM_SPLIT encoding is only supported for FLOAT or DOUBLE data"); } - Plain(read_buf, define_out, read_now, &filter, result_offset, result); + Plain(read_buf, define_out, read_now, filter, result_offset, result); } else { PlainReference(block, result); - Plain(block, define_out, read_now, &filter, result_offset, result); + Plain(block, define_out, read_now, filter, result_offset, result); } result_offset += read_now; @@ -667,13 +610,12 @@ void ColumnReader::ApplyPendingSkips(idx_t num_values) { dummy_repeat.zero(); // TODO this can be optimized, for example we dont actually have to bitunpack offsets - Vector base_result(type, nullptr); + Vector dummy_result(type, nullptr); idx_t remaining = num_values; idx_t read = 0; while (remaining) { - Vector dummy_result(base_result); idx_t to_read = MinValue(remaining, STANDARD_VECTOR_SIZE); read += Read(to_read, none_filter, dummy_define.ptr, dummy_repeat.ptr, dummy_result); remaining -= to_read; @@ -718,6 +660,27 @@ uint32_t StringColumnReader::VerifyString(const char *str_data, uint32_t str_len return VerifyString(str_data, str_len, Type() == LogicalTypeId::VARCHAR); } +void StringColumnReader::Dictionary(shared_ptr data, idx_t num_entries) { + dict = std::move(data); + dict_strings = unsafe_unique_ptr(new string_t[num_entries]); + for (idx_t dict_idx = 0; dict_idx < num_entries; dict_idx++) { + uint32_t str_len; + if (fixed_width_string_length == 0) { + // variable length string: read from dictionary + str_len = dict->read(); + } else { + // fixed length string + str_len = fixed_width_string_length; + } + dict->available(str_len); + + auto dict_str = reinterpret_cast(dict->ptr); + auto actual_str_len = VerifyString(dict_str, str_len); + dict_strings[dict_idx] = string_t(dict_str, actual_str_len); + dict->inc(str_len); + } +} + static shared_ptr ReadDbpData(Allocator &allocator, ResizeableBuffer &buffer, idx_t &value_count) { auto decoder = make_uniq(buffer.ptr, buffer.len); value_count = decoder->TotalValues(); @@ -744,7 +707,6 @@ void StringColumnReader::PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) { auto string_data = FlatVector::GetData(*byte_array_data); for (idx_t i = 0; i < value_count; i++) { auto str_len = length_data[i]; - buffer.available(str_len); string_data[i] = StringVector::EmptyString(*byte_array_data, str_len); auto result_data = string_data[i].GetDataWriteable(); memcpy(result_data, buffer.ptr, length_data[i]); @@ -773,7 +735,6 @@ void StringColumnReader::PrepareDeltaByteArray(ResizeableBuffer &buffer) { auto string_data = FlatVector::GetData(*byte_array_data); for (idx_t i = 0; i < prefix_count; i++) { auto str_len = prefix_data[i] + suffix_data[i]; - buffer.available(suffix_data[i]); string_data[i] = StringVector::EmptyString(*byte_array_data, str_len); auto result_data = string_data[i].GetDataWriteable(); if (prefix_data[i] > 0) { @@ -825,10 +786,17 @@ class ParquetStringVectorBuffer : public VectorBuffer { shared_ptr buffer; }; +void StringColumnReader::DictReference(Vector &result) { + StringVector::AddBuffer(result, make_buffer(dict)); +} void StringColumnReader::PlainReference(shared_ptr plain_data, Vector &result) { StringVector::AddBuffer(result, make_buffer(std::move(plain_data))); } +string_t StringParquetValueConversion::DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { + return reader.Cast().dict_strings[offset]; +} + string_t StringParquetValueConversion::PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { auto &scr = reader.Cast(); uint32_t str_len = scr.fixed_width_string_length == 0 ? plain_data.read() : scr.fixed_width_string_length; @@ -1191,19 +1159,14 @@ StructColumnReader::StructColumnReader(ParquetReader &reader, LogicalType type_p D_ASSERT(type.InternalType() == PhysicalType::STRUCT); } -ColumnReader &StructColumnReader::GetChildReader(idx_t child_idx) { - if (!child_readers[child_idx]) { - throw InternalException("StructColumnReader::GetChildReader(%d) - but this child reader is not set", child_idx); - } - return *child_readers[child_idx].get(); +ColumnReader *StructColumnReader::GetChildReader(idx_t child_idx) { + D_ASSERT(child_idx < child_readers.size()); + return child_readers[child_idx].get(); } void StructColumnReader::InitializeRead(idx_t row_group_idx_p, const vector &columns, TProtocol &protocol_p) { for (auto &child : child_readers) { - if (!child) { - continue; - } child->InitializeRead(row_group_idx_p, columns, protocol_p); } } @@ -1217,51 +1180,34 @@ idx_t StructColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, da ApplyPendingSkips(pending_skips); } - optional_idx read_count; - for (idx_t i = 0; i < child_readers.size(); i++) { - auto &child = child_readers[i]; - auto &target_vector = *struct_entries[i]; - if (!child) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - continue; - } - auto child_num_values = child->Read(num_values, filter, define_out, repeat_out, target_vector); - if (!read_count.IsValid()) { + idx_t read_count = num_values; + for (idx_t i = 0; i < struct_entries.size(); i++) { + auto child_num_values = child_readers[i]->Read(num_values, filter, define_out, repeat_out, *struct_entries[i]); + if (i == 0) { read_count = child_num_values; - } else if (read_count.GetIndex() != child_num_values) { + } else if (read_count != child_num_values) { throw std::runtime_error("Struct child row count mismatch"); } } - if (!read_count.IsValid()) { - read_count = num_values; - } // set the validity mask for this level auto &validity = FlatVector::Validity(result); - for (idx_t i = 0; i < read_count.GetIndex(); i++) { + for (idx_t i = 0; i < read_count; i++) { if (define_out[i] < max_define) { validity.SetInvalid(i); } } - return read_count.GetIndex(); + return read_count; } void StructColumnReader::Skip(idx_t num_values) { - for (auto &child : child_readers) { - if (!child) { - continue; - } - child->Skip(num_values); + for (auto &child_reader : child_readers) { + child_reader->Skip(num_values); } } void StructColumnReader::RegisterPrefetch(ThriftFileTransport &transport, bool allow_merge) { for (auto &child : child_readers) { - if (!child) { - continue; - } child->RegisterPrefetch(transport, allow_merge); } } @@ -1269,9 +1215,6 @@ void StructColumnReader::RegisterPrefetch(ThriftFileTransport &transport, bool a uint64_t StructColumnReader::TotalCompressedSize() { uint64_t size = 0; for (auto &child : child_readers) { - if (!child) { - continue; - } size += child->TotalCompressedSize(); } return size; @@ -1308,6 +1251,9 @@ idx_t StructColumnReader::GroupRowsAvailable() { //===--------------------------------------------------------------------===// template struct DecimalParquetValueConversion { + static DUCKDB_PHYSICAL_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { + return reinterpret_cast(dict.ptr)[offset]; + } static DUCKDB_PHYSICAL_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { idx_t byte_len; @@ -1357,6 +1303,14 @@ class DecimalColumnReader reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; protected: + void Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT + BaseType::AllocateDict(num_entries * sizeof(DUCKDB_PHYSICAL_TYPE)); + auto dict_ptr = (DUCKDB_PHYSICAL_TYPE *)this->dict->ptr; + for (idx_t i = 0; i < num_entries; i++) { + dict_ptr[i] = + DecimalParquetValueConversion::PlainRead(*dictionary_data, *this); + } + } }; template @@ -1386,7 +1340,7 @@ static unique_ptr CreateDecimalReaderInternal(ParquetReader &reade template <> double ParquetDecimalUtils::ReadDecimalValue(const_data_ptr_t pointer, idx_t size, - const duckdb_parquet::SchemaElement &schema_ele) { + const duckdb_parquet::format::SchemaElement &schema_ele) { double res = 0; bool positive = (*pointer & 0x80) == 0; for (idx_t i = 0; i < size; i += 8) { @@ -1423,6 +1377,10 @@ unique_ptr ParquetDecimalUtils::CreateReader(ParquetReader &reader // UUID Column Reader //===--------------------------------------------------------------------===// struct UUIDValueConversion { + static hugeint_t DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { + return reinterpret_cast(dict.ptr)[offset]; + } + static hugeint_t ReadParquetUUID(const_data_ptr_t input) { hugeint_t result; result.lower = 0; @@ -1470,6 +1428,15 @@ class UUIDColumnReader : public TemplatedColumnReader(reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; + +protected: + void Dictionary(shared_ptr dictionary_data, idx_t num_entries) { // NOLINT + AllocateDict(num_entries * sizeof(hugeint_t)); + auto dict_ptr = reinterpret_cast(this->dict->ptr); + for (idx_t i = 0; i < num_entries; i++) { + dict_ptr[i] = UUIDValueConversion::PlainRead(*dictionary_data, *this); + } + } }; //===--------------------------------------------------------------------===// @@ -1478,6 +1445,10 @@ class UUIDColumnReader : public TemplatedColumnReader(dict.ptr)[offset]; + } + static interval_t ReadParquetInterval(const_data_ptr_t input) { interval_t result; result.months = Load(input); @@ -1517,6 +1488,15 @@ class IntervalColumnReader : public TemplatedColumnReader(reader, std::move(type_p), schema_p, file_idx_p, max_define_p, max_repeat_p) {}; + +protected: + void Dictionary(shared_ptr dictionary_data, idx_t num_entries) override { // NOLINT + AllocateDict(num_entries * sizeof(interval_t)); + auto dict_ptr = reinterpret_cast(this->dict->ptr); + for (idx_t i = 0; i < num_entries; i++) { + dict_ptr[i] = IntervalValueConversion::PlainRead(*dictionary_data, *this); + } + } }; //===--------------------------------------------------------------------===// diff --git a/src/duckdb/extension/parquet/column_writer.cpp b/src/duckdb/extension/parquet/column_writer.cpp index 677bacf42..0b1d867c8 100644 --- a/src/duckdb/extension/parquet/column_writer.cpp +++ b/src/duckdb/extension/parquet/column_writer.cpp @@ -1,14 +1,10 @@ #include "column_writer.hpp" #include "duckdb.hpp" -#include "geo_parquet.hpp" -#include "parquet_dbp_encoder.hpp" -#include "parquet_dlba_encoder.hpp" #include "parquet_rle_bp_decoder.hpp" #include "parquet_rle_bp_encoder.hpp" -#include "parquet_bss_encoder.hpp" -#include "parquet_statistics.hpp" #include "parquet_writer.hpp" +#include "geo_parquet.hpp" #ifndef DUCKDB_AMALGAMATION #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/comparison_operators.hpp" @@ -23,32 +19,49 @@ #include "duckdb/execution/expression_executor.hpp" #endif -#include "brotli/encode.h" #include "lz4.hpp" #include "miniz_wrapper.hpp" #include "snappy.h" #include "zstd.h" -#include "zstd/common/xxhash.hpp" - -#include +#include "brotli/encode.h" namespace duckdb { using namespace duckdb_parquet; // NOLINT using namespace duckdb_miniz; // NOLINT -using duckdb_parquet::CompressionCodec; -using duckdb_parquet::ConvertedType; -using duckdb_parquet::Encoding; -using duckdb_parquet::FieldRepetitionType; -using duckdb_parquet::FileMetaData; -using duckdb_parquet::PageHeader; -using duckdb_parquet::PageType; -using ParquetRowGroup = duckdb_parquet::RowGroup; -using duckdb_parquet::Type; +using duckdb_parquet::format::CompressionCodec; +using duckdb_parquet::format::ConvertedType; +using duckdb_parquet::format::Encoding; +using duckdb_parquet::format::FieldRepetitionType; +using duckdb_parquet::format::FileMetaData; +using duckdb_parquet::format::PageHeader; +using duckdb_parquet::format::PageType; +using ParquetRowGroup = duckdb_parquet::format::RowGroup; +using duckdb_parquet::format::Type; #define PARQUET_DEFINE_VALID 65535 +static void VarintEncode(uint32_t val, WriteStream &ser) { + do { + uint8_t byte = val & 127; + val >>= 7; + if (val != 0) { + byte |= 128; + } + ser.Write(byte); + } while (val != 0); +} + +static uint8_t GetVarintSize(uint32_t val) { + uint8_t res = 0; + do { + val >>= 7; + res++; + } while (val != 0); + return res; +} + //===--------------------------------------------------------------------===// // ColumnWriterStatistics //===--------------------------------------------------------------------===// @@ -93,7 +106,7 @@ void RleBpEncoder::BeginPrepare(uint32_t first_value) { void RleBpEncoder::FinishRun() { // last value, or value has changed // write out the current run - byte_count += ParquetDecodeUtils::GetVarintSize(current_run_count << 1) + byte_width; + byte_count += GetVarintSize(current_run_count << 1) + byte_width; current_run_count = 1; run_count++; } @@ -124,7 +137,7 @@ void RleBpEncoder::BeginWrite(WriteStream &writer, uint32_t first_value) { void RleBpEncoder::WriteRun(WriteStream &writer) { // write the header of the run - ParquetDecodeUtils::VarintEncode(current_run_count << 1, writer); + VarintEncode(current_run_count << 1, writer); // now write the value D_ASSERT(last_value >> (byte_width * 8) == 0); switch (byte_width) { @@ -211,11 +224,16 @@ void ColumnWriter::CompressPage(MemoryStream &temp_writer, size_t &compressed_si break; } case CompressionCodec::ZSTD: { + auto configured_compression = writer.CompressionLevel(); + int compress_level = ZSTD_CLEVEL_DEFAULT; + if (configured_compression.IsValid()) { + compress_level = static_cast(configured_compression.GetIndex()); + } compressed_size = duckdb_zstd::ZSTD_compressBound(temp_writer.GetPosition()); compressed_buf = unique_ptr(new data_t[compressed_size]); - compressed_size = duckdb_zstd::ZSTD_compress((void *)compressed_buf.get(), compressed_size, - (const void *)temp_writer.GetData(), temp_writer.GetPosition(), - UnsafeNumericCast(writer.CompressionLevel())); + compressed_size = + duckdb_zstd::ZSTD_compress((void *)compressed_buf.get(), compressed_size, + (const void *)temp_writer.GetData(), temp_writer.GetPosition(), compress_level); compressed_data = compressed_buf.get(); break; } @@ -326,20 +344,18 @@ struct PageWriteInformation { class BasicColumnWriterState : public ColumnWriterState { public: - BasicColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) + BasicColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { page_info.emplace_back(); } ~BasicColumnWriterState() override = default; - duckdb_parquet::RowGroup &row_group; + duckdb_parquet::format::RowGroup &row_group; idx_t col_idx; vector page_info; vector write_info; unique_ptr stats_state; idx_t current_page = 0; - - unique_ptr bloom_filter; }; //===--------------------------------------------------------------------===// @@ -361,15 +377,17 @@ class BasicColumnWriter : public ColumnWriter { //! Dictionary pages must be below 2GB. Unlike data pages, there's only one dictionary page. //! For this reason we go with a much higher, but still a conservative upper bound of 1GB; static constexpr const idx_t MAX_UNCOMPRESSED_DICT_PAGE_SIZE = 1e9; - //! If the dictionary has this many entries, we stop creating the dictionary + //! If the dictionary has this many entries, but the compression ratio is still below 1, + //! we stop creating the dictionary static constexpr const idx_t DICTIONARY_ANALYZE_THRESHOLD = 1e4; + //! The maximum size a key entry in an RLE page takes static constexpr const idx_t MAX_DICTIONARY_KEY_SIZE = sizeof(uint32_t); //! The size of encoding the string length static constexpr const idx_t STRING_LENGTH_SIZE = sizeof(uint32_t); public: - unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; void Prepare(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void BeginWrite(ColumnWriterState &state) override; void Write(ColumnWriterState &state, Vector &vector, idx_t count) override; @@ -379,7 +397,7 @@ class BasicColumnWriter : public ColumnWriter { static void WriteLevels(WriteStream &temp_writer, const unsafe_vector &levels, idx_t max_value, idx_t start_offset, idx_t count); - virtual duckdb_parquet::Encoding::type GetEncoding(BasicColumnWriterState &state); + virtual duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state); void NextPage(BasicColumnWriterState &state); void FlushPage(BasicColumnWriterState &state); @@ -407,18 +425,18 @@ class BasicColumnWriter : public ColumnWriter { void WriteDictionary(BasicColumnWriterState &state, unique_ptr temp_writer, idx_t row_count); virtual void FlushDictionary(BasicColumnWriterState &state, ColumnWriterStatistics *stats); - void SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::ColumnChunk &column); - void RegisterToRowGroup(duckdb_parquet::RowGroup &row_group); + void SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::format::ColumnChunk &column); + void RegisterToRowGroup(duckdb_parquet::format::RowGroup &row_group); }; -unique_ptr BasicColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { +unique_ptr BasicColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); RegisterToRowGroup(row_group); return std::move(result); } -void BasicColumnWriter::RegisterToRowGroup(duckdb_parquet::RowGroup &row_group) { - duckdb_parquet::ColumnChunk column_chunk; +void BasicColumnWriter::RegisterToRowGroup(duckdb_parquet::format::RowGroup &row_group) { + format::ColumnChunk column_chunk; column_chunk.__isset.meta_data = true; column_chunk.meta_data.codec = writer.GetCodec(); column_chunk.meta_data.path_in_schema = schema_path; @@ -468,7 +486,7 @@ void BasicColumnWriter::Prepare(ColumnWriterState &state_p, ColumnWriterState *p } } -duckdb_parquet::Encoding::type BasicColumnWriter::GetEncoding(BasicColumnWriterState &state) { +duckdb_parquet::format::Encoding::type BasicColumnWriter::GetEncoding(BasicColumnWriterState &state) { return Encoding::PLAIN; } @@ -628,10 +646,8 @@ void BasicColumnWriter::Write(ColumnWriterState &state_p, Vector &vector, idx_t } } -void BasicColumnWriter::SetParquetStatistics(BasicColumnWriterState &state, duckdb_parquet::ColumnChunk &column_chunk) { - if (!state.stats_state) { - return; - } +void BasicColumnWriter::SetParquetStatistics(BasicColumnWriterState &state, + duckdb_parquet::format::ColumnChunk &column_chunk) { if (max_repeat == 0) { column_chunk.meta_data.statistics.null_count = NumericCast(state.null_count); column_chunk.meta_data.statistics.__isset.null_count = true; @@ -666,11 +682,6 @@ void BasicColumnWriter::SetParquetStatistics(BasicColumnWriterState &state, duck column_chunk.meta_data.__isset.statistics = true; } for (const auto &write_info : state.write_info) { - // only care about data page encodings, data_page_header.encoding is meaningless for dict - if (write_info.page_header.type != PageType::DATA_PAGE && - write_info.page_header.type != PageType::DATA_PAGE_V2) { - continue; - } column_chunk.meta_data.encodings.push_back(write_info.page_header.data_page_header.encoding); } } @@ -717,11 +728,6 @@ void BasicColumnWriter::FinalizeWrite(ColumnWriterState &state_p) { column_chunk.meta_data.total_compressed_size = UnsafeNumericCast(column_writer.GetTotalWritten() - start_offset); column_chunk.meta_data.total_uncompressed_size = UnsafeNumericCast(total_uncompressed_size); - - if (state.bloom_filter) { - writer.BufferBloomFilter(state.col_idx, std::move(state.bloom_filter)); - } - // which row group is this? } void BasicColumnWriter::FlushDictionary(BasicColumnWriterState &state, ColumnWriterStatistics *stats) { @@ -786,47 +792,21 @@ class NumericStatisticsState : public ColumnWriterStatistics { return NumericLimits::IsSigned() ? GetMaxValue() : string(); } string GetMinValue() override { - return HasStats() ? string(char_ptr_cast(&min), sizeof(T)) : string(); + return HasStats() ? string((char *)&min, sizeof(T)) : string(); } string GetMaxValue() override { - return HasStats() ? string(char_ptr_cast(&max), sizeof(T)) : string(); + return HasStats() ? string((char *)&max, sizeof(T)) : string(); } }; struct BaseParquetOperator { - - template - static void WriteToStream(const TGT &input, WriteStream &ser) { - ser.WriteData(const_data_ptr_cast(&input), sizeof(TGT)); - } - - template - static uint64_t XXHash64(const TGT &target_value) { - return duckdb_zstd::XXH64(&target_value, sizeof(target_value), 0); - } - - template - static unique_ptr InitializeStats() { - return nullptr; - } - - template - static void HandleStats(ColumnWriterStatistics *stats, TGT target_value) { - } -}; - -struct ParquetCastOperator : public BaseParquetOperator { - template - static TGT Operation(SRC input) { - return TGT(input); - } template static unique_ptr InitializeStats() { return make_uniq>(); } template - static void HandleStats(ColumnWriterStatistics *stats, TGT target_value) { + static void HandleStats(ColumnWriterStatistics *stats, SRC source_value, TGT target_value) { auto &numeric_stats = (NumericStatisticsState &)*stats; if (LessThan::Operation(target_value, numeric_stats.min)) { numeric_stats.min = target_value; @@ -837,165 +817,24 @@ struct ParquetCastOperator : public BaseParquetOperator { } }; -struct ParquetTimestampNSOperator : public ParquetCastOperator { +struct ParquetCastOperator : public BaseParquetOperator { template static TGT Operation(SRC input) { return TGT(input); } }; -struct ParquetTimestampSOperator : public ParquetCastOperator { - template - static TGT Operation(SRC input) { - return Timestamp::FromEpochSecondsPossiblyInfinite(input).value; - } -}; - -class StringStatisticsState : public ColumnWriterStatistics { - static constexpr const idx_t MAX_STRING_STATISTICS_SIZE = 10000; - -public: - StringStatisticsState() : has_stats(false), values_too_big(false), min(), max() { - } - - bool has_stats; - bool values_too_big; - string min; - string max; - -public: - bool HasStats() override { - return has_stats; - } - - void Update(const string_t &val) { - if (values_too_big) { - return; - } - auto str_len = val.GetSize(); - if (str_len > MAX_STRING_STATISTICS_SIZE) { - // we avoid gathering stats when individual string values are too large - // this is because the statistics are copied into the Parquet file meta data in uncompressed format - // ideally we avoid placing several mega or giga-byte long strings there - // we put a threshold of 10KB, if we see strings that exceed this threshold we avoid gathering stats - values_too_big = true; - has_stats = false; - min = string(); - max = string(); - return; - } - if (!has_stats || LessThan::Operation(val, string_t(min))) { - min = val.GetString(); - } - if (!has_stats || GreaterThan::Operation(val, string_t(max))) { - max = val.GetString(); - } - has_stats = true; - } - - string GetMin() override { - return GetMinValue(); - } - string GetMax() override { - return GetMaxValue(); - } - string GetMinValue() override { - return HasStats() ? min : string(); - } - string GetMaxValue() override { - return HasStats() ? max : string(); - } -}; - -struct ParquetStringOperator : public BaseParquetOperator { - template - static TGT Operation(SRC input) { - return input; - } - - template - static unique_ptr InitializeStats() { - return make_uniq(); - } - - template - static void HandleStats(ColumnWriterStatistics *stats, TGT target_value) { - auto &string_stats = stats->Cast(); - string_stats.Update(target_value); - } - - template - static void WriteToStream(const TGT &target_value, WriteStream &ser) { - ser.Write(target_value.GetSize()); - ser.WriteData(const_data_ptr_cast(target_value.GetData()), target_value.GetSize()); - } - - template - static uint64_t XXHash64(const TGT &target_value) { - return duckdb_zstd::XXH64(target_value.GetData(), target_value.GetSize(), 0); - } -}; - -struct ParquetIntervalTargetType { - static constexpr const idx_t PARQUET_INTERVAL_SIZE = 12; - data_t bytes[PARQUET_INTERVAL_SIZE]; -}; - -struct ParquetIntervalOperator : public BaseParquetOperator { +struct ParquetTimestampNSOperator : public BaseParquetOperator { template static TGT Operation(SRC input) { - - if (input.days < 0 || input.months < 0 || input.micros < 0) { - throw IOException("Parquet files do not support negative intervals"); - } - TGT result; - Store(input.months, result.bytes); - Store(input.days, result.bytes + sizeof(uint32_t)); - Store(input.micros / 1000, result.bytes + sizeof(uint32_t) * 2); - return result; - } - - template - static void WriteToStream(const TGT &target_value, WriteStream &ser) { - ser.WriteData(target_value.bytes, ParquetIntervalTargetType::PARQUET_INTERVAL_SIZE); - } - - template - static uint64_t XXHash64(const TGT &target_value) { - return duckdb_zstd::XXH64(target_value.bytes, ParquetIntervalTargetType::PARQUET_INTERVAL_SIZE, 0); + return TGT(input); } }; -struct ParquetUUIDTargetType { - static constexpr const idx_t PARQUET_UUID_SIZE = 16; - data_t bytes[PARQUET_UUID_SIZE]; -}; - -struct ParquetUUIDOperator : public BaseParquetOperator { +struct ParquetTimestampSOperator : public BaseParquetOperator { template static TGT Operation(SRC input) { - TGT result; - uint64_t high_bytes = input.upper ^ (int64_t(1) << 63); - uint64_t low_bytes = input.lower; - for (idx_t i = 0; i < sizeof(uint64_t); i++) { - auto shift_count = (sizeof(uint64_t) - i - 1) * 8; - result.bytes[i] = (high_bytes >> shift_count) & 0xFF; - } - for (idx_t i = 0; i < sizeof(uint64_t); i++) { - auto shift_count = (sizeof(uint64_t) - i - 1) * 8; - result.bytes[sizeof(uint64_t) + i] = (low_bytes >> shift_count) & 0xFF; - } - return result; - } - - template - static void WriteToStream(const TGT &target_value, WriteStream &ser) { - ser.WriteData(target_value.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE); - } - - template - static uint64_t XXHash64(const TGT &target_value) { - return duckdb_zstd::XXH64(target_value.bytes, ParquetUUIDTargetType::PARQUET_UUID_SIZE, 0); + return Timestamp::FromEpochSecondsPossiblyInfinite(input).value; } }; @@ -1006,7 +845,7 @@ struct ParquetTimeTZOperator : public BaseParquetOperator { } }; -struct ParquetHugeintOperator : public BaseParquetOperator { +struct ParquetHugeintOperator { template static TGT Operation(SRC input) { return Hugeint::Cast(input); @@ -1018,11 +857,11 @@ struct ParquetHugeintOperator : public BaseParquetOperator { } template - static void HandleStats(ColumnWriterStatistics *stats, TGT target_value) { + static void HandleStats(ColumnWriterStatistics *stats, SRC source_value, TGT target_value) { } }; -struct ParquetUhugeintOperator : public BaseParquetOperator { +struct ParquetUhugeintOperator { template static TGT Operation(SRC input) { return Uhugeint::Cast(input); @@ -1034,13 +873,16 @@ struct ParquetUhugeintOperator : public BaseParquetOperator { } template - static void HandleStats(ColumnWriterStatistics *stats, TGT target_value) { + static void HandleStats(ColumnWriterStatistics *stats, SRC source_value, TGT target_value) { } }; template static void TemplatedWritePlain(Vector &col, ColumnWriterStatistics *stats, const idx_t chunk_start, - const idx_t chunk_end, const ValidityMask &mask, WriteStream &ser) { + const idx_t chunk_end, ValidityMask &mask, WriteStream &ser) { + static constexpr idx_t WRITE_COMBINER_CAPACITY = 8; + TGT write_combiner[WRITE_COMBINER_CAPACITY]; + idx_t write_combiner_count = 0; const auto *ptr = FlatVector::GetData(col); for (idx_t r = chunk_start; r < chunk_end; r++) { @@ -1048,589 +890,368 @@ static void TemplatedWritePlain(Vector &col, ColumnWriterStatistics *stats, cons continue; } TGT target_value = OP::template Operation(ptr[r]); - OP::template HandleStats(stats, target_value); - OP::template WriteToStream(target_value, ser); + OP::template HandleStats(stats, ptr[r], target_value); + write_combiner[write_combiner_count++] = target_value; + if (write_combiner_count == WRITE_COMBINER_CAPACITY) { + ser.WriteData(const_data_ptr_cast(write_combiner), WRITE_COMBINER_CAPACITY * sizeof(TGT)); + write_combiner_count = 0; + } } + ser.WriteData(const_data_ptr_cast(write_combiner), write_combiner_count * sizeof(TGT)); } -template -class StandardColumnWriterState : public BasicColumnWriterState { +template +class StandardColumnWriter : public BasicColumnWriter { public: - StandardColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) - : BasicColumnWriterState(row_group, col_idx) { + StandardColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, // NOLINT + idx_t max_repeat, idx_t max_define, bool can_have_nulls) + : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { + } + ~StandardColumnWriter() override = default; + +public: + unique_ptr InitializeStatsState() override { + return OP::template InitializeStats(); } - ~StandardColumnWriterState() override = default; - // analysis state for integer values for DELTA_BINARY_PACKED/DELTA_LENGTH_BYTE_ARRAY - idx_t total_value_count = 0; - idx_t total_string_size = 0; + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats, ColumnWriterPageState *page_state, + Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { + auto &mask = FlatVector::Validity(input_column); + TemplatedWritePlain(input_column, stats, chunk_start, chunk_end, mask, temp_writer); + } - unordered_map dictionary; - duckdb_parquet::Encoding::type encoding; + idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { + return sizeof(TGT); + } }; -template -class StandardWriterPageState : public ColumnWriterPageState { +//===--------------------------------------------------------------------===// +// Boolean Column Writer +//===--------------------------------------------------------------------===// +class BooleanStatisticsState : public ColumnWriterStatistics { public: - explicit StandardWriterPageState(const idx_t total_value_count, const idx_t total_string_size, - Encoding::type encoding_p, const unordered_map &dictionary_p) - : encoding(encoding_p), dbp_initialized(false), dbp_encoder(total_value_count), dlba_initialized(false), - dlba_encoder(total_value_count, total_string_size), bss_encoder(total_value_count, sizeof(TGT)), - dictionary(dictionary_p), dict_written_value(false), - dict_bit_width(RleBpDecoder::ComputeBitWidth(dictionary.size())), dict_encoder(dict_bit_width) { + BooleanStatisticsState() : min(true), max(false) { } - duckdb_parquet::Encoding::type encoding; - - bool dbp_initialized; - DbpEncoder dbp_encoder; - bool dlba_initialized; - DlbaEncoder dlba_encoder; + bool min; + bool max; - BssEncoder bss_encoder; +public: + bool HasStats() override { + return !(min && !max); + } - const unordered_map &dictionary; - bool dict_written_value; - uint32_t dict_bit_width; - RleBpEncoder dict_encoder; + string GetMin() override { + return GetMinValue(); + } + string GetMax() override { + return GetMaxValue(); + } + string GetMinValue() override { + return HasStats() ? string(const_char_ptr_cast(&min), sizeof(bool)) : string(); + } + string GetMaxValue() override { + return HasStats() ? string(const_char_ptr_cast(&max), sizeof(bool)) : string(); + } }; -namespace dbp_encoder { - -template -void BeginWrite(DbpEncoder &encoder, WriteStream &writer, const T &first_value) { - throw InternalException("Can't write type to DELTA_BINARY_PACKED column"); -} +class BooleanWriterPageState : public ColumnWriterPageState { +public: + uint8_t byte = 0; + uint8_t byte_pos = 0; +}; -template <> -void BeginWrite(DbpEncoder &encoder, WriteStream &writer, const int64_t &first_value) { - encoder.BeginWrite(writer, first_value); -} +class BooleanColumnWriter : public BasicColumnWriter { +public: + BooleanColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, + idx_t max_define, bool can_have_nulls) + : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { + } + ~BooleanColumnWriter() override = default; -template <> -void BeginWrite(DbpEncoder &encoder, WriteStream &writer, const int32_t &first_value) { - BeginWrite(encoder, writer, UnsafeNumericCast(first_value)); -} +public: + unique_ptr InitializeStatsState() override { + return make_uniq(); + } -template <> -void BeginWrite(DbpEncoder &encoder, WriteStream &writer, const uint64_t &first_value) { - encoder.BeginWrite(writer, UnsafeNumericCast(first_value)); -} + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *state_p, + Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { + auto &stats = stats_p->Cast(); + auto &state = state_p->Cast(); + auto &mask = FlatVector::Validity(input_column); -template <> -void BeginWrite(DbpEncoder &encoder, WriteStream &writer, const uint32_t &first_value) { - BeginWrite(encoder, writer, UnsafeNumericCast(first_value)); -} + auto *ptr = FlatVector::GetData(input_column); + for (idx_t r = chunk_start; r < chunk_end; r++) { + if (mask.RowIsValid(r)) { + // only encode if non-null + if (ptr[r]) { + stats.max = true; + state.byte |= 1 << state.byte_pos; + } else { + stats.min = false; + } + state.byte_pos++; -template -void WriteValue(DbpEncoder &encoder, WriteStream &writer, const T &value) { - throw InternalException("Can't write type to DELTA_BINARY_PACKED column"); -} + if (state.byte_pos == 8) { + temp_writer.Write(state.byte); + state.byte = 0; + state.byte_pos = 0; + } + } + } + } -template <> -void WriteValue(DbpEncoder &encoder, WriteStream &writer, const int64_t &value) { - encoder.WriteValue(writer, value); -} + unique_ptr InitializePageState(BasicColumnWriterState &state) override { + return make_uniq(); + } -template <> -void WriteValue(DbpEncoder &encoder, WriteStream &writer, const int32_t &value) { - WriteValue(encoder, writer, UnsafeNumericCast(value)); -} + void FlushPageState(WriteStream &temp_writer, ColumnWriterPageState *state_p) override { + auto &state = state_p->Cast(); + if (state.byte_pos > 0) { + temp_writer.Write(state.byte); + state.byte = 0; + state.byte_pos = 0; + } + } -template <> -void WriteValue(DbpEncoder &encoder, WriteStream &writer, const uint64_t &value) { - encoder.WriteValue(writer, UnsafeNumericCast(value)); -} - -template <> -void WriteValue(DbpEncoder &encoder, WriteStream &writer, const uint32_t &value) { - WriteValue(encoder, writer, UnsafeNumericCast(value)); -} - -} // namespace dbp_encoder - -namespace dlba_encoder { - -template -void BeginWrite(DlbaEncoder &encoder, WriteStream &writer, const T &first_value) { - throw InternalException("Can't write type to DELTA_LENGTH_BYTE_ARRAY column"); -} - -template <> -void BeginWrite(DlbaEncoder &encoder, WriteStream &writer, const string_t &first_value) { - encoder.BeginWrite(writer, first_value); -} - -template -void WriteValue(DlbaEncoder &encoder, WriteStream &writer, const T &value) { - throw InternalException("Can't write type to DELTA_LENGTH_BYTE_ARRAY column"); -} - -template <> -void WriteValue(DlbaEncoder &encoder, WriteStream &writer, const string_t &value) { - encoder.WriteValue(writer, value); -} - -// helpers to get size from strings -template -static constexpr idx_t GetDlbaStringSize(const SRC &src_value) { - return 0; -} - -template <> -idx_t GetDlbaStringSize(const string_t &src_value) { - return src_value.GetSize(); -} - -} // namespace dlba_encoder - -namespace bss_encoder { - -template -void WriteValue(BssEncoder &encoder, const T &value) { - throw InternalException("Can't write type to BYTE_STREAM_SPLIT column"); -} + idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { + return sizeof(bool); + } +}; -template <> -void WriteValue(BssEncoder &encoder, const float &value) { - encoder.WriteValue(value); -} +//===--------------------------------------------------------------------===// +// Decimal Column Writer +//===--------------------------------------------------------------------===// +static void WriteParquetDecimal(hugeint_t input, data_ptr_t result) { + bool positive = input >= 0; + // numbers are stored as two's complement so some muckery is required + if (!positive) { + input = NumericLimits::Maximum() + input + 1; + } + uint64_t high_bytes = uint64_t(input.upper); + uint64_t low_bytes = input.lower; -template <> -void WriteValue(BssEncoder &encoder, const double &value) { - encoder.WriteValue(value); + for (idx_t i = 0; i < sizeof(uint64_t); i++) { + auto shift_count = (sizeof(uint64_t) - i - 1) * 8; + result[i] = (high_bytes >> shift_count) & 0xFF; + } + for (idx_t i = 0; i < sizeof(uint64_t); i++) { + auto shift_count = (sizeof(uint64_t) - i - 1) * 8; + result[sizeof(uint64_t) + i] = (low_bytes >> shift_count) & 0xFF; + } + if (!positive) { + result[0] |= 0x80; + } } -} // namespace bss_encoder - -template -class StandardColumnWriter : public BasicColumnWriter { +class FixedDecimalStatistics : public ColumnWriterStatistics { public: - StandardColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, // NOLINT - idx_t max_repeat, idx_t max_define, bool can_have_nulls) - : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { + FixedDecimalStatistics() : min(NumericLimits::Maximum()), max(NumericLimits::Minimum()) { } - ~StandardColumnWriter() override = default; + + hugeint_t min; + hugeint_t max; public: - unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override { - auto result = make_uniq>(row_group, row_group.columns.size()); - result->encoding = Encoding::RLE_DICTIONARY; - RegisterToRowGroup(row_group); - return std::move(result); + string GetStats(hugeint_t &input) { + data_t buffer[16]; + WriteParquetDecimal(input, buffer); + return string(const_char_ptr_cast(buffer), 16); } - unique_ptr InitializePageState(BasicColumnWriterState &state_p) override { - auto &state = state_p.Cast>(); - - auto result = make_uniq>(state.total_value_count, state.total_string_size, - state.encoding, state.dictionary); - return std::move(result); + bool HasStats() override { + return min <= max; } - void FlushPageState(WriteStream &temp_writer, ColumnWriterPageState *state_p) override { - auto &page_state = state_p->Cast>(); - switch (page_state.encoding) { - case Encoding::DELTA_BINARY_PACKED: - if (!page_state.dbp_initialized) { - dbp_encoder::BeginWrite(page_state.dbp_encoder, temp_writer, 0); - } - page_state.dbp_encoder.FinishWrite(temp_writer); - break; - case Encoding::RLE_DICTIONARY: - D_ASSERT(page_state.dict_bit_width != 0); - if (!page_state.dict_written_value) { - // all values are null - // just write the bit width - temp_writer.Write(page_state.dict_bit_width); - return; - } - page_state.dict_encoder.FinishWrite(temp_writer); - break; - case Encoding::DELTA_LENGTH_BYTE_ARRAY: - if (!page_state.dlba_initialized) { - dlba_encoder::BeginWrite(page_state.dlba_encoder, temp_writer, string_t("")); - } - page_state.dlba_encoder.FinishWrite(temp_writer); - break; - case Encoding::BYTE_STREAM_SPLIT: - page_state.bss_encoder.FinishWrite(temp_writer); - break; - case Encoding::PLAIN: - break; - default: - throw InternalException("Unknown encoding"); + void Update(hugeint_t &val) { + if (LessThan::Operation(val, min)) { + min = val; + } + if (GreaterThan::Operation(val, max)) { + max = val; } } - Encoding::type GetEncoding(BasicColumnWriterState &state_p) override { - auto &state = state_p.Cast>(); - return state.encoding; - } - - bool HasAnalyze() override { - return true; + string GetMin() override { + return GetMinValue(); } - - void Analyze(ColumnWriterState &state_p, ColumnWriterState *parent, Vector &vector, idx_t count) override { - auto &state = state_p.Cast>(); - - auto data_ptr = FlatVector::GetData(vector); - idx_t vector_index = 0; - uint32_t new_value_index = state.dictionary.size(); - - const bool check_parent_empty = parent && !parent->is_empty.empty(); - const idx_t parent_index = state.definition_levels.size(); - - const idx_t vcount = - check_parent_empty ? parent->definition_levels.size() - state.definition_levels.size() : count; - - const auto &validity = FlatVector::Validity(vector); - - for (idx_t i = 0; i < vcount; i++) { - if (check_parent_empty && parent->is_empty[parent_index + i]) { - continue; - } - if (validity.RowIsValid(vector_index)) { - const auto &src_value = data_ptr[vector_index]; - if (state.dictionary.size() <= writer.DictionarySizeLimit()) { - if (state.dictionary.find(src_value) == state.dictionary.end()) { - state.dictionary[src_value] = new_value_index; - new_value_index++; - } - } - state.total_value_count++; - state.total_string_size += dlba_encoder::GetDlbaStringSize(src_value); - } - vector_index++; - } + string GetMax() override { + return GetMaxValue(); } - - void FinalizeAnalyze(ColumnWriterState &state_p) override { - const auto type = writer.GetType(schema_idx); - - auto &state = state_p.Cast>(); - if (state.dictionary.size() == 0 || state.dictionary.size() > writer.DictionarySizeLimit()) { - // If we aren't doing dictionary encoding, the following encodings are virtually always better than PLAIN - switch (type) { - case Type::type::INT32: - case Type::type::INT64: - state.encoding = Encoding::DELTA_BINARY_PACKED; - break; - case Type::type::BYTE_ARRAY: - state.encoding = Encoding::DELTA_LENGTH_BYTE_ARRAY; - break; - case Type::type::FLOAT: - case Type::type::DOUBLE: - state.encoding = Encoding::BYTE_STREAM_SPLIT; - break; - default: - state.encoding = Encoding::PLAIN; - } - state.dictionary.clear(); - } + string GetMinValue() override { + return HasStats() ? GetStats(min) : string(); } - - unique_ptr InitializeStatsState() override { - return OP::template InitializeStats(); + string GetMaxValue() override { + return HasStats() ? GetStats(max) : string(); } +}; - bool HasDictionary(BasicColumnWriterState &state_p) override { - auto &state = state_p.Cast>(); - return state.encoding == Encoding::RLE_DICTIONARY; +class FixedDecimalColumnWriter : public BasicColumnWriter { +public: + FixedDecimalColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, + idx_t max_define, bool can_have_nulls) + : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { } + ~FixedDecimalColumnWriter() override = default; - idx_t DictionarySize(BasicColumnWriterState &state_p) override { - auto &state = state_p.Cast>(); - return state.dictionary.size(); +public: + unique_ptr InitializeStatsState() override { + return make_uniq(); } - void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats, ColumnWriterPageState *page_state_p, + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *page_state, Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { - auto &page_state = page_state_p->Cast>(); - - const auto &mask = FlatVector::Validity(input_column); - const auto *data_ptr = FlatVector::GetData(input_column); - - switch (page_state.encoding) { - case Encoding::RLE_DICTIONARY: { - for (idx_t r = chunk_start; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - auto &src_val = data_ptr[r]; - auto value_index = page_state.dictionary.at(src_val); - if (!page_state.dict_written_value) { - // first value - // write the bit-width as a one-byte entry - temp_writer.Write(page_state.dict_bit_width); - // now begin writing the actual value - page_state.dict_encoder.BeginWrite(temp_writer, value_index); - page_state.dict_written_value = true; - } else { - page_state.dict_encoder.WriteValue(temp_writer, value_index); - } - } - break; - } - case Encoding::DELTA_BINARY_PACKED: { - idx_t r = chunk_start; - if (!page_state.dbp_initialized) { - // find first non-null value - for (; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - const TGT target_value = OP::template Operation(data_ptr[r]); - OP::template HandleStats(stats, target_value); - dbp_encoder::BeginWrite(page_state.dbp_encoder, temp_writer, target_value); - page_state.dbp_initialized = true; - r++; // skip over - break; - } - } - - for (; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - const TGT target_value = OP::template Operation(data_ptr[r]); - OP::template HandleStats(stats, target_value); - dbp_encoder::WriteValue(page_state.dbp_encoder, temp_writer, target_value); - } - break; - } - case Encoding::DELTA_LENGTH_BYTE_ARRAY: { - idx_t r = chunk_start; - if (!page_state.dlba_initialized) { - // find first non-null value - for (; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - const TGT target_value = OP::template Operation(data_ptr[r]); - OP::template HandleStats(stats, target_value); - dlba_encoder::BeginWrite(page_state.dlba_encoder, temp_writer, target_value); - page_state.dlba_initialized = true; - r++; // skip over - break; - } - } + auto &mask = FlatVector::Validity(input_column); + auto *ptr = FlatVector::GetData(input_column); + auto &stats = stats_p->Cast(); - for (; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - const TGT target_value = OP::template Operation(data_ptr[r]); - OP::template HandleStats(stats, target_value); - dlba_encoder::WriteValue(page_state.dlba_encoder, temp_writer, target_value); - } - break; - } - case Encoding::BYTE_STREAM_SPLIT: { - for (idx_t r = chunk_start; r < chunk_end; r++) { - if (!mask.RowIsValid(r)) { - continue; - } - const TGT target_value = OP::template Operation(data_ptr[r]); - OP::template HandleStats(stats, target_value); - bss_encoder::WriteValue(page_state.bss_encoder, target_value); + data_t temp_buffer[16]; + for (idx_t r = chunk_start; r < chunk_end; r++) { + if (mask.RowIsValid(r)) { + stats.Update(ptr[r]); + WriteParquetDecimal(ptr[r], temp_buffer); + temp_writer.WriteData(temp_buffer, 16); } - break; - } - case Encoding::PLAIN: { - D_ASSERT(page_state.encoding == Encoding::PLAIN); - TemplatedWritePlain(input_column, stats, chunk_start, chunk_end, mask, temp_writer); - break; - } - default: - throw InternalException("Unknown encoding"); } } - void FlushDictionary(BasicColumnWriterState &state_p, ColumnWriterStatistics *stats) override { - auto &state = state_p.Cast>(); - - D_ASSERT(state.encoding == Encoding::RLE_DICTIONARY); - - // first we need to sort the values in index order - auto values = vector(state.dictionary.size()); - for (const auto &entry : state.dictionary) { - values[entry.second] = entry.first; - } - - state.bloom_filter = - make_uniq(state.dictionary.size(), writer.BloomFilterFalsePositiveRatio()); - - // first write the contents of the dictionary page to a temporary buffer - auto temp_writer = make_uniq(MaxValue( - NextPowerOfTwo(state.dictionary.size() * sizeof(TGT)), MemoryStream::DEFAULT_INITIAL_CAPACITY)); - for (idx_t r = 0; r < values.size(); r++) { - const TGT target_value = OP::template Operation(values[r]); - // update the statistics - OP::template HandleStats(stats, target_value); - // update the bloom filter - auto hash = OP::template XXHash64(target_value); - state.bloom_filter->FilterInsert(hash); - // actually write the dictionary value - OP::template WriteToStream(target_value, *temp_writer); - } - // flush the dictionary page and add it to the to-be-written pages - WriteDictionary(state, std::move(temp_writer), values.size()); - // bloom filter will be queued for writing in ParquetWriter::BufferBloomFilter one level up - } - - // TODO this now vastly over-estimates the page size - idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state_p) const override { - return sizeof(TGT); + idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { + return sizeof(hugeint_t); } }; //===--------------------------------------------------------------------===// -// Boolean Column Writer +// UUID Column Writer //===--------------------------------------------------------------------===// -class BooleanStatisticsState : public ColumnWriterStatistics { -public: - BooleanStatisticsState() : min(true), max(false) { - } - - bool min; - bool max; - -public: - bool HasStats() override { - return !(min && !max); - } - - string GetMin() override { - return GetMinValue(); - } - string GetMax() override { - return GetMaxValue(); - } - string GetMinValue() override { - return HasStats() ? string(const_char_ptr_cast(&min), sizeof(bool)) : string(); - } - string GetMaxValue() override { - return HasStats() ? string(const_char_ptr_cast(&max), sizeof(bool)) : string(); - } -}; - -class BooleanWriterPageState : public ColumnWriterPageState { -public: - uint8_t byte = 0; - uint8_t byte_pos = 0; -}; +class UUIDColumnWriter : public BasicColumnWriter { + static constexpr const idx_t PARQUET_UUID_SIZE = 16; -class BooleanColumnWriter : public BasicColumnWriter { public: - BooleanColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, - idx_t max_define, bool can_have_nulls) + UUIDColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, + idx_t max_define, bool can_have_nulls) : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { } - ~BooleanColumnWriter() override = default; + ~UUIDColumnWriter() override = default; public: - unique_ptr InitializeStatsState() override { - return make_uniq(); + static void WriteParquetUUID(hugeint_t input, data_ptr_t result) { + uint64_t high_bytes = input.upper ^ (int64_t(1) << 63); + uint64_t low_bytes = input.lower; + + for (idx_t i = 0; i < sizeof(uint64_t); i++) { + auto shift_count = (sizeof(uint64_t) - i - 1) * 8; + result[i] = (high_bytes >> shift_count) & 0xFF; + } + for (idx_t i = 0; i < sizeof(uint64_t); i++) { + auto shift_count = (sizeof(uint64_t) - i - 1) * 8; + result[sizeof(uint64_t) + i] = (low_bytes >> shift_count) & 0xFF; + } } - void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *state_p, + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *page_state, Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { - auto &stats = stats_p->Cast(); - auto &state = state_p->Cast(); auto &mask = FlatVector::Validity(input_column); + auto *ptr = FlatVector::GetData(input_column); - auto *ptr = FlatVector::GetData(input_column); + data_t temp_buffer[PARQUET_UUID_SIZE]; for (idx_t r = chunk_start; r < chunk_end; r++) { if (mask.RowIsValid(r)) { - // only encode if non-null - if (ptr[r]) { - stats.max = true; - state.byte |= 1 << state.byte_pos; - } else { - stats.min = false; - } - state.byte_pos++; - - if (state.byte_pos == 8) { - temp_writer.Write(state.byte); - state.byte = 0; - state.byte_pos = 0; - } + WriteParquetUUID(ptr[r], temp_buffer); + temp_writer.WriteData(temp_buffer, PARQUET_UUID_SIZE); } } } - unique_ptr InitializePageState(BasicColumnWriterState &state) override { - return make_uniq(); + idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { + return PARQUET_UUID_SIZE; } +}; - void FlushPageState(WriteStream &temp_writer, ColumnWriterPageState *state_p) override { - auto &state = state_p->Cast(); - if (state.byte_pos > 0) { - temp_writer.Write(state.byte); - state.byte = 0; - state.byte_pos = 0; +//===--------------------------------------------------------------------===// +// Interval Column Writer +//===--------------------------------------------------------------------===// +class IntervalColumnWriter : public BasicColumnWriter { + static constexpr const idx_t PARQUET_INTERVAL_SIZE = 12; + +public: + IntervalColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, + idx_t max_define, bool can_have_nulls) + : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { + } + ~IntervalColumnWriter() override = default; + +public: + static void WriteParquetInterval(interval_t input, data_ptr_t result) { + if (input.days < 0 || input.months < 0 || input.micros < 0) { + throw IOException("Parquet files do not support negative intervals"); + } + Store(input.months, result); + Store(input.days, result + sizeof(uint32_t)); + Store(input.micros / 1000, result + sizeof(uint32_t) * 2); + } + + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *page_state, + Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { + auto &mask = FlatVector::Validity(input_column); + auto *ptr = FlatVector::GetData(input_column); + + data_t temp_buffer[PARQUET_INTERVAL_SIZE]; + for (idx_t r = chunk_start; r < chunk_end; r++) { + if (mask.RowIsValid(r)) { + WriteParquetInterval(ptr[r], temp_buffer); + temp_writer.WriteData(temp_buffer, PARQUET_INTERVAL_SIZE); + } } } idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { - return sizeof(bool); + return PARQUET_INTERVAL_SIZE; } }; //===--------------------------------------------------------------------===// -// Decimal Column Writer +// String Column Writer //===--------------------------------------------------------------------===// -static void WriteParquetDecimal(hugeint_t input, data_ptr_t result) { - bool positive = input >= 0; - // numbers are stored as two's complement so some muckery is required - if (!positive) { - input = NumericLimits::Maximum() + input + 1; - } - uint64_t high_bytes = uint64_t(input.upper); - uint64_t low_bytes = input.lower; - - for (idx_t i = 0; i < sizeof(uint64_t); i++) { - auto shift_count = (sizeof(uint64_t) - i - 1) * 8; - result[i] = (high_bytes >> shift_count) & 0xFF; - } - for (idx_t i = 0; i < sizeof(uint64_t); i++) { - auto shift_count = (sizeof(uint64_t) - i - 1) * 8; - result[sizeof(uint64_t) + i] = (low_bytes >> shift_count) & 0xFF; - } - if (!positive) { - result[0] |= 0x80; - } -} +class StringStatisticsState : public ColumnWriterStatistics { + static constexpr const idx_t MAX_STRING_STATISTICS_SIZE = 10000; -class FixedDecimalStatistics : public ColumnWriterStatistics { public: - FixedDecimalStatistics() : min(NumericLimits::Maximum()), max(NumericLimits::Minimum()) { + StringStatisticsState() : has_stats(false), values_too_big(false), min(), max() { } - hugeint_t min; - hugeint_t max; + bool has_stats; + bool values_too_big; + string min; + string max; public: - string GetStats(hugeint_t &input) { - data_t buffer[16]; - WriteParquetDecimal(input, buffer); - return string(const_char_ptr_cast(buffer), 16); - } - bool HasStats() override { - return min <= max; + return has_stats; } - void Update(hugeint_t &val) { - if (LessThan::Operation(val, min)) { - min = val; + void Update(const string_t &val) { + if (values_too_big) { + return; } - if (GreaterThan::Operation(val, max)) { - max = val; + auto str_len = val.GetSize(); + if (str_len > MAX_STRING_STATISTICS_SIZE) { + // we avoid gathering stats when individual string values are too large + // this is because the statistics are copied into the Parquet file meta data in uncompressed format + // ideally we avoid placing several mega or giga-byte long strings there + // we put a threshold of 10KB, if we see strings that exceed this threshold we avoid gathering stats + values_too_big = true; + has_stats = false; + min = string(); + max = string(); + return; + } + if (!has_stats || LessThan::Operation(val, string_t(min))) { + min = val.GetString(); + } + if (!has_stats || GreaterThan::Operation(val, string_t(max))) { + max = val.GetString(); } + has_stats = true; } string GetMin() override { @@ -1640,44 +1261,264 @@ class FixedDecimalStatistics : public ColumnWriterStatistics { return GetMaxValue(); } string GetMinValue() override { - return HasStats() ? GetStats(min) : string(); + return HasStats() ? min : string(); } string GetMaxValue() override { - return HasStats() ? GetStats(max) : string(); + return HasStats() ? max : string(); } }; -class FixedDecimalColumnWriter : public BasicColumnWriter { +class StringColumnWriterState : public BasicColumnWriterState { public: - FixedDecimalColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, - idx_t max_define, bool can_have_nulls) + StringColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + : BasicColumnWriterState(row_group, col_idx) { + } + ~StringColumnWriterState() override = default; + + // analysis state + idx_t estimated_dict_page_size = 0; + idx_t estimated_rle_pages_size = 0; + idx_t estimated_plain_size = 0; + + // Dictionary and accompanying string heap + string_map_t dictionary; + // key_bit_width== 0 signifies the chunk is written in plain encoding + uint32_t key_bit_width; + + bool IsDictionaryEncoded() const { + return key_bit_width != 0; + } +}; + +class StringWriterPageState : public ColumnWriterPageState { +public: + explicit StringWriterPageState(uint32_t bit_width, const string_map_t &values) + : bit_width(bit_width), dictionary(values), encoder(bit_width), written_value(false) { + D_ASSERT(IsDictionaryEncoded() || (bit_width == 0 && dictionary.empty())); + } + + bool IsDictionaryEncoded() { + return bit_width != 0; + } + // if 0, we're writing a plain page + uint32_t bit_width; + const string_map_t &dictionary; + RleBpEncoder encoder; + bool written_value; +}; + +class StringColumnWriter : public BasicColumnWriter { +public: + StringColumnWriter(ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, + idx_t max_define, bool can_have_nulls) : BasicColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls) { } - ~FixedDecimalColumnWriter() override = default; + ~StringColumnWriter() override = default; public: unique_ptr InitializeStatsState() override { - return make_uniq(); + return make_uniq(); } - void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *page_state, + unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override { + auto result = make_uniq(row_group, row_group.columns.size()); + RegisterToRowGroup(row_group); + return std::move(result); + } + + bool HasAnalyze() override { + return true; + } + + void Analyze(ColumnWriterState &state_p, ColumnWriterState *parent, Vector &vector, idx_t count) override { + auto &state = state_p.Cast(); + if (writer.DictionaryCompressionRatioThreshold() == NumericLimits::Maximum() || + (state.dictionary.size() > DICTIONARY_ANALYZE_THRESHOLD && WontUseDictionary(state))) { + // Early out: compression ratio is less than the specified parameter + // after seeing more entries than the threshold + return; + } + + idx_t vcount = parent ? parent->definition_levels.size() - state.definition_levels.size() : count; + idx_t parent_index = state.definition_levels.size(); + auto &validity = FlatVector::Validity(vector); + idx_t vector_index = 0; + uint32_t new_value_index = state.dictionary.size(); + uint32_t last_value_index = -1; + idx_t run_length = 0; + idx_t run_count = 0; + auto strings = FlatVector::GetData(vector); + for (idx_t i = 0; i < vcount; i++) { + if (parent && !parent->is_empty.empty() && parent->is_empty[parent_index + i]) { + continue; + } + + if (validity.RowIsValid(vector_index)) { + run_length++; + const auto &value = strings[vector_index]; + // Try to insert into the dictionary. If it's already there, we get back the value index + auto found = state.dictionary.insert(string_map_t::value_type(value, new_value_index)); + state.estimated_plain_size += value.GetSize() + STRING_LENGTH_SIZE; + if (found.second) { + // string didn't exist yet in the dictionary + new_value_index++; + state.estimated_dict_page_size += value.GetSize() + MAX_DICTIONARY_KEY_SIZE; + } + + // if the value changed, we will encode it in the page + if (last_value_index != found.first->second) { + // we will add the value index size later, when we know the total number of keys + state.estimated_rle_pages_size += GetVarintSize(run_length); + run_length = 0; + run_count++; + last_value_index = found.first->second; + } + } + vector_index++; + } + // Add the costs of keys sizes. We don't know yet how many bytes the keys need as we haven't + // seen all the values. therefore we use an over-estimation of + state.estimated_rle_pages_size += MAX_DICTIONARY_KEY_SIZE * run_count; + } + + void FinalizeAnalyze(ColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + + // check if a dictionary will require more space than a plain write, or if the dictionary page is going to + // be too large + if (WontUseDictionary(state)) { + // clearing the dictionary signals a plain write + state.dictionary.clear(); + state.key_bit_width = 0; + } else { + state.key_bit_width = RleBpDecoder::ComputeBitWidth(state.dictionary.size()); + } + } + + void WriteVector(WriteStream &temp_writer, ColumnWriterStatistics *stats_p, ColumnWriterPageState *page_state_p, Vector &input_column, idx_t chunk_start, idx_t chunk_end) override { + auto &page_state = page_state_p->Cast(); auto &mask = FlatVector::Validity(input_column); - auto *ptr = FlatVector::GetData(input_column); - auto &stats = stats_p->Cast(); + auto &stats = stats_p->Cast(); - data_t temp_buffer[16]; - for (idx_t r = chunk_start; r < chunk_end; r++) { - if (mask.RowIsValid(r)) { + auto *ptr = FlatVector::GetData(input_column); + if (page_state.IsDictionaryEncoded()) { + // dictionary based page + for (idx_t r = chunk_start; r < chunk_end; r++) { + if (!mask.RowIsValid(r)) { + continue; + } + auto value_index = page_state.dictionary.at(ptr[r]); + if (!page_state.written_value) { + // first value + // write the bit-width as a one-byte entry + temp_writer.Write(page_state.bit_width); + // now begin writing the actual value + page_state.encoder.BeginWrite(temp_writer, value_index); + page_state.written_value = true; + } else { + page_state.encoder.WriteValue(temp_writer, value_index); + } + } + } else { + // plain page + for (idx_t r = chunk_start; r < chunk_end; r++) { + if (!mask.RowIsValid(r)) { + continue; + } stats.Update(ptr[r]); - WriteParquetDecimal(ptr[r], temp_buffer); - temp_writer.WriteData(temp_buffer, 16); + temp_writer.Write(ptr[r].GetSize()); + temp_writer.WriteData(const_data_ptr_cast(ptr[r].GetData()), ptr[r].GetSize()); } } } - idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state) const override { - return sizeof(hugeint_t); + unique_ptr InitializePageState(BasicColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + return make_uniq(state.key_bit_width, state.dictionary); + } + + void FlushPageState(WriteStream &temp_writer, ColumnWriterPageState *state_p) override { + auto &page_state = state_p->Cast(); + if (page_state.bit_width != 0) { + if (!page_state.written_value) { + // all values are null + // just write the bit width + temp_writer.Write(page_state.bit_width); + return; + } + page_state.encoder.FinishWrite(temp_writer); + } + } + + duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + return state.IsDictionaryEncoded() ? Encoding::RLE_DICTIONARY : Encoding::PLAIN; + } + + bool HasDictionary(BasicColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + return state.IsDictionaryEncoded(); + } + + idx_t DictionarySize(BasicColumnWriterState &state_p) override { + auto &state = state_p.Cast(); + D_ASSERT(state.IsDictionaryEncoded()); + return state.dictionary.size(); + } + + void FlushDictionary(BasicColumnWriterState &state_p, ColumnWriterStatistics *stats_p) override { + auto &stats = stats_p->Cast(); + auto &state = state_p.Cast(); + if (!state.IsDictionaryEncoded()) { + return; + } + // first we need to sort the values in index order + auto values = vector(state.dictionary.size()); + for (const auto &entry : state.dictionary) { + D_ASSERT(values[entry.second].GetSize() == 0); + values[entry.second] = entry.first; + } + // first write the contents of the dictionary page to a temporary buffer + auto temp_writer = make_uniq( + MaxValue(NextPowerOfTwo(state.estimated_dict_page_size), MemoryStream::DEFAULT_INITIAL_CAPACITY)); + for (idx_t r = 0; r < values.size(); r++) { + auto &value = values[r]; + // update the statistics + stats.Update(value); + // write this string value to the dictionary + temp_writer->Write(value.GetSize()); + temp_writer->WriteData(const_data_ptr_cast((value.GetData())), value.GetSize()); + } + // flush the dictionary page and add it to the to-be-written pages + WriteDictionary(state, std::move(temp_writer), values.size()); + } + + idx_t GetRowSize(const Vector &vector, const idx_t index, const BasicColumnWriterState &state_p) const override { + auto &state = state_p.Cast(); + if (state.IsDictionaryEncoded()) { + return (state.key_bit_width + 7) / 8; + } else { + auto strings = FlatVector::GetData(vector); + return strings[index].GetSize(); + } + } + +private: + bool WontUseDictionary(StringColumnWriterState &state) const { + return state.estimated_dict_page_size > MAX_UNCOMPRESSED_DICT_PAGE_SIZE || + DictionaryCompressionRatio(state) < writer.DictionaryCompressionRatioThreshold(); + } + + static double DictionaryCompressionRatio(StringColumnWriterState &state) { + // If any are 0, we just return a compression ratio of 1 + if (state.estimated_plain_size == 0 || state.estimated_rle_pages_size == 0 || + state.estimated_dict_page_size == 0) { + return 1; + } + // Otherwise, plain size divided by compressed size + return double(state.estimated_plain_size) / + double(state.estimated_rle_pages_size + state.estimated_dict_page_size); } }; @@ -1686,42 +1527,40 @@ class FixedDecimalColumnWriter : public BasicColumnWriter { //===--------------------------------------------------------------------===// // Used to store the metadata for a WKB-encoded geometry column when writing // GeoParquet files. -class WKBColumnWriterState final : public StandardColumnWriterState { +class WKBColumnWriterState final : public StringColumnWriterState { public: - WKBColumnWriterState(ClientContext &context, duckdb_parquet::RowGroup &row_group, idx_t col_idx) - : StandardColumnWriterState(row_group, col_idx), geo_data(), geo_data_writer(context) { + WKBColumnWriterState(ClientContext &context, duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + : StringColumnWriterState(row_group, col_idx), geo_data(), geo_data_writer(context) { } GeoParquetColumnMetadata geo_data; GeoParquetColumnMetadataWriter geo_data_writer; }; -class WKBColumnWriter final : public StandardColumnWriter { +class WKBColumnWriter final : public StringColumnWriter { public: WKBColumnWriter(ClientContext &context_p, ParquetWriter &writer, idx_t schema_idx, vector schema_path_p, idx_t max_repeat, idx_t max_define, bool can_have_nulls, string name) - : StandardColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls), + : StringColumnWriter(writer, schema_idx, std::move(schema_path_p), max_repeat, max_define, can_have_nulls), column_name(std::move(name)), context(context_p) { this->writer.GetGeoParquetData().RegisterGeometryColumn(column_name); } - unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override { + unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override { auto result = make_uniq(context, row_group, row_group.columns.size()); - result->encoding = Encoding::RLE_DICTIONARY; RegisterToRowGroup(row_group); return std::move(result); } - void Write(ColumnWriterState &state, Vector &vector, idx_t count) override { - StandardColumnWriter::Write(state, vector, count); + StringColumnWriter::Write(state, vector, count); auto &geo_state = state.Cast(); geo_state.geo_data_writer.Update(geo_state.geo_data, vector, count); } void FinalizeWrite(ColumnWriterState &state) override { - StandardColumnWriter::FinalizeWrite(state); + StringColumnWriter::FinalizeWrite(state); // Add the geodata object to the writer const auto &geo_state = state.Cast(); @@ -1819,7 +1658,7 @@ class EnumColumnWriter : public BasicColumnWriter { page_state.encoder.FinishWrite(temp_writer); } - duckdb_parquet::Encoding::type GetEncoding(BasicColumnWriterState &state) override { + duckdb_parquet::format::Encoding::type GetEncoding(BasicColumnWriterState &state) override { return Encoding::RLE_DICTIONARY; } @@ -1871,7 +1710,7 @@ class StructColumnWriter : public ColumnWriter { vector> child_writers; public: - unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; bool HasAnalyze() override; void Analyze(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void FinalizeAnalyze(ColumnWriterState &state) override; @@ -1884,17 +1723,17 @@ class StructColumnWriter : public ColumnWriter { class StructColumnWriterState : public ColumnWriterState { public: - StructColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) + StructColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { } ~StructColumnWriterState() override = default; - duckdb_parquet::RowGroup &row_group; + duckdb_parquet::format::RowGroup &row_group; idx_t col_idx; vector> child_states; }; -unique_ptr StructColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { +unique_ptr StructColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); result->child_states.reserve(child_writers.size()); @@ -1992,7 +1831,7 @@ class ListColumnWriter : public ColumnWriter { unique_ptr child_writer; public: - unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) override; + unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) override; bool HasAnalyze() override; void Analyze(ColumnWriterState &state, ColumnWriterState *parent, Vector &vector, idx_t count) override; void FinalizeAnalyze(ColumnWriterState &state) override; @@ -2005,17 +1844,18 @@ class ListColumnWriter : public ColumnWriter { class ListColumnWriterState : public ColumnWriterState { public: - ListColumnWriterState(duckdb_parquet::RowGroup &row_group, idx_t col_idx) : row_group(row_group), col_idx(col_idx) { + ListColumnWriterState(duckdb_parquet::format::RowGroup &row_group, idx_t col_idx) + : row_group(row_group), col_idx(col_idx) { } ~ListColumnWriterState() override = default; - duckdb_parquet::RowGroup &row_group; + duckdb_parquet::format::RowGroup &row_group; idx_t col_idx; unique_ptr child_state; idx_t parent_index = 0; }; -unique_ptr ListColumnWriter::InitializeWriteState(duckdb_parquet::RowGroup &row_group) { +unique_ptr ListColumnWriter::InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) { auto result = make_uniq(row_group, row_group.columns.size()); result->child_state = child_writer->InitializeWriteState(row_group); return std::move(result); @@ -2238,50 +2078,12 @@ void ArrayColumnWriter::Write(ColumnWriterState &state_p, Vector &vector, idx_t child_writer->Write(*state.child_state, array_child, count * array_size); } -// special double/float class to deal with dictionary encoding and NaN equality -struct double_na_equal { - double_na_equal() : val(0) { - } - explicit double_na_equal(const double val_p) : val(val_p) { - } - // NOLINTNEXTLINE: allow implicit conversion to double - operator double() const { - return val; - } - - bool operator==(const double &right) const { - if (std::isnan(val) && std::isnan(right)) { - return true; - } - return val == right; - } - double val; -}; - -struct float_na_equal { - float_na_equal() : val(0) { - } - explicit float_na_equal(const float val_p) : val(val_p) { - } - // NOLINTNEXTLINE: allow implicit conversion to float - operator float() const { - return val; - } - bool operator==(const float &right) const { - if (std::isnan(val) && std::isnan(right)) { - return true; - } - return val == right; - } - float val; -}; - //===--------------------------------------------------------------------===// // Create Column Writer //===--------------------------------------------------------------------===// unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &context, - vector &schemas, + vector &schemas, ParquetWriter &writer, const LogicalType &type, const string &name, vector schema_path, optional_ptr field_ids, @@ -2305,7 +2107,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont if (type.id() == LogicalTypeId::STRUCT || type.id() == LogicalTypeId::UNION) { auto &child_types = StructType::GetChildTypes(type); // set up the schema element for this struct - duckdb_parquet::SchemaElement schema_element; + duckdb_parquet::format::SchemaElement schema_element; schema_element.repetition_type = null_type; schema_element.num_children = UnsafeNumericCast(child_types.size()); schema_element.__isset.num_children = true; @@ -2335,7 +2137,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont // set up the two schema elements for the list // for some reason we only set the converted type in the OPTIONAL element // first an OPTIONAL element - duckdb_parquet::SchemaElement optional_element; + duckdb_parquet::format::SchemaElement optional_element; optional_element.repetition_type = null_type; optional_element.num_children = 1; optional_element.converted_type = ConvertedType::LIST; @@ -2352,7 +2154,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont schema_path.push_back(name); // then a REPEATED element - duckdb_parquet::SchemaElement repeated_element; + duckdb_parquet::format::SchemaElement repeated_element; repeated_element.repetition_type = FieldRepetitionType::REPEATED; repeated_element.num_children = 1; repeated_element.__isset.num_children = true; @@ -2382,7 +2184,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont // } // } // top map element - duckdb_parquet::SchemaElement top_element; + duckdb_parquet::format::SchemaElement top_element; top_element.repetition_type = null_type; top_element.num_children = 1; top_element.converted_type = ConvertedType::MAP; @@ -2399,7 +2201,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont schema_path.push_back(name); // key_value element - duckdb_parquet::SchemaElement kv_element; + duckdb_parquet::format::SchemaElement kv_element; kv_element.repetition_type = FieldRepetitionType::REPEATED; kv_element.num_children = 2; kv_element.__isset.repetition_type = true; @@ -2427,7 +2229,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont return make_uniq(writer, schema_idx, schema_path, max_repeat, max_define, std::move(struct_writer), can_have_nulls); } - duckdb_parquet::SchemaElement schema_element; + duckdb_parquet::format::SchemaElement schema_element; schema_element.type = ParquetWriter::DuckDBTypeToParquetType(type); schema_element.repetition_type = null_type; schema_element.__isset.num_children = false; @@ -2441,6 +2243,7 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont ParquetWriter::SetSchemaProperties(type, schema_element); schemas.push_back(std::move(schema_element)); schema_path.push_back(name); + if (type.id() == LogicalTypeId::BLOB && type.GetAlias() == "WKB_BLOB" && GeoParquetFileMetadata::IsGeoParquetConversionEnabled(context)) { return make_uniq(context, writer, schema_idx, std::move(schema_path), max_repeat, max_define, @@ -2496,11 +2299,11 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont return make_uniq>(writer, schema_idx, std::move(schema_path), max_repeat, max_define, can_have_nulls); case LogicalTypeId::FLOAT: - return make_uniq>(writer, schema_idx, std::move(schema_path), - max_repeat, max_define, can_have_nulls); + return make_uniq>(writer, schema_idx, std::move(schema_path), max_repeat, + max_define, can_have_nulls); case LogicalTypeId::DOUBLE: - return make_uniq>(writer, schema_idx, std::move(schema_path), - max_repeat, max_define, can_have_nulls); + return make_uniq>(writer, schema_idx, std::move(schema_path), max_repeat, + max_define, can_have_nulls); case LogicalTypeId::DECIMAL: switch (type.InternalType()) { case PhysicalType::INT16: @@ -2518,14 +2321,14 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont } case LogicalTypeId::BLOB: case LogicalTypeId::VARCHAR: - return make_uniq>( - writer, schema_idx, std::move(schema_path), max_repeat, max_define, can_have_nulls); + return make_uniq(writer, schema_idx, std::move(schema_path), max_repeat, max_define, + can_have_nulls); case LogicalTypeId::UUID: - return make_uniq>( - writer, schema_idx, std::move(schema_path), max_repeat, max_define, can_have_nulls); + return make_uniq(writer, schema_idx, std::move(schema_path), max_repeat, max_define, + can_have_nulls); case LogicalTypeId::INTERVAL: - return make_uniq>( - writer, schema_idx, std::move(schema_path), max_repeat, max_define, can_have_nulls); + return make_uniq(writer, schema_idx, std::move(schema_path), max_repeat, max_define, + can_have_nulls); case LogicalTypeId::ENUM: return make_uniq(writer, type, schema_idx, std::move(schema_path), max_repeat, max_define, can_have_nulls); @@ -2534,73 +2337,4 @@ unique_ptr ColumnWriter::CreateWriterRecursive(ClientContext &cont } } -template <> -struct NumericLimits { - static constexpr float Minimum() { - return std::numeric_limits::lowest(); - }; - static constexpr float Maximum() { - return std::numeric_limits::max(); - }; - static constexpr bool IsSigned() { - return std::is_signed::value; - } - static constexpr bool IsIntegral() { - return std::is_integral::value; - } -}; - -template <> -struct NumericLimits { - static constexpr double Minimum() { - return std::numeric_limits::lowest(); - }; - static constexpr double Maximum() { - return std::numeric_limits::max(); - }; - static constexpr bool IsSigned() { - return std::is_signed::value; - } - static constexpr bool IsIntegral() { - return std::is_integral::value; - } -}; - } // namespace duckdb - -namespace std { -template <> -struct hash { - size_t operator()(const duckdb::ParquetIntervalTargetType &val) const { - return duckdb::Hash(duckdb::const_char_ptr_cast(val.bytes), - duckdb::ParquetIntervalTargetType::PARQUET_INTERVAL_SIZE); - } -}; - -template <> -struct hash { - size_t operator()(const duckdb::ParquetUUIDTargetType &val) const { - return duckdb::Hash(duckdb::const_char_ptr_cast(val.bytes), duckdb::ParquetUUIDTargetType::PARQUET_UUID_SIZE); - } -}; - -template <> -struct hash { - size_t operator()(const duckdb::float_na_equal &val) const { - if (std::isnan(val.val)) { - return duckdb::Hash(std::numeric_limits::quiet_NaN()); - } - return duckdb::Hash(val.val); - } -}; - -template <> -struct hash { - inline size_t operator()(const duckdb::double_na_equal &val) const { - if (std::isnan(val.val)) { - return duckdb::Hash(std::numeric_limits::quiet_NaN()); - } - return duckdb::Hash(val.val); - } -}; -} // namespace std diff --git a/src/duckdb/extension/parquet/geo_parquet.cpp b/src/duckdb/extension/parquet/geo_parquet.cpp index ec252a50d..b82cd5028 100644 --- a/src/duckdb/extension/parquet/geo_parquet.cpp +++ b/src/duckdb/extension/parquet/geo_parquet.cpp @@ -176,8 +176,9 @@ void GeoParquetColumnMetadataWriter::Update(GeoParquetColumnMetadata &meta, Vect // GeoParquetFileMetadata //------------------------------------------------------------------------------ -unique_ptr GeoParquetFileMetadata::TryRead(const duckdb_parquet::FileMetaData &file_meta_data, - const ClientContext &context) { +unique_ptr +GeoParquetFileMetadata::TryRead(const duckdb_parquet::format::FileMetaData &file_meta_data, + const ClientContext &context) { // Conversion not enabled, or spatial is not loaded! if (!IsGeoParquetConversionEnabled(context)) { @@ -288,7 +289,7 @@ void GeoParquetFileMetadata::FlushColumnMeta(const string &column_name, const Ge column.bbox.Combine(meta.bbox); } -void GeoParquetFileMetadata::Write(duckdb_parquet::FileMetaData &file_meta_data) const { +void GeoParquetFileMetadata::Write(duckdb_parquet::format::FileMetaData &file_meta_data) const { yyjson_mut_doc *doc = yyjson_mut_doc_new(nullptr); yyjson_mut_val *root = yyjson_mut_obj(doc); @@ -342,7 +343,7 @@ void GeoParquetFileMetadata::Write(duckdb_parquet::FileMetaData &file_meta_data) } // Create a string from the JSON - duckdb_parquet::KeyValue kv; + duckdb_parquet::format::KeyValue kv; kv.__set_key("geo"); kv.__set_value(string(json, len)); diff --git a/src/duckdb/extension/parquet/include/boolean_column_reader.hpp b/src/duckdb/extension/parquet/include/boolean_column_reader.hpp index c37c62098..125c548dc 100644 --- a/src/duckdb/extension/parquet/include/boolean_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/boolean_column_reader.hpp @@ -40,6 +40,10 @@ class BooleanColumnReader : public TemplatedColumnReader parquet_filter_t; @@ -57,9 +57,6 @@ class ColumnReader { ParquetReader &Reader(); const LogicalType &Type() const; const SchemaElement &Schema() const; - optional_ptr GetParentSchema() const; - void SetParentSchema(const SchemaElement &parent_schema); - idx_t FileIdx() const; idx_t MaxDefine() const; idx_t MaxRepeat() const; @@ -75,7 +72,7 @@ class ColumnReader { template void PlainTemplated(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, - parquet_filter_t *filter, idx_t result_offset, Vector &result) { + parquet_filter_t &filter, idx_t result_offset, Vector &result) { if (HasDefines()) { if (CONVERSION::PlainAvailable(*plain_data, num_values)) { PlainTemplatedInternal(*plain_data, defines, num_values, filter, @@ -98,13 +95,13 @@ class ColumnReader { private: template void PlainTemplatedInternal(ByteBuffer &plain_data, const uint8_t *__restrict defines, const uint64_t num_values, - const parquet_filter_t *filter, const idx_t result_offset, Vector &result) { + const parquet_filter_t &filter, const idx_t result_offset, Vector &result) { const auto result_ptr = FlatVector::GetData(result); auto &result_mask = FlatVector::Validity(result); for (idx_t row_idx = result_offset; row_idx < result_offset + num_values; row_idx++) { - if (HAS_DEFINES && defines && defines[row_idx] != max_define) { + if (HAS_DEFINES && defines[row_idx] != max_define) { result_mask.SetInvalid(row_idx); - } else if (!filter || filter->test(row_idx)) { + } else if (filter.test(row_idx)) { result_ptr[row_idx] = UNSAFE ? CONVERSION::UnsafePlainRead(plain_data, *this) : CONVERSION::PlainRead(plain_data, *this); } else { // there is still some data there that we have to skip over @@ -120,9 +117,14 @@ class ColumnReader { protected: Allocator &GetAllocator(); // readers that use the default Read() need to implement those - virtual void Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, parquet_filter_t *filter, + virtual void Plain(shared_ptr plain_data, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, idx_t result_offset, Vector &result); + virtual void Dictionary(shared_ptr dictionary_data, idx_t num_entries); + virtual void Offsets(uint32_t *offsets, uint8_t *defines, idx_t num_values, parquet_filter_t &filter, + idx_t result_offset, Vector &result); + // these are nops for most types, but not for strings + virtual void DictReference(Vector &result); virtual void PlainReference(shared_ptr, Vector &result); virtual void PrepareDeltaLengthByteArray(ResizeableBuffer &buffer); @@ -143,7 +145,6 @@ class ColumnReader { protected: const SchemaElement &schema; - optional_ptr parent_schema; idx_t file_idx; idx_t max_define; @@ -167,11 +168,10 @@ class ColumnReader { void PreparePageV2(PageHeader &page_hdr); void DecompressInternal(CompressionCodec::type codec, const_data_ptr_t src, idx_t src_size, data_ptr_t dst, idx_t dst_size); - void ConvertDictToSelVec(uint32_t *offsets, uint8_t *defines, parquet_filter_t &filter, idx_t read_now, - idx_t result_offset); - const ColumnChunk *chunk = nullptr; - TProtocol *protocol; + const duckdb_parquet::format::ColumnChunk *chunk = nullptr; + + duckdb_apache::thrift::protocol::TProtocol *protocol; idx_t page_rows_available; idx_t group_rows_available; idx_t chunk_read_offset; @@ -193,11 +193,6 @@ class ColumnReader { ResizeableBuffer dummy_define; ResizeableBuffer dummy_repeat; - SelectionVector dictionary_selection_vector; - idx_t dictionary_size; - unique_ptr dictionary; - string dictionary_id; - public: template TARGET &Cast() { diff --git a/src/duckdb/extension/parquet/include/column_writer.hpp b/src/duckdb/extension/parquet/include/column_writer.hpp index b27254f74..65f89e596 100644 --- a/src/duckdb/extension/parquet/include/column_writer.hpp +++ b/src/duckdb/extension/parquet/include/column_writer.hpp @@ -17,8 +17,6 @@ class ParquetWriter; class ColumnWriterPageState; class BasicColumnWriterState; struct ChildFieldIDs; -class ResizeableBuffer; -class ParquetBloomFilter; class ColumnWriterState { public: @@ -82,12 +80,12 @@ class ColumnWriter { public: //! Create the column writer for a specific type recursively static unique_ptr - CreateWriterRecursive(ClientContext &context, vector &schemas, ParquetWriter &writer, - const LogicalType &type, const string &name, vector schema_path, - optional_ptr field_ids, idx_t max_repeat = 0, idx_t max_define = 1, - bool can_have_nulls = true); + CreateWriterRecursive(ClientContext &context, vector &schemas, + ParquetWriter &writer, const LogicalType &type, const string &name, + vector schema_path, optional_ptr field_ids, idx_t max_repeat = 0, + idx_t max_define = 1, bool can_have_nulls = true); - virtual unique_ptr InitializeWriteState(duckdb_parquet::RowGroup &row_group) = 0; + virtual unique_ptr InitializeWriteState(duckdb_parquet::format::RowGroup &row_group) = 0; //! indicates whether the write need to analyse the data before preparing it virtual bool HasAnalyze() { diff --git a/src/duckdb/extension/parquet/include/decode_utils.hpp b/src/duckdb/extension/parquet/include/decode_utils.hpp index d6c4a854b..3b2829d61 100644 --- a/src/duckdb/extension/parquet/include/decode_utils.hpp +++ b/src/duckdb/extension/parquet/include/decode_utils.hpp @@ -1,160 +1,40 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// decode_utils.hpp -// -// -//===----------------------------------------------------------------------===// - #pragma once -#include "duckdb/common/bitpacking.hpp" #include "resizable_buffer.hpp" namespace duckdb { - class ParquetDecodeUtils { - //===--------------------------------------------------------------------===// - // Bitpacking - //===--------------------------------------------------------------------===// -private: + +public: + template + static T ZigzagToInt(const uint64_t n) { + return T(n >> 1) ^ -T(n & 1); + } + static const uint64_t BITPACK_MASKS[]; static const uint64_t BITPACK_MASKS_SIZE; static const uint8_t BITPACK_DLEN; - static void CheckWidth(const uint8_t width) { - if (width >= BITPACK_MASKS_SIZE) { + template + static uint32_t BitUnpack(ByteBuffer &buffer, uint8_t &bitpack_pos, T *dest, uint32_t count, uint8_t width) { + if (width >= ParquetDecodeUtils::BITPACK_MASKS_SIZE) { throw InvalidInputException("The width (%d) of the bitpacked data exceeds the supported max width (%d), " "the file might be corrupted.", - width, BITPACK_MASKS_SIZE); + width, ParquetDecodeUtils::BITPACK_MASKS_SIZE); } - } + auto mask = BITPACK_MASKS[width]; -public: - template - static void BitUnpack(ByteBuffer &src, bitpacking_width_t &bitpack_pos, T *dst, idx_t count, - const bitpacking_width_t width) { - CheckWidth(width); - const auto mask = BITPACK_MASKS[width]; - src.available(count * width / BITPACK_DLEN); // check if buffer has enough space available once - if (bitpack_pos == 0 && count >= BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE) { - idx_t remainder = count % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; - idx_t aligned_count = count - remainder; - BitUnpackAlignedInternal(src, dst, aligned_count, width); - dst += aligned_count; - count = remainder; - } - for (idx_t i = 0; i < count; i++) { - auto val = (src.unsafe_get() >> bitpack_pos) & mask; + for (uint32_t i = 0; i < count; i++) { + T val = (buffer.get() >> bitpack_pos) & mask; bitpack_pos += width; while (bitpack_pos > BITPACK_DLEN) { - src.unsafe_inc(1); - val |= (static_cast(src.unsafe_get()) - << static_cast(BITPACK_DLEN - (bitpack_pos - width))) & - mask; + buffer.inc(1); + val |= (T(buffer.get()) << T(BITPACK_DLEN - (bitpack_pos - width))) & mask; bitpack_pos -= BITPACK_DLEN; } - dst[i] = val; - } - } - - template - static void BitPackAligned(T *src, data_ptr_t dst, const idx_t count, const bitpacking_width_t width) { - D_ASSERT(width < BITPACK_MASKS_SIZE); - D_ASSERT(count % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0); - BitpackingPrimitives::PackBuffer(dst, src, count, width); - } - - template - static void BitUnpackAlignedInternal(ByteBuffer &src, T *dst, const idx_t count, const bitpacking_width_t width) { - for (idx_t i = 0; i < count; i += BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE) { - const auto next_read = BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE * width / 8; - - // Buffer for alignment - T aligned_data[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE]; - - // Copy over to aligned buffer - memcpy(aligned_data, src.ptr, next_read); - - // Unpack - BitpackingPrimitives::UnPackBlock(data_ptr_cast(dst), data_ptr_cast(aligned_data), width, true); - - src.unsafe_inc(next_read); - dst += BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; + dest[i] = val; } - } - - template - static void BitUnpackAligned(ByteBuffer &src, T *dst, const idx_t count, const bitpacking_width_t width) { - CheckWidth(width); - if (count % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE != 0) { - throw InvalidInputException("Aligned bitpacking count must be a multiple of %llu", - BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE); - } - const auto read_size = count * width / BITPACK_DLEN; - src.available(read_size); // check if buffer has enough space available once - BitUnpackAlignedInternal(src, dst, count, width); - } - - //===--------------------------------------------------------------------===// - // Zigzag - //===--------------------------------------------------------------------===// -private: - //! https://lemire.me/blog/2022/11/25/making-all-your-integers-positive-with-zigzag-encoding/ - template - static typename std::enable_if::value, typename std::make_signed::type>::type - ZigzagToIntInternal(UNSIGNED x) { - return (x >> 1) ^ (-(x & 1)); - } - - template - static typename std::enable_if::value, typename std::make_unsigned::type>::type - IntToZigzagInternal(SIGNED x) { - using UNSIGNED = typename std::make_unsigned::type; - return (static_cast(x) << 1) ^ static_cast(x >> (sizeof(SIGNED) * 8 - 1)); - } - -public: - template - static typename std::enable_if::value, typename std::make_signed::type>::type - ZigzagToInt(UNSIGNED x) { - auto integer = ZigzagToIntInternal(x); - D_ASSERT(x == IntToZigzagInternal(integer)); // test roundtrip - return integer; - } - - template - static typename std::enable_if::value, typename std::make_unsigned::type>::type - IntToZigzag(SIGNED x) { - auto zigzag = IntToZigzagInternal(x); - D_ASSERT(x == ZigzagToIntInternal(zigzag)); // test roundtrip - return zigzag; - } - - //===--------------------------------------------------------------------===// - // Varint - //===--------------------------------------------------------------------===// -public: - template - static uint8_t GetVarintSize(T val) { - uint8_t res = 0; - do { - val >>= 7; - res++; - } while (val != 0); - return res; - } - - template - static void VarintEncode(T val, WriteStream &ser) { - do { - uint8_t byte = val & 127; - val >>= 7; - if (val != 0) { - byte |= 128; - } - ser.Write(byte); - } while (val != 0); + return count; } template diff --git a/src/duckdb/extension/parquet/include/geo_parquet.hpp b/src/duckdb/extension/parquet/include/geo_parquet.hpp index 0a9b0966f..e9b7ce484 100644 --- a/src/duckdb/extension/parquet/include/geo_parquet.hpp +++ b/src/duckdb/extension/parquet/include/geo_parquet.hpp @@ -119,16 +119,15 @@ class GeoParquetFileMetadata { public: // Try to read GeoParquet metadata. Returns nullptr if not found, invalid or the required spatial extension is not // available. - - static unique_ptr TryRead(const duckdb_parquet::FileMetaData &file_meta_data, + static unique_ptr TryRead(const duckdb_parquet::format::FileMetaData &file_meta_data, const ClientContext &context); - void Write(duckdb_parquet::FileMetaData &file_meta_data) const; + void Write(duckdb_parquet::format::FileMetaData &file_meta_data) const; void FlushColumnMeta(const string &column_name, const GeoParquetColumnMetadata &meta); const unordered_map &GetColumnMeta() const; unique_ptr CreateColumnReader(ParquetReader &reader, const LogicalType &logical_type, - const duckdb_parquet::SchemaElement &s_ele, idx_t schema_idx_p, + const duckdb_parquet::format::SchemaElement &s_ele, idx_t schema_idx_p, idx_t max_define_p, idx_t max_repeat_p, ClientContext &context); bool IsGeometryColumn(const string &column_name) const; diff --git a/src/duckdb/extension/parquet/include/null_column_reader.hpp b/src/duckdb/extension/parquet/include/null_column_reader.hpp index 6d89c906b..567efee3e 100644 --- a/src/duckdb/extension/parquet/include/null_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/null_column_reader.hpp @@ -25,7 +25,20 @@ class NullColumnReader : public ColumnReader { shared_ptr dict; public: - void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t *filter, + void Dictionary(shared_ptr data, idx_t num_entries) override { + dict = std::move(data); + } + + void Offsets(uint32_t *offsets, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, + idx_t result_offset, Vector &result) override { + auto &result_mask = FlatVector::Validity(result); + + for (idx_t row_idx = 0; row_idx < num_values; row_idx++) { + result_mask.SetInvalid(row_idx + result_offset); + } + } + + void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, idx_t result_offset, Vector &result) override { (void)defines; (void)plain_data; diff --git a/src/duckdb/extension/parquet/include/parquet_bss_encoder.hpp b/src/duckdb/extension/parquet/include/parquet_bss_encoder.hpp deleted file mode 100644 index 80da1726d..000000000 --- a/src/duckdb/extension/parquet/include/parquet_bss_encoder.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_bss_encoder.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "decode_utils.hpp" - -namespace duckdb { - -class BssEncoder { -public: - explicit BssEncoder(const idx_t total_value_count_p, const idx_t bit_width_p) - : total_value_count(total_value_count_p), bit_width(bit_width_p), count(0), - buffer(Allocator::DefaultAllocator().Allocate(total_value_count * bit_width + 1)) { - } - -public: - template - void WriteValue(const T &value) { - D_ASSERT(sizeof(T) == bit_width); - for (idx_t i = 0; i < sizeof(T); i++) { - buffer.get()[i * total_value_count + count] = reinterpret_cast(&value)[i]; - } - count++; - } - - void FinishWrite(WriteStream &writer) { - D_ASSERT(count == total_value_count); - writer.WriteData(buffer.get(), total_value_count * bit_width); - } - -private: - const idx_t total_value_count; - const idx_t bit_width; - - idx_t count; - AllocatedData buffer; -}; - -} // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_crypto.hpp b/src/duckdb/extension/parquet/include/parquet_crypto.hpp index 470648446..b4aed9d0c 100644 --- a/src/duckdb/extension/parquet/include/parquet_crypto.hpp +++ b/src/duckdb/extension/parquet/include/parquet_crypto.hpp @@ -4,7 +4,7 @@ // parquet_crypto.hpp // // -//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===/ #pragma once diff --git a/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp b/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp index 4925a0ff9..c40c3c026 100644 --- a/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp +++ b/src/duckdb/extension/parquet/include/parquet_dbp_decoder.hpp @@ -1,137 +1,126 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_dbp_deccoder.hpp -// -// -//===----------------------------------------------------------------------===// - #pragma once - #include "decode_utils.hpp" namespace duckdb { - class DbpDecoder { public: - DbpDecoder(const data_ptr_t buffer, const uint32_t buffer_len) - : buffer_(buffer, buffer_len), - // - block_size_in_values(ParquetDecodeUtils::VarintDecode(buffer_)), - number_of_miniblocks_per_block(ParquetDecodeUtils::VarintDecode(buffer_)), - number_of_values_in_a_miniblock(block_size_in_values / number_of_miniblocks_per_block), - total_value_count(ParquetDecodeUtils::VarintDecode(buffer_)), - previous_value(ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_))), - // init state to something sane - is_first_value(true), read_values(0), min_delta(NumericLimits::Maximum()), - miniblock_index(number_of_miniblocks_per_block - 1), list_of_bitwidths_of_miniblocks(nullptr), - miniblock_offset(number_of_values_in_a_miniblock), - unpacked_data_offset(BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE) { - if (!(block_size_in_values % number_of_miniblocks_per_block == 0 && - number_of_values_in_a_miniblock % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0)) { - throw InvalidInputException("Parquet file has invalid block sizes for DELTA_BINARY_PACKED"); - } + DbpDecoder(data_ptr_t buffer, uint32_t buffer_len) : buffer_(buffer, buffer_len) { + // + // overall header + block_value_count = ParquetDecodeUtils::VarintDecode(buffer_); + miniblocks_per_block = ParquetDecodeUtils::VarintDecode(buffer_); + total_value_count = ParquetDecodeUtils::VarintDecode(buffer_); + start_value = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); + + // some derivatives + D_ASSERT(miniblocks_per_block > 0); + values_per_miniblock = block_value_count / miniblocks_per_block; + miniblock_bit_widths = unique_ptr(new data_t[miniblocks_per_block]); + + // init state to something sane + values_left_in_block = 0; + values_left_in_miniblock = 0; + miniblock_offset = 0; + min_delta = 0; + bitpack_pos = 0; + is_first_value = true; }; - ByteBuffer BufferPtr() const { + ByteBuffer BufferPtr() { + if (bitpack_pos != 0) { + buffer_.inc(1); + bitpack_pos = 0; + } return buffer_; } - uint64_t TotalValues() const { - return total_value_count; - } - template - void GetBatch(const data_ptr_t target_values_ptr, const idx_t batch_size) { - if (read_values + batch_size > total_value_count) { - throw std::runtime_error("DBP decode did not find enough values"); - } - read_values += batch_size; - GetBatchInternal(target_values_ptr, batch_size); - } - - void Finalize() { - if (miniblock_offset == number_of_values_in_a_miniblock) { - return; - } - auto data = make_unsafe_uniq_array(number_of_values_in_a_miniblock); - GetBatchInternal(data_ptr_cast(data.get()), number_of_values_in_a_miniblock - miniblock_offset); - } + void GetBatch(data_ptr_t values_target_ptr, uint32_t batch_size) { + auto values = reinterpret_cast(values_target_ptr); -private: - template - void GetBatchInternal(const data_ptr_t target_values_ptr, const idx_t batch_size) { if (batch_size == 0) { return; } + idx_t value_offset = 0; - auto target_values = reinterpret_cast(target_values_ptr); - idx_t target_values_offset = 0; if (is_first_value) { - target_values[0] = static_cast(previous_value); - target_values_offset++; + values[0] = start_value; + value_offset++; is_first_value = false; } - while (target_values_offset < batch_size) { - // Copy over any remaining data - const idx_t next = MinValue(batch_size - target_values_offset, - BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE - unpacked_data_offset); - if (next != 0) { - for (idx_t i = 0; i < next; i++) { - auto &target = target_values[target_values_offset + i]; - const auto &unpacked_value = unpacked_data[unpacked_data_offset + i]; - target = static_cast(static_cast(previous_value) + static_cast(min_delta) + - unpacked_value); - previous_value = static_cast(target); - } - target_values_offset += next; - unpacked_data_offset += next; - continue; + if (total_value_count == 1) { // I guess it's a special case + if (batch_size > 1) { + throw std::runtime_error("DBP decode did not find enough values (have 1)"); } + return; + } - // Move to next miniblock / block - D_ASSERT(unpacked_data_offset == BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE); - D_ASSERT(miniblock_index < number_of_miniblocks_per_block); - D_ASSERT(miniblock_offset <= number_of_values_in_a_miniblock); - if (miniblock_offset == number_of_values_in_a_miniblock) { - miniblock_offset = 0; - if (++miniblock_index == number_of_miniblocks_per_block) { - // - min_delta = ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); - buffer_.available(number_of_miniblocks_per_block); - list_of_bitwidths_of_miniblocks = buffer_.ptr; - buffer_.unsafe_inc(number_of_miniblocks_per_block); - miniblock_index = 0; + while (value_offset < batch_size) { + if (values_left_in_block == 0) { // need to open new block + if (bitpack_pos > 0) { // have to eat the leftovers if any + buffer_.inc(1); + } + min_delta = + ParquetDecodeUtils::ZigzagToInt(ParquetDecodeUtils::VarintDecode(buffer_)); + for (idx_t miniblock_idx = 0; miniblock_idx < miniblocks_per_block; miniblock_idx++) { + miniblock_bit_widths[miniblock_idx] = buffer_.read(); + // TODO what happens if width is 0? } + values_left_in_block = block_value_count; + miniblock_offset = 0; + bitpack_pos = 0; + values_left_in_miniblock = values_per_miniblock; + } + if (values_left_in_miniblock == 0) { + miniblock_offset++; + values_left_in_miniblock = values_per_miniblock; } - // Unpack from current miniblock - ParquetDecodeUtils::BitUnpackAligned(buffer_, unpacked_data, - BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE, - list_of_bitwidths_of_miniblocks[miniblock_index]); - unpacked_data_offset = 0; - miniblock_offset += BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; + auto read_now = MinValue(values_left_in_miniblock, (idx_t)batch_size - value_offset); + ParquetDecodeUtils::BitUnpack(buffer_, bitpack_pos, &values[value_offset], read_now, + miniblock_bit_widths[miniblock_offset]); + for (idx_t i = value_offset; i < value_offset + read_now; i++) { + values[i] = T(uint64_t((i == 0) ? start_value : values[i - 1]) + min_delta + uint64_t(values[i])); + } + value_offset += read_now; + values_left_in_miniblock -= read_now; + values_left_in_block -= read_now; + } + + if (value_offset != batch_size) { + throw std::runtime_error("DBP decode did not find enough values"); + } + start_value = values[batch_size - 1]; + } + void Finalize() { + if (values_left_in_miniblock == 0) { + return; } + auto data = unique_ptr(new uint32_t[values_left_in_miniblock]); + GetBatch(data_ptr_cast(data.get()), values_left_in_miniblock); + } + + uint64_t TotalValues() { + return total_value_count; } private: ByteBuffer buffer_; - const idx_t block_size_in_values; - const idx_t number_of_miniblocks_per_block; - const idx_t number_of_values_in_a_miniblock; - const idx_t total_value_count; - int64_t previous_value; + idx_t block_value_count; + idx_t miniblocks_per_block; + idx_t total_value_count; + int64_t start_value; + idx_t values_per_miniblock; + + unique_ptr miniblock_bit_widths; + idx_t values_left_in_block; + idx_t values_left_in_miniblock; + idx_t miniblock_offset; + int64_t min_delta; bool is_first_value; - idx_t read_values; - //! Block stuff - int64_t min_delta; - idx_t miniblock_index; - bitpacking_width_t *list_of_bitwidths_of_miniblocks; - idx_t miniblock_offset; - uint64_t unpacked_data[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE]; - idx_t unpacked_data_offset; + uint8_t bitpack_pos; }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp b/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp deleted file mode 100644 index 791d10e08..000000000 --- a/src/duckdb/extension/parquet/include/parquet_dbp_encoder.hpp +++ /dev/null @@ -1,179 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_dbp_encoder.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "decode_utils.hpp" - -namespace duckdb { - -class DbpEncoder { -private: - static constexpr uint64_t BLOCK_SIZE_IN_VALUES = 2048; - static constexpr uint64_t NUMBER_OF_MINIBLOCKS_IN_A_BLOCK = 8; - static constexpr uint64_t NUMBER_OF_VALUES_IN_A_MINIBLOCK = BLOCK_SIZE_IN_VALUES / NUMBER_OF_MINIBLOCKS_IN_A_BLOCK; - -public: - explicit DbpEncoder(const idx_t total_value_count_p) : total_value_count(total_value_count_p), count(0) { - } - -public: - void BeginWrite(WriteStream &writer, const int64_t &first_value) { - // - - // the block size is a multiple of 128; it is stored as a ULEB128 int - ParquetDecodeUtils::VarintEncode(BLOCK_SIZE_IN_VALUES, writer); - // the miniblock count per block is a divisor of the block size such that their quotient, - // the number of values in a miniblock, is a multiple of 32 - static_assert(BLOCK_SIZE_IN_VALUES % NUMBER_OF_MINIBLOCKS_IN_A_BLOCK == 0 && - NUMBER_OF_VALUES_IN_A_MINIBLOCK % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0, - "invalid block sizes for DELTA_BINARY_PACKED"); - // it is stored as a ULEB128 int - ParquetDecodeUtils::VarintEncode(NUMBER_OF_MINIBLOCKS_IN_A_BLOCK, writer); - // the total value count is stored as a ULEB128 int - ParquetDecodeUtils::VarintEncode(total_value_count, writer); - // the first value is stored as a zigzag ULEB128 int - ParquetDecodeUtils::VarintEncode(ParquetDecodeUtils::IntToZigzag(first_value), writer); - - // initialize - if (total_value_count != 0) { - count++; - } - previous_value = first_value; - - min_delta = NumericLimits::Maximum(); - block_count = 0; - } - - void WriteValue(WriteStream &writer, const int64_t &value) { - // 1. Compute the differences between consecutive elements. For the first element in the block, - // use the last element in the previous block or, in the case of the first block, - // use the first value of the whole sequence, stored in the header. - - // Subtractions in steps 1) and 2) may incur signed arithmetic overflow, - // and so will the corresponding additions when decoding. - // Overflow should be allowed and handled as wrapping around in 2’s complement notation - // so that the original values are correctly restituted. - // This may require explicit care in some programming languages - // (for example by doing all arithmetic in the unsigned domain). - const auto delta = static_cast(static_cast(value) - static_cast(previous_value)); - previous_value = value; - // Compute the frame of reference (the minimum of the deltas in the block). - min_delta = MinValue(min_delta, delta); - // append. if block is full, write it out - data[block_count++] = delta; - if (block_count == BLOCK_SIZE_IN_VALUES) { - WriteBlock(writer); - } - } - - void FinishWrite(WriteStream &writer) { - if (count + block_count != total_value_count) { - throw InternalException("value count mismatch when writing DELTA_BINARY_PACKED"); - } - if (block_count != 0) { - WriteBlock(writer); - } - } - -private: - void WriteBlock(WriteStream &writer) { - D_ASSERT(count + block_count == total_value_count || block_count == BLOCK_SIZE_IN_VALUES); - const auto number_of_miniblocks = - (block_count + NUMBER_OF_VALUES_IN_A_MINIBLOCK - 1) / NUMBER_OF_VALUES_IN_A_MINIBLOCK; - for (idx_t miniblock_idx = 0; miniblock_idx < number_of_miniblocks; miniblock_idx++) { - for (idx_t i = 0; i < NUMBER_OF_VALUES_IN_A_MINIBLOCK; i++) { - const idx_t index = miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK + i; - auto &value = data[index]; - if (index < block_count) { - // 2. Compute the frame of reference (the minimum of the deltas in the block). - // Subtract this min delta from all deltas in the block. - // This guarantees that all values are non-negative. - D_ASSERT(min_delta <= value); - value = static_cast(static_cast(value) - static_cast(min_delta)); - } else { - // If there are not enough values to fill the last miniblock, we pad the miniblock - // so that its length is always the number of values in a full miniblock multiplied by the bit - // width. The values of the padding bits should be zero, but readers must accept paddings consisting - // of arbitrary bits as well. - value = 0; - } - } - } - - for (idx_t miniblock_idx = 0; miniblock_idx < NUMBER_OF_MINIBLOCKS_IN_A_BLOCK; miniblock_idx++) { - auto &width = list_of_bitwidths_of_miniblocks[miniblock_idx]; - if (miniblock_idx < number_of_miniblocks) { - const auto src = &data[miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK]; - width = BitpackingPrimitives::MinimumBitWidth(reinterpret_cast(src), - NUMBER_OF_VALUES_IN_A_MINIBLOCK); - D_ASSERT(width <= sizeof(int64_t) * 8); - } else { - // If, in the last block, less than miniblocks are needed to store the - // values, the bytes storing the bit widths of the unneeded miniblocks are still present, their value - // should be zero, but readers must accept arbitrary values as well. There are no additional padding - // bytes for the miniblock bodies though, as if their bit widths were 0 (regardless of the actual byte - // values). The reader knows when to stop reading by keeping track of the number of values read. - width = 0; - } - } - - // 3. Encode the frame of reference (min delta) as a zigzag ULEB128 int - // followed by the bit widths of the miniblocks - // and the delta values (minus the min delta) bit-packed per miniblock. - // - - // the min delta is a zigzag ULEB128 int (we compute a minimum as we need positive integers for bit packing) - ParquetDecodeUtils::VarintEncode(ParquetDecodeUtils::IntToZigzag(min_delta), writer); - // the bitwidth of each block is stored as a byte - writer.WriteData(list_of_bitwidths_of_miniblocks, NUMBER_OF_MINIBLOCKS_IN_A_BLOCK); - // each miniblock is a list of bit packed ints according to the bit width stored at the beginning of the block - for (idx_t miniblock_idx = 0; miniblock_idx < number_of_miniblocks; miniblock_idx++) { - const auto src = &data[miniblock_idx * NUMBER_OF_VALUES_IN_A_MINIBLOCK]; - const auto &width = list_of_bitwidths_of_miniblocks[miniblock_idx]; - memset(data_packed, 0, sizeof(data_packed)); - ParquetDecodeUtils::BitPackAligned(reinterpret_cast(src), data_packed, - NUMBER_OF_VALUES_IN_A_MINIBLOCK, width); - const auto write_size = NUMBER_OF_VALUES_IN_A_MINIBLOCK * width / 8; -#ifdef DEBUG - // immediately verify that unpacking yields the input data - int64_t verification_data[NUMBER_OF_VALUES_IN_A_MINIBLOCK]; - ByteBuffer byte_buffer(data_ptr_cast(data_packed), write_size); - bitpacking_width_t bitpack_pos = 0; - ParquetDecodeUtils::BitUnpack(byte_buffer, bitpack_pos, verification_data, NUMBER_OF_VALUES_IN_A_MINIBLOCK, - width); - for (idx_t i = 0; i < NUMBER_OF_VALUES_IN_A_MINIBLOCK; i++) { - D_ASSERT(src[i] == verification_data[i]); - } -#endif - writer.WriteData(data_packed, write_size); - } - - count += block_count; - - min_delta = NumericLimits::Maximum(); - block_count = 0; - } - -private: - //! Overall fields - const idx_t total_value_count; - idx_t count; - int64_t previous_value; - - //! Block-specific fields - int64_t min_delta; - int64_t data[BLOCK_SIZE_IN_VALUES]; - idx_t block_count; - - //! Bitpacking fields - bitpacking_width_t list_of_bitwidths_of_miniblocks[NUMBER_OF_MINIBLOCKS_IN_A_BLOCK]; - data_t data_packed[NUMBER_OF_VALUES_IN_A_MINIBLOCK * sizeof(int64_t)]; -}; - -} // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp b/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp index 119ed5672..4f189bbcf 100644 --- a/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp +++ b/src/duckdb/extension/parquet/include/parquet_decimal_utils.hpp @@ -16,7 +16,8 @@ namespace duckdb { class ParquetDecimalUtils { public: template - static PHYSICAL_TYPE ReadDecimalValue(const_data_ptr_t pointer, idx_t size, const duckdb_parquet::SchemaElement &) { + static PHYSICAL_TYPE ReadDecimalValue(const_data_ptr_t pointer, idx_t size, + const duckdb_parquet::format::SchemaElement &) { PHYSICAL_TYPE res = 0; auto res_ptr = (uint8_t *)&res; @@ -53,6 +54,6 @@ class ParquetDecimalUtils { template <> double ParquetDecimalUtils::ReadDecimalValue(const_data_ptr_t pointer, idx_t size, - const duckdb_parquet::SchemaElement &schema_ele); + const duckdb_parquet::format::SchemaElement &schema_ele); } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_dlba_encoder.hpp b/src/duckdb/extension/parquet/include/parquet_dlba_encoder.hpp deleted file mode 100644 index b3cd1aa96..000000000 --- a/src/duckdb/extension/parquet/include/parquet_dlba_encoder.hpp +++ /dev/null @@ -1,48 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_dlba_encoder.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "parquet_dbp_encoder.hpp" -#include "duckdb/common/serializer/memory_stream.hpp" - -namespace duckdb { - -class DlbaEncoder { -public: - DlbaEncoder(const idx_t total_value_count_p, const idx_t total_string_size_p) - : dbp_encoder(total_value_count_p), total_string_size(total_string_size_p), - buffer(Allocator::DefaultAllocator().Allocate(total_string_size + 1)), - stream(make_unsafe_uniq(buffer.get(), buffer.GetSize())) { - } - -public: - void BeginWrite(WriteStream &writer, const string_t &first_value) { - dbp_encoder.BeginWrite(writer, UnsafeNumericCast(first_value.GetSize())); - stream->WriteData(const_data_ptr_cast(first_value.GetData()), first_value.GetSize()); - } - - void WriteValue(WriteStream &writer, const string_t &value) { - dbp_encoder.WriteValue(writer, UnsafeNumericCast(value.GetSize())); - stream->WriteData(const_data_ptr_cast(value.GetData()), value.GetSize()); - } - - void FinishWrite(WriteStream &writer) { - D_ASSERT(stream->GetPosition() == total_string_size); - dbp_encoder.FinishWrite(writer); - writer.WriteData(buffer.get(), total_string_size); - } - -private: - DbpEncoder dbp_encoder; - const idx_t total_string_size; - AllocatedData buffer; - unsafe_unique_ptr stream; -}; - -} // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_extension.hpp b/src/duckdb/extension/parquet/include/parquet_extension.hpp index 413a104b6..702adb382 100644 --- a/src/duckdb/extension/parquet/include/parquet_extension.hpp +++ b/src/duckdb/extension/parquet/include/parquet_extension.hpp @@ -1,11 +1,3 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_extension.hpp -// -// -//===----------------------------------------------------------------------===/ - #pragma once #include "duckdb.hpp" diff --git a/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp b/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp index b7373056f..48b6448de 100644 --- a/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp +++ b/src/duckdb/extension/parquet/include/parquet_file_metadata_cache.hpp @@ -20,7 +20,7 @@ class ParquetFileMetadataCache : public ObjectCacheEntry { public: ParquetFileMetadataCache() : metadata(nullptr) { } - ParquetFileMetadataCache(unique_ptr file_metadata, time_t r_time, + ParquetFileMetadataCache(unique_ptr file_metadata, time_t r_time, unique_ptr geo_metadata) : metadata(std::move(file_metadata)), read_time(r_time), geo_metadata(std::move(geo_metadata)) { } @@ -28,7 +28,7 @@ class ParquetFileMetadataCache : public ObjectCacheEntry { ~ParquetFileMetadataCache() override = default; //! Parquet file metadata - unique_ptr metadata; + unique_ptr metadata; //! read time time_t read_time; diff --git a/src/duckdb/extension/parquet/include/parquet_metadata.hpp b/src/duckdb/extension/parquet/include/parquet_metadata.hpp index 09ecd5afa..2310e1de8 100644 --- a/src/duckdb/extension/parquet/include/parquet_metadata.hpp +++ b/src/duckdb/extension/parquet/include/parquet_metadata.hpp @@ -33,9 +33,4 @@ class ParquetFileMetadataFunction : public TableFunction { ParquetFileMetadataFunction(); }; -class ParquetBloomProbeFunction : public TableFunction { -public: - ParquetBloomProbeFunction(); -}; - } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_reader.hpp b/src/duckdb/extension/parquet/include/parquet_reader.hpp index 79de2b4cc..6b536bbd5 100644 --- a/src/duckdb/extension/parquet/include/parquet_reader.hpp +++ b/src/duckdb/extension/parquet/include/parquet_reader.hpp @@ -138,7 +138,7 @@ class ParquetReader { //! Index of the file_row_number column idx_t file_row_number_idx = DConstants::INVALID_INDEX; //! Parquet schema for the generated columns - vector generated_column_schema; + vector generated_column_schema; //! Table column names - set when using COPY tbl FROM file.parquet vector table_columns; @@ -167,7 +167,7 @@ class ParquetReader { idx_t NumRows(); idx_t NumRowGroups(); - const duckdb_parquet::FileMetaData *GetFileMetadata(); + const duckdb_parquet::format::FileMetaData *GetFileMetadata(); uint32_t Read(duckdb_apache::thrift::TBase &object, TProtocol &iprot); uint32_t ReadData(duckdb_apache::thrift::protocol::TProtocol &iprot, const data_ptr_t buffer, @@ -202,10 +202,9 @@ class ParquetReader { bool ScanInternal(ParquetReaderScanState &state, DataChunk &output); unique_ptr CreateReader(ClientContext &context); - unique_ptr CreateReaderRecursive(ClientContext &context, const vector &indexes, - idx_t depth, idx_t max_define, idx_t max_repeat, - idx_t &next_schema_idx, idx_t &next_file_idx); - const duckdb_parquet::RowGroup &GetGroup(ParquetReaderScanState &state); + unique_ptr CreateReaderRecursive(ClientContext &context, idx_t depth, idx_t max_define, + idx_t max_repeat, idx_t &next_schema_idx, idx_t &next_file_idx); + const duckdb_parquet::format::RowGroup &GetGroup(ParquetReaderScanState &state); uint64_t GetGroupCompressedSize(ParquetReaderScanState &state); idx_t GetGroupOffset(ParquetReaderScanState &state); // Group span is the distance between the min page offset and the max page offset plus the max page compressed size diff --git a/src/duckdb/extension/parquet/include/parquet_rle_bp_decoder.hpp b/src/duckdb/extension/parquet/include/parquet_rle_bp_decoder.hpp index b8dc35b35..49583f714 100644 --- a/src/duckdb/extension/parquet/include/parquet_rle_bp_decoder.hpp +++ b/src/duckdb/extension/parquet/include/parquet_rle_bp_decoder.hpp @@ -40,7 +40,11 @@ class RleBpDecoder { values_read += repeat_batch; } else if (literal_count_ > 0) { uint32_t literal_batch = MinValue(batch_size - values_read, static_cast(literal_count_)); - ParquetDecodeUtils::BitUnpack(buffer_, bitpack_pos, values + values_read, literal_batch, bit_width_); + uint32_t actual_read = ParquetDecodeUtils::BitUnpack(buffer_, bitpack_pos, values + values_read, + literal_batch, bit_width_); + if (literal_batch != actual_read) { + throw std::runtime_error("Did not find enough values"); + } literal_count_ -= literal_batch; values_read += literal_batch; } else { diff --git a/src/duckdb/extension/parquet/include/parquet_statistics.hpp b/src/duckdb/extension/parquet/include/parquet_statistics.hpp index ad1f939c8..94ce194e2 100644 --- a/src/duckdb/extension/parquet/include/parquet_statistics.hpp +++ b/src/duckdb/extension/parquet/include/parquet_statistics.hpp @@ -1,11 +1,3 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// parquet_statistics.hpp -// -// -//===----------------------------------------------------------------------===/ - #pragma once #include "duckdb.hpp" @@ -16,95 +8,19 @@ namespace duckdb { -using duckdb_parquet::ColumnChunk; -using duckdb_parquet::SchemaElement; +using duckdb_parquet::format::ColumnChunk; +using duckdb_parquet::format::SchemaElement; struct LogicalType; class ColumnReader; -class ResizeableBuffer; struct ParquetStatisticsUtils { static unique_ptr TransformColumnStatistics(const ColumnReader &reader, const vector &columns); - static Value ConvertValue(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, + static Value ConvertValue(const LogicalType &type, const duckdb_parquet::format::SchemaElement &schema_ele, const std::string &stats); - - static bool BloomFilterSupported(const LogicalTypeId &type_id); - - static bool BloomFilterExcludes(const TableFilter &filter, const duckdb_parquet::ColumnMetaData &column_meta_data, - duckdb_apache::thrift::protocol::TProtocol &file_proto, Allocator &allocator); - -private: - static Value ConvertValueInternal(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, - const std::string &stats); -}; - -class ParquetBloomFilter { - static constexpr const idx_t DEFAULT_BLOCK_COUNT = 32; // 4k filter - -public: - ParquetBloomFilter(idx_t num_entries, double bloom_filter_false_positive_ratio); - ParquetBloomFilter(unique_ptr data_p); - void FilterInsert(uint64_t x); - bool FilterCheck(uint64_t x); - void Shrink(idx_t new_block_count); - double OneRatio(); - ResizeableBuffer *Get(); - -private: - unique_ptr data; - idx_t block_count; -}; - -// see https://github.com/apache/parquet-format/blob/master/BloomFilter.md - -struct ParquetBloomBlock { - struct ParquetBloomMaskResult { - uint8_t bit_set[8] = {0}; - }; - - uint32_t block[8] = {0}; - - static bool check_bit(uint32_t &x, const uint8_t i) { - D_ASSERT(i < 32); - return (x >> i) & (uint32_t)1; - } - - static void set_bit(uint32_t &x, const uint8_t i) { - D_ASSERT(i < 32); - x |= (uint32_t)1 << i; - D_ASSERT(check_bit(x, i)); - } - - static ParquetBloomMaskResult Mask(uint32_t x) { - static const uint32_t parquet_bloom_salt[8] = {0x47b6137bU, 0x44974d91U, 0x8824ad5bU, 0xa2b7289dU, - 0x705495c7U, 0x2df1424bU, 0x9efc4947U, 0x5c6bfb31U}; - ParquetBloomMaskResult result; - for (idx_t i = 0; i < 8; i++) { - result.bit_set[i] = (x * parquet_bloom_salt[i]) >> 27; - } - return result; - } - - static void BlockInsert(ParquetBloomBlock &b, uint32_t x) { - auto masked = Mask(x); - for (idx_t i = 0; i < 8; i++) { - set_bit(b.block[i], masked.bit_set[i]); - D_ASSERT(check_bit(b.block[i], masked.bit_set[i])); - } - } - - static bool BlockCheck(ParquetBloomBlock &b, uint32_t x) { - auto masked = Mask(x); - for (idx_t i = 0; i < 8; i++) { - if (!check_bit(b.block[i], masked.bit_set[i])) { - return false; - } - } - return true; - } }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/parquet_writer.hpp b/src/duckdb/extension/parquet/include/parquet_writer.hpp index e601926b2..297d2efa6 100644 --- a/src/duckdb/extension/parquet/include/parquet_writer.hpp +++ b/src/duckdb/extension/parquet/include/parquet_writer.hpp @@ -19,7 +19,6 @@ #include "duckdb/function/copy_function.hpp" #endif -#include "parquet_statistics.hpp" #include "column_writer.hpp" #include "parquet_types.h" #include "geo_parquet.hpp" @@ -34,7 +33,7 @@ class Serializer; class Deserializer; struct PreparedRowGroup { - duckdb_parquet::RowGroup row_group; + duckdb_parquet::format::RowGroup row_group; vector> states; vector> heaps; }; @@ -62,19 +61,13 @@ struct FieldID { static FieldID Deserialize(Deserializer &source); }; -struct ParquetBloomFilterEntry { - unique_ptr bloom_filter; - idx_t row_group_idx; - idx_t column_idx; -}; - class ParquetWriter { public: ParquetWriter(ClientContext &context, FileSystem &fs, string file_name, vector types, - vector names, duckdb_parquet::CompressionCodec::type codec, ChildFieldIDs field_ids, + vector names, duckdb_parquet::format::CompressionCodec::type codec, ChildFieldIDs field_ids, const vector> &kv_metadata, - shared_ptr encryption_config, idx_t dictionary_size_limit, - double bloom_filter_false_positive_ratio, int64_t compression_level, bool debug_use_openssl); + shared_ptr encryption_config, double dictionary_compression_ratio_threshold, + optional_idx compression_level, bool debug_use_openssl); public: void PrepareRowGroup(ColumnDataCollection &buffer, PreparedRowGroup &result); @@ -82,16 +75,16 @@ class ParquetWriter { void Flush(ColumnDataCollection &buffer); void Finalize(); - static duckdb_parquet::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type); - static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele); + static duckdb_parquet::format::Type::type DuckDBTypeToParquetType(const LogicalType &duckdb_type); + static void SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::format::SchemaElement &schema_ele); duckdb_apache::thrift::protocol::TProtocol *GetProtocol() { return protocol.get(); } - duckdb_parquet::CompressionCodec::type GetCodec() { + duckdb_parquet::format::CompressionCodec::type GetCodec() { return codec; } - duckdb_parquet::Type::type GetType(idx_t schema_idx) { + duckdb_parquet::format::Type::type GetType(idx_t schema_idx) { return file_meta_data.schema[schema_idx].type; } LogicalType GetSQLType(idx_t schema_idx) const { @@ -104,13 +97,10 @@ class ParquetWriter { lock_guard glock(lock); return writer->total_written; } - idx_t DictionarySizeLimit() const { - return dictionary_size_limit; + double DictionaryCompressionRatioThreshold() const { + return dictionary_compression_ratio_threshold; } - double BloomFilterFalsePositiveRatio() const { - return bloom_filter_false_positive_ratio; - } - int64_t CompressionLevel() const { + optional_idx CompressionLevel() const { return compression_level; } idx_t NumberOfRowGroups() { @@ -124,32 +114,28 @@ class ParquetWriter { GeoParquetFileMetadata &GetGeoParquetData(); static bool TryGetParquetType(const LogicalType &duckdb_type, - optional_ptr type = nullptr); - - void BufferBloomFilter(idx_t col_idx, unique_ptr bloom_filter); + optional_ptr type = nullptr); private: string file_name; vector sql_types; vector column_names; - duckdb_parquet::CompressionCodec::type codec; + duckdb_parquet::format::CompressionCodec::type codec; ChildFieldIDs field_ids; shared_ptr encryption_config; - idx_t dictionary_size_limit; - double bloom_filter_false_positive_ratio; - int64_t compression_level; + double dictionary_compression_ratio_threshold; + optional_idx compression_level; bool debug_use_openssl; shared_ptr encryption_util; unique_ptr writer; std::shared_ptr protocol; - duckdb_parquet::FileMetaData file_meta_data; + duckdb_parquet::format::FileMetaData file_meta_data; std::mutex lock; vector> column_writers; unique_ptr geoparquet_data; - vector bloom_filters; }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/include/resizable_buffer.hpp b/src/duckdb/extension/parquet/include/resizable_buffer.hpp index 14658ecee..65b639bab 100644 --- a/src/duckdb/extension/parquet/include/resizable_buffer.hpp +++ b/src/duckdb/extension/parquet/include/resizable_buffer.hpp @@ -5,7 +5,6 @@ // // //===----------------------------------------------------------------------===// - #pragma once #include "duckdb.hpp" diff --git a/src/duckdb/extension/parquet/include/string_column_reader.hpp b/src/duckdb/extension/parquet/include/string_column_reader.hpp index 2ab96a296..f67bbd9da 100644 --- a/src/duckdb/extension/parquet/include/string_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/string_column_reader.hpp @@ -13,8 +13,11 @@ namespace duckdb { struct StringParquetValueConversion { + static string_t DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader); + static string_t PlainRead(ByteBuffer &plain_data, ColumnReader &reader); static void PlainSkip(ByteBuffer &plain_data, ColumnReader &reader); + static bool PlainAvailable(const ByteBuffer &plain_data, const idx_t count); static string_t UnsafePlainRead(ByteBuffer &plain_data, ColumnReader &reader); static void UnsafePlainSkip(ByteBuffer &plain_data, ColumnReader &reader); @@ -27,10 +30,14 @@ class StringColumnReader : public TemplatedColumnReader dict_strings; idx_t fixed_width_string_length; idx_t delta_offset = 0; public: + void Dictionary(shared_ptr dictionary_data, idx_t num_entries) override; + void PrepareDeltaLengthByteArray(ResizeableBuffer &buffer) override; void PrepareDeltaByteArray(ResizeableBuffer &buffer) override; void DeltaByteArray(uint8_t *defines, idx_t num_values, parquet_filter_t &filter, idx_t result_offset, @@ -39,6 +46,7 @@ class StringColumnReader : public TemplatedColumnReader plain_data, Vector &result) override; }; diff --git a/src/duckdb/extension/parquet/include/struct_column_reader.hpp b/src/duckdb/extension/parquet/include/struct_column_reader.hpp index 4a0254695..b9a9b5eee 100644 --- a/src/duckdb/extension/parquet/include/struct_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/struct_column_reader.hpp @@ -24,7 +24,7 @@ class StructColumnReader : public ColumnReader { vector> child_readers; public: - ColumnReader &GetChildReader(idx_t child_idx); + ColumnReader *GetChildReader(idx_t child_idx); void InitializeRead(idx_t row_group_idx_p, const vector &columns, TProtocol &protocol_p) override; diff --git a/src/duckdb/extension/parquet/include/templated_column_reader.hpp b/src/duckdb/extension/parquet/include/templated_column_reader.hpp index d85865309..f9311524f 100644 --- a/src/duckdb/extension/parquet/include/templated_column_reader.hpp +++ b/src/duckdb/extension/parquet/include/templated_column_reader.hpp @@ -15,6 +15,10 @@ namespace duckdb { template struct TemplatedParquetValueConversion { + static VALUE_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { + D_ASSERT(offset < dict.len / sizeof(VALUE_TYPE)); + return ((VALUE_TYPE *)dict.ptr)[offset]; + } static VALUE_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { return plain_data.read(); @@ -58,16 +62,53 @@ class TemplatedColumnReader : public ColumnReader { } } - void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t *filter, + void Dictionary(shared_ptr data, idx_t num_entries) override { + dict = std::move(data); + } + + void Offsets(uint32_t *offsets, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, + idx_t result_offset, Vector &result) override { + if (HasDefines()) { + OffsetsInternal(*dict, offsets, defines, num_values, filter, result_offset, result); + } else { + OffsetsInternal(*dict, offsets, defines, num_values, filter, result_offset, result); + } + } + + void Plain(shared_ptr plain_data, uint8_t *defines, uint64_t num_values, parquet_filter_t &filter, idx_t result_offset, Vector &result) override { PlainTemplated(std::move(plain_data), defines, num_values, filter, result_offset, result); } + +private: + template + void OffsetsInternal(ResizeableBuffer &dict_ref, uint32_t *__restrict offsets, const uint8_t *__restrict defines, + const uint64_t num_values, const parquet_filter_t &filter, const idx_t result_offset, + Vector &result) { + const auto result_ptr = FlatVector::GetData(result); + auto &result_mask = FlatVector::Validity(result); + idx_t offset_idx = 0; + for (idx_t row_idx = result_offset; row_idx < result_offset + num_values; row_idx++) { + if (HAS_DEFINES && defines[row_idx] != max_define) { + result_mask.SetInvalid(row_idx); + continue; + } + if (filter.test(row_idx)) { + result_ptr[row_idx] = VALUE_CONVERSION::DictRead(dict_ref, offsets[offset_idx++], *this); + } else { + offset_idx++; + } + } + } }; template struct CallbackParquetValueConversion { + static DUCKDB_PHYSICAL_TYPE DictRead(ByteBuffer &dict, uint32_t &offset, ColumnReader &reader) { + return TemplatedParquetValueConversion::DictRead(dict, offset, reader); + } static DUCKDB_PHYSICAL_TYPE PlainRead(ByteBuffer &plain_data, ColumnReader &reader) { return FUNC(plain_data.read()); diff --git a/src/duckdb/extension/parquet/include/thrift_tools.hpp b/src/duckdb/extension/parquet/include/thrift_tools.hpp index de1eaca34..2306aa30b 100644 --- a/src/duckdb/extension/parquet/include/thrift_tools.hpp +++ b/src/duckdb/extension/parquet/include/thrift_tools.hpp @@ -1,13 +1,4 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// thrift_tools.hpp -// -// -//===----------------------------------------------------------------------===/ - #pragma once - #include #include "thrift/protocol/TCompactProtocol.h" #include "thrift/transport/TBufferTransports.h" @@ -98,10 +89,7 @@ struct ReadAheadBuffer { } if (read_head.GetEnd() > handle.GetFileSize()) { - throw std::runtime_error("Prefetch registered for bytes outside file: " + handle.GetPath() + - ", attempted range: [" + std::to_string(pos) + ", " + - std::to_string(read_head.GetEnd()) + - "), file size: " + std::to_string(handle.GetFileSize())); + throw std::runtime_error("Prefetch registered for bytes outside file"); } } diff --git a/src/duckdb/extension/parquet/include/zstd_file_system.hpp b/src/duckdb/extension/parquet/include/zstd_file_system.hpp index 5b132bc8a..230aef36d 100644 --- a/src/duckdb/extension/parquet/include/zstd_file_system.hpp +++ b/src/duckdb/extension/parquet/include/zstd_file_system.hpp @@ -26,10 +26,6 @@ class ZStdFileSystem : public CompressedFileSystem { unique_ptr CreateStream() override; idx_t InBufferSize() override; idx_t OutBufferSize() override; - - static int64_t DefaultCompressionLevel(); - static int64_t MinimumCompressionLevel(); - static int64_t MaximumCompressionLevel(); }; } // namespace duckdb diff --git a/src/duckdb/extension/parquet/parquet_extension.cpp b/src/duckdb/extension/parquet/parquet_extension.cpp index 500b89919..617dc3cac 100644 --- a/src/duckdb/extension/parquet/parquet_extension.cpp +++ b/src/duckdb/extension/parquet/parquet_extension.cpp @@ -165,7 +165,7 @@ struct ParquetReadGlobalState : public GlobalTableFunctionState { idx_t max_threads; vector projection_ids; vector scanned_types; - vector column_indexes; + vector column_ids; optional_ptr filters; idx_t MaxThreads() const override { @@ -180,27 +180,27 @@ struct ParquetReadGlobalState : public GlobalTableFunctionState { struct ParquetWriteBindData : public TableFunctionData { vector sql_types; vector column_names; - duckdb_parquet::CompressionCodec::type codec = duckdb_parquet::CompressionCodec::SNAPPY; + duckdb_parquet::format::CompressionCodec::type codec = duckdb_parquet::format::CompressionCodec::SNAPPY; vector> kv_metadata; - idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; - idx_t row_group_size_bytes = NumericLimits::Maximum(); + idx_t row_group_size = Storage::ROW_GROUP_SIZE; + + //! If row_group_size_bytes is not set, we default to row_group_size * BYTES_PER_ROW + static constexpr const idx_t BYTES_PER_ROW = 1024; + idx_t row_group_size_bytes; //! How/Whether to encrypt the data shared_ptr encryption_config; bool debug_use_openssl = true; - //! After how many distinct values should we abandon dictionary compression and bloom filters? - idx_t dictionary_size_limit = row_group_size / 100; - - //! What false positive rate are we willing to accept for bloom filters - double bloom_filter_false_positive_ratio = 0.01; + //! Dictionary compression is applied only if the compression ratio exceeds this threshold + double dictionary_compression_ratio_threshold = 1.0; //! After how many row groups to rotate to a new file optional_idx row_groups_per_file; ChildFieldIDs field_ids; //! The compression level, higher value is more - int64_t compression_level = ZStdFileSystem::DefaultCompressionLevel(); + optional_idx compression_level; }; struct ParquetWriteGlobalState : public GlobalFunctionData { @@ -209,7 +209,7 @@ struct ParquetWriteGlobalState : public GlobalFunctionData { struct ParquetWriteLocalState : public LocalFunctionData { explicit ParquetWriteLocalState(ClientContext &context, const vector &types) - : buffer(BufferAllocator::Get(context), types) { + : buffer(context, types, ColumnDataAllocatorType::HYBRID) { buffer.InitializeAppend(append_state); } @@ -285,7 +285,7 @@ static MultiFileReaderBindData BindSchema(ClientContext &context, vector &global_column_ids, + const vector &global_column_ids, optional_ptr table_filters, ClientContext &context, optional_idx file_idx, optional_ptr reader_state) { auto &parquet_options = bind_data.parquet_options; @@ -313,21 +313,15 @@ static void InitializeParquetReader(ParquetReader &reader, const ParquetReadBind unordered_map field_id_to_column_index; auto &column_readers = reader.root_reader->Cast().child_readers; for (idx_t column_index = 0; column_index < column_readers.size(); column_index++) { - auto &column_reader = *column_readers[column_index]; - auto &column_schema = column_reader.Schema(); + auto &column_schema = column_readers[column_index]->Schema(); if (column_schema.__isset.field_id) { field_id_to_column_index[column_schema.field_id] = column_index; - } else if (column_reader.GetParentSchema()) { - auto &parent_column_schema = *column_reader.GetParentSchema(); - if (parent_column_schema.__isset.field_id) { - field_id_to_column_index[parent_column_schema.field_id] = column_index; - } } } // loop through the schema definition for (idx_t i = 0; i < global_column_ids.size(); i++) { - auto global_column_index = global_column_ids[i].GetPrimaryIndex(); + auto global_column_index = global_column_ids[i]; // check if this is a constant column bool constant = false; @@ -389,11 +383,6 @@ static bool GetBooleanArgument(const pair> &option) { return BooleanValue::Get(boolean_value); } -TablePartitionInfo ParquetGetPartitionInfo(ClientContext &context, TableFunctionPartitionInput &input) { - auto &parquet_bind = input.bind_data->Cast(); - return parquet_bind.multi_file_reader->GetPartitionInfo(context, parquet_bind.reader_bind, input); -} - class ParquetScanFunction { public: static TableFunctionSet GetFunctionSet() { @@ -412,7 +401,7 @@ class ParquetScanFunction { {"type", LogicalType::VARCHAR}, {"default_value", LogicalType::VARCHAR}}})); table_function.named_parameters["encryption_config"] = LogicalTypeId::ANY; - table_function.get_partition_data = ParquetScanGetPartitionData; + table_function.get_batch_index = ParquetScanGetBatchIndex; table_function.serialize = ParquetScanSerialize; table_function.deserialize = ParquetScanDeserialize; table_function.get_bind_info = ParquetGetBindInfo; @@ -420,7 +409,6 @@ class ParquetScanFunction { table_function.filter_pushdown = true; table_function.filter_prune = true; table_function.pushdown_complex_filter = ParquetComplexFilterPushdown; - table_function.get_partition_info = ParquetGetPartitionInfo; MultiFileReader::AddParameters(table_function); @@ -473,23 +461,66 @@ class ParquetScanFunction { } // NOTE: we do not want to parse the Parquet metadata for the sole purpose of getting column statistics - if (bind_data.file_list->GetExpandResult() == FileExpandResult::MULTIPLE_FILES) { - // multiple files, no luck! - return nullptr; - } - if (!bind_data.initial_reader) { - // no reader - return nullptr; + + auto &config = DBConfig::GetConfig(context); + + if (bind_data.file_list->GetExpandResult() != FileExpandResult::MULTIPLE_FILES) { + if (bind_data.initial_reader) { + // most common path, scanning single parquet file + return bind_data.initial_reader->ReadStatistics(bind_data.names[column_index]); + } else if (!config.options.object_cache_enable) { + // our initial reader was reset + return nullptr; + } + } else if (config.options.object_cache_enable) { + // multiple files, object cache enabled: merge statistics + unique_ptr overall_stats; + + auto &cache = ObjectCache::GetObjectCache(context); + // for more than one file, we could be lucky and metadata for *every* file is in the object cache (if + // enabled at all) + FileSystem &fs = FileSystem::GetFileSystem(context); + + for (const auto &file_name : bind_data.file_list->Files()) { + auto metadata = cache.Get(file_name); + if (!metadata) { + // missing metadata entry in cache, no usable stats + return nullptr; + } + if (!fs.IsRemoteFile(file_name)) { + auto handle = fs.OpenFile(file_name, FileFlags::FILE_FLAGS_READ); + // we need to check if the metadata cache entries are current + if (fs.GetLastModifiedTime(*handle) >= metadata->read_time) { + // missing or invalid metadata entry in cache, no usable stats overall + return nullptr; + } + } else { + // for remote files we just avoid reading stats entirely + return nullptr; + } + // get and merge stats for file + auto file_stats = ParquetReader::ReadStatistics(context, bind_data.parquet_options, metadata, + bind_data.names[column_index]); + if (!file_stats) { + return nullptr; + } + if (overall_stats) { + overall_stats->Merge(*file_stats); + } else { + overall_stats = std::move(file_stats); + } + } + // success! + return overall_stats; } - // scanning single parquet file and we have the metadata read already - return bind_data.initial_reader->ReadStatistics(bind_data.names[column_index]); + // multiple files and no object cache, no luck! return nullptr; } static unique_ptr ParquetScanBindInternal(ClientContext &context, unique_ptr multi_file_reader, - shared_ptr file_list, + unique_ptr file_list, vector &return_types, vector &names, ParquetOptions parquet_options) { auto result = make_uniq(); @@ -668,7 +699,7 @@ class ParquetScanFunction { result->multi_file_reader_state = bind_data.multi_file_reader->InitializeGlobalState( context, bind_data.parquet_options.file_options, bind_data.reader_bind, file_list, bind_data.types, - bind_data.names, input.column_indexes); + bind_data.names, input.column_ids); if (file_list.IsEmpty()) { result->readers = {}; } else if (!bind_data.union_readers.empty()) { @@ -706,12 +737,12 @@ class ParquetScanFunction { if (file_name != reader_data->reader->file_name) { throw InternalException("Mismatch in filename order and reader order in parquet scan"); } - InitializeParquetReader(*reader_data->reader, bind_data, input.column_indexes, input.filters, context, + InitializeParquetReader(*reader_data->reader, bind_data, input.column_ids, input.filters, context, file_idx, result->multi_file_reader_state); } } - result->column_indexes = input.column_indexes; + result->column_ids = input.column_ids; result->filters = input.filters.get(); result->row_group_index = 0; result->file_index = 0; @@ -724,16 +755,16 @@ class ParquetScanFunction { if (!input.projection_ids.empty()) { result->projection_ids = input.projection_ids; } else { - result->projection_ids.resize(input.column_indexes.size()); + result->projection_ids.resize(input.column_ids.size()); iota(begin(result->projection_ids), end(result->projection_ids), 0); } const auto table_types = bind_data.types; - for (const auto &col_idx : input.column_indexes) { - if (col_idx.IsRowIdColumn()) { + for (const auto &col_idx : input.column_ids) { + if (IsRowIdColumnId(col_idx)) { result->scanned_types.emplace_back(LogicalType::ROW_TYPE); } else { - result->scanned_types.push_back(table_types[col_idx.GetPrimaryIndex()]); + result->scanned_types.push_back(table_types[col_idx]); } } } @@ -747,16 +778,11 @@ class ParquetScanFunction { return std::move(result); } - static OperatorPartitionData ParquetScanGetPartitionData(ClientContext &context, - TableFunctionGetPartitionInput &input) { - auto &bind_data = input.bind_data->CastNoConst(); - auto &data = input.local_state->Cast(); - auto &gstate = input.global_state->Cast(); - OperatorPartitionData partition_data(data.batch_index); - bind_data.multi_file_reader->GetPartitionData(context, bind_data.reader_bind, data.reader->reader_data, - gstate.multi_file_reader_state, input.partition_info, - partition_data); - return partition_data; + static idx_t ParquetScanGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, + GlobalTableFunctionState *global_state) { + auto &data = local_state->Cast(); + return data.batch_index; } static void ParquetScanSerialize(Serializer &serializer, const optional_ptr bind_data_p, @@ -803,18 +829,15 @@ class ParquetScanFunction { auto &gstate = data_p.global_state->Cast(); auto &bind_data = data_p.bind_data->CastNoConst(); - bool rowgroup_finished; do { if (gstate.CanRemoveColumns()) { data.all_columns.Reset(); data.reader->Scan(data.scan_state, data.all_columns); - rowgroup_finished = data.all_columns.size() == 0; bind_data.multi_file_reader->FinalizeChunk(context, bind_data.reader_bind, data.reader->reader_data, data.all_columns, gstate.multi_file_reader_state); output.ReferenceColumns(data.all_columns, gstate.projection_ids); } else { data.reader->Scan(data.scan_state, output); - rowgroup_finished = output.size() == 0; bind_data.multi_file_reader->FinalizeChunk(context, bind_data.reader_bind, data.reader->reader_data, output, gstate.multi_file_reader_state); } @@ -823,7 +846,7 @@ class ParquetScanFunction { if (output.size() > 0) { return; } - if (rowgroup_finished && !ParquetParallelStateNext(context, bind_data, data, gstate)) { + if (!ParquetParallelStateNext(context, bind_data, data, gstate)) { return; } } while (true); @@ -991,7 +1014,7 @@ class ParquetScanFunction { reader = make_shared_ptr(context, current_reader_data.file_to_be_opened, pq_options); } - InitializeParquetReader(*reader, bind_data, parallel_state.column_indexes, parallel_state.filters, + InitializeParquetReader(*reader, bind_data, parallel_state.column_ids, parallel_state.filters, context, i, parallel_state.multi_file_reader_state); } catch (...) { parallel_lock.lock(); @@ -1166,7 +1189,6 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi const vector &names, const vector &sql_types) { D_ASSERT(names.size() == sql_types.size()); bool row_group_size_bytes_set = false; - bool compression_level_set = false; auto bind_data = make_uniq(); for (auto &option : input.info.options) { const auto loption = StringUtil::Lower(option.first); @@ -1189,19 +1211,19 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi } else if (loption == "compression" || loption == "codec") { const auto roption = StringUtil::Lower(option.second[0].ToString()); if (roption == "uncompressed") { - bind_data->codec = duckdb_parquet::CompressionCodec::UNCOMPRESSED; + bind_data->codec = duckdb_parquet::format::CompressionCodec::UNCOMPRESSED; } else if (roption == "snappy") { - bind_data->codec = duckdb_parquet::CompressionCodec::SNAPPY; + bind_data->codec = duckdb_parquet::format::CompressionCodec::SNAPPY; } else if (roption == "gzip") { - bind_data->codec = duckdb_parquet::CompressionCodec::GZIP; + bind_data->codec = duckdb_parquet::format::CompressionCodec::GZIP; } else if (roption == "zstd") { - bind_data->codec = duckdb_parquet::CompressionCodec::ZSTD; + bind_data->codec = duckdb_parquet::format::CompressionCodec::ZSTD; } else if (roption == "brotli") { - bind_data->codec = duckdb_parquet::CompressionCodec::BROTLI; + bind_data->codec = duckdb_parquet::format::CompressionCodec::BROTLI; } else if (roption == "lz4" || roption == "lz4_raw") { /* LZ4 is technically another compression scheme, but deprecated and arrow also uses them * interchangeably */ - bind_data->codec = duckdb_parquet::CompressionCodec::LZ4_RAW; + bind_data->codec = duckdb_parquet::format::CompressionCodec::LZ4_RAW; } else { throw BinderException("Expected %s argument to be either [uncompressed, brotli, gzip, snappy, or zstd]", loption); @@ -1244,19 +1266,14 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi } else if (loption == "encryption_config") { bind_data->encryption_config = ParquetEncryptionConfig::Create(context, option.second[0]); } else if (loption == "dictionary_compression_ratio_threshold") { - // deprecated, ignore setting - } else if (loption == "dictionary_size_limit") { - auto val = option.second[0].GetValue(); - if (val < 0) { - throw BinderException("dictionary_size_limit must be greater than 0 or 0 to disable"); - } - bind_data->dictionary_size_limit = val; - } else if (loption == "bloom_filter_false_positive_ratio") { auto val = option.second[0].GetValue(); - if (val <= 0) { - throw BinderException("bloom_filter_false_positive_ratio must be greater than 0"); + if (val == -1) { + val = NumericLimits::Maximum(); + } else if (val < 0) { + throw BinderException("dictionary_compression_ratio_threshold must be greater than 0, or -1 to disable " + "dictionary compression"); } - bind_data->bloom_filter_false_positive_ratio = val; + bind_data->dictionary_compression_ratio_threshold = val; } else if (loption == "debug_use_openssl") { auto val = StringUtil::Lower(option.second[0].GetValue()); if (val == "false") { @@ -1267,14 +1284,7 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi throw BinderException("Expected debug_use_openssl to be a BOOLEAN"); } } else if (loption == "compression_level") { - const auto val = option.second[0].GetValue(); - if (val < ZStdFileSystem::MinimumCompressionLevel() || val > ZStdFileSystem::MaximumCompressionLevel()) { - throw BinderException("Compression level must be between %lld and %lld", - ZStdFileSystem::MinimumCompressionLevel(), - ZStdFileSystem::MaximumCompressionLevel()); - } - bind_data->compression_level = val; - compression_level_set = true; + bind_data->compression_level = option.second[0].GetValue(); } else { throw NotImplementedException("Unrecognized option for PARQUET: %s", option.first.c_str()); } @@ -1284,10 +1294,9 @@ unique_ptr ParquetWriteBind(ClientContext &context, CopyFunctionBi throw BinderException("ROW_GROUP_SIZE_BYTES does not work while preserving insertion order. Use \"SET " "preserve_insertion_order=false;\" to disable preserving insertion order."); } - } - - if (compression_level_set && bind_data->codec != CompressionCodec::ZSTD) { - throw BinderException("Compression level is only supported for the ZSTD compression codec"); + } else { + // We always set a max row group size bytes so we don't use too much memory + bind_data->row_group_size_bytes = bind_data->row_group_size * ParquetWriteBindData::BYTES_PER_ROW; } bind_data->sql_types = sql_types; @@ -1301,11 +1310,11 @@ unique_ptr ParquetWriteInitializeGlobal(ClientContext &conte auto &parquet_bind = bind_data.Cast(); auto &fs = FileSystem::GetFileSystem(context); - global_state->writer = make_uniq( - context, fs, file_path, parquet_bind.sql_types, parquet_bind.column_names, parquet_bind.codec, - parquet_bind.field_ids.Copy(), parquet_bind.kv_metadata, parquet_bind.encryption_config, - parquet_bind.dictionary_size_limit, parquet_bind.bloom_filter_false_positive_ratio, - parquet_bind.compression_level, parquet_bind.debug_use_openssl); + global_state->writer = + make_uniq(context, fs, file_path, parquet_bind.sql_types, parquet_bind.column_names, + parquet_bind.codec, parquet_bind.field_ids.Copy(), parquet_bind.kv_metadata, + parquet_bind.encryption_config, parquet_bind.dictionary_compression_ratio_threshold, + parquet_bind.compression_level, parquet_bind.debug_use_openssl); return std::move(global_state); } @@ -1350,7 +1359,8 @@ unique_ptr ParquetWriteInitializeLocal(ExecutionContext &cont // FIXME: Have these be generated instead template <> -const char *EnumUtil::ToChars(duckdb_parquet::CompressionCodec::type value) { +const char *EnumUtil::ToChars( + duckdb_parquet::format::CompressionCodec::type value) { switch (value) { case CompressionCodec::UNCOMPRESSED: return "UNCOMPRESSED"; @@ -1382,7 +1392,8 @@ const char *EnumUtil::ToChars(duckdb_par } template <> -duckdb_parquet::CompressionCodec::type EnumUtil::FromString(const char *value) { +duckdb_parquet::format::CompressionCodec::type +EnumUtil::FromString(const char *value) { if (StringUtil::Equals(value, "UNCOMPRESSED")) { return CompressionCodec::UNCOMPRESSED; } @@ -1410,23 +1421,6 @@ duckdb_parquet::CompressionCodec::type EnumUtil::FromString::Maximum() - NumericCast(AbsValue(compression_level)) - : NumericCast(compression_level); -} - -static int64_t DeserializeCompressionLevel(const optional_idx compression_level) { - // Was originally an optional_idx, now int64_t, so we still serialize as such - if (!compression_level.IsValid()) { - return ZStdFileSystem::DefaultCompressionLevel(); - } - if (compression_level.GetIndex() > NumericCast(ZStdFileSystem::MaximumCompressionLevel())) { - // restore the negative compression level - return -NumericCast(NumericLimits::Maximum() - compression_level.GetIndex()); - } - return NumericCast(compression_level.GetIndex()); -} - static void ParquetCopySerialize(Serializer &serializer, const FunctionData &bind_data_p, const CopyFunction &function) { auto &bind_data = bind_data_p.Cast(); @@ -1439,42 +1433,30 @@ static void ParquetCopySerialize(Serializer &serializer, const FunctionData &bin serializer.WriteProperty(106, "field_ids", bind_data.field_ids); serializer.WritePropertyWithDefault>(107, "encryption_config", bind_data.encryption_config, nullptr); - - // 108 was dictionary_compression_ratio_threshold, but was deleted - const auto compression_level = SerializeCompressionLevel(bind_data.compression_level); - D_ASSERT(DeserializeCompressionLevel(compression_level) == bind_data.compression_level); - serializer.WritePropertyWithDefault(109, "compression_level", compression_level); + serializer.WriteProperty(108, "dictionary_compression_ratio_threshold", + bind_data.dictionary_compression_ratio_threshold); + serializer.WritePropertyWithDefault(109, "compression_level", bind_data.compression_level); serializer.WriteProperty(110, "row_groups_per_file", bind_data.row_groups_per_file); serializer.WriteProperty(111, "debug_use_openssl", bind_data.debug_use_openssl); - serializer.WriteProperty(112, "dictionary_size_limit", bind_data.dictionary_size_limit); - serializer.WriteProperty(113, "bloom_filter_false_positive_ratio", bind_data.bloom_filter_false_positive_ratio); } static unique_ptr ParquetCopyDeserialize(Deserializer &deserializer, CopyFunction &function) { auto data = make_uniq(); data->sql_types = deserializer.ReadProperty>(100, "sql_types"); data->column_names = deserializer.ReadProperty>(101, "column_names"); - data->codec = deserializer.ReadProperty(102, "codec"); + data->codec = deserializer.ReadProperty(102, "codec"); data->row_group_size = deserializer.ReadProperty(103, "row_group_size"); data->row_group_size_bytes = deserializer.ReadProperty(104, "row_group_size_bytes"); data->kv_metadata = deserializer.ReadProperty>>(105, "kv_metadata"); data->field_ids = deserializer.ReadProperty(106, "field_ids"); deserializer.ReadPropertyWithExplicitDefault>(107, "encryption_config", data->encryption_config, nullptr); - deserializer.ReadDeletedProperty(108, "dictionary_compression_ratio_threshold"); - - optional_idx compression_level; - deserializer.ReadPropertyWithDefault(109, "compression_level", compression_level); - data->compression_level = DeserializeCompressionLevel(compression_level); - D_ASSERT(SerializeCompressionLevel(data->compression_level) == compression_level); + deserializer.ReadPropertyWithExplicitDefault(108, "dictionary_compression_ratio_threshold", + data->dictionary_compression_ratio_threshold, 1.0); + deserializer.ReadPropertyWithDefault(109, "compression_level", data->compression_level); data->row_groups_per_file = deserializer.ReadPropertyWithExplicitDefault(110, "row_groups_per_file", optional_idx::Invalid()); data->debug_use_openssl = deserializer.ReadPropertyWithExplicitDefault(111, "debug_use_openssl", true); - data->dictionary_size_limit = - deserializer.ReadPropertyWithExplicitDefault(112, "dictionary_size_limit", data->row_group_size / 10); - data->bloom_filter_false_positive_ratio = - deserializer.ReadPropertyWithExplicitDefault(113, "bloom_filter_false_positive_ratio", 0.01); - return std::move(data); } // LCOV_EXCL_STOP @@ -1595,7 +1577,7 @@ static vector> ParquetWriteSelect(CopyToSelectInput &inpu for (auto &expr : input.select_list) { const auto &type = expr->return_type; - const auto &name = expr->GetAlias(); + const auto &name = expr->alias; // Spatial types need to be encoded into WKB when writing GeoParquet. // But dont perform this conversion if this is a EXPORT DATABASE statement @@ -1606,7 +1588,7 @@ static vector> ParquetWriteSelect(CopyToSelectInput &inpu wkb_blob_type.SetAlias("WKB_BLOB"); auto cast_expr = BoundCastExpression::AddCastToType(context, std::move(expr), wkb_blob_type, false); - cast_expr->SetAlias(name); + cast_expr->alias = name; result.push_back(std::move(cast_expr)); any_change = true; } @@ -1618,7 +1600,7 @@ static vector> ParquetWriteSelect(CopyToSelectInput &inpu // Cast the column to the new type auto cast_expr = BoundCastExpression::AddCastToType(context, std::move(expr), new_type, false); - cast_expr->SetAlias(name); + cast_expr->alias = name; result.push_back(std::move(cast_expr)); any_change = true; } @@ -1631,7 +1613,7 @@ static vector> ParquetWriteSelect(CopyToSelectInput &inpu }); auto cast_expr = BoundCastExpression::AddCastToType(context, std::move(expr), new_type, false); - cast_expr->SetAlias(name); + cast_expr->alias = name; result.push_back(std::move(cast_expr)); any_change = true; } @@ -1676,10 +1658,6 @@ void ParquetExtension::Load(DuckDB &db) { ParquetFileMetadataFunction file_meta_fun; ExtensionUtil::RegisterFunction(db_instance, MultiFileReader::CreateFunctionSet(file_meta_fun)); - // parquet_bloom_probe - ParquetBloomProbeFunction bloom_probe_fun; - ExtensionUtil::RegisterFunction(db_instance, MultiFileReader::CreateFunctionSet(bloom_probe_fun)); - CopyFunction function("parquet"); function.copy_to_select = ParquetWriteSelect; function.copy_to_bind = ParquetWriteBind; @@ -1711,14 +1689,7 @@ void ParquetExtension::Load(DuckDB &db) { config.replacement_scans.emplace_back(ParquetScanReplacement); config.AddExtensionOption("binary_as_string", "In Parquet files, interpret binary data as a string.", LogicalType::BOOLEAN); - config.AddExtensionOption("disable_parquet_prefetching", "Disable the prefetching mechanism in Parquet", - LogicalType::BOOLEAN, Value(false)); - config.AddExtensionOption("prefetch_all_parquet_files", - "Use the prefetching mechanism for all types of parquet files", LogicalType::BOOLEAN, - Value(false)); - config.AddExtensionOption("parquet_metadata_cache", - "Cache Parquet metadata - useful when reading the same files multiple times", - LogicalType::BOOLEAN, Value(false)); + config.AddExtensionOption( "enable_geoparquet_conversion", "Attempt to decode/encode geometry data in/as GeoParquet files if the spatial extension is present.", diff --git a/src/duckdb/extension/parquet/parquet_metadata.cpp b/src/duckdb/extension/parquet/parquet_metadata.cpp index 456c9b3e4..b1d70a543 100644 --- a/src/duckdb/extension/parquet/parquet_metadata.cpp +++ b/src/duckdb/extension/parquet/parquet_metadata.cpp @@ -8,7 +8,6 @@ #include "duckdb/common/multi_file_reader.hpp" #include "duckdb/common/types/blob.hpp" #include "duckdb/common/types/column/column_data_collection.hpp" -#include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/main/config.hpp" #endif @@ -16,22 +15,11 @@ namespace duckdb { struct ParquetMetaDataBindData : public TableFunctionData { vector return_types; - shared_ptr file_list; + unique_ptr file_list; unique_ptr multi_file_reader; }; -struct ParquetBloomProbeBindData : public ParquetMetaDataBindData { - string probe_column_name; - Value probe_constant; -}; - -enum class ParquetMetadataOperatorType : uint8_t { - META_DATA, - SCHEMA, - KEY_VALUE_META_DATA, - FILE_META_DATA, - BLOOM_PROBE -}; +enum class ParquetMetadataOperatorType : uint8_t { META_DATA, SCHEMA, KEY_VALUE_META_DATA, FILE_META_DATA }; struct ParquetMetaDataOperatorData : public GlobalTableFunctionState { explicit ParquetMetaDataOperatorData(ClientContext &context, const vector &types) @@ -49,14 +37,11 @@ struct ParquetMetaDataOperatorData : public GlobalTableFunctionState { static void BindSchema(vector &return_types, vector &names); static void BindKeyValueMetaData(vector &return_types, vector &names); static void BindFileMetaData(vector &return_types, vector &names); - static void BindBloomProbe(vector &return_types, vector &names); void LoadRowGroupMetadata(ClientContext &context, const vector &return_types, const string &file_path); void LoadSchemaData(ClientContext &context, const vector &return_types, const string &file_path); void LoadKeyValueMetaData(ClientContext &context, const vector &return_types, const string &file_path); void LoadFileMetaData(ClientContext &context, const vector &return_types, const string &file_path); - void ExecuteBloomProbe(ClientContext &context, const vector &return_types, const string &file_path, - const string &column_name, const Value &probe); }; template @@ -179,16 +164,10 @@ void ParquetMetaDataOperatorData::BindMetaData(vector &return_types names.emplace_back("key_value_metadata"); return_types.emplace_back(LogicalType::MAP(LogicalType::BLOB, LogicalType::BLOB)); - - names.emplace_back("bloom_filter_offset"); - return_types.emplace_back(LogicalType::BIGINT); - - names.emplace_back("bloom_filter_length"); - return_types.emplace_back(LogicalType::BIGINT); } -Value ConvertParquetStats(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, bool stats_is_set, - const std::string &stats) { +Value ConvertParquetStats(const LogicalType &type, const duckdb_parquet::format::SchemaElement &schema_ele, + bool stats_is_set, const std::string &stats) { if (!stats_is_set) { return Value(LogicalType::VARCHAR); } @@ -319,14 +298,6 @@ void ParquetMetaDataOperatorData::LoadRowGroupMetadata(ClientContext &context, c 23, count, Value::MAP(LogicalType::BLOB, LogicalType::BLOB, std::move(map_keys), std::move(map_values))); - // bloom_filter_offset, LogicalType::BIGINT - current_chunk.SetValue( - 24, count, ParquetElementBigint(col_meta.bloom_filter_offset, col_meta.__isset.bloom_filter_offset)); - - // bloom_filter_length, LogicalType::BIGINT - current_chunk.SetValue( - 25, count, ParquetElementBigint(col_meta.bloom_filter_length, col_meta.__isset.bloom_filter_length)); - count++; if (count >= STANDARD_VECTOR_SIZE) { current_chunk.SetCardinality(count); @@ -381,7 +352,7 @@ void ParquetMetaDataOperatorData::BindSchema(vector &return_types, return_types.emplace_back(LogicalType::VARCHAR); } -Value ParquetLogicalTypeToString(const duckdb_parquet::LogicalType &type, bool is_set) { +Value ParquetLogicalTypeToString(const duckdb_parquet::format::LogicalType &type, bool is_set) { if (!is_set) { return Value(); } @@ -589,84 +560,12 @@ void ParquetMetaDataOperatorData::LoadFileMetaData(ClientContext &context, const collection.InitializeScan(scan_state); } -//===--------------------------------------------------------------------===// -// Bloom Probe -//===--------------------------------------------------------------------===// -void ParquetMetaDataOperatorData::BindBloomProbe(vector &return_types, vector &names) { - names.emplace_back("file_name"); - return_types.emplace_back(LogicalType::VARCHAR); - - names.emplace_back("row_group_id"); - return_types.emplace_back(LogicalType::BIGINT); - - names.emplace_back("bloom_filter_excludes"); - return_types.emplace_back(LogicalType::BOOLEAN); -} - -void ParquetMetaDataOperatorData::ExecuteBloomProbe(ClientContext &context, const vector &return_types, - const string &file_path, const string &column_name, - const Value &probe) { - collection.Reset(); - ParquetOptions parquet_options(context); - auto reader = make_uniq(context, file_path, parquet_options); - idx_t count = 0; - DataChunk current_chunk; - current_chunk.Initialize(context, return_types); - auto meta_data = reader->GetFileMetadata(); - - optional_idx probe_column_idx; - for (idx_t column_idx = 0; column_idx < reader->names.size(); column_idx++) { - if (reader->names[column_idx] == column_name) { - probe_column_idx = column_idx; - } - } - - if (!probe_column_idx.IsValid()) { - throw InvalidInputException("Column %s not found in %s", column_name, file_path); - } - - auto &allocator = Allocator::DefaultAllocator(); - auto transport = std::make_shared(allocator, reader->GetHandle(), false); - auto protocol = - make_uniq>(std::move(transport)); - - D_ASSERT(!probe.IsNull()); - ConstantFilter filter(ExpressionType::COMPARE_EQUAL, - probe.CastAs(context, reader->GetTypes()[probe_column_idx.GetIndex()])); - - for (idx_t row_group_idx = 0; row_group_idx < meta_data->row_groups.size(); row_group_idx++) { - auto &row_group = meta_data->row_groups[row_group_idx]; - auto &column = row_group.columns[probe_column_idx.GetIndex()]; - - auto bloom_excludes = - ParquetStatisticsUtils::BloomFilterExcludes(filter, column.meta_data, *protocol, allocator); - current_chunk.SetValue(0, count, Value(file_path)); - current_chunk.SetValue(1, count, Value::BIGINT(NumericCast(row_group_idx))); - current_chunk.SetValue(2, count, Value::BOOLEAN(bloom_excludes)); - - count++; - if (count >= STANDARD_VECTOR_SIZE) { - current_chunk.SetCardinality(count); - collection.Append(current_chunk); - - count = 0; - current_chunk.Reset(); - } - } - - current_chunk.SetCardinality(count); - collection.Append(current_chunk); - collection.InitializeScan(scan_state); -} - //===--------------------------------------------------------------------===// // Bind //===--------------------------------------------------------------------===// template unique_ptr ParquetMetaDataBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { - auto result = make_uniq(); - switch (TYPE) { case ParquetMetadataOperatorType::SCHEMA: ParquetMetaDataOperatorData::BindSchema(return_types, names); @@ -680,26 +579,14 @@ unique_ptr ParquetMetaDataBind(ClientContext &context, TableFuncti case ParquetMetadataOperatorType::FILE_META_DATA: ParquetMetaDataOperatorData::BindFileMetaData(return_types, names); break; - case ParquetMetadataOperatorType::BLOOM_PROBE: { - auto probe_bind_data = make_uniq(); - D_ASSERT(input.inputs.size() == 3); - if (input.inputs[1].IsNull() || input.inputs[2].IsNull()) { - throw InvalidInputException("Can't have NULL parameters for parquet_bloom_probe"); - } - probe_bind_data->probe_column_name = input.inputs[1].CastAs(context, LogicalType::VARCHAR).GetValue(); - probe_bind_data->probe_constant = input.inputs[2]; - result = std::move(probe_bind_data); - ParquetMetaDataOperatorData::BindBloomProbe(return_types, names); - break; - } default: throw InternalException("Unsupported ParquetMetadataOperatorType"); } + auto result = make_uniq(); result->return_types = return_types; result->multi_file_reader = MultiFileReader::Create(input.table_function); result->file_list = result->multi_file_reader->CreateFileList(context, input.inputs[0]); - return std::move(result); } @@ -727,12 +614,6 @@ unique_ptr ParquetMetaDataInit(ClientContext &context, case ParquetMetadataOperatorType::FILE_META_DATA: result->LoadFileMetaData(context, bind_data.return_types, bind_data.file_list->GetFirstFile()); break; - case ParquetMetadataOperatorType::BLOOM_PROBE: { - auto &bloom_probe_bind_data = input.bind_data->Cast(); - result->ExecuteBloomProbe(context, bind_data.return_types, bind_data.file_list->GetFirstFile(), - bloom_probe_bind_data.probe_column_name, bloom_probe_bind_data.probe_constant); - break; - } default: throw InternalException("Unsupported ParquetMetadataOperatorType"); } @@ -766,12 +647,6 @@ void ParquetMetaDataImplementation(ClientContext &context, TableFunctionInput &d case ParquetMetadataOperatorType::FILE_META_DATA: data.LoadFileMetaData(context, bind_data.return_types, data.current_file); break; - case ParquetMetadataOperatorType::BLOOM_PROBE: { - auto &bloom_probe_bind_data = data_p.bind_data->Cast(); - data.ExecuteBloomProbe(context, bind_data.return_types, bind_data.file_list->GetFirstFile(), - bloom_probe_bind_data.probe_column_name, bloom_probe_bind_data.probe_constant); - break; - } default: throw InternalException("Unsupported ParquetMetadataOperatorType"); } @@ -811,11 +686,4 @@ ParquetFileMetadataFunction::ParquetFileMetadataFunction() ParquetMetaDataInit) { } -ParquetBloomProbeFunction::ParquetBloomProbeFunction() - : TableFunction("parquet_bloom_probe", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::ANY}, - ParquetMetaDataImplementation, - ParquetMetaDataBind, - ParquetMetaDataInit) { -} - } // namespace duckdb diff --git a/src/duckdb/extension/parquet/parquet_reader.cpp b/src/duckdb/extension/parquet/parquet_reader.cpp index 1d2565a2d..7357767b7 100644 --- a/src/duckdb/extension/parquet/parquet_reader.cpp +++ b/src/duckdb/extension/parquet/parquet_reader.cpp @@ -29,7 +29,6 @@ #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/object_cache.hpp" #endif @@ -41,15 +40,15 @@ namespace duckdb { -using duckdb_parquet::ColumnChunk; -using duckdb_parquet::ConvertedType; -using duckdb_parquet::FieldRepetitionType; -using duckdb_parquet::FileCryptoMetaData; -using duckdb_parquet::FileMetaData; -using ParquetRowGroup = duckdb_parquet::RowGroup; -using duckdb_parquet::SchemaElement; -using duckdb_parquet::Statistics; -using duckdb_parquet::Type; +using duckdb_parquet::format::ColumnChunk; +using duckdb_parquet::format::ConvertedType; +using duckdb_parquet::format::FieldRepetitionType; +using duckdb_parquet::format::FileCryptoMetaData; +using duckdb_parquet::format::FileMetaData; +using ParquetRowGroup = duckdb_parquet::format::RowGroup; +using duckdb_parquet::format::SchemaElement; +using duckdb_parquet::format::Statistics; +using duckdb_parquet::format::Type; static unique_ptr CreateThriftFileProtocol(Allocator &allocator, FileHandle &file_handle, bool prefetch_mode) { @@ -148,10 +147,6 @@ LogicalType ParquetReader::DeriveLogicalType(const SchemaElement &s_ele, bool bi } } if (s_ele.__isset.converted_type) { - // Legacy NULL type, does no longer exist, but files are still around of course - if (static_cast(s_ele.converted_type) == 24) { - return LogicalTypeId::SQLNULL; - } switch (s_ele.converted_type) { case ConvertedType::INT_8: if (s_ele.type == Type::INT32) { @@ -256,6 +251,8 @@ LogicalType ParquetReader::DeriveLogicalType(const SchemaElement &s_ele, bool bi return LogicalType::INTERVAL; case ConvertedType::JSON: return LogicalType::JSON(); + case ConvertedType::NULL_TYPE: + return LogicalTypeId::SQLNULL; case ConvertedType::MAP: case ConvertedType::MAP_KEY_VALUE: case ConvertedType::LIST: @@ -295,10 +292,9 @@ LogicalType ParquetReader::DeriveLogicalType(const SchemaElement &s_ele) { return DeriveLogicalType(s_ele, parquet_options.binary_as_string); } -unique_ptr ParquetReader::CreateReaderRecursive(ClientContext &context, - const vector &indexes, idx_t depth, - idx_t max_define, idx_t max_repeat, - idx_t &next_schema_idx, idx_t &next_file_idx) { +unique_ptr ParquetReader::CreateReaderRecursive(ClientContext &context, idx_t depth, idx_t max_define, + idx_t max_repeat, idx_t &next_schema_idx, + idx_t &next_file_idx) { auto file_meta_data = GetFileMetadata(); D_ASSERT(file_meta_data); D_ASSERT(next_schema_idx < file_meta_data->schema.size()); @@ -328,12 +324,6 @@ unique_ptr ParquetReader::CreateReaderRecursive(ClientContext &con if (s_ele.__isset.num_children && s_ele.num_children > 0) { // inner node child_list_t child_types; vector> child_readers; - // this type is a nested type - it has child columns specified - // create a mapping for which column readers we should create - unordered_map> required_readers; - for (auto &index : indexes) { - required_readers.insert(make_pair(index.GetPrimaryIndex(), index.GetChildIndexes())); - } idx_t c_idx = 0; while (c_idx < (idx_t)s_ele.num_children) { @@ -341,23 +331,10 @@ unique_ptr ParquetReader::CreateReaderRecursive(ClientContext &con auto &child_ele = file_meta_data->schema[next_schema_idx]; - // figure out which child columns we should read of this child column - vector child_indexes; - auto entry = required_readers.find(c_idx); - if (entry != required_readers.end()) { - child_indexes = entry->second; - } - auto child_reader = CreateReaderRecursive(context, child_indexes, depth + 1, max_define, max_repeat, - next_schema_idx, next_file_idx); + auto child_reader = + CreateReaderRecursive(context, depth + 1, max_define, max_repeat, next_schema_idx, next_file_idx); child_types.push_back(make_pair(child_ele.name, child_reader->Type())); - if (indexes.empty() || entry != required_readers.end()) { - // either (1) indexes is empty, meaning we need to read all child columns, or (2) we need to read this - // column - child_readers.push_back(std::move(child_reader)); - } else { - // this column was explicitly not required - push an empty child reader here - child_readers.push_back(nullptr); - } + child_readers.push_back(std::move(child_reader)); c_idx++; } @@ -418,10 +395,9 @@ unique_ptr ParquetReader::CreateReaderRecursive(ClientContext &con } if (is_repeated) { result_type = LogicalType::LIST(result_type); - result = make_uniq(*this, result_type, s_ele, this_idx, max_define, max_repeat, - std::move(result)); + return make_uniq(*this, result_type, s_ele, this_idx, max_define, max_repeat, + std::move(result)); } - result->SetParentSchema(s_ele); return result; } else { // leaf node if (!s_ele.__isset.type) { @@ -456,7 +432,7 @@ unique_ptr ParquetReader::CreateReader(ClientContext &context) { if (file_meta_data->schema[0].num_children == 0) { throw IOException("Parquet reader: root schema element has no children"); } - auto ret = CreateReaderRecursive(context, reader_data.column_indexes, 0, 0, 0, next_schema_idx, next_file_idx); + auto ret = CreateReaderRecursive(context, 0, 0, 0, next_schema_idx, next_file_idx); if (ret->Type().id() != LogicalTypeId::STRUCT) { throw InvalidInputException("Root element of Parquet file must be a struct"); } @@ -562,13 +538,11 @@ ParquetReader::ParquetReader(ClientContext &context_p, string file_name_p, Parqu encryption_util = make_shared_ptr(); } - // If metadata cached is disabled + // If object cached is disabled // or if this file has cached metadata // or if the cached version already expired if (!metadata_p) { - Value metadata_cache = false; - context_p.TryGetCurrentSetting("parquet_metadata_cache", metadata_cache); - if (!metadata_cache.GetValue()) { + if (!ObjectCache::ObjectCacheEnabled(context_p)) { metadata = LoadMetadata(context_p, allocator, *file_handle, parquet_options.encryption_config, *encryption_util); } else { @@ -618,11 +592,11 @@ unique_ptr ParquetReader::ReadStatistics(const string &name) { unique_ptr column_stats; auto file_meta_data = GetFileMetadata(); - auto &column_reader = root_reader->Cast().GetChildReader(file_col_idx); + auto column_reader = root_reader->Cast().GetChildReader(file_col_idx); for (idx_t row_group_idx = 0; row_group_idx < file_meta_data->row_groups.size(); row_group_idx++) { auto &row_group = file_meta_data->row_groups[row_group_idx]; - auto chunk_stats = column_reader.Stats(row_group_idx, row_group.columns); + auto chunk_stats = column_reader->Stats(row_group_idx, row_group.columns); if (!chunk_stats) { return nullptr; } @@ -745,30 +719,22 @@ static FilterPropagateResult CheckParquetStringFilter(BaseStatistics &stats, con void ParquetReader::PrepareRowGroupBuffer(ParquetReaderScanState &state, idx_t col_idx) { auto &group = GetGroup(state); auto column_id = reader_data.column_ids[col_idx]; - auto &column_reader = state.root_reader->Cast().GetChildReader(column_id); + auto column_reader = state.root_reader->Cast().GetChildReader(column_id); // TODO move this to columnreader too if (reader_data.filters) { - auto stats = column_reader.Stats(state.group_idx_list[state.current_group], group.columns); + auto stats = column_reader->Stats(state.group_idx_list[state.current_group], group.columns); // filters contain output chunk index, not file col idx! auto global_id = reader_data.column_mapping[col_idx]; auto filter_entry = reader_data.filters->filters.find(global_id); - if (stats && filter_entry != reader_data.filters->filters.end()) { + bool skip_chunk = false; auto &filter = *filter_entry->second; FilterPropagateResult prune_result; - // TODO we might not have stats but STILL a bloom filter so move this up - // check the bloom filter if present - if (!column_reader.Type().IsNested() && - ParquetStatisticsUtils::BloomFilterSupported(column_reader.Type().id()) && - ParquetStatisticsUtils::BloomFilterExcludes(filter, group.columns[column_reader.FileIdx()].meta_data, - *state.thrift_file_proto, allocator)) { - prune_result = FilterPropagateResult::FILTER_ALWAYS_FALSE; - } else if (column_reader.Type().id() == LogicalTypeId::VARCHAR && - group.columns[column_reader.FileIdx()].meta_data.statistics.__isset.min_value && - group.columns[column_reader.FileIdx()].meta_data.statistics.__isset.max_value) { - + if (column_reader->Type().id() == LogicalTypeId::VARCHAR && + group.columns[column_reader->FileIdx()].meta_data.statistics.__isset.min_value && + group.columns[column_reader->FileIdx()].meta_data.statistics.__isset.max_value) { // our StringStats only store the first 8 bytes of strings (even if Parquet has longer string stats) // however, when reading remote Parquet files, skipping row groups is really important // here, we implement a special case to check the full length for string filters @@ -777,7 +743,7 @@ void ParquetReader::PrepareRowGroupBuffer(ParquetReaderScanState &state, idx_t c auto and_result = FilterPropagateResult::FILTER_ALWAYS_TRUE; for (auto &child_filter : and_filter.child_filters) { auto child_prune_result = CheckParquetStringFilter( - *stats, group.columns[column_reader.FileIdx()].meta_data.statistics, *child_filter); + *stats, group.columns[column_reader->FileIdx()].meta_data.statistics, *child_filter); if (child_prune_result == FilterPropagateResult::FILTER_ALWAYS_FALSE) { and_result = FilterPropagateResult::FILTER_ALWAYS_FALSE; break; @@ -788,13 +754,16 @@ void ParquetReader::PrepareRowGroupBuffer(ParquetReaderScanState &state, idx_t c prune_result = and_result; } else { prune_result = CheckParquetStringFilter( - *stats, group.columns[column_reader.FileIdx()].meta_data.statistics, filter); + *stats, group.columns[column_reader->FileIdx()].meta_data.statistics, filter); } } else { prune_result = filter.CheckStatistics(*stats); } if (prune_result == FilterPropagateResult::FILTER_ALWAYS_FALSE) { + skip_chunk = true; + } + if (skip_chunk) { // this effectively will skip this chunk state.group_offset = group.num_rows; return; @@ -824,14 +793,7 @@ void ParquetReader::InitializeScan(ClientContext &context, ParquetReaderScanStat if (!state.file_handle || state.file_handle->path != file_handle->path) { auto flags = FileFlags::FILE_FLAGS_READ; - Value disable_prefetch = false; - Value prefetch_all_files = false; - context.TryGetCurrentSetting("disable_parquet_prefetching", disable_prefetch); - context.TryGetCurrentSetting("prefetch_all_parquet_files", prefetch_all_files); - bool should_prefetch = !file_handle->OnDiskFile() || prefetch_all_files.GetValue(); - bool can_prefetch = file_handle->CanSeek() && !disable_prefetch.GetValue(); - - if (should_prefetch && can_prefetch) { + if (!file_handle->OnDiskFile() && file_handle->CanSeek()) { state.prefetch_mode = true; flags |= FileFlags::FILE_FLAGS_DIRECT_IO; } else { @@ -855,16 +817,15 @@ void FilterIsNull(Vector &v, parquet_filter_t &filter_mask, idx_t count) { } return; } + D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); - UnifiedVectorFormat unified; - v.ToUnifiedFormat(count, unified); - - if (unified.validity.AllValid()) { + auto &mask = FlatVector::Validity(v); + if (mask.AllValid()) { filter_mask.reset(); } else { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, !unified.validity.RowIsValid(unified.sel->get_index(i))); + filter_mask.set(i, !mask.RowIsValid(i)); } } } @@ -878,14 +839,13 @@ void FilterIsNotNull(Vector &v, parquet_filter_t &filter_mask, idx_t count) { } return; } + D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); - UnifiedVectorFormat unified; - v.ToUnifiedFormat(count, unified); - - if (!unified.validity.AllValid()) { + auto &mask = FlatVector::Validity(v); + if (!mask.AllValid()) { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, unified.validity.RowIsValid(unified.sel->get_index(i))); + filter_mask.set(i, mask.RowIsValid(i)); } } } @@ -901,32 +861,24 @@ void TemplatedFilterOperation(Vector &v, T constant, parquet_filter_t &filter_ma if (!OP::Operation(v_ptr[0], constant)) { filter_mask.reset(); } - } else { - filter_mask.reset(); } return; } - UnifiedVectorFormat unified; - v.ToUnifiedFormat(count, unified); - auto data_ptr = UnifiedVectorFormat::GetData(unified); + D_ASSERT(v.GetVectorType() == VectorType::FLAT_VECTOR); + auto v_ptr = FlatVector::GetData(v); + auto &mask = FlatVector::Validity(v); - if (!unified.validity.AllValid()) { + if (!mask.AllValid()) { for (idx_t i = 0; i < count; i++) { - if (filter_mask.test(i)) { - auto idx = unified.sel->get_index(i); - bool is_valid = unified.validity.RowIsValid(idx); - if (is_valid) { - filter_mask.set(i, OP::Operation(data_ptr[idx], constant)); - } else { - filter_mask.set(i, false); - } + if (filter_mask.test(i) && mask.RowIsValid(i)) { + filter_mask.set(i, OP::Operation(v_ptr[i], constant)); } } } else { for (idx_t i = 0; i < count; i++) { if (filter_mask.test(i)) { - filter_mask.set(i, OP::Operation(data_ptr[unified.sel->get_index(i)], constant)); + filter_mask.set(i, OP::Operation(v_ptr[i], constant)); } } } @@ -1025,11 +977,8 @@ static void ApplyFilter(Vector &v, TableFilter &filter, parquet_filter_t &filter case ExpressionType::COMPARE_GREATERTHANOREQUALTO: FilterOperationSwitch(v, constant_filter.constant, filter_mask, count); break; - case ExpressionType::COMPARE_NOTEQUAL: - FilterOperationSwitch(v, constant_filter.constant, filter_mask, count); - break; default: - throw InternalException("Unsupported comparison for Parquet filter pushdown"); + D_ASSERT(0); } break; } @@ -1043,12 +992,7 @@ static void ApplyFilter(Vector &v, TableFilter &filter, parquet_filter_t &filter auto &struct_filter = filter.Cast(); auto &child = StructVector::GetEntries(v)[struct_filter.child_idx]; ApplyFilter(*child, *struct_filter.child_filter, filter_mask, count); - } - case TableFilterType::OPTIONAL_FILTER: { - // we don't execute zone map filters here - we only consider them for zone map pruning - // do nothing to the mask. - break; - } + } break; default: D_ASSERT(0); break; @@ -1090,21 +1034,19 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul auto file_col_idx = reader_data.column_ids[col_idx]; auto &root_reader = state.root_reader->Cast(); - to_scan_compressed_bytes += root_reader.GetChildReader(file_col_idx).TotalCompressedSize(); + to_scan_compressed_bytes += root_reader.GetChildReader(file_col_idx)->TotalCompressedSize(); } auto &group = GetGroup(state); if (state.prefetch_mode && state.group_offset != (idx_t)group.num_rows) { + uint64_t total_row_group_span = GetGroupSpan(state); double scan_percentage = (double)(to_scan_compressed_bytes) / static_cast(total_row_group_span); if (to_scan_compressed_bytes > total_row_group_span) { - throw IOException( - "The parquet file '%s' seems to have incorrectly set page offsets. This interferes with DuckDB's " - "prefetching optimization. DuckDB may still be able to scan this file by manually disabling the " - "prefetching mechanism using: 'SET disable_parquet_prefetching=true'.", - file_name); + throw InvalidInputException( + "Malformed parquet file: sum of total compressed bytes of columns seems incorrect"); } if (!reader_data.filters && @@ -1132,7 +1074,7 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul auto entry = reader_data.filters->filters.find(reader_data.column_mapping[col_idx]); has_filter = entry != reader_data.filters->filters.end(); } - root_reader.GetChildReader(file_col_idx).RegisterPrefetch(trans, !(lazy_fetch && !has_filter)); + root_reader.GetChildReader(file_col_idx)->RegisterPrefetch(trans, !(lazy_fetch && !has_filter)); } trans.FinalizeRegistration(); @@ -1192,8 +1134,8 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul auto result_idx = reader_data.column_mapping[id]; auto &result_vector = result.data[result_idx]; - auto &child_reader = root_reader.GetChildReader(file_col_idx); - child_reader.Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); + auto child_reader = root_reader.GetChildReader(file_col_idx); + child_reader->Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); need_to_read[id] = false; ApplyFilter(result_vector, *filter_col.second, filter_mask, this_output_chunk_rows); @@ -1207,12 +1149,12 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul } auto file_col_idx = reader_data.column_ids[col_idx]; if (filter_mask.none()) { - root_reader.GetChildReader(file_col_idx).Skip(result.size()); + root_reader.GetChildReader(file_col_idx)->Skip(result.size()); continue; } auto &result_vector = result.data[reader_data.column_mapping[col_idx]]; - auto &child_reader = root_reader.GetChildReader(file_col_idx); - child_reader.Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); + auto child_reader = root_reader.GetChildReader(file_col_idx); + child_reader->Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); } idx_t sel_size = 0; @@ -1227,8 +1169,8 @@ bool ParquetReader::ScanInternal(ParquetReaderScanState &state, DataChunk &resul for (idx_t col_idx = 0; col_idx < reader_data.column_ids.size(); col_idx++) { auto file_col_idx = reader_data.column_ids[col_idx]; auto &result_vector = result.data[reader_data.column_mapping[col_idx]]; - auto &child_reader = root_reader.GetChildReader(file_col_idx); - auto rows_read = child_reader.Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); + auto child_reader = root_reader.GetChildReader(file_col_idx); + auto rows_read = child_reader->Read(result.size(), filter_mask, define_ptr, repeat_ptr, result_vector); if (rows_read != result.size()) { throw InvalidInputException("Mismatch in parquet read for column %llu, expected %llu rows, got %llu", file_col_idx, result.size(), rows_read); diff --git a/src/duckdb/extension/parquet/parquet_statistics.cpp b/src/duckdb/extension/parquet/parquet_statistics.cpp index 7e4ceac40..26896c576 100644 --- a/src/duckdb/extension/parquet/parquet_statistics.cpp +++ b/src/duckdb/extension/parquet/parquet_statistics.cpp @@ -5,24 +5,21 @@ #include "parquet_timestamp.hpp" #include "string_column_reader.hpp" #include "struct_column_reader.hpp" -#include "zstd/common/xxhash.hpp" - #ifndef DUCKDB_AMALGAMATION #include "duckdb/common/types/blob.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/storage/statistics/struct_stats.hpp" -#include "duckdb/planner/filter/constant_filter.hpp" #endif namespace duckdb { -using duckdb_parquet::ConvertedType; -using duckdb_parquet::Type; +using duckdb_parquet::format::ConvertedType; +using duckdb_parquet::format::Type; static unique_ptr CreateNumericStats(const LogicalType &type, - const duckdb_parquet::SchemaElement &schema_ele, - const duckdb_parquet::Statistics &parquet_stats) { + const duckdb_parquet::format::SchemaElement &schema_ele, + const duckdb_parquet::format::Statistics &parquet_stats) { auto stats = NumericStats::CreateUnknown(type); // for reasons unknown to science, Parquet defines *both* `min` and `min_value` as well as `max` and @@ -30,16 +27,16 @@ static unique_ptr CreateNumericStats(const LogicalType &type, Value min; Value max; if (parquet_stats.__isset.min_value) { - min = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.min_value); + min = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.min_value).DefaultCastAs(type); } else if (parquet_stats.__isset.min) { - min = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.min); + min = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.min).DefaultCastAs(type); } else { min = Value(type); } if (parquet_stats.__isset.max_value) { - max = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.max_value); + max = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.max_value).DefaultCastAs(type); } else if (parquet_stats.__isset.max) { - max = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.max); + max = ParquetStatisticsUtils::ConvertValue(type, schema_ele, parquet_stats.max).DefaultCastAs(type); } else { max = Value(type); } @@ -48,24 +45,14 @@ static unique_ptr CreateNumericStats(const LogicalType &type, return stats.ToUnique(); } -Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, const duckdb_parquet::SchemaElement &schema_ele, +Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type, + const duckdb_parquet::format::SchemaElement &schema_ele, const std::string &stats) { - Value result; - string error; - auto stats_val = ConvertValueInternal(type, schema_ele, stats); - if (!stats_val.DefaultTryCastAs(type, result, &error)) { - return Value(type); - } - return result; -} -Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, - const duckdb_parquet::SchemaElement &schema_ele, - const std::string &stats) { auto stats_data = const_data_ptr_cast(stats.c_str()); switch (type.id()) { case LogicalTypeId::BOOLEAN: { if (stats.size() != sizeof(bool)) { - throw InvalidInputException("Incorrect stats size for type BOOLEAN"); + throw InternalException("Incorrect stats size for type BOOLEAN"); } return Value::BOOLEAN(Load(stats_data)); } @@ -73,29 +60,29 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, case LogicalTypeId::USMALLINT: case LogicalTypeId::UINTEGER: if (stats.size() != sizeof(uint32_t)) { - throw InvalidInputException("Incorrect stats size for type UINTEGER"); + throw InternalException("Incorrect stats size for type UINTEGER"); } return Value::UINTEGER(Load(stats_data)); case LogicalTypeId::UBIGINT: if (stats.size() != sizeof(uint64_t)) { - throw InvalidInputException("Incorrect stats size for type UBIGINT"); + throw InternalException("Incorrect stats size for type UBIGINT"); } return Value::UBIGINT(Load(stats_data)); case LogicalTypeId::TINYINT: case LogicalTypeId::SMALLINT: case LogicalTypeId::INTEGER: if (stats.size() != sizeof(int32_t)) { - throw InvalidInputException("Incorrect stats size for type INTEGER"); + throw InternalException("Incorrect stats size for type INTEGER"); } return Value::INTEGER(Load(stats_data)); case LogicalTypeId::BIGINT: if (stats.size() != sizeof(int64_t)) { - throw InvalidInputException("Incorrect stats size for type BIGINT"); + throw InternalException("Incorrect stats size for type BIGINT"); } return Value::BIGINT(Load(stats_data)); case LogicalTypeId::FLOAT: { if (stats.size() != sizeof(float)) { - throw InvalidInputException("Incorrect stats size for type FLOAT"); + throw InternalException("Incorrect stats size for type FLOAT"); } auto val = Load(stats_data); if (!Value::FloatIsFinite(val)) { @@ -113,7 +100,7 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, break; } if (stats.size() != sizeof(double)) { - throw InvalidInputException("Incorrect stats size for type DOUBLE"); + throw InternalException("Incorrect stats size for type DOUBLE"); } auto val = Load(stats_data); if (!Value::DoubleIsFinite(val)) { @@ -127,13 +114,13 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, switch (schema_ele.type) { case Type::INT32: { if (stats.size() != sizeof(int32_t)) { - throw InvalidInputException("Incorrect stats size for type %s", type.ToString()); + throw InternalException("Incorrect stats size for type %s", type.ToString()); } return Value::DECIMAL(Load(stats_data), width, scale); } case Type::INT64: { if (stats.size() != sizeof(int64_t)) { - throw InvalidInputException("Incorrect stats size for type %s", type.ToString()); + throw InternalException("Incorrect stats size for type %s", type.ToString()); } return Value::DECIMAL(Load(stats_data), width, scale); } @@ -154,21 +141,22 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, ParquetDecimalUtils::ReadDecimalValue(stats_data, stats.size(), schema_ele), width, scale); default: - throw InvalidInputException("Unsupported internal type for decimal"); + throw InternalException("Unsupported internal type for decimal"); } default: throw InternalException("Unsupported internal type for decimal?.."); } } - case LogicalTypeId::VARCHAR: - case LogicalTypeId::BLOB: - if (type.id() == LogicalTypeId::BLOB || !Value::StringIsValid(stats)) { + case LogicalType::VARCHAR: + case LogicalType::BLOB: + if (Value::StringIsValid(stats)) { + return Value(stats); + } else { return Value(Blob::ToString(string_t(stats))); } - return Value(stats); case LogicalTypeId::DATE: if (stats.size() != sizeof(int32_t)) { - throw InvalidInputException("Incorrect stats size for type DATE"); + throw InternalException("Incorrect stats size for type DATE"); } return Value::DATE(date_t(Load(stats_data))); case LogicalTypeId::TIME: { @@ -178,7 +166,7 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, } else if (stats.size() == sizeof(int64_t)) { val = Load(stats_data); } else { - throw InvalidInputException("Incorrect stats size for type TIME"); + throw InternalException("Incorrect stats size for type TIME"); } if (schema_ele.__isset.logicalType && schema_ele.logicalType.__isset.TIME) { // logical type @@ -192,7 +180,7 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, throw InternalException("Time logicalType is set but unit is not defined"); } } - if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIME_MILLIS) { + if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIME_MILLIS) { return Value::TIME(Time::FromTimeMs(val)); } else { return Value::TIME(dtime_t(val)); @@ -205,7 +193,7 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, } else if (stats.size() == sizeof(int64_t)) { val = Load(stats_data); } else { - throw InvalidInputException("Incorrect stats size for type TIMETZ"); + throw InternalException("Incorrect stats size for type TIMETZ"); } if (schema_ele.__isset.logicalType && schema_ele.logicalType.__isset.TIME) { // logical type @@ -226,13 +214,13 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, timestamp_t timestamp_value; if (schema_ele.type == Type::INT96) { if (stats.size() != sizeof(Int96)) { - throw InvalidInputException("Incorrect stats size for type TIMESTAMP"); + throw InternalException("Incorrect stats size for type TIMESTAMP"); } timestamp_value = ImpalaTimestampToTimestamp(Load(stats_data)); } else { D_ASSERT(schema_ele.type == Type::INT64); if (stats.size() != sizeof(int64_t)) { - throw InvalidInputException("Incorrect stats size for type TIMESTAMP"); + throw InternalException("Incorrect stats size for type TIMESTAMP"); } auto val = Load(stats_data); if (schema_ele.__isset.logicalType && schema_ele.logicalType.__isset.TIMESTAMP) { @@ -246,28 +234,29 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, } else { throw InternalException("Timestamp logicalType is set but unit is not defined"); } - } else if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIMESTAMP_MILLIS) { + } else if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIMESTAMP_MILLIS) { timestamp_value = Timestamp::FromEpochMs(val); } else { timestamp_value = timestamp_t(val); } } if (type.id() == LogicalTypeId::TIMESTAMP_TZ) { - return Value::TIMESTAMPTZ(timestamp_tz_t(timestamp_value)); + return Value::TIMESTAMPTZ(timestamp_value); + } else { + return Value::TIMESTAMP(timestamp_value); } - return Value::TIMESTAMP(timestamp_value); } case LogicalTypeId::TIMESTAMP_NS: { timestamp_ns_t timestamp_value; if (schema_ele.type == Type::INT96) { if (stats.size() != sizeof(Int96)) { - throw InvalidInputException("Incorrect stats size for type TIMESTAMP_NS"); + throw InternalException("Incorrect stats size for type TIMESTAMP_NS"); } timestamp_value = ImpalaTimestampToTimestampNS(Load(stats_data)); } else { D_ASSERT(schema_ele.type == Type::INT64); if (stats.size() != sizeof(int64_t)) { - throw InvalidInputException("Incorrect stats size for type TIMESTAMP_NS"); + throw InternalException("Incorrect stats size for type TIMESTAMP_NS"); } auto val = Load(stats_data); if (schema_ele.__isset.logicalType && schema_ele.logicalType.__isset.TIMESTAMP) { @@ -281,7 +270,7 @@ Value ParquetStatisticsUtils::ConvertValueInternal(const LogicalType &type, } else { throw InternalException("Timestamp (NS) logicalType is set but unit is unknown"); } - } else if (schema_ele.converted_type == duckdb_parquet::ConvertedType::TIMESTAMP_MILLIS) { + } else if (schema_ele.converted_type == duckdb_parquet::format::ConvertedType::TIMESTAMP_MILLIS) { timestamp_value = ParquetTimestampMsToTimestampNs(val); } else { timestamp_value = ParquetTimestampUsToTimestampNs(val); @@ -311,9 +300,6 @@ unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(con auto &struct_reader = reader.Cast(); // Recurse into child readers for (idx_t i = 0; i < struct_reader.child_readers.size(); i++) { - if (!struct_reader.child_readers[i]) { - continue; - } auto &child_reader = *struct_reader.child_readers[i]; auto child_stats = ParquetStatisticsUtils::TransformColumnStatistics(child_reader, columns); StructStats::SetChildStats(struct_stats, i, std::move(child_stats)); @@ -401,210 +387,4 @@ unique_ptr ParquetStatisticsUtils::TransformColumnStatistics(con return row_group_stats; } -static bool HasFilterConstants(const TableFilter &duckdb_filter) { - switch (duckdb_filter.filter_type) { - case TableFilterType::CONSTANT_COMPARISON: { - auto &constant_filter = duckdb_filter.Cast(); - return (constant_filter.comparison_type == ExpressionType::COMPARE_EQUAL && !constant_filter.constant.IsNull()); - } - case TableFilterType::CONJUNCTION_AND: { - auto &conjunction_and_filter = duckdb_filter.Cast(); - bool child_has_constant = false; - for (auto &child_filter : conjunction_and_filter.child_filters) { - child_has_constant |= HasFilterConstants(*child_filter); - } - return child_has_constant; - } - case TableFilterType::CONJUNCTION_OR: { - auto &conjunction_or_filter = duckdb_filter.Cast(); - bool child_has_constant = false; - for (auto &child_filter : conjunction_or_filter.child_filters) { - child_has_constant |= HasFilterConstants(*child_filter); - } - return child_has_constant; - } - default: - return false; - } -} - -template -uint64_t ValueXH64FixedWidth(const Value &constant) { - T val = constant.GetValue(); - return duckdb_zstd::XXH64(&val, sizeof(val), 0); -} - -// TODO we can only this if the parquet representation of the type exactly matches the duckdb rep! -// TODO TEST THIS! -// TODO perhaps we can re-use some writer infra here -static uint64_t ValueXXH64(const Value &constant) { - switch (constant.type().InternalType()) { - case PhysicalType::UINT8: - return ValueXH64FixedWidth(constant); - case PhysicalType::INT8: - return ValueXH64FixedWidth(constant); - case PhysicalType::UINT16: - return ValueXH64FixedWidth(constant); - case PhysicalType::INT16: - return ValueXH64FixedWidth(constant); - case PhysicalType::UINT32: - return ValueXH64FixedWidth(constant); - case PhysicalType::INT32: - return ValueXH64FixedWidth(constant); - case PhysicalType::UINT64: - return ValueXH64FixedWidth(constant); - case PhysicalType::INT64: - return ValueXH64FixedWidth(constant); - case PhysicalType::FLOAT: - return ValueXH64FixedWidth(constant); - case PhysicalType::DOUBLE: - return ValueXH64FixedWidth(constant); - case PhysicalType::VARCHAR: { - auto val = constant.GetValue(); - return duckdb_zstd::XXH64(val.c_str(), val.length(), 0); - } - default: - return 0; - } -} - -static bool ApplyBloomFilter(const TableFilter &duckdb_filter, ParquetBloomFilter &bloom_filter) { - switch (duckdb_filter.filter_type) { - case TableFilterType::CONSTANT_COMPARISON: { - auto &constant_filter = duckdb_filter.Cast(); - auto is_compare_equal = constant_filter.comparison_type == ExpressionType::COMPARE_EQUAL; - D_ASSERT(!constant_filter.constant.IsNull()); - auto hash = ValueXXH64(constant_filter.constant); - return hash > 0 && !bloom_filter.FilterCheck(hash) && is_compare_equal; - } - case TableFilterType::CONJUNCTION_AND: { - auto &conjunction_and_filter = duckdb_filter.Cast(); - bool any_children_true = false; - for (auto &child_filter : conjunction_and_filter.child_filters) { - any_children_true |= ApplyBloomFilter(*child_filter, bloom_filter); - } - return any_children_true; - } - case TableFilterType::CONJUNCTION_OR: { - auto &conjunction_or_filter = duckdb_filter.Cast(); - bool all_children_true = true; - for (auto &child_filter : conjunction_or_filter.child_filters) { - all_children_true &= ApplyBloomFilter(*child_filter, bloom_filter); - } - return all_children_true; - } - default: - return false; - } -} - -bool ParquetStatisticsUtils::BloomFilterSupported(const LogicalTypeId &type_id) { - switch (type_id) { - case LogicalTypeId::TINYINT: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - case LogicalTypeId::VARCHAR: - case LogicalTypeId::BLOB: - return true; - default: - return false; - } -} - -bool ParquetStatisticsUtils::BloomFilterExcludes(const TableFilter &duckdb_filter, - const duckdb_parquet::ColumnMetaData &column_meta_data, - TProtocol &file_proto, Allocator &allocator) { - if (!HasFilterConstants(duckdb_filter) || !column_meta_data.__isset.bloom_filter_offset || - column_meta_data.bloom_filter_offset <= 0) { - return false; - } - // TODO check length against file length! - - auto &transport = reinterpret_cast(*file_proto.getTransport()); - transport.SetLocation(column_meta_data.bloom_filter_offset); - if (column_meta_data.__isset.bloom_filter_length && column_meta_data.bloom_filter_length > 0) { - transport.Prefetch(column_meta_data.bloom_filter_offset, column_meta_data.bloom_filter_length); - } - - duckdb_parquet::BloomFilterHeader filter_header; - // TODO the bloom filter could be encrypted, too, so need to double check that this is NOT the case - filter_header.read(&file_proto); - if (!filter_header.algorithm.__isset.BLOCK || !filter_header.compression.__isset.UNCOMPRESSED || - !filter_header.hash.__isset.XXHASH) { - return false; - } - - auto new_buffer = make_uniq(allocator, filter_header.numBytes); - transport.read(new_buffer->ptr, filter_header.numBytes); - ParquetBloomFilter bloom_filter(std::move(new_buffer)); - return ApplyBloomFilter(duckdb_filter, bloom_filter); -} - -ParquetBloomFilter::ParquetBloomFilter(idx_t num_entries, double bloom_filter_false_positive_ratio) { - - // aim for hit ratio of 0.01% - // see http://tfk.mit.edu/pdf/bloom.pdf - double f = bloom_filter_false_positive_ratio; - double k = 8.0; - double n = LossyNumericCast(num_entries); - double m = -k * n / std::log(1 - std::pow(f, 1 / k)); - auto b = MaxValue(NextPowerOfTwo(LossyNumericCast(m / k)) / 32, 1); - - D_ASSERT(b > 0 && IsPowerOfTwo(b)); - - data = make_uniq(Allocator::DefaultAllocator(), sizeof(ParquetBloomBlock) * b); - data->zero(); - block_count = data->len / sizeof(ParquetBloomBlock); - D_ASSERT(data->len % sizeof(ParquetBloomBlock) == 0); -} - -ParquetBloomFilter::ParquetBloomFilter(unique_ptr data_p) { - D_ASSERT(data_p->len % sizeof(ParquetBloomBlock) == 0); - data = std::move(data_p); - block_count = data->len / sizeof(ParquetBloomBlock); - D_ASSERT(data->len % sizeof(ParquetBloomBlock) == 0); -} - -void ParquetBloomFilter::FilterInsert(uint64_t x) { - auto blocks = reinterpret_cast(data->ptr); - uint64_t i = ((x >> 32) * block_count) >> 32; - auto &b = blocks[i]; - ParquetBloomBlock::BlockInsert(b, x); -} - -bool ParquetBloomFilter::FilterCheck(uint64_t x) { - auto blocks = reinterpret_cast(data->ptr); - auto i = ((x >> 32) * block_count) >> 32; - return ParquetBloomBlock::BlockCheck(blocks[i], x); -} - -// compiler optimizes this into a single instruction (popcnt) -static uint8_t PopCnt64(uint64_t n) { - uint8_t c = 0; - for (; n; ++c) { - n &= n - 1; - } - return c; -} - -double ParquetBloomFilter::OneRatio() { - auto bloom_ptr = reinterpret_cast(data->ptr); - idx_t one_count = 0; - for (idx_t b_idx = 0; b_idx < data->len / sizeof(uint64_t); ++b_idx) { - one_count += PopCnt64(bloom_ptr[b_idx]); - } - return LossyNumericCast(one_count) / (LossyNumericCast(data->len) * 8.0); -} - -ResizeableBuffer *ParquetBloomFilter::Get() { - return data.get(); -} - } // namespace duckdb diff --git a/src/duckdb/extension/parquet/parquet_timestamp.cpp b/src/duckdb/extension/parquet/parquet_timestamp.cpp index 84c158f19..a0ada7d14 100644 --- a/src/duckdb/extension/parquet/parquet_timestamp.cpp +++ b/src/duckdb/extension/parquet/parquet_timestamp.cpp @@ -105,16 +105,6 @@ date_t ParquetIntToDate(const int32_t &raw_date) { return date_t(raw_date); } -template -static T ParquetWrapTime(const T &raw, const T day) { - // Special case 24:00:00 - if (raw == day) { - return raw; - } - const auto modulus = raw % day; - return modulus + (modulus < 0) * day; -} - dtime_t ParquetIntToTimeMs(const int32_t &raw_millis) { return Time::FromTimeMs(raw_millis); } @@ -128,19 +118,15 @@ dtime_t ParquetIntToTimeNs(const int64_t &raw_nanos) { } dtime_tz_t ParquetIntToTimeMsTZ(const int32_t &raw_millis) { - const int32_t MSECS_PER_DAY = Interval::MSECS_PER_SEC * Interval::SECS_PER_DAY; - const auto millis = ParquetWrapTime(raw_millis, MSECS_PER_DAY); - return dtime_tz_t(Time::FromTimeMs(millis), 0); + return dtime_tz_t(Time::FromTimeMs(raw_millis), 0); } dtime_tz_t ParquetIntToTimeTZ(const int64_t &raw_micros) { - const auto micros = ParquetWrapTime(raw_micros, Interval::MICROS_PER_DAY); - return dtime_tz_t(dtime_t(micros), 0); + return dtime_tz_t(dtime_t(raw_micros), 0); } dtime_tz_t ParquetIntToTimeNsTZ(const int64_t &raw_nanos) { - const auto nanos = ParquetWrapTime(raw_nanos, Interval::NANOS_PER_DAY); - return dtime_tz_t(Time::FromTimeNs(nanos), 0); + return dtime_tz_t(Time::FromTimeNs(raw_nanos), 0); } } // namespace duckdb diff --git a/src/duckdb/extension/parquet/parquet_writer.cpp b/src/duckdb/extension/parquet/parquet_writer.cpp index 883f03069..a7a847afb 100644 --- a/src/duckdb/extension/parquet/parquet_writer.cpp +++ b/src/duckdb/extension/parquet/parquet_writer.cpp @@ -4,7 +4,6 @@ #include "mbedtls_wrapper.hpp" #include "parquet_crypto.hpp" #include "parquet_timestamp.hpp" -#include "resizable_buffer.hpp" #ifndef DUCKDB_AMALGAMATION #include "duckdb/common/file_system.hpp" @@ -26,16 +25,16 @@ using namespace duckdb_apache::thrift; // NOLINT using namespace duckdb_apache::thrift::protocol; // NOLINT using namespace duckdb_apache::thrift::transport; // NOLINT -using duckdb_parquet::CompressionCodec; -using duckdb_parquet::ConvertedType; -using duckdb_parquet::Encoding; -using duckdb_parquet::FieldRepetitionType; -using duckdb_parquet::FileCryptoMetaData; -using duckdb_parquet::FileMetaData; -using duckdb_parquet::PageHeader; -using duckdb_parquet::PageType; -using ParquetRowGroup = duckdb_parquet::RowGroup; -using duckdb_parquet::Type; +using duckdb_parquet::format::CompressionCodec; +using duckdb_parquet::format::ConvertedType; +using duckdb_parquet::format::Encoding; +using duckdb_parquet::format::FieldRepetitionType; +using duckdb_parquet::format::FileCryptoMetaData; +using duckdb_parquet::format::FileMetaData; +using duckdb_parquet::format::PageHeader; +using duckdb_parquet::format::PageType; +using ParquetRowGroup = duckdb_parquet::format::RowGroup; +using duckdb_parquet::format::Type; ChildFieldIDs::ChildFieldIDs() : ids(make_uniq>()) { } @@ -168,12 +167,11 @@ Type::type ParquetWriter::DuckDBTypeToParquetType(const LogicalType &duckdb_type throw NotImplementedException("Unimplemented type for Parquet \"%s\"", duckdb_type.ToString()); } -void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, duckdb_parquet::SchemaElement &schema_ele) { +void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type, + duckdb_parquet::format::SchemaElement &schema_ele) { if (duckdb_type.IsJSONType()) { schema_ele.converted_type = ConvertedType::JSON; schema_ele.__isset.converted_type = true; - schema_ele.__isset.logicalType = true; - schema_ele.logicalType.__set_JSON(duckdb_parquet::JsonType()); return; } switch (duckdb_type.id()) { @@ -319,15 +317,13 @@ void VerifyUniqueNames(const vector &names) { ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file_name_p, vector types_p, vector names_p, CompressionCodec::type codec, ChildFieldIDs field_ids_p, const vector> &kv_metadata, - shared_ptr encryption_config_p, idx_t dictionary_size_limit_p, - double bloom_filter_false_positive_ratio_p, int64_t compression_level_p, + shared_ptr encryption_config_p, + double dictionary_compression_ratio_threshold_p, optional_idx compression_level_p, bool debug_use_openssl_p) : file_name(std::move(file_name_p)), sql_types(std::move(types_p)), column_names(std::move(names_p)), codec(codec), field_ids(std::move(field_ids_p)), encryption_config(std::move(encryption_config_p)), - dictionary_size_limit(dictionary_size_limit_p), - bloom_filter_false_positive_ratio(bloom_filter_false_positive_ratio_p), compression_level(compression_level_p), + dictionary_compression_ratio_threshold(dictionary_compression_ratio_threshold_p), debug_use_openssl(debug_use_openssl_p) { - // initialize the file writer writer = make_uniq(fs, file_name.c_str(), FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE_NEW); @@ -360,18 +356,31 @@ ParquetWriter::ParquetWriter(ClientContext &context, FileSystem &fs, string file file_meta_data.schema.resize(1); for (auto &kv_pair : kv_metadata) { - duckdb_parquet::KeyValue kv; + duckdb_parquet::format::KeyValue kv; kv.__set_key(kv_pair.first); kv.__set_value(kv_pair.second); file_meta_data.key_value_metadata.push_back(kv); file_meta_data.__isset.key_value_metadata = true; } + if (compression_level_p.IsValid()) { + idx_t level = compression_level_p.GetIndex(); + switch (codec) { + case CompressionCodec::ZSTD: + if (level < 1 || level > 22) { + throw BinderException("Compression level for ZSTD must be between 1 and 22"); + } + break; + default: + throw NotImplementedException("Compression level is only supported for the ZSTD compression codec"); + } + compression_level = level; + } // populate root schema object file_meta_data.schema[0].name = "duckdb_schema"; file_meta_data.schema[0].num_children = NumericCast(sql_types.size()); file_meta_data.schema[0].__isset.num_children = true; - file_meta_data.schema[0].repetition_type = duckdb_parquet::FieldRepetitionType::REQUIRED; + file_meta_data.schema[0].repetition_type = duckdb_parquet::format::FieldRepetitionType::REQUIRED; file_meta_data.schema[0].__isset.repetition_type = true; auto &unique_names = column_names; @@ -526,41 +535,12 @@ void ParquetWriter::Flush(ColumnDataCollection &buffer) { } void ParquetWriter::Finalize() { - - // dump the bloom filters right before footer, not if stuff is encrypted - - for (auto &bloom_filter_entry : bloom_filters) { - D_ASSERT(!encryption_config); - // write nonsense bloom filter header - duckdb_parquet::BloomFilterHeader filter_header; - auto bloom_filter_bytes = bloom_filter_entry.bloom_filter->Get(); - filter_header.numBytes = NumericCast(bloom_filter_bytes->len); - filter_header.algorithm.__set_BLOCK(duckdb_parquet::SplitBlockAlgorithm()); - filter_header.compression.__set_UNCOMPRESSED(duckdb_parquet::Uncompressed()); - filter_header.hash.__set_XXHASH(duckdb_parquet::XxHash()); - - // set metadata flags - auto &column_chunk = - file_meta_data.row_groups[bloom_filter_entry.row_group_idx].columns[bloom_filter_entry.column_idx]; - - column_chunk.meta_data.__isset.bloom_filter_offset = true; - column_chunk.meta_data.bloom_filter_offset = NumericCast(writer->GetTotalWritten()); - - auto bloom_filter_header_size = Write(filter_header); - // write actual data - WriteData(bloom_filter_bytes->ptr, bloom_filter_bytes->len); - - column_chunk.meta_data.__isset.bloom_filter_length = true; - column_chunk.meta_data.bloom_filter_length = - NumericCast(bloom_filter_header_size + bloom_filter_bytes->len); - } - - const auto metadata_start_offset = writer->GetTotalWritten(); + const auto start_offset = writer->GetTotalWritten(); if (encryption_config) { // Crypto metadata is written unencrypted FileCryptoMetaData crypto_metadata; - duckdb_parquet::AesGcmV1 aes_gcm_v1; - duckdb_parquet::EncryptionAlgorithm alg; + duckdb_parquet::format::AesGcmV1 aes_gcm_v1; + duckdb_parquet::format::EncryptionAlgorithm alg; alg.__set_AES_GCM_V1(aes_gcm_v1); crypto_metadata.__set_encryption_algorithm(alg); crypto_metadata.write(protocol.get()); @@ -573,7 +553,7 @@ void ParquetWriter::Finalize() { Write(file_meta_data); - writer->Write(writer->GetTotalWritten() - metadata_start_offset); + writer->Write(writer->GetTotalWritten() - start_offset); if (encryption_config) { // encrypted parquet files also end with the string "PARE" @@ -595,15 +575,4 @@ GeoParquetFileMetadata &ParquetWriter::GetGeoParquetData() { return *geoparquet_data; } -void ParquetWriter::BufferBloomFilter(idx_t col_idx, unique_ptr bloom_filter) { - if (encryption_config) { - return; - } - ParquetBloomFilterEntry new_entry; - new_entry.bloom_filter = std::move(bloom_filter); - new_entry.column_idx = col_idx; - new_entry.row_group_idx = file_meta_data.row_groups.size(); - bloom_filters.push_back(std::move(new_entry)); -} - } // namespace duckdb diff --git a/src/duckdb/extension/parquet/serialize_parquet.cpp b/src/duckdb/extension/parquet/serialize_parquet.cpp index bcb334a45..b72a78be2 100644 --- a/src/duckdb/extension/parquet/serialize_parquet.cpp +++ b/src/duckdb/extension/parquet/serialize_parquet.cpp @@ -70,7 +70,6 @@ void ParquetOptions::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(103, "schema", schema); serializer.WritePropertyWithDefault>(104, "encryption_config", encryption_config, nullptr); serializer.WritePropertyWithDefault(105, "debug_use_openssl", debug_use_openssl, true); - serializer.WritePropertyWithDefault(106, "explicit_cardinality", explicit_cardinality, 0); } ParquetOptions ParquetOptions::Deserialize(Deserializer &deserializer) { @@ -81,7 +80,6 @@ ParquetOptions ParquetOptions::Deserialize(Deserializer &deserializer) { deserializer.ReadPropertyWithDefault>(103, "schema", result.schema); deserializer.ReadPropertyWithExplicitDefault>(104, "encryption_config", result.encryption_config, nullptr); deserializer.ReadPropertyWithExplicitDefault(105, "debug_use_openssl", result.debug_use_openssl, true); - deserializer.ReadPropertyWithExplicitDefault(106, "explicit_cardinality", result.explicit_cardinality, 0); return result; } diff --git a/src/duckdb/extension/parquet/zstd_file_system.cpp b/src/duckdb/extension/parquet/zstd_file_system.cpp index 7204f3607..5a630b056 100644 --- a/src/duckdb/extension/parquet/zstd_file_system.cpp +++ b/src/duckdb/extension/parquet/zstd_file_system.cpp @@ -1,5 +1,4 @@ #include "zstd_file_system.hpp" - #include "zstd.h" namespace duckdb { @@ -185,16 +184,4 @@ idx_t ZStdFileSystem::OutBufferSize() { return duckdb_zstd::ZSTD_DStreamOutSize(); } -int64_t ZStdFileSystem::DefaultCompressionLevel() { - return duckdb_zstd::ZSTD_defaultCLevel(); -} - -int64_t ZStdFileSystem::MinimumCompressionLevel() { - return duckdb_zstd::ZSTD_minCLevel(); -} - -int64_t ZStdFileSystem::MaximumCompressionLevel() { - return duckdb_zstd::ZSTD_maxCLevel(); -} - } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog.cpp b/src/duckdb/src/catalog/catalog.cpp index 45047f185..08a01d93d 100644 --- a/src/duckdb/src/catalog/catalog.cpp +++ b/src/duckdb/src/catalog/catalog.cpp @@ -71,12 +71,7 @@ Catalog &Catalog::GetSystemCatalog(ClientContext &context) { return Catalog::GetSystemCatalog(*context.db); } -const string &GetDefaultCatalog(CatalogEntryRetriever &retriever) { - return DatabaseManager::GetDefaultDatabase(retriever.GetContext()); -} - -optional_ptr Catalog::GetCatalogEntry(CatalogEntryRetriever &retriever, const string &catalog_name) { - auto &context = retriever.GetContext(); +optional_ptr Catalog::GetCatalogEntry(ClientContext &context, const string &catalog_name) { auto &db_manager = DatabaseManager::Get(context); if (catalog_name == TEMP_CATALOG) { return &ClientData::Get(context).temporary_objects->GetCatalog(); @@ -84,32 +79,22 @@ optional_ptr Catalog::GetCatalogEntry(CatalogEntryRetriever &retriever, if (catalog_name == SYSTEM_CATALOG) { return &GetSystemCatalog(context); } - auto entry = - db_manager.GetDatabase(context, IsInvalidCatalog(catalog_name) ? GetDefaultCatalog(retriever) : catalog_name); + auto entry = db_manager.GetDatabase( + context, IsInvalidCatalog(catalog_name) ? DatabaseManager::GetDefaultDatabase(context) : catalog_name); if (!entry) { return nullptr; } return &entry->GetCatalog(); } -optional_ptr Catalog::GetCatalogEntry(ClientContext &context, const string &catalog_name) { - CatalogEntryRetriever entry_retriever(context); - return GetCatalogEntry(entry_retriever, catalog_name); -} - -Catalog &Catalog::GetCatalog(CatalogEntryRetriever &retriever, const string &catalog_name) { - auto catalog = Catalog::GetCatalogEntry(retriever, catalog_name); +Catalog &Catalog::GetCatalog(ClientContext &context, const string &catalog_name) { + auto catalog = Catalog::GetCatalogEntry(context, catalog_name); if (!catalog) { throw BinderException("Catalog \"%s\" does not exist!", catalog_name); } return *catalog; } -Catalog &Catalog::GetCatalog(ClientContext &context, const string &catalog_name) { - CatalogEntryRetriever entry_retriever(context); - return GetCatalog(entry_retriever, catalog_name); -} - //===--------------------------------------------------------------------===// // Schema //===--------------------------------------------------------------------===// @@ -304,24 +289,26 @@ optional_ptr Catalog::CreateIndex(ClientContext &context, CreateIn return CreateIndex(GetCatalogTransaction(context), info); } -unique_ptr Catalog::BindAlterAddIndex(Binder &binder, TableCatalogEntry &table_entry, - unique_ptr plan, - unique_ptr create_info, - unique_ptr alter_info) { - throw NotImplementedException("BindAlterAddIndex not supported by this catalog"); -} - //===--------------------------------------------------------------------===// // Lookup Structures //===--------------------------------------------------------------------===// struct CatalogLookup { - CatalogLookup(Catalog &catalog, string schema_p, string name_p) - : catalog(catalog), schema(std::move(schema_p)), name(std::move(name_p)) { + CatalogLookup(Catalog &catalog, string schema_p) : catalog(catalog), schema(std::move(schema_p)) { } Catalog &catalog; string schema; - string name; +}; + +//! Return value of Catalog::LookupEntry +struct CatalogEntryLookup { + optional_ptr schema; + optional_ptr entry; + ErrorData error; + + DUCKDB_API bool Found() const { + return entry; + } }; //===--------------------------------------------------------------------===// @@ -334,8 +321,8 @@ void Catalog::DropEntry(ClientContext &context, DropInfo &info) { return; } - CatalogEntryRetriever retriever(context); - auto lookup = LookupEntry(retriever, info.type, info.schema, info.name, info.if_not_found); + auto lookup = LookupEntry(context, info.type, info.schema, info.name, info.if_not_found); + if (!lookup.Found()) { return; } @@ -365,10 +352,9 @@ SchemaCatalogEntry &Catalog::GetSchema(CatalogTransaction transaction, const str //===--------------------------------------------------------------------===// // Lookup //===--------------------------------------------------------------------===// -vector Catalog::SimilarEntriesInSchemas(ClientContext &context, const string &entry_name, - CatalogType type, - const reference_set_t &schemas) { - vector results; +SimilarCatalogEntry Catalog::SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type, + const reference_set_t &schemas) { + SimilarCatalogEntry result; for (auto schema_ref : schemas) { auto &schema = schema_ref.get(); auto transaction = schema.catalog.GetCatalogTransaction(context); @@ -377,23 +363,17 @@ vector Catalog::SimilarEntriesInSchemas(ClientContext &cont // no similar entry found continue; } - if (results.empty() || results[0].score <= entry.score) { - if (!results.empty() && results[0].score < entry.score) { - results.clear(); - } - - results.push_back(entry); - results.back().schema = &schema; + if (!result.Found() || result.score < entry.score) { + result = entry; + result.schema = &schema; } } - return results; + return result; } -vector GetCatalogEntries(CatalogEntryRetriever &retriever, const string &catalog, - const string &schema) { - auto &context = retriever.GetContext(); +vector GetCatalogEntries(ClientContext &context, const string &catalog, const string &schema) { vector entries; - auto &search_path = retriever.GetSearchPath(); + auto &search_path = *context.client_data->catalog_search_path; if (IsInvalidCatalog(catalog) && IsInvalidSchema(schema)) { // no catalog or schema provided - scan the entire search path entries = search_path.Get(); @@ -403,12 +383,7 @@ vector GetCatalogEntries(CatalogEntryRetriever &retriever, c entries.emplace_back(catalog_name, schema); } if (entries.empty()) { - auto &default_entry = search_path.GetDefault(); - if (!IsInvalidCatalog(default_entry.catalog)) { - entries.emplace_back(default_entry.catalog, schema); - } else { - entries.emplace_back(DatabaseManager::GetDefaultDatabase(context), schema); - } + entries.emplace_back(DatabaseManager::GetDefaultDatabase(context), schema); } } else if (IsInvalidSchema(schema)) { auto schemas = search_path.GetSchemasForCatalog(catalog); @@ -425,11 +400,11 @@ vector GetCatalogEntries(CatalogEntryRetriever &retriever, c return entries; } -void FindMinimalQualification(CatalogEntryRetriever &retriever, const string &catalog_name, const string &schema_name, +void FindMinimalQualification(ClientContext &context, const string &catalog_name, const string &schema_name, bool &qualify_database, bool &qualify_schema) { // check if we can we qualify ONLY the schema bool found = false; - auto entries = GetCatalogEntries(retriever, INVALID_CATALOG, schema_name); + auto entries = GetCatalogEntries(context, INVALID_CATALOG, schema_name); for (auto &entry : entries) { if (entry.catalog == catalog_name && entry.schema == schema_name) { found = true; @@ -443,7 +418,7 @@ void FindMinimalQualification(CatalogEntryRetriever &retriever, const string &ca } // check if we can qualify ONLY the catalog found = false; - entries = GetCatalogEntries(retriever, catalog_name, INVALID_SCHEMA); + entries = GetCatalogEntries(context, catalog_name, INVALID_SCHEMA); for (auto &entry : entries) { if (entry.catalog == catalog_name && entry.schema == schema_name) { found = true; @@ -501,38 +476,25 @@ static bool IsAutoloadableFunction(CatalogType type) { type == CatalogType::AGGREGATE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY); } -bool IsTableFunction(CatalogType type) { - switch (type) { - case CatalogType::TABLE_FUNCTION_ENTRY: - case CatalogType::TABLE_MACRO_ENTRY: - case CatalogType::PRAGMA_FUNCTION_ENTRY: - return true; - default: - return false; - } -} - -bool IsScalarFunction(CatalogType type) { - switch (type) { - case CatalogType::SCALAR_FUNCTION_ENTRY: - case CatalogType::AGGREGATE_FUNCTION_ENTRY: - case CatalogType::MACRO_ENTRY: - return true; - default: - return false; - } -} - static bool CompareCatalogTypes(CatalogType type_a, CatalogType type_b) { if (type_a == type_b) { // Types are same return true; } - if (IsScalarFunction(type_a) && IsScalarFunction(type_b)) { - return true; - } - if (IsTableFunction(type_a) && IsTableFunction(type_b)) { - return true; + if (!IsAutoloadableFunction(type_a)) { + D_ASSERT(IsAutoloadableFunction(type_b)); + // Make sure that `type_a` is an autoloadable function + return CompareCatalogTypes(type_b, type_a); + } + if (type_a == CatalogType::TABLE_FUNCTION_ENTRY) { + // These are all table functions + return type_b == CatalogType::TABLE_MACRO_ENTRY || type_b == CatalogType::PRAGMA_FUNCTION_ENTRY; + } else if (type_a == CatalogType::SCALAR_FUNCTION_ENTRY) { + // These are all scalar functions + return type_b == CatalogType::MACRO_ENTRY; + } else if (type_a == CatalogType::PRAGMA_FUNCTION_ENTRY) { + // These are all table functions + return type_b == CatalogType::TABLE_MACRO_ENTRY || type_b == CatalogType::TABLE_FUNCTION_ENTRY; } return false; } @@ -591,19 +553,18 @@ CatalogException Catalog::UnrecognizedConfigurationError(ClientContext &context, throw CatalogException::MissingEntry("configuration parameter", name, potential_names); } -CatalogException Catalog::CreateMissingEntryException(CatalogEntryRetriever &retriever, const string &entry_name, +CatalogException Catalog::CreateMissingEntryException(ClientContext &context, const string &entry_name, CatalogType type, const reference_set_t &schemas, QueryErrorContext error_context) { - auto &context = retriever.GetContext(); - auto entries = SimilarEntriesInSchemas(context, entry_name, type, schemas); + auto entry = SimilarEntryInSchemas(context, entry_name, type, schemas); reference_set_t unseen_schemas; auto &db_manager = DatabaseManager::Get(context); auto databases = db_manager.GetDatabases(context); auto &config = DBConfig::GetConfig(context); - auto max_schema_count = config.GetSetting(context); + auto max_schema_count = config.options.catalog_error_max_schemas; for (auto database : databases) { if (unseen_schemas.size() >= max_schema_count) { break; @@ -676,36 +637,20 @@ CatalogException Catalog::CreateMissingEntryException(CatalogEntryRetriever &ret // entries in other schemas get a penalty // however, if there is an exact match in another schema, we will always show it static constexpr const double UNSEEN_PENALTY = 0.2; - auto unseen_entries = SimilarEntriesInSchemas(context, entry_name, type, unseen_schemas); - vector suggestions; - if (!unseen_entries.empty() && (unseen_entries[0].score == 1.0 || unseen_entries[0].score - UNSEEN_PENALTY > - (entries.empty() ? 0.0 : entries[0].score))) { + auto unseen_entry = SimilarEntryInSchemas(context, entry_name, type, unseen_schemas); + string did_you_mean; + if (unseen_entry.Found() && (unseen_entry.score == 1.0 || unseen_entry.score - UNSEEN_PENALTY > entry.score)) { // the closest matching entry requires qualification as it is not in the default search path // check how to minimally qualify this entry - for (auto &unseen_entry : unseen_entries) { - auto catalog_name = unseen_entry.schema->catalog.GetName(); - auto schema_name = unseen_entry.schema->name; - bool qualify_database; - bool qualify_schema; - FindMinimalQualification(retriever, catalog_name, schema_name, qualify_database, qualify_schema); - suggestions.push_back(unseen_entry.GetQualifiedName(qualify_database, qualify_schema)); - } - } else if (!entries.empty()) { - for (auto &entry : entries) { - suggestions.push_back(entry.name); - } - } - - string did_you_mean; - std::sort(suggestions.begin(), suggestions.end()); - if (suggestions.size() > 2) { - auto last = suggestions.back(); - suggestions.pop_back(); - did_you_mean = StringUtil::Join(suggestions, ", ") + ", or " + last; - } else { - did_you_mean = StringUtil::Join(suggestions, " or "); + auto catalog_name = unseen_entry.schema->catalog.GetName(); + auto schema_name = unseen_entry.schema->name; + bool qualify_database; + bool qualify_schema; + FindMinimalQualification(context, catalog_name, schema_name, qualify_database, qualify_schema); + did_you_mean = unseen_entry.GetQualifiedName(qualify_database, qualify_schema); + } else if (entry.Found()) { + did_you_mean = entry.name; } - return CatalogException::MissingEntry(type, entry_name, did_you_mean, error_context); } @@ -722,14 +667,13 @@ CatalogEntryLookup Catalog::TryLookupEntryInternal(CatalogTransaction transactio return {schema_entry, entry, ErrorData()}; } -CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, +CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto &context = retriever.GetContext(); reference_set_t schemas; if (IsInvalidSchema(schema)) { // try all schemas for this catalog - auto entries = GetCatalogEntries(retriever, GetName(), INVALID_SCHEMA); + auto entries = GetCatalogEntries(context, GetName(), INVALID_SCHEMA); for (auto &entry : entries) { auto &candidate_schema = entry.schema; auto transaction = GetCatalogTransaction(context); @@ -755,15 +699,15 @@ CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, Cat if (if_not_found == OnEntryNotFound::RETURN_NULL) { return {nullptr, nullptr, ErrorData()}; } else { - auto except = CreateMissingEntryException(retriever, name, type, schemas, error_context); + auto except = CreateMissingEntryException(context, name, type, schemas, error_context); return {nullptr, nullptr, ErrorData(except)}; } } -CatalogEntryLookup Catalog::LookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, +CatalogEntryLookup Catalog::LookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto res = TryLookupEntry(retriever, type, schema, name, if_not_found, error_context); + auto res = TryLookupEntry(context, type, schema, name, if_not_found, error_context); if (res.error.HasError()) { res.error.Throw(); @@ -772,14 +716,13 @@ CatalogEntryLookup Catalog::LookupEntry(CatalogEntryRetriever &retriever, Catalo return res; } -CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, vector &lookups, - CatalogType type, const string &name, OnEntryNotFound if_not_found, +CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, vector &lookups, CatalogType type, + const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto &context = retriever.GetContext(); reference_set_t schemas; for (auto &lookup : lookups) { auto transaction = lookup.catalog.GetCatalogTransaction(context); - auto result = lookup.catalog.TryLookupEntryInternal(transaction, type, lookup.schema, lookup.name); + auto result = lookup.catalog.TryLookupEntryInternal(transaction, type, lookup.schema, name); if (result.Found()) { return result; } @@ -791,60 +734,24 @@ CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, vec if (if_not_found == OnEntryNotFound::RETURN_NULL) { return {nullptr, nullptr, ErrorData()}; } else { - auto except = CreateMissingEntryException(retriever, name, type, schemas, error_context); + auto except = CreateMissingEntryException(context, name, type, schemas, error_context); return {nullptr, nullptr, ErrorData(except)}; } } -CatalogEntryLookup Catalog::TryLookupDefaultTable(CatalogEntryRetriever &retriever, CatalogType type, - const string &catalog, const string &schema, const string &name, - OnEntryNotFound if_not_found, QueryErrorContext error_context) { - // Default tables of catalogs can only be accessed by the catalog name directly - if (!schema.empty() || !catalog.empty()) { - return {nullptr, nullptr, ErrorData()}; - } - - vector catalog_by_name_lookups; - auto catalog_by_name = GetCatalogEntry(retriever, name); - if (catalog_by_name && catalog_by_name->HasDefaultTable()) { - catalog_by_name_lookups.emplace_back(*catalog_by_name, catalog_by_name->GetDefaultTableSchema(), - catalog_by_name->GetDefaultTable()); - } - - return TryLookupEntry(retriever, catalog_by_name_lookups, type, name, if_not_found, error_context); -} - -static void ThrowDefaultTableAmbiguityException(CatalogEntryLookup &base_lookup, CatalogEntryLookup &default_table, - const string &name) { - auto entry_type = CatalogTypeToString(base_lookup.entry->type); - string fully_qualified_name_hint; - if (base_lookup.schema) { - fully_qualified_name_hint = StringUtil::Format(": '%s.%s.%s'", base_lookup.schema->catalog.GetName(), - base_lookup.schema->name, base_lookup.entry->name); - } - string fully_qualified_catalog_name_hint = StringUtil::Format( - ": '%s.%s.%s'", default_table.schema->catalog.GetName(), default_table.schema->name, default_table.entry->name); - throw CatalogException( - "Ambiguity detected for '%s': this could either refer to the '%s' '%s', or the " - "attached catalog '%s' which has a default table. To avoid this error, either detach the catalog and " - "reattach under a different name, or use a fully qualified name for the '%s'%s or for the Catalog " - "Default Table%s.", - name, entry_type, name, name, entry_type, fully_qualified_name_hint, fully_qualified_catalog_name_hint); -} - -CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, +CatalogEntryLookup Catalog::TryLookupEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto entries = GetCatalogEntries(retriever, catalog, schema); + auto entries = GetCatalogEntries(context, catalog, schema); vector lookups; vector final_lookups; lookups.reserve(entries.size()); for (auto &entry : entries) { optional_ptr catalog_entry; if (if_not_found == OnEntryNotFound::RETURN_NULL) { - catalog_entry = Catalog::GetCatalogEntry(retriever, entry.catalog); + catalog_entry = Catalog::GetCatalogEntry(context, entry.catalog); } else { - catalog_entry = &Catalog::GetCatalog(retriever, entry.catalog); + catalog_entry = &Catalog::GetCatalog(context, entry.catalog); } if (!catalog_entry) { return {nullptr, nullptr, ErrorData()}; @@ -852,46 +759,26 @@ CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, Cat D_ASSERT(catalog_entry); auto lookup_behavior = catalog_entry->CatalogTypeLookupRule(type); if (lookup_behavior == CatalogLookupBehavior::STANDARD) { - lookups.emplace_back(*catalog_entry, entry.schema, name); + lookups.emplace_back(*catalog_entry, entry.schema); } else if (lookup_behavior == CatalogLookupBehavior::LOWER_PRIORITY) { - final_lookups.emplace_back(*catalog_entry, entry.schema, name); + final_lookups.emplace_back(*catalog_entry, entry.schema); } } - for (auto &lookup : final_lookups) { lookups.emplace_back(std::move(lookup)); } - - // Do the main lookup - auto lookup_result = TryLookupEntry(retriever, lookups, type, name, if_not_found, error_context); - - // Special case for tables: we do a second lookup searching for catalogs with default tables that also match this - // lookup - if (type == CatalogType::TABLE_ENTRY) { - auto lookup_result_default_table = - TryLookupDefaultTable(retriever, type, catalog, schema, name, OnEntryNotFound::RETURN_NULL, error_context); - - if (lookup_result_default_table.Found() && lookup_result.Found()) { - ThrowDefaultTableAmbiguityException(lookup_result, lookup_result_default_table, name); - } - - if (lookup_result_default_table.Found()) { - return lookup_result_default_table; - } - } - - return lookup_result; + return Catalog::TryLookupEntry(context, lookups, type, name, if_not_found, error_context); } -optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, CatalogType type, - const string &schema_name, const string &name, - OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto lookup_entry = TryLookupEntry(retriever, type, schema_name, name, if_not_found, error_context); +optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema_name, + const string &name, OnEntryNotFound if_not_found, + QueryErrorContext error_context) { + auto lookup_entry = TryLookupEntry(context, type, schema_name, name, if_not_found, error_context); // Try autoloading extension to resolve lookup if (!lookup_entry.Found()) { - if (AutoLoadExtensionByCatalogEntry(*retriever.GetContext().db, type, name)) { - lookup_entry = TryLookupEntry(retriever, type, schema_name, name, if_not_found, error_context); + if (AutoLoadExtensionByCatalogEntry(*context.db, type, name)) { + lookup_entry = TryLookupEntry(context, type, schema_name, name, if_not_found, error_context); } } @@ -902,27 +789,20 @@ optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, C return lookup_entry.entry.get(); } -optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema_name, - const string &name, OnEntryNotFound if_not_found, - QueryErrorContext error_context) { - CatalogEntryRetriever retriever(context); - return GetEntry(retriever, type, schema_name, name, if_not_found, error_context); -} - CatalogEntry &Catalog::GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, QueryErrorContext error_context) { return *Catalog::GetEntry(context, type, schema, name, OnEntryNotFound::THROW_EXCEPTION, error_context); } -optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, +optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto result = TryLookupEntry(retriever, type, catalog, schema, name, if_not_found, error_context); + auto result = TryLookupEntry(context, type, catalog, schema, name, if_not_found, error_context); // Try autoloading extension to resolve lookup if (!result.Found()) { - if (AutoLoadExtensionByCatalogEntry(*retriever.GetContext().db, type, name)) { - result = TryLookupEntry(retriever, type, catalog, schema, name, if_not_found, error_context); + if (AutoLoadExtensionByCatalogEntry(*context.db, type, name)) { + result = TryLookupEntry(context, type, catalog, schema, name, if_not_found, error_context); } } @@ -936,26 +816,20 @@ optional_ptr Catalog::GetEntry(CatalogEntryRetriever &retriever, C } return result.entry.get(); } -optional_ptr Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, - const string &schema, const string &name, OnEntryNotFound if_not_found, - QueryErrorContext error_context) { - CatalogEntryRetriever retriever(context); - return GetEntry(retriever, type, catalog, schema, name, if_not_found, error_context); -} CatalogEntry &Catalog::GetEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, QueryErrorContext error_context) { return *Catalog::GetEntry(context, type, catalog, schema, name, OnEntryNotFound::THROW_EXCEPTION, error_context); } -optional_ptr Catalog::GetSchema(CatalogEntryRetriever &retriever, const string &catalog_name, +optional_ptr Catalog::GetSchema(ClientContext &context, const string &catalog_name, const string &schema_name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { - auto entries = GetCatalogEntries(retriever, catalog_name, schema_name); + auto entries = GetCatalogEntries(context, catalog_name, schema_name); for (idx_t i = 0; i < entries.size(); i++) { auto on_not_found = i + 1 == entries.size() ? if_not_found : OnEntryNotFound::RETURN_NULL; - auto &catalog = Catalog::GetCatalog(retriever, entries[i].catalog); - auto result = catalog.GetSchema(retriever.GetContext(), schema_name, on_not_found, error_context); + auto &catalog = Catalog::GetCatalog(context, entries[i].catalog); + auto result = catalog.GetSchema(context, schema_name, on_not_found, error_context); if (result) { return result; } @@ -963,28 +837,20 @@ optional_ptr Catalog::GetSchema(CatalogEntryRetriever &retri return nullptr; } -optional_ptr Catalog::GetSchema(ClientContext &context, const string &catalog_name, - const string &schema_name, OnEntryNotFound if_not_found, - QueryErrorContext error_context) { - CatalogEntryRetriever retriever(context); - return GetSchema(retriever, catalog_name, schema_name, if_not_found, error_context); -} - vector> Catalog::GetSchemas(ClientContext &context) { vector> schemas; ScanSchemas(context, [&](SchemaCatalogEntry &entry) { schemas.push_back(entry); }); return schemas; } -vector> Catalog::GetSchemas(CatalogEntryRetriever &retriever, - const string &catalog_name) { +vector> Catalog::GetSchemas(ClientContext &context, const string &catalog_name) { vector> catalogs; if (IsInvalidCatalog(catalog_name)) { reference_set_t inserted_catalogs; - auto &search_path = retriever.GetSearchPath(); + auto &search_path = *context.client_data->catalog_search_path; for (auto &entry : search_path.Get()) { - auto &catalog = Catalog::GetCatalog(retriever, entry.catalog); + auto &catalog = Catalog::GetCatalog(context, entry.catalog); if (inserted_catalogs.find(catalog) != inserted_catalogs.end()) { continue; } @@ -992,21 +858,16 @@ vector> Catalog::GetSchemas(CatalogEntryRetriever catalogs.push_back(catalog); } } else { - catalogs.push_back(Catalog::GetCatalog(retriever, catalog_name)); + catalogs.push_back(Catalog::GetCatalog(context, catalog_name)); } vector> result; for (auto catalog : catalogs) { - auto schemas = catalog.get().GetSchemas(retriever.GetContext()); + auto schemas = catalog.get().GetSchemas(context); result.insert(result.end(), schemas.begin(), schemas.end()); } return result; } -vector> Catalog::GetSchemas(ClientContext &context, const string &catalog_name) { - CatalogEntryRetriever retriever(context); - return GetSchemas(retriever, catalog_name); -} - vector> Catalog::GetAllSchemas(ClientContext &context) { vector> result; @@ -1035,8 +896,8 @@ vector> Catalog::GetAllSchemas(ClientContext &cont void Catalog::Alter(CatalogTransaction transaction, AlterInfo &info) { if (transaction.HasContext()) { - CatalogEntryRetriever retriever(transaction.GetContext()); - auto lookup = LookupEntry(retriever, info.GetCatalogType(), info.schema, info.name, info.if_not_found); + auto lookup = + LookupEntry(transaction.GetContext(), info.GetCatalogType(), info.schema, info.name, info.if_not_found); if (!lookup.Found()) { return; } @@ -1055,28 +916,6 @@ vector Catalog::GetMetadataInfo(ClientContext &context) { return vector(); } -optional_ptr Catalog::GetDependencyManager() { - return nullptr; -} - -//! Whether this catalog has a default table. Catalogs with a default table can be queries by their catalog name -bool Catalog::HasDefaultTable() const { - return !default_table.empty(); -} - -void Catalog::SetDefaultTable(const string &schema, const string &name) { - default_table = name; - default_table_schema = schema; -} - -string Catalog::GetDefaultTable() const { - return default_table; -} - -string Catalog::GetDefaultTableSchema() const { - return !default_table_schema.empty() ? default_table_schema : DEFAULT_SCHEMA; -} - void Catalog::Verify() { } diff --git a/src/duckdb/src/catalog/catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry.cpp index d6a96d6ec..3c8f383ae 100644 --- a/src/duckdb/src/catalog/catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry.cpp @@ -109,9 +109,6 @@ unique_ptr CatalogEntry::Deserialize(Deserializer &deserializer) { void CatalogEntry::Verify(Catalog &catalog_p) { } -void CatalogEntry::Rollback(CatalogEntry &prev_entry) { -} - InCatalogEntry::InCatalogEntry(CatalogType type, Catalog &catalog, string name) : CatalogEntry(type, catalog, std::move(name)), catalog(catalog) { } diff --git a/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp index c70984e53..be047bfe3 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_index_entry.cpp @@ -9,20 +9,17 @@ IndexDataTableInfo::IndexDataTableInfo(shared_ptr info_p, const s : info(std::move(info_p)), index_name(index_name_p) { } -void DuckIndexEntry::Rollback(CatalogEntry &) { +IndexDataTableInfo::~IndexDataTableInfo() { if (!info) { return; } - if (!info->info) { - return; - } - info->info->GetIndexes().RemoveIndex(name); + // FIXME: this should happen differently. + info->GetIndexes().RemoveIndex(index_name); } DuckIndexEntry::DuckIndexEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateIndexInfo &create_info, TableCatalogEntry &table_p) : IndexCatalogEntry(catalog, schema, create_info), initial_index_size(0) { - auto &table = table_p.Cast(); auto &storage = table.GetStorage(); info = make_shared_ptr(storage.GetDataTableInfo(), name); @@ -57,9 +54,7 @@ DataTableInfo &DuckIndexEntry::GetDataTableInfo() const { void DuckIndexEntry::CommitDrop() { D_ASSERT(info); - auto &indexes = GetDataTableInfo().GetIndexes(); - indexes.CommitDrop(name); - indexes.RemoveIndex(name); + GetDataTableInfo().GetIndexes().CommitDrop(name); } } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp index 9f07d4acf..f3c8684fb 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp @@ -168,9 +168,6 @@ optional_ptr DuckSchemaEntry::CreateTable(CatalogTransaction trans auto &set = GetCatalogSet(CatalogType::TABLE_ENTRY); info.dependencies.AddDependency(*set.GetEntry(transaction, fk_info.name)); } - for (auto &dep : info.dependencies.Set()) { - table->dependencies.AddDependency(dep); - } auto entry = AddEntryInternal(transaction, std::move(table), info.Base().on_conflict, info.dependencies); if (!entry) { @@ -369,11 +366,6 @@ optional_ptr DuckSchemaEntry::GetEntry(CatalogTransaction transact return GetCatalogSet(type).GetEntry(transaction, name); } -CatalogSet::EntryLookup DuckSchemaEntry::GetEntryDetailed(CatalogTransaction transaction, CatalogType type, - const string &name) { - return GetCatalogSet(type).GetEntryDetailed(transaction, name); -} - SimilarCatalogEntry DuckSchemaEntry::GetSimilarEntry(CatalogTransaction transaction, CatalogType type, const string &name) { return GetCatalogSet(type).SimilarEntry(transaction, name); diff --git a/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp b/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp index 4983710d9..be1041f9b 100644 --- a/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp @@ -20,22 +20,72 @@ #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/operator/logical_update.hpp" #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" +#include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/storage_manager.hpp" #include "duckdb/storage/table_storage_info.hpp" namespace duckdb { -IndexStorageInfo GetIndexInfo(const IndexConstraintType type, const bool v1_0_0_storage, unique_ptr &info, - const idx_t id) { +void AddDataTableIndex(DataTable &storage, const ColumnList &columns, const vector &keys, + IndexConstraintType constraint_type, const IndexStorageInfo &info) { + + // fetch types and create expressions for the index from the columns + vector column_ids; + vector> unbound_expressions; + vector> bound_expressions; + idx_t key_nr = 0; + column_ids.reserve(keys.size()); + for (auto &physical_key : keys) { + auto &column = columns.GetColumn(physical_key); + D_ASSERT(!column.Generated()); + unbound_expressions.push_back( + make_uniq(column.Name(), column.Type(), ColumnBinding(0, column_ids.size()))); + + bound_expressions.push_back(make_uniq(column.Type(), key_nr++)); + column_ids.push_back(column.StorageOid()); + } + // create an adaptive radix tree around the expressions + auto art = make_uniq(info.name, constraint_type, column_ids, TableIOManager::Get(storage), + std::move(unbound_expressions), storage.db, nullptr, info); + if (!info.IsValid() && !info.name.empty() && !storage.IsRoot()) { + throw TransactionException("Transaction conflict: cannot add an index to a table that has been altered!"); + } + storage.AddIndex(std::move(art)); +} + +void AddDataTableIndex(DataTable &storage, const ColumnList &columns, vector &keys, + IndexConstraintType constraint_type, const IndexStorageInfo &info) { + vector new_keys; + new_keys.reserve(keys.size()); + for (auto &logical_key : keys) { + new_keys.push_back(columns.LogicalToPhysical(logical_key)); + } + AddDataTableIndex(storage, columns, new_keys, constraint_type, info); +} + +IndexStorageInfo GetIndexInfo(const IndexConstraintType &constraint_type, const bool v1_0_0_storage, + unique_ptr &create_info, const idx_t identifier) { - auto &table_info = info->Cast(); - auto constraint_name = EnumUtil::ToString(type) + "_"; - auto name = constraint_name + table_info.table + "_" + to_string(id); - IndexStorageInfo index_info(name); + auto &create_table_info = create_info->Cast(); + auto constraint_name = EnumUtil::ToString(constraint_type) + "_"; + auto name = constraint_name + create_table_info.table + "_" + to_string(identifier); + IndexStorageInfo info(name); if (!v1_0_0_storage) { - index_info.options.emplace("v1_0_0_storage", v1_0_0_storage); + info.options.emplace("v1_0_0_storage", v1_0_0_storage); + } + return info; +} + +vector GetUniqueConstraintKeys(const ColumnList &columns, const UniqueConstraint &constraint) { + vector indexes; + if (constraint.HasIndex()) { + indexes.push_back(columns.LogicalToPhysical(constraint.GetIndex())); + } else { + for (auto &keyname : constraint.GetColumnNames()) { + indexes.push_back(columns.GetColumn(keyname).Physical()); + } } - return index_info; + return indexes; } DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, BoundCreateTableInfo &info, @@ -51,30 +101,28 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou } // create the physical storage - vector column_defs; + vector storage_columns; for (auto &col_def : columns.Physical()) { - column_defs.push_back(col_def.Copy()); + storage_columns.push_back(col_def.Copy()); } storage = make_shared_ptr(catalog.GetAttached(), StorageManager::Get(catalog).GetTableIOManager(&info), - schema.name, name, std::move(column_defs), std::move(info.data)); + schema.name, name, std::move(storage_columns), std::move(info.data)); - // Create the unique indexes for the UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints. + // create the unique indexes for the UNIQUE and PRIMARY KEY and FOREIGN KEY constraints idx_t indexes_idx = 0; for (idx_t i = 0; i < constraints.size(); i++) { auto &constraint = constraints[i]; if (constraint->type == ConstraintType::UNIQUE) { - - // UNIQUE constraint: Create a unique index. + // unique constraint: create a unique index auto &unique = constraint->Cast(); IndexConstraintType constraint_type = IndexConstraintType::UNIQUE; if (unique.is_primary_key) { constraint_type = IndexConstraintType::PRIMARY; } - - auto column_indexes = unique.GetLogicalIndexes(columns); + auto unique_keys = GetUniqueConstraintKeys(columns, unique); if (info.indexes.empty()) { - auto index_info = GetIndexInfo(constraint_type, false, info.base, i); - storage->AddIndex(columns, column_indexes, constraint_type, index_info); + auto index_storage_info = GetIndexInfo(constraint_type, false, info.base, i); + AddDataTableIndex(*storage, columns, unique_keys, constraint_type, index_storage_info); continue; } @@ -84,27 +132,21 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou info.indexes[indexes_idx].name = name_info.name; } - // Now we can add the index. - storage->AddIndex(columns, column_indexes, constraint_type, info.indexes[indexes_idx++]); + // now add the index + AddDataTableIndex(*storage, columns, unique_keys, constraint_type, info.indexes[indexes_idx++]); continue; } if (constraint->type == ConstraintType::FOREIGN_KEY) { - // Create a FOREIGN KEY index. + // foreign key constraint: create a foreign key index auto &bfk = constraint->Cast(); if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { - vector column_indexes; - for (const auto &physical_index : bfk.info.fk_keys) { - auto &col = columns.GetColumn(physical_index); - column_indexes.push_back(col.Logical()); - } - if (info.indexes.empty()) { auto constraint_type = IndexConstraintType::FOREIGN; - auto index_info = GetIndexInfo(constraint_type, false, info.base, i); - storage->AddIndex(columns, column_indexes, constraint_type, index_info); + auto index_storage_info = GetIndexInfo(constraint_type, false, info.base, i); + AddDataTableIndex(*storage, columns, bfk.info.fk_keys, constraint_type, index_storage_info); continue; } @@ -114,8 +156,9 @@ DuckTableEntry::DuckTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, Bou info.indexes[indexes_idx].name = name_info.name; } - // Now we can add the index. - storage->AddIndex(columns, column_indexes, IndexConstraintType::FOREIGN, info.indexes[indexes_idx++]); + // now add the index + AddDataTableIndex(*storage, columns, bfk.info.fk_keys, IndexConstraintType::FOREIGN, + info.indexes[indexes_idx++]); } } } @@ -136,10 +179,6 @@ unique_ptr DuckTableEntry::GetStatistics(ClientContext &context, return storage->GetStatistics(context, column.StorageOid()); } -unique_ptr DuckTableEntry::GetSample() { - return storage->GetSample(); -} - unique_ptr DuckTableEntry::AlterEntry(CatalogTransaction transaction, AlterInfo &info) { if (transaction.HasContext()) { return AlterEntry(transaction.GetContext(), info); @@ -219,10 +258,6 @@ unique_ptr DuckTableEntry::AlterEntry(ClientContext &context, Alte auto &drop_not_null_info = table_info.Cast(); return DropNotNull(context, drop_not_null_info); } - case AlterTableType::ADD_CONSTRAINT: { - auto &add_constraint_info = table_info.Cast(); - return AddConstraint(context, add_constraint_info); - } default: throw InternalException("Unrecognized alter table type!"); } @@ -243,7 +278,7 @@ void DuckTableEntry::UndoAlter(ClientContext &context, AlterInfo &info) { } static void RenameExpression(ParsedExpression &expr, RenameColumnInfo &info) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); if (colref.column_names.back() == info.old_name) { colref.column_names.back() = info.new_name; @@ -530,6 +565,7 @@ unique_ptr DuckTableEntry::SetDefault(ClientContext &context, SetD } unique_ptr DuckTableEntry::SetNotNull(ClientContext &context, SetNotNullInfo &info) { + auto create_info = make_uniq(schema, name); create_info->comment = comment; create_info->tags = tags; @@ -562,9 +598,8 @@ unique_ptr DuckTableEntry::SetNotNull(ClientContext &context, SetN } // Return with new storage info. Note that we need the bound column index here. - auto physical_columns = columns.LogicalToPhysical(LogicalIndex(not_null_idx)); - auto bound_constraint = make_uniq(physical_columns); - auto new_storage = make_shared_ptr(context, *storage, *bound_constraint); + auto new_storage = make_shared_ptr( + context, *storage, make_uniq(columns.LogicalToPhysical(LogicalIndex(not_null_idx)))); return make_uniq(catalog, schema, *bound_create_info, new_storage); } @@ -595,24 +630,12 @@ unique_ptr DuckTableEntry::DropNotNull(ClientContext &context, Dro unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context, ChangeColumnTypeInfo &info) { auto binder = Binder::CreateBinder(context); binder->BindLogicalType(info.target_type, &catalog, schema.name); - auto change_idx = GetColumnIndex(info.column_name); auto create_info = make_uniq(schema, name); create_info->temporary = temporary; create_info->comment = comment; create_info->tags = tags; - // Bind the USING expression. - vector bound_columns; - AlterBinder expr_binder(*binder, context, *this, bound_columns, info.target_type); - auto expression = info.expression->Copy(); - auto bound_expression = expr_binder.Bind(expression); - - // Infer the target_type from the USING expression, if not set explicitly. - if (info.target_type == LogicalType::UNKNOWN) { - info.target_type = bound_expression->return_type; - } - auto bound_constraints = binder->BindConstraints(constraints, name, columns); for (auto &col : columns.Logical()) { auto copy = col.Copy(); @@ -632,11 +655,11 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context create_info->columns.AddColumn(std::move(copy)); } - for (idx_t constr_idx = 0; constr_idx < constraints.size(); constr_idx++) { - auto constraint = constraints[constr_idx]->Copy(); + for (idx_t i = 0; i < constraints.size(); i++) { + auto constraint = constraints[i]->Copy(); switch (constraint->type) { case ConstraintType::CHECK: { - auto &bound_check = bound_constraints[constr_idx]->Cast(); + auto &bound_check = bound_constraints[i]->Cast(); auto physical_index = columns.LogicalToPhysical(change_idx); if (bound_check.bound_columns.find(physical_index) != bound_check.bound_columns.end()) { throw BinderException("Cannot change the type of a column that has a CHECK constraint specified"); @@ -646,21 +669,22 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context case ConstraintType::NOT_NULL: break; case ConstraintType::UNIQUE: { - auto &bound_unique = bound_constraints[constr_idx]->Cast(); - auto physical_index = columns.LogicalToPhysical(change_idx); - if (bound_unique.key_set.find(physical_index) != bound_unique.key_set.end()) { + auto &bound_unique = bound_constraints[i]->Cast(); + if (bound_unique.key_set.find(change_idx) != bound_unique.key_set.end()) { throw BinderException( "Cannot change the type of a column that has a UNIQUE or PRIMARY KEY constraint specified"); } break; } case ConstraintType::FOREIGN_KEY: { - auto &bfk = bound_constraints[constr_idx]->Cast(); + auto &bfk = bound_constraints[i]->Cast(); auto key_set = bfk.pk_key_set; if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE) { key_set = bfk.fk_key_set; } else if (bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { - key_set.insert(bfk.info.fk_keys.begin(), bfk.info.fk_keys.end()); + for (idx_t i = 0; i < bfk.info.fk_keys.size(); i++) { + key_set.insert(bfk.info.fk_keys[i]); + } } if (key_set.find(columns.LogicalToPhysical(change_idx)) != key_set.end()) { throw BinderException("Cannot change the type of a column that has a FOREIGN KEY constraint specified"); @@ -673,14 +697,18 @@ unique_ptr DuckTableEntry::ChangeColumnType(ClientContext &context create_info->constraints.push_back(std::move(constraint)); } + // bind the specified expression + vector bound_columns; + AlterBinder expr_binder(*binder, context, *this, bound_columns, info.target_type); + auto expression = info.expression->Copy(); + auto bound_expression = expr_binder.Bind(expression); auto bound_create_info = binder->BindCreateTableInfo(std::move(create_info), schema); - - vector storage_oids; + vector storage_oids; for (idx_t i = 0; i < bound_columns.size(); i++) { - storage_oids.emplace_back(columns.LogicalToPhysical(bound_columns[i]).index); + storage_oids.push_back(columns.LogicalToPhysical(bound_columns[i]).index); } if (storage_oids.empty()) { - storage_oids.emplace_back(COLUMN_IDENTIFIER_ROW_ID); + storage_oids.push_back(COLUMN_IDENTIFIER_ROW_ID); } auto new_storage = @@ -773,84 +801,6 @@ unique_ptr DuckTableEntry::DropForeignKeyConstraint(ClientContext return make_uniq(catalog, schema, *bound_create_info, storage); } -void DuckTableEntry::Rollback(CatalogEntry &prev_entry) { - if (prev_entry.type != CatalogType::TABLE_ENTRY) { - return; - } - - // Rolls back any physical index creation. - // FIXME: Currently only works for PKs. - // FIXME: Should be changed to work for any index-based constraint. - - auto &table = Cast(); - auto &prev_table = prev_entry.Cast(); - auto &prev_info = prev_table.GetStorage().GetDataTableInfo(); - auto &prev_indexes = prev_info->GetIndexes(); - - // Find all index-based constraints that exist in rollback_table, but not in table. - // Then, remove them. - - unordered_set names; - for (const auto &constraint : prev_table.GetConstraints()) { - if (constraint->type != ConstraintType::UNIQUE) { - continue; - } - const auto &unique = constraint->Cast(); - if (unique.is_primary_key) { - auto index_name = unique.GetName(prev_table.name); - names.insert(index_name); - } - } - - for (const auto &constraint : GetConstraints()) { - if (constraint->type != ConstraintType::UNIQUE) { - continue; - } - const auto &unique = constraint->Cast(); - if (!unique.IsPrimaryKey()) { - continue; - } - auto index_name = unique.GetName(table.name); - if (names.find(index_name) == names.end()) { - prev_indexes.RemoveIndex(index_name); - } - } -} - -unique_ptr DuckTableEntry::AddConstraint(ClientContext &context, AddConstraintInfo &info) { - auto create_info = make_uniq(schema, name); - create_info->comment = comment; - - // Copy all columns and constraints to the modified table. - create_info->columns = columns.Copy(); - for (const auto &constraint : constraints) { - create_info->constraints.push_back(constraint->Copy()); - } - - if (info.constraint->type == ConstraintType::UNIQUE) { - const auto &unique = info.constraint->Cast(); - const auto existing_pk = GetPrimaryKey(); - - if (unique.is_primary_key && existing_pk) { - auto existing_name = existing_pk->ToString(); - throw CatalogException("table \"%s\" can have only one primary key: %s", name, existing_name); - } - create_info->constraints.push_back(info.constraint->Copy()); - - } else { - throw InternalException("unsupported constraint type in ALTER TABLE statement"); - } - - // We create a physical table with a new constraint and a new unique index. - const auto binder = Binder::CreateBinder(context); - const auto bound_constraint = binder->BindConstraint(*info.constraint, create_info->table, create_info->columns); - const auto bound_create_info = binder->BindCreateTableInfo(std::move(create_info), schema); - - auto new_storage = make_shared_ptr(context, *storage, *bound_constraint); - auto new_entry = make_uniq(catalog, schema, *bound_create_info, new_storage); - return std::move(new_entry); -} - unique_ptr DuckTableEntry::Copy(ClientContext &context) const { auto create_info = make_uniq(schema, name); create_info->comment = comment; diff --git a/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp index f983fb762..865ac4734 100644 --- a/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp @@ -1,5 +1,4 @@ #include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" -#include "duckdb/common/vector.hpp" #include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" namespace duckdb { @@ -9,7 +8,7 @@ ScalarFunctionCatalogEntry::ScalarFunctionCatalogEntry(Catalog &catalog, SchemaC : FunctionEntry(CatalogType::SCALAR_FUNCTION_ENTRY, catalog, schema, info), functions(info.functions) { } -unique_ptr ScalarFunctionCatalogEntry::AlterEntry(CatalogTransaction transaction, AlterInfo &info) { +unique_ptr ScalarFunctionCatalogEntry::AlterEntry(ClientContext &context, AlterInfo &info) { if (info.type != AlterType::ALTER_SCALAR_FUNCTION) { throw InternalException("Attempting to alter ScalarFunctionCatalogEntry with unsupported alter type"); } @@ -21,15 +20,10 @@ unique_ptr ScalarFunctionCatalogEntry::AlterEntry(CatalogTransacti auto &add_overloads = function_info.Cast(); ScalarFunctionSet new_set = functions; - if (!new_set.MergeFunctionSet(add_overloads.new_overloads->functions, true)) { - throw BinderException( - "Failed to add new function overloads to function \"%s\": function overload already exists", name); + if (!new_set.MergeFunctionSet(add_overloads.new_overloads)) { + throw BinderException("Failed to add new function overloads to function \"%s\": function already exists", name); } CreateScalarFunctionInfo new_info(std::move(new_set)); - new_info.internal = internal; - new_info.descriptions = descriptions; - new_info.descriptions.insert(new_info.descriptions.end(), add_overloads.new_overloads->descriptions.begin(), - add_overloads.new_overloads->descriptions.end()); return make_uniq(catalog, schema, new_info); } diff --git a/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp index ef14221ff..3c8e7c700 100644 --- a/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/schema_catalog_entry.cpp @@ -1,5 +1,4 @@ #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" -#include "duckdb/catalog/default/default_schemas.hpp" #include "duckdb/catalog/catalog.hpp" #include "duckdb/common/algorithm.hpp" @@ -40,20 +39,6 @@ SimilarCatalogEntry SchemaCatalogEntry::GetSimilarEntry(CatalogTransaction trans return result; } -//! This should not be used, it's only implemented to not put the burden of implementing it on every derived class of -//! SchemaCatalogEntry -CatalogSet::EntryLookup SchemaCatalogEntry::GetEntryDetailed(CatalogTransaction transaction, CatalogType type, - const string &name) { - CatalogSet::EntryLookup result; - result.result = GetEntry(transaction, type, name); - if (!result.result) { - result.reason = CatalogSet::EntryLookup::FailureReason::DELETED; - } else { - result.reason = CatalogSet::EntryLookup::FailureReason::SUCCESS; - } - return result; -} - unique_ptr SchemaCatalogEntry::GetInfo() const { auto result = make_uniq(); result->schema = name; diff --git a/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp index 3070b2e30..abb66b7e1 100644 --- a/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/table_catalog_entry.cpp @@ -43,10 +43,6 @@ LogicalIndex TableCatalogEntry::GetColumnIndex(string &column_name, bool if_exis return entry; } -unique_ptr TableCatalogEntry::GetSample() { - return nullptr; -} - bool TableCatalogEntry::ColumnExists(const string &name) const { return columns.ColumnExists(name); } @@ -148,7 +144,7 @@ string TableCatalogEntry::ColumnsToSQL(const ColumnList &columns, const vector(); D_ASSERT(cast_expr.cast_type.id() == column_type.id()); generated_expression = *cast_expr.child; @@ -180,24 +176,6 @@ string TableCatalogEntry::ColumnsToSQL(const ColumnList &columns, const vector 0) { - ss << ", "; - } - ss << KeywordHelper::WriteOptionallyQuoted(column.Name()) << " "; - } - ss << ")"; - return ss.str(); -} - string TableCatalogEntry::ToSQL() const { auto create_info = GetInfo(); return create_info->ToString(); @@ -255,6 +233,28 @@ static void BindExtraColumns(TableCatalogEntry &table, LogicalGet &get, LogicalP } } +static bool TypeSupportsRegularUpdate(const LogicalType &type) { + switch (type.id()) { + case LogicalTypeId::LIST: + case LogicalTypeId::ARRAY: + case LogicalTypeId::MAP: + case LogicalTypeId::UNION: + // lists and maps and unions don't support updates directly + return false; + case LogicalTypeId::STRUCT: { + auto &child_types = StructType::GetChildTypes(type); + for (auto &entry : child_types) { + if (!TypeSupportsRegularUpdate(entry.second)) { + return false; + } + } + return true; + } + default: + return true; + } +} + vector TableCatalogEntry::GetColumnSegmentInfo() { return {}; } @@ -299,7 +299,7 @@ void TableCatalogEntry::BindUpdateConstraints(Binder &binder, LogicalGet &get, L // we also convert any updates on LIST columns into delete + insert for (auto &col_index : update.columns) { auto &column = GetColumns().GetColumn(col_index); - if (!column.Type().SupportsRegularUpdate()) { + if (!TypeSupportsRegularUpdate(column.Type())) { update.update_is_del_and_insert = true; break; } @@ -316,20 +316,4 @@ void TableCatalogEntry::BindUpdateConstraints(Binder &binder, LogicalGet &get, L } } -optional_ptr TableCatalogEntry::GetPrimaryKey() const { - for (const auto &constraint : GetConstraints()) { - if (constraint->type == ConstraintType::UNIQUE) { - auto &unique = constraint->Cast(); - if (unique.IsPrimaryKey()) { - return &unique; - } - } - } - return nullptr; -} - -bool TableCatalogEntry::HasPrimaryKey() const { - return GetPrimaryKey() != nullptr; -} - } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp index 9b80a1d5d..1b3b566ba 100644 --- a/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp @@ -9,7 +9,7 @@ TableFunctionCatalogEntry::TableFunctionCatalogEntry(Catalog &catalog, SchemaCat D_ASSERT(this->functions.Size() > 0); } -unique_ptr TableFunctionCatalogEntry::AlterEntry(CatalogTransaction transaction, AlterInfo &info) { +unique_ptr TableFunctionCatalogEntry::AlterEntry(ClientContext &context, AlterInfo &info) { if (info.type != AlterType::ALTER_TABLE_FUNCTION) { throw InternalException("Attempting to alter TableFunctionCatalogEntry with unsupported alter type"); } diff --git a/src/duckdb/src/catalog/catalog_entry/type_catalog_entry.cpp b/src/duckdb/src/catalog/catalog_entry/type_catalog_entry.cpp index be9c24834..c60c7167d 100644 --- a/src/duckdb/src/catalog/catalog_entry/type_catalog_entry.cpp +++ b/src/duckdb/src/catalog/catalog_entry/type_catalog_entry.cpp @@ -11,7 +11,7 @@ namespace duckdb { TypeCatalogEntry::TypeCatalogEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateTypeInfo &info) : StandardEntry(CatalogType::TYPE_ENTRY, schema, catalog, info.name), user_type(info.type), - bind_function(info.bind_function) { + bind_modifiers(info.bind_modifiers) { this->temporary = info.temporary; this->internal = info.internal; this->dependencies = info.dependencies; @@ -35,7 +35,7 @@ unique_ptr TypeCatalogEntry::GetInfo() const { result->dependencies = dependencies; result->comment = comment; result->tags = tags; - result->bind_function = bind_function; + result->bind_modifiers = bind_modifiers; return std::move(result); } diff --git a/src/duckdb/src/catalog/catalog_entry_retriever.cpp b/src/duckdb/src/catalog/catalog_entry_retriever.cpp index c37562d72..db0d0d423 100644 --- a/src/duckdb/src/catalog/catalog_entry_retriever.cpp +++ b/src/duckdb/src/catalog/catalog_entry_retriever.cpp @@ -7,7 +7,6 @@ #include "duckdb/common/enums/catalog_type.hpp" #include "duckdb/common/optional_ptr.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" -#include "duckdb/main/client_data.hpp" namespace duckdb { @@ -37,13 +36,14 @@ optional_ptr CatalogEntryRetriever::GetEntry(CatalogType type, con const string &schema, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - return ReturnAndCallback(Catalog::GetEntry(*this, type, catalog, schema, name, on_entry_not_found, error_context)); + return GetEntryInternal( + [&]() { return Catalog::GetEntry(context, type, catalog, schema, name, on_entry_not_found, error_context); }); } optional_ptr CatalogEntryRetriever::GetSchema(const string &catalog, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - auto result = Catalog::GetSchema(*this, catalog, name, on_entry_not_found, error_context); + auto result = Catalog::GetSchema(context, catalog, name, on_entry_not_found, error_context); if (!result) { return result; } @@ -57,63 +57,8 @@ optional_ptr CatalogEntryRetriever::GetSchema(const string & optional_ptr CatalogEntryRetriever::GetEntry(CatalogType type, Catalog &catalog, const string &schema, const string &name, OnEntryNotFound on_entry_not_found, QueryErrorContext error_context) { - return ReturnAndCallback(catalog.GetEntry(*this, type, schema, name, on_entry_not_found, error_context)); -} - -optional_ptr CatalogEntryRetriever::ReturnAndCallback(optional_ptr result) { - if (!result) { - return result; - } - if (callback) { - // Call the callback if it's set - callback(*result); - } - return result; -} - -void CatalogEntryRetriever::Inherit(const CatalogEntryRetriever &parent) { - this->callback = parent.callback; - this->search_path = parent.search_path; -} - -CatalogSearchPath &CatalogEntryRetriever::GetSearchPath() { - if (search_path) { - return *search_path; - } - return *ClientData::Get(context).catalog_search_path; -} - -void CatalogEntryRetriever::SetSearchPath(vector entries) { - vector new_path; - for (auto &entry : entries) { - if (IsInvalidCatalog(entry.catalog) || entry.catalog == SYSTEM_CATALOG || entry.catalog == TEMP_CATALOG) { - continue; - } - new_path.push_back(std::move(entry)); - } - if (new_path.empty()) { - return; - } - - // push the set paths from the ClientContext behind the provided paths - auto &client_search_path = *ClientData::Get(context).catalog_search_path; - auto &set_paths = client_search_path.GetSetPaths(); - for (auto path : set_paths) { - if (IsInvalidCatalog(path.catalog)) { - path.catalog = DatabaseManager::GetDefaultDatabase(context); - } - new_path.push_back(std::move(path)); - } - - this->search_path = make_shared_ptr(context, std::move(new_path)); -} - -void CatalogEntryRetriever::SetCallback(catalog_entry_callback_t callback) { - this->callback = std::move(callback); -} - -catalog_entry_callback_t CatalogEntryRetriever::GetCallback() { - return callback; + return GetEntryInternal( + [&]() { return catalog.GetEntry(context, type, schema, name, on_entry_not_found, error_context); }); } } // namespace duckdb diff --git a/src/duckdb/src/catalog/catalog_search_path.cpp b/src/duckdb/src/catalog/catalog_search_path.cpp index dcf2569d8..9368e300f 100644 --- a/src/duckdb/src/catalog/catalog_search_path.cpp +++ b/src/duckdb/src/catalog/catalog_search_path.cpp @@ -1,5 +1,4 @@ #include "duckdb/catalog/catalog_search_path.hpp" -#include "duckdb/catalog/default/default_schemas.hpp" #include "duckdb/catalog/catalog.hpp" #include "duckdb/common/constants.hpp" @@ -124,17 +123,13 @@ vector CatalogSearchEntry::ParseList(const string &input) { return result; } -CatalogSearchPath::CatalogSearchPath(ClientContext &context_p, vector entries) - : context(context_p) { - SetPathsInternal(std::move(entries)); -} - -CatalogSearchPath::CatalogSearchPath(ClientContext &context_p) : CatalogSearchPath(context_p, {}) { +CatalogSearchPath::CatalogSearchPath(ClientContext &context_p) : context(context_p) { + Reset(); } void CatalogSearchPath::Reset() { vector empty; - SetPathsInternal(empty); + SetPaths(empty); } string CatalogSearchPath::GetSetName(CatalogSetPathType set_type) { @@ -181,7 +176,8 @@ void CatalogSearchPath::Set(vector new_paths, CatalogSetPath new_paths[0].catalog); } } - SetPathsInternal(std::move(new_paths)); + this->set_paths = std::move(new_paths); + SetPaths(set_paths); } void CatalogSearchPath::Set(CatalogSearchEntry new_value, CatalogSetPathType set_type) { @@ -206,9 +202,6 @@ string CatalogSearchPath::GetDefaultSchema(const string &catalog) { } string CatalogSearchPath::GetDefaultCatalog(const string &schema) { - if (DefaultSchemaGenerator::IsDefaultSchema(schema)) { - return SYSTEM_CATALOG; - } for (auto &path : paths) { if (path.catalog == TEMP_CATALOG) { continue; @@ -222,13 +215,9 @@ string CatalogSearchPath::GetDefaultCatalog(const string &schema) { vector CatalogSearchPath::GetCatalogsForSchema(const string &schema) { vector schemas; - if (DefaultSchemaGenerator::IsDefaultSchema(schema)) { - schemas.push_back(SYSTEM_CATALOG); - } else { - for (auto &path : paths) { - if (StringUtil::CIEquals(path.schema, schema)) { - schemas.push_back(path.catalog); - } + for (auto &path : paths) { + if (StringUtil::CIEquals(path.schema, schema)) { + schemas.push_back(path.catalog); } } return schemas; @@ -250,14 +239,12 @@ const CatalogSearchEntry &CatalogSearchPath::GetDefault() { return paths[1]; } -void CatalogSearchPath::SetPathsInternal(vector new_paths) { - this->set_paths = std::move(new_paths); - +void CatalogSearchPath::SetPaths(vector new_paths) { paths.clear(); - paths.reserve(set_paths.size() + 3); + paths.reserve(new_paths.size() + 3); paths.emplace_back(TEMP_CATALOG, DEFAULT_SCHEMA); - for (auto &path : set_paths) { - paths.push_back(path); + for (auto &path : new_paths) { + paths.push_back(std::move(path)); } paths.emplace_back(INVALID_CATALOG, DEFAULT_SCHEMA); paths.emplace_back(SYSTEM_CATALOG, DEFAULT_SCHEMA); diff --git a/src/duckdb/src/catalog/catalog_set.cpp b/src/duckdb/src/catalog/catalog_set.cpp index b95f85747..f3f7ef1b9 100644 --- a/src/duckdb/src/catalog/catalog_set.cpp +++ b/src/duckdb/src/catalog/catalog_set.cpp @@ -88,6 +88,10 @@ CatalogSet::CatalogSet(Catalog &catalog_p, unique_ptr defaults CatalogSet::~CatalogSet() { } +bool IsDependencyEntry(CatalogEntry &entry) { + return entry.type == CatalogType::DEPENDENCY_ENTRY; +} + bool CatalogSet::StartChain(CatalogTransaction transaction, const string &name, unique_lock &read_lock) { D_ASSERT(!map.GetEntry(name)); @@ -97,8 +101,9 @@ bool CatalogSet::StartChain(CatalogTransaction transaction, const string &name, return false; } - // first create a dummy deleted entry - // so other transactions will see that instead of the entry that is to be added. + // first create a dummy deleted entry for this entry + // so transactions started before the commit of this transaction don't + // see it yet auto dummy_node = make_uniq(CatalogType::INVALID, catalog, name); dummy_node->timestamp = 0; dummy_node->deleted = true; @@ -109,23 +114,20 @@ bool CatalogSet::StartChain(CatalogTransaction transaction, const string &name, } bool CatalogSet::VerifyVacancy(CatalogTransaction transaction, CatalogEntry &entry) { + // if it does, we have to check version numbers if (HasConflict(transaction, entry.timestamp)) { - // A transaction that is not visible to our snapshot has already made a change to this entry. - // Because of Catalog limitations we can't push our change on this, even if the change was made by another - // active transaction that might end up being aborted. So we have to cancel this transaction. + // current version has been written to by a currently active + // transaction throw TransactionException("Catalog write-write conflict on create with \"%s\"", entry.name); } - // The entry is visible to our snapshot + // there is a current version that has been committed + // if it has not been deleted there is a conflict if (!entry.deleted) { return false; } return true; } -static bool IsDependencyEntry(CatalogEntry &entry) { - return entry.type == CatalogType::DEPENDENCY_ENTRY; -} - void CatalogSet::CheckCatalogEntryInvariants(CatalogEntry &value, const string &name) { if (value.internal && !catalog.IsSystemCatalog() && name != DEFAULT_SCHEMA) { throw InternalException("Attempting to create internal entry \"%s\" in non-system catalog - internal entries " @@ -158,7 +160,7 @@ optional_ptr CatalogSet::CreateCommittedEntry(unique_ptrset = this; - // Give the entry commit id 0, so it is visible to all transactions + // Set the timestamp to the first committed transaction entry->timestamp = 0; map.AddEntry(std::move(entry)); @@ -174,7 +176,7 @@ bool CatalogSet::CreateEntryInternal(CatalogTransaction transaction, const strin return false; } } else if (should_be_empty) { - // Verify that the entry is deleted, not altered by another transaction + // Verify that the chain is deleted, not altered by another transaction if (!VerifyVacancy(transaction, *entry_value)) { return false; } @@ -183,7 +185,7 @@ bool CatalogSet::CreateEntryInternal(CatalogTransaction transaction, const strin // Finally add the new entry to the chain auto value_ptr = value.get(); map.UpdateEntry(std::move(value)); - // Push the old entry in the undo buffer for this transaction, so it can be restored in the event of failure + // push the old entry in the undo buffer for this transaction if (transaction.transaction) { DuckTransactionManager::Get(GetCatalog().GetAttached()) .PushCatalogEntry(*transaction.transaction, value_ptr->Child()); @@ -195,10 +197,11 @@ bool CatalogSet::CreateEntry(CatalogTransaction transaction, const string &name, const LogicalDependencyList &dependencies) { CheckCatalogEntryInvariants(*value, name); - // Mark this entry as being created by the current active transaction + // Set the timestamp to the timestamp of the current transaction value->timestamp = transaction.transaction_id; value->set = this; - catalog.GetDependencyManager()->AddObject(transaction, *value, dependencies); + // now add the dependency set of this object to the dependency manager + catalog.GetDependencyManager().AddObject(transaction, *value, dependencies); // lock the catalog for writing lock_guard write_lock(catalog.GetWriteLock()); @@ -213,24 +216,24 @@ bool CatalogSet::CreateEntry(ClientContext &context, const string &name, unique_ return CreateEntry(catalog.GetCatalogTransaction(context), name, std::move(value), dependencies); } -//! This method is used to retrieve an entry for the purpose of making a new version, through an alter/drop/create optional_ptr CatalogSet::GetEntryInternal(CatalogTransaction transaction, const string &name) { auto entry_value = map.GetEntry(name); if (!entry_value) { + // the entry does not exist, check if we can create a default entry return nullptr; } auto &catalog_entry = *entry_value; - // Check if this entry is visible to our snapshot + // if it does: we have to retrieve the entry and to check version numbers if (HasConflict(transaction, catalog_entry.timestamp)) { - // We intend to create a new version of the entry. - // Another transaction has already made an edit to this catalog entry, because of limitations in the Catalog we - // can't create an edit alongside this even if the other transaction might end up getting aborted. So we have to - // abort the transaction. + // current version has been written to by a currently active + // transaction throw TransactionException("Catalog write-write conflict on alter with \"%s\"", catalog_entry.name); } - // The entry is visible to our snapshot, check if it's deleted + // there is a current version that has been committed by this transaction if (catalog_entry.deleted) { + // if the entry was already deleted, it now does not exist anymore + // so we return that we could not find it return nullptr; } return &catalog_entry; @@ -259,7 +262,7 @@ bool CatalogSet::AlterOwnership(CatalogTransaction transaction, ChangeOwnershipI throw CatalogException("CatalogElement \"%s.%s\" does not exist!", info.owner_schema, info.owner_name); } write_lock.unlock(); - catalog.GetDependencyManager()->AddOwnership(transaction, *owner_entry, *entry); + catalog.GetDependencyManager().AddOwnership(transaction, *owner_entry, *entry); return true; } @@ -368,7 +371,7 @@ bool CatalogSet::AlterEntry(CatalogTransaction transaction, const string &name, write_lock.unlock(); // Check the dependency manager to verify that there are no conflicting dependencies with this alter - catalog.GetDependencyManager()->AlterObject(transaction, *entry, *new_entry, alter_info); + catalog.GetDependencyManager().AlterObject(transaction, *entry, *new_entry, alter_info); return true; } @@ -385,7 +388,7 @@ bool CatalogSet::DropDependencies(CatalogTransaction transaction, const string & // check any dependencies of this object D_ASSERT(entry->ParentCatalog().IsDuckCatalog()); auto &duck_catalog = entry->ParentCatalog().Cast(); - duck_catalog.GetDependencyManager()->DropObject(transaction, *entry, cascade); + duck_catalog.GetDependencyManager().DropObject(transaction, *entry, cascade); return true; } @@ -431,35 +434,6 @@ bool CatalogSet::DropEntry(ClientContext &context, const string &name, bool casc return DropEntry(catalog.GetCatalogTransaction(context), name, cascade, allow_drop_internal); } -//! Verify that the object referenced by the dependency still exists when we commit the dependency -void CatalogSet::VerifyExistenceOfDependency(transaction_t commit_id, CatalogEntry &entry) { - auto &duck_catalog = GetCatalog(); - - // Make sure that we don't see any uncommitted changes - auto transaction_id = MAX_TRANSACTION_ID; - // This will allow us to see all committed changes made before this COMMIT happened - auto tx_start_time = commit_id; - CatalogTransaction commit_transaction(duck_catalog.GetDatabase(), transaction_id, tx_start_time); - - D_ASSERT(entry.type == CatalogType::DEPENDENCY_ENTRY); - auto &dep = entry.Cast(); - duck_catalog.GetDependencyManager()->VerifyExistence(commit_transaction, dep); -} - -//! Verify that no dependencies creations were committed since our transaction started, that reference the entry we're -//! dropping -void CatalogSet::CommitDrop(transaction_t commit_id, transaction_t start_time, CatalogEntry &entry) { - auto &duck_catalog = GetCatalog(); - - // Make sure that we don't see any uncommitted changes - auto transaction_id = MAX_TRANSACTION_ID; - // This will allow us to see all committed changes made before this COMMIT happened - auto tx_start_time = commit_id; - CatalogTransaction commit_transaction(duck_catalog.GetDatabase(), transaction_id, tx_start_time); - - duck_catalog.GetDependencyManager()->VerifyCommitDrop(commit_transaction, start_time, entry); -} - DuckCatalog &CatalogSet::GetCatalog() { return catalog; } @@ -493,11 +467,6 @@ bool CatalogSet::HasConflict(CatalogTransaction transaction, transaction_t times return CreatedByOtherActiveTransaction(transaction, timestamp) || CommittedAfterStarting(transaction, timestamp); } -bool CatalogSet::IsCommitted(transaction_t timestamp) { - //! FIXME: `transaction_t` itself should be a class that has these methods - return timestamp < TRANSACTION_ID_START; -} - bool CatalogSet::UseTimestamp(CatalogTransaction transaction, transaction_t timestamp) { if (timestamp == transaction.transaction_id) { // we created this version @@ -511,20 +480,13 @@ bool CatalogSet::UseTimestamp(CatalogTransaction transaction, transaction_t time } CatalogEntry &CatalogSet::GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry ¤t) { - bool visible; - return GetEntryForTransaction(transaction, current, visible); -} - -CatalogEntry &CatalogSet::GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry ¤t, bool &visible) { reference entry(current); while (entry.get().HasChild()) { if (UseTimestamp(transaction, entry.get().timestamp)) { - visible = true; - return entry.get(); + break; } entry = entry.get().Child(); } - visible = false; return entry.get(); } @@ -592,14 +554,9 @@ CatalogSet::EntryLookup CatalogSet::GetEntryDetailed(CatalogTransaction transact // check the version numbers auto &catalog_entry = *entry_value; - bool visible; - auto ¤t = GetEntryForTransaction(transaction, catalog_entry, visible); + auto ¤t = GetEntryForTransaction(transaction, catalog_entry); if (current.deleted) { - if (!visible) { - return EntryLookup {nullptr, EntryLookup::FailureReason::INVISIBLE}; - } else { - return EntryLookup {nullptr, EntryLookup::FailureReason::DELETED}; - } + return EntryLookup {nullptr, EntryLookup::FailureReason::DELETED}; } D_ASSERT(StringUtil::CIEquals(name, current.name)); return EntryLookup {¤t, EntryLookup::FailureReason::SUCCESS}; @@ -633,7 +590,6 @@ void CatalogSet::Undo(CatalogEntry &entry) { // i.e. we have to place (entry) as (entry->parent) again auto &to_be_removed_node = entry.Parent(); - to_be_removed_node.Rollback(entry); D_ASSERT(StringUtil::CIEquals(entry.name, to_be_removed_node.name)); if (!to_be_removed_node.HasParent()) { diff --git a/src/duckdb/src/catalog/default/default_functions.cpp b/src/duckdb/src/catalog/default/default_functions.cpp index 7702bc4e0..f7f4634b9 100644 --- a/src/duckdb/src/catalog/default/default_functions.cpp +++ b/src/duckdb/src/catalog/default/default_functions.cpp @@ -27,10 +27,10 @@ static const DefaultMacro internal_macros[] = { {"pg_catalog", "pg_typeof", {"expression", nullptr}, {{nullptr, nullptr}}, "lower(typeof(expression))"}, // get the data type of any value - {"pg_catalog", "current_database", {nullptr}, {{nullptr, nullptr}}, "system.main.current_database()"}, // name of current database (called "catalog" in the SQL standard) - {"pg_catalog", "current_query", {nullptr}, {{nullptr, nullptr}}, "system.main.current_query()"}, // the currently executing query (NULL if not inside a plpgsql function) - {"pg_catalog", "current_schema", {nullptr}, {{nullptr, nullptr}}, "system.main.current_schema()"}, // name of current schema - {"pg_catalog", "current_schemas", {"include_implicit"}, {{nullptr, nullptr}}, "system.main.current_schemas(include_implicit)"}, // names of schemas in search path + {"pg_catalog", "current_database", {nullptr}, {{nullptr, nullptr}}, "main.current_database()"}, // name of current database (called "catalog" in the SQL standard) + {"pg_catalog", "current_query", {nullptr}, {{nullptr, nullptr}}, "main.current_query()"}, // the currently executing query (NULL if not inside a plpgsql function) + {"pg_catalog", "current_schema", {nullptr}, {{nullptr, nullptr}}, "main.current_schema()"}, // name of current schema + {"pg_catalog", "current_schemas", {"include_implicit"}, {{nullptr, nullptr}}, "main.current_schemas(include_implicit)"}, // names of schemas in search path // privilege functions {"pg_catalog", "has_any_column_privilege", {"table", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does current user have privilege for any column of table @@ -63,7 +63,7 @@ static const DefaultMacro internal_macros[] = { {"pg_catalog", "pg_get_expr", {"pg_node_tree", "relation_oid", nullptr}, {{nullptr, nullptr}}, "pg_node_tree"}, {"pg_catalog", "format_pg_type", {"logical_type", "type_name", nullptr}, {{nullptr, nullptr}}, "case upper(logical_type) when 'FLOAT' then 'float4' when 'DOUBLE' then 'float8' when 'DECIMAL' then 'numeric' when 'ENUM' then lower(type_name) when 'VARCHAR' then 'varchar' when 'BLOB' then 'bytea' when 'TIMESTAMP' then 'timestamp' when 'TIME' then 'time' when 'TIMESTAMP WITH TIME ZONE' then 'timestamptz' when 'TIME WITH TIME ZONE' then 'timetz' when 'SMALLINT' then 'int2' when 'INTEGER' then 'int4' when 'BIGINT' then 'int8' when 'BOOLEAN' then 'bool' else lower(logical_type) end"}, {"pg_catalog", "format_type", {"type_oid", "typemod", nullptr}, {{nullptr, nullptr}}, "(select format_pg_type(logical_type, type_name) from duckdb_types() t where t.type_oid=type_oid) || case when typemod>0 then concat('(', typemod//1000, ',', typemod%1000, ')') else '' end"}, - {"pg_catalog", "map_to_pg_oid", {"type_name", nullptr}, {{nullptr, nullptr}}, "case type_name when 'bool' then 16 when 'int16' then 21 when 'int' then 23 when 'bigint' then 20 when 'date' then 1082 when 'time' then 1083 when 'datetime' then 1114 when 'dec' then 1700 when 'float' then 700 when 'double' then 701 when 'bpchar' then 1043 when 'binary' then 17 when 'interval' then 1186 when 'timestamptz' then 1184 when 'timetz' then 1266 when 'bit' then 1560 when 'guid' then 2950 else null end"}, // map duckdb_oid to pg_oid. If no corresponding type, return null + {"pg_catalog", "map_to_pg_oid", {"type_name", nullptr}, {{nullptr, nullptr}}, "case type_name when 'bool' then 16 when 'int16' then 21 when 'int' then 23 when 'bigint' then 20 when 'date' then 1082 when 'time' then 1083 when 'datetime' then 1114 when 'dec' then 1700 when 'float' then 700 when 'double' then 701 when 'bpchar' then 1043 when 'binary' then 17 when 'interval' then 1186 when 'timestamptz' then 1184 when 'timetz' then 1266 when 'bit' then 1560 when 'guid' then 2950 else null end"}, // map duckdb_oid to pg_oid. If no corresponding type, return null {"pg_catalog", "pg_has_role", {"user", "role", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does user have privilege for role {"pg_catalog", "pg_has_role", {"role", "privilege", nullptr}, {{nullptr, nullptr}}, "true"}, //boolean //does current user have privilege for role @@ -102,17 +102,15 @@ static const DefaultMacro internal_macros[] = { {DEFAULT_SCHEMA, "array_to_string", {"arr", "sep", nullptr}, {{nullptr, nullptr}}, "list_aggr(arr::varchar[], 'string_agg', sep)"}, // Test default parameters {DEFAULT_SCHEMA, "array_to_string_comma_default", {"arr", nullptr}, {{"sep", "','"}, {nullptr, nullptr}}, "list_aggr(arr::varchar[], 'string_agg', sep)"}, - + {DEFAULT_SCHEMA, "generate_subscripts", {"arr", "dim", nullptr}, {{nullptr, nullptr}}, "unnest(generate_series(1, array_length(arr, dim)))"}, {DEFAULT_SCHEMA, "fdiv", {"x", "y", nullptr}, {{nullptr, nullptr}}, "floor(x/y)"}, {DEFAULT_SCHEMA, "fmod", {"x", "y", nullptr}, {{nullptr, nullptr}}, "(x-y*floor(x/y))"}, - {DEFAULT_SCHEMA, "split_part", {"string", "delimiter", "position", nullptr}, {{nullptr, nullptr}}, "if(string IS NOT NULL AND delimiter IS NOT NULL AND position IS NOT NULL, coalesce(string_split(string, delimiter)[position],''), NULL)"}, + {DEFAULT_SCHEMA, "count_if", {"l", nullptr}, {{nullptr, nullptr}}, "sum(if(l, 1, 0))"}, + {DEFAULT_SCHEMA, "split_part", {"string", "delimiter", "position", nullptr}, {{nullptr, nullptr}}, "coalesce(string_split(string, delimiter)[position],'')"}, {DEFAULT_SCHEMA, "geomean", {"x", nullptr}, {{nullptr, nullptr}}, "exp(avg(ln(x)))"}, {DEFAULT_SCHEMA, "geometric_mean", {"x", nullptr}, {{nullptr, nullptr}}, "geomean(x)"}, - {DEFAULT_SCHEMA, "weighted_avg", {"value", "weight", nullptr}, {{nullptr, nullptr}}, "SUM(value * weight) / SUM(CASE WHEN value IS NOT NULL THEN weight ELSE 0 END)"}, - {DEFAULT_SCHEMA, "wavg", {"value", "weight", nullptr}, {{nullptr, nullptr}}, "weighted_avg(value, weight)"}, - {DEFAULT_SCHEMA, "list_reverse", {"l", nullptr}, {{nullptr, nullptr}}, "l[:-:-1]"}, {DEFAULT_SCHEMA, "array_reverse", {"l", nullptr}, {{nullptr, nullptr}}, "list_reverse(l)"}, @@ -163,9 +161,6 @@ static const DefaultMacro internal_macros[] = { // date functions {DEFAULT_SCHEMA, "date_add", {"date", "interval", nullptr}, {{nullptr, nullptr}}, "date + interval"}, - {DEFAULT_SCHEMA, "current_date", {nullptr}, {{nullptr, nullptr}}, "current_timestamp::DATE"}, - {DEFAULT_SCHEMA, "today", {nullptr}, {{nullptr, nullptr}}, "current_timestamp::DATE"}, - {DEFAULT_SCHEMA, "get_current_time", {nullptr}, {{nullptr, nullptr}}, "current_timestamp::TIMETZ"}, // regexp functions {DEFAULT_SCHEMA, "regexp_split_to_table", {"text", "pattern", nullptr}, {{nullptr, nullptr}}, "unnest(string_split_regex(text, pattern))"}, diff --git a/src/duckdb/src/catalog/dependency_manager.cpp b/src/duckdb/src/catalog/dependency_manager.cpp index 4fcb4d4d1..51c60d3ad 100644 --- a/src/duckdb/src/catalog/dependency_manager.cpp +++ b/src/duckdb/src/catalog/dependency_manager.cpp @@ -433,86 +433,17 @@ string DependencyManager::CollectDependents(CatalogTransaction transaction, cata return result; } -void DependencyManager::VerifyExistence(CatalogTransaction transaction, DependencyEntry &object) { - auto &subject = object.Subject(); - - CatalogEntryInfo info; - if (subject.flags.IsOwnership()) { - info = object.SourceInfo(); - } else { - info = object.EntryInfo(); - } - - auto &type = info.type; - auto &schema = info.schema; - auto &name = info.name; - - auto &duck_catalog = catalog.Cast(); - auto &schema_catalog_set = duck_catalog.GetSchemaCatalogSet(); - - CatalogSet::EntryLookup lookup_result; - lookup_result = schema_catalog_set.GetEntryDetailed(transaction, schema); - - if (type != CatalogType::SCHEMA_ENTRY && lookup_result.result) { - auto &schema_entry = lookup_result.result->Cast(); - lookup_result = schema_entry.GetEntryDetailed(transaction, type, name); - } - - if (lookup_result.reason == CatalogSet::EntryLookup::FailureReason::DELETED) { - throw DependencyException("Could not commit creation of dependency, subject \"%s\" has been deleted", - object.SourceInfo().name); - } -} - -void DependencyManager::VerifyCommitDrop(CatalogTransaction transaction, transaction_t start_time, - CatalogEntry &object) { - if (IsSystemEntry(object)) { - return; - } - auto info = GetLookupProperties(object); - ScanDependents(transaction, info, [&](DependencyEntry &dep) { - auto dep_committed_at = dep.timestamp.load(); - if (dep_committed_at > start_time) { - // In the event of a CASCADE, the dependency drop has not committed yet - // so we would be halted by the existence of a dependency we are already dropping unless we check the - // timestamp - // - // Which differentiates between objects that we were already aware of (and will subsequently be dropped) and - // objects that were introduced inbetween, which should cause this error: - throw DependencyException( - "Could not commit DROP of \"%s\" because a dependency was created after the transaction started", - object.name); - } - }); - ScanSubjects(transaction, info, [&](DependencyEntry &dep) { - auto dep_committed_at = dep.timestamp.load(); - if (!dep.Dependent().flags.IsOwnedBy()) { - return; - } - D_ASSERT(dep.Subject().flags.IsOwnership()); - if (dep_committed_at > start_time) { - // Same as above, objects that are owned by the object that is being dropped will be dropped as part of this - // transaction. Only objects that were introduced by other transactions, that this transaction could not - // see, should cause this error: - throw DependencyException( - "Could not commit DROP of \"%s\" because a dependency was created after the transaction started", - object.name); - } - }); -} - -catalog_entry_set_t DependencyManager::CheckDropDependencies(CatalogTransaction transaction, CatalogEntry &object, - bool cascade) { +void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry &object, bool cascade) { if (IsSystemEntry(object)) { // Don't do anything for this - return catalog_entry_set_t(); + return; } + auto info = GetLookupProperties(object); + // Check if there are any entries that block the DROP because they still depend on the object catalog_entry_set_t to_drop; - catalog_entry_set_t blocking_dependents; - auto info = GetLookupProperties(object); - // Look through all the objects that depend on the 'object' + catalog_entry_set_t blocking_dependents; ScanDependents(transaction, info, [&](DependencyEntry &dep) { // It makes no sense to have a schema depend on anything D_ASSERT(dep.EntryInfo().type != CatalogType::SCHEMA_ENTRY); @@ -536,7 +467,6 @@ catalog_entry_set_t DependencyManager::CheckDropDependencies(CatalogTransaction throw DependencyException(error_string); } - // Look through all the entries that 'object' depends on ScanSubjects(transaction, info, [&](DependencyEntry &dep) { auto flags = dep.Subject().flags; if (flags.IsOwnership()) { @@ -545,17 +475,7 @@ catalog_entry_set_t DependencyManager::CheckDropDependencies(CatalogTransaction to_drop.insert(*entry); } }); - return to_drop; -} -void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry &object, bool cascade) { - if (IsSystemEntry(object)) { - // Don't do anything for this - return; - } - - // Check if there are any entries that block the DROP because they still depend on the object - auto to_drop = CheckDropDependencies(transaction, object, cascade); CleanupDependencies(transaction, object); for (auto &entry : to_drop) { @@ -565,54 +485,6 @@ void DependencyManager::DropObject(CatalogTransaction transaction, CatalogEntry } } -void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries, ClientContext &context) { - auto transaction = catalog.GetCatalogTransaction(context); - // Read all the entries visible to this snapshot - ReorderEntries(entries, transaction); -} - -void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries) { - // Read all committed entries - CatalogTransaction transaction(catalog.GetDatabase(), TRANSACTION_ID_START - 1, TRANSACTION_ID_START - 1); - ReorderEntries(entries, transaction); -} - -void DependencyManager::ReorderEntry(CatalogTransaction transaction, CatalogEntry &entry, catalog_entry_set_t &visited, - catalog_entry_vector_t &order) { - auto &catalog_entry = *LookupEntry(transaction, entry); - // We use this in CheckpointManager, it has the highest commit ID, allowing us to read any committed data - bool allow_internal = transaction.start_time == TRANSACTION_ID_START - 1; - if (visited.count(catalog_entry) || (!allow_internal && catalog_entry.internal)) { - // Already seen and ordered appropriately - return; - } - - // Check if there are any entries that this entry depends on, those are written first - catalog_entry_vector_t dependents; - auto info = GetLookupProperties(entry); - ScanSubjects(transaction, info, [&](DependencyEntry &dep) { dependents.push_back(dep); }); - for (auto &dep : dependents) { - ReorderEntry(transaction, dep, visited, order); - } - - // Then write the entry - visited.insert(catalog_entry); - order.push_back(catalog_entry); -} - -void DependencyManager::ReorderEntries(catalog_entry_vector_t &entries, CatalogTransaction transaction) { - catalog_entry_vector_t reordered; - catalog_entry_set_t visited; - for (auto &entry : entries) { - ReorderEntry(transaction, entry, visited, reordered); - } - // If this would fail, that means there are more entries that we somehow reached through the dependency manager - // but those entries should not actually be visible to this transaction - D_ASSERT(entries.size() == reordered.size()); - entries.clear(); - entries = reordered; -} - void DependencyManager::AlterObject(CatalogTransaction transaction, CatalogEntry &old_obj, CatalogEntry &new_obj, AlterInfo &alter_info) { if (IsSystemEntry(new_obj)) { diff --git a/src/duckdb/src/catalog/duck_catalog.cpp b/src/duckdb/src/catalog/duck_catalog.cpp index a55349a74..920740c96 100644 --- a/src/duckdb/src/catalog/duck_catalog.cpp +++ b/src/duckdb/src/catalog/duck_catalog.cpp @@ -8,13 +8,15 @@ #include "duckdb/function/built_in_functions.hpp" #include "duckdb/main/attached_database.hpp" #include "duckdb/transaction/duck_transaction_manager.hpp" -#include "duckdb/function/function_list.hpp" +#ifndef DISABLE_CORE_FUNCTIONS_EXTENSION +#include "duckdb/core_functions/core_functions.hpp" +#endif namespace duckdb { DuckCatalog::DuckCatalog(AttachedDatabase &db) : Catalog(db), dependency_manager(make_uniq(*this)), - schemas(make_uniq(*this, IsSystemCatalog() ? make_uniq(*this) : nullptr)) { + schemas(make_uniq(*this, make_uniq(*this))) { } DuckCatalog::~DuckCatalog() { @@ -33,11 +35,13 @@ void DuckCatalog::Initialize(bool load_builtin) { CreateSchema(data, info); if (load_builtin) { + // initialize default functions BuiltinFunctions builtin(data, *this); builtin.Initialize(); - // initialize default functions - FunctionList::RegisterFunctions(*this, data); +#ifndef DISABLE_CORE_FUNCTIONS_EXTENSION + CoreFunctions::RegisterFunctions(*this, data); +#endif } Verify(); @@ -47,25 +51,17 @@ bool DuckCatalog::IsDuckCatalog() { return true; } -optional_ptr DuckCatalog::GetDependencyManager() { - return dependency_manager.get(); -} - //===--------------------------------------------------------------------===// // Schema //===--------------------------------------------------------------------===// optional_ptr DuckCatalog::CreateSchemaInternal(CatalogTransaction transaction, CreateSchemaInfo &info) { LogicalDependencyList dependencies; - - if (!info.internal && DefaultSchemaGenerator::IsDefaultSchema(info.schema)) { - return nullptr; - } auto entry = make_uniq(*this, info); auto result = entry.get(); if (!schemas->CreateEntry(transaction, info.schema, std::move(entry), dependencies)) { return nullptr; } - return result; + return (CatalogEntry *)result; } optional_ptr DuckCatalog::CreateSchema(CatalogTransaction transaction, CreateSchemaInfo &info) { @@ -119,10 +115,6 @@ void DuckCatalog::ScanSchemas(std::function callback schemas->Scan([&](CatalogEntry &entry) { callback(entry.Cast()); }); } -CatalogSet &DuckCatalog::GetSchemaCatalogSet() { - return *schemas; -} - optional_ptr DuckCatalog::GetSchema(CatalogTransaction transaction, const string &schema_name, OnEntryNotFound if_not_found, QueryErrorContext error_context) { D_ASSERT(!schema_name.empty()); diff --git a/src/duckdb/src/common/adbc/adbc.cpp b/src/duckdb/src/common/adbc/adbc.cpp index 7323f3b1f..1d002b578 100644 --- a/src/duckdb/src/common/adbc/adbc.cpp +++ b/src/duckdb/src/common/adbc/adbc.cpp @@ -172,15 +172,6 @@ AdbcStatusCode StatementSetSubstraitPlan(struct AdbcStatement *statement, const return ADBC_STATUS_INVALID_ARGUMENT; } auto wrapper = static_cast(statement->private_data); - if (wrapper->ingestion_stream.release) { - // Release any resources currently held by the ingestion stream before we overwrite it - wrapper->ingestion_stream.release(&wrapper->ingestion_stream); - wrapper->ingestion_stream.release = nullptr; - } - if (wrapper->statement) { - duckdb_destroy_prepare(&wrapper->statement); - wrapper->statement = nullptr; - } wrapper->substrait_plan = static_cast(malloc(sizeof(uint8_t) * length)); wrapper->plan_length = length; memcpy(wrapper->substrait_plan, plan, length); @@ -921,15 +912,6 @@ AdbcStatusCode StatementSetSqlQuery(struct AdbcStatement *statement, const char } auto wrapper = static_cast(statement->private_data); - if (wrapper->ingestion_stream.release) { - // Release any resources currently held by the ingestion stream before we overwrite it - wrapper->ingestion_stream.release(&wrapper->ingestion_stream); - wrapper->ingestion_stream.release = nullptr; - } - if (wrapper->statement) { - duckdb_destroy_prepare(&wrapper->statement); - wrapper->statement = nullptr; - } auto res = duckdb_prepare(wrapper->connection, query, &wrapper->statement); auto error_msg = duckdb_prepare_error(wrapper->statement); return CheckResult(res, error, error_msg); diff --git a/src/duckdb/src/common/allocator.cpp b/src/duckdb/src/common/allocator.cpp index 977087939..c13387151 100644 --- a/src/duckdb/src/common/allocator.cpp +++ b/src/duckdb/src/common/allocator.cpp @@ -5,7 +5,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/helper.hpp" #include "duckdb/common/numeric_utils.hpp" -#include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/types/timestamp.hpp" #include @@ -243,8 +242,7 @@ static void MallocTrim(idx_t pad) { static atomic LAST_TRIM_TIMESTAMP_MS {0}; int64_t last_trim_timestamp_ms = LAST_TRIM_TIMESTAMP_MS.load(); - auto current_ts = Timestamp::GetCurrentTimestamp(); - auto current_timestamp_ms = Cast::Operation(current_ts).value; + int64_t current_timestamp_ms = Timestamp::GetEpochMs(Timestamp::GetCurrentTimestamp()); if (current_timestamp_ms - last_trim_timestamp_ms < TRIM_INTERVAL_MS) { return; // We trimmed less than TRIM_INTERVAL_MS ago diff --git a/src/duckdb/src/common/arrow/arrow_converter.cpp b/src/duckdb/src/common/arrow/arrow_converter.cpp index 582daf34b..9c674cd78 100644 --- a/src/duckdb/src/common/arrow/arrow_converter.cpp +++ b/src/duckdb/src/common/arrow/arrow_converter.cpp @@ -127,7 +127,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co case LogicalTypeId::HUGEINT: { if (options.arrow_lossless_conversion) { child.format = "w:16"; - auto schema_metadata = ArrowSchemaMetadata::DuckDBInternalType("hugeint"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("duckdb.hugeint"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); } else { @@ -137,7 +137,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co } case LogicalTypeId::UHUGEINT: { child.format = "w:16"; - auto schema_metadata = ArrowSchemaMetadata::DuckDBInternalType("uhugeint"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("duckdb.uhugeint"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); break; @@ -148,7 +148,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co } else { child.format = "z"; } - auto schema_metadata = ArrowSchemaMetadata::DuckDBInternalType("varint"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("duckdb.varint"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); break; @@ -160,7 +160,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co if (options.arrow_lossless_conversion) { // This is a canonical extension, hence needs the "arrow." prefix child.format = "w:16"; - auto schema_metadata = ArrowSchemaMetadata::ArrowCanonicalType("arrow.uuid"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("arrow.uuid"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); } else { @@ -178,7 +178,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co } case LogicalTypeId::VARCHAR: if (type.IsJSONType() && options.arrow_lossless_conversion) { - auto schema_metadata = ArrowSchemaMetadata::ArrowCanonicalType("arrow.json"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("arrow.json"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); } @@ -198,7 +198,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co case LogicalTypeId::TIME_TZ: { if (options.arrow_lossless_conversion) { child.format = "w:8"; - auto schema_metadata = ArrowSchemaMetadata::DuckDBInternalType("time_tz"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("duckdb.time_tz"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); } else { @@ -256,7 +256,7 @@ void SetArrowFormat(DuckDBArrowSchemaHolder &root_holder, ArrowSchema &child, co child.format = "z"; } if (options.arrow_lossless_conversion) { - auto schema_metadata = ArrowSchemaMetadata::DuckDBInternalType("bit"); + auto schema_metadata = ArrowSchemaMetadata::MetadataFromName("duckdb.bit"); root_holder.metadata_info.emplace_back(schema_metadata.SerializeMetadata()); child.metadata = root_holder.metadata_info.back().get(); } diff --git a/src/duckdb/src/common/arrow/arrow_merge_event.cpp b/src/duckdb/src/common/arrow/arrow_merge_event.cpp index 1315ad1ad..4dafac60f 100644 --- a/src/duckdb/src/common/arrow/arrow_merge_event.cpp +++ b/src/duckdb/src/common/arrow/arrow_merge_event.cpp @@ -87,7 +87,7 @@ void ArrowMergeEvent::Schedule() { idx_t tuples_for_task = 0; idx_t start_index = transformer.GetIndex(); idx_t end_index = start_index; - while (tuples_for_task < DEFAULT_ROW_GROUP_SIZE) { + while (tuples_for_task < Storage::ROW_GROUP_SIZE) { idx_t batch_size; if (!transformer.TryGetNextBatchSize(batch_size)) { finished = true; diff --git a/src/duckdb/src/common/arrow/schema_metadata.cpp b/src/duckdb/src/common/arrow/schema_metadata.cpp index 836f89f2c..7240d40f3 100644 --- a/src/duckdb/src/common/arrow/schema_metadata.cpp +++ b/src/duckdb/src/common/arrow/schema_metadata.cpp @@ -1,7 +1,6 @@ #include "duckdb/common/arrow/schema_metadata.hpp" namespace duckdb { - ArrowSchemaMetadata::ArrowSchemaMetadata(const char *metadata) { if (metadata) { // Read the number of key-value pairs (int32) @@ -28,18 +27,17 @@ ArrowSchemaMetadata::ArrowSchemaMetadata(const char *metadata) { // Read the value const std::string value(metadata, static_cast(value_length)); metadata += value_length; - schema_metadata_map[key] = value; + metadata_map[key] = value; } } - extension_metadata_map = StringUtil::ParseJSONMap(schema_metadata_map[ARROW_METADATA_KEY]); } void ArrowSchemaMetadata::AddOption(const string &key, const string &value) { - schema_metadata_map[key] = value; + metadata_map[key] = value; } string ArrowSchemaMetadata::GetOption(const string &key) const { - auto it = schema_metadata_map.find(key); - if (it != schema_metadata_map.end()) { + auto it = metadata_map.find(key); + if (it != metadata_map.end()) { return it->second; } else { return ""; @@ -50,40 +48,14 @@ string ArrowSchemaMetadata::GetExtensionName() const { return GetOption(ARROW_EXTENSION_NAME); } -ArrowSchemaMetadata ArrowSchemaMetadata::ArrowCanonicalType(const string &extension_name) { - ArrowSchemaMetadata metadata; - metadata.AddOption(ARROW_EXTENSION_NAME, extension_name); - metadata.AddOption(ARROW_METADATA_KEY, ""); - return metadata; -} - -ArrowSchemaMetadata ArrowSchemaMetadata::DuckDBInternalType(const string &type_name) { +ArrowSchemaMetadata ArrowSchemaMetadata::MetadataFromName(const string &extension_name) { ArrowSchemaMetadata metadata; - metadata.AddOption(ARROW_EXTENSION_NAME, ARROW_EXTENSION_NON_CANONICAL); - // We have to set the metadata key with type_name and vendor_name. - metadata.extension_metadata_map["vendor_name"] = "DuckDB"; - metadata.extension_metadata_map["type_name"] = type_name; - metadata.AddOption(ARROW_METADATA_KEY, StringUtil::ToJSONMap(metadata.extension_metadata_map)); + metadata.AddOption(ArrowSchemaMetadata::ARROW_EXTENSION_NAME, extension_name); + metadata.AddOption(ArrowSchemaMetadata::ARROW_METADATA_KEY, ""); return metadata; } -bool ArrowSchemaMetadata::IsNonCanonicalType(const string &type, const string &vendor) const { - if (schema_metadata_map.find(ARROW_EXTENSION_NAME) == schema_metadata_map.end()) { - return false; - } - if (schema_metadata_map.find(ARROW_EXTENSION_NAME)->second != ARROW_EXTENSION_NON_CANONICAL) { - return false; - } - if (extension_metadata_map.find("type_name") == extension_metadata_map.end() || - extension_metadata_map.find("vendor_name") == extension_metadata_map.end()) { - return false; - } - auto vendor_name = extension_metadata_map.find("vendor_name")->second; - auto type_name = extension_metadata_map.find("type_name")->second; - return vendor_name == vendor && type_name == type; -} - -bool ArrowSchemaMetadata::HasExtension() const { +bool ArrowSchemaMetadata::HasExtension() { auto arrow_extension = GetOption(ArrowSchemaMetadata::ARROW_EXTENSION_NAME); // FIXME: We are currently ignoring the ogc extensions return !arrow_extension.empty() && !StringUtil::StartsWith(arrow_extension, "ogc"); @@ -93,7 +65,7 @@ unsafe_unique_array ArrowSchemaMetadata::SerializeMetadata() const { // First we have to figure out the total size: // 1. number of key-value pairs (int32) idx_t total_size = sizeof(int32_t); - for (const auto &option : schema_metadata_map) { + for (const auto &option : metadata_map) { // 2. Length of the key and value (2 * int32) total_size += 2 * sizeof(int32_t); // 3. Length of key @@ -104,11 +76,11 @@ unsafe_unique_array ArrowSchemaMetadata::SerializeMetadata() const { auto metadata_array_ptr = make_unsafe_uniq_array(total_size); auto metadata_ptr = metadata_array_ptr.get(); // 1. number of key-value pairs (int32) - const idx_t map_size = schema_metadata_map.size(); + const idx_t map_size = metadata_map.size(); memcpy(metadata_ptr, &map_size, sizeof(int32_t)); metadata_ptr += sizeof(int32_t); // Iterate through each key-value pair in the map - for (const auto &pair : schema_metadata_map) { + for (const auto &pair : metadata_map) { const std::string &key = pair.first; idx_t key_size = key.size(); // Length of the key (int32) diff --git a/src/duckdb/src/common/assert.cpp b/src/duckdb/src/common/assert.cpp index 02f62212e..3397fce21 100644 --- a/src/duckdb/src/common/assert.cpp +++ b/src/duckdb/src/common/assert.cpp @@ -10,7 +10,8 @@ void DuckDBAssertInternal(bool condition, const char *condition_name, const char if (condition) { return; } - throw InternalException("Assertion triggered in file \"%s\" on line %d: %s", file, linenr, condition_name); + throw InternalException("Assertion triggered in file \"%s\" on line %d: %s%s", file, linenr, condition_name, + Exception::GetStackTrace()); } } // namespace duckdb diff --git a/src/duckdb/src/common/bind_helpers.cpp b/src/duckdb/src/common/bind_helpers.cpp index b618b797b..2d8a9f323 100644 --- a/src/duckdb/src/common/bind_helpers.cpp +++ b/src/duckdb/src/common/bind_helpers.cpp @@ -11,7 +11,7 @@ namespace duckdb { Value ConvertVectorToValue(vector set) { if (set.empty()) { - return Value::LIST(LogicalType::BOOLEAN, std::move(set)); + return Value::EMPTYLIST(LogicalType::BOOLEAN); } return Value::LIST(std::move(set)); } diff --git a/src/duckdb/src/common/box_renderer.cpp b/src/duckdb/src/common/box_renderer.cpp index f85cf622d..404bb32fd 100644 --- a/src/duckdb/src/common/box_renderer.cpp +++ b/src/duckdb/src/common/box_renderer.cpp @@ -11,90 +11,11 @@ namespace duckdb { const idx_t BoxRenderer::SPLIT_COLUMN = idx_t(-1); -//===--------------------------------------------------------------------===// -// Result Renderer -//===--------------------------------------------------------------------===// -BaseResultRenderer::BaseResultRenderer() : value_type(LogicalTypeId::INVALID) { -} - -BaseResultRenderer::~BaseResultRenderer() { -} - -BaseResultRenderer &BaseResultRenderer::operator<<(char c) { - RenderLayout(string(1, c)); - return *this; -} - -BaseResultRenderer &BaseResultRenderer::operator<<(const string &val) { - RenderLayout(val); - return *this; -} - -void BaseResultRenderer::Render(ResultRenderType render_mode, const string &val) { - switch (render_mode) { - case ResultRenderType::LAYOUT: - RenderLayout(val); - break; - case ResultRenderType::COLUMN_NAME: - RenderColumnName(val); - break; - case ResultRenderType::COLUMN_TYPE: - RenderType(val); - break; - case ResultRenderType::VALUE: - RenderValue(val, value_type); - break; - case ResultRenderType::NULL_VALUE: - RenderNull(val, value_type); - break; - case ResultRenderType::FOOTER: - RenderFooter(val); - break; - default: - throw InternalException("Unsupported type for result renderer"); - } -} - -void BaseResultRenderer::SetValueType(const LogicalType &type) { - value_type = type; -} - -void StringResultRenderer::RenderLayout(const string &text) { - result += text; -} - -void StringResultRenderer::RenderColumnName(const string &text) { - result += text; -} - -void StringResultRenderer::RenderType(const string &text) { - result += text; -} - -void StringResultRenderer::RenderValue(const string &text, const LogicalType &type) { - result += text; -} - -void StringResultRenderer::RenderNull(const string &text, const LogicalType &type) { - result += text; -} - -void StringResultRenderer::RenderFooter(const string &text) { - result += text; -} - -const string &StringResultRenderer::str() { - return result; -} - -//===--------------------------------------------------------------------===// -// Box Renderer -//===--------------------------------------------------------------------===// BoxRenderer::BoxRenderer(BoxRendererConfig config_p) : config(std::move(config_p)) { } string BoxRenderer::ToString(ClientContext &context, const vector &names, const ColumnDataCollection &result) { - StringResultRenderer ss; + std::stringstream ss; Render(context, names, result, ss); return ss.str(); } @@ -103,8 +24,8 @@ void BoxRenderer::Print(ClientContext &context, const vector &names, con Printer::Print(ToString(context, names, result)); } -void BoxRenderer::RenderValue(BaseResultRenderer &ss, const string &value, idx_t column_width, - ResultRenderType render_mode, ValueRenderAlignment alignment) { +void BoxRenderer::RenderValue(std::ostream &ss, const string &value, idx_t column_width, + ValueRenderAlignment alignment) { auto render_width = Utf8Proc::RenderWidth(value); const string *render_value = &value; @@ -151,7 +72,7 @@ void BoxRenderer::RenderValue(BaseResultRenderer &ss, const string &value, idx_t } ss << config.VERTICAL; ss << string(lpadding, ' '); - ss.Render(render_mode, *render_value); + ss << *render_value; ss << string(rpadding, ' '); } @@ -210,74 +131,6 @@ ValueRenderAlignment BoxRenderer::TypeAlignment(const LogicalType &type) { } } -string BoxRenderer::TryFormatLargeNumber(const string &numeric) { - // we only return a readable rendering if the number is > 1 million - if (numeric.size() <= 5) { - // number too small for sure - return string(); - } - // get the number to summarize - idx_t number = 0; - bool negative = false; - idx_t i = 0; - if (numeric[0] == '-') { - negative = true; - i++; - } - for (; i < numeric.size(); i++) { - char c = numeric[i]; - if (c == '.') { - break; - } - if (c < '0' || c > '9') { - // not a number or something funky (e.g. 1.23e7) - // we could theoretically summarize numbers with exponents - return string(); - } - if (number >= 1000000000000000000ULL) { - // number too big - return string(); - } - number = number * 10 + static_cast(c - '0'); - } - struct UnitBase { - idx_t base; - const char *name; - }; - static constexpr idx_t BASE_COUNT = 5; - UnitBase bases[] = {{1000000ULL, "million"}, - {1000000000ULL, "billion"}, - {1000000000000ULL, "trillion"}, - {1000000000000000ULL, "quadrillion"}, - {1000000000000000000ULL, "quintillion"}}; - idx_t base = 0; - string unit; - for (idx_t i = 0; i < BASE_COUNT; i++) { - // round the number according to this base - idx_t rounded_number = number + ((bases[i].base / 100ULL) / 2); - if (rounded_number >= bases[i].base) { - base = bases[i].base; - unit = bases[i].name; - } - } - if (unit.empty()) { - return string(); - } - number += (base / 100ULL) / 2; - idx_t decimal_unit = number / (base / 100ULL); - string decimal_str = to_string(decimal_unit); - string result; - if (negative) { - result += "-"; - } - result += decimal_str.substr(0, decimal_str.size() - 2); - result += config.decimal_separator == '\0' ? '.' : config.decimal_separator; - result += decimal_str.substr(decimal_str.size() - 2, 2); - result += " "; - result += unit; - return result; -} - list BoxRenderer::FetchRenderCollections(ClientContext &context, const ColumnDataCollection &result, idx_t top_rows, idx_t bottom_rows) { @@ -299,13 +152,6 @@ list BoxRenderer::FetchRenderCollections(ClientContext &co DataChunk insert_result; insert_result.Initialize(context, varchar_types); - if (config.large_number_rendering == LargeNumberRendering::FOOTER) { - if (config.render_mode != RenderMode::ROWS || result.Count() != 1) { - // large number footer can only be constructed (1) if we have a single row, and (2) in ROWS mode - config.large_number_rendering = LargeNumberRendering::NONE; - } - } - // fetch the top rows from the ColumnDataCollection idx_t chunk_idx = 0; idx_t row_idx = 0; @@ -325,38 +171,6 @@ list BoxRenderer::FetchRenderCollections(ClientContext &co // construct the render collection top_collection.Append(insert_result); - // if we have are constructing a footer - if (config.large_number_rendering == LargeNumberRendering::FOOTER) { - D_ASSERT(insert_count == 1); - vector readable_numbers; - readable_numbers.resize(column_count); - bool all_readable = true; - for (idx_t c = 0; c < column_count; c++) { - if (!result.Types()[c].IsNumeric()) { - // not a numeric type - cannot summarize - all_readable = false; - break; - } - // add a readable rendering of the value (i.e. "1234567" becomes "1.23 million") - // we only add the rendering if the string is big - auto numeric_val = insert_result.data[c].GetValue(0).ToString(); - readable_numbers[c] = TryFormatLargeNumber(numeric_val); - if (readable_numbers[c].empty()) { - all_readable = false; - break; - } - readable_numbers[c] = "(" + readable_numbers[c] + ")"; - } - insert_result.Reset(); - if (all_readable) { - for (idx_t c = 0; c < column_count; c++) { - insert_result.data[c].SetValue(0, Value(readable_numbers[c])); - } - insert_result.SetCardinality(1); - top_collection.Append(insert_result); - } - } - chunk_idx++; row_idx += fetch_result.size(); } @@ -445,7 +259,7 @@ list BoxRenderer::PivotCollections(ClientContext &context, return result; } -string BoxRenderer::ConvertRenderValue(const string &input) { +string ConvertRenderValue(const string &input) { string result; result.reserve(input.size()); for (idx_t c = 0; c < input.size(); c++) { @@ -497,80 +311,13 @@ string BoxRenderer::ConvertRenderValue(const string &input) { return result; } -string BoxRenderer::FormatNumber(const string &input) { - if (config.large_number_rendering == LargeNumberRendering::ALL) { - // when large number rendering is set to ALL, we try to format all numbers as large numbers - auto number = TryFormatLargeNumber(input); - if (!number.empty()) { - return number; - } - } - if (config.decimal_separator == '\0' && config.thousand_separator == '\0') { - // no thousand separator - return input; - } - // first check how many digits there are (preceding any decimal point) - idx_t character_count = 0; - for (auto c : input) { - if (!StringUtil::CharacterIsDigit(c)) { - break; - } - character_count++; - } - // find the position of the first thousand separator - idx_t separator_position = character_count % 3 == 0 ? 3 : character_count % 3; - // now add the thousand separators - string result; - for (idx_t c = 0; c < character_count; c++) { - if (c == separator_position && config.thousand_separator != '\0') { - result += config.thousand_separator; - separator_position += 3; - } - result += input[c]; - } - // add any remaining characters - for (idx_t c = character_count; c < input.size(); c++) { - if (input[c] == '.' && config.decimal_separator != '\0') { - result += config.decimal_separator; - } else { - result += input[c]; - } - } - return result; -} - -string BoxRenderer::ConvertRenderValue(const string &input, const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::TINYINT: - case LogicalTypeId::SMALLINT: - case LogicalTypeId::INTEGER: - case LogicalTypeId::BIGINT: - case LogicalTypeId::HUGEINT: - case LogicalTypeId::UTINYINT: - case LogicalTypeId::USMALLINT: - case LogicalTypeId::UINTEGER: - case LogicalTypeId::UBIGINT: - case LogicalTypeId::UHUGEINT: - case LogicalTypeId::DECIMAL: - case LogicalTypeId::FLOAT: - case LogicalTypeId::DOUBLE: - return FormatNumber(input); - default: - return ConvertRenderValue(input); - } -} - -string BoxRenderer::GetRenderValue(BaseResultRenderer &ss, ColumnDataRowCollection &rows, idx_t c, idx_t r, - const LogicalType &type, ResultRenderType &render_mode) { +string BoxRenderer::GetRenderValue(ColumnDataRowCollection &rows, idx_t c, idx_t r) { try { - render_mode = ResultRenderType::VALUE; - ss.SetValueType(type); auto row = rows.GetValue(c, r); if (row.IsNull()) { - render_mode = ResultRenderType::NULL_VALUE; return config.null_value; } - return ConvertRenderValue(StringValue::Get(row), type); + return ConvertRenderValue(StringValue::Get(row)); } catch (std::exception &ex) { return "????INVALID VALUE - " + string(ex.what()) + "?????"; } @@ -599,7 +346,7 @@ vector BoxRenderer::ComputeRenderWidths(const vector &names, cons if (FlatVector::IsNull(chunk.data[c], r)) { render_value = config.null_value; } else { - render_value = ConvertRenderValue(string_data[r].GetString(), result_types[c]); + render_value = ConvertRenderValue(string_data[r].GetString()); } auto render_width = Utf8Proc::RenderWidth(render_value); widths[c] = MaxValue(render_width, widths[c]); @@ -688,7 +435,7 @@ vector BoxRenderer::ComputeRenderWidths(const vector &names, cons void BoxRenderer::RenderHeader(const vector &names, const vector &result_types, const vector &column_map, const vector &widths, const vector &boundaries, idx_t total_length, bool has_results, - BaseResultRenderer &ss) { + std::ostream &ss) { auto column_count = column_map.size(); // render the top line ss << config.LTCORNER; @@ -708,15 +455,12 @@ void BoxRenderer::RenderHeader(const vector &names, const vector &names, const vector &names, const vector &collections, const vector &column_map, - const vector &widths, const vector &result_types, - BaseResultRenderer &ss) { + const vector &widths, const vector &result_types, std::ostream &ss) { auto &top_collection = collections.front(); auto &bottom_collection = collections.back(); // render the top rows @@ -764,15 +500,12 @@ void BoxRenderer::RenderValues(const list &collections, co auto bottom_rows = bottom_collection.Count(); auto column_count = column_map.size(); - bool large_number_footer = config.large_number_rendering == LargeNumberRendering::FOOTER; vector alignments; if (config.render_mode == RenderMode::ROWS) { for (idx_t c = 0; c < column_count; c++) { auto column_idx = column_map[c]; if (column_idx == SPLIT_COLUMN) { alignments.push_back(ValueRenderAlignment::MIDDLE); - } else if (large_number_footer && result_types[column_idx].IsNumeric()) { - alignments.push_back(ValueRenderAlignment::MIDDLE); } else { alignments.push_back(TypeAlignment(result_types[column_idx])); } @@ -784,32 +517,15 @@ void BoxRenderer::RenderValues(const list &collections, co for (idx_t c = 0; c < column_count; c++) { auto column_idx = column_map[c]; string str; - ResultRenderType render_mode; if (column_idx == SPLIT_COLUMN) { str = config.DOTDOTDOT; - render_mode = ResultRenderType::LAYOUT; } else { - str = GetRenderValue(ss, rows, column_idx, r, result_types[column_idx], render_mode); + str = GetRenderValue(rows, column_idx, r); } ValueRenderAlignment alignment; if (config.render_mode == RenderMode::ROWS) { alignment = alignments[c]; - if (large_number_footer && r == 1) { - // render readable numbers with highlighting of a NULL value - render_mode = ResultRenderType::NULL_VALUE; - } } else { - switch (c) { - case 0: - render_mode = ResultRenderType::COLUMN_NAME; - break; - case 1: - render_mode = ResultRenderType::COLUMN_TYPE; - break; - default: - render_mode = ResultRenderType::VALUE; - break; - } if (c < 2) { alignment = ValueRenderAlignment::LEFT; } else if (c == SPLIT_COLUMN) { @@ -818,7 +534,7 @@ void BoxRenderer::RenderValues(const list &collections, co alignment = ValueRenderAlignment::RIGHT; } } - RenderValue(ss, str, widths[c], render_mode, alignment); + RenderValue(ss, str, widths[c], alignment); } ss << config.VERTICAL; ss << '\n'; @@ -840,11 +556,8 @@ void BoxRenderer::RenderValues(const list &collections, co str = config.DOT; } else { // align the dots in the center of the column - ResultRenderType render_mode; - auto top_value = - GetRenderValue(ss, rows, column_idx, top_rows - 1, result_types[column_idx], render_mode); - auto bottom_value = - GetRenderValue(ss, brows, column_idx, bottom_rows - 1, result_types[column_idx], render_mode); + auto top_value = GetRenderValue(rows, column_idx, top_rows - 1); + auto bottom_value = GetRenderValue(brows, column_idx, bottom_rows - 1); auto top_length = MinValue(widths[c], Utf8Proc::RenderWidth(top_value)); auto bottom_length = MinValue(widths[c], Utf8Proc::RenderWidth(bottom_value)); auto dot_length = MinValue(top_length, bottom_length); @@ -877,7 +590,7 @@ void BoxRenderer::RenderValues(const list &collections, co str = config.DOT; } } - RenderValue(ss, str, widths[c], ResultRenderType::LAYOUT, alignment); + RenderValue(ss, str, widths[c], alignment); } ss << config.VERTICAL; ss << '\n'; @@ -887,15 +600,12 @@ void BoxRenderer::RenderValues(const list &collections, co for (idx_t c = 0; c < column_count; c++) { auto column_idx = column_map[c]; string str; - ResultRenderType render_mode; if (column_idx == SPLIT_COLUMN) { str = config.DOTDOTDOT; - render_mode = ResultRenderType::LAYOUT; } else { - str = GetRenderValue(ss, brows, column_idx, bottom_rows - r - 1, result_types[column_idx], - render_mode); + str = GetRenderValue(brows, column_idx, bottom_rows - r - 1); } - RenderValue(ss, str, widths[c], render_mode, alignments[c]); + RenderValue(ss, str, widths[c], alignments[c]); } ss << config.VERTICAL; ss << '\n'; @@ -906,7 +616,7 @@ void BoxRenderer::RenderValues(const list &collections, co void BoxRenderer::RenderRowCount(string row_count_str, string shown_str, const string &column_count_str, const vector &boundaries, bool has_hidden_rows, bool has_hidden_columns, idx_t total_length, idx_t row_count, idx_t column_count, idx_t minimum_row_length, - BaseResultRenderer &ss) { + std::ostream &ss) { // check if we can merge the row_count_str and the shown_str bool display_shown_separately = has_hidden_rows; if (has_hidden_rows && total_length >= row_count_str.size() + shown_str.size() + 5) { @@ -946,19 +656,19 @@ void BoxRenderer::RenderRowCount(string row_count_str, string shown_str, const s if (render_rows_and_columns) { ss << config.VERTICAL; ss << " "; - ss.Render(ResultRenderType::FOOTER, row_count_str); + ss << row_count_str; ss << string(total_length - row_count_str.size() - column_count_str.size() - 4, ' '); - ss.Render(ResultRenderType::FOOTER, column_count_str); + ss << column_count_str; ss << " "; ss << config.VERTICAL; ss << '\n'; } else if (render_rows) { - RenderValue(ss, row_count_str, total_length - 4, ResultRenderType::FOOTER); + RenderValue(ss, row_count_str, total_length - 4); ss << config.VERTICAL; ss << '\n'; if (display_shown_separately) { - RenderValue(ss, shown_str, total_length - 4, ResultRenderType::FOOTER); + RenderValue(ss, shown_str, total_length - 4); ss << config.VERTICAL; ss << '\n'; } @@ -973,7 +683,7 @@ void BoxRenderer::RenderRowCount(string row_count_str, string shown_str, const s } void BoxRenderer::Render(ClientContext &context, const vector &names, const ColumnDataCollection &result, - BaseResultRenderer &ss) { + std::ostream &ss) { if (result.ColumnCount() != names.size()) { throw InternalException("Error in BoxRenderer::Render - unaligned columns and names"); } diff --git a/src/duckdb/src/common/cgroups.cpp b/src/duckdb/src/common/cgroups.cpp index d7ddd980c..eb240b208 100644 --- a/src/duckdb/src/common/cgroups.cpp +++ b/src/duckdb/src/common/cgroups.cpp @@ -86,13 +86,7 @@ string CGroups::ReadCGroupPath(FileSystem &fs, const char *cgroup_file) { string content(buffer); auto pos = content.find("::"); if (pos != string::npos) { - // remove trailing \n - auto pos2 = content.find('\n', pos + 2); - if (pos2 != string::npos) { - return content.substr(pos + 2, pos2 - (pos + 2)); - } else { - return content.substr(pos + 2); - } + return content.substr(pos + 2); } #endif return ""; diff --git a/src/duckdb/src/common/compressed_file_system.cpp b/src/duckdb/src/common/compressed_file_system.cpp index ddc325cf1..b34c6c21d 100644 --- a/src/duckdb/src/common/compressed_file_system.cpp +++ b/src/duckdb/src/common/compressed_file_system.cpp @@ -7,7 +7,7 @@ StreamWrapper::~StreamWrapper() { } CompressedFile::CompressedFile(CompressedFileSystem &fs, unique_ptr child_handle_p, const string &path) - : FileHandle(fs, path, child_handle_p->GetFlags()), compressed_fs(fs), child_handle(std::move(child_handle_p)) { + : FileHandle(fs, path), compressed_fs(fs), child_handle(std::move(child_handle_p)) { } CompressedFile::~CompressedFile() { diff --git a/src/duckdb/src/common/enum_util.cpp b/src/duckdb/src/common/enum_util.cpp index 1fd91919b..9a0db08f8 100644 --- a/src/duckdb/src/common/enum_util.cpp +++ b/src/duckdb/src/common/enum_util.cpp @@ -28,7 +28,6 @@ #include "duckdb/common/enums/file_compression_type.hpp" #include "duckdb/common/enums/file_glob_options.hpp" #include "duckdb/common/enums/filter_propagate_result.hpp" -#include "duckdb/common/enums/function_errors.hpp" #include "duckdb/common/enums/index_constraint_type.hpp" #include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/enums/joinref_type.hpp" @@ -46,7 +45,6 @@ #include "duckdb/common/enums/physical_operator_type.hpp" #include "duckdb/common/enums/prepared_statement_mode.hpp" #include "duckdb/common/enums/profiler_format.hpp" -#include "duckdb/common/enums/quantile_enum.hpp" #include "duckdb/common/enums/relation_type.hpp" #include "duckdb/common/enums/scan_options.hpp" #include "duckdb/common/enums/set_operation_type.hpp" @@ -73,13 +71,13 @@ #include "duckdb/common/types/column/column_data_scan_states.hpp" #include "duckdb/common/types/column/partitioned_column_data.hpp" #include "duckdb/common/types/conflict_manager.hpp" -#include "duckdb/common/types/date.hpp" #include "duckdb/common/types/hyperloglog.hpp" #include "duckdb/common/types/row/partitioned_tuple_data.hpp" #include "duckdb/common/types/row/tuple_data_states.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/types/vector_buffer.hpp" +#include "duckdb/core_functions/aggregate/quantile_enum.hpp" #include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/index/art/node.hpp" #include "duckdb/execution/operator/csv_scanner/csv_option.hpp" @@ -87,12 +85,10 @@ #include "duckdb/execution/operator/csv_scanner/quote_rules.hpp" #include "duckdb/execution/reservoir_sample.hpp" #include "duckdb/function/aggregate_state.hpp" -#include "duckdb/function/compression_function.hpp" #include "duckdb/function/copy_function.hpp" #include "duckdb/function/function.hpp" #include "duckdb/function/macro_function.hpp" -#include "duckdb/function/partition_stats.hpp" -#include "duckdb/function/scalar/compressed_materialization_utils.hpp" +#include "duckdb/function/scalar/compressed_materialization_functions.hpp" #include "duckdb/function/scalar/strftime_format.hpp" #include "duckdb/function/table/arrow/enum/arrow_datetime_type.hpp" #include "duckdb/function/table/arrow/enum/arrow_type_info_type.hpp" @@ -143,4097 +139,8200 @@ #include "duckdb/storage/statistics/base_statistics.hpp" #include "duckdb/storage/table/chunk_info.hpp" #include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/temporary_file_manager.hpp" #include "duckdb/verification/statement_verifier.hpp" namespace duckdb { -const StringUtil::EnumStringLiteral *GetARTAppendModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ARTAppendMode::DEFAULT), "DEFAULT" }, - { static_cast(ARTAppendMode::IGNORE_DUPLICATES), "IGNORE_DUPLICATES" }, - { static_cast(ARTAppendMode::INSERT_DUPLICATES), "INSERT_DUPLICATES" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(ARTAppendMode value) { - return StringUtil::EnumToString(GetARTAppendModeValues(), 3, "ARTAppendMode", static_cast(value)); -} - -template<> -ARTAppendMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetARTAppendModeValues(), 3, "ARTAppendMode", value)); -} - -const StringUtil::EnumStringLiteral *GetARTConflictTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ARTConflictType::NO_CONFLICT), "NO_CONFLICT" }, - { static_cast(ARTConflictType::CONSTRAINT), "CONSTRAINT" }, - { static_cast(ARTConflictType::TRANSACTION), "TRANSACTION" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(ARTConflictType value) { - return StringUtil::EnumToString(GetARTConflictTypeValues(), 3, "ARTConflictType", static_cast(value)); -} - -template<> -ARTConflictType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetARTConflictTypeValues(), 3, "ARTConflictType", value)); -} - -const StringUtil::EnumStringLiteral *GetAccessModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AccessMode::UNDEFINED), "UNDEFINED" }, - { static_cast(AccessMode::AUTOMATIC), "AUTOMATIC" }, - { static_cast(AccessMode::READ_ONLY), "READ_ONLY" }, - { static_cast(AccessMode::READ_WRITE), "READ_WRITE" } - }; - return values; -} - template<> const char* EnumUtil::ToChars(AccessMode value) { - return StringUtil::EnumToString(GetAccessModeValues(), 4, "AccessMode", static_cast(value)); + switch(value) { + case AccessMode::UNDEFINED: + return "UNDEFINED"; + case AccessMode::AUTOMATIC: + return "AUTOMATIC"; + case AccessMode::READ_ONLY: + return "READ_ONLY"; + case AccessMode::READ_WRITE: + return "READ_WRITE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AccessMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAccessModeValues(), 4, "AccessMode", value)); -} - -const StringUtil::EnumStringLiteral *GetAggregateCombineTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AggregateCombineType::PRESERVE_INPUT), "PRESERVE_INPUT" }, - { static_cast(AggregateCombineType::ALLOW_DESTRUCTIVE), "ALLOW_DESTRUCTIVE" } - }; - return values; + if (StringUtil::Equals(value, "UNDEFINED")) { + return AccessMode::UNDEFINED; + } + if (StringUtil::Equals(value, "AUTOMATIC")) { + return AccessMode::AUTOMATIC; + } + if (StringUtil::Equals(value, "READ_ONLY")) { + return AccessMode::READ_ONLY; + } + if (StringUtil::Equals(value, "READ_WRITE")) { + return AccessMode::READ_WRITE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AggregateCombineType value) { - return StringUtil::EnumToString(GetAggregateCombineTypeValues(), 2, "AggregateCombineType", static_cast(value)); + switch(value) { + case AggregateCombineType::PRESERVE_INPUT: + return "PRESERVE_INPUT"; + case AggregateCombineType::ALLOW_DESTRUCTIVE: + return "ALLOW_DESTRUCTIVE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AggregateCombineType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAggregateCombineTypeValues(), 2, "AggregateCombineType", value)); -} - -const StringUtil::EnumStringLiteral *GetAggregateDistinctDependentValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AggregateDistinctDependent::DISTINCT_DEPENDENT), "DISTINCT_DEPENDENT" }, - { static_cast(AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT), "NOT_DISTINCT_DEPENDENT" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(AggregateDistinctDependent value) { - return StringUtil::EnumToString(GetAggregateDistinctDependentValues(), 2, "AggregateDistinctDependent", static_cast(value)); -} - -template<> -AggregateDistinctDependent EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAggregateDistinctDependentValues(), 2, "AggregateDistinctDependent", value)); -} - -const StringUtil::EnumStringLiteral *GetAggregateHandlingValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AggregateHandling::STANDARD_HANDLING), "STANDARD_HANDLING" }, - { static_cast(AggregateHandling::NO_AGGREGATES_ALLOWED), "NO_AGGREGATES_ALLOWED" }, - { static_cast(AggregateHandling::FORCE_AGGREGATES), "FORCE_AGGREGATES" } - }; - return values; + if (StringUtil::Equals(value, "PRESERVE_INPUT")) { + return AggregateCombineType::PRESERVE_INPUT; + } + if (StringUtil::Equals(value, "ALLOW_DESTRUCTIVE")) { + return AggregateCombineType::ALLOW_DESTRUCTIVE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AggregateHandling value) { - return StringUtil::EnumToString(GetAggregateHandlingValues(), 3, "AggregateHandling", static_cast(value)); + switch(value) { + case AggregateHandling::STANDARD_HANDLING: + return "STANDARD_HANDLING"; + case AggregateHandling::NO_AGGREGATES_ALLOWED: + return "NO_AGGREGATES_ALLOWED"; + case AggregateHandling::FORCE_AGGREGATES: + return "FORCE_AGGREGATES"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AggregateHandling EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAggregateHandlingValues(), 3, "AggregateHandling", value)); -} - -const StringUtil::EnumStringLiteral *GetAggregateOrderDependentValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AggregateOrderDependent::ORDER_DEPENDENT), "ORDER_DEPENDENT" }, - { static_cast(AggregateOrderDependent::NOT_ORDER_DEPENDENT), "NOT_ORDER_DEPENDENT" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD_HANDLING")) { + return AggregateHandling::STANDARD_HANDLING; + } + if (StringUtil::Equals(value, "NO_AGGREGATES_ALLOWED")) { + return AggregateHandling::NO_AGGREGATES_ALLOWED; + } + if (StringUtil::Equals(value, "FORCE_AGGREGATES")) { + return AggregateHandling::FORCE_AGGREGATES; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AggregateOrderDependent value) { - return StringUtil::EnumToString(GetAggregateOrderDependentValues(), 2, "AggregateOrderDependent", static_cast(value)); + switch(value) { + case AggregateOrderDependent::ORDER_DEPENDENT: + return "ORDER_DEPENDENT"; + case AggregateOrderDependent::NOT_ORDER_DEPENDENT: + return "NOT_ORDER_DEPENDENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AggregateOrderDependent EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAggregateOrderDependentValues(), 2, "AggregateOrderDependent", value)); -} - -const StringUtil::EnumStringLiteral *GetAggregateTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AggregateType::NON_DISTINCT), "NON_DISTINCT" }, - { static_cast(AggregateType::DISTINCT), "DISTINCT" } - }; - return values; + if (StringUtil::Equals(value, "ORDER_DEPENDENT")) { + return AggregateOrderDependent::ORDER_DEPENDENT; + } + if (StringUtil::Equals(value, "NOT_ORDER_DEPENDENT")) { + return AggregateOrderDependent::NOT_ORDER_DEPENDENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AggregateType value) { - return StringUtil::EnumToString(GetAggregateTypeValues(), 2, "AggregateType", static_cast(value)); + switch(value) { + case AggregateType::NON_DISTINCT: + return "NON_DISTINCT"; + case AggregateType::DISTINCT: + return "DISTINCT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AggregateType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAggregateTypeValues(), 2, "AggregateType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterForeignKeyTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterForeignKeyType::AFT_ADD), "AFT_ADD" }, - { static_cast(AlterForeignKeyType::AFT_DELETE), "AFT_DELETE" } - }; - return values; + if (StringUtil::Equals(value, "NON_DISTINCT")) { + return AggregateType::NON_DISTINCT; + } + if (StringUtil::Equals(value, "DISTINCT")) { + return AggregateType::DISTINCT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterForeignKeyType value) { - return StringUtil::EnumToString(GetAlterForeignKeyTypeValues(), 2, "AlterForeignKeyType", static_cast(value)); + switch(value) { + case AlterForeignKeyType::AFT_ADD: + return "AFT_ADD"; + case AlterForeignKeyType::AFT_DELETE: + return "AFT_DELETE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterForeignKeyType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterForeignKeyTypeValues(), 2, "AlterForeignKeyType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterScalarFunctionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterScalarFunctionType::INVALID), "INVALID" }, - { static_cast(AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS), "ADD_FUNCTION_OVERLOADS" } - }; - return values; + if (StringUtil::Equals(value, "AFT_ADD")) { + return AlterForeignKeyType::AFT_ADD; + } + if (StringUtil::Equals(value, "AFT_DELETE")) { + return AlterForeignKeyType::AFT_DELETE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterScalarFunctionType value) { - return StringUtil::EnumToString(GetAlterScalarFunctionTypeValues(), 2, "AlterScalarFunctionType", static_cast(value)); + switch(value) { + case AlterScalarFunctionType::INVALID: + return "INVALID"; + case AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS: + return "ADD_FUNCTION_OVERLOADS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterScalarFunctionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterScalarFunctionTypeValues(), 2, "AlterScalarFunctionType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterTableFunctionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterTableFunctionType::INVALID), "INVALID" }, - { static_cast(AlterTableFunctionType::ADD_FUNCTION_OVERLOADS), "ADD_FUNCTION_OVERLOADS" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return AlterScalarFunctionType::INVALID; + } + if (StringUtil::Equals(value, "ADD_FUNCTION_OVERLOADS")) { + return AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterTableFunctionType value) { - return StringUtil::EnumToString(GetAlterTableFunctionTypeValues(), 2, "AlterTableFunctionType", static_cast(value)); + switch(value) { + case AlterTableFunctionType::INVALID: + return "INVALID"; + case AlterTableFunctionType::ADD_FUNCTION_OVERLOADS: + return "ADD_FUNCTION_OVERLOADS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterTableFunctionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterTableFunctionTypeValues(), 2, "AlterTableFunctionType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterTableTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterTableType::INVALID), "INVALID" }, - { static_cast(AlterTableType::RENAME_COLUMN), "RENAME_COLUMN" }, - { static_cast(AlterTableType::RENAME_TABLE), "RENAME_TABLE" }, - { static_cast(AlterTableType::ADD_COLUMN), "ADD_COLUMN" }, - { static_cast(AlterTableType::REMOVE_COLUMN), "REMOVE_COLUMN" }, - { static_cast(AlterTableType::ALTER_COLUMN_TYPE), "ALTER_COLUMN_TYPE" }, - { static_cast(AlterTableType::SET_DEFAULT), "SET_DEFAULT" }, - { static_cast(AlterTableType::FOREIGN_KEY_CONSTRAINT), "FOREIGN_KEY_CONSTRAINT" }, - { static_cast(AlterTableType::SET_NOT_NULL), "SET_NOT_NULL" }, - { static_cast(AlterTableType::DROP_NOT_NULL), "DROP_NOT_NULL" }, - { static_cast(AlterTableType::SET_COLUMN_COMMENT), "SET_COLUMN_COMMENT" }, - { static_cast(AlterTableType::ADD_CONSTRAINT), "ADD_CONSTRAINT" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return AlterTableFunctionType::INVALID; + } + if (StringUtil::Equals(value, "ADD_FUNCTION_OVERLOADS")) { + return AlterTableFunctionType::ADD_FUNCTION_OVERLOADS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterTableType value) { - return StringUtil::EnumToString(GetAlterTableTypeValues(), 12, "AlterTableType", static_cast(value)); + switch(value) { + case AlterTableType::INVALID: + return "INVALID"; + case AlterTableType::RENAME_COLUMN: + return "RENAME_COLUMN"; + case AlterTableType::RENAME_TABLE: + return "RENAME_TABLE"; + case AlterTableType::ADD_COLUMN: + return "ADD_COLUMN"; + case AlterTableType::REMOVE_COLUMN: + return "REMOVE_COLUMN"; + case AlterTableType::ALTER_COLUMN_TYPE: + return "ALTER_COLUMN_TYPE"; + case AlterTableType::SET_DEFAULT: + return "SET_DEFAULT"; + case AlterTableType::FOREIGN_KEY_CONSTRAINT: + return "FOREIGN_KEY_CONSTRAINT"; + case AlterTableType::SET_NOT_NULL: + return "SET_NOT_NULL"; + case AlterTableType::DROP_NOT_NULL: + return "DROP_NOT_NULL"; + case AlterTableType::SET_COLUMN_COMMENT: + return "SET_COLUMN_COMMENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterTableType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterTableTypeValues(), 12, "AlterTableType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterType::INVALID), "INVALID" }, - { static_cast(AlterType::ALTER_TABLE), "ALTER_TABLE" }, - { static_cast(AlterType::ALTER_VIEW), "ALTER_VIEW" }, - { static_cast(AlterType::ALTER_SEQUENCE), "ALTER_SEQUENCE" }, - { static_cast(AlterType::CHANGE_OWNERSHIP), "CHANGE_OWNERSHIP" }, - { static_cast(AlterType::ALTER_SCALAR_FUNCTION), "ALTER_SCALAR_FUNCTION" }, - { static_cast(AlterType::ALTER_TABLE_FUNCTION), "ALTER_TABLE_FUNCTION" }, - { static_cast(AlterType::SET_COMMENT), "SET_COMMENT" }, - { static_cast(AlterType::SET_COLUMN_COMMENT), "SET_COLUMN_COMMENT" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return AlterTableType::INVALID; + } + if (StringUtil::Equals(value, "RENAME_COLUMN")) { + return AlterTableType::RENAME_COLUMN; + } + if (StringUtil::Equals(value, "RENAME_TABLE")) { + return AlterTableType::RENAME_TABLE; + } + if (StringUtil::Equals(value, "ADD_COLUMN")) { + return AlterTableType::ADD_COLUMN; + } + if (StringUtil::Equals(value, "REMOVE_COLUMN")) { + return AlterTableType::REMOVE_COLUMN; + } + if (StringUtil::Equals(value, "ALTER_COLUMN_TYPE")) { + return AlterTableType::ALTER_COLUMN_TYPE; + } + if (StringUtil::Equals(value, "SET_DEFAULT")) { + return AlterTableType::SET_DEFAULT; + } + if (StringUtil::Equals(value, "FOREIGN_KEY_CONSTRAINT")) { + return AlterTableType::FOREIGN_KEY_CONSTRAINT; + } + if (StringUtil::Equals(value, "SET_NOT_NULL")) { + return AlterTableType::SET_NOT_NULL; + } + if (StringUtil::Equals(value, "DROP_NOT_NULL")) { + return AlterTableType::DROP_NOT_NULL; + } + if (StringUtil::Equals(value, "SET_COLUMN_COMMENT")) { + return AlterTableType::SET_COLUMN_COMMENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterType value) { - return StringUtil::EnumToString(GetAlterTypeValues(), 9, "AlterType", static_cast(value)); + switch(value) { + case AlterType::INVALID: + return "INVALID"; + case AlterType::ALTER_TABLE: + return "ALTER_TABLE"; + case AlterType::ALTER_VIEW: + return "ALTER_VIEW"; + case AlterType::ALTER_SEQUENCE: + return "ALTER_SEQUENCE"; + case AlterType::CHANGE_OWNERSHIP: + return "CHANGE_OWNERSHIP"; + case AlterType::ALTER_SCALAR_FUNCTION: + return "ALTER_SCALAR_FUNCTION"; + case AlterType::ALTER_TABLE_FUNCTION: + return "ALTER_TABLE_FUNCTION"; + case AlterType::SET_COMMENT: + return "SET_COMMENT"; + case AlterType::SET_COLUMN_COMMENT: + return "SET_COLUMN_COMMENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterTypeValues(), 9, "AlterType", value)); -} - -const StringUtil::EnumStringLiteral *GetAlterViewTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AlterViewType::INVALID), "INVALID" }, - { static_cast(AlterViewType::RENAME_VIEW), "RENAME_VIEW" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return AlterType::INVALID; + } + if (StringUtil::Equals(value, "ALTER_TABLE")) { + return AlterType::ALTER_TABLE; + } + if (StringUtil::Equals(value, "ALTER_VIEW")) { + return AlterType::ALTER_VIEW; + } + if (StringUtil::Equals(value, "ALTER_SEQUENCE")) { + return AlterType::ALTER_SEQUENCE; + } + if (StringUtil::Equals(value, "CHANGE_OWNERSHIP")) { + return AlterType::CHANGE_OWNERSHIP; + } + if (StringUtil::Equals(value, "ALTER_SCALAR_FUNCTION")) { + return AlterType::ALTER_SCALAR_FUNCTION; + } + if (StringUtil::Equals(value, "ALTER_TABLE_FUNCTION")) { + return AlterType::ALTER_TABLE_FUNCTION; + } + if (StringUtil::Equals(value, "SET_COMMENT")) { + return AlterType::SET_COMMENT; + } + if (StringUtil::Equals(value, "SET_COLUMN_COMMENT")) { + return AlterType::SET_COLUMN_COMMENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AlterViewType value) { - return StringUtil::EnumToString(GetAlterViewTypeValues(), 2, "AlterViewType", static_cast(value)); + switch(value) { + case AlterViewType::INVALID: + return "INVALID"; + case AlterViewType::RENAME_VIEW: + return "RENAME_VIEW"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AlterViewType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAlterViewTypeValues(), 2, "AlterViewType", value)); -} - -const StringUtil::EnumStringLiteral *GetAppenderTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(AppenderType::LOGICAL), "LOGICAL" }, - { static_cast(AppenderType::PHYSICAL), "PHYSICAL" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return AlterViewType::INVALID; + } + if (StringUtil::Equals(value, "RENAME_VIEW")) { + return AlterViewType::RENAME_VIEW; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(AppenderType value) { - return StringUtil::EnumToString(GetAppenderTypeValues(), 2, "AppenderType", static_cast(value)); + switch(value) { + case AppenderType::LOGICAL: + return "LOGICAL"; + case AppenderType::PHYSICAL: + return "PHYSICAL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> AppenderType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetAppenderTypeValues(), 2, "AppenderType", value)); -} - -const StringUtil::EnumStringLiteral *GetArrowDateTimeTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ArrowDateTimeType::MILLISECONDS), "MILLISECONDS" }, - { static_cast(ArrowDateTimeType::MICROSECONDS), "MICROSECONDS" }, - { static_cast(ArrowDateTimeType::NANOSECONDS), "NANOSECONDS" }, - { static_cast(ArrowDateTimeType::SECONDS), "SECONDS" }, - { static_cast(ArrowDateTimeType::DAYS), "DAYS" }, - { static_cast(ArrowDateTimeType::MONTHS), "MONTHS" }, - { static_cast(ArrowDateTimeType::MONTH_DAY_NANO), "MONTH_DAY_NANO" } - }; - return values; + if (StringUtil::Equals(value, "LOGICAL")) { + return AppenderType::LOGICAL; + } + if (StringUtil::Equals(value, "PHYSICAL")) { + return AppenderType::PHYSICAL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ArrowDateTimeType value) { - return StringUtil::EnumToString(GetArrowDateTimeTypeValues(), 7, "ArrowDateTimeType", static_cast(value)); + switch(value) { + case ArrowDateTimeType::MILLISECONDS: + return "MILLISECONDS"; + case ArrowDateTimeType::MICROSECONDS: + return "MICROSECONDS"; + case ArrowDateTimeType::NANOSECONDS: + return "NANOSECONDS"; + case ArrowDateTimeType::SECONDS: + return "SECONDS"; + case ArrowDateTimeType::DAYS: + return "DAYS"; + case ArrowDateTimeType::MONTHS: + return "MONTHS"; + case ArrowDateTimeType::MONTH_DAY_NANO: + return "MONTH_DAY_NANO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ArrowDateTimeType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetArrowDateTimeTypeValues(), 7, "ArrowDateTimeType", value)); -} - -const StringUtil::EnumStringLiteral *GetArrowOffsetSizeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ArrowOffsetSize::REGULAR), "REGULAR" }, - { static_cast(ArrowOffsetSize::LARGE), "LARGE" } - }; - return values; + if (StringUtil::Equals(value, "MILLISECONDS")) { + return ArrowDateTimeType::MILLISECONDS; + } + if (StringUtil::Equals(value, "MICROSECONDS")) { + return ArrowDateTimeType::MICROSECONDS; + } + if (StringUtil::Equals(value, "NANOSECONDS")) { + return ArrowDateTimeType::NANOSECONDS; + } + if (StringUtil::Equals(value, "SECONDS")) { + return ArrowDateTimeType::SECONDS; + } + if (StringUtil::Equals(value, "DAYS")) { + return ArrowDateTimeType::DAYS; + } + if (StringUtil::Equals(value, "MONTHS")) { + return ArrowDateTimeType::MONTHS; + } + if (StringUtil::Equals(value, "MONTH_DAY_NANO")) { + return ArrowDateTimeType::MONTH_DAY_NANO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ArrowOffsetSize value) { - return StringUtil::EnumToString(GetArrowOffsetSizeValues(), 2, "ArrowOffsetSize", static_cast(value)); + switch(value) { + case ArrowOffsetSize::REGULAR: + return "REGULAR"; + case ArrowOffsetSize::LARGE: + return "LARGE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ArrowOffsetSize EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetArrowOffsetSizeValues(), 2, "ArrowOffsetSize", value)); -} - -const StringUtil::EnumStringLiteral *GetArrowTypeInfoTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ArrowTypeInfoType::LIST), "LIST" }, - { static_cast(ArrowTypeInfoType::STRUCT), "STRUCT" }, - { static_cast(ArrowTypeInfoType::DATE_TIME), "DATE_TIME" }, - { static_cast(ArrowTypeInfoType::STRING), "STRING" }, - { static_cast(ArrowTypeInfoType::ARRAY), "ARRAY" } - }; - return values; + if (StringUtil::Equals(value, "REGULAR")) { + return ArrowOffsetSize::REGULAR; + } + if (StringUtil::Equals(value, "LARGE")) { + return ArrowOffsetSize::LARGE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ArrowTypeInfoType value) { - return StringUtil::EnumToString(GetArrowTypeInfoTypeValues(), 5, "ArrowTypeInfoType", static_cast(value)); + switch(value) { + case ArrowTypeInfoType::LIST: + return "LIST"; + case ArrowTypeInfoType::STRUCT: + return "STRUCT"; + case ArrowTypeInfoType::DATE_TIME: + return "DATE_TIME"; + case ArrowTypeInfoType::STRING: + return "STRING"; + case ArrowTypeInfoType::ARRAY: + return "ARRAY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ArrowTypeInfoType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetArrowTypeInfoTypeValues(), 5, "ArrowTypeInfoType", value)); -} - -const StringUtil::EnumStringLiteral *GetArrowVariableSizeTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ArrowVariableSizeType::NORMAL), "NORMAL" }, - { static_cast(ArrowVariableSizeType::FIXED_SIZE), "FIXED_SIZE" }, - { static_cast(ArrowVariableSizeType::SUPER_SIZE), "SUPER_SIZE" }, - { static_cast(ArrowVariableSizeType::VIEW), "VIEW" } - }; - return values; + if (StringUtil::Equals(value, "LIST")) { + return ArrowTypeInfoType::LIST; + } + if (StringUtil::Equals(value, "STRUCT")) { + return ArrowTypeInfoType::STRUCT; + } + if (StringUtil::Equals(value, "DATE_TIME")) { + return ArrowTypeInfoType::DATE_TIME; + } + if (StringUtil::Equals(value, "STRING")) { + return ArrowTypeInfoType::STRING; + } + if (StringUtil::Equals(value, "ARRAY")) { + return ArrowTypeInfoType::ARRAY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ArrowVariableSizeType value) { - return StringUtil::EnumToString(GetArrowVariableSizeTypeValues(), 4, "ArrowVariableSizeType", static_cast(value)); + switch(value) { + case ArrowVariableSizeType::NORMAL: + return "NORMAL"; + case ArrowVariableSizeType::FIXED_SIZE: + return "FIXED_SIZE"; + case ArrowVariableSizeType::SUPER_SIZE: + return "SUPER_SIZE"; + case ArrowVariableSizeType::VIEW: + return "VIEW"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ArrowVariableSizeType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetArrowVariableSizeTypeValues(), 4, "ArrowVariableSizeType", value)); -} - -const StringUtil::EnumStringLiteral *GetBinderTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(BinderType::REGULAR_BINDER), "REGULAR_BINDER" }, - { static_cast(BinderType::VIEW_BINDER), "VIEW_BINDER" } - }; - return values; + if (StringUtil::Equals(value, "NORMAL")) { + return ArrowVariableSizeType::NORMAL; + } + if (StringUtil::Equals(value, "FIXED_SIZE")) { + return ArrowVariableSizeType::FIXED_SIZE; + } + if (StringUtil::Equals(value, "SUPER_SIZE")) { + return ArrowVariableSizeType::SUPER_SIZE; + } + if (StringUtil::Equals(value, "VIEW")) { + return ArrowVariableSizeType::VIEW; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(BinderType value) { - return StringUtil::EnumToString(GetBinderTypeValues(), 2, "BinderType", static_cast(value)); + switch(value) { + case BinderType::REGULAR_BINDER: + return "REGULAR_BINDER"; + case BinderType::VIEW_BINDER: + return "VIEW_BINDER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> BinderType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetBinderTypeValues(), 2, "BinderType", value)); -} - -const StringUtil::EnumStringLiteral *GetBindingModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(BindingMode::STANDARD_BINDING), "STANDARD_BINDING" }, - { static_cast(BindingMode::EXTRACT_NAMES), "EXTRACT_NAMES" }, - { static_cast(BindingMode::EXTRACT_REPLACEMENT_SCANS), "EXTRACT_REPLACEMENT_SCANS" } - }; - return values; + if (StringUtil::Equals(value, "REGULAR_BINDER")) { + return BinderType::REGULAR_BINDER; + } + if (StringUtil::Equals(value, "VIEW_BINDER")) { + return BinderType::VIEW_BINDER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(BindingMode value) { - return StringUtil::EnumToString(GetBindingModeValues(), 3, "BindingMode", static_cast(value)); + switch(value) { + case BindingMode::STANDARD_BINDING: + return "STANDARD_BINDING"; + case BindingMode::EXTRACT_NAMES: + return "EXTRACT_NAMES"; + case BindingMode::EXTRACT_REPLACEMENT_SCANS: + return "EXTRACT_REPLACEMENT_SCANS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> BindingMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetBindingModeValues(), 3, "BindingMode", value)); -} - -const StringUtil::EnumStringLiteral *GetBitpackingModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(BitpackingMode::INVALID), "INVALID" }, - { static_cast(BitpackingMode::AUTO), "AUTO" }, - { static_cast(BitpackingMode::CONSTANT), "CONSTANT" }, - { static_cast(BitpackingMode::CONSTANT_DELTA), "CONSTANT_DELTA" }, - { static_cast(BitpackingMode::DELTA_FOR), "DELTA_FOR" }, - { static_cast(BitpackingMode::FOR), "FOR" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD_BINDING")) { + return BindingMode::STANDARD_BINDING; + } + if (StringUtil::Equals(value, "EXTRACT_NAMES")) { + return BindingMode::EXTRACT_NAMES; + } + if (StringUtil::Equals(value, "EXTRACT_REPLACEMENT_SCANS")) { + return BindingMode::EXTRACT_REPLACEMENT_SCANS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(BitpackingMode value) { - return StringUtil::EnumToString(GetBitpackingModeValues(), 6, "BitpackingMode", static_cast(value)); + switch(value) { + case BitpackingMode::INVALID: + return "INVALID"; + case BitpackingMode::AUTO: + return "AUTO"; + case BitpackingMode::CONSTANT: + return "CONSTANT"; + case BitpackingMode::CONSTANT_DELTA: + return "CONSTANT_DELTA"; + case BitpackingMode::DELTA_FOR: + return "DELTA_FOR"; + case BitpackingMode::FOR: + return "FOR"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> BitpackingMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetBitpackingModeValues(), 6, "BitpackingMode", value)); -} - -const StringUtil::EnumStringLiteral *GetBlockStateValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(BlockState::BLOCK_UNLOADED), "BLOCK_UNLOADED" }, - { static_cast(BlockState::BLOCK_LOADED), "BLOCK_LOADED" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return BitpackingMode::INVALID; + } + if (StringUtil::Equals(value, "AUTO")) { + return BitpackingMode::AUTO; + } + if (StringUtil::Equals(value, "CONSTANT")) { + return BitpackingMode::CONSTANT; + } + if (StringUtil::Equals(value, "CONSTANT_DELTA")) { + return BitpackingMode::CONSTANT_DELTA; + } + if (StringUtil::Equals(value, "DELTA_FOR")) { + return BitpackingMode::DELTA_FOR; + } + if (StringUtil::Equals(value, "FOR")) { + return BitpackingMode::FOR; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(BlockState value) { - return StringUtil::EnumToString(GetBlockStateValues(), 2, "BlockState", static_cast(value)); + switch(value) { + case BlockState::BLOCK_UNLOADED: + return "BLOCK_UNLOADED"; + case BlockState::BLOCK_LOADED: + return "BLOCK_LOADED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> BlockState EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetBlockStateValues(), 2, "BlockState", value)); -} - -const StringUtil::EnumStringLiteral *GetCAPIResultSetTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_NONE), "CAPI_RESULT_TYPE_NONE" }, - { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED), "CAPI_RESULT_TYPE_MATERIALIZED" }, - { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING), "CAPI_RESULT_TYPE_STREAMING" }, - { static_cast(CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED), "CAPI_RESULT_TYPE_DEPRECATED" } - }; - return values; + if (StringUtil::Equals(value, "BLOCK_UNLOADED")) { + return BlockState::BLOCK_UNLOADED; + } + if (StringUtil::Equals(value, "BLOCK_LOADED")) { + return BlockState::BLOCK_LOADED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CAPIResultSetType value) { - return StringUtil::EnumToString(GetCAPIResultSetTypeValues(), 4, "CAPIResultSetType", static_cast(value)); + switch(value) { + case CAPIResultSetType::CAPI_RESULT_TYPE_NONE: + return "CAPI_RESULT_TYPE_NONE"; + case CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED: + return "CAPI_RESULT_TYPE_MATERIALIZED"; + case CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING: + return "CAPI_RESULT_TYPE_STREAMING"; + case CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED: + return "CAPI_RESULT_TYPE_DEPRECATED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CAPIResultSetType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCAPIResultSetTypeValues(), 4, "CAPIResultSetType", value)); -} - -const StringUtil::EnumStringLiteral *GetCSVStateValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CSVState::STANDARD), "STANDARD" }, - { static_cast(CSVState::DELIMITER), "DELIMITER" }, - { static_cast(CSVState::DELIMITER_FIRST_BYTE), "DELIMITER_FIRST_BYTE" }, - { static_cast(CSVState::DELIMITER_SECOND_BYTE), "DELIMITER_SECOND_BYTE" }, - { static_cast(CSVState::DELIMITER_THIRD_BYTE), "DELIMITER_THIRD_BYTE" }, - { static_cast(CSVState::RECORD_SEPARATOR), "RECORD_SEPARATOR" }, - { static_cast(CSVState::CARRIAGE_RETURN), "CARRIAGE_RETURN" }, - { static_cast(CSVState::QUOTED), "QUOTED" }, - { static_cast(CSVState::UNQUOTED), "UNQUOTED" }, - { static_cast(CSVState::ESCAPE), "ESCAPE" }, - { static_cast(CSVState::INVALID), "INVALID" }, - { static_cast(CSVState::NOT_SET), "NOT_SET" }, - { static_cast(CSVState::QUOTED_NEW_LINE), "QUOTED_NEW_LINE" }, - { static_cast(CSVState::EMPTY_SPACE), "EMPTY_SPACE" }, - { static_cast(CSVState::COMMENT), "COMMENT" }, - { static_cast(CSVState::STANDARD_NEWLINE), "STANDARD_NEWLINE" }, - { static_cast(CSVState::UNQUOTED_ESCAPE), "UNQUOTED_ESCAPE" }, - { static_cast(CSVState::ESCAPED_RETURN), "ESCAPED_RETURN" }, - { static_cast(CSVState::MAYBE_QUOTED), "MAYBE_QUOTED" } - }; - return values; + if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_NONE")) { + return CAPIResultSetType::CAPI_RESULT_TYPE_NONE; + } + if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_MATERIALIZED")) { + return CAPIResultSetType::CAPI_RESULT_TYPE_MATERIALIZED; + } + if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_STREAMING")) { + return CAPIResultSetType::CAPI_RESULT_TYPE_STREAMING; + } + if (StringUtil::Equals(value, "CAPI_RESULT_TYPE_DEPRECATED")) { + return CAPIResultSetType::CAPI_RESULT_TYPE_DEPRECATED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CSVState value) { - return StringUtil::EnumToString(GetCSVStateValues(), 19, "CSVState", static_cast(value)); + switch(value) { + case CSVState::STANDARD: + return "STANDARD"; + case CSVState::DELIMITER: + return "DELIMITER"; + case CSVState::RECORD_SEPARATOR: + return "RECORD_SEPARATOR"; + case CSVState::CARRIAGE_RETURN: + return "CARRIAGE_RETURN"; + case CSVState::QUOTED: + return "QUOTED"; + case CSVState::UNQUOTED: + return "UNQUOTED"; + case CSVState::ESCAPE: + return "ESCAPE"; + case CSVState::INVALID: + return "INVALID"; + case CSVState::NOT_SET: + return "NOT_SET"; + case CSVState::QUOTED_NEW_LINE: + return "QUOTED_NEW_LINE"; + case CSVState::EMPTY_SPACE: + return "EMPTY_SPACE"; + case CSVState::COMMENT: + return "COMMENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CSVState EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCSVStateValues(), 19, "CSVState", value)); -} - -const StringUtil::EnumStringLiteral *GetCTEMaterializeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CTEMaterialize::CTE_MATERIALIZE_DEFAULT), "CTE_MATERIALIZE_DEFAULT" }, - { static_cast(CTEMaterialize::CTE_MATERIALIZE_ALWAYS), "CTE_MATERIALIZE_ALWAYS" }, - { static_cast(CTEMaterialize::CTE_MATERIALIZE_NEVER), "CTE_MATERIALIZE_NEVER" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD")) { + return CSVState::STANDARD; + } + if (StringUtil::Equals(value, "DELIMITER")) { + return CSVState::DELIMITER; + } + if (StringUtil::Equals(value, "RECORD_SEPARATOR")) { + return CSVState::RECORD_SEPARATOR; + } + if (StringUtil::Equals(value, "CARRIAGE_RETURN")) { + return CSVState::CARRIAGE_RETURN; + } + if (StringUtil::Equals(value, "QUOTED")) { + return CSVState::QUOTED; + } + if (StringUtil::Equals(value, "UNQUOTED")) { + return CSVState::UNQUOTED; + } + if (StringUtil::Equals(value, "ESCAPE")) { + return CSVState::ESCAPE; + } + if (StringUtil::Equals(value, "INVALID")) { + return CSVState::INVALID; + } + if (StringUtil::Equals(value, "NOT_SET")) { + return CSVState::NOT_SET; + } + if (StringUtil::Equals(value, "QUOTED_NEW_LINE")) { + return CSVState::QUOTED_NEW_LINE; + } + if (StringUtil::Equals(value, "EMPTY_SPACE")) { + return CSVState::EMPTY_SPACE; + } + if (StringUtil::Equals(value, "COMMENT")) { + return CSVState::COMMENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CTEMaterialize value) { - return StringUtil::EnumToString(GetCTEMaterializeValues(), 3, "CTEMaterialize", static_cast(value)); + switch(value) { + case CTEMaterialize::CTE_MATERIALIZE_DEFAULT: + return "CTE_MATERIALIZE_DEFAULT"; + case CTEMaterialize::CTE_MATERIALIZE_ALWAYS: + return "CTE_MATERIALIZE_ALWAYS"; + case CTEMaterialize::CTE_MATERIALIZE_NEVER: + return "CTE_MATERIALIZE_NEVER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CTEMaterialize EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCTEMaterializeValues(), 3, "CTEMaterialize", value)); -} - -const StringUtil::EnumStringLiteral *GetCatalogLookupBehaviorValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CatalogLookupBehavior::STANDARD), "STANDARD" }, - { static_cast(CatalogLookupBehavior::LOWER_PRIORITY), "LOWER_PRIORITY" }, - { static_cast(CatalogLookupBehavior::NEVER_LOOKUP), "NEVER_LOOKUP" } - }; - return values; + if (StringUtil::Equals(value, "CTE_MATERIALIZE_DEFAULT")) { + return CTEMaterialize::CTE_MATERIALIZE_DEFAULT; + } + if (StringUtil::Equals(value, "CTE_MATERIALIZE_ALWAYS")) { + return CTEMaterialize::CTE_MATERIALIZE_ALWAYS; + } + if (StringUtil::Equals(value, "CTE_MATERIALIZE_NEVER")) { + return CTEMaterialize::CTE_MATERIALIZE_NEVER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CatalogLookupBehavior value) { - return StringUtil::EnumToString(GetCatalogLookupBehaviorValues(), 3, "CatalogLookupBehavior", static_cast(value)); + switch(value) { + case CatalogLookupBehavior::STANDARD: + return "STANDARD"; + case CatalogLookupBehavior::LOWER_PRIORITY: + return "LOWER_PRIORITY"; + case CatalogLookupBehavior::NEVER_LOOKUP: + return "NEVER_LOOKUP"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CatalogLookupBehavior EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCatalogLookupBehaviorValues(), 3, "CatalogLookupBehavior", value)); -} - -const StringUtil::EnumStringLiteral *GetCatalogTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CatalogType::INVALID), "INVALID" }, - { static_cast(CatalogType::TABLE_ENTRY), "TABLE_ENTRY" }, - { static_cast(CatalogType::SCHEMA_ENTRY), "SCHEMA_ENTRY" }, - { static_cast(CatalogType::VIEW_ENTRY), "VIEW_ENTRY" }, - { static_cast(CatalogType::INDEX_ENTRY), "INDEX_ENTRY" }, - { static_cast(CatalogType::PREPARED_STATEMENT), "PREPARED_STATEMENT" }, - { static_cast(CatalogType::SEQUENCE_ENTRY), "SEQUENCE_ENTRY" }, - { static_cast(CatalogType::COLLATION_ENTRY), "COLLATION_ENTRY" }, - { static_cast(CatalogType::TYPE_ENTRY), "TYPE_ENTRY" }, - { static_cast(CatalogType::DATABASE_ENTRY), "DATABASE_ENTRY" }, - { static_cast(CatalogType::TABLE_FUNCTION_ENTRY), "TABLE_FUNCTION_ENTRY" }, - { static_cast(CatalogType::SCALAR_FUNCTION_ENTRY), "SCALAR_FUNCTION_ENTRY" }, - { static_cast(CatalogType::AGGREGATE_FUNCTION_ENTRY), "AGGREGATE_FUNCTION_ENTRY" }, - { static_cast(CatalogType::PRAGMA_FUNCTION_ENTRY), "PRAGMA_FUNCTION_ENTRY" }, - { static_cast(CatalogType::COPY_FUNCTION_ENTRY), "COPY_FUNCTION_ENTRY" }, - { static_cast(CatalogType::MACRO_ENTRY), "MACRO_ENTRY" }, - { static_cast(CatalogType::TABLE_MACRO_ENTRY), "TABLE_MACRO_ENTRY" }, - { static_cast(CatalogType::DELETED_ENTRY), "DELETED_ENTRY" }, - { static_cast(CatalogType::RENAMED_ENTRY), "RENAMED_ENTRY" }, - { static_cast(CatalogType::SECRET_ENTRY), "SECRET_ENTRY" }, - { static_cast(CatalogType::SECRET_TYPE_ENTRY), "SECRET_TYPE_ENTRY" }, - { static_cast(CatalogType::SECRET_FUNCTION_ENTRY), "SECRET_FUNCTION_ENTRY" }, - { static_cast(CatalogType::DEPENDENCY_ENTRY), "DEPENDENCY_ENTRY" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD")) { + return CatalogLookupBehavior::STANDARD; + } + if (StringUtil::Equals(value, "LOWER_PRIORITY")) { + return CatalogLookupBehavior::LOWER_PRIORITY; + } + if (StringUtil::Equals(value, "NEVER_LOOKUP")) { + return CatalogLookupBehavior::NEVER_LOOKUP; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CatalogType value) { - return StringUtil::EnumToString(GetCatalogTypeValues(), 23, "CatalogType", static_cast(value)); + switch(value) { + case CatalogType::INVALID: + return "INVALID"; + case CatalogType::TABLE_ENTRY: + return "TABLE_ENTRY"; + case CatalogType::SCHEMA_ENTRY: + return "SCHEMA_ENTRY"; + case CatalogType::VIEW_ENTRY: + return "VIEW_ENTRY"; + case CatalogType::INDEX_ENTRY: + return "INDEX_ENTRY"; + case CatalogType::PREPARED_STATEMENT: + return "PREPARED_STATEMENT"; + case CatalogType::SEQUENCE_ENTRY: + return "SEQUENCE_ENTRY"; + case CatalogType::COLLATION_ENTRY: + return "COLLATION_ENTRY"; + case CatalogType::TYPE_ENTRY: + return "TYPE_ENTRY"; + case CatalogType::DATABASE_ENTRY: + return "DATABASE_ENTRY"; + case CatalogType::TABLE_FUNCTION_ENTRY: + return "TABLE_FUNCTION_ENTRY"; + case CatalogType::SCALAR_FUNCTION_ENTRY: + return "SCALAR_FUNCTION_ENTRY"; + case CatalogType::AGGREGATE_FUNCTION_ENTRY: + return "AGGREGATE_FUNCTION_ENTRY"; + case CatalogType::PRAGMA_FUNCTION_ENTRY: + return "PRAGMA_FUNCTION_ENTRY"; + case CatalogType::COPY_FUNCTION_ENTRY: + return "COPY_FUNCTION_ENTRY"; + case CatalogType::MACRO_ENTRY: + return "MACRO_ENTRY"; + case CatalogType::TABLE_MACRO_ENTRY: + return "TABLE_MACRO_ENTRY"; + case CatalogType::DELETED_ENTRY: + return "DELETED_ENTRY"; + case CatalogType::RENAMED_ENTRY: + return "RENAMED_ENTRY"; + case CatalogType::SECRET_ENTRY: + return "SECRET_ENTRY"; + case CatalogType::SECRET_TYPE_ENTRY: + return "SECRET_TYPE_ENTRY"; + case CatalogType::SECRET_FUNCTION_ENTRY: + return "SECRET_FUNCTION_ENTRY"; + case CatalogType::DEPENDENCY_ENTRY: + return "DEPENDENCY_ENTRY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CatalogType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCatalogTypeValues(), 23, "CatalogType", value)); -} - -const StringUtil::EnumStringLiteral *GetCheckpointAbortValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CheckpointAbort::NO_ABORT), "NONE" }, - { static_cast(CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE), "BEFORE_TRUNCATE" }, - { static_cast(CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER), "BEFORE_HEADER" }, - { static_cast(CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE), "AFTER_FREE_LIST_WRITE" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return CatalogType::INVALID; + } + if (StringUtil::Equals(value, "TABLE_ENTRY")) { + return CatalogType::TABLE_ENTRY; + } + if (StringUtil::Equals(value, "SCHEMA_ENTRY")) { + return CatalogType::SCHEMA_ENTRY; + } + if (StringUtil::Equals(value, "VIEW_ENTRY")) { + return CatalogType::VIEW_ENTRY; + } + if (StringUtil::Equals(value, "INDEX_ENTRY")) { + return CatalogType::INDEX_ENTRY; + } + if (StringUtil::Equals(value, "PREPARED_STATEMENT")) { + return CatalogType::PREPARED_STATEMENT; + } + if (StringUtil::Equals(value, "SEQUENCE_ENTRY")) { + return CatalogType::SEQUENCE_ENTRY; + } + if (StringUtil::Equals(value, "COLLATION_ENTRY")) { + return CatalogType::COLLATION_ENTRY; + } + if (StringUtil::Equals(value, "TYPE_ENTRY")) { + return CatalogType::TYPE_ENTRY; + } + if (StringUtil::Equals(value, "DATABASE_ENTRY")) { + return CatalogType::DATABASE_ENTRY; + } + if (StringUtil::Equals(value, "TABLE_FUNCTION_ENTRY")) { + return CatalogType::TABLE_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "SCALAR_FUNCTION_ENTRY")) { + return CatalogType::SCALAR_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "AGGREGATE_FUNCTION_ENTRY")) { + return CatalogType::AGGREGATE_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "PRAGMA_FUNCTION_ENTRY")) { + return CatalogType::PRAGMA_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "COPY_FUNCTION_ENTRY")) { + return CatalogType::COPY_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "MACRO_ENTRY")) { + return CatalogType::MACRO_ENTRY; + } + if (StringUtil::Equals(value, "TABLE_MACRO_ENTRY")) { + return CatalogType::TABLE_MACRO_ENTRY; + } + if (StringUtil::Equals(value, "DELETED_ENTRY")) { + return CatalogType::DELETED_ENTRY; + } + if (StringUtil::Equals(value, "RENAMED_ENTRY")) { + return CatalogType::RENAMED_ENTRY; + } + if (StringUtil::Equals(value, "SECRET_ENTRY")) { + return CatalogType::SECRET_ENTRY; + } + if (StringUtil::Equals(value, "SECRET_TYPE_ENTRY")) { + return CatalogType::SECRET_TYPE_ENTRY; + } + if (StringUtil::Equals(value, "SECRET_FUNCTION_ENTRY")) { + return CatalogType::SECRET_FUNCTION_ENTRY; + } + if (StringUtil::Equals(value, "DEPENDENCY_ENTRY")) { + return CatalogType::DEPENDENCY_ENTRY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CheckpointAbort value) { - return StringUtil::EnumToString(GetCheckpointAbortValues(), 4, "CheckpointAbort", static_cast(value)); + switch(value) { + case CheckpointAbort::NO_ABORT: + return "NO_ABORT"; + case CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE: + return "DEBUG_ABORT_BEFORE_TRUNCATE"; + case CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER: + return "DEBUG_ABORT_BEFORE_HEADER"; + case CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE: + return "DEBUG_ABORT_AFTER_FREE_LIST_WRITE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CheckpointAbort EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCheckpointAbortValues(), 4, "CheckpointAbort", value)); -} - -const StringUtil::EnumStringLiteral *GetChunkInfoTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ChunkInfoType::CONSTANT_INFO), "CONSTANT_INFO" }, - { static_cast(ChunkInfoType::VECTOR_INFO), "VECTOR_INFO" }, - { static_cast(ChunkInfoType::EMPTY_INFO), "EMPTY_INFO" } - }; - return values; + if (StringUtil::Equals(value, "NO_ABORT")) { + return CheckpointAbort::NO_ABORT; + } + if (StringUtil::Equals(value, "DEBUG_ABORT_BEFORE_TRUNCATE")) { + return CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE; + } + if (StringUtil::Equals(value, "DEBUG_ABORT_BEFORE_HEADER")) { + return CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER; + } + if (StringUtil::Equals(value, "DEBUG_ABORT_AFTER_FREE_LIST_WRITE")) { + return CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ChunkInfoType value) { - return StringUtil::EnumToString(GetChunkInfoTypeValues(), 3, "ChunkInfoType", static_cast(value)); + switch(value) { + case ChunkInfoType::CONSTANT_INFO: + return "CONSTANT_INFO"; + case ChunkInfoType::VECTOR_INFO: + return "VECTOR_INFO"; + case ChunkInfoType::EMPTY_INFO: + return "EMPTY_INFO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ChunkInfoType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetChunkInfoTypeValues(), 3, "ChunkInfoType", value)); -} - -const StringUtil::EnumStringLiteral *GetColumnDataAllocatorTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR), "BUFFER_MANAGER_ALLOCATOR" }, - { static_cast(ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR), "IN_MEMORY_ALLOCATOR" }, - { static_cast(ColumnDataAllocatorType::HYBRID), "HYBRID" } - }; - return values; + if (StringUtil::Equals(value, "CONSTANT_INFO")) { + return ChunkInfoType::CONSTANT_INFO; + } + if (StringUtil::Equals(value, "VECTOR_INFO")) { + return ChunkInfoType::VECTOR_INFO; + } + if (StringUtil::Equals(value, "EMPTY_INFO")) { + return ChunkInfoType::EMPTY_INFO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ColumnDataAllocatorType value) { - return StringUtil::EnumToString(GetColumnDataAllocatorTypeValues(), 3, "ColumnDataAllocatorType", static_cast(value)); + switch(value) { + case ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR: + return "BUFFER_MANAGER_ALLOCATOR"; + case ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR: + return "IN_MEMORY_ALLOCATOR"; + case ColumnDataAllocatorType::HYBRID: + return "HYBRID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ColumnDataAllocatorType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetColumnDataAllocatorTypeValues(), 3, "ColumnDataAllocatorType", value)); -} - -const StringUtil::EnumStringLiteral *GetColumnDataScanPropertiesValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ColumnDataScanProperties::INVALID), "INVALID" }, - { static_cast(ColumnDataScanProperties::ALLOW_ZERO_COPY), "ALLOW_ZERO_COPY" }, - { static_cast(ColumnDataScanProperties::DISALLOW_ZERO_COPY), "DISALLOW_ZERO_COPY" } - }; - return values; + if (StringUtil::Equals(value, "BUFFER_MANAGER_ALLOCATOR")) { + return ColumnDataAllocatorType::BUFFER_MANAGER_ALLOCATOR; + } + if (StringUtil::Equals(value, "IN_MEMORY_ALLOCATOR")) { + return ColumnDataAllocatorType::IN_MEMORY_ALLOCATOR; + } + if (StringUtil::Equals(value, "HYBRID")) { + return ColumnDataAllocatorType::HYBRID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ColumnDataScanProperties value) { - return StringUtil::EnumToString(GetColumnDataScanPropertiesValues(), 3, "ColumnDataScanProperties", static_cast(value)); + switch(value) { + case ColumnDataScanProperties::INVALID: + return "INVALID"; + case ColumnDataScanProperties::ALLOW_ZERO_COPY: + return "ALLOW_ZERO_COPY"; + case ColumnDataScanProperties::DISALLOW_ZERO_COPY: + return "DISALLOW_ZERO_COPY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ColumnDataScanProperties EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetColumnDataScanPropertiesValues(), 3, "ColumnDataScanProperties", value)); -} - -const StringUtil::EnumStringLiteral *GetColumnSegmentTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ColumnSegmentType::TRANSIENT), "TRANSIENT" }, - { static_cast(ColumnSegmentType::PERSISTENT), "PERSISTENT" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ColumnDataScanProperties::INVALID; + } + if (StringUtil::Equals(value, "ALLOW_ZERO_COPY")) { + return ColumnDataScanProperties::ALLOW_ZERO_COPY; + } + if (StringUtil::Equals(value, "DISALLOW_ZERO_COPY")) { + return ColumnDataScanProperties::DISALLOW_ZERO_COPY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ColumnSegmentType value) { - return StringUtil::EnumToString(GetColumnSegmentTypeValues(), 2, "ColumnSegmentType", static_cast(value)); + switch(value) { + case ColumnSegmentType::TRANSIENT: + return "TRANSIENT"; + case ColumnSegmentType::PERSISTENT: + return "PERSISTENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ColumnSegmentType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetColumnSegmentTypeValues(), 2, "ColumnSegmentType", value)); -} - -const StringUtil::EnumStringLiteral *GetCompressedMaterializationDirectionValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CompressedMaterializationDirection::INVALID), "INVALID" }, - { static_cast(CompressedMaterializationDirection::COMPRESS), "COMPRESS" }, - { static_cast(CompressedMaterializationDirection::DECOMPRESS), "DECOMPRESS" } - }; - return values; + if (StringUtil::Equals(value, "TRANSIENT")) { + return ColumnSegmentType::TRANSIENT; + } + if (StringUtil::Equals(value, "PERSISTENT")) { + return ColumnSegmentType::PERSISTENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CompressedMaterializationDirection value) { - return StringUtil::EnumToString(GetCompressedMaterializationDirectionValues(), 3, "CompressedMaterializationDirection", static_cast(value)); + switch(value) { + case CompressedMaterializationDirection::INVALID: + return "INVALID"; + case CompressedMaterializationDirection::COMPRESS: + return "COMPRESS"; + case CompressedMaterializationDirection::DECOMPRESS: + return "DECOMPRESS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CompressedMaterializationDirection EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCompressedMaterializationDirectionValues(), 3, "CompressedMaterializationDirection", value)); -} - -const StringUtil::EnumStringLiteral *GetCompressionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CompressionType::COMPRESSION_AUTO), "COMPRESSION_AUTO" }, - { static_cast(CompressionType::COMPRESSION_UNCOMPRESSED), "COMPRESSION_UNCOMPRESSED" }, - { static_cast(CompressionType::COMPRESSION_CONSTANT), "COMPRESSION_CONSTANT" }, - { static_cast(CompressionType::COMPRESSION_RLE), "COMPRESSION_RLE" }, - { static_cast(CompressionType::COMPRESSION_DICTIONARY), "COMPRESSION_DICTIONARY" }, - { static_cast(CompressionType::COMPRESSION_PFOR_DELTA), "COMPRESSION_PFOR_DELTA" }, - { static_cast(CompressionType::COMPRESSION_BITPACKING), "COMPRESSION_BITPACKING" }, - { static_cast(CompressionType::COMPRESSION_FSST), "COMPRESSION_FSST" }, - { static_cast(CompressionType::COMPRESSION_CHIMP), "COMPRESSION_CHIMP" }, - { static_cast(CompressionType::COMPRESSION_PATAS), "COMPRESSION_PATAS" }, - { static_cast(CompressionType::COMPRESSION_ALP), "COMPRESSION_ALP" }, - { static_cast(CompressionType::COMPRESSION_ALPRD), "COMPRESSION_ALPRD" }, - { static_cast(CompressionType::COMPRESSION_ZSTD), "COMPRESSION_ZSTD" }, - { static_cast(CompressionType::COMPRESSION_ROARING), "COMPRESSION_ROARING" }, - { static_cast(CompressionType::COMPRESSION_EMPTY), "COMPRESSION_EMPTY" }, - { static_cast(CompressionType::COMPRESSION_COUNT), "COMPRESSION_COUNT" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return CompressedMaterializationDirection::INVALID; + } + if (StringUtil::Equals(value, "COMPRESS")) { + return CompressedMaterializationDirection::COMPRESS; + } + if (StringUtil::Equals(value, "DECOMPRESS")) { + return CompressedMaterializationDirection::DECOMPRESS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CompressionType value) { - return StringUtil::EnumToString(GetCompressionTypeValues(), 16, "CompressionType", static_cast(value)); + switch(value) { + case CompressionType::COMPRESSION_AUTO: + return "COMPRESSION_AUTO"; + case CompressionType::COMPRESSION_UNCOMPRESSED: + return "COMPRESSION_UNCOMPRESSED"; + case CompressionType::COMPRESSION_CONSTANT: + return "COMPRESSION_CONSTANT"; + case CompressionType::COMPRESSION_RLE: + return "COMPRESSION_RLE"; + case CompressionType::COMPRESSION_DICTIONARY: + return "COMPRESSION_DICTIONARY"; + case CompressionType::COMPRESSION_PFOR_DELTA: + return "COMPRESSION_PFOR_DELTA"; + case CompressionType::COMPRESSION_BITPACKING: + return "COMPRESSION_BITPACKING"; + case CompressionType::COMPRESSION_FSST: + return "COMPRESSION_FSST"; + case CompressionType::COMPRESSION_CHIMP: + return "COMPRESSION_CHIMP"; + case CompressionType::COMPRESSION_PATAS: + return "COMPRESSION_PATAS"; + case CompressionType::COMPRESSION_ALP: + return "COMPRESSION_ALP"; + case CompressionType::COMPRESSION_ALPRD: + return "COMPRESSION_ALPRD"; + case CompressionType::COMPRESSION_COUNT: + return "COMPRESSION_COUNT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CompressionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCompressionTypeValues(), 16, "CompressionType", value)); -} - -const StringUtil::EnumStringLiteral *GetCompressionValidityValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CompressionValidity::REQUIRES_VALIDITY), "REQUIRES_VALIDITY" }, - { static_cast(CompressionValidity::NO_VALIDITY_REQUIRED), "NO_VALIDITY_REQUIRED" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(CompressionValidity value) { - return StringUtil::EnumToString(GetCompressionValidityValues(), 2, "CompressionValidity", static_cast(value)); -} - -template<> -CompressionValidity EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCompressionValidityValues(), 2, "CompressionValidity", value)); -} - -const StringUtil::EnumStringLiteral *GetConflictManagerModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ConflictManagerMode::SCAN), "SCAN" }, - { static_cast(ConflictManagerMode::THROW), "THROW" } - }; - return values; + if (StringUtil::Equals(value, "COMPRESSION_AUTO")) { + return CompressionType::COMPRESSION_AUTO; + } + if (StringUtil::Equals(value, "COMPRESSION_UNCOMPRESSED")) { + return CompressionType::COMPRESSION_UNCOMPRESSED; + } + if (StringUtil::Equals(value, "COMPRESSION_CONSTANT")) { + return CompressionType::COMPRESSION_CONSTANT; + } + if (StringUtil::Equals(value, "COMPRESSION_RLE")) { + return CompressionType::COMPRESSION_RLE; + } + if (StringUtil::Equals(value, "COMPRESSION_DICTIONARY")) { + return CompressionType::COMPRESSION_DICTIONARY; + } + if (StringUtil::Equals(value, "COMPRESSION_PFOR_DELTA")) { + return CompressionType::COMPRESSION_PFOR_DELTA; + } + if (StringUtil::Equals(value, "COMPRESSION_BITPACKING")) { + return CompressionType::COMPRESSION_BITPACKING; + } + if (StringUtil::Equals(value, "COMPRESSION_FSST")) { + return CompressionType::COMPRESSION_FSST; + } + if (StringUtil::Equals(value, "COMPRESSION_CHIMP")) { + return CompressionType::COMPRESSION_CHIMP; + } + if (StringUtil::Equals(value, "COMPRESSION_PATAS")) { + return CompressionType::COMPRESSION_PATAS; + } + if (StringUtil::Equals(value, "COMPRESSION_ALP")) { + return CompressionType::COMPRESSION_ALP; + } + if (StringUtil::Equals(value, "COMPRESSION_ALPRD")) { + return CompressionType::COMPRESSION_ALPRD; + } + if (StringUtil::Equals(value, "COMPRESSION_COUNT")) { + return CompressionType::COMPRESSION_COUNT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ConflictManagerMode value) { - return StringUtil::EnumToString(GetConflictManagerModeValues(), 2, "ConflictManagerMode", static_cast(value)); + switch(value) { + case ConflictManagerMode::SCAN: + return "SCAN"; + case ConflictManagerMode::THROW: + return "THROW"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ConflictManagerMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetConflictManagerModeValues(), 2, "ConflictManagerMode", value)); -} - -const StringUtil::EnumStringLiteral *GetConstraintTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ConstraintType::INVALID), "INVALID" }, - { static_cast(ConstraintType::NOT_NULL), "NOT_NULL" }, - { static_cast(ConstraintType::CHECK), "CHECK" }, - { static_cast(ConstraintType::UNIQUE), "UNIQUE" }, - { static_cast(ConstraintType::FOREIGN_KEY), "FOREIGN_KEY" } - }; - return values; + if (StringUtil::Equals(value, "SCAN")) { + return ConflictManagerMode::SCAN; + } + if (StringUtil::Equals(value, "THROW")) { + return ConflictManagerMode::THROW; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ConstraintType value) { - return StringUtil::EnumToString(GetConstraintTypeValues(), 5, "ConstraintType", static_cast(value)); + switch(value) { + case ConstraintType::INVALID: + return "INVALID"; + case ConstraintType::NOT_NULL: + return "NOT_NULL"; + case ConstraintType::CHECK: + return "CHECK"; + case ConstraintType::UNIQUE: + return "UNIQUE"; + case ConstraintType::FOREIGN_KEY: + return "FOREIGN_KEY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ConstraintType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetConstraintTypeValues(), 5, "ConstraintType", value)); -} - -const StringUtil::EnumStringLiteral *GetCopyFunctionReturnTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CopyFunctionReturnType::CHANGED_ROWS), "CHANGED_ROWS" }, - { static_cast(CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST), "CHANGED_ROWS_AND_FILE_LIST" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ConstraintType::INVALID; + } + if (StringUtil::Equals(value, "NOT_NULL")) { + return ConstraintType::NOT_NULL; + } + if (StringUtil::Equals(value, "CHECK")) { + return ConstraintType::CHECK; + } + if (StringUtil::Equals(value, "UNIQUE")) { + return ConstraintType::UNIQUE; + } + if (StringUtil::Equals(value, "FOREIGN_KEY")) { + return ConstraintType::FOREIGN_KEY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CopyFunctionReturnType value) { - return StringUtil::EnumToString(GetCopyFunctionReturnTypeValues(), 2, "CopyFunctionReturnType", static_cast(value)); + switch(value) { + case CopyFunctionReturnType::CHANGED_ROWS: + return "CHANGED_ROWS"; + case CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST: + return "CHANGED_ROWS_AND_FILE_LIST"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CopyFunctionReturnType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCopyFunctionReturnTypeValues(), 2, "CopyFunctionReturnType", value)); -} - -const StringUtil::EnumStringLiteral *GetCopyOverwriteModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CopyOverwriteMode::COPY_ERROR_ON_CONFLICT), "COPY_ERROR_ON_CONFLICT" }, - { static_cast(CopyOverwriteMode::COPY_OVERWRITE), "COPY_OVERWRITE" }, - { static_cast(CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE), "COPY_OVERWRITE_OR_IGNORE" }, - { static_cast(CopyOverwriteMode::COPY_APPEND), "COPY_APPEND" } - }; - return values; + if (StringUtil::Equals(value, "CHANGED_ROWS")) { + return CopyFunctionReturnType::CHANGED_ROWS; + } + if (StringUtil::Equals(value, "CHANGED_ROWS_AND_FILE_LIST")) { + return CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CopyOverwriteMode value) { - return StringUtil::EnumToString(GetCopyOverwriteModeValues(), 4, "CopyOverwriteMode", static_cast(value)); + switch(value) { + case CopyOverwriteMode::COPY_ERROR_ON_CONFLICT: + return "COPY_ERROR_ON_CONFLICT"; + case CopyOverwriteMode::COPY_OVERWRITE: + return "COPY_OVERWRITE"; + case CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE: + return "COPY_OVERWRITE_OR_IGNORE"; + case CopyOverwriteMode::COPY_APPEND: + return "COPY_APPEND"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CopyOverwriteMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCopyOverwriteModeValues(), 4, "CopyOverwriteMode", value)); -} - -const StringUtil::EnumStringLiteral *GetCopyToTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(CopyToType::COPY_TO_FILE), "COPY_TO_FILE" }, - { static_cast(CopyToType::EXPORT_DATABASE), "EXPORT_DATABASE" } - }; - return values; + if (StringUtil::Equals(value, "COPY_ERROR_ON_CONFLICT")) { + return CopyOverwriteMode::COPY_ERROR_ON_CONFLICT; + } + if (StringUtil::Equals(value, "COPY_OVERWRITE")) { + return CopyOverwriteMode::COPY_OVERWRITE; + } + if (StringUtil::Equals(value, "COPY_OVERWRITE_OR_IGNORE")) { + return CopyOverwriteMode::COPY_OVERWRITE_OR_IGNORE; + } + if (StringUtil::Equals(value, "COPY_APPEND")) { + return CopyOverwriteMode::COPY_APPEND; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(CopyToType value) { - return StringUtil::EnumToString(GetCopyToTypeValues(), 2, "CopyToType", static_cast(value)); + switch(value) { + case CopyToType::COPY_TO_FILE: + return "COPY_TO_FILE"; + case CopyToType::EXPORT_DATABASE: + return "EXPORT_DATABASE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> CopyToType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetCopyToTypeValues(), 2, "CopyToType", value)); -} - -const StringUtil::EnumStringLiteral *GetDataFileTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DataFileType::FILE_DOES_NOT_EXIST), "FILE_DOES_NOT_EXIST" }, - { static_cast(DataFileType::DUCKDB_FILE), "DUCKDB_FILE" }, - { static_cast(DataFileType::SQLITE_FILE), "SQLITE_FILE" }, - { static_cast(DataFileType::PARQUET_FILE), "PARQUET_FILE" } - }; - return values; + if (StringUtil::Equals(value, "COPY_TO_FILE")) { + return CopyToType::COPY_TO_FILE; + } + if (StringUtil::Equals(value, "EXPORT_DATABASE")) { + return CopyToType::EXPORT_DATABASE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DataFileType value) { - return StringUtil::EnumToString(GetDataFileTypeValues(), 4, "DataFileType", static_cast(value)); + switch(value) { + case DataFileType::FILE_DOES_NOT_EXIST: + return "FILE_DOES_NOT_EXIST"; + case DataFileType::DUCKDB_FILE: + return "DUCKDB_FILE"; + case DataFileType::SQLITE_FILE: + return "SQLITE_FILE"; + case DataFileType::PARQUET_FILE: + return "PARQUET_FILE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DataFileType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDataFileTypeValues(), 4, "DataFileType", value)); -} - -const StringUtil::EnumStringLiteral *GetDateCastResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DateCastResult::SUCCESS), "SUCCESS" }, - { static_cast(DateCastResult::ERROR_INCORRECT_FORMAT), "ERROR_INCORRECT_FORMAT" }, - { static_cast(DateCastResult::ERROR_RANGE), "ERROR_RANGE" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(DateCastResult value) { - return StringUtil::EnumToString(GetDateCastResultValues(), 3, "DateCastResult", static_cast(value)); -} - -template<> -DateCastResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDateCastResultValues(), 3, "DateCastResult", value)); -} - -const StringUtil::EnumStringLiteral *GetDatePartSpecifierValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DatePartSpecifier::YEAR), "YEAR" }, - { static_cast(DatePartSpecifier::MONTH), "MONTH" }, - { static_cast(DatePartSpecifier::DAY), "DAY" }, - { static_cast(DatePartSpecifier::DECADE), "DECADE" }, - { static_cast(DatePartSpecifier::CENTURY), "CENTURY" }, - { static_cast(DatePartSpecifier::MILLENNIUM), "MILLENNIUM" }, - { static_cast(DatePartSpecifier::MICROSECONDS), "MICROSECONDS" }, - { static_cast(DatePartSpecifier::MILLISECONDS), "MILLISECONDS" }, - { static_cast(DatePartSpecifier::SECOND), "SECOND" }, - { static_cast(DatePartSpecifier::MINUTE), "MINUTE" }, - { static_cast(DatePartSpecifier::HOUR), "HOUR" }, - { static_cast(DatePartSpecifier::DOW), "DOW" }, - { static_cast(DatePartSpecifier::ISODOW), "ISODOW" }, - { static_cast(DatePartSpecifier::WEEK), "WEEK" }, - { static_cast(DatePartSpecifier::ISOYEAR), "ISOYEAR" }, - { static_cast(DatePartSpecifier::QUARTER), "QUARTER" }, - { static_cast(DatePartSpecifier::DOY), "DOY" }, - { static_cast(DatePartSpecifier::YEARWEEK), "YEARWEEK" }, - { static_cast(DatePartSpecifier::ERA), "ERA" }, - { static_cast(DatePartSpecifier::TIMEZONE), "TIMEZONE" }, - { static_cast(DatePartSpecifier::TIMEZONE_HOUR), "TIMEZONE_HOUR" }, - { static_cast(DatePartSpecifier::TIMEZONE_MINUTE), "TIMEZONE_MINUTE" }, - { static_cast(DatePartSpecifier::EPOCH), "EPOCH" }, - { static_cast(DatePartSpecifier::JULIAN_DAY), "JULIAN_DAY" }, - { static_cast(DatePartSpecifier::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "FILE_DOES_NOT_EXIST")) { + return DataFileType::FILE_DOES_NOT_EXIST; + } + if (StringUtil::Equals(value, "DUCKDB_FILE")) { + return DataFileType::DUCKDB_FILE; + } + if (StringUtil::Equals(value, "SQLITE_FILE")) { + return DataFileType::SQLITE_FILE; + } + if (StringUtil::Equals(value, "PARQUET_FILE")) { + return DataFileType::PARQUET_FILE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DatePartSpecifier value) { - return StringUtil::EnumToString(GetDatePartSpecifierValues(), 25, "DatePartSpecifier", static_cast(value)); + switch(value) { + case DatePartSpecifier::YEAR: + return "YEAR"; + case DatePartSpecifier::MONTH: + return "MONTH"; + case DatePartSpecifier::DAY: + return "DAY"; + case DatePartSpecifier::DECADE: + return "DECADE"; + case DatePartSpecifier::CENTURY: + return "CENTURY"; + case DatePartSpecifier::MILLENNIUM: + return "MILLENNIUM"; + case DatePartSpecifier::MICROSECONDS: + return "MICROSECONDS"; + case DatePartSpecifier::MILLISECONDS: + return "MILLISECONDS"; + case DatePartSpecifier::SECOND: + return "SECOND"; + case DatePartSpecifier::MINUTE: + return "MINUTE"; + case DatePartSpecifier::HOUR: + return "HOUR"; + case DatePartSpecifier::DOW: + return "DOW"; + case DatePartSpecifier::ISODOW: + return "ISODOW"; + case DatePartSpecifier::WEEK: + return "WEEK"; + case DatePartSpecifier::ISOYEAR: + return "ISOYEAR"; + case DatePartSpecifier::QUARTER: + return "QUARTER"; + case DatePartSpecifier::DOY: + return "DOY"; + case DatePartSpecifier::YEARWEEK: + return "YEARWEEK"; + case DatePartSpecifier::ERA: + return "ERA"; + case DatePartSpecifier::TIMEZONE: + return "TIMEZONE"; + case DatePartSpecifier::TIMEZONE_HOUR: + return "TIMEZONE_HOUR"; + case DatePartSpecifier::TIMEZONE_MINUTE: + return "TIMEZONE_MINUTE"; + case DatePartSpecifier::EPOCH: + return "EPOCH"; + case DatePartSpecifier::JULIAN_DAY: + return "JULIAN_DAY"; + case DatePartSpecifier::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DatePartSpecifier EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDatePartSpecifierValues(), 25, "DatePartSpecifier", value)); -} - -const StringUtil::EnumStringLiteral *GetDebugInitializeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DebugInitialize::NO_INITIALIZE), "NO_INITIALIZE" }, - { static_cast(DebugInitialize::DEBUG_ZERO_INITIALIZE), "DEBUG_ZERO_INITIALIZE" }, - { static_cast(DebugInitialize::DEBUG_ONE_INITIALIZE), "DEBUG_ONE_INITIALIZE" } - }; - return values; + if (StringUtil::Equals(value, "YEAR")) { + return DatePartSpecifier::YEAR; + } + if (StringUtil::Equals(value, "MONTH")) { + return DatePartSpecifier::MONTH; + } + if (StringUtil::Equals(value, "DAY")) { + return DatePartSpecifier::DAY; + } + if (StringUtil::Equals(value, "DECADE")) { + return DatePartSpecifier::DECADE; + } + if (StringUtil::Equals(value, "CENTURY")) { + return DatePartSpecifier::CENTURY; + } + if (StringUtil::Equals(value, "MILLENNIUM")) { + return DatePartSpecifier::MILLENNIUM; + } + if (StringUtil::Equals(value, "MICROSECONDS")) { + return DatePartSpecifier::MICROSECONDS; + } + if (StringUtil::Equals(value, "MILLISECONDS")) { + return DatePartSpecifier::MILLISECONDS; + } + if (StringUtil::Equals(value, "SECOND")) { + return DatePartSpecifier::SECOND; + } + if (StringUtil::Equals(value, "MINUTE")) { + return DatePartSpecifier::MINUTE; + } + if (StringUtil::Equals(value, "HOUR")) { + return DatePartSpecifier::HOUR; + } + if (StringUtil::Equals(value, "DOW")) { + return DatePartSpecifier::DOW; + } + if (StringUtil::Equals(value, "ISODOW")) { + return DatePartSpecifier::ISODOW; + } + if (StringUtil::Equals(value, "WEEK")) { + return DatePartSpecifier::WEEK; + } + if (StringUtil::Equals(value, "ISOYEAR")) { + return DatePartSpecifier::ISOYEAR; + } + if (StringUtil::Equals(value, "QUARTER")) { + return DatePartSpecifier::QUARTER; + } + if (StringUtil::Equals(value, "DOY")) { + return DatePartSpecifier::DOY; + } + if (StringUtil::Equals(value, "YEARWEEK")) { + return DatePartSpecifier::YEARWEEK; + } + if (StringUtil::Equals(value, "ERA")) { + return DatePartSpecifier::ERA; + } + if (StringUtil::Equals(value, "TIMEZONE")) { + return DatePartSpecifier::TIMEZONE; + } + if (StringUtil::Equals(value, "TIMEZONE_HOUR")) { + return DatePartSpecifier::TIMEZONE_HOUR; + } + if (StringUtil::Equals(value, "TIMEZONE_MINUTE")) { + return DatePartSpecifier::TIMEZONE_MINUTE; + } + if (StringUtil::Equals(value, "EPOCH")) { + return DatePartSpecifier::EPOCH; + } + if (StringUtil::Equals(value, "JULIAN_DAY")) { + return DatePartSpecifier::JULIAN_DAY; + } + if (StringUtil::Equals(value, "INVALID")) { + return DatePartSpecifier::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DebugInitialize value) { - return StringUtil::EnumToString(GetDebugInitializeValues(), 3, "DebugInitialize", static_cast(value)); + switch(value) { + case DebugInitialize::NO_INITIALIZE: + return "NO_INITIALIZE"; + case DebugInitialize::DEBUG_ZERO_INITIALIZE: + return "DEBUG_ZERO_INITIALIZE"; + case DebugInitialize::DEBUG_ONE_INITIALIZE: + return "DEBUG_ONE_INITIALIZE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DebugInitialize EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDebugInitializeValues(), 3, "DebugInitialize", value)); -} - -const StringUtil::EnumStringLiteral *GetDefaultOrderByNullTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DefaultOrderByNullType::INVALID), "INVALID" }, - { static_cast(DefaultOrderByNullType::NULLS_FIRST), "NULLS_FIRST" }, - { static_cast(DefaultOrderByNullType::NULLS_LAST), "NULLS_LAST" }, - { static_cast(DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC), "NULLS_FIRST_ON_ASC_LAST_ON_DESC" }, - { static_cast(DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC), "NULLS_LAST_ON_ASC_FIRST_ON_DESC" } - }; - return values; + if (StringUtil::Equals(value, "NO_INITIALIZE")) { + return DebugInitialize::NO_INITIALIZE; + } + if (StringUtil::Equals(value, "DEBUG_ZERO_INITIALIZE")) { + return DebugInitialize::DEBUG_ZERO_INITIALIZE; + } + if (StringUtil::Equals(value, "DEBUG_ONE_INITIALIZE")) { + return DebugInitialize::DEBUG_ONE_INITIALIZE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DefaultOrderByNullType value) { - return StringUtil::EnumToString(GetDefaultOrderByNullTypeValues(), 5, "DefaultOrderByNullType", static_cast(value)); + switch(value) { + case DefaultOrderByNullType::INVALID: + return "INVALID"; + case DefaultOrderByNullType::NULLS_FIRST: + return "NULLS_FIRST"; + case DefaultOrderByNullType::NULLS_LAST: + return "NULLS_LAST"; + case DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC: + return "NULLS_FIRST_ON_ASC_LAST_ON_DESC"; + case DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC: + return "NULLS_LAST_ON_ASC_FIRST_ON_DESC"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DefaultOrderByNullType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDefaultOrderByNullTypeValues(), 5, "DefaultOrderByNullType", value)); -} - -const StringUtil::EnumStringLiteral *GetDependencyEntryTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DependencyEntryType::SUBJECT), "SUBJECT" }, - { static_cast(DependencyEntryType::DEPENDENT), "DEPENDENT" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return DefaultOrderByNullType::INVALID; + } + if (StringUtil::Equals(value, "NULLS_FIRST")) { + return DefaultOrderByNullType::NULLS_FIRST; + } + if (StringUtil::Equals(value, "NULLS_LAST")) { + return DefaultOrderByNullType::NULLS_LAST; + } + if (StringUtil::Equals(value, "NULLS_FIRST_ON_ASC_LAST_ON_DESC")) { + return DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; + } + if (StringUtil::Equals(value, "NULLS_LAST_ON_ASC_FIRST_ON_DESC")) { + return DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DependencyEntryType value) { - return StringUtil::EnumToString(GetDependencyEntryTypeValues(), 2, "DependencyEntryType", static_cast(value)); + switch(value) { + case DependencyEntryType::SUBJECT: + return "SUBJECT"; + case DependencyEntryType::DEPENDENT: + return "DEPENDENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DependencyEntryType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDependencyEntryTypeValues(), 2, "DependencyEntryType", value)); -} - -const StringUtil::EnumStringLiteral *GetDeprecatedIndexTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DeprecatedIndexType::INVALID), "INVALID" }, - { static_cast(DeprecatedIndexType::ART), "ART" }, - { static_cast(DeprecatedIndexType::EXTENSION), "EXTENSION" } - }; - return values; + if (StringUtil::Equals(value, "SUBJECT")) { + return DependencyEntryType::SUBJECT; + } + if (StringUtil::Equals(value, "DEPENDENT")) { + return DependencyEntryType::DEPENDENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DeprecatedIndexType value) { - return StringUtil::EnumToString(GetDeprecatedIndexTypeValues(), 3, "DeprecatedIndexType", static_cast(value)); + switch(value) { + case DeprecatedIndexType::INVALID: + return "INVALID"; + case DeprecatedIndexType::ART: + return "ART"; + case DeprecatedIndexType::EXTENSION: + return "EXTENSION"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DeprecatedIndexType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDeprecatedIndexTypeValues(), 3, "DeprecatedIndexType", value)); -} - -const StringUtil::EnumStringLiteral *GetDestroyBufferUponValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DestroyBufferUpon::BLOCK), "BLOCK" }, - { static_cast(DestroyBufferUpon::EVICTION), "EVICTION" }, - { static_cast(DestroyBufferUpon::UNPIN), "UNPIN" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return DeprecatedIndexType::INVALID; + } + if (StringUtil::Equals(value, "ART")) { + return DeprecatedIndexType::ART; + } + if (StringUtil::Equals(value, "EXTENSION")) { + return DeprecatedIndexType::EXTENSION; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DestroyBufferUpon value) { - return StringUtil::EnumToString(GetDestroyBufferUponValues(), 3, "DestroyBufferUpon", static_cast(value)); + switch(value) { + case DestroyBufferUpon::BLOCK: + return "BLOCK"; + case DestroyBufferUpon::EVICTION: + return "EVICTION"; + case DestroyBufferUpon::UNPIN: + return "UNPIN"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DestroyBufferUpon EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDestroyBufferUponValues(), 3, "DestroyBufferUpon", value)); -} - -const StringUtil::EnumStringLiteral *GetDistinctTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(DistinctType::DISTINCT), "DISTINCT" }, - { static_cast(DistinctType::DISTINCT_ON), "DISTINCT_ON" } - }; - return values; + if (StringUtil::Equals(value, "BLOCK")) { + return DestroyBufferUpon::BLOCK; + } + if (StringUtil::Equals(value, "EVICTION")) { + return DestroyBufferUpon::EVICTION; + } + if (StringUtil::Equals(value, "UNPIN")) { + return DestroyBufferUpon::UNPIN; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(DistinctType value) { - return StringUtil::EnumToString(GetDistinctTypeValues(), 2, "DistinctType", static_cast(value)); + switch(value) { + case DistinctType::DISTINCT: + return "DISTINCT"; + case DistinctType::DISTINCT_ON: + return "DISTINCT_ON"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> DistinctType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetDistinctTypeValues(), 2, "DistinctType", value)); -} - -const StringUtil::EnumStringLiteral *GetErrorTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ErrorType::UNSIGNED_EXTENSION), "UNSIGNED_EXTENSION" }, - { static_cast(ErrorType::INVALIDATED_TRANSACTION), "INVALIDATED_TRANSACTION" }, - { static_cast(ErrorType::INVALIDATED_DATABASE), "INVALIDATED_DATABASE" }, - { static_cast(ErrorType::ERROR_COUNT), "ERROR_COUNT" }, - { static_cast(ErrorType::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "DISTINCT")) { + return DistinctType::DISTINCT; + } + if (StringUtil::Equals(value, "DISTINCT_ON")) { + return DistinctType::DISTINCT_ON; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ErrorType value) { - return StringUtil::EnumToString(GetErrorTypeValues(), 5, "ErrorType", static_cast(value)); + switch(value) { + case ErrorType::UNSIGNED_EXTENSION: + return "UNSIGNED_EXTENSION"; + case ErrorType::INVALIDATED_TRANSACTION: + return "INVALIDATED_TRANSACTION"; + case ErrorType::INVALIDATED_DATABASE: + return "INVALIDATED_DATABASE"; + case ErrorType::ERROR_COUNT: + return "ERROR_COUNT"; + case ErrorType::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ErrorType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetErrorTypeValues(), 5, "ErrorType", value)); -} - -const StringUtil::EnumStringLiteral *GetExceptionFormatValueTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE), "FORMAT_VALUE_TYPE_DOUBLE" }, - { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER), "FORMAT_VALUE_TYPE_INTEGER" }, - { static_cast(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), "FORMAT_VALUE_TYPE_STRING" } - }; - return values; + if (StringUtil::Equals(value, "UNSIGNED_EXTENSION")) { + return ErrorType::UNSIGNED_EXTENSION; + } + if (StringUtil::Equals(value, "INVALIDATED_TRANSACTION")) { + return ErrorType::INVALIDATED_TRANSACTION; + } + if (StringUtil::Equals(value, "INVALIDATED_DATABASE")) { + return ErrorType::INVALIDATED_DATABASE; + } + if (StringUtil::Equals(value, "ERROR_COUNT")) { + return ErrorType::ERROR_COUNT; + } + if (StringUtil::Equals(value, "INVALID")) { + return ErrorType::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExceptionFormatValueType value) { - return StringUtil::EnumToString(GetExceptionFormatValueTypeValues(), 3, "ExceptionFormatValueType", static_cast(value)); + switch(value) { + case ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE: + return "FORMAT_VALUE_TYPE_DOUBLE"; + case ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER: + return "FORMAT_VALUE_TYPE_INTEGER"; + case ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING: + return "FORMAT_VALUE_TYPE_STRING"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExceptionFormatValueType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExceptionFormatValueTypeValues(), 3, "ExceptionFormatValueType", value)); -} - -const StringUtil::EnumStringLiteral *GetExceptionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExceptionType::INVALID), "INVALID" }, - { static_cast(ExceptionType::OUT_OF_RANGE), "OUT_OF_RANGE" }, - { static_cast(ExceptionType::CONVERSION), "CONVERSION" }, - { static_cast(ExceptionType::UNKNOWN_TYPE), "UNKNOWN_TYPE" }, - { static_cast(ExceptionType::DECIMAL), "DECIMAL" }, - { static_cast(ExceptionType::MISMATCH_TYPE), "MISMATCH_TYPE" }, - { static_cast(ExceptionType::DIVIDE_BY_ZERO), "DIVIDE_BY_ZERO" }, - { static_cast(ExceptionType::OBJECT_SIZE), "OBJECT_SIZE" }, - { static_cast(ExceptionType::INVALID_TYPE), "INVALID_TYPE" }, - { static_cast(ExceptionType::SERIALIZATION), "SERIALIZATION" }, - { static_cast(ExceptionType::TRANSACTION), "TRANSACTION" }, - { static_cast(ExceptionType::NOT_IMPLEMENTED), "NOT_IMPLEMENTED" }, - { static_cast(ExceptionType::EXPRESSION), "EXPRESSION" }, - { static_cast(ExceptionType::CATALOG), "CATALOG" }, - { static_cast(ExceptionType::PARSER), "PARSER" }, - { static_cast(ExceptionType::PLANNER), "PLANNER" }, - { static_cast(ExceptionType::SCHEDULER), "SCHEDULER" }, - { static_cast(ExceptionType::EXECUTOR), "EXECUTOR" }, - { static_cast(ExceptionType::CONSTRAINT), "CONSTRAINT" }, - { static_cast(ExceptionType::INDEX), "INDEX" }, - { static_cast(ExceptionType::STAT), "STAT" }, - { static_cast(ExceptionType::CONNECTION), "CONNECTION" }, - { static_cast(ExceptionType::SYNTAX), "SYNTAX" }, - { static_cast(ExceptionType::SETTINGS), "SETTINGS" }, - { static_cast(ExceptionType::BINDER), "BINDER" }, - { static_cast(ExceptionType::NETWORK), "NETWORK" }, - { static_cast(ExceptionType::OPTIMIZER), "OPTIMIZER" }, - { static_cast(ExceptionType::NULL_POINTER), "NULL_POINTER" }, - { static_cast(ExceptionType::IO), "IO" }, - { static_cast(ExceptionType::INTERRUPT), "INTERRUPT" }, - { static_cast(ExceptionType::FATAL), "FATAL" }, - { static_cast(ExceptionType::INTERNAL), "INTERNAL" }, - { static_cast(ExceptionType::INVALID_INPUT), "INVALID_INPUT" }, - { static_cast(ExceptionType::OUT_OF_MEMORY), "OUT_OF_MEMORY" }, - { static_cast(ExceptionType::PERMISSION), "PERMISSION" }, - { static_cast(ExceptionType::PARAMETER_NOT_RESOLVED), "PARAMETER_NOT_RESOLVED" }, - { static_cast(ExceptionType::PARAMETER_NOT_ALLOWED), "PARAMETER_NOT_ALLOWED" }, - { static_cast(ExceptionType::DEPENDENCY), "DEPENDENCY" }, - { static_cast(ExceptionType::HTTP), "HTTP" }, - { static_cast(ExceptionType::MISSING_EXTENSION), "MISSING_EXTENSION" }, - { static_cast(ExceptionType::AUTOLOAD), "AUTOLOAD" }, - { static_cast(ExceptionType::SEQUENCE), "SEQUENCE" }, - { static_cast(ExceptionType::INVALID_CONFIGURATION), "INVALID_CONFIGURATION" } - }; - return values; + if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_DOUBLE")) { + return ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE; + } + if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_INTEGER")) { + return ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER; + } + if (StringUtil::Equals(value, "FORMAT_VALUE_TYPE_STRING")) { + return ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExceptionType value) { - return StringUtil::EnumToString(GetExceptionTypeValues(), 43, "ExceptionType", static_cast(value)); + switch(value) { + case ExceptionType::INVALID: + return "INVALID"; + case ExceptionType::OUT_OF_RANGE: + return "OUT_OF_RANGE"; + case ExceptionType::CONVERSION: + return "CONVERSION"; + case ExceptionType::UNKNOWN_TYPE: + return "UNKNOWN_TYPE"; + case ExceptionType::DECIMAL: + return "DECIMAL"; + case ExceptionType::MISMATCH_TYPE: + return "MISMATCH_TYPE"; + case ExceptionType::DIVIDE_BY_ZERO: + return "DIVIDE_BY_ZERO"; + case ExceptionType::OBJECT_SIZE: + return "OBJECT_SIZE"; + case ExceptionType::INVALID_TYPE: + return "INVALID_TYPE"; + case ExceptionType::SERIALIZATION: + return "SERIALIZATION"; + case ExceptionType::TRANSACTION: + return "TRANSACTION"; + case ExceptionType::NOT_IMPLEMENTED: + return "NOT_IMPLEMENTED"; + case ExceptionType::EXPRESSION: + return "EXPRESSION"; + case ExceptionType::CATALOG: + return "CATALOG"; + case ExceptionType::PARSER: + return "PARSER"; + case ExceptionType::PLANNER: + return "PLANNER"; + case ExceptionType::SCHEDULER: + return "SCHEDULER"; + case ExceptionType::EXECUTOR: + return "EXECUTOR"; + case ExceptionType::CONSTRAINT: + return "CONSTRAINT"; + case ExceptionType::INDEX: + return "INDEX"; + case ExceptionType::STAT: + return "STAT"; + case ExceptionType::CONNECTION: + return "CONNECTION"; + case ExceptionType::SYNTAX: + return "SYNTAX"; + case ExceptionType::SETTINGS: + return "SETTINGS"; + case ExceptionType::BINDER: + return "BINDER"; + case ExceptionType::NETWORK: + return "NETWORK"; + case ExceptionType::OPTIMIZER: + return "OPTIMIZER"; + case ExceptionType::NULL_POINTER: + return "NULL_POINTER"; + case ExceptionType::IO: + return "IO"; + case ExceptionType::INTERRUPT: + return "INTERRUPT"; + case ExceptionType::FATAL: + return "FATAL"; + case ExceptionType::INTERNAL: + return "INTERNAL"; + case ExceptionType::INVALID_INPUT: + return "INVALID_INPUT"; + case ExceptionType::OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case ExceptionType::PERMISSION: + return "PERMISSION"; + case ExceptionType::PARAMETER_NOT_RESOLVED: + return "PARAMETER_NOT_RESOLVED"; + case ExceptionType::PARAMETER_NOT_ALLOWED: + return "PARAMETER_NOT_ALLOWED"; + case ExceptionType::DEPENDENCY: + return "DEPENDENCY"; + case ExceptionType::HTTP: + return "HTTP"; + case ExceptionType::MISSING_EXTENSION: + return "MISSING_EXTENSION"; + case ExceptionType::AUTOLOAD: + return "AUTOLOAD"; + case ExceptionType::SEQUENCE: + return "SEQUENCE"; + case ExceptionType::INVALID_CONFIGURATION: + return "INVALID_CONFIGURATION"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExceptionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExceptionTypeValues(), 43, "ExceptionType", value)); -} - -const StringUtil::EnumStringLiteral *GetExplainFormatValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExplainFormat::DEFAULT), "DEFAULT" }, - { static_cast(ExplainFormat::TEXT), "TEXT" }, - { static_cast(ExplainFormat::JSON), "JSON" }, - { static_cast(ExplainFormat::HTML), "HTML" }, - { static_cast(ExplainFormat::GRAPHVIZ), "GRAPHVIZ" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ExceptionType::INVALID; + } + if (StringUtil::Equals(value, "OUT_OF_RANGE")) { + return ExceptionType::OUT_OF_RANGE; + } + if (StringUtil::Equals(value, "CONVERSION")) { + return ExceptionType::CONVERSION; + } + if (StringUtil::Equals(value, "UNKNOWN_TYPE")) { + return ExceptionType::UNKNOWN_TYPE; + } + if (StringUtil::Equals(value, "DECIMAL")) { + return ExceptionType::DECIMAL; + } + if (StringUtil::Equals(value, "MISMATCH_TYPE")) { + return ExceptionType::MISMATCH_TYPE; + } + if (StringUtil::Equals(value, "DIVIDE_BY_ZERO")) { + return ExceptionType::DIVIDE_BY_ZERO; + } + if (StringUtil::Equals(value, "OBJECT_SIZE")) { + return ExceptionType::OBJECT_SIZE; + } + if (StringUtil::Equals(value, "INVALID_TYPE")) { + return ExceptionType::INVALID_TYPE; + } + if (StringUtil::Equals(value, "SERIALIZATION")) { + return ExceptionType::SERIALIZATION; + } + if (StringUtil::Equals(value, "TRANSACTION")) { + return ExceptionType::TRANSACTION; + } + if (StringUtil::Equals(value, "NOT_IMPLEMENTED")) { + return ExceptionType::NOT_IMPLEMENTED; + } + if (StringUtil::Equals(value, "EXPRESSION")) { + return ExceptionType::EXPRESSION; + } + if (StringUtil::Equals(value, "CATALOG")) { + return ExceptionType::CATALOG; + } + if (StringUtil::Equals(value, "PARSER")) { + return ExceptionType::PARSER; + } + if (StringUtil::Equals(value, "PLANNER")) { + return ExceptionType::PLANNER; + } + if (StringUtil::Equals(value, "SCHEDULER")) { + return ExceptionType::SCHEDULER; + } + if (StringUtil::Equals(value, "EXECUTOR")) { + return ExceptionType::EXECUTOR; + } + if (StringUtil::Equals(value, "CONSTRAINT")) { + return ExceptionType::CONSTRAINT; + } + if (StringUtil::Equals(value, "INDEX")) { + return ExceptionType::INDEX; + } + if (StringUtil::Equals(value, "STAT")) { + return ExceptionType::STAT; + } + if (StringUtil::Equals(value, "CONNECTION")) { + return ExceptionType::CONNECTION; + } + if (StringUtil::Equals(value, "SYNTAX")) { + return ExceptionType::SYNTAX; + } + if (StringUtil::Equals(value, "SETTINGS")) { + return ExceptionType::SETTINGS; + } + if (StringUtil::Equals(value, "BINDER")) { + return ExceptionType::BINDER; + } + if (StringUtil::Equals(value, "NETWORK")) { + return ExceptionType::NETWORK; + } + if (StringUtil::Equals(value, "OPTIMIZER")) { + return ExceptionType::OPTIMIZER; + } + if (StringUtil::Equals(value, "NULL_POINTER")) { + return ExceptionType::NULL_POINTER; + } + if (StringUtil::Equals(value, "IO")) { + return ExceptionType::IO; + } + if (StringUtil::Equals(value, "INTERRUPT")) { + return ExceptionType::INTERRUPT; + } + if (StringUtil::Equals(value, "FATAL")) { + return ExceptionType::FATAL; + } + if (StringUtil::Equals(value, "INTERNAL")) { + return ExceptionType::INTERNAL; + } + if (StringUtil::Equals(value, "INVALID_INPUT")) { + return ExceptionType::INVALID_INPUT; + } + if (StringUtil::Equals(value, "OUT_OF_MEMORY")) { + return ExceptionType::OUT_OF_MEMORY; + } + if (StringUtil::Equals(value, "PERMISSION")) { + return ExceptionType::PERMISSION; + } + if (StringUtil::Equals(value, "PARAMETER_NOT_RESOLVED")) { + return ExceptionType::PARAMETER_NOT_RESOLVED; + } + if (StringUtil::Equals(value, "PARAMETER_NOT_ALLOWED")) { + return ExceptionType::PARAMETER_NOT_ALLOWED; + } + if (StringUtil::Equals(value, "DEPENDENCY")) { + return ExceptionType::DEPENDENCY; + } + if (StringUtil::Equals(value, "HTTP")) { + return ExceptionType::HTTP; + } + if (StringUtil::Equals(value, "MISSING_EXTENSION")) { + return ExceptionType::MISSING_EXTENSION; + } + if (StringUtil::Equals(value, "AUTOLOAD")) { + return ExceptionType::AUTOLOAD; + } + if (StringUtil::Equals(value, "SEQUENCE")) { + return ExceptionType::SEQUENCE; + } + if (StringUtil::Equals(value, "INVALID_CONFIGURATION")) { + return ExceptionType::INVALID_CONFIGURATION; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExplainFormat value) { - return StringUtil::EnumToString(GetExplainFormatValues(), 5, "ExplainFormat", static_cast(value)); + switch(value) { + case ExplainFormat::DEFAULT: + return "DEFAULT"; + case ExplainFormat::TEXT: + return "TEXT"; + case ExplainFormat::JSON: + return "JSON"; + case ExplainFormat::HTML: + return "HTML"; + case ExplainFormat::GRAPHVIZ: + return "GRAPHVIZ"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExplainFormat EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExplainFormatValues(), 5, "ExplainFormat", value)); -} - -const StringUtil::EnumStringLiteral *GetExplainOutputTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExplainOutputType::ALL), "ALL" }, - { static_cast(ExplainOutputType::OPTIMIZED_ONLY), "OPTIMIZED_ONLY" }, - { static_cast(ExplainOutputType::PHYSICAL_ONLY), "PHYSICAL_ONLY" } - }; - return values; + if (StringUtil::Equals(value, "DEFAULT")) { + return ExplainFormat::DEFAULT; + } + if (StringUtil::Equals(value, "TEXT")) { + return ExplainFormat::TEXT; + } + if (StringUtil::Equals(value, "JSON")) { + return ExplainFormat::JSON; + } + if (StringUtil::Equals(value, "HTML")) { + return ExplainFormat::HTML; + } + if (StringUtil::Equals(value, "GRAPHVIZ")) { + return ExplainFormat::GRAPHVIZ; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExplainOutputType value) { - return StringUtil::EnumToString(GetExplainOutputTypeValues(), 3, "ExplainOutputType", static_cast(value)); + switch(value) { + case ExplainOutputType::ALL: + return "ALL"; + case ExplainOutputType::OPTIMIZED_ONLY: + return "OPTIMIZED_ONLY"; + case ExplainOutputType::PHYSICAL_ONLY: + return "PHYSICAL_ONLY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExplainOutputType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExplainOutputTypeValues(), 3, "ExplainOutputType", value)); -} - -const StringUtil::EnumStringLiteral *GetExplainTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExplainType::EXPLAIN_STANDARD), "EXPLAIN_STANDARD" }, - { static_cast(ExplainType::EXPLAIN_ANALYZE), "EXPLAIN_ANALYZE" } - }; - return values; + if (StringUtil::Equals(value, "ALL")) { + return ExplainOutputType::ALL; + } + if (StringUtil::Equals(value, "OPTIMIZED_ONLY")) { + return ExplainOutputType::OPTIMIZED_ONLY; + } + if (StringUtil::Equals(value, "PHYSICAL_ONLY")) { + return ExplainOutputType::PHYSICAL_ONLY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExplainType value) { - return StringUtil::EnumToString(GetExplainTypeValues(), 2, "ExplainType", static_cast(value)); + switch(value) { + case ExplainType::EXPLAIN_STANDARD: + return "EXPLAIN_STANDARD"; + case ExplainType::EXPLAIN_ANALYZE: + return "EXPLAIN_ANALYZE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExplainType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExplainTypeValues(), 2, "ExplainType", value)); -} - -const StringUtil::EnumStringLiteral *GetExponentTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExponentType::NONE), "NONE" }, - { static_cast(ExponentType::POSITIVE), "POSITIVE" }, - { static_cast(ExponentType::NEGATIVE), "NEGATIVE" } - }; - return values; + if (StringUtil::Equals(value, "EXPLAIN_STANDARD")) { + return ExplainType::EXPLAIN_STANDARD; + } + if (StringUtil::Equals(value, "EXPLAIN_ANALYZE")) { + return ExplainType::EXPLAIN_ANALYZE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExponentType value) { - return StringUtil::EnumToString(GetExponentTypeValues(), 3, "ExponentType", static_cast(value)); + switch(value) { + case ExponentType::NONE: + return "NONE"; + case ExponentType::POSITIVE: + return "POSITIVE"; + case ExponentType::NEGATIVE: + return "NEGATIVE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExponentType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExponentTypeValues(), 3, "ExponentType", value)); -} - -const StringUtil::EnumStringLiteral *GetExpressionClassValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExpressionClass::INVALID), "INVALID" }, - { static_cast(ExpressionClass::AGGREGATE), "AGGREGATE" }, - { static_cast(ExpressionClass::CASE), "CASE" }, - { static_cast(ExpressionClass::CAST), "CAST" }, - { static_cast(ExpressionClass::COLUMN_REF), "COLUMN_REF" }, - { static_cast(ExpressionClass::COMPARISON), "COMPARISON" }, - { static_cast(ExpressionClass::CONJUNCTION), "CONJUNCTION" }, - { static_cast(ExpressionClass::CONSTANT), "CONSTANT" }, - { static_cast(ExpressionClass::DEFAULT), "DEFAULT" }, - { static_cast(ExpressionClass::FUNCTION), "FUNCTION" }, - { static_cast(ExpressionClass::OPERATOR), "OPERATOR" }, - { static_cast(ExpressionClass::STAR), "STAR" }, - { static_cast(ExpressionClass::SUBQUERY), "SUBQUERY" }, - { static_cast(ExpressionClass::WINDOW), "WINDOW" }, - { static_cast(ExpressionClass::PARAMETER), "PARAMETER" }, - { static_cast(ExpressionClass::COLLATE), "COLLATE" }, - { static_cast(ExpressionClass::LAMBDA), "LAMBDA" }, - { static_cast(ExpressionClass::POSITIONAL_REFERENCE), "POSITIONAL_REFERENCE" }, - { static_cast(ExpressionClass::BETWEEN), "BETWEEN" }, - { static_cast(ExpressionClass::LAMBDA_REF), "LAMBDA_REF" }, - { static_cast(ExpressionClass::BOUND_AGGREGATE), "BOUND_AGGREGATE" }, - { static_cast(ExpressionClass::BOUND_CASE), "BOUND_CASE" }, - { static_cast(ExpressionClass::BOUND_CAST), "BOUND_CAST" }, - { static_cast(ExpressionClass::BOUND_COLUMN_REF), "BOUND_COLUMN_REF" }, - { static_cast(ExpressionClass::BOUND_COMPARISON), "BOUND_COMPARISON" }, - { static_cast(ExpressionClass::BOUND_CONJUNCTION), "BOUND_CONJUNCTION" }, - { static_cast(ExpressionClass::BOUND_CONSTANT), "BOUND_CONSTANT" }, - { static_cast(ExpressionClass::BOUND_DEFAULT), "BOUND_DEFAULT" }, - { static_cast(ExpressionClass::BOUND_FUNCTION), "BOUND_FUNCTION" }, - { static_cast(ExpressionClass::BOUND_OPERATOR), "BOUND_OPERATOR" }, - { static_cast(ExpressionClass::BOUND_PARAMETER), "BOUND_PARAMETER" }, - { static_cast(ExpressionClass::BOUND_REF), "BOUND_REF" }, - { static_cast(ExpressionClass::BOUND_SUBQUERY), "BOUND_SUBQUERY" }, - { static_cast(ExpressionClass::BOUND_WINDOW), "BOUND_WINDOW" }, - { static_cast(ExpressionClass::BOUND_BETWEEN), "BOUND_BETWEEN" }, - { static_cast(ExpressionClass::BOUND_UNNEST), "BOUND_UNNEST" }, - { static_cast(ExpressionClass::BOUND_LAMBDA), "BOUND_LAMBDA" }, - { static_cast(ExpressionClass::BOUND_LAMBDA_REF), "BOUND_LAMBDA_REF" }, - { static_cast(ExpressionClass::BOUND_EXPRESSION), "BOUND_EXPRESSION" }, - { static_cast(ExpressionClass::BOUND_EXPANDED), "BOUND_EXPANDED" } - }; - return values; + if (StringUtil::Equals(value, "NONE")) { + return ExponentType::NONE; + } + if (StringUtil::Equals(value, "POSITIVE")) { + return ExponentType::POSITIVE; + } + if (StringUtil::Equals(value, "NEGATIVE")) { + return ExponentType::NEGATIVE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExpressionClass value) { - return StringUtil::EnumToString(GetExpressionClassValues(), 40, "ExpressionClass", static_cast(value)); + switch(value) { + case ExpressionClass::INVALID: + return "INVALID"; + case ExpressionClass::AGGREGATE: + return "AGGREGATE"; + case ExpressionClass::CASE: + return "CASE"; + case ExpressionClass::CAST: + return "CAST"; + case ExpressionClass::COLUMN_REF: + return "COLUMN_REF"; + case ExpressionClass::COMPARISON: + return "COMPARISON"; + case ExpressionClass::CONJUNCTION: + return "CONJUNCTION"; + case ExpressionClass::CONSTANT: + return "CONSTANT"; + case ExpressionClass::DEFAULT: + return "DEFAULT"; + case ExpressionClass::FUNCTION: + return "FUNCTION"; + case ExpressionClass::OPERATOR: + return "OPERATOR"; + case ExpressionClass::STAR: + return "STAR"; + case ExpressionClass::SUBQUERY: + return "SUBQUERY"; + case ExpressionClass::WINDOW: + return "WINDOW"; + case ExpressionClass::PARAMETER: + return "PARAMETER"; + case ExpressionClass::COLLATE: + return "COLLATE"; + case ExpressionClass::LAMBDA: + return "LAMBDA"; + case ExpressionClass::POSITIONAL_REFERENCE: + return "POSITIONAL_REFERENCE"; + case ExpressionClass::BETWEEN: + return "BETWEEN"; + case ExpressionClass::LAMBDA_REF: + return "LAMBDA_REF"; + case ExpressionClass::BOUND_AGGREGATE: + return "BOUND_AGGREGATE"; + case ExpressionClass::BOUND_CASE: + return "BOUND_CASE"; + case ExpressionClass::BOUND_CAST: + return "BOUND_CAST"; + case ExpressionClass::BOUND_COLUMN_REF: + return "BOUND_COLUMN_REF"; + case ExpressionClass::BOUND_COMPARISON: + return "BOUND_COMPARISON"; + case ExpressionClass::BOUND_CONJUNCTION: + return "BOUND_CONJUNCTION"; + case ExpressionClass::BOUND_CONSTANT: + return "BOUND_CONSTANT"; + case ExpressionClass::BOUND_DEFAULT: + return "BOUND_DEFAULT"; + case ExpressionClass::BOUND_FUNCTION: + return "BOUND_FUNCTION"; + case ExpressionClass::BOUND_OPERATOR: + return "BOUND_OPERATOR"; + case ExpressionClass::BOUND_PARAMETER: + return "BOUND_PARAMETER"; + case ExpressionClass::BOUND_REF: + return "BOUND_REF"; + case ExpressionClass::BOUND_SUBQUERY: + return "BOUND_SUBQUERY"; + case ExpressionClass::BOUND_WINDOW: + return "BOUND_WINDOW"; + case ExpressionClass::BOUND_BETWEEN: + return "BOUND_BETWEEN"; + case ExpressionClass::BOUND_UNNEST: + return "BOUND_UNNEST"; + case ExpressionClass::BOUND_LAMBDA: + return "BOUND_LAMBDA"; + case ExpressionClass::BOUND_LAMBDA_REF: + return "BOUND_LAMBDA_REF"; + case ExpressionClass::BOUND_EXPRESSION: + return "BOUND_EXPRESSION"; + case ExpressionClass::BOUND_EXPANDED: + return "BOUND_EXPANDED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExpressionClass EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExpressionClassValues(), 40, "ExpressionClass", value)); -} - -const StringUtil::EnumStringLiteral *GetExpressionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExpressionType::INVALID), "INVALID" }, - { static_cast(ExpressionType::OPERATOR_CAST), "OPERATOR_CAST" }, - { static_cast(ExpressionType::OPERATOR_NOT), "OPERATOR_NOT" }, - { static_cast(ExpressionType::OPERATOR_IS_NULL), "OPERATOR_IS_NULL" }, - { static_cast(ExpressionType::OPERATOR_IS_NOT_NULL), "OPERATOR_IS_NOT_NULL" }, - { static_cast(ExpressionType::COMPARE_EQUAL), "COMPARE_EQUAL" }, - { static_cast(ExpressionType::COMPARE_NOTEQUAL), "COMPARE_NOTEQUAL" }, - { static_cast(ExpressionType::COMPARE_LESSTHAN), "COMPARE_LESSTHAN" }, - { static_cast(ExpressionType::COMPARE_GREATERTHAN), "COMPARE_GREATERTHAN" }, - { static_cast(ExpressionType::COMPARE_LESSTHANOREQUALTO), "COMPARE_LESSTHANOREQUALTO" }, - { static_cast(ExpressionType::COMPARE_GREATERTHANOREQUALTO), "COMPARE_GREATERTHANOREQUALTO" }, - { static_cast(ExpressionType::COMPARE_IN), "COMPARE_IN" }, - { static_cast(ExpressionType::COMPARE_NOT_IN), "COMPARE_NOT_IN" }, - { static_cast(ExpressionType::COMPARE_DISTINCT_FROM), "COMPARE_DISTINCT_FROM" }, - { static_cast(ExpressionType::COMPARE_BETWEEN), "COMPARE_BETWEEN" }, - { static_cast(ExpressionType::COMPARE_NOT_BETWEEN), "COMPARE_NOT_BETWEEN" }, - { static_cast(ExpressionType::COMPARE_NOT_DISTINCT_FROM), "COMPARE_NOT_DISTINCT_FROM" }, - { static_cast(ExpressionType::CONJUNCTION_AND), "CONJUNCTION_AND" }, - { static_cast(ExpressionType::CONJUNCTION_OR), "CONJUNCTION_OR" }, - { static_cast(ExpressionType::VALUE_CONSTANT), "VALUE_CONSTANT" }, - { static_cast(ExpressionType::VALUE_PARAMETER), "VALUE_PARAMETER" }, - { static_cast(ExpressionType::VALUE_TUPLE), "VALUE_TUPLE" }, - { static_cast(ExpressionType::VALUE_TUPLE_ADDRESS), "VALUE_TUPLE_ADDRESS" }, - { static_cast(ExpressionType::VALUE_NULL), "VALUE_NULL" }, - { static_cast(ExpressionType::VALUE_VECTOR), "VALUE_VECTOR" }, - { static_cast(ExpressionType::VALUE_SCALAR), "VALUE_SCALAR" }, - { static_cast(ExpressionType::VALUE_DEFAULT), "VALUE_DEFAULT" }, - { static_cast(ExpressionType::AGGREGATE), "AGGREGATE" }, - { static_cast(ExpressionType::BOUND_AGGREGATE), "BOUND_AGGREGATE" }, - { static_cast(ExpressionType::GROUPING_FUNCTION), "GROUPING_FUNCTION" }, - { static_cast(ExpressionType::WINDOW_AGGREGATE), "WINDOW_AGGREGATE" }, - { static_cast(ExpressionType::WINDOW_RANK), "WINDOW_RANK" }, - { static_cast(ExpressionType::WINDOW_RANK_DENSE), "WINDOW_RANK_DENSE" }, - { static_cast(ExpressionType::WINDOW_NTILE), "WINDOW_NTILE" }, - { static_cast(ExpressionType::WINDOW_PERCENT_RANK), "WINDOW_PERCENT_RANK" }, - { static_cast(ExpressionType::WINDOW_CUME_DIST), "WINDOW_CUME_DIST" }, - { static_cast(ExpressionType::WINDOW_ROW_NUMBER), "WINDOW_ROW_NUMBER" }, - { static_cast(ExpressionType::WINDOW_FIRST_VALUE), "WINDOW_FIRST_VALUE" }, - { static_cast(ExpressionType::WINDOW_LAST_VALUE), "WINDOW_LAST_VALUE" }, - { static_cast(ExpressionType::WINDOW_LEAD), "WINDOW_LEAD" }, - { static_cast(ExpressionType::WINDOW_LAG), "WINDOW_LAG" }, - { static_cast(ExpressionType::WINDOW_NTH_VALUE), "WINDOW_NTH_VALUE" }, - { static_cast(ExpressionType::FUNCTION), "FUNCTION" }, - { static_cast(ExpressionType::BOUND_FUNCTION), "BOUND_FUNCTION" }, - { static_cast(ExpressionType::CASE_EXPR), "CASE_EXPR" }, - { static_cast(ExpressionType::OPERATOR_NULLIF), "OPERATOR_NULLIF" }, - { static_cast(ExpressionType::OPERATOR_COALESCE), "OPERATOR_COALESCE" }, - { static_cast(ExpressionType::ARRAY_EXTRACT), "ARRAY_EXTRACT" }, - { static_cast(ExpressionType::ARRAY_SLICE), "ARRAY_SLICE" }, - { static_cast(ExpressionType::STRUCT_EXTRACT), "STRUCT_EXTRACT" }, - { static_cast(ExpressionType::ARRAY_CONSTRUCTOR), "ARRAY_CONSTRUCTOR" }, - { static_cast(ExpressionType::ARROW), "ARROW" }, - { static_cast(ExpressionType::SUBQUERY), "SUBQUERY" }, - { static_cast(ExpressionType::STAR), "STAR" }, - { static_cast(ExpressionType::TABLE_STAR), "TABLE_STAR" }, - { static_cast(ExpressionType::PLACEHOLDER), "PLACEHOLDER" }, - { static_cast(ExpressionType::COLUMN_REF), "COLUMN_REF" }, - { static_cast(ExpressionType::FUNCTION_REF), "FUNCTION_REF" }, - { static_cast(ExpressionType::TABLE_REF), "TABLE_REF" }, - { static_cast(ExpressionType::LAMBDA_REF), "LAMBDA_REF" }, - { static_cast(ExpressionType::CAST), "CAST" }, - { static_cast(ExpressionType::BOUND_REF), "BOUND_REF" }, - { static_cast(ExpressionType::BOUND_COLUMN_REF), "BOUND_COLUMN_REF" }, - { static_cast(ExpressionType::BOUND_UNNEST), "BOUND_UNNEST" }, - { static_cast(ExpressionType::COLLATE), "COLLATE" }, - { static_cast(ExpressionType::LAMBDA), "LAMBDA" }, - { static_cast(ExpressionType::POSITIONAL_REFERENCE), "POSITIONAL_REFERENCE" }, - { static_cast(ExpressionType::BOUND_LAMBDA_REF), "BOUND_LAMBDA_REF" }, - { static_cast(ExpressionType::BOUND_EXPANDED), "BOUND_EXPANDED" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ExpressionClass::INVALID; + } + if (StringUtil::Equals(value, "AGGREGATE")) { + return ExpressionClass::AGGREGATE; + } + if (StringUtil::Equals(value, "CASE")) { + return ExpressionClass::CASE; + } + if (StringUtil::Equals(value, "CAST")) { + return ExpressionClass::CAST; + } + if (StringUtil::Equals(value, "COLUMN_REF")) { + return ExpressionClass::COLUMN_REF; + } + if (StringUtil::Equals(value, "COMPARISON")) { + return ExpressionClass::COMPARISON; + } + if (StringUtil::Equals(value, "CONJUNCTION")) { + return ExpressionClass::CONJUNCTION; + } + if (StringUtil::Equals(value, "CONSTANT")) { + return ExpressionClass::CONSTANT; + } + if (StringUtil::Equals(value, "DEFAULT")) { + return ExpressionClass::DEFAULT; + } + if (StringUtil::Equals(value, "FUNCTION")) { + return ExpressionClass::FUNCTION; + } + if (StringUtil::Equals(value, "OPERATOR")) { + return ExpressionClass::OPERATOR; + } + if (StringUtil::Equals(value, "STAR")) { + return ExpressionClass::STAR; + } + if (StringUtil::Equals(value, "SUBQUERY")) { + return ExpressionClass::SUBQUERY; + } + if (StringUtil::Equals(value, "WINDOW")) { + return ExpressionClass::WINDOW; + } + if (StringUtil::Equals(value, "PARAMETER")) { + return ExpressionClass::PARAMETER; + } + if (StringUtil::Equals(value, "COLLATE")) { + return ExpressionClass::COLLATE; + } + if (StringUtil::Equals(value, "LAMBDA")) { + return ExpressionClass::LAMBDA; + } + if (StringUtil::Equals(value, "POSITIONAL_REFERENCE")) { + return ExpressionClass::POSITIONAL_REFERENCE; + } + if (StringUtil::Equals(value, "BETWEEN")) { + return ExpressionClass::BETWEEN; + } + if (StringUtil::Equals(value, "LAMBDA_REF")) { + return ExpressionClass::LAMBDA_REF; + } + if (StringUtil::Equals(value, "BOUND_AGGREGATE")) { + return ExpressionClass::BOUND_AGGREGATE; + } + if (StringUtil::Equals(value, "BOUND_CASE")) { + return ExpressionClass::BOUND_CASE; + } + if (StringUtil::Equals(value, "BOUND_CAST")) { + return ExpressionClass::BOUND_CAST; + } + if (StringUtil::Equals(value, "BOUND_COLUMN_REF")) { + return ExpressionClass::BOUND_COLUMN_REF; + } + if (StringUtil::Equals(value, "BOUND_COMPARISON")) { + return ExpressionClass::BOUND_COMPARISON; + } + if (StringUtil::Equals(value, "BOUND_CONJUNCTION")) { + return ExpressionClass::BOUND_CONJUNCTION; + } + if (StringUtil::Equals(value, "BOUND_CONSTANT")) { + return ExpressionClass::BOUND_CONSTANT; + } + if (StringUtil::Equals(value, "BOUND_DEFAULT")) { + return ExpressionClass::BOUND_DEFAULT; + } + if (StringUtil::Equals(value, "BOUND_FUNCTION")) { + return ExpressionClass::BOUND_FUNCTION; + } + if (StringUtil::Equals(value, "BOUND_OPERATOR")) { + return ExpressionClass::BOUND_OPERATOR; + } + if (StringUtil::Equals(value, "BOUND_PARAMETER")) { + return ExpressionClass::BOUND_PARAMETER; + } + if (StringUtil::Equals(value, "BOUND_REF")) { + return ExpressionClass::BOUND_REF; + } + if (StringUtil::Equals(value, "BOUND_SUBQUERY")) { + return ExpressionClass::BOUND_SUBQUERY; + } + if (StringUtil::Equals(value, "BOUND_WINDOW")) { + return ExpressionClass::BOUND_WINDOW; + } + if (StringUtil::Equals(value, "BOUND_BETWEEN")) { + return ExpressionClass::BOUND_BETWEEN; + } + if (StringUtil::Equals(value, "BOUND_UNNEST")) { + return ExpressionClass::BOUND_UNNEST; + } + if (StringUtil::Equals(value, "BOUND_LAMBDA")) { + return ExpressionClass::BOUND_LAMBDA; + } + if (StringUtil::Equals(value, "BOUND_LAMBDA_REF")) { + return ExpressionClass::BOUND_LAMBDA_REF; + } + if (StringUtil::Equals(value, "BOUND_EXPRESSION")) { + return ExpressionClass::BOUND_EXPRESSION; + } + if (StringUtil::Equals(value, "BOUND_EXPANDED")) { + return ExpressionClass::BOUND_EXPANDED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExpressionType value) { - return StringUtil::EnumToString(GetExpressionTypeValues(), 69, "ExpressionType", static_cast(value)); + switch(value) { + case ExpressionType::INVALID: + return "INVALID"; + case ExpressionType::OPERATOR_CAST: + return "OPERATOR_CAST"; + case ExpressionType::OPERATOR_NOT: + return "OPERATOR_NOT"; + case ExpressionType::OPERATOR_IS_NULL: + return "OPERATOR_IS_NULL"; + case ExpressionType::OPERATOR_IS_NOT_NULL: + return "OPERATOR_IS_NOT_NULL"; + case ExpressionType::COMPARE_EQUAL: + return "COMPARE_EQUAL"; + case ExpressionType::COMPARE_NOTEQUAL: + return "COMPARE_NOTEQUAL"; + case ExpressionType::COMPARE_LESSTHAN: + return "COMPARE_LESSTHAN"; + case ExpressionType::COMPARE_GREATERTHAN: + return "COMPARE_GREATERTHAN"; + case ExpressionType::COMPARE_LESSTHANOREQUALTO: + return "COMPARE_LESSTHANOREQUALTO"; + case ExpressionType::COMPARE_GREATERTHANOREQUALTO: + return "COMPARE_GREATERTHANOREQUALTO"; + case ExpressionType::COMPARE_IN: + return "COMPARE_IN"; + case ExpressionType::COMPARE_NOT_IN: + return "COMPARE_NOT_IN"; + case ExpressionType::COMPARE_DISTINCT_FROM: + return "COMPARE_DISTINCT_FROM"; + case ExpressionType::COMPARE_BETWEEN: + return "COMPARE_BETWEEN"; + case ExpressionType::COMPARE_NOT_BETWEEN: + return "COMPARE_NOT_BETWEEN"; + case ExpressionType::COMPARE_NOT_DISTINCT_FROM: + return "COMPARE_NOT_DISTINCT_FROM"; + case ExpressionType::CONJUNCTION_AND: + return "CONJUNCTION_AND"; + case ExpressionType::CONJUNCTION_OR: + return "CONJUNCTION_OR"; + case ExpressionType::VALUE_CONSTANT: + return "VALUE_CONSTANT"; + case ExpressionType::VALUE_PARAMETER: + return "VALUE_PARAMETER"; + case ExpressionType::VALUE_TUPLE: + return "VALUE_TUPLE"; + case ExpressionType::VALUE_TUPLE_ADDRESS: + return "VALUE_TUPLE_ADDRESS"; + case ExpressionType::VALUE_NULL: + return "VALUE_NULL"; + case ExpressionType::VALUE_VECTOR: + return "VALUE_VECTOR"; + case ExpressionType::VALUE_SCALAR: + return "VALUE_SCALAR"; + case ExpressionType::VALUE_DEFAULT: + return "VALUE_DEFAULT"; + case ExpressionType::AGGREGATE: + return "AGGREGATE"; + case ExpressionType::BOUND_AGGREGATE: + return "BOUND_AGGREGATE"; + case ExpressionType::GROUPING_FUNCTION: + return "GROUPING_FUNCTION"; + case ExpressionType::WINDOW_AGGREGATE: + return "WINDOW_AGGREGATE"; + case ExpressionType::WINDOW_RANK: + return "WINDOW_RANK"; + case ExpressionType::WINDOW_RANK_DENSE: + return "WINDOW_RANK_DENSE"; + case ExpressionType::WINDOW_NTILE: + return "WINDOW_NTILE"; + case ExpressionType::WINDOW_PERCENT_RANK: + return "WINDOW_PERCENT_RANK"; + case ExpressionType::WINDOW_CUME_DIST: + return "WINDOW_CUME_DIST"; + case ExpressionType::WINDOW_ROW_NUMBER: + return "WINDOW_ROW_NUMBER"; + case ExpressionType::WINDOW_FIRST_VALUE: + return "WINDOW_FIRST_VALUE"; + case ExpressionType::WINDOW_LAST_VALUE: + return "WINDOW_LAST_VALUE"; + case ExpressionType::WINDOW_LEAD: + return "WINDOW_LEAD"; + case ExpressionType::WINDOW_LAG: + return "WINDOW_LAG"; + case ExpressionType::WINDOW_NTH_VALUE: + return "WINDOW_NTH_VALUE"; + case ExpressionType::FUNCTION: + return "FUNCTION"; + case ExpressionType::BOUND_FUNCTION: + return "BOUND_FUNCTION"; + case ExpressionType::CASE_EXPR: + return "CASE_EXPR"; + case ExpressionType::OPERATOR_NULLIF: + return "OPERATOR_NULLIF"; + case ExpressionType::OPERATOR_COALESCE: + return "OPERATOR_COALESCE"; + case ExpressionType::ARRAY_EXTRACT: + return "ARRAY_EXTRACT"; + case ExpressionType::ARRAY_SLICE: + return "ARRAY_SLICE"; + case ExpressionType::STRUCT_EXTRACT: + return "STRUCT_EXTRACT"; + case ExpressionType::ARRAY_CONSTRUCTOR: + return "ARRAY_CONSTRUCTOR"; + case ExpressionType::ARROW: + return "ARROW"; + case ExpressionType::SUBQUERY: + return "SUBQUERY"; + case ExpressionType::STAR: + return "STAR"; + case ExpressionType::TABLE_STAR: + return "TABLE_STAR"; + case ExpressionType::PLACEHOLDER: + return "PLACEHOLDER"; + case ExpressionType::COLUMN_REF: + return "COLUMN_REF"; + case ExpressionType::FUNCTION_REF: + return "FUNCTION_REF"; + case ExpressionType::TABLE_REF: + return "TABLE_REF"; + case ExpressionType::LAMBDA_REF: + return "LAMBDA_REF"; + case ExpressionType::CAST: + return "CAST"; + case ExpressionType::BOUND_REF: + return "BOUND_REF"; + case ExpressionType::BOUND_COLUMN_REF: + return "BOUND_COLUMN_REF"; + case ExpressionType::BOUND_UNNEST: + return "BOUND_UNNEST"; + case ExpressionType::COLLATE: + return "COLLATE"; + case ExpressionType::LAMBDA: + return "LAMBDA"; + case ExpressionType::POSITIONAL_REFERENCE: + return "POSITIONAL_REFERENCE"; + case ExpressionType::BOUND_LAMBDA_REF: + return "BOUND_LAMBDA_REF"; + case ExpressionType::BOUND_EXPANDED: + return "BOUND_EXPANDED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExpressionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExpressionTypeValues(), 69, "ExpressionType", value)); -} - -const StringUtil::EnumStringLiteral *GetExtensionABITypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtensionABIType::UNKNOWN), "UNKNOWN" }, - { static_cast(ExtensionABIType::CPP), "CPP" }, - { static_cast(ExtensionABIType::C_STRUCT), "C_STRUCT" }, - { static_cast(ExtensionABIType::C_STRUCT_UNSTABLE), "C_STRUCT_UNSTABLE" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ExpressionType::INVALID; + } + if (StringUtil::Equals(value, "OPERATOR_CAST")) { + return ExpressionType::OPERATOR_CAST; + } + if (StringUtil::Equals(value, "OPERATOR_NOT")) { + return ExpressionType::OPERATOR_NOT; + } + if (StringUtil::Equals(value, "OPERATOR_IS_NULL")) { + return ExpressionType::OPERATOR_IS_NULL; + } + if (StringUtil::Equals(value, "OPERATOR_IS_NOT_NULL")) { + return ExpressionType::OPERATOR_IS_NOT_NULL; + } + if (StringUtil::Equals(value, "COMPARE_EQUAL")) { + return ExpressionType::COMPARE_EQUAL; + } + if (StringUtil::Equals(value, "COMPARE_NOTEQUAL")) { + return ExpressionType::COMPARE_NOTEQUAL; + } + if (StringUtil::Equals(value, "COMPARE_LESSTHAN")) { + return ExpressionType::COMPARE_LESSTHAN; + } + if (StringUtil::Equals(value, "COMPARE_GREATERTHAN")) { + return ExpressionType::COMPARE_GREATERTHAN; + } + if (StringUtil::Equals(value, "COMPARE_LESSTHANOREQUALTO")) { + return ExpressionType::COMPARE_LESSTHANOREQUALTO; + } + if (StringUtil::Equals(value, "COMPARE_GREATERTHANOREQUALTO")) { + return ExpressionType::COMPARE_GREATERTHANOREQUALTO; + } + if (StringUtil::Equals(value, "COMPARE_IN")) { + return ExpressionType::COMPARE_IN; + } + if (StringUtil::Equals(value, "COMPARE_NOT_IN")) { + return ExpressionType::COMPARE_NOT_IN; + } + if (StringUtil::Equals(value, "COMPARE_DISTINCT_FROM")) { + return ExpressionType::COMPARE_DISTINCT_FROM; + } + if (StringUtil::Equals(value, "COMPARE_BETWEEN")) { + return ExpressionType::COMPARE_BETWEEN; + } + if (StringUtil::Equals(value, "COMPARE_NOT_BETWEEN")) { + return ExpressionType::COMPARE_NOT_BETWEEN; + } + if (StringUtil::Equals(value, "COMPARE_NOT_DISTINCT_FROM")) { + return ExpressionType::COMPARE_NOT_DISTINCT_FROM; + } + if (StringUtil::Equals(value, "CONJUNCTION_AND")) { + return ExpressionType::CONJUNCTION_AND; + } + if (StringUtil::Equals(value, "CONJUNCTION_OR")) { + return ExpressionType::CONJUNCTION_OR; + } + if (StringUtil::Equals(value, "VALUE_CONSTANT")) { + return ExpressionType::VALUE_CONSTANT; + } + if (StringUtil::Equals(value, "VALUE_PARAMETER")) { + return ExpressionType::VALUE_PARAMETER; + } + if (StringUtil::Equals(value, "VALUE_TUPLE")) { + return ExpressionType::VALUE_TUPLE; + } + if (StringUtil::Equals(value, "VALUE_TUPLE_ADDRESS")) { + return ExpressionType::VALUE_TUPLE_ADDRESS; + } + if (StringUtil::Equals(value, "VALUE_NULL")) { + return ExpressionType::VALUE_NULL; + } + if (StringUtil::Equals(value, "VALUE_VECTOR")) { + return ExpressionType::VALUE_VECTOR; + } + if (StringUtil::Equals(value, "VALUE_SCALAR")) { + return ExpressionType::VALUE_SCALAR; + } + if (StringUtil::Equals(value, "VALUE_DEFAULT")) { + return ExpressionType::VALUE_DEFAULT; + } + if (StringUtil::Equals(value, "AGGREGATE")) { + return ExpressionType::AGGREGATE; + } + if (StringUtil::Equals(value, "BOUND_AGGREGATE")) { + return ExpressionType::BOUND_AGGREGATE; + } + if (StringUtil::Equals(value, "GROUPING_FUNCTION")) { + return ExpressionType::GROUPING_FUNCTION; + } + if (StringUtil::Equals(value, "WINDOW_AGGREGATE")) { + return ExpressionType::WINDOW_AGGREGATE; + } + if (StringUtil::Equals(value, "WINDOW_RANK")) { + return ExpressionType::WINDOW_RANK; + } + if (StringUtil::Equals(value, "WINDOW_RANK_DENSE")) { + return ExpressionType::WINDOW_RANK_DENSE; + } + if (StringUtil::Equals(value, "WINDOW_NTILE")) { + return ExpressionType::WINDOW_NTILE; + } + if (StringUtil::Equals(value, "WINDOW_PERCENT_RANK")) { + return ExpressionType::WINDOW_PERCENT_RANK; + } + if (StringUtil::Equals(value, "WINDOW_CUME_DIST")) { + return ExpressionType::WINDOW_CUME_DIST; + } + if (StringUtil::Equals(value, "WINDOW_ROW_NUMBER")) { + return ExpressionType::WINDOW_ROW_NUMBER; + } + if (StringUtil::Equals(value, "WINDOW_FIRST_VALUE")) { + return ExpressionType::WINDOW_FIRST_VALUE; + } + if (StringUtil::Equals(value, "WINDOW_LAST_VALUE")) { + return ExpressionType::WINDOW_LAST_VALUE; + } + if (StringUtil::Equals(value, "WINDOW_LEAD")) { + return ExpressionType::WINDOW_LEAD; + } + if (StringUtil::Equals(value, "WINDOW_LAG")) { + return ExpressionType::WINDOW_LAG; + } + if (StringUtil::Equals(value, "WINDOW_NTH_VALUE")) { + return ExpressionType::WINDOW_NTH_VALUE; + } + if (StringUtil::Equals(value, "FUNCTION")) { + return ExpressionType::FUNCTION; + } + if (StringUtil::Equals(value, "BOUND_FUNCTION")) { + return ExpressionType::BOUND_FUNCTION; + } + if (StringUtil::Equals(value, "CASE_EXPR")) { + return ExpressionType::CASE_EXPR; + } + if (StringUtil::Equals(value, "OPERATOR_NULLIF")) { + return ExpressionType::OPERATOR_NULLIF; + } + if (StringUtil::Equals(value, "OPERATOR_COALESCE")) { + return ExpressionType::OPERATOR_COALESCE; + } + if (StringUtil::Equals(value, "ARRAY_EXTRACT")) { + return ExpressionType::ARRAY_EXTRACT; + } + if (StringUtil::Equals(value, "ARRAY_SLICE")) { + return ExpressionType::ARRAY_SLICE; + } + if (StringUtil::Equals(value, "STRUCT_EXTRACT")) { + return ExpressionType::STRUCT_EXTRACT; + } + if (StringUtil::Equals(value, "ARRAY_CONSTRUCTOR")) { + return ExpressionType::ARRAY_CONSTRUCTOR; + } + if (StringUtil::Equals(value, "ARROW")) { + return ExpressionType::ARROW; + } + if (StringUtil::Equals(value, "SUBQUERY")) { + return ExpressionType::SUBQUERY; + } + if (StringUtil::Equals(value, "STAR")) { + return ExpressionType::STAR; + } + if (StringUtil::Equals(value, "TABLE_STAR")) { + return ExpressionType::TABLE_STAR; + } + if (StringUtil::Equals(value, "PLACEHOLDER")) { + return ExpressionType::PLACEHOLDER; + } + if (StringUtil::Equals(value, "COLUMN_REF")) { + return ExpressionType::COLUMN_REF; + } + if (StringUtil::Equals(value, "FUNCTION_REF")) { + return ExpressionType::FUNCTION_REF; + } + if (StringUtil::Equals(value, "TABLE_REF")) { + return ExpressionType::TABLE_REF; + } + if (StringUtil::Equals(value, "LAMBDA_REF")) { + return ExpressionType::LAMBDA_REF; + } + if (StringUtil::Equals(value, "CAST")) { + return ExpressionType::CAST; + } + if (StringUtil::Equals(value, "BOUND_REF")) { + return ExpressionType::BOUND_REF; + } + if (StringUtil::Equals(value, "BOUND_COLUMN_REF")) { + return ExpressionType::BOUND_COLUMN_REF; + } + if (StringUtil::Equals(value, "BOUND_UNNEST")) { + return ExpressionType::BOUND_UNNEST; + } + if (StringUtil::Equals(value, "COLLATE")) { + return ExpressionType::COLLATE; + } + if (StringUtil::Equals(value, "LAMBDA")) { + return ExpressionType::LAMBDA; + } + if (StringUtil::Equals(value, "POSITIONAL_REFERENCE")) { + return ExpressionType::POSITIONAL_REFERENCE; + } + if (StringUtil::Equals(value, "BOUND_LAMBDA_REF")) { + return ExpressionType::BOUND_LAMBDA_REF; + } + if (StringUtil::Equals(value, "BOUND_EXPANDED")) { + return ExpressionType::BOUND_EXPANDED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtensionABIType value) { - return StringUtil::EnumToString(GetExtensionABITypeValues(), 4, "ExtensionABIType", static_cast(value)); + switch(value) { + case ExtensionABIType::UNKNOWN: + return "UNKNOWN"; + case ExtensionABIType::CPP: + return "CPP"; + case ExtensionABIType::C_STRUCT: + return "C_STRUCT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtensionABIType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtensionABITypeValues(), 4, "ExtensionABIType", value)); -} - -const StringUtil::EnumStringLiteral *GetExtensionInstallModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtensionInstallMode::UNKNOWN), "UNKNOWN" }, - { static_cast(ExtensionInstallMode::REPOSITORY), "REPOSITORY" }, - { static_cast(ExtensionInstallMode::CUSTOM_PATH), "CUSTOM_PATH" }, - { static_cast(ExtensionInstallMode::STATICALLY_LINKED), "STATICALLY_LINKED" }, - { static_cast(ExtensionInstallMode::NOT_INSTALLED), "NOT_INSTALLED" } - }; - return values; + if (StringUtil::Equals(value, "UNKNOWN")) { + return ExtensionABIType::UNKNOWN; + } + if (StringUtil::Equals(value, "CPP")) { + return ExtensionABIType::CPP; + } + if (StringUtil::Equals(value, "C_STRUCT")) { + return ExtensionABIType::C_STRUCT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtensionInstallMode value) { - return StringUtil::EnumToString(GetExtensionInstallModeValues(), 5, "ExtensionInstallMode", static_cast(value)); + switch(value) { + case ExtensionInstallMode::UNKNOWN: + return "UNKNOWN"; + case ExtensionInstallMode::REPOSITORY: + return "REPOSITORY"; + case ExtensionInstallMode::CUSTOM_PATH: + return "CUSTOM_PATH"; + case ExtensionInstallMode::STATICALLY_LINKED: + return "STATICALLY_LINKED"; + case ExtensionInstallMode::NOT_INSTALLED: + return "NOT_INSTALLED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtensionInstallMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtensionInstallModeValues(), 5, "ExtensionInstallMode", value)); -} - -const StringUtil::EnumStringLiteral *GetExtensionLoadResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtensionLoadResult::LOADED_EXTENSION), "LOADED_EXTENSION" }, - { static_cast(ExtensionLoadResult::EXTENSION_UNKNOWN), "EXTENSION_UNKNOWN" }, - { static_cast(ExtensionLoadResult::NOT_LOADED), "NOT_LOADED" } - }; - return values; + if (StringUtil::Equals(value, "UNKNOWN")) { + return ExtensionInstallMode::UNKNOWN; + } + if (StringUtil::Equals(value, "REPOSITORY")) { + return ExtensionInstallMode::REPOSITORY; + } + if (StringUtil::Equals(value, "CUSTOM_PATH")) { + return ExtensionInstallMode::CUSTOM_PATH; + } + if (StringUtil::Equals(value, "STATICALLY_LINKED")) { + return ExtensionInstallMode::STATICALLY_LINKED; + } + if (StringUtil::Equals(value, "NOT_INSTALLED")) { + return ExtensionInstallMode::NOT_INSTALLED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtensionLoadResult value) { - return StringUtil::EnumToString(GetExtensionLoadResultValues(), 3, "ExtensionLoadResult", static_cast(value)); + switch(value) { + case ExtensionLoadResult::LOADED_EXTENSION: + return "LOADED_EXTENSION"; + case ExtensionLoadResult::EXTENSION_UNKNOWN: + return "EXTENSION_UNKNOWN"; + case ExtensionLoadResult::NOT_LOADED: + return "NOT_LOADED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtensionLoadResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtensionLoadResultValues(), 3, "ExtensionLoadResult", value)); -} - -const StringUtil::EnumStringLiteral *GetExtensionUpdateResultTagValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtensionUpdateResultTag::UNKNOWN), "UNKNOWN" }, - { static_cast(ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE), "NO_UPDATE_AVAILABLE" }, - { static_cast(ExtensionUpdateResultTag::NOT_A_REPOSITORY), "NOT_A_REPOSITORY" }, - { static_cast(ExtensionUpdateResultTag::NOT_INSTALLED), "NOT_INSTALLED" }, - { static_cast(ExtensionUpdateResultTag::STATICALLY_LOADED), "STATICALLY_LOADED" }, - { static_cast(ExtensionUpdateResultTag::MISSING_INSTALL_INFO), "MISSING_INSTALL_INFO" }, - { static_cast(ExtensionUpdateResultTag::REDOWNLOADED), "REDOWNLOADED" }, - { static_cast(ExtensionUpdateResultTag::UPDATED), "UPDATED" } - }; - return values; + if (StringUtil::Equals(value, "LOADED_EXTENSION")) { + return ExtensionLoadResult::LOADED_EXTENSION; + } + if (StringUtil::Equals(value, "EXTENSION_UNKNOWN")) { + return ExtensionLoadResult::EXTENSION_UNKNOWN; + } + if (StringUtil::Equals(value, "NOT_LOADED")) { + return ExtensionLoadResult::NOT_LOADED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtensionUpdateResultTag value) { - return StringUtil::EnumToString(GetExtensionUpdateResultTagValues(), 8, "ExtensionUpdateResultTag", static_cast(value)); + switch(value) { + case ExtensionUpdateResultTag::UNKNOWN: + return "UNKNOWN"; + case ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE: + return "NO_UPDATE_AVAILABLE"; + case ExtensionUpdateResultTag::NOT_A_REPOSITORY: + return "NOT_A_REPOSITORY"; + case ExtensionUpdateResultTag::NOT_INSTALLED: + return "NOT_INSTALLED"; + case ExtensionUpdateResultTag::STATICALLY_LOADED: + return "STATICALLY_LOADED"; + case ExtensionUpdateResultTag::MISSING_INSTALL_INFO: + return "MISSING_INSTALL_INFO"; + case ExtensionUpdateResultTag::REDOWNLOADED: + return "REDOWNLOADED"; + case ExtensionUpdateResultTag::UPDATED: + return "UPDATED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtensionUpdateResultTag EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtensionUpdateResultTagValues(), 8, "ExtensionUpdateResultTag", value)); -} - -const StringUtil::EnumStringLiteral *GetExtraDropInfoTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtraDropInfoType::INVALID), "INVALID" }, - { static_cast(ExtraDropInfoType::SECRET_INFO), "SECRET_INFO" } - }; - return values; + if (StringUtil::Equals(value, "UNKNOWN")) { + return ExtensionUpdateResultTag::UNKNOWN; + } + if (StringUtil::Equals(value, "NO_UPDATE_AVAILABLE")) { + return ExtensionUpdateResultTag::NO_UPDATE_AVAILABLE; + } + if (StringUtil::Equals(value, "NOT_A_REPOSITORY")) { + return ExtensionUpdateResultTag::NOT_A_REPOSITORY; + } + if (StringUtil::Equals(value, "NOT_INSTALLED")) { + return ExtensionUpdateResultTag::NOT_INSTALLED; + } + if (StringUtil::Equals(value, "STATICALLY_LOADED")) { + return ExtensionUpdateResultTag::STATICALLY_LOADED; + } + if (StringUtil::Equals(value, "MISSING_INSTALL_INFO")) { + return ExtensionUpdateResultTag::MISSING_INSTALL_INFO; + } + if (StringUtil::Equals(value, "REDOWNLOADED")) { + return ExtensionUpdateResultTag::REDOWNLOADED; + } + if (StringUtil::Equals(value, "UPDATED")) { + return ExtensionUpdateResultTag::UPDATED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtraDropInfoType value) { - return StringUtil::EnumToString(GetExtraDropInfoTypeValues(), 2, "ExtraDropInfoType", static_cast(value)); + switch(value) { + case ExtraDropInfoType::INVALID: + return "INVALID"; + case ExtraDropInfoType::SECRET_INFO: + return "SECRET_INFO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtraDropInfoType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtraDropInfoTypeValues(), 2, "ExtraDropInfoType", value)); -} - -const StringUtil::EnumStringLiteral *GetExtraTypeInfoTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ExtraTypeInfoType::INVALID_TYPE_INFO), "INVALID_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::GENERIC_TYPE_INFO), "GENERIC_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::DECIMAL_TYPE_INFO), "DECIMAL_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::STRING_TYPE_INFO), "STRING_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::LIST_TYPE_INFO), "LIST_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::STRUCT_TYPE_INFO), "STRUCT_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::ENUM_TYPE_INFO), "ENUM_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::USER_TYPE_INFO), "USER_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO), "AGGREGATE_STATE_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::ARRAY_TYPE_INFO), "ARRAY_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::ANY_TYPE_INFO), "ANY_TYPE_INFO" }, - { static_cast(ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO), "INTEGER_LITERAL_TYPE_INFO" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return ExtraDropInfoType::INVALID; + } + if (StringUtil::Equals(value, "SECRET_INFO")) { + return ExtraDropInfoType::SECRET_INFO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ExtraTypeInfoType value) { - return StringUtil::EnumToString(GetExtraTypeInfoTypeValues(), 12, "ExtraTypeInfoType", static_cast(value)); + switch(value) { + case ExtraTypeInfoType::INVALID_TYPE_INFO: + return "INVALID_TYPE_INFO"; + case ExtraTypeInfoType::GENERIC_TYPE_INFO: + return "GENERIC_TYPE_INFO"; + case ExtraTypeInfoType::DECIMAL_TYPE_INFO: + return "DECIMAL_TYPE_INFO"; + case ExtraTypeInfoType::STRING_TYPE_INFO: + return "STRING_TYPE_INFO"; + case ExtraTypeInfoType::LIST_TYPE_INFO: + return "LIST_TYPE_INFO"; + case ExtraTypeInfoType::STRUCT_TYPE_INFO: + return "STRUCT_TYPE_INFO"; + case ExtraTypeInfoType::ENUM_TYPE_INFO: + return "ENUM_TYPE_INFO"; + case ExtraTypeInfoType::USER_TYPE_INFO: + return "USER_TYPE_INFO"; + case ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO: + return "AGGREGATE_STATE_TYPE_INFO"; + case ExtraTypeInfoType::ARRAY_TYPE_INFO: + return "ARRAY_TYPE_INFO"; + case ExtraTypeInfoType::ANY_TYPE_INFO: + return "ANY_TYPE_INFO"; + case ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO: + return "INTEGER_LITERAL_TYPE_INFO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ExtraTypeInfoType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetExtraTypeInfoTypeValues(), 12, "ExtraTypeInfoType", value)); -} - -const StringUtil::EnumStringLiteral *GetFileBufferTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FileBufferType::BLOCK), "BLOCK" }, - { static_cast(FileBufferType::MANAGED_BUFFER), "MANAGED_BUFFER" }, - { static_cast(FileBufferType::TINY_BUFFER), "TINY_BUFFER" } - }; - return values; + if (StringUtil::Equals(value, "INVALID_TYPE_INFO")) { + return ExtraTypeInfoType::INVALID_TYPE_INFO; + } + if (StringUtil::Equals(value, "GENERIC_TYPE_INFO")) { + return ExtraTypeInfoType::GENERIC_TYPE_INFO; + } + if (StringUtil::Equals(value, "DECIMAL_TYPE_INFO")) { + return ExtraTypeInfoType::DECIMAL_TYPE_INFO; + } + if (StringUtil::Equals(value, "STRING_TYPE_INFO")) { + return ExtraTypeInfoType::STRING_TYPE_INFO; + } + if (StringUtil::Equals(value, "LIST_TYPE_INFO")) { + return ExtraTypeInfoType::LIST_TYPE_INFO; + } + if (StringUtil::Equals(value, "STRUCT_TYPE_INFO")) { + return ExtraTypeInfoType::STRUCT_TYPE_INFO; + } + if (StringUtil::Equals(value, "ENUM_TYPE_INFO")) { + return ExtraTypeInfoType::ENUM_TYPE_INFO; + } + if (StringUtil::Equals(value, "USER_TYPE_INFO")) { + return ExtraTypeInfoType::USER_TYPE_INFO; + } + if (StringUtil::Equals(value, "AGGREGATE_STATE_TYPE_INFO")) { + return ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO; + } + if (StringUtil::Equals(value, "ARRAY_TYPE_INFO")) { + return ExtraTypeInfoType::ARRAY_TYPE_INFO; + } + if (StringUtil::Equals(value, "ANY_TYPE_INFO")) { + return ExtraTypeInfoType::ANY_TYPE_INFO; + } + if (StringUtil::Equals(value, "INTEGER_LITERAL_TYPE_INFO")) { + return ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FileBufferType value) { - return StringUtil::EnumToString(GetFileBufferTypeValues(), 3, "FileBufferType", static_cast(value)); + switch(value) { + case FileBufferType::BLOCK: + return "BLOCK"; + case FileBufferType::MANAGED_BUFFER: + return "MANAGED_BUFFER"; + case FileBufferType::TINY_BUFFER: + return "TINY_BUFFER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FileBufferType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFileBufferTypeValues(), 3, "FileBufferType", value)); -} - -const StringUtil::EnumStringLiteral *GetFileCompressionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FileCompressionType::AUTO_DETECT), "AUTO_DETECT" }, - { static_cast(FileCompressionType::UNCOMPRESSED), "UNCOMPRESSED" }, - { static_cast(FileCompressionType::GZIP), "GZIP" }, - { static_cast(FileCompressionType::ZSTD), "ZSTD" } - }; - return values; + if (StringUtil::Equals(value, "BLOCK")) { + return FileBufferType::BLOCK; + } + if (StringUtil::Equals(value, "MANAGED_BUFFER")) { + return FileBufferType::MANAGED_BUFFER; + } + if (StringUtil::Equals(value, "TINY_BUFFER")) { + return FileBufferType::TINY_BUFFER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FileCompressionType value) { - return StringUtil::EnumToString(GetFileCompressionTypeValues(), 4, "FileCompressionType", static_cast(value)); + switch(value) { + case FileCompressionType::AUTO_DETECT: + return "AUTO_DETECT"; + case FileCompressionType::UNCOMPRESSED: + return "UNCOMPRESSED"; + case FileCompressionType::GZIP: + return "GZIP"; + case FileCompressionType::ZSTD: + return "ZSTD"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FileCompressionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFileCompressionTypeValues(), 4, "FileCompressionType", value)); -} - -const StringUtil::EnumStringLiteral *GetFileExpandResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FileExpandResult::NO_FILES), "NO_FILES" }, - { static_cast(FileExpandResult::SINGLE_FILE), "SINGLE_FILE" }, - { static_cast(FileExpandResult::MULTIPLE_FILES), "MULTIPLE_FILES" } - }; - return values; + if (StringUtil::Equals(value, "AUTO_DETECT")) { + return FileCompressionType::AUTO_DETECT; + } + if (StringUtil::Equals(value, "UNCOMPRESSED")) { + return FileCompressionType::UNCOMPRESSED; + } + if (StringUtil::Equals(value, "GZIP")) { + return FileCompressionType::GZIP; + } + if (StringUtil::Equals(value, "ZSTD")) { + return FileCompressionType::ZSTD; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FileExpandResult value) { - return StringUtil::EnumToString(GetFileExpandResultValues(), 3, "FileExpandResult", static_cast(value)); + switch(value) { + case FileExpandResult::NO_FILES: + return "NO_FILES"; + case FileExpandResult::SINGLE_FILE: + return "SINGLE_FILE"; + case FileExpandResult::MULTIPLE_FILES: + return "MULTIPLE_FILES"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FileExpandResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFileExpandResultValues(), 3, "FileExpandResult", value)); -} - -const StringUtil::EnumStringLiteral *GetFileGlobOptionsValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FileGlobOptions::DISALLOW_EMPTY), "DISALLOW_EMPTY" }, - { static_cast(FileGlobOptions::ALLOW_EMPTY), "ALLOW_EMPTY" } - }; - return values; + if (StringUtil::Equals(value, "NO_FILES")) { + return FileExpandResult::NO_FILES; + } + if (StringUtil::Equals(value, "SINGLE_FILE")) { + return FileExpandResult::SINGLE_FILE; + } + if (StringUtil::Equals(value, "MULTIPLE_FILES")) { + return FileExpandResult::MULTIPLE_FILES; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FileGlobOptions value) { - return StringUtil::EnumToString(GetFileGlobOptionsValues(), 2, "FileGlobOptions", static_cast(value)); + switch(value) { + case FileGlobOptions::DISALLOW_EMPTY: + return "DISALLOW_EMPTY"; + case FileGlobOptions::ALLOW_EMPTY: + return "ALLOW_EMPTY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FileGlobOptions EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFileGlobOptionsValues(), 2, "FileGlobOptions", value)); -} - -const StringUtil::EnumStringLiteral *GetFileLockTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FileLockType::NO_LOCK), "NO_LOCK" }, - { static_cast(FileLockType::READ_LOCK), "READ_LOCK" }, - { static_cast(FileLockType::WRITE_LOCK), "WRITE_LOCK" } - }; - return values; + if (StringUtil::Equals(value, "DISALLOW_EMPTY")) { + return FileGlobOptions::DISALLOW_EMPTY; + } + if (StringUtil::Equals(value, "ALLOW_EMPTY")) { + return FileGlobOptions::ALLOW_EMPTY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FileLockType value) { - return StringUtil::EnumToString(GetFileLockTypeValues(), 3, "FileLockType", static_cast(value)); + switch(value) { + case FileLockType::NO_LOCK: + return "NO_LOCK"; + case FileLockType::READ_LOCK: + return "READ_LOCK"; + case FileLockType::WRITE_LOCK: + return "WRITE_LOCK"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FileLockType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFileLockTypeValues(), 3, "FileLockType", value)); -} - -const StringUtil::EnumStringLiteral *GetFilterPropagateResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FilterPropagateResult::NO_PRUNING_POSSIBLE), "NO_PRUNING_POSSIBLE" }, - { static_cast(FilterPropagateResult::FILTER_ALWAYS_TRUE), "FILTER_ALWAYS_TRUE" }, - { static_cast(FilterPropagateResult::FILTER_ALWAYS_FALSE), "FILTER_ALWAYS_FALSE" }, - { static_cast(FilterPropagateResult::FILTER_TRUE_OR_NULL), "FILTER_TRUE_OR_NULL" }, - { static_cast(FilterPropagateResult::FILTER_FALSE_OR_NULL), "FILTER_FALSE_OR_NULL" } - }; - return values; + if (StringUtil::Equals(value, "NO_LOCK")) { + return FileLockType::NO_LOCK; + } + if (StringUtil::Equals(value, "READ_LOCK")) { + return FileLockType::READ_LOCK; + } + if (StringUtil::Equals(value, "WRITE_LOCK")) { + return FileLockType::WRITE_LOCK; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FilterPropagateResult value) { - return StringUtil::EnumToString(GetFilterPropagateResultValues(), 5, "FilterPropagateResult", static_cast(value)); + switch(value) { + case FilterPropagateResult::NO_PRUNING_POSSIBLE: + return "NO_PRUNING_POSSIBLE"; + case FilterPropagateResult::FILTER_ALWAYS_TRUE: + return "FILTER_ALWAYS_TRUE"; + case FilterPropagateResult::FILTER_ALWAYS_FALSE: + return "FILTER_ALWAYS_FALSE"; + case FilterPropagateResult::FILTER_TRUE_OR_NULL: + return "FILTER_TRUE_OR_NULL"; + case FilterPropagateResult::FILTER_FALSE_OR_NULL: + return "FILTER_FALSE_OR_NULL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FilterPropagateResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFilterPropagateResultValues(), 5, "FilterPropagateResult", value)); -} - -const StringUtil::EnumStringLiteral *GetForeignKeyTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE), "FK_TYPE_PRIMARY_KEY_TABLE" }, - { static_cast(ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE), "FK_TYPE_FOREIGN_KEY_TABLE" }, - { static_cast(ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE), "FK_TYPE_SELF_REFERENCE_TABLE" } - }; - return values; + if (StringUtil::Equals(value, "NO_PRUNING_POSSIBLE")) { + return FilterPropagateResult::NO_PRUNING_POSSIBLE; + } + if (StringUtil::Equals(value, "FILTER_ALWAYS_TRUE")) { + return FilterPropagateResult::FILTER_ALWAYS_TRUE; + } + if (StringUtil::Equals(value, "FILTER_ALWAYS_FALSE")) { + return FilterPropagateResult::FILTER_ALWAYS_FALSE; + } + if (StringUtil::Equals(value, "FILTER_TRUE_OR_NULL")) { + return FilterPropagateResult::FILTER_TRUE_OR_NULL; + } + if (StringUtil::Equals(value, "FILTER_FALSE_OR_NULL")) { + return FilterPropagateResult::FILTER_FALSE_OR_NULL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ForeignKeyType value) { - return StringUtil::EnumToString(GetForeignKeyTypeValues(), 3, "ForeignKeyType", static_cast(value)); + switch(value) { + case ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE: + return "FK_TYPE_PRIMARY_KEY_TABLE"; + case ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE: + return "FK_TYPE_FOREIGN_KEY_TABLE"; + case ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE: + return "FK_TYPE_SELF_REFERENCE_TABLE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ForeignKeyType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetForeignKeyTypeValues(), 3, "ForeignKeyType", value)); -} - -const StringUtil::EnumStringLiteral *GetFunctionCollationHandlingValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FunctionCollationHandling::PROPAGATE_COLLATIONS), "PROPAGATE_COLLATIONS" }, - { static_cast(FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS), "PUSH_COMBINABLE_COLLATIONS" }, - { static_cast(FunctionCollationHandling::IGNORE_COLLATIONS), "IGNORE_COLLATIONS" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(FunctionCollationHandling value) { - return StringUtil::EnumToString(GetFunctionCollationHandlingValues(), 3, "FunctionCollationHandling", static_cast(value)); -} - -template<> -FunctionCollationHandling EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFunctionCollationHandlingValues(), 3, "FunctionCollationHandling", value)); -} - -const StringUtil::EnumStringLiteral *GetFunctionErrorsValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FunctionErrors::CANNOT_ERROR), "CANNOT_ERROR" }, - { static_cast(FunctionErrors::CAN_THROW_RUNTIME_ERROR), "CAN_THROW_RUNTIME_ERROR" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(FunctionErrors value) { - return StringUtil::EnumToString(GetFunctionErrorsValues(), 2, "FunctionErrors", static_cast(value)); -} - -template<> -FunctionErrors EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFunctionErrorsValues(), 2, "FunctionErrors", value)); -} - -const StringUtil::EnumStringLiteral *GetFunctionNullHandlingValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FunctionNullHandling::DEFAULT_NULL_HANDLING), "DEFAULT_NULL_HANDLING" }, - { static_cast(FunctionNullHandling::SPECIAL_HANDLING), "SPECIAL_HANDLING" } - }; - return values; + if (StringUtil::Equals(value, "FK_TYPE_PRIMARY_KEY_TABLE")) { + return ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE; + } + if (StringUtil::Equals(value, "FK_TYPE_FOREIGN_KEY_TABLE")) { + return ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE; + } + if (StringUtil::Equals(value, "FK_TYPE_SELF_REFERENCE_TABLE")) { + return ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FunctionNullHandling value) { - return StringUtil::EnumToString(GetFunctionNullHandlingValues(), 2, "FunctionNullHandling", static_cast(value)); + switch(value) { + case FunctionNullHandling::DEFAULT_NULL_HANDLING: + return "DEFAULT_NULL_HANDLING"; + case FunctionNullHandling::SPECIAL_HANDLING: + return "SPECIAL_HANDLING"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FunctionNullHandling EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFunctionNullHandlingValues(), 2, "FunctionNullHandling", value)); -} - -const StringUtil::EnumStringLiteral *GetFunctionStabilityValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(FunctionStability::CONSISTENT), "CONSISTENT" }, - { static_cast(FunctionStability::VOLATILE), "VOLATILE" }, - { static_cast(FunctionStability::CONSISTENT_WITHIN_QUERY), "CONSISTENT_WITHIN_QUERY" } - }; - return values; + if (StringUtil::Equals(value, "DEFAULT_NULL_HANDLING")) { + return FunctionNullHandling::DEFAULT_NULL_HANDLING; + } + if (StringUtil::Equals(value, "SPECIAL_HANDLING")) { + return FunctionNullHandling::SPECIAL_HANDLING; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(FunctionStability value) { - return StringUtil::EnumToString(GetFunctionStabilityValues(), 3, "FunctionStability", static_cast(value)); + switch(value) { + case FunctionStability::CONSISTENT: + return "CONSISTENT"; + case FunctionStability::VOLATILE: + return "VOLATILE"; + case FunctionStability::CONSISTENT_WITHIN_QUERY: + return "CONSISTENT_WITHIN_QUERY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> FunctionStability EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetFunctionStabilityValues(), 3, "FunctionStability", value)); -} - -const StringUtil::EnumStringLiteral *GetGateStatusValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(GateStatus::GATE_NOT_SET), "GATE_NOT_SET" }, - { static_cast(GateStatus::GATE_SET), "GATE_SET" } - }; - return values; + if (StringUtil::Equals(value, "CONSISTENT")) { + return FunctionStability::CONSISTENT; + } + if (StringUtil::Equals(value, "VOLATILE")) { + return FunctionStability::VOLATILE; + } + if (StringUtil::Equals(value, "CONSISTENT_WITHIN_QUERY")) { + return FunctionStability::CONSISTENT_WITHIN_QUERY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(GateStatus value) { - return StringUtil::EnumToString(GetGateStatusValues(), 2, "GateStatus", static_cast(value)); + switch(value) { + case GateStatus::GATE_NOT_SET: + return "GATE_NOT_SET"; + case GateStatus::GATE_SET: + return "GATE_SET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> GateStatus EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetGateStatusValues(), 2, "GateStatus", value)); -} - -const StringUtil::EnumStringLiteral *GetHLLStorageTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(HLLStorageType::HLL_V1), "HLL_V1" }, - { static_cast(HLLStorageType::HLL_V2), "HLL_V2" } - }; - return values; + if (StringUtil::Equals(value, "GATE_NOT_SET")) { + return GateStatus::GATE_NOT_SET; + } + if (StringUtil::Equals(value, "GATE_SET")) { + return GateStatus::GATE_SET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(HLLStorageType value) { - return StringUtil::EnumToString(GetHLLStorageTypeValues(), 2, "HLLStorageType", static_cast(value)); + switch(value) { + case HLLStorageType::HLL_V1: + return "HLL_V1"; + case HLLStorageType::HLL_V2: + return "HLL_V2"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> HLLStorageType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetHLLStorageTypeValues(), 2, "HLLStorageType", value)); -} - -const StringUtil::EnumStringLiteral *GetIndexConstraintTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(IndexConstraintType::NONE), "NONE" }, - { static_cast(IndexConstraintType::UNIQUE), "UNIQUE" }, - { static_cast(IndexConstraintType::PRIMARY), "PRIMARY" }, - { static_cast(IndexConstraintType::FOREIGN), "FOREIGN" } - }; - return values; + if (StringUtil::Equals(value, "HLL_V1")) { + return HLLStorageType::HLL_V1; + } + if (StringUtil::Equals(value, "HLL_V2")) { + return HLLStorageType::HLL_V2; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(IndexConstraintType value) { - return StringUtil::EnumToString(GetIndexConstraintTypeValues(), 4, "IndexConstraintType", static_cast(value)); + switch(value) { + case IndexConstraintType::NONE: + return "NONE"; + case IndexConstraintType::UNIQUE: + return "UNIQUE"; + case IndexConstraintType::PRIMARY: + return "PRIMARY"; + case IndexConstraintType::FOREIGN: + return "FOREIGN"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> IndexConstraintType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetIndexConstraintTypeValues(), 4, "IndexConstraintType", value)); -} - -const StringUtil::EnumStringLiteral *GetInsertColumnOrderValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(InsertColumnOrder::INSERT_BY_POSITION), "INSERT_BY_POSITION" }, - { static_cast(InsertColumnOrder::INSERT_BY_NAME), "INSERT_BY_NAME" } - }; - return values; + if (StringUtil::Equals(value, "NONE")) { + return IndexConstraintType::NONE; + } + if (StringUtil::Equals(value, "UNIQUE")) { + return IndexConstraintType::UNIQUE; + } + if (StringUtil::Equals(value, "PRIMARY")) { + return IndexConstraintType::PRIMARY; + } + if (StringUtil::Equals(value, "FOREIGN")) { + return IndexConstraintType::FOREIGN; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(InsertColumnOrder value) { - return StringUtil::EnumToString(GetInsertColumnOrderValues(), 2, "InsertColumnOrder", static_cast(value)); + switch(value) { + case InsertColumnOrder::INSERT_BY_POSITION: + return "INSERT_BY_POSITION"; + case InsertColumnOrder::INSERT_BY_NAME: + return "INSERT_BY_NAME"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> InsertColumnOrder EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetInsertColumnOrderValues(), 2, "InsertColumnOrder", value)); -} - -const StringUtil::EnumStringLiteral *GetInterruptModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(InterruptMode::NO_INTERRUPTS), "NO_INTERRUPTS" }, - { static_cast(InterruptMode::TASK), "TASK" }, - { static_cast(InterruptMode::BLOCKING), "BLOCKING" } - }; - return values; + if (StringUtil::Equals(value, "INSERT_BY_POSITION")) { + return InsertColumnOrder::INSERT_BY_POSITION; + } + if (StringUtil::Equals(value, "INSERT_BY_NAME")) { + return InsertColumnOrder::INSERT_BY_NAME; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(InterruptMode value) { - return StringUtil::EnumToString(GetInterruptModeValues(), 3, "InterruptMode", static_cast(value)); + switch(value) { + case InterruptMode::NO_INTERRUPTS: + return "NO_INTERRUPTS"; + case InterruptMode::TASK: + return "TASK"; + case InterruptMode::BLOCKING: + return "BLOCKING"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> InterruptMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetInterruptModeValues(), 3, "InterruptMode", value)); -} - -const StringUtil::EnumStringLiteral *GetJoinRefTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(JoinRefType::REGULAR), "REGULAR" }, - { static_cast(JoinRefType::NATURAL), "NATURAL" }, - { static_cast(JoinRefType::CROSS), "CROSS" }, - { static_cast(JoinRefType::POSITIONAL), "POSITIONAL" }, - { static_cast(JoinRefType::ASOF), "ASOF" }, - { static_cast(JoinRefType::DEPENDENT), "DEPENDENT" } - }; - return values; + if (StringUtil::Equals(value, "NO_INTERRUPTS")) { + return InterruptMode::NO_INTERRUPTS; + } + if (StringUtil::Equals(value, "TASK")) { + return InterruptMode::TASK; + } + if (StringUtil::Equals(value, "BLOCKING")) { + return InterruptMode::BLOCKING; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(JoinRefType value) { - return StringUtil::EnumToString(GetJoinRefTypeValues(), 6, "JoinRefType", static_cast(value)); + switch(value) { + case JoinRefType::REGULAR: + return "REGULAR"; + case JoinRefType::NATURAL: + return "NATURAL"; + case JoinRefType::CROSS: + return "CROSS"; + case JoinRefType::POSITIONAL: + return "POSITIONAL"; + case JoinRefType::ASOF: + return "ASOF"; + case JoinRefType::DEPENDENT: + return "DEPENDENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> JoinRefType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetJoinRefTypeValues(), 6, "JoinRefType", value)); -} - -const StringUtil::EnumStringLiteral *GetJoinTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(JoinType::INVALID), "INVALID" }, - { static_cast(JoinType::LEFT), "LEFT" }, - { static_cast(JoinType::RIGHT), "RIGHT" }, - { static_cast(JoinType::INNER), "INNER" }, - { static_cast(JoinType::OUTER), "FULL" }, - { static_cast(JoinType::SEMI), "SEMI" }, - { static_cast(JoinType::ANTI), "ANTI" }, - { static_cast(JoinType::MARK), "MARK" }, - { static_cast(JoinType::SINGLE), "SINGLE" }, - { static_cast(JoinType::RIGHT_SEMI), "RIGHT_SEMI" }, - { static_cast(JoinType::RIGHT_ANTI), "RIGHT_ANTI" } - }; - return values; + if (StringUtil::Equals(value, "REGULAR")) { + return JoinRefType::REGULAR; + } + if (StringUtil::Equals(value, "NATURAL")) { + return JoinRefType::NATURAL; + } + if (StringUtil::Equals(value, "CROSS")) { + return JoinRefType::CROSS; + } + if (StringUtil::Equals(value, "POSITIONAL")) { + return JoinRefType::POSITIONAL; + } + if (StringUtil::Equals(value, "ASOF")) { + return JoinRefType::ASOF; + } + if (StringUtil::Equals(value, "DEPENDENT")) { + return JoinRefType::DEPENDENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(JoinType value) { - return StringUtil::EnumToString(GetJoinTypeValues(), 11, "JoinType", static_cast(value)); + switch(value) { + case JoinType::INVALID: + return "INVALID"; + case JoinType::LEFT: + return "LEFT"; + case JoinType::RIGHT: + return "RIGHT"; + case JoinType::INNER: + return "INNER"; + case JoinType::OUTER: + return "FULL"; + case JoinType::SEMI: + return "SEMI"; + case JoinType::ANTI: + return "ANTI"; + case JoinType::MARK: + return "MARK"; + case JoinType::SINGLE: + return "SINGLE"; + case JoinType::RIGHT_SEMI: + return "RIGHT_SEMI"; + case JoinType::RIGHT_ANTI: + return "RIGHT_ANTI"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> JoinType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetJoinTypeValues(), 11, "JoinType", value)); -} - -const StringUtil::EnumStringLiteral *GetKeywordCategoryValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(KeywordCategory::KEYWORD_RESERVED), "KEYWORD_RESERVED" }, - { static_cast(KeywordCategory::KEYWORD_UNRESERVED), "KEYWORD_UNRESERVED" }, - { static_cast(KeywordCategory::KEYWORD_TYPE_FUNC), "KEYWORD_TYPE_FUNC" }, - { static_cast(KeywordCategory::KEYWORD_COL_NAME), "KEYWORD_COL_NAME" }, - { static_cast(KeywordCategory::KEYWORD_NONE), "KEYWORD_NONE" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return JoinType::INVALID; + } + if (StringUtil::Equals(value, "LEFT")) { + return JoinType::LEFT; + } + if (StringUtil::Equals(value, "RIGHT")) { + return JoinType::RIGHT; + } + if (StringUtil::Equals(value, "INNER")) { + return JoinType::INNER; + } + if (StringUtil::Equals(value, "FULL")) { + return JoinType::OUTER; + } + if (StringUtil::Equals(value, "SEMI")) { + return JoinType::SEMI; + } + if (StringUtil::Equals(value, "ANTI")) { + return JoinType::ANTI; + } + if (StringUtil::Equals(value, "MARK")) { + return JoinType::MARK; + } + if (StringUtil::Equals(value, "SINGLE")) { + return JoinType::SINGLE; + } + if (StringUtil::Equals(value, "RIGHT_SEMI")) { + return JoinType::RIGHT_SEMI; + } + if (StringUtil::Equals(value, "RIGHT_ANTI")) { + return JoinType::RIGHT_ANTI; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(KeywordCategory value) { - return StringUtil::EnumToString(GetKeywordCategoryValues(), 5, "KeywordCategory", static_cast(value)); + switch(value) { + case KeywordCategory::KEYWORD_RESERVED: + return "KEYWORD_RESERVED"; + case KeywordCategory::KEYWORD_UNRESERVED: + return "KEYWORD_UNRESERVED"; + case KeywordCategory::KEYWORD_TYPE_FUNC: + return "KEYWORD_TYPE_FUNC"; + case KeywordCategory::KEYWORD_COL_NAME: + return "KEYWORD_COL_NAME"; + case KeywordCategory::KEYWORD_NONE: + return "KEYWORD_NONE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> KeywordCategory EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetKeywordCategoryValues(), 5, "KeywordCategory", value)); -} - -const StringUtil::EnumStringLiteral *GetLimitNodeTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(LimitNodeType::UNSET), "UNSET" }, - { static_cast(LimitNodeType::CONSTANT_VALUE), "CONSTANT_VALUE" }, - { static_cast(LimitNodeType::CONSTANT_PERCENTAGE), "CONSTANT_PERCENTAGE" }, - { static_cast(LimitNodeType::EXPRESSION_VALUE), "EXPRESSION_VALUE" }, - { static_cast(LimitNodeType::EXPRESSION_PERCENTAGE), "EXPRESSION_PERCENTAGE" } - }; - return values; + if (StringUtil::Equals(value, "KEYWORD_RESERVED")) { + return KeywordCategory::KEYWORD_RESERVED; + } + if (StringUtil::Equals(value, "KEYWORD_UNRESERVED")) { + return KeywordCategory::KEYWORD_UNRESERVED; + } + if (StringUtil::Equals(value, "KEYWORD_TYPE_FUNC")) { + return KeywordCategory::KEYWORD_TYPE_FUNC; + } + if (StringUtil::Equals(value, "KEYWORD_COL_NAME")) { + return KeywordCategory::KEYWORD_COL_NAME; + } + if (StringUtil::Equals(value, "KEYWORD_NONE")) { + return KeywordCategory::KEYWORD_NONE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(LimitNodeType value) { - return StringUtil::EnumToString(GetLimitNodeTypeValues(), 5, "LimitNodeType", static_cast(value)); + switch(value) { + case LimitNodeType::UNSET: + return "UNSET"; + case LimitNodeType::CONSTANT_VALUE: + return "CONSTANT_VALUE"; + case LimitNodeType::CONSTANT_PERCENTAGE: + return "CONSTANT_PERCENTAGE"; + case LimitNodeType::EXPRESSION_VALUE: + return "EXPRESSION_VALUE"; + case LimitNodeType::EXPRESSION_PERCENTAGE: + return "EXPRESSION_PERCENTAGE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> LimitNodeType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLimitNodeTypeValues(), 5, "LimitNodeType", value)); -} - -const StringUtil::EnumStringLiteral *GetLoadTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(LoadType::LOAD), "LOAD" }, - { static_cast(LoadType::INSTALL), "INSTALL" }, - { static_cast(LoadType::FORCE_INSTALL), "FORCE_INSTALL" } - }; - return values; + if (StringUtil::Equals(value, "UNSET")) { + return LimitNodeType::UNSET; + } + if (StringUtil::Equals(value, "CONSTANT_VALUE")) { + return LimitNodeType::CONSTANT_VALUE; + } + if (StringUtil::Equals(value, "CONSTANT_PERCENTAGE")) { + return LimitNodeType::CONSTANT_PERCENTAGE; + } + if (StringUtil::Equals(value, "EXPRESSION_VALUE")) { + return LimitNodeType::EXPRESSION_VALUE; + } + if (StringUtil::Equals(value, "EXPRESSION_PERCENTAGE")) { + return LimitNodeType::EXPRESSION_PERCENTAGE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(LoadType value) { - return StringUtil::EnumToString(GetLoadTypeValues(), 3, "LoadType", static_cast(value)); + switch(value) { + case LoadType::LOAD: + return "LOAD"; + case LoadType::INSTALL: + return "INSTALL"; + case LoadType::FORCE_INSTALL: + return "FORCE_INSTALL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> LoadType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLoadTypeValues(), 3, "LoadType", value)); -} - -const StringUtil::EnumStringLiteral *GetLogicalOperatorTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(LogicalOperatorType::LOGICAL_INVALID), "LOGICAL_INVALID" }, - { static_cast(LogicalOperatorType::LOGICAL_PROJECTION), "LOGICAL_PROJECTION" }, - { static_cast(LogicalOperatorType::LOGICAL_FILTER), "LOGICAL_FILTER" }, - { static_cast(LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY), "LOGICAL_AGGREGATE_AND_GROUP_BY" }, - { static_cast(LogicalOperatorType::LOGICAL_WINDOW), "LOGICAL_WINDOW" }, - { static_cast(LogicalOperatorType::LOGICAL_UNNEST), "LOGICAL_UNNEST" }, - { static_cast(LogicalOperatorType::LOGICAL_LIMIT), "LOGICAL_LIMIT" }, - { static_cast(LogicalOperatorType::LOGICAL_ORDER_BY), "LOGICAL_ORDER_BY" }, - { static_cast(LogicalOperatorType::LOGICAL_TOP_N), "LOGICAL_TOP_N" }, - { static_cast(LogicalOperatorType::LOGICAL_COPY_TO_FILE), "LOGICAL_COPY_TO_FILE" }, - { static_cast(LogicalOperatorType::LOGICAL_DISTINCT), "LOGICAL_DISTINCT" }, - { static_cast(LogicalOperatorType::LOGICAL_SAMPLE), "LOGICAL_SAMPLE" }, - { static_cast(LogicalOperatorType::LOGICAL_PIVOT), "LOGICAL_PIVOT" }, - { static_cast(LogicalOperatorType::LOGICAL_COPY_DATABASE), "LOGICAL_COPY_DATABASE" }, - { static_cast(LogicalOperatorType::LOGICAL_GET), "LOGICAL_GET" }, - { static_cast(LogicalOperatorType::LOGICAL_CHUNK_GET), "LOGICAL_CHUNK_GET" }, - { static_cast(LogicalOperatorType::LOGICAL_DELIM_GET), "LOGICAL_DELIM_GET" }, - { static_cast(LogicalOperatorType::LOGICAL_EXPRESSION_GET), "LOGICAL_EXPRESSION_GET" }, - { static_cast(LogicalOperatorType::LOGICAL_DUMMY_SCAN), "LOGICAL_DUMMY_SCAN" }, - { static_cast(LogicalOperatorType::LOGICAL_EMPTY_RESULT), "LOGICAL_EMPTY_RESULT" }, - { static_cast(LogicalOperatorType::LOGICAL_CTE_REF), "LOGICAL_CTE_REF" }, - { static_cast(LogicalOperatorType::LOGICAL_JOIN), "LOGICAL_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_DELIM_JOIN), "LOGICAL_DELIM_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_COMPARISON_JOIN), "LOGICAL_COMPARISON_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_ANY_JOIN), "LOGICAL_ANY_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_CROSS_PRODUCT), "LOGICAL_CROSS_PRODUCT" }, - { static_cast(LogicalOperatorType::LOGICAL_POSITIONAL_JOIN), "LOGICAL_POSITIONAL_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_ASOF_JOIN), "LOGICAL_ASOF_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_DEPENDENT_JOIN), "LOGICAL_DEPENDENT_JOIN" }, - { static_cast(LogicalOperatorType::LOGICAL_UNION), "LOGICAL_UNION" }, - { static_cast(LogicalOperatorType::LOGICAL_EXCEPT), "LOGICAL_EXCEPT" }, - { static_cast(LogicalOperatorType::LOGICAL_INTERSECT), "LOGICAL_INTERSECT" }, - { static_cast(LogicalOperatorType::LOGICAL_RECURSIVE_CTE), "LOGICAL_RECURSIVE_CTE" }, - { static_cast(LogicalOperatorType::LOGICAL_MATERIALIZED_CTE), "LOGICAL_MATERIALIZED_CTE" }, - { static_cast(LogicalOperatorType::LOGICAL_INSERT), "LOGICAL_INSERT" }, - { static_cast(LogicalOperatorType::LOGICAL_DELETE), "LOGICAL_DELETE" }, - { static_cast(LogicalOperatorType::LOGICAL_UPDATE), "LOGICAL_UPDATE" }, - { static_cast(LogicalOperatorType::LOGICAL_ALTER), "LOGICAL_ALTER" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_TABLE), "LOGICAL_CREATE_TABLE" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_INDEX), "LOGICAL_CREATE_INDEX" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_SEQUENCE), "LOGICAL_CREATE_SEQUENCE" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_VIEW), "LOGICAL_CREATE_VIEW" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_SCHEMA), "LOGICAL_CREATE_SCHEMA" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_MACRO), "LOGICAL_CREATE_MACRO" }, - { static_cast(LogicalOperatorType::LOGICAL_DROP), "LOGICAL_DROP" }, - { static_cast(LogicalOperatorType::LOGICAL_PRAGMA), "LOGICAL_PRAGMA" }, - { static_cast(LogicalOperatorType::LOGICAL_TRANSACTION), "LOGICAL_TRANSACTION" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_TYPE), "LOGICAL_CREATE_TYPE" }, - { static_cast(LogicalOperatorType::LOGICAL_ATTACH), "LOGICAL_ATTACH" }, - { static_cast(LogicalOperatorType::LOGICAL_DETACH), "LOGICAL_DETACH" }, - { static_cast(LogicalOperatorType::LOGICAL_EXPLAIN), "LOGICAL_EXPLAIN" }, - { static_cast(LogicalOperatorType::LOGICAL_PREPARE), "LOGICAL_PREPARE" }, - { static_cast(LogicalOperatorType::LOGICAL_EXECUTE), "LOGICAL_EXECUTE" }, - { static_cast(LogicalOperatorType::LOGICAL_EXPORT), "LOGICAL_EXPORT" }, - { static_cast(LogicalOperatorType::LOGICAL_VACUUM), "LOGICAL_VACUUM" }, - { static_cast(LogicalOperatorType::LOGICAL_SET), "LOGICAL_SET" }, - { static_cast(LogicalOperatorType::LOGICAL_LOAD), "LOGICAL_LOAD" }, - { static_cast(LogicalOperatorType::LOGICAL_RESET), "LOGICAL_RESET" }, - { static_cast(LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS), "LOGICAL_UPDATE_EXTENSIONS" }, - { static_cast(LogicalOperatorType::LOGICAL_CREATE_SECRET), "LOGICAL_CREATE_SECRET" }, - { static_cast(LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR), "LOGICAL_EXTENSION_OPERATOR" } - }; - return values; + if (StringUtil::Equals(value, "LOAD")) { + return LoadType::LOAD; + } + if (StringUtil::Equals(value, "INSTALL")) { + return LoadType::INSTALL; + } + if (StringUtil::Equals(value, "FORCE_INSTALL")) { + return LoadType::FORCE_INSTALL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(LogicalOperatorType value) { - return StringUtil::EnumToString(GetLogicalOperatorTypeValues(), 61, "LogicalOperatorType", static_cast(value)); + switch(value) { + case LogicalOperatorType::LOGICAL_INVALID: + return "LOGICAL_INVALID"; + case LogicalOperatorType::LOGICAL_PROJECTION: + return "LOGICAL_PROJECTION"; + case LogicalOperatorType::LOGICAL_FILTER: + return "LOGICAL_FILTER"; + case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: + return "LOGICAL_AGGREGATE_AND_GROUP_BY"; + case LogicalOperatorType::LOGICAL_WINDOW: + return "LOGICAL_WINDOW"; + case LogicalOperatorType::LOGICAL_UNNEST: + return "LOGICAL_UNNEST"; + case LogicalOperatorType::LOGICAL_LIMIT: + return "LOGICAL_LIMIT"; + case LogicalOperatorType::LOGICAL_ORDER_BY: + return "LOGICAL_ORDER_BY"; + case LogicalOperatorType::LOGICAL_TOP_N: + return "LOGICAL_TOP_N"; + case LogicalOperatorType::LOGICAL_COPY_TO_FILE: + return "LOGICAL_COPY_TO_FILE"; + case LogicalOperatorType::LOGICAL_DISTINCT: + return "LOGICAL_DISTINCT"; + case LogicalOperatorType::LOGICAL_SAMPLE: + return "LOGICAL_SAMPLE"; + case LogicalOperatorType::LOGICAL_PIVOT: + return "LOGICAL_PIVOT"; + case LogicalOperatorType::LOGICAL_COPY_DATABASE: + return "LOGICAL_COPY_DATABASE"; + case LogicalOperatorType::LOGICAL_GET: + return "LOGICAL_GET"; + case LogicalOperatorType::LOGICAL_CHUNK_GET: + return "LOGICAL_CHUNK_GET"; + case LogicalOperatorType::LOGICAL_DELIM_GET: + return "LOGICAL_DELIM_GET"; + case LogicalOperatorType::LOGICAL_EXPRESSION_GET: + return "LOGICAL_EXPRESSION_GET"; + case LogicalOperatorType::LOGICAL_DUMMY_SCAN: + return "LOGICAL_DUMMY_SCAN"; + case LogicalOperatorType::LOGICAL_EMPTY_RESULT: + return "LOGICAL_EMPTY_RESULT"; + case LogicalOperatorType::LOGICAL_CTE_REF: + return "LOGICAL_CTE_REF"; + case LogicalOperatorType::LOGICAL_JOIN: + return "LOGICAL_JOIN"; + case LogicalOperatorType::LOGICAL_DELIM_JOIN: + return "LOGICAL_DELIM_JOIN"; + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + return "LOGICAL_COMPARISON_JOIN"; + case LogicalOperatorType::LOGICAL_ANY_JOIN: + return "LOGICAL_ANY_JOIN"; + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: + return "LOGICAL_CROSS_PRODUCT"; + case LogicalOperatorType::LOGICAL_POSITIONAL_JOIN: + return "LOGICAL_POSITIONAL_JOIN"; + case LogicalOperatorType::LOGICAL_ASOF_JOIN: + return "LOGICAL_ASOF_JOIN"; + case LogicalOperatorType::LOGICAL_DEPENDENT_JOIN: + return "LOGICAL_DEPENDENT_JOIN"; + case LogicalOperatorType::LOGICAL_UNION: + return "LOGICAL_UNION"; + case LogicalOperatorType::LOGICAL_EXCEPT: + return "LOGICAL_EXCEPT"; + case LogicalOperatorType::LOGICAL_INTERSECT: + return "LOGICAL_INTERSECT"; + case LogicalOperatorType::LOGICAL_RECURSIVE_CTE: + return "LOGICAL_RECURSIVE_CTE"; + case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: + return "LOGICAL_MATERIALIZED_CTE"; + case LogicalOperatorType::LOGICAL_INSERT: + return "LOGICAL_INSERT"; + case LogicalOperatorType::LOGICAL_DELETE: + return "LOGICAL_DELETE"; + case LogicalOperatorType::LOGICAL_UPDATE: + return "LOGICAL_UPDATE"; + case LogicalOperatorType::LOGICAL_ALTER: + return "LOGICAL_ALTER"; + case LogicalOperatorType::LOGICAL_CREATE_TABLE: + return "LOGICAL_CREATE_TABLE"; + case LogicalOperatorType::LOGICAL_CREATE_INDEX: + return "LOGICAL_CREATE_INDEX"; + case LogicalOperatorType::LOGICAL_CREATE_SEQUENCE: + return "LOGICAL_CREATE_SEQUENCE"; + case LogicalOperatorType::LOGICAL_CREATE_VIEW: + return "LOGICAL_CREATE_VIEW"; + case LogicalOperatorType::LOGICAL_CREATE_SCHEMA: + return "LOGICAL_CREATE_SCHEMA"; + case LogicalOperatorType::LOGICAL_CREATE_MACRO: + return "LOGICAL_CREATE_MACRO"; + case LogicalOperatorType::LOGICAL_DROP: + return "LOGICAL_DROP"; + case LogicalOperatorType::LOGICAL_PRAGMA: + return "LOGICAL_PRAGMA"; + case LogicalOperatorType::LOGICAL_TRANSACTION: + return "LOGICAL_TRANSACTION"; + case LogicalOperatorType::LOGICAL_CREATE_TYPE: + return "LOGICAL_CREATE_TYPE"; + case LogicalOperatorType::LOGICAL_ATTACH: + return "LOGICAL_ATTACH"; + case LogicalOperatorType::LOGICAL_DETACH: + return "LOGICAL_DETACH"; + case LogicalOperatorType::LOGICAL_EXPLAIN: + return "LOGICAL_EXPLAIN"; + case LogicalOperatorType::LOGICAL_PREPARE: + return "LOGICAL_PREPARE"; + case LogicalOperatorType::LOGICAL_EXECUTE: + return "LOGICAL_EXECUTE"; + case LogicalOperatorType::LOGICAL_EXPORT: + return "LOGICAL_EXPORT"; + case LogicalOperatorType::LOGICAL_VACUUM: + return "LOGICAL_VACUUM"; + case LogicalOperatorType::LOGICAL_SET: + return "LOGICAL_SET"; + case LogicalOperatorType::LOGICAL_LOAD: + return "LOGICAL_LOAD"; + case LogicalOperatorType::LOGICAL_RESET: + return "LOGICAL_RESET"; + case LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS: + return "LOGICAL_UPDATE_EXTENSIONS"; + case LogicalOperatorType::LOGICAL_CREATE_SECRET: + return "LOGICAL_CREATE_SECRET"; + case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: + return "LOGICAL_EXTENSION_OPERATOR"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> LogicalOperatorType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLogicalOperatorTypeValues(), 61, "LogicalOperatorType", value)); -} - -const StringUtil::EnumStringLiteral *GetLogicalTypeIdValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(LogicalTypeId::INVALID), "INVALID" }, - { static_cast(LogicalTypeId::SQLNULL), "NULL" }, - { static_cast(LogicalTypeId::UNKNOWN), "UNKNOWN" }, - { static_cast(LogicalTypeId::ANY), "ANY" }, - { static_cast(LogicalTypeId::USER), "USER" }, - { static_cast(LogicalTypeId::BOOLEAN), "BOOLEAN" }, - { static_cast(LogicalTypeId::TINYINT), "TINYINT" }, - { static_cast(LogicalTypeId::SMALLINT), "SMALLINT" }, - { static_cast(LogicalTypeId::INTEGER), "INTEGER" }, - { static_cast(LogicalTypeId::BIGINT), "BIGINT" }, - { static_cast(LogicalTypeId::DATE), "DATE" }, - { static_cast(LogicalTypeId::TIME), "TIME" }, - { static_cast(LogicalTypeId::TIMESTAMP_SEC), "TIMESTAMP_S" }, - { static_cast(LogicalTypeId::TIMESTAMP_MS), "TIMESTAMP_MS" }, - { static_cast(LogicalTypeId::TIMESTAMP), "TIMESTAMP" }, - { static_cast(LogicalTypeId::TIMESTAMP_NS), "TIMESTAMP_NS" }, - { static_cast(LogicalTypeId::DECIMAL), "DECIMAL" }, - { static_cast(LogicalTypeId::FLOAT), "FLOAT" }, - { static_cast(LogicalTypeId::DOUBLE), "DOUBLE" }, - { static_cast(LogicalTypeId::CHAR), "CHAR" }, - { static_cast(LogicalTypeId::VARCHAR), "VARCHAR" }, - { static_cast(LogicalTypeId::BLOB), "BLOB" }, - { static_cast(LogicalTypeId::INTERVAL), "INTERVAL" }, - { static_cast(LogicalTypeId::UTINYINT), "UTINYINT" }, - { static_cast(LogicalTypeId::USMALLINT), "USMALLINT" }, - { static_cast(LogicalTypeId::UINTEGER), "UINTEGER" }, - { static_cast(LogicalTypeId::UBIGINT), "UBIGINT" }, - { static_cast(LogicalTypeId::TIMESTAMP_TZ), "TIMESTAMP WITH TIME ZONE" }, - { static_cast(LogicalTypeId::TIME_TZ), "TIME WITH TIME ZONE" }, - { static_cast(LogicalTypeId::BIT), "BIT" }, - { static_cast(LogicalTypeId::STRING_LITERAL), "STRING_LITERAL" }, - { static_cast(LogicalTypeId::INTEGER_LITERAL), "INTEGER_LITERAL" }, - { static_cast(LogicalTypeId::VARINT), "VARINT" }, - { static_cast(LogicalTypeId::UHUGEINT), "UHUGEINT" }, - { static_cast(LogicalTypeId::HUGEINT), "HUGEINT" }, - { static_cast(LogicalTypeId::POINTER), "POINTER" }, - { static_cast(LogicalTypeId::VALIDITY), "VALIDITY" }, - { static_cast(LogicalTypeId::UUID), "UUID" }, - { static_cast(LogicalTypeId::STRUCT), "STRUCT" }, - { static_cast(LogicalTypeId::LIST), "LIST" }, - { static_cast(LogicalTypeId::MAP), "MAP" }, - { static_cast(LogicalTypeId::TABLE), "TABLE" }, - { static_cast(LogicalTypeId::ENUM), "ENUM" }, - { static_cast(LogicalTypeId::AGGREGATE_STATE), "AGGREGATE_STATE" }, - { static_cast(LogicalTypeId::LAMBDA), "LAMBDA" }, - { static_cast(LogicalTypeId::UNION), "UNION" }, - { static_cast(LogicalTypeId::ARRAY), "ARRAY" } - }; - return values; + if (StringUtil::Equals(value, "LOGICAL_INVALID")) { + return LogicalOperatorType::LOGICAL_INVALID; + } + if (StringUtil::Equals(value, "LOGICAL_PROJECTION")) { + return LogicalOperatorType::LOGICAL_PROJECTION; + } + if (StringUtil::Equals(value, "LOGICAL_FILTER")) { + return LogicalOperatorType::LOGICAL_FILTER; + } + if (StringUtil::Equals(value, "LOGICAL_AGGREGATE_AND_GROUP_BY")) { + return LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY; + } + if (StringUtil::Equals(value, "LOGICAL_WINDOW")) { + return LogicalOperatorType::LOGICAL_WINDOW; + } + if (StringUtil::Equals(value, "LOGICAL_UNNEST")) { + return LogicalOperatorType::LOGICAL_UNNEST; + } + if (StringUtil::Equals(value, "LOGICAL_LIMIT")) { + return LogicalOperatorType::LOGICAL_LIMIT; + } + if (StringUtil::Equals(value, "LOGICAL_ORDER_BY")) { + return LogicalOperatorType::LOGICAL_ORDER_BY; + } + if (StringUtil::Equals(value, "LOGICAL_TOP_N")) { + return LogicalOperatorType::LOGICAL_TOP_N; + } + if (StringUtil::Equals(value, "LOGICAL_COPY_TO_FILE")) { + return LogicalOperatorType::LOGICAL_COPY_TO_FILE; + } + if (StringUtil::Equals(value, "LOGICAL_DISTINCT")) { + return LogicalOperatorType::LOGICAL_DISTINCT; + } + if (StringUtil::Equals(value, "LOGICAL_SAMPLE")) { + return LogicalOperatorType::LOGICAL_SAMPLE; + } + if (StringUtil::Equals(value, "LOGICAL_PIVOT")) { + return LogicalOperatorType::LOGICAL_PIVOT; + } + if (StringUtil::Equals(value, "LOGICAL_COPY_DATABASE")) { + return LogicalOperatorType::LOGICAL_COPY_DATABASE; + } + if (StringUtil::Equals(value, "LOGICAL_GET")) { + return LogicalOperatorType::LOGICAL_GET; + } + if (StringUtil::Equals(value, "LOGICAL_CHUNK_GET")) { + return LogicalOperatorType::LOGICAL_CHUNK_GET; + } + if (StringUtil::Equals(value, "LOGICAL_DELIM_GET")) { + return LogicalOperatorType::LOGICAL_DELIM_GET; + } + if (StringUtil::Equals(value, "LOGICAL_EXPRESSION_GET")) { + return LogicalOperatorType::LOGICAL_EXPRESSION_GET; + } + if (StringUtil::Equals(value, "LOGICAL_DUMMY_SCAN")) { + return LogicalOperatorType::LOGICAL_DUMMY_SCAN; + } + if (StringUtil::Equals(value, "LOGICAL_EMPTY_RESULT")) { + return LogicalOperatorType::LOGICAL_EMPTY_RESULT; + } + if (StringUtil::Equals(value, "LOGICAL_CTE_REF")) { + return LogicalOperatorType::LOGICAL_CTE_REF; + } + if (StringUtil::Equals(value, "LOGICAL_JOIN")) { + return LogicalOperatorType::LOGICAL_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_DELIM_JOIN")) { + return LogicalOperatorType::LOGICAL_DELIM_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_COMPARISON_JOIN")) { + return LogicalOperatorType::LOGICAL_COMPARISON_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_ANY_JOIN")) { + return LogicalOperatorType::LOGICAL_ANY_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_CROSS_PRODUCT")) { + return LogicalOperatorType::LOGICAL_CROSS_PRODUCT; + } + if (StringUtil::Equals(value, "LOGICAL_POSITIONAL_JOIN")) { + return LogicalOperatorType::LOGICAL_POSITIONAL_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_ASOF_JOIN")) { + return LogicalOperatorType::LOGICAL_ASOF_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_DEPENDENT_JOIN")) { + return LogicalOperatorType::LOGICAL_DEPENDENT_JOIN; + } + if (StringUtil::Equals(value, "LOGICAL_UNION")) { + return LogicalOperatorType::LOGICAL_UNION; + } + if (StringUtil::Equals(value, "LOGICAL_EXCEPT")) { + return LogicalOperatorType::LOGICAL_EXCEPT; + } + if (StringUtil::Equals(value, "LOGICAL_INTERSECT")) { + return LogicalOperatorType::LOGICAL_INTERSECT; + } + if (StringUtil::Equals(value, "LOGICAL_RECURSIVE_CTE")) { + return LogicalOperatorType::LOGICAL_RECURSIVE_CTE; + } + if (StringUtil::Equals(value, "LOGICAL_MATERIALIZED_CTE")) { + return LogicalOperatorType::LOGICAL_MATERIALIZED_CTE; + } + if (StringUtil::Equals(value, "LOGICAL_INSERT")) { + return LogicalOperatorType::LOGICAL_INSERT; + } + if (StringUtil::Equals(value, "LOGICAL_DELETE")) { + return LogicalOperatorType::LOGICAL_DELETE; + } + if (StringUtil::Equals(value, "LOGICAL_UPDATE")) { + return LogicalOperatorType::LOGICAL_UPDATE; + } + if (StringUtil::Equals(value, "LOGICAL_ALTER")) { + return LogicalOperatorType::LOGICAL_ALTER; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_TABLE")) { + return LogicalOperatorType::LOGICAL_CREATE_TABLE; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_INDEX")) { + return LogicalOperatorType::LOGICAL_CREATE_INDEX; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_SEQUENCE")) { + return LogicalOperatorType::LOGICAL_CREATE_SEQUENCE; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_VIEW")) { + return LogicalOperatorType::LOGICAL_CREATE_VIEW; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_SCHEMA")) { + return LogicalOperatorType::LOGICAL_CREATE_SCHEMA; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_MACRO")) { + return LogicalOperatorType::LOGICAL_CREATE_MACRO; + } + if (StringUtil::Equals(value, "LOGICAL_DROP")) { + return LogicalOperatorType::LOGICAL_DROP; + } + if (StringUtil::Equals(value, "LOGICAL_PRAGMA")) { + return LogicalOperatorType::LOGICAL_PRAGMA; + } + if (StringUtil::Equals(value, "LOGICAL_TRANSACTION")) { + return LogicalOperatorType::LOGICAL_TRANSACTION; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_TYPE")) { + return LogicalOperatorType::LOGICAL_CREATE_TYPE; + } + if (StringUtil::Equals(value, "LOGICAL_ATTACH")) { + return LogicalOperatorType::LOGICAL_ATTACH; + } + if (StringUtil::Equals(value, "LOGICAL_DETACH")) { + return LogicalOperatorType::LOGICAL_DETACH; + } + if (StringUtil::Equals(value, "LOGICAL_EXPLAIN")) { + return LogicalOperatorType::LOGICAL_EXPLAIN; + } + if (StringUtil::Equals(value, "LOGICAL_PREPARE")) { + return LogicalOperatorType::LOGICAL_PREPARE; + } + if (StringUtil::Equals(value, "LOGICAL_EXECUTE")) { + return LogicalOperatorType::LOGICAL_EXECUTE; + } + if (StringUtil::Equals(value, "LOGICAL_EXPORT")) { + return LogicalOperatorType::LOGICAL_EXPORT; + } + if (StringUtil::Equals(value, "LOGICAL_VACUUM")) { + return LogicalOperatorType::LOGICAL_VACUUM; + } + if (StringUtil::Equals(value, "LOGICAL_SET")) { + return LogicalOperatorType::LOGICAL_SET; + } + if (StringUtil::Equals(value, "LOGICAL_LOAD")) { + return LogicalOperatorType::LOGICAL_LOAD; + } + if (StringUtil::Equals(value, "LOGICAL_RESET")) { + return LogicalOperatorType::LOGICAL_RESET; + } + if (StringUtil::Equals(value, "LOGICAL_UPDATE_EXTENSIONS")) { + return LogicalOperatorType::LOGICAL_UPDATE_EXTENSIONS; + } + if (StringUtil::Equals(value, "LOGICAL_CREATE_SECRET")) { + return LogicalOperatorType::LOGICAL_CREATE_SECRET; + } + if (StringUtil::Equals(value, "LOGICAL_EXTENSION_OPERATOR")) { + return LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(LogicalTypeId value) { - return StringUtil::EnumToString(GetLogicalTypeIdValues(), 47, "LogicalTypeId", static_cast(value)); + switch(value) { + case LogicalTypeId::INVALID: + return "INVALID"; + case LogicalTypeId::SQLNULL: + return "NULL"; + case LogicalTypeId::UNKNOWN: + return "UNKNOWN"; + case LogicalTypeId::ANY: + return "ANY"; + case LogicalTypeId::USER: + return "USER"; + case LogicalTypeId::BOOLEAN: + return "BOOLEAN"; + case LogicalTypeId::TINYINT: + return "TINYINT"; + case LogicalTypeId::SMALLINT: + return "SMALLINT"; + case LogicalTypeId::INTEGER: + return "INTEGER"; + case LogicalTypeId::BIGINT: + return "BIGINT"; + case LogicalTypeId::DATE: + return "DATE"; + case LogicalTypeId::TIME: + return "TIME"; + case LogicalTypeId::TIMESTAMP_SEC: + return "TIMESTAMP_S"; + case LogicalTypeId::TIMESTAMP_MS: + return "TIMESTAMP_MS"; + case LogicalTypeId::TIMESTAMP: + return "TIMESTAMP"; + case LogicalTypeId::TIMESTAMP_NS: + return "TIMESTAMP_NS"; + case LogicalTypeId::DECIMAL: + return "DECIMAL"; + case LogicalTypeId::FLOAT: + return "FLOAT"; + case LogicalTypeId::DOUBLE: + return "DOUBLE"; + case LogicalTypeId::CHAR: + return "CHAR"; + case LogicalTypeId::VARCHAR: + return "VARCHAR"; + case LogicalTypeId::BLOB: + return "BLOB"; + case LogicalTypeId::INTERVAL: + return "INTERVAL"; + case LogicalTypeId::UTINYINT: + return "UTINYINT"; + case LogicalTypeId::USMALLINT: + return "USMALLINT"; + case LogicalTypeId::UINTEGER: + return "UINTEGER"; + case LogicalTypeId::UBIGINT: + return "UBIGINT"; + case LogicalTypeId::TIMESTAMP_TZ: + return "TIMESTAMP WITH TIME ZONE"; + case LogicalTypeId::TIME_TZ: + return "TIME WITH TIME ZONE"; + case LogicalTypeId::BIT: + return "BIT"; + case LogicalTypeId::STRING_LITERAL: + return "STRING_LITERAL"; + case LogicalTypeId::INTEGER_LITERAL: + return "INTEGER_LITERAL"; + case LogicalTypeId::VARINT: + return "VARINT"; + case LogicalTypeId::UHUGEINT: + return "UHUGEINT"; + case LogicalTypeId::HUGEINT: + return "HUGEINT"; + case LogicalTypeId::POINTER: + return "POINTER"; + case LogicalTypeId::VALIDITY: + return "VALIDITY"; + case LogicalTypeId::UUID: + return "UUID"; + case LogicalTypeId::STRUCT: + return "STRUCT"; + case LogicalTypeId::LIST: + return "LIST"; + case LogicalTypeId::MAP: + return "MAP"; + case LogicalTypeId::TABLE: + return "TABLE"; + case LogicalTypeId::ENUM: + return "ENUM"; + case LogicalTypeId::AGGREGATE_STATE: + return "AGGREGATE_STATE"; + case LogicalTypeId::LAMBDA: + return "LAMBDA"; + case LogicalTypeId::UNION: + return "UNION"; + case LogicalTypeId::ARRAY: + return "ARRAY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> LogicalTypeId EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLogicalTypeIdValues(), 47, "LogicalTypeId", value)); -} - -const StringUtil::EnumStringLiteral *GetLookupResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(LookupResultType::LOOKUP_MISS), "LOOKUP_MISS" }, - { static_cast(LookupResultType::LOOKUP_HIT), "LOOKUP_HIT" }, - { static_cast(LookupResultType::LOOKUP_NULL), "LOOKUP_NULL" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return LogicalTypeId::INVALID; + } + if (StringUtil::Equals(value, "NULL")) { + return LogicalTypeId::SQLNULL; + } + if (StringUtil::Equals(value, "UNKNOWN")) { + return LogicalTypeId::UNKNOWN; + } + if (StringUtil::Equals(value, "ANY")) { + return LogicalTypeId::ANY; + } + if (StringUtil::Equals(value, "USER")) { + return LogicalTypeId::USER; + } + if (StringUtil::Equals(value, "BOOLEAN")) { + return LogicalTypeId::BOOLEAN; + } + if (StringUtil::Equals(value, "TINYINT")) { + return LogicalTypeId::TINYINT; + } + if (StringUtil::Equals(value, "SMALLINT")) { + return LogicalTypeId::SMALLINT; + } + if (StringUtil::Equals(value, "INTEGER")) { + return LogicalTypeId::INTEGER; + } + if (StringUtil::Equals(value, "BIGINT")) { + return LogicalTypeId::BIGINT; + } + if (StringUtil::Equals(value, "DATE")) { + return LogicalTypeId::DATE; + } + if (StringUtil::Equals(value, "TIME")) { + return LogicalTypeId::TIME; + } + if (StringUtil::Equals(value, "TIMESTAMP_S")) { + return LogicalTypeId::TIMESTAMP_SEC; + } + if (StringUtil::Equals(value, "TIMESTAMP_MS")) { + return LogicalTypeId::TIMESTAMP_MS; + } + if (StringUtil::Equals(value, "TIMESTAMP")) { + return LogicalTypeId::TIMESTAMP; + } + if (StringUtil::Equals(value, "TIMESTAMP_NS")) { + return LogicalTypeId::TIMESTAMP_NS; + } + if (StringUtil::Equals(value, "DECIMAL")) { + return LogicalTypeId::DECIMAL; + } + if (StringUtil::Equals(value, "FLOAT")) { + return LogicalTypeId::FLOAT; + } + if (StringUtil::Equals(value, "DOUBLE")) { + return LogicalTypeId::DOUBLE; + } + if (StringUtil::Equals(value, "CHAR")) { + return LogicalTypeId::CHAR; + } + if (StringUtil::Equals(value, "VARCHAR")) { + return LogicalTypeId::VARCHAR; + } + if (StringUtil::Equals(value, "BLOB")) { + return LogicalTypeId::BLOB; + } + if (StringUtil::Equals(value, "INTERVAL")) { + return LogicalTypeId::INTERVAL; + } + if (StringUtil::Equals(value, "UTINYINT")) { + return LogicalTypeId::UTINYINT; + } + if (StringUtil::Equals(value, "USMALLINT")) { + return LogicalTypeId::USMALLINT; + } + if (StringUtil::Equals(value, "UINTEGER")) { + return LogicalTypeId::UINTEGER; + } + if (StringUtil::Equals(value, "UBIGINT")) { + return LogicalTypeId::UBIGINT; + } + if (StringUtil::Equals(value, "TIMESTAMP WITH TIME ZONE")) { + return LogicalTypeId::TIMESTAMP_TZ; + } + if (StringUtil::Equals(value, "TIME WITH TIME ZONE")) { + return LogicalTypeId::TIME_TZ; + } + if (StringUtil::Equals(value, "BIT")) { + return LogicalTypeId::BIT; + } + if (StringUtil::Equals(value, "STRING_LITERAL")) { + return LogicalTypeId::STRING_LITERAL; + } + if (StringUtil::Equals(value, "INTEGER_LITERAL")) { + return LogicalTypeId::INTEGER_LITERAL; + } + if (StringUtil::Equals(value, "VARINT")) { + return LogicalTypeId::VARINT; + } + if (StringUtil::Equals(value, "UHUGEINT")) { + return LogicalTypeId::UHUGEINT; + } + if (StringUtil::Equals(value, "HUGEINT")) { + return LogicalTypeId::HUGEINT; + } + if (StringUtil::Equals(value, "POINTER")) { + return LogicalTypeId::POINTER; + } + if (StringUtil::Equals(value, "VALIDITY")) { + return LogicalTypeId::VALIDITY; + } + if (StringUtil::Equals(value, "UUID")) { + return LogicalTypeId::UUID; + } + if (StringUtil::Equals(value, "STRUCT")) { + return LogicalTypeId::STRUCT; + } + if (StringUtil::Equals(value, "LIST")) { + return LogicalTypeId::LIST; + } + if (StringUtil::Equals(value, "MAP")) { + return LogicalTypeId::MAP; + } + if (StringUtil::Equals(value, "TABLE")) { + return LogicalTypeId::TABLE; + } + if (StringUtil::Equals(value, "ENUM")) { + return LogicalTypeId::ENUM; + } + if (StringUtil::Equals(value, "AGGREGATE_STATE")) { + return LogicalTypeId::AGGREGATE_STATE; + } + if (StringUtil::Equals(value, "LAMBDA")) { + return LogicalTypeId::LAMBDA; + } + if (StringUtil::Equals(value, "UNION")) { + return LogicalTypeId::UNION; + } + if (StringUtil::Equals(value, "ARRAY")) { + return LogicalTypeId::ARRAY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(LookupResultType value) { - return StringUtil::EnumToString(GetLookupResultTypeValues(), 3, "LookupResultType", static_cast(value)); + switch(value) { + case LookupResultType::LOOKUP_MISS: + return "LOOKUP_MISS"; + case LookupResultType::LOOKUP_HIT: + return "LOOKUP_HIT"; + case LookupResultType::LOOKUP_NULL: + return "LOOKUP_NULL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> LookupResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetLookupResultTypeValues(), 3, "LookupResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetMacroTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(MacroType::VOID_MACRO), "VOID_MACRO" }, - { static_cast(MacroType::TABLE_MACRO), "TABLE_MACRO" }, - { static_cast(MacroType::SCALAR_MACRO), "SCALAR_MACRO" } - }; - return values; + if (StringUtil::Equals(value, "LOOKUP_MISS")) { + return LookupResultType::LOOKUP_MISS; + } + if (StringUtil::Equals(value, "LOOKUP_HIT")) { + return LookupResultType::LOOKUP_HIT; + } + if (StringUtil::Equals(value, "LOOKUP_NULL")) { + return LookupResultType::LOOKUP_NULL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(MacroType value) { - return StringUtil::EnumToString(GetMacroTypeValues(), 3, "MacroType", static_cast(value)); + switch(value) { + case MacroType::VOID_MACRO: + return "VOID_MACRO"; + case MacroType::TABLE_MACRO: + return "TABLE_MACRO"; + case MacroType::SCALAR_MACRO: + return "SCALAR_MACRO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> MacroType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMacroTypeValues(), 3, "MacroType", value)); -} - -const StringUtil::EnumStringLiteral *GetMapInvalidReasonValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(MapInvalidReason::VALID), "VALID" }, - { static_cast(MapInvalidReason::NULL_KEY), "NULL_KEY" }, - { static_cast(MapInvalidReason::DUPLICATE_KEY), "DUPLICATE_KEY" }, - { static_cast(MapInvalidReason::NOT_ALIGNED), "NOT_ALIGNED" }, - { static_cast(MapInvalidReason::INVALID_PARAMS), "INVALID_PARAMS" } - }; - return values; + if (StringUtil::Equals(value, "VOID_MACRO")) { + return MacroType::VOID_MACRO; + } + if (StringUtil::Equals(value, "TABLE_MACRO")) { + return MacroType::TABLE_MACRO; + } + if (StringUtil::Equals(value, "SCALAR_MACRO")) { + return MacroType::SCALAR_MACRO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(MapInvalidReason value) { - return StringUtil::EnumToString(GetMapInvalidReasonValues(), 5, "MapInvalidReason", static_cast(value)); + switch(value) { + case MapInvalidReason::VALID: + return "VALID"; + case MapInvalidReason::NULL_KEY: + return "NULL_KEY"; + case MapInvalidReason::DUPLICATE_KEY: + return "DUPLICATE_KEY"; + case MapInvalidReason::NOT_ALIGNED: + return "NOT_ALIGNED"; + case MapInvalidReason::INVALID_PARAMS: + return "INVALID_PARAMS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> MapInvalidReason EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMapInvalidReasonValues(), 5, "MapInvalidReason", value)); -} - -const StringUtil::EnumStringLiteral *GetMemoryTagValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(MemoryTag::BASE_TABLE), "BASE_TABLE" }, - { static_cast(MemoryTag::HASH_TABLE), "HASH_TABLE" }, - { static_cast(MemoryTag::PARQUET_READER), "PARQUET_READER" }, - { static_cast(MemoryTag::CSV_READER), "CSV_READER" }, - { static_cast(MemoryTag::ORDER_BY), "ORDER_BY" }, - { static_cast(MemoryTag::ART_INDEX), "ART_INDEX" }, - { static_cast(MemoryTag::COLUMN_DATA), "COLUMN_DATA" }, - { static_cast(MemoryTag::METADATA), "METADATA" }, - { static_cast(MemoryTag::OVERFLOW_STRINGS), "OVERFLOW_STRINGS" }, - { static_cast(MemoryTag::IN_MEMORY_TABLE), "IN_MEMORY_TABLE" }, - { static_cast(MemoryTag::ALLOCATOR), "ALLOCATOR" }, - { static_cast(MemoryTag::EXTENSION), "EXTENSION" }, - { static_cast(MemoryTag::TRANSACTION), "TRANSACTION" } - }; - return values; + if (StringUtil::Equals(value, "VALID")) { + return MapInvalidReason::VALID; + } + if (StringUtil::Equals(value, "NULL_KEY")) { + return MapInvalidReason::NULL_KEY; + } + if (StringUtil::Equals(value, "DUPLICATE_KEY")) { + return MapInvalidReason::DUPLICATE_KEY; + } + if (StringUtil::Equals(value, "NOT_ALIGNED")) { + return MapInvalidReason::NOT_ALIGNED; + } + if (StringUtil::Equals(value, "INVALID_PARAMS")) { + return MapInvalidReason::INVALID_PARAMS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(MemoryTag value) { - return StringUtil::EnumToString(GetMemoryTagValues(), 13, "MemoryTag", static_cast(value)); + switch(value) { + case MemoryTag::BASE_TABLE: + return "BASE_TABLE"; + case MemoryTag::HASH_TABLE: + return "HASH_TABLE"; + case MemoryTag::PARQUET_READER: + return "PARQUET_READER"; + case MemoryTag::CSV_READER: + return "CSV_READER"; + case MemoryTag::ORDER_BY: + return "ORDER_BY"; + case MemoryTag::ART_INDEX: + return "ART_INDEX"; + case MemoryTag::COLUMN_DATA: + return "COLUMN_DATA"; + case MemoryTag::METADATA: + return "METADATA"; + case MemoryTag::OVERFLOW_STRINGS: + return "OVERFLOW_STRINGS"; + case MemoryTag::IN_MEMORY_TABLE: + return "IN_MEMORY_TABLE"; + case MemoryTag::ALLOCATOR: + return "ALLOCATOR"; + case MemoryTag::EXTENSION: + return "EXTENSION"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> MemoryTag EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMemoryTagValues(), 13, "MemoryTag", value)); -} - -const StringUtil::EnumStringLiteral *GetMetaPipelineTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(MetaPipelineType::REGULAR), "REGULAR" }, - { static_cast(MetaPipelineType::JOIN_BUILD), "JOIN_BUILD" } - }; - return values; + if (StringUtil::Equals(value, "BASE_TABLE")) { + return MemoryTag::BASE_TABLE; + } + if (StringUtil::Equals(value, "HASH_TABLE")) { + return MemoryTag::HASH_TABLE; + } + if (StringUtil::Equals(value, "PARQUET_READER")) { + return MemoryTag::PARQUET_READER; + } + if (StringUtil::Equals(value, "CSV_READER")) { + return MemoryTag::CSV_READER; + } + if (StringUtil::Equals(value, "ORDER_BY")) { + return MemoryTag::ORDER_BY; + } + if (StringUtil::Equals(value, "ART_INDEX")) { + return MemoryTag::ART_INDEX; + } + if (StringUtil::Equals(value, "COLUMN_DATA")) { + return MemoryTag::COLUMN_DATA; + } + if (StringUtil::Equals(value, "METADATA")) { + return MemoryTag::METADATA; + } + if (StringUtil::Equals(value, "OVERFLOW_STRINGS")) { + return MemoryTag::OVERFLOW_STRINGS; + } + if (StringUtil::Equals(value, "IN_MEMORY_TABLE")) { + return MemoryTag::IN_MEMORY_TABLE; + } + if (StringUtil::Equals(value, "ALLOCATOR")) { + return MemoryTag::ALLOCATOR; + } + if (StringUtil::Equals(value, "EXTENSION")) { + return MemoryTag::EXTENSION; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(MetaPipelineType value) { - return StringUtil::EnumToString(GetMetaPipelineTypeValues(), 2, "MetaPipelineType", static_cast(value)); + switch(value) { + case MetaPipelineType::REGULAR: + return "REGULAR"; + case MetaPipelineType::JOIN_BUILD: + return "JOIN_BUILD"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> MetaPipelineType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMetaPipelineTypeValues(), 2, "MetaPipelineType", value)); -} - -const StringUtil::EnumStringLiteral *GetMetricsTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(MetricsType::QUERY_NAME), "QUERY_NAME" }, - { static_cast(MetricsType::BLOCKED_THREAD_TIME), "BLOCKED_THREAD_TIME" }, - { static_cast(MetricsType::CPU_TIME), "CPU_TIME" }, - { static_cast(MetricsType::EXTRA_INFO), "EXTRA_INFO" }, - { static_cast(MetricsType::CUMULATIVE_CARDINALITY), "CUMULATIVE_CARDINALITY" }, - { static_cast(MetricsType::OPERATOR_TYPE), "OPERATOR_TYPE" }, - { static_cast(MetricsType::OPERATOR_CARDINALITY), "OPERATOR_CARDINALITY" }, - { static_cast(MetricsType::CUMULATIVE_ROWS_SCANNED), "CUMULATIVE_ROWS_SCANNED" }, - { static_cast(MetricsType::OPERATOR_ROWS_SCANNED), "OPERATOR_ROWS_SCANNED" }, - { static_cast(MetricsType::OPERATOR_TIMING), "OPERATOR_TIMING" }, - { static_cast(MetricsType::RESULT_SET_SIZE), "RESULT_SET_SIZE" }, - { static_cast(MetricsType::LATENCY), "LATENCY" }, - { static_cast(MetricsType::ROWS_RETURNED), "ROWS_RETURNED" }, - { static_cast(MetricsType::OPERATOR_NAME), "OPERATOR_NAME" }, - { static_cast(MetricsType::ALL_OPTIMIZERS), "ALL_OPTIMIZERS" }, - { static_cast(MetricsType::CUMULATIVE_OPTIMIZER_TIMING), "CUMULATIVE_OPTIMIZER_TIMING" }, - { static_cast(MetricsType::PLANNER), "PLANNER" }, - { static_cast(MetricsType::PLANNER_BINDING), "PLANNER_BINDING" }, - { static_cast(MetricsType::PHYSICAL_PLANNER), "PHYSICAL_PLANNER" }, - { static_cast(MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING), "PHYSICAL_PLANNER_COLUMN_BINDING" }, - { static_cast(MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES), "PHYSICAL_PLANNER_RESOLVE_TYPES" }, - { static_cast(MetricsType::PHYSICAL_PLANNER_CREATE_PLAN), "PHYSICAL_PLANNER_CREATE_PLAN" }, - { static_cast(MetricsType::OPTIMIZER_EXPRESSION_REWRITER), "OPTIMIZER_EXPRESSION_REWRITER" }, - { static_cast(MetricsType::OPTIMIZER_FILTER_PULLUP), "OPTIMIZER_FILTER_PULLUP" }, - { static_cast(MetricsType::OPTIMIZER_FILTER_PUSHDOWN), "OPTIMIZER_FILTER_PUSHDOWN" }, - { static_cast(MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP), "OPTIMIZER_EMPTY_RESULT_PULLUP" }, - { static_cast(MetricsType::OPTIMIZER_CTE_FILTER_PUSHER), "OPTIMIZER_CTE_FILTER_PUSHER" }, - { static_cast(MetricsType::OPTIMIZER_REGEX_RANGE), "OPTIMIZER_REGEX_RANGE" }, - { static_cast(MetricsType::OPTIMIZER_IN_CLAUSE), "OPTIMIZER_IN_CLAUSE" }, - { static_cast(MetricsType::OPTIMIZER_JOIN_ORDER), "OPTIMIZER_JOIN_ORDER" }, - { static_cast(MetricsType::OPTIMIZER_DELIMINATOR), "OPTIMIZER_DELIMINATOR" }, - { static_cast(MetricsType::OPTIMIZER_UNNEST_REWRITER), "OPTIMIZER_UNNEST_REWRITER" }, - { static_cast(MetricsType::OPTIMIZER_UNUSED_COLUMNS), "OPTIMIZER_UNUSED_COLUMNS" }, - { static_cast(MetricsType::OPTIMIZER_STATISTICS_PROPAGATION), "OPTIMIZER_STATISTICS_PROPAGATION" }, - { static_cast(MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS), "OPTIMIZER_COMMON_SUBEXPRESSIONS" }, - { static_cast(MetricsType::OPTIMIZER_COMMON_AGGREGATE), "OPTIMIZER_COMMON_AGGREGATE" }, - { static_cast(MetricsType::OPTIMIZER_COLUMN_LIFETIME), "OPTIMIZER_COLUMN_LIFETIME" }, - { static_cast(MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE), "OPTIMIZER_BUILD_SIDE_PROBE_SIDE" }, - { static_cast(MetricsType::OPTIMIZER_LIMIT_PUSHDOWN), "OPTIMIZER_LIMIT_PUSHDOWN" }, - { static_cast(MetricsType::OPTIMIZER_TOP_N), "OPTIMIZER_TOP_N" }, - { static_cast(MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION), "OPTIMIZER_COMPRESSED_MATERIALIZATION" }, - { static_cast(MetricsType::OPTIMIZER_DUPLICATE_GROUPS), "OPTIMIZER_DUPLICATE_GROUPS" }, - { static_cast(MetricsType::OPTIMIZER_REORDER_FILTER), "OPTIMIZER_REORDER_FILTER" }, - { static_cast(MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN), "OPTIMIZER_SAMPLING_PUSHDOWN" }, - { static_cast(MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN), "OPTIMIZER_JOIN_FILTER_PUSHDOWN" }, - { static_cast(MetricsType::OPTIMIZER_EXTENSION), "OPTIMIZER_EXTENSION" }, - { static_cast(MetricsType::OPTIMIZER_MATERIALIZED_CTE), "OPTIMIZER_MATERIALIZED_CTE" }, - { static_cast(MetricsType::OPTIMIZER_SUM_REWRITER), "OPTIMIZER_SUM_REWRITER" } - }; - return values; + if (StringUtil::Equals(value, "REGULAR")) { + return MetaPipelineType::REGULAR; + } + if (StringUtil::Equals(value, "JOIN_BUILD")) { + return MetaPipelineType::JOIN_BUILD; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(MetricsType value) { - return StringUtil::EnumToString(GetMetricsTypeValues(), 48, "MetricsType", static_cast(value)); + switch(value) { + case MetricsType::QUERY_NAME: + return "QUERY_NAME"; + case MetricsType::BLOCKED_THREAD_TIME: + return "BLOCKED_THREAD_TIME"; + case MetricsType::CPU_TIME: + return "CPU_TIME"; + case MetricsType::EXTRA_INFO: + return "EXTRA_INFO"; + case MetricsType::CUMULATIVE_CARDINALITY: + return "CUMULATIVE_CARDINALITY"; + case MetricsType::OPERATOR_TYPE: + return "OPERATOR_TYPE"; + case MetricsType::OPERATOR_CARDINALITY: + return "OPERATOR_CARDINALITY"; + case MetricsType::CUMULATIVE_ROWS_SCANNED: + return "CUMULATIVE_ROWS_SCANNED"; + case MetricsType::OPERATOR_ROWS_SCANNED: + return "OPERATOR_ROWS_SCANNED"; + case MetricsType::OPERATOR_TIMING: + return "OPERATOR_TIMING"; + case MetricsType::LATENCY: + return "LATENCY"; + case MetricsType::ROWS_RETURNED: + return "ROWS_RETURNED"; + case MetricsType::RESULT_SET_SIZE: + return "RESULT_SET_SIZE"; + case MetricsType::ALL_OPTIMIZERS: + return "ALL_OPTIMIZERS"; + case MetricsType::CUMULATIVE_OPTIMIZER_TIMING: + return "CUMULATIVE_OPTIMIZER_TIMING"; + case MetricsType::PLANNER: + return "PLANNER"; + case MetricsType::PLANNER_BINDING: + return "PLANNER_BINDING"; + case MetricsType::PHYSICAL_PLANNER: + return "PHYSICAL_PLANNER"; + case MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING: + return "PHYSICAL_PLANNER_COLUMN_BINDING"; + case MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES: + return "PHYSICAL_PLANNER_RESOLVE_TYPES"; + case MetricsType::PHYSICAL_PLANNER_CREATE_PLAN: + return "PHYSICAL_PLANNER_CREATE_PLAN"; + case MetricsType::OPTIMIZER_EXPRESSION_REWRITER: + return "OPTIMIZER_EXPRESSION_REWRITER"; + case MetricsType::OPTIMIZER_FILTER_PULLUP: + return "OPTIMIZER_FILTER_PULLUP"; + case MetricsType::OPTIMIZER_FILTER_PUSHDOWN: + return "OPTIMIZER_FILTER_PUSHDOWN"; + case MetricsType::OPTIMIZER_CTE_FILTER_PUSHER: + return "OPTIMIZER_CTE_FILTER_PUSHER"; + case MetricsType::OPTIMIZER_REGEX_RANGE: + return "OPTIMIZER_REGEX_RANGE"; + case MetricsType::OPTIMIZER_IN_CLAUSE: + return "OPTIMIZER_IN_CLAUSE"; + case MetricsType::OPTIMIZER_JOIN_ORDER: + return "OPTIMIZER_JOIN_ORDER"; + case MetricsType::OPTIMIZER_DELIMINATOR: + return "OPTIMIZER_DELIMINATOR"; + case MetricsType::OPTIMIZER_UNNEST_REWRITER: + return "OPTIMIZER_UNNEST_REWRITER"; + case MetricsType::OPTIMIZER_UNUSED_COLUMNS: + return "OPTIMIZER_UNUSED_COLUMNS"; + case MetricsType::OPTIMIZER_STATISTICS_PROPAGATION: + return "OPTIMIZER_STATISTICS_PROPAGATION"; + case MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS: + return "OPTIMIZER_COMMON_SUBEXPRESSIONS"; + case MetricsType::OPTIMIZER_COMMON_AGGREGATE: + return "OPTIMIZER_COMMON_AGGREGATE"; + case MetricsType::OPTIMIZER_COLUMN_LIFETIME: + return "OPTIMIZER_COLUMN_LIFETIME"; + case MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE: + return "OPTIMIZER_BUILD_SIDE_PROBE_SIDE"; + case MetricsType::OPTIMIZER_LIMIT_PUSHDOWN: + return "OPTIMIZER_LIMIT_PUSHDOWN"; + case MetricsType::OPTIMIZER_TOP_N: + return "OPTIMIZER_TOP_N"; + case MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION: + return "OPTIMIZER_COMPRESSED_MATERIALIZATION"; + case MetricsType::OPTIMIZER_DUPLICATE_GROUPS: + return "OPTIMIZER_DUPLICATE_GROUPS"; + case MetricsType::OPTIMIZER_REORDER_FILTER: + return "OPTIMIZER_REORDER_FILTER"; + case MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN: + return "OPTIMIZER_JOIN_FILTER_PUSHDOWN"; + case MetricsType::OPTIMIZER_EXTENSION: + return "OPTIMIZER_EXTENSION"; + case MetricsType::OPTIMIZER_MATERIALIZED_CTE: + return "OPTIMIZER_MATERIALIZED_CTE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> MetricsType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetMetricsTypeValues(), 48, "MetricsType", value)); -} - -const StringUtil::EnumStringLiteral *GetNTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(NType::PREFIX), "PREFIX" }, - { static_cast(NType::LEAF), "LEAF" }, - { static_cast(NType::NODE_4), "NODE_4" }, - { static_cast(NType::NODE_16), "NODE_16" }, - { static_cast(NType::NODE_48), "NODE_48" }, - { static_cast(NType::NODE_256), "NODE_256" }, - { static_cast(NType::LEAF_INLINED), "LEAF_INLINED" }, - { static_cast(NType::NODE_7_LEAF), "NODE_7_LEAF" }, - { static_cast(NType::NODE_15_LEAF), "NODE_15_LEAF" }, - { static_cast(NType::NODE_256_LEAF), "NODE_256_LEAF" } - }; - return values; + if (StringUtil::Equals(value, "QUERY_NAME")) { + return MetricsType::QUERY_NAME; + } + if (StringUtil::Equals(value, "BLOCKED_THREAD_TIME")) { + return MetricsType::BLOCKED_THREAD_TIME; + } + if (StringUtil::Equals(value, "CPU_TIME")) { + return MetricsType::CPU_TIME; + } + if (StringUtil::Equals(value, "EXTRA_INFO")) { + return MetricsType::EXTRA_INFO; + } + if (StringUtil::Equals(value, "CUMULATIVE_CARDINALITY")) { + return MetricsType::CUMULATIVE_CARDINALITY; + } + if (StringUtil::Equals(value, "OPERATOR_TYPE")) { + return MetricsType::OPERATOR_TYPE; + } + if (StringUtil::Equals(value, "OPERATOR_CARDINALITY")) { + return MetricsType::OPERATOR_CARDINALITY; + } + if (StringUtil::Equals(value, "CUMULATIVE_ROWS_SCANNED")) { + return MetricsType::CUMULATIVE_ROWS_SCANNED; + } + if (StringUtil::Equals(value, "OPERATOR_ROWS_SCANNED")) { + return MetricsType::OPERATOR_ROWS_SCANNED; + } + if (StringUtil::Equals(value, "OPERATOR_TIMING")) { + return MetricsType::OPERATOR_TIMING; + } + if (StringUtil::Equals(value, "LATENCY")) { + return MetricsType::LATENCY; + } + if (StringUtil::Equals(value, "ROWS_RETURNED")) { + return MetricsType::ROWS_RETURNED; + } + if (StringUtil::Equals(value, "RESULT_SET_SIZE")) { + return MetricsType::RESULT_SET_SIZE; + } + if (StringUtil::Equals(value, "ALL_OPTIMIZERS")) { + return MetricsType::ALL_OPTIMIZERS; + } + if (StringUtil::Equals(value, "CUMULATIVE_OPTIMIZER_TIMING")) { + return MetricsType::CUMULATIVE_OPTIMIZER_TIMING; + } + if (StringUtil::Equals(value, "PLANNER")) { + return MetricsType::PLANNER; + } + if (StringUtil::Equals(value, "PLANNER_BINDING")) { + return MetricsType::PLANNER_BINDING; + } + if (StringUtil::Equals(value, "PHYSICAL_PLANNER")) { + return MetricsType::PHYSICAL_PLANNER; + } + if (StringUtil::Equals(value, "PHYSICAL_PLANNER_COLUMN_BINDING")) { + return MetricsType::PHYSICAL_PLANNER_COLUMN_BINDING; + } + if (StringUtil::Equals(value, "PHYSICAL_PLANNER_RESOLVE_TYPES")) { + return MetricsType::PHYSICAL_PLANNER_RESOLVE_TYPES; + } + if (StringUtil::Equals(value, "PHYSICAL_PLANNER_CREATE_PLAN")) { + return MetricsType::PHYSICAL_PLANNER_CREATE_PLAN; + } + if (StringUtil::Equals(value, "OPTIMIZER_EXPRESSION_REWRITER")) { + return MetricsType::OPTIMIZER_EXPRESSION_REWRITER; + } + if (StringUtil::Equals(value, "OPTIMIZER_FILTER_PULLUP")) { + return MetricsType::OPTIMIZER_FILTER_PULLUP; + } + if (StringUtil::Equals(value, "OPTIMIZER_FILTER_PUSHDOWN")) { + return MetricsType::OPTIMIZER_FILTER_PUSHDOWN; + } + if (StringUtil::Equals(value, "OPTIMIZER_CTE_FILTER_PUSHER")) { + return MetricsType::OPTIMIZER_CTE_FILTER_PUSHER; + } + if (StringUtil::Equals(value, "OPTIMIZER_REGEX_RANGE")) { + return MetricsType::OPTIMIZER_REGEX_RANGE; + } + if (StringUtil::Equals(value, "OPTIMIZER_IN_CLAUSE")) { + return MetricsType::OPTIMIZER_IN_CLAUSE; + } + if (StringUtil::Equals(value, "OPTIMIZER_JOIN_ORDER")) { + return MetricsType::OPTIMIZER_JOIN_ORDER; + } + if (StringUtil::Equals(value, "OPTIMIZER_DELIMINATOR")) { + return MetricsType::OPTIMIZER_DELIMINATOR; + } + if (StringUtil::Equals(value, "OPTIMIZER_UNNEST_REWRITER")) { + return MetricsType::OPTIMIZER_UNNEST_REWRITER; + } + if (StringUtil::Equals(value, "OPTIMIZER_UNUSED_COLUMNS")) { + return MetricsType::OPTIMIZER_UNUSED_COLUMNS; + } + if (StringUtil::Equals(value, "OPTIMIZER_STATISTICS_PROPAGATION")) { + return MetricsType::OPTIMIZER_STATISTICS_PROPAGATION; + } + if (StringUtil::Equals(value, "OPTIMIZER_COMMON_SUBEXPRESSIONS")) { + return MetricsType::OPTIMIZER_COMMON_SUBEXPRESSIONS; + } + if (StringUtil::Equals(value, "OPTIMIZER_COMMON_AGGREGATE")) { + return MetricsType::OPTIMIZER_COMMON_AGGREGATE; + } + if (StringUtil::Equals(value, "OPTIMIZER_COLUMN_LIFETIME")) { + return MetricsType::OPTIMIZER_COLUMN_LIFETIME; + } + if (StringUtil::Equals(value, "OPTIMIZER_BUILD_SIDE_PROBE_SIDE")) { + return MetricsType::OPTIMIZER_BUILD_SIDE_PROBE_SIDE; + } + if (StringUtil::Equals(value, "OPTIMIZER_LIMIT_PUSHDOWN")) { + return MetricsType::OPTIMIZER_LIMIT_PUSHDOWN; + } + if (StringUtil::Equals(value, "OPTIMIZER_TOP_N")) { + return MetricsType::OPTIMIZER_TOP_N; + } + if (StringUtil::Equals(value, "OPTIMIZER_COMPRESSED_MATERIALIZATION")) { + return MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION; + } + if (StringUtil::Equals(value, "OPTIMIZER_DUPLICATE_GROUPS")) { + return MetricsType::OPTIMIZER_DUPLICATE_GROUPS; + } + if (StringUtil::Equals(value, "OPTIMIZER_REORDER_FILTER")) { + return MetricsType::OPTIMIZER_REORDER_FILTER; + } + if (StringUtil::Equals(value, "OPTIMIZER_JOIN_FILTER_PUSHDOWN")) { + return MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN; + } + if (StringUtil::Equals(value, "OPTIMIZER_EXTENSION")) { + return MetricsType::OPTIMIZER_EXTENSION; + } + if (StringUtil::Equals(value, "OPTIMIZER_MATERIALIZED_CTE")) { + return MetricsType::OPTIMIZER_MATERIALIZED_CTE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(NType value) { - return StringUtil::EnumToString(GetNTypeValues(), 10, "NType", static_cast(value)); + switch(value) { + case NType::PREFIX: + return "PREFIX"; + case NType::LEAF: + return "LEAF"; + case NType::NODE_4: + return "NODE_4"; + case NType::NODE_16: + return "NODE_16"; + case NType::NODE_48: + return "NODE_48"; + case NType::NODE_256: + return "NODE_256"; + case NType::LEAF_INLINED: + return "LEAF_INLINED"; + case NType::NODE_7_LEAF: + return "NODE_7_LEAF"; + case NType::NODE_15_LEAF: + return "NODE_15_LEAF"; + case NType::NODE_256_LEAF: + return "NODE_256_LEAF"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> NType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetNTypeValues(), 10, "NType", value)); -} - -const StringUtil::EnumStringLiteral *GetNewLineIdentifierValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(NewLineIdentifier::SINGLE_N), "SINGLE_N" }, - { static_cast(NewLineIdentifier::CARRY_ON), "CARRY_ON" }, - { static_cast(NewLineIdentifier::NOT_SET), "NOT_SET" }, - { static_cast(NewLineIdentifier::SINGLE_R), "SINGLE_R" } - }; - return values; + if (StringUtil::Equals(value, "PREFIX")) { + return NType::PREFIX; + } + if (StringUtil::Equals(value, "LEAF")) { + return NType::LEAF; + } + if (StringUtil::Equals(value, "NODE_4")) { + return NType::NODE_4; + } + if (StringUtil::Equals(value, "NODE_16")) { + return NType::NODE_16; + } + if (StringUtil::Equals(value, "NODE_48")) { + return NType::NODE_48; + } + if (StringUtil::Equals(value, "NODE_256")) { + return NType::NODE_256; + } + if (StringUtil::Equals(value, "LEAF_INLINED")) { + return NType::LEAF_INLINED; + } + if (StringUtil::Equals(value, "NODE_7_LEAF")) { + return NType::NODE_7_LEAF; + } + if (StringUtil::Equals(value, "NODE_15_LEAF")) { + return NType::NODE_15_LEAF; + } + if (StringUtil::Equals(value, "NODE_256_LEAF")) { + return NType::NODE_256_LEAF; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(NewLineIdentifier value) { - return StringUtil::EnumToString(GetNewLineIdentifierValues(), 4, "NewLineIdentifier", static_cast(value)); + switch(value) { + case NewLineIdentifier::SINGLE_N: + return "SINGLE_N"; + case NewLineIdentifier::CARRY_ON: + return "CARRY_ON"; + case NewLineIdentifier::NOT_SET: + return "NOT_SET"; + case NewLineIdentifier::SINGLE_R: + return "SINGLE_R"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> NewLineIdentifier EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetNewLineIdentifierValues(), 4, "NewLineIdentifier", value)); -} - -const StringUtil::EnumStringLiteral *GetOnConflictActionValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OnConflictAction::THROW), "THROW" }, - { static_cast(OnConflictAction::NOTHING), "NOTHING" }, - { static_cast(OnConflictAction::UPDATE), "UPDATE" }, - { static_cast(OnConflictAction::REPLACE), "REPLACE" } - }; - return values; + if (StringUtil::Equals(value, "SINGLE_N")) { + return NewLineIdentifier::SINGLE_N; + } + if (StringUtil::Equals(value, "CARRY_ON")) { + return NewLineIdentifier::CARRY_ON; + } + if (StringUtil::Equals(value, "NOT_SET")) { + return NewLineIdentifier::NOT_SET; + } + if (StringUtil::Equals(value, "SINGLE_R")) { + return NewLineIdentifier::SINGLE_R; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OnConflictAction value) { - return StringUtil::EnumToString(GetOnConflictActionValues(), 4, "OnConflictAction", static_cast(value)); + switch(value) { + case OnConflictAction::THROW: + return "THROW"; + case OnConflictAction::NOTHING: + return "NOTHING"; + case OnConflictAction::UPDATE: + return "UPDATE"; + case OnConflictAction::REPLACE: + return "REPLACE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OnConflictAction EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOnConflictActionValues(), 4, "OnConflictAction", value)); -} - -const StringUtil::EnumStringLiteral *GetOnCreateConflictValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OnCreateConflict::ERROR_ON_CONFLICT), "ERROR_ON_CONFLICT" }, - { static_cast(OnCreateConflict::IGNORE_ON_CONFLICT), "IGNORE_ON_CONFLICT" }, - { static_cast(OnCreateConflict::REPLACE_ON_CONFLICT), "REPLACE_ON_CONFLICT" }, - { static_cast(OnCreateConflict::ALTER_ON_CONFLICT), "ALTER_ON_CONFLICT" } - }; - return values; + if (StringUtil::Equals(value, "THROW")) { + return OnConflictAction::THROW; + } + if (StringUtil::Equals(value, "NOTHING")) { + return OnConflictAction::NOTHING; + } + if (StringUtil::Equals(value, "UPDATE")) { + return OnConflictAction::UPDATE; + } + if (StringUtil::Equals(value, "REPLACE")) { + return OnConflictAction::REPLACE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OnCreateConflict value) { - return StringUtil::EnumToString(GetOnCreateConflictValues(), 4, "OnCreateConflict", static_cast(value)); + switch(value) { + case OnCreateConflict::ERROR_ON_CONFLICT: + return "ERROR_ON_CONFLICT"; + case OnCreateConflict::IGNORE_ON_CONFLICT: + return "IGNORE_ON_CONFLICT"; + case OnCreateConflict::REPLACE_ON_CONFLICT: + return "REPLACE_ON_CONFLICT"; + case OnCreateConflict::ALTER_ON_CONFLICT: + return "ALTER_ON_CONFLICT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OnCreateConflict EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOnCreateConflictValues(), 4, "OnCreateConflict", value)); -} - -const StringUtil::EnumStringLiteral *GetOnEntryNotFoundValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OnEntryNotFound::THROW_EXCEPTION), "THROW_EXCEPTION" }, - { static_cast(OnEntryNotFound::RETURN_NULL), "RETURN_NULL" } - }; - return values; + if (StringUtil::Equals(value, "ERROR_ON_CONFLICT")) { + return OnCreateConflict::ERROR_ON_CONFLICT; + } + if (StringUtil::Equals(value, "IGNORE_ON_CONFLICT")) { + return OnCreateConflict::IGNORE_ON_CONFLICT; + } + if (StringUtil::Equals(value, "REPLACE_ON_CONFLICT")) { + return OnCreateConflict::REPLACE_ON_CONFLICT; + } + if (StringUtil::Equals(value, "ALTER_ON_CONFLICT")) { + return OnCreateConflict::ALTER_ON_CONFLICT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OnEntryNotFound value) { - return StringUtil::EnumToString(GetOnEntryNotFoundValues(), 2, "OnEntryNotFound", static_cast(value)); + switch(value) { + case OnEntryNotFound::THROW_EXCEPTION: + return "THROW_EXCEPTION"; + case OnEntryNotFound::RETURN_NULL: + return "RETURN_NULL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OnEntryNotFound EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOnEntryNotFoundValues(), 2, "OnEntryNotFound", value)); -} - -const StringUtil::EnumStringLiteral *GetOperatorFinalizeResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OperatorFinalizeResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, - { static_cast(OperatorFinalizeResultType::FINISHED), "FINISHED" } - }; - return values; + if (StringUtil::Equals(value, "THROW_EXCEPTION")) { + return OnEntryNotFound::THROW_EXCEPTION; + } + if (StringUtil::Equals(value, "RETURN_NULL")) { + return OnEntryNotFound::RETURN_NULL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OperatorFinalizeResultType value) { - return StringUtil::EnumToString(GetOperatorFinalizeResultTypeValues(), 2, "OperatorFinalizeResultType", static_cast(value)); + switch(value) { + case OperatorFinalizeResultType::HAVE_MORE_OUTPUT: + return "HAVE_MORE_OUTPUT"; + case OperatorFinalizeResultType::FINISHED: + return "FINISHED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OperatorFinalizeResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOperatorFinalizeResultTypeValues(), 2, "OperatorFinalizeResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetOperatorResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OperatorResultType::NEED_MORE_INPUT), "NEED_MORE_INPUT" }, - { static_cast(OperatorResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, - { static_cast(OperatorResultType::FINISHED), "FINISHED" }, - { static_cast(OperatorResultType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { + return OperatorFinalizeResultType::HAVE_MORE_OUTPUT; + } + if (StringUtil::Equals(value, "FINISHED")) { + return OperatorFinalizeResultType::FINISHED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OperatorResultType value) { - return StringUtil::EnumToString(GetOperatorResultTypeValues(), 4, "OperatorResultType", static_cast(value)); + switch(value) { + case OperatorResultType::NEED_MORE_INPUT: + return "NEED_MORE_INPUT"; + case OperatorResultType::HAVE_MORE_OUTPUT: + return "HAVE_MORE_OUTPUT"; + case OperatorResultType::FINISHED: + return "FINISHED"; + case OperatorResultType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OperatorResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOperatorResultTypeValues(), 4, "OperatorResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetOptimizerTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OptimizerType::INVALID), "INVALID" }, - { static_cast(OptimizerType::EXPRESSION_REWRITER), "EXPRESSION_REWRITER" }, - { static_cast(OptimizerType::FILTER_PULLUP), "FILTER_PULLUP" }, - { static_cast(OptimizerType::FILTER_PUSHDOWN), "FILTER_PUSHDOWN" }, - { static_cast(OptimizerType::EMPTY_RESULT_PULLUP), "EMPTY_RESULT_PULLUP" }, - { static_cast(OptimizerType::CTE_FILTER_PUSHER), "CTE_FILTER_PUSHER" }, - { static_cast(OptimizerType::REGEX_RANGE), "REGEX_RANGE" }, - { static_cast(OptimizerType::IN_CLAUSE), "IN_CLAUSE" }, - { static_cast(OptimizerType::JOIN_ORDER), "JOIN_ORDER" }, - { static_cast(OptimizerType::DELIMINATOR), "DELIMINATOR" }, - { static_cast(OptimizerType::UNNEST_REWRITER), "UNNEST_REWRITER" }, - { static_cast(OptimizerType::UNUSED_COLUMNS), "UNUSED_COLUMNS" }, - { static_cast(OptimizerType::STATISTICS_PROPAGATION), "STATISTICS_PROPAGATION" }, - { static_cast(OptimizerType::COMMON_SUBEXPRESSIONS), "COMMON_SUBEXPRESSIONS" }, - { static_cast(OptimizerType::COMMON_AGGREGATE), "COMMON_AGGREGATE" }, - { static_cast(OptimizerType::COLUMN_LIFETIME), "COLUMN_LIFETIME" }, - { static_cast(OptimizerType::BUILD_SIDE_PROBE_SIDE), "BUILD_SIDE_PROBE_SIDE" }, - { static_cast(OptimizerType::LIMIT_PUSHDOWN), "LIMIT_PUSHDOWN" }, - { static_cast(OptimizerType::TOP_N), "TOP_N" }, - { static_cast(OptimizerType::COMPRESSED_MATERIALIZATION), "COMPRESSED_MATERIALIZATION" }, - { static_cast(OptimizerType::DUPLICATE_GROUPS), "DUPLICATE_GROUPS" }, - { static_cast(OptimizerType::REORDER_FILTER), "REORDER_FILTER" }, - { static_cast(OptimizerType::SAMPLING_PUSHDOWN), "SAMPLING_PUSHDOWN" }, - { static_cast(OptimizerType::JOIN_FILTER_PUSHDOWN), "JOIN_FILTER_PUSHDOWN" }, - { static_cast(OptimizerType::EXTENSION), "EXTENSION" }, - { static_cast(OptimizerType::MATERIALIZED_CTE), "MATERIALIZED_CTE" }, - { static_cast(OptimizerType::SUM_REWRITER), "SUM_REWRITER" } - }; - return values; + if (StringUtil::Equals(value, "NEED_MORE_INPUT")) { + return OperatorResultType::NEED_MORE_INPUT; + } + if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { + return OperatorResultType::HAVE_MORE_OUTPUT; + } + if (StringUtil::Equals(value, "FINISHED")) { + return OperatorResultType::FINISHED; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return OperatorResultType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OptimizerType value) { - return StringUtil::EnumToString(GetOptimizerTypeValues(), 27, "OptimizerType", static_cast(value)); + switch(value) { + case OptimizerType::INVALID: + return "INVALID"; + case OptimizerType::EXPRESSION_REWRITER: + return "EXPRESSION_REWRITER"; + case OptimizerType::FILTER_PULLUP: + return "FILTER_PULLUP"; + case OptimizerType::FILTER_PUSHDOWN: + return "FILTER_PUSHDOWN"; + case OptimizerType::CTE_FILTER_PUSHER: + return "CTE_FILTER_PUSHER"; + case OptimizerType::REGEX_RANGE: + return "REGEX_RANGE"; + case OptimizerType::IN_CLAUSE: + return "IN_CLAUSE"; + case OptimizerType::JOIN_ORDER: + return "JOIN_ORDER"; + case OptimizerType::DELIMINATOR: + return "DELIMINATOR"; + case OptimizerType::UNNEST_REWRITER: + return "UNNEST_REWRITER"; + case OptimizerType::UNUSED_COLUMNS: + return "UNUSED_COLUMNS"; + case OptimizerType::STATISTICS_PROPAGATION: + return "STATISTICS_PROPAGATION"; + case OptimizerType::COMMON_SUBEXPRESSIONS: + return "COMMON_SUBEXPRESSIONS"; + case OptimizerType::COMMON_AGGREGATE: + return "COMMON_AGGREGATE"; + case OptimizerType::COLUMN_LIFETIME: + return "COLUMN_LIFETIME"; + case OptimizerType::BUILD_SIDE_PROBE_SIDE: + return "BUILD_SIDE_PROBE_SIDE"; + case OptimizerType::LIMIT_PUSHDOWN: + return "LIMIT_PUSHDOWN"; + case OptimizerType::TOP_N: + return "TOP_N"; + case OptimizerType::COMPRESSED_MATERIALIZATION: + return "COMPRESSED_MATERIALIZATION"; + case OptimizerType::DUPLICATE_GROUPS: + return "DUPLICATE_GROUPS"; + case OptimizerType::REORDER_FILTER: + return "REORDER_FILTER"; + case OptimizerType::JOIN_FILTER_PUSHDOWN: + return "JOIN_FILTER_PUSHDOWN"; + case OptimizerType::EXTENSION: + return "EXTENSION"; + case OptimizerType::MATERIALIZED_CTE: + return "MATERIALIZED_CTE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OptimizerType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOptimizerTypeValues(), 27, "OptimizerType", value)); -} - -const StringUtil::EnumStringLiteral *GetOrderByNullTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OrderByNullType::INVALID), "INVALID" }, - { static_cast(OrderByNullType::ORDER_DEFAULT), "ORDER_DEFAULT" }, - { static_cast(OrderByNullType::ORDER_DEFAULT), "DEFAULT" }, - { static_cast(OrderByNullType::NULLS_FIRST), "NULLS_FIRST" }, - { static_cast(OrderByNullType::NULLS_FIRST), "NULLS FIRST" }, - { static_cast(OrderByNullType::NULLS_LAST), "NULLS_LAST" }, - { static_cast(OrderByNullType::NULLS_LAST), "NULLS LAST" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return OptimizerType::INVALID; + } + if (StringUtil::Equals(value, "EXPRESSION_REWRITER")) { + return OptimizerType::EXPRESSION_REWRITER; + } + if (StringUtil::Equals(value, "FILTER_PULLUP")) { + return OptimizerType::FILTER_PULLUP; + } + if (StringUtil::Equals(value, "FILTER_PUSHDOWN")) { + return OptimizerType::FILTER_PUSHDOWN; + } + if (StringUtil::Equals(value, "CTE_FILTER_PUSHER")) { + return OptimizerType::CTE_FILTER_PUSHER; + } + if (StringUtil::Equals(value, "REGEX_RANGE")) { + return OptimizerType::REGEX_RANGE; + } + if (StringUtil::Equals(value, "IN_CLAUSE")) { + return OptimizerType::IN_CLAUSE; + } + if (StringUtil::Equals(value, "JOIN_ORDER")) { + return OptimizerType::JOIN_ORDER; + } + if (StringUtil::Equals(value, "DELIMINATOR")) { + return OptimizerType::DELIMINATOR; + } + if (StringUtil::Equals(value, "UNNEST_REWRITER")) { + return OptimizerType::UNNEST_REWRITER; + } + if (StringUtil::Equals(value, "UNUSED_COLUMNS")) { + return OptimizerType::UNUSED_COLUMNS; + } + if (StringUtil::Equals(value, "STATISTICS_PROPAGATION")) { + return OptimizerType::STATISTICS_PROPAGATION; + } + if (StringUtil::Equals(value, "COMMON_SUBEXPRESSIONS")) { + return OptimizerType::COMMON_SUBEXPRESSIONS; + } + if (StringUtil::Equals(value, "COMMON_AGGREGATE")) { + return OptimizerType::COMMON_AGGREGATE; + } + if (StringUtil::Equals(value, "COLUMN_LIFETIME")) { + return OptimizerType::COLUMN_LIFETIME; + } + if (StringUtil::Equals(value, "BUILD_SIDE_PROBE_SIDE")) { + return OptimizerType::BUILD_SIDE_PROBE_SIDE; + } + if (StringUtil::Equals(value, "LIMIT_PUSHDOWN")) { + return OptimizerType::LIMIT_PUSHDOWN; + } + if (StringUtil::Equals(value, "TOP_N")) { + return OptimizerType::TOP_N; + } + if (StringUtil::Equals(value, "COMPRESSED_MATERIALIZATION")) { + return OptimizerType::COMPRESSED_MATERIALIZATION; + } + if (StringUtil::Equals(value, "DUPLICATE_GROUPS")) { + return OptimizerType::DUPLICATE_GROUPS; + } + if (StringUtil::Equals(value, "REORDER_FILTER")) { + return OptimizerType::REORDER_FILTER; + } + if (StringUtil::Equals(value, "JOIN_FILTER_PUSHDOWN")) { + return OptimizerType::JOIN_FILTER_PUSHDOWN; + } + if (StringUtil::Equals(value, "EXTENSION")) { + return OptimizerType::EXTENSION; + } + if (StringUtil::Equals(value, "MATERIALIZED_CTE")) { + return OptimizerType::MATERIALIZED_CTE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OrderByNullType value) { - return StringUtil::EnumToString(GetOrderByNullTypeValues(), 7, "OrderByNullType", static_cast(value)); + switch(value) { + case OrderByNullType::INVALID: + return "INVALID"; + case OrderByNullType::ORDER_DEFAULT: + return "ORDER_DEFAULT"; + case OrderByNullType::NULLS_FIRST: + return "NULLS_FIRST"; + case OrderByNullType::NULLS_LAST: + return "NULLS_LAST"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OrderByNullType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOrderByNullTypeValues(), 7, "OrderByNullType", value)); -} - -const StringUtil::EnumStringLiteral *GetOrderPreservationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OrderPreservationType::NO_ORDER), "NO_ORDER" }, - { static_cast(OrderPreservationType::INSERTION_ORDER), "INSERTION_ORDER" }, - { static_cast(OrderPreservationType::FIXED_ORDER), "FIXED_ORDER" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return OrderByNullType::INVALID; + } + if (StringUtil::Equals(value, "ORDER_DEFAULT") || StringUtil::Equals(value, "DEFAULT")) { + return OrderByNullType::ORDER_DEFAULT; + } + if (StringUtil::Equals(value, "NULLS_FIRST") || StringUtil::Equals(value, "NULLS FIRST")) { + return OrderByNullType::NULLS_FIRST; + } + if (StringUtil::Equals(value, "NULLS_LAST") || StringUtil::Equals(value, "NULLS LAST")) { + return OrderByNullType::NULLS_LAST; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OrderPreservationType value) { - return StringUtil::EnumToString(GetOrderPreservationTypeValues(), 3, "OrderPreservationType", static_cast(value)); + switch(value) { + case OrderPreservationType::NO_ORDER: + return "NO_ORDER"; + case OrderPreservationType::INSERTION_ORDER: + return "INSERTION_ORDER"; + case OrderPreservationType::FIXED_ORDER: + return "FIXED_ORDER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OrderPreservationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOrderPreservationTypeValues(), 3, "OrderPreservationType", value)); -} - -const StringUtil::EnumStringLiteral *GetOrderTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OrderType::INVALID), "INVALID" }, - { static_cast(OrderType::ORDER_DEFAULT), "ORDER_DEFAULT" }, - { static_cast(OrderType::ORDER_DEFAULT), "DEFAULT" }, - { static_cast(OrderType::ASCENDING), "ASCENDING" }, - { static_cast(OrderType::ASCENDING), "ASC" }, - { static_cast(OrderType::DESCENDING), "DESCENDING" }, - { static_cast(OrderType::DESCENDING), "DESC" } - }; - return values; + if (StringUtil::Equals(value, "NO_ORDER")) { + return OrderPreservationType::NO_ORDER; + } + if (StringUtil::Equals(value, "INSERTION_ORDER")) { + return OrderPreservationType::INSERTION_ORDER; + } + if (StringUtil::Equals(value, "FIXED_ORDER")) { + return OrderPreservationType::FIXED_ORDER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OrderType value) { - return StringUtil::EnumToString(GetOrderTypeValues(), 7, "OrderType", static_cast(value)); + switch(value) { + case OrderType::INVALID: + return "INVALID"; + case OrderType::ORDER_DEFAULT: + return "ORDER_DEFAULT"; + case OrderType::ASCENDING: + return "ASCENDING"; + case OrderType::DESCENDING: + return "DESCENDING"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OrderType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOrderTypeValues(), 7, "OrderType", value)); -} - -const StringUtil::EnumStringLiteral *GetOutputStreamValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(OutputStream::STREAM_STDOUT), "STREAM_STDOUT" }, - { static_cast(OutputStream::STREAM_STDERR), "STREAM_STDERR" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return OrderType::INVALID; + } + if (StringUtil::Equals(value, "ORDER_DEFAULT") || StringUtil::Equals(value, "DEFAULT")) { + return OrderType::ORDER_DEFAULT; + } + if (StringUtil::Equals(value, "ASCENDING") || StringUtil::Equals(value, "ASC")) { + return OrderType::ASCENDING; + } + if (StringUtil::Equals(value, "DESCENDING") || StringUtil::Equals(value, "DESC")) { + return OrderType::DESCENDING; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(OutputStream value) { - return StringUtil::EnumToString(GetOutputStreamValues(), 2, "OutputStream", static_cast(value)); + switch(value) { + case OutputStream::STREAM_STDOUT: + return "STREAM_STDOUT"; + case OutputStream::STREAM_STDERR: + return "STREAM_STDERR"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> OutputStream EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetOutputStreamValues(), 2, "OutputStream", value)); -} - -const StringUtil::EnumStringLiteral *GetParseInfoTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ParseInfoType::ALTER_INFO), "ALTER_INFO" }, - { static_cast(ParseInfoType::ATTACH_INFO), "ATTACH_INFO" }, - { static_cast(ParseInfoType::COPY_INFO), "COPY_INFO" }, - { static_cast(ParseInfoType::CREATE_INFO), "CREATE_INFO" }, - { static_cast(ParseInfoType::CREATE_SECRET_INFO), "CREATE_SECRET_INFO" }, - { static_cast(ParseInfoType::DETACH_INFO), "DETACH_INFO" }, - { static_cast(ParseInfoType::DROP_INFO), "DROP_INFO" }, - { static_cast(ParseInfoType::BOUND_EXPORT_DATA), "BOUND_EXPORT_DATA" }, - { static_cast(ParseInfoType::LOAD_INFO), "LOAD_INFO" }, - { static_cast(ParseInfoType::PRAGMA_INFO), "PRAGMA_INFO" }, - { static_cast(ParseInfoType::SHOW_SELECT_INFO), "SHOW_SELECT_INFO" }, - { static_cast(ParseInfoType::TRANSACTION_INFO), "TRANSACTION_INFO" }, - { static_cast(ParseInfoType::VACUUM_INFO), "VACUUM_INFO" }, - { static_cast(ParseInfoType::COMMENT_ON_INFO), "COMMENT_ON_INFO" }, - { static_cast(ParseInfoType::COMMENT_ON_COLUMN_INFO), "COMMENT_ON_COLUMN_INFO" }, - { static_cast(ParseInfoType::COPY_DATABASE_INFO), "COPY_DATABASE_INFO" }, - { static_cast(ParseInfoType::UPDATE_EXTENSIONS_INFO), "UPDATE_EXTENSIONS_INFO" } - }; - return values; + if (StringUtil::Equals(value, "STREAM_STDOUT")) { + return OutputStream::STREAM_STDOUT; + } + if (StringUtil::Equals(value, "STREAM_STDERR")) { + return OutputStream::STREAM_STDERR; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ParseInfoType value) { - return StringUtil::EnumToString(GetParseInfoTypeValues(), 17, "ParseInfoType", static_cast(value)); + switch(value) { + case ParseInfoType::ALTER_INFO: + return "ALTER_INFO"; + case ParseInfoType::ATTACH_INFO: + return "ATTACH_INFO"; + case ParseInfoType::COPY_INFO: + return "COPY_INFO"; + case ParseInfoType::CREATE_INFO: + return "CREATE_INFO"; + case ParseInfoType::CREATE_SECRET_INFO: + return "CREATE_SECRET_INFO"; + case ParseInfoType::DETACH_INFO: + return "DETACH_INFO"; + case ParseInfoType::DROP_INFO: + return "DROP_INFO"; + case ParseInfoType::BOUND_EXPORT_DATA: + return "BOUND_EXPORT_DATA"; + case ParseInfoType::LOAD_INFO: + return "LOAD_INFO"; + case ParseInfoType::PRAGMA_INFO: + return "PRAGMA_INFO"; + case ParseInfoType::SHOW_SELECT_INFO: + return "SHOW_SELECT_INFO"; + case ParseInfoType::TRANSACTION_INFO: + return "TRANSACTION_INFO"; + case ParseInfoType::VACUUM_INFO: + return "VACUUM_INFO"; + case ParseInfoType::COMMENT_ON_INFO: + return "COMMENT_ON_INFO"; + case ParseInfoType::COMMENT_ON_COLUMN_INFO: + return "COMMENT_ON_COLUMN_INFO"; + case ParseInfoType::COPY_DATABASE_INFO: + return "COPY_DATABASE_INFO"; + case ParseInfoType::UPDATE_EXTENSIONS_INFO: + return "UPDATE_EXTENSIONS_INFO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ParseInfoType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetParseInfoTypeValues(), 17, "ParseInfoType", value)); -} - -const StringUtil::EnumStringLiteral *GetParserExtensionResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ParserExtensionResultType::PARSE_SUCCESSFUL), "PARSE_SUCCESSFUL" }, - { static_cast(ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR), "DISPLAY_ORIGINAL_ERROR" }, - { static_cast(ParserExtensionResultType::DISPLAY_EXTENSION_ERROR), "DISPLAY_EXTENSION_ERROR" } - }; - return values; + if (StringUtil::Equals(value, "ALTER_INFO")) { + return ParseInfoType::ALTER_INFO; + } + if (StringUtil::Equals(value, "ATTACH_INFO")) { + return ParseInfoType::ATTACH_INFO; + } + if (StringUtil::Equals(value, "COPY_INFO")) { + return ParseInfoType::COPY_INFO; + } + if (StringUtil::Equals(value, "CREATE_INFO")) { + return ParseInfoType::CREATE_INFO; + } + if (StringUtil::Equals(value, "CREATE_SECRET_INFO")) { + return ParseInfoType::CREATE_SECRET_INFO; + } + if (StringUtil::Equals(value, "DETACH_INFO")) { + return ParseInfoType::DETACH_INFO; + } + if (StringUtil::Equals(value, "DROP_INFO")) { + return ParseInfoType::DROP_INFO; + } + if (StringUtil::Equals(value, "BOUND_EXPORT_DATA")) { + return ParseInfoType::BOUND_EXPORT_DATA; + } + if (StringUtil::Equals(value, "LOAD_INFO")) { + return ParseInfoType::LOAD_INFO; + } + if (StringUtil::Equals(value, "PRAGMA_INFO")) { + return ParseInfoType::PRAGMA_INFO; + } + if (StringUtil::Equals(value, "SHOW_SELECT_INFO")) { + return ParseInfoType::SHOW_SELECT_INFO; + } + if (StringUtil::Equals(value, "TRANSACTION_INFO")) { + return ParseInfoType::TRANSACTION_INFO; + } + if (StringUtil::Equals(value, "VACUUM_INFO")) { + return ParseInfoType::VACUUM_INFO; + } + if (StringUtil::Equals(value, "COMMENT_ON_INFO")) { + return ParseInfoType::COMMENT_ON_INFO; + } + if (StringUtil::Equals(value, "COMMENT_ON_COLUMN_INFO")) { + return ParseInfoType::COMMENT_ON_COLUMN_INFO; + } + if (StringUtil::Equals(value, "COPY_DATABASE_INFO")) { + return ParseInfoType::COPY_DATABASE_INFO; + } + if (StringUtil::Equals(value, "UPDATE_EXTENSIONS_INFO")) { + return ParseInfoType::UPDATE_EXTENSIONS_INFO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ParserExtensionResultType value) { - return StringUtil::EnumToString(GetParserExtensionResultTypeValues(), 3, "ParserExtensionResultType", static_cast(value)); + switch(value) { + case ParserExtensionResultType::PARSE_SUCCESSFUL: + return "PARSE_SUCCESSFUL"; + case ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR: + return "DISPLAY_ORIGINAL_ERROR"; + case ParserExtensionResultType::DISPLAY_EXTENSION_ERROR: + return "DISPLAY_EXTENSION_ERROR"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ParserExtensionResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetParserExtensionResultTypeValues(), 3, "ParserExtensionResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetPartitionSortStageValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PartitionSortStage::INIT), "INIT" }, - { static_cast(PartitionSortStage::SCAN), "SCAN" }, - { static_cast(PartitionSortStage::PREPARE), "PREPARE" }, - { static_cast(PartitionSortStage::MERGE), "MERGE" }, - { static_cast(PartitionSortStage::SORTED), "SORTED" }, - { static_cast(PartitionSortStage::FINISHED), "FINISHED" } - }; - return values; + if (StringUtil::Equals(value, "PARSE_SUCCESSFUL")) { + return ParserExtensionResultType::PARSE_SUCCESSFUL; + } + if (StringUtil::Equals(value, "DISPLAY_ORIGINAL_ERROR")) { + return ParserExtensionResultType::DISPLAY_ORIGINAL_ERROR; + } + if (StringUtil::Equals(value, "DISPLAY_EXTENSION_ERROR")) { + return ParserExtensionResultType::DISPLAY_EXTENSION_ERROR; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PartitionSortStage value) { - return StringUtil::EnumToString(GetPartitionSortStageValues(), 6, "PartitionSortStage", static_cast(value)); + switch(value) { + case PartitionSortStage::INIT: + return "INIT"; + case PartitionSortStage::SCAN: + return "SCAN"; + case PartitionSortStage::PREPARE: + return "PREPARE"; + case PartitionSortStage::MERGE: + return "MERGE"; + case PartitionSortStage::SORTED: + return "SORTED"; + case PartitionSortStage::FINISHED: + return "FINISHED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PartitionSortStage EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPartitionSortStageValues(), 6, "PartitionSortStage", value)); -} - -const StringUtil::EnumStringLiteral *GetPartitionedColumnDataTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PartitionedColumnDataType::INVALID), "INVALID" }, - { static_cast(PartitionedColumnDataType::RADIX), "RADIX" }, - { static_cast(PartitionedColumnDataType::HIVE), "HIVE" } - }; - return values; + if (StringUtil::Equals(value, "INIT")) { + return PartitionSortStage::INIT; + } + if (StringUtil::Equals(value, "SCAN")) { + return PartitionSortStage::SCAN; + } + if (StringUtil::Equals(value, "PREPARE")) { + return PartitionSortStage::PREPARE; + } + if (StringUtil::Equals(value, "MERGE")) { + return PartitionSortStage::MERGE; + } + if (StringUtil::Equals(value, "SORTED")) { + return PartitionSortStage::SORTED; + } + if (StringUtil::Equals(value, "FINISHED")) { + return PartitionSortStage::FINISHED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PartitionedColumnDataType value) { - return StringUtil::EnumToString(GetPartitionedColumnDataTypeValues(), 3, "PartitionedColumnDataType", static_cast(value)); + switch(value) { + case PartitionedColumnDataType::INVALID: + return "INVALID"; + case PartitionedColumnDataType::RADIX: + return "RADIX"; + case PartitionedColumnDataType::HIVE: + return "HIVE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PartitionedColumnDataType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPartitionedColumnDataTypeValues(), 3, "PartitionedColumnDataType", value)); -} - -const StringUtil::EnumStringLiteral *GetPartitionedTupleDataTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PartitionedTupleDataType::INVALID), "INVALID" }, - { static_cast(PartitionedTupleDataType::RADIX), "RADIX" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return PartitionedColumnDataType::INVALID; + } + if (StringUtil::Equals(value, "RADIX")) { + return PartitionedColumnDataType::RADIX; + } + if (StringUtil::Equals(value, "HIVE")) { + return PartitionedColumnDataType::HIVE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PartitionedTupleDataType value) { - return StringUtil::EnumToString(GetPartitionedTupleDataTypeValues(), 2, "PartitionedTupleDataType", static_cast(value)); + switch(value) { + case PartitionedTupleDataType::INVALID: + return "INVALID"; + case PartitionedTupleDataType::RADIX: + return "RADIX"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PartitionedTupleDataType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPartitionedTupleDataTypeValues(), 2, "PartitionedTupleDataType", value)); -} - -const StringUtil::EnumStringLiteral *GetPendingExecutionResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PendingExecutionResult::RESULT_READY), "RESULT_READY" }, - { static_cast(PendingExecutionResult::RESULT_NOT_READY), "RESULT_NOT_READY" }, - { static_cast(PendingExecutionResult::EXECUTION_ERROR), "EXECUTION_ERROR" }, - { static_cast(PendingExecutionResult::BLOCKED), "BLOCKED" }, - { static_cast(PendingExecutionResult::NO_TASKS_AVAILABLE), "NO_TASKS_AVAILABLE" }, - { static_cast(PendingExecutionResult::EXECUTION_FINISHED), "EXECUTION_FINISHED" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return PartitionedTupleDataType::INVALID; + } + if (StringUtil::Equals(value, "RADIX")) { + return PartitionedTupleDataType::RADIX; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PendingExecutionResult value) { - return StringUtil::EnumToString(GetPendingExecutionResultValues(), 6, "PendingExecutionResult", static_cast(value)); + switch(value) { + case PendingExecutionResult::RESULT_READY: + return "RESULT_READY"; + case PendingExecutionResult::RESULT_NOT_READY: + return "RESULT_NOT_READY"; + case PendingExecutionResult::EXECUTION_ERROR: + return "EXECUTION_ERROR"; + case PendingExecutionResult::BLOCKED: + return "BLOCKED"; + case PendingExecutionResult::NO_TASKS_AVAILABLE: + return "NO_TASKS_AVAILABLE"; + case PendingExecutionResult::EXECUTION_FINISHED: + return "EXECUTION_FINISHED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PendingExecutionResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPendingExecutionResultValues(), 6, "PendingExecutionResult", value)); -} - -const StringUtil::EnumStringLiteral *GetPhysicalOperatorTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PhysicalOperatorType::INVALID), "INVALID" }, - { static_cast(PhysicalOperatorType::ORDER_BY), "ORDER_BY" }, - { static_cast(PhysicalOperatorType::LIMIT), "LIMIT" }, - { static_cast(PhysicalOperatorType::STREAMING_LIMIT), "STREAMING_LIMIT" }, - { static_cast(PhysicalOperatorType::LIMIT_PERCENT), "LIMIT_PERCENT" }, - { static_cast(PhysicalOperatorType::TOP_N), "TOP_N" }, - { static_cast(PhysicalOperatorType::WINDOW), "WINDOW" }, - { static_cast(PhysicalOperatorType::UNNEST), "UNNEST" }, - { static_cast(PhysicalOperatorType::UNGROUPED_AGGREGATE), "UNGROUPED_AGGREGATE" }, - { static_cast(PhysicalOperatorType::HASH_GROUP_BY), "HASH_GROUP_BY" }, - { static_cast(PhysicalOperatorType::PERFECT_HASH_GROUP_BY), "PERFECT_HASH_GROUP_BY" }, - { static_cast(PhysicalOperatorType::PARTITIONED_AGGREGATE), "PARTITIONED_AGGREGATE" }, - { static_cast(PhysicalOperatorType::FILTER), "FILTER" }, - { static_cast(PhysicalOperatorType::PROJECTION), "PROJECTION" }, - { static_cast(PhysicalOperatorType::COPY_TO_FILE), "COPY_TO_FILE" }, - { static_cast(PhysicalOperatorType::BATCH_COPY_TO_FILE), "BATCH_COPY_TO_FILE" }, - { static_cast(PhysicalOperatorType::RESERVOIR_SAMPLE), "RESERVOIR_SAMPLE" }, - { static_cast(PhysicalOperatorType::STREAMING_SAMPLE), "STREAMING_SAMPLE" }, - { static_cast(PhysicalOperatorType::STREAMING_WINDOW), "STREAMING_WINDOW" }, - { static_cast(PhysicalOperatorType::PIVOT), "PIVOT" }, - { static_cast(PhysicalOperatorType::COPY_DATABASE), "COPY_DATABASE" }, - { static_cast(PhysicalOperatorType::TABLE_SCAN), "TABLE_SCAN" }, - { static_cast(PhysicalOperatorType::DUMMY_SCAN), "DUMMY_SCAN" }, - { static_cast(PhysicalOperatorType::COLUMN_DATA_SCAN), "COLUMN_DATA_SCAN" }, - { static_cast(PhysicalOperatorType::CHUNK_SCAN), "CHUNK_SCAN" }, - { static_cast(PhysicalOperatorType::RECURSIVE_CTE_SCAN), "RECURSIVE_CTE_SCAN" }, - { static_cast(PhysicalOperatorType::CTE_SCAN), "CTE_SCAN" }, - { static_cast(PhysicalOperatorType::DELIM_SCAN), "DELIM_SCAN" }, - { static_cast(PhysicalOperatorType::EXPRESSION_SCAN), "EXPRESSION_SCAN" }, - { static_cast(PhysicalOperatorType::POSITIONAL_SCAN), "POSITIONAL_SCAN" }, - { static_cast(PhysicalOperatorType::BLOCKWISE_NL_JOIN), "BLOCKWISE_NL_JOIN" }, - { static_cast(PhysicalOperatorType::NESTED_LOOP_JOIN), "NESTED_LOOP_JOIN" }, - { static_cast(PhysicalOperatorType::HASH_JOIN), "HASH_JOIN" }, - { static_cast(PhysicalOperatorType::CROSS_PRODUCT), "CROSS_PRODUCT" }, - { static_cast(PhysicalOperatorType::PIECEWISE_MERGE_JOIN), "PIECEWISE_MERGE_JOIN" }, - { static_cast(PhysicalOperatorType::IE_JOIN), "IE_JOIN" }, - { static_cast(PhysicalOperatorType::LEFT_DELIM_JOIN), "LEFT_DELIM_JOIN" }, - { static_cast(PhysicalOperatorType::RIGHT_DELIM_JOIN), "RIGHT_DELIM_JOIN" }, - { static_cast(PhysicalOperatorType::POSITIONAL_JOIN), "POSITIONAL_JOIN" }, - { static_cast(PhysicalOperatorType::ASOF_JOIN), "ASOF_JOIN" }, - { static_cast(PhysicalOperatorType::UNION), "UNION" }, - { static_cast(PhysicalOperatorType::RECURSIVE_CTE), "RECURSIVE_CTE" }, - { static_cast(PhysicalOperatorType::CTE), "CTE" }, - { static_cast(PhysicalOperatorType::INSERT), "INSERT" }, - { static_cast(PhysicalOperatorType::BATCH_INSERT), "BATCH_INSERT" }, - { static_cast(PhysicalOperatorType::DELETE_OPERATOR), "DELETE_OPERATOR" }, - { static_cast(PhysicalOperatorType::UPDATE), "UPDATE" }, - { static_cast(PhysicalOperatorType::CREATE_TABLE), "CREATE_TABLE" }, - { static_cast(PhysicalOperatorType::CREATE_TABLE_AS), "CREATE_TABLE_AS" }, - { static_cast(PhysicalOperatorType::BATCH_CREATE_TABLE_AS), "BATCH_CREATE_TABLE_AS" }, - { static_cast(PhysicalOperatorType::CREATE_INDEX), "CREATE_INDEX" }, - { static_cast(PhysicalOperatorType::ALTER), "ALTER" }, - { static_cast(PhysicalOperatorType::CREATE_SEQUENCE), "CREATE_SEQUENCE" }, - { static_cast(PhysicalOperatorType::CREATE_VIEW), "CREATE_VIEW" }, - { static_cast(PhysicalOperatorType::CREATE_SCHEMA), "CREATE_SCHEMA" }, - { static_cast(PhysicalOperatorType::CREATE_MACRO), "CREATE_MACRO" }, - { static_cast(PhysicalOperatorType::DROP), "DROP" }, - { static_cast(PhysicalOperatorType::PRAGMA), "PRAGMA" }, - { static_cast(PhysicalOperatorType::TRANSACTION), "TRANSACTION" }, - { static_cast(PhysicalOperatorType::CREATE_TYPE), "CREATE_TYPE" }, - { static_cast(PhysicalOperatorType::ATTACH), "ATTACH" }, - { static_cast(PhysicalOperatorType::DETACH), "DETACH" }, - { static_cast(PhysicalOperatorType::EXPLAIN), "EXPLAIN" }, - { static_cast(PhysicalOperatorType::EXPLAIN_ANALYZE), "EXPLAIN_ANALYZE" }, - { static_cast(PhysicalOperatorType::EMPTY_RESULT), "EMPTY_RESULT" }, - { static_cast(PhysicalOperatorType::EXECUTE), "EXECUTE" }, - { static_cast(PhysicalOperatorType::PREPARE), "PREPARE" }, - { static_cast(PhysicalOperatorType::VACUUM), "VACUUM" }, - { static_cast(PhysicalOperatorType::EXPORT), "EXPORT" }, - { static_cast(PhysicalOperatorType::SET), "SET" }, - { static_cast(PhysicalOperatorType::SET_VARIABLE), "SET_VARIABLE" }, - { static_cast(PhysicalOperatorType::LOAD), "LOAD" }, - { static_cast(PhysicalOperatorType::INOUT_FUNCTION), "INOUT_FUNCTION" }, - { static_cast(PhysicalOperatorType::RESULT_COLLECTOR), "RESULT_COLLECTOR" }, - { static_cast(PhysicalOperatorType::RESET), "RESET" }, - { static_cast(PhysicalOperatorType::EXTENSION), "EXTENSION" }, - { static_cast(PhysicalOperatorType::VERIFY_VECTOR), "VERIFY_VECTOR" }, - { static_cast(PhysicalOperatorType::UPDATE_EXTENSIONS), "UPDATE_EXTENSIONS" }, - { static_cast(PhysicalOperatorType::CREATE_SECRET), "CREATE_SECRET" } - }; - return values; + if (StringUtil::Equals(value, "RESULT_READY")) { + return PendingExecutionResult::RESULT_READY; + } + if (StringUtil::Equals(value, "RESULT_NOT_READY")) { + return PendingExecutionResult::RESULT_NOT_READY; + } + if (StringUtil::Equals(value, "EXECUTION_ERROR")) { + return PendingExecutionResult::EXECUTION_ERROR; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return PendingExecutionResult::BLOCKED; + } + if (StringUtil::Equals(value, "NO_TASKS_AVAILABLE")) { + return PendingExecutionResult::NO_TASKS_AVAILABLE; + } + if (StringUtil::Equals(value, "EXECUTION_FINISHED")) { + return PendingExecutionResult::EXECUTION_FINISHED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PhysicalOperatorType value) { - return StringUtil::EnumToString(GetPhysicalOperatorTypeValues(), 79, "PhysicalOperatorType", static_cast(value)); + switch(value) { + case PhysicalOperatorType::INVALID: + return "INVALID"; + case PhysicalOperatorType::ORDER_BY: + return "ORDER_BY"; + case PhysicalOperatorType::LIMIT: + return "LIMIT"; + case PhysicalOperatorType::STREAMING_LIMIT: + return "STREAMING_LIMIT"; + case PhysicalOperatorType::LIMIT_PERCENT: + return "LIMIT_PERCENT"; + case PhysicalOperatorType::TOP_N: + return "TOP_N"; + case PhysicalOperatorType::WINDOW: + return "WINDOW"; + case PhysicalOperatorType::UNNEST: + return "UNNEST"; + case PhysicalOperatorType::UNGROUPED_AGGREGATE: + return "UNGROUPED_AGGREGATE"; + case PhysicalOperatorType::HASH_GROUP_BY: + return "HASH_GROUP_BY"; + case PhysicalOperatorType::PERFECT_HASH_GROUP_BY: + return "PERFECT_HASH_GROUP_BY"; + case PhysicalOperatorType::FILTER: + return "FILTER"; + case PhysicalOperatorType::PROJECTION: + return "PROJECTION"; + case PhysicalOperatorType::COPY_TO_FILE: + return "COPY_TO_FILE"; + case PhysicalOperatorType::BATCH_COPY_TO_FILE: + return "BATCH_COPY_TO_FILE"; + case PhysicalOperatorType::RESERVOIR_SAMPLE: + return "RESERVOIR_SAMPLE"; + case PhysicalOperatorType::STREAMING_SAMPLE: + return "STREAMING_SAMPLE"; + case PhysicalOperatorType::STREAMING_WINDOW: + return "STREAMING_WINDOW"; + case PhysicalOperatorType::PIVOT: + return "PIVOT"; + case PhysicalOperatorType::COPY_DATABASE: + return "COPY_DATABASE"; + case PhysicalOperatorType::TABLE_SCAN: + return "TABLE_SCAN"; + case PhysicalOperatorType::DUMMY_SCAN: + return "DUMMY_SCAN"; + case PhysicalOperatorType::COLUMN_DATA_SCAN: + return "COLUMN_DATA_SCAN"; + case PhysicalOperatorType::CHUNK_SCAN: + return "CHUNK_SCAN"; + case PhysicalOperatorType::RECURSIVE_CTE_SCAN: + return "RECURSIVE_CTE_SCAN"; + case PhysicalOperatorType::CTE_SCAN: + return "CTE_SCAN"; + case PhysicalOperatorType::DELIM_SCAN: + return "DELIM_SCAN"; + case PhysicalOperatorType::EXPRESSION_SCAN: + return "EXPRESSION_SCAN"; + case PhysicalOperatorType::POSITIONAL_SCAN: + return "POSITIONAL_SCAN"; + case PhysicalOperatorType::BLOCKWISE_NL_JOIN: + return "BLOCKWISE_NL_JOIN"; + case PhysicalOperatorType::NESTED_LOOP_JOIN: + return "NESTED_LOOP_JOIN"; + case PhysicalOperatorType::HASH_JOIN: + return "HASH_JOIN"; + case PhysicalOperatorType::CROSS_PRODUCT: + return "CROSS_PRODUCT"; + case PhysicalOperatorType::PIECEWISE_MERGE_JOIN: + return "PIECEWISE_MERGE_JOIN"; + case PhysicalOperatorType::IE_JOIN: + return "IE_JOIN"; + case PhysicalOperatorType::LEFT_DELIM_JOIN: + return "LEFT_DELIM_JOIN"; + case PhysicalOperatorType::RIGHT_DELIM_JOIN: + return "RIGHT_DELIM_JOIN"; + case PhysicalOperatorType::POSITIONAL_JOIN: + return "POSITIONAL_JOIN"; + case PhysicalOperatorType::ASOF_JOIN: + return "ASOF_JOIN"; + case PhysicalOperatorType::UNION: + return "UNION"; + case PhysicalOperatorType::RECURSIVE_CTE: + return "RECURSIVE_CTE"; + case PhysicalOperatorType::CTE: + return "CTE"; + case PhysicalOperatorType::INSERT: + return "INSERT"; + case PhysicalOperatorType::BATCH_INSERT: + return "BATCH_INSERT"; + case PhysicalOperatorType::DELETE_OPERATOR: + return "DELETE_OPERATOR"; + case PhysicalOperatorType::UPDATE: + return "UPDATE"; + case PhysicalOperatorType::CREATE_TABLE: + return "CREATE_TABLE"; + case PhysicalOperatorType::CREATE_TABLE_AS: + return "CREATE_TABLE_AS"; + case PhysicalOperatorType::BATCH_CREATE_TABLE_AS: + return "BATCH_CREATE_TABLE_AS"; + case PhysicalOperatorType::CREATE_INDEX: + return "CREATE_INDEX"; + case PhysicalOperatorType::ALTER: + return "ALTER"; + case PhysicalOperatorType::CREATE_SEQUENCE: + return "CREATE_SEQUENCE"; + case PhysicalOperatorType::CREATE_VIEW: + return "CREATE_VIEW"; + case PhysicalOperatorType::CREATE_SCHEMA: + return "CREATE_SCHEMA"; + case PhysicalOperatorType::CREATE_MACRO: + return "CREATE_MACRO"; + case PhysicalOperatorType::DROP: + return "DROP"; + case PhysicalOperatorType::PRAGMA: + return "PRAGMA"; + case PhysicalOperatorType::TRANSACTION: + return "TRANSACTION"; + case PhysicalOperatorType::CREATE_TYPE: + return "CREATE_TYPE"; + case PhysicalOperatorType::ATTACH: + return "ATTACH"; + case PhysicalOperatorType::DETACH: + return "DETACH"; + case PhysicalOperatorType::EXPLAIN: + return "EXPLAIN"; + case PhysicalOperatorType::EXPLAIN_ANALYZE: + return "EXPLAIN_ANALYZE"; + case PhysicalOperatorType::EMPTY_RESULT: + return "EMPTY_RESULT"; + case PhysicalOperatorType::EXECUTE: + return "EXECUTE"; + case PhysicalOperatorType::PREPARE: + return "PREPARE"; + case PhysicalOperatorType::VACUUM: + return "VACUUM"; + case PhysicalOperatorType::EXPORT: + return "EXPORT"; + case PhysicalOperatorType::SET: + return "SET"; + case PhysicalOperatorType::SET_VARIABLE: + return "SET_VARIABLE"; + case PhysicalOperatorType::LOAD: + return "LOAD"; + case PhysicalOperatorType::INOUT_FUNCTION: + return "INOUT_FUNCTION"; + case PhysicalOperatorType::RESULT_COLLECTOR: + return "RESULT_COLLECTOR"; + case PhysicalOperatorType::RESET: + return "RESET"; + case PhysicalOperatorType::EXTENSION: + return "EXTENSION"; + case PhysicalOperatorType::VERIFY_VECTOR: + return "VERIFY_VECTOR"; + case PhysicalOperatorType::UPDATE_EXTENSIONS: + return "UPDATE_EXTENSIONS"; + case PhysicalOperatorType::CREATE_SECRET: + return "CREATE_SECRET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PhysicalOperatorType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPhysicalOperatorTypeValues(), 79, "PhysicalOperatorType", value)); -} - -const StringUtil::EnumStringLiteral *GetPhysicalTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PhysicalType::BOOL), "BOOL" }, - { static_cast(PhysicalType::UINT8), "UINT8" }, - { static_cast(PhysicalType::INT8), "INT8" }, - { static_cast(PhysicalType::UINT16), "UINT16" }, - { static_cast(PhysicalType::INT16), "INT16" }, - { static_cast(PhysicalType::UINT32), "UINT32" }, - { static_cast(PhysicalType::INT32), "INT32" }, - { static_cast(PhysicalType::UINT64), "UINT64" }, - { static_cast(PhysicalType::INT64), "INT64" }, - { static_cast(PhysicalType::FLOAT), "FLOAT" }, - { static_cast(PhysicalType::DOUBLE), "DOUBLE" }, - { static_cast(PhysicalType::INTERVAL), "INTERVAL" }, - { static_cast(PhysicalType::LIST), "LIST" }, - { static_cast(PhysicalType::STRUCT), "STRUCT" }, - { static_cast(PhysicalType::ARRAY), "ARRAY" }, - { static_cast(PhysicalType::VARCHAR), "VARCHAR" }, - { static_cast(PhysicalType::UINT128), "UINT128" }, - { static_cast(PhysicalType::INT128), "INT128" }, - { static_cast(PhysicalType::UNKNOWN), "UNKNOWN" }, - { static_cast(PhysicalType::BIT), "BIT" }, - { static_cast(PhysicalType::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return PhysicalOperatorType::INVALID; + } + if (StringUtil::Equals(value, "ORDER_BY")) { + return PhysicalOperatorType::ORDER_BY; + } + if (StringUtil::Equals(value, "LIMIT")) { + return PhysicalOperatorType::LIMIT; + } + if (StringUtil::Equals(value, "STREAMING_LIMIT")) { + return PhysicalOperatorType::STREAMING_LIMIT; + } + if (StringUtil::Equals(value, "LIMIT_PERCENT")) { + return PhysicalOperatorType::LIMIT_PERCENT; + } + if (StringUtil::Equals(value, "TOP_N")) { + return PhysicalOperatorType::TOP_N; + } + if (StringUtil::Equals(value, "WINDOW")) { + return PhysicalOperatorType::WINDOW; + } + if (StringUtil::Equals(value, "UNNEST")) { + return PhysicalOperatorType::UNNEST; + } + if (StringUtil::Equals(value, "UNGROUPED_AGGREGATE")) { + return PhysicalOperatorType::UNGROUPED_AGGREGATE; + } + if (StringUtil::Equals(value, "HASH_GROUP_BY")) { + return PhysicalOperatorType::HASH_GROUP_BY; + } + if (StringUtil::Equals(value, "PERFECT_HASH_GROUP_BY")) { + return PhysicalOperatorType::PERFECT_HASH_GROUP_BY; + } + if (StringUtil::Equals(value, "FILTER")) { + return PhysicalOperatorType::FILTER; + } + if (StringUtil::Equals(value, "PROJECTION")) { + return PhysicalOperatorType::PROJECTION; + } + if (StringUtil::Equals(value, "COPY_TO_FILE")) { + return PhysicalOperatorType::COPY_TO_FILE; + } + if (StringUtil::Equals(value, "BATCH_COPY_TO_FILE")) { + return PhysicalOperatorType::BATCH_COPY_TO_FILE; + } + if (StringUtil::Equals(value, "RESERVOIR_SAMPLE")) { + return PhysicalOperatorType::RESERVOIR_SAMPLE; + } + if (StringUtil::Equals(value, "STREAMING_SAMPLE")) { + return PhysicalOperatorType::STREAMING_SAMPLE; + } + if (StringUtil::Equals(value, "STREAMING_WINDOW")) { + return PhysicalOperatorType::STREAMING_WINDOW; + } + if (StringUtil::Equals(value, "PIVOT")) { + return PhysicalOperatorType::PIVOT; + } + if (StringUtil::Equals(value, "COPY_DATABASE")) { + return PhysicalOperatorType::COPY_DATABASE; + } + if (StringUtil::Equals(value, "TABLE_SCAN")) { + return PhysicalOperatorType::TABLE_SCAN; + } + if (StringUtil::Equals(value, "DUMMY_SCAN")) { + return PhysicalOperatorType::DUMMY_SCAN; + } + if (StringUtil::Equals(value, "COLUMN_DATA_SCAN")) { + return PhysicalOperatorType::COLUMN_DATA_SCAN; + } + if (StringUtil::Equals(value, "CHUNK_SCAN")) { + return PhysicalOperatorType::CHUNK_SCAN; + } + if (StringUtil::Equals(value, "RECURSIVE_CTE_SCAN")) { + return PhysicalOperatorType::RECURSIVE_CTE_SCAN; + } + if (StringUtil::Equals(value, "CTE_SCAN")) { + return PhysicalOperatorType::CTE_SCAN; + } + if (StringUtil::Equals(value, "DELIM_SCAN")) { + return PhysicalOperatorType::DELIM_SCAN; + } + if (StringUtil::Equals(value, "EXPRESSION_SCAN")) { + return PhysicalOperatorType::EXPRESSION_SCAN; + } + if (StringUtil::Equals(value, "POSITIONAL_SCAN")) { + return PhysicalOperatorType::POSITIONAL_SCAN; + } + if (StringUtil::Equals(value, "BLOCKWISE_NL_JOIN")) { + return PhysicalOperatorType::BLOCKWISE_NL_JOIN; + } + if (StringUtil::Equals(value, "NESTED_LOOP_JOIN")) { + return PhysicalOperatorType::NESTED_LOOP_JOIN; + } + if (StringUtil::Equals(value, "HASH_JOIN")) { + return PhysicalOperatorType::HASH_JOIN; + } + if (StringUtil::Equals(value, "CROSS_PRODUCT")) { + return PhysicalOperatorType::CROSS_PRODUCT; + } + if (StringUtil::Equals(value, "PIECEWISE_MERGE_JOIN")) { + return PhysicalOperatorType::PIECEWISE_MERGE_JOIN; + } + if (StringUtil::Equals(value, "IE_JOIN")) { + return PhysicalOperatorType::IE_JOIN; + } + if (StringUtil::Equals(value, "LEFT_DELIM_JOIN")) { + return PhysicalOperatorType::LEFT_DELIM_JOIN; + } + if (StringUtil::Equals(value, "RIGHT_DELIM_JOIN")) { + return PhysicalOperatorType::RIGHT_DELIM_JOIN; + } + if (StringUtil::Equals(value, "POSITIONAL_JOIN")) { + return PhysicalOperatorType::POSITIONAL_JOIN; + } + if (StringUtil::Equals(value, "ASOF_JOIN")) { + return PhysicalOperatorType::ASOF_JOIN; + } + if (StringUtil::Equals(value, "UNION")) { + return PhysicalOperatorType::UNION; + } + if (StringUtil::Equals(value, "RECURSIVE_CTE")) { + return PhysicalOperatorType::RECURSIVE_CTE; + } + if (StringUtil::Equals(value, "CTE")) { + return PhysicalOperatorType::CTE; + } + if (StringUtil::Equals(value, "INSERT")) { + return PhysicalOperatorType::INSERT; + } + if (StringUtil::Equals(value, "BATCH_INSERT")) { + return PhysicalOperatorType::BATCH_INSERT; + } + if (StringUtil::Equals(value, "DELETE_OPERATOR")) { + return PhysicalOperatorType::DELETE_OPERATOR; + } + if (StringUtil::Equals(value, "UPDATE")) { + return PhysicalOperatorType::UPDATE; + } + if (StringUtil::Equals(value, "CREATE_TABLE")) { + return PhysicalOperatorType::CREATE_TABLE; + } + if (StringUtil::Equals(value, "CREATE_TABLE_AS")) { + return PhysicalOperatorType::CREATE_TABLE_AS; + } + if (StringUtil::Equals(value, "BATCH_CREATE_TABLE_AS")) { + return PhysicalOperatorType::BATCH_CREATE_TABLE_AS; + } + if (StringUtil::Equals(value, "CREATE_INDEX")) { + return PhysicalOperatorType::CREATE_INDEX; + } + if (StringUtil::Equals(value, "ALTER")) { + return PhysicalOperatorType::ALTER; + } + if (StringUtil::Equals(value, "CREATE_SEQUENCE")) { + return PhysicalOperatorType::CREATE_SEQUENCE; + } + if (StringUtil::Equals(value, "CREATE_VIEW")) { + return PhysicalOperatorType::CREATE_VIEW; + } + if (StringUtil::Equals(value, "CREATE_SCHEMA")) { + return PhysicalOperatorType::CREATE_SCHEMA; + } + if (StringUtil::Equals(value, "CREATE_MACRO")) { + return PhysicalOperatorType::CREATE_MACRO; + } + if (StringUtil::Equals(value, "DROP")) { + return PhysicalOperatorType::DROP; + } + if (StringUtil::Equals(value, "PRAGMA")) { + return PhysicalOperatorType::PRAGMA; + } + if (StringUtil::Equals(value, "TRANSACTION")) { + return PhysicalOperatorType::TRANSACTION; + } + if (StringUtil::Equals(value, "CREATE_TYPE")) { + return PhysicalOperatorType::CREATE_TYPE; + } + if (StringUtil::Equals(value, "ATTACH")) { + return PhysicalOperatorType::ATTACH; + } + if (StringUtil::Equals(value, "DETACH")) { + return PhysicalOperatorType::DETACH; + } + if (StringUtil::Equals(value, "EXPLAIN")) { + return PhysicalOperatorType::EXPLAIN; + } + if (StringUtil::Equals(value, "EXPLAIN_ANALYZE")) { + return PhysicalOperatorType::EXPLAIN_ANALYZE; + } + if (StringUtil::Equals(value, "EMPTY_RESULT")) { + return PhysicalOperatorType::EMPTY_RESULT; + } + if (StringUtil::Equals(value, "EXECUTE")) { + return PhysicalOperatorType::EXECUTE; + } + if (StringUtil::Equals(value, "PREPARE")) { + return PhysicalOperatorType::PREPARE; + } + if (StringUtil::Equals(value, "VACUUM")) { + return PhysicalOperatorType::VACUUM; + } + if (StringUtil::Equals(value, "EXPORT")) { + return PhysicalOperatorType::EXPORT; + } + if (StringUtil::Equals(value, "SET")) { + return PhysicalOperatorType::SET; + } + if (StringUtil::Equals(value, "SET_VARIABLE")) { + return PhysicalOperatorType::SET_VARIABLE; + } + if (StringUtil::Equals(value, "LOAD")) { + return PhysicalOperatorType::LOAD; + } + if (StringUtil::Equals(value, "INOUT_FUNCTION")) { + return PhysicalOperatorType::INOUT_FUNCTION; + } + if (StringUtil::Equals(value, "RESULT_COLLECTOR")) { + return PhysicalOperatorType::RESULT_COLLECTOR; + } + if (StringUtil::Equals(value, "RESET")) { + return PhysicalOperatorType::RESET; + } + if (StringUtil::Equals(value, "EXTENSION")) { + return PhysicalOperatorType::EXTENSION; + } + if (StringUtil::Equals(value, "VERIFY_VECTOR")) { + return PhysicalOperatorType::VERIFY_VECTOR; + } + if (StringUtil::Equals(value, "UPDATE_EXTENSIONS")) { + return PhysicalOperatorType::UPDATE_EXTENSIONS; + } + if (StringUtil::Equals(value, "CREATE_SECRET")) { + return PhysicalOperatorType::CREATE_SECRET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PhysicalType value) { - return StringUtil::EnumToString(GetPhysicalTypeValues(), 21, "PhysicalType", static_cast(value)); + switch(value) { + case PhysicalType::BOOL: + return "BOOL"; + case PhysicalType::UINT8: + return "UINT8"; + case PhysicalType::INT8: + return "INT8"; + case PhysicalType::UINT16: + return "UINT16"; + case PhysicalType::INT16: + return "INT16"; + case PhysicalType::UINT32: + return "UINT32"; + case PhysicalType::INT32: + return "INT32"; + case PhysicalType::UINT64: + return "UINT64"; + case PhysicalType::INT64: + return "INT64"; + case PhysicalType::FLOAT: + return "FLOAT"; + case PhysicalType::DOUBLE: + return "DOUBLE"; + case PhysicalType::INTERVAL: + return "INTERVAL"; + case PhysicalType::LIST: + return "LIST"; + case PhysicalType::STRUCT: + return "STRUCT"; + case PhysicalType::ARRAY: + return "ARRAY"; + case PhysicalType::VARCHAR: + return "VARCHAR"; + case PhysicalType::UINT128: + return "UINT128"; + case PhysicalType::INT128: + return "INT128"; + case PhysicalType::UNKNOWN: + return "UNKNOWN"; + case PhysicalType::BIT: + return "BIT"; + case PhysicalType::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PhysicalType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPhysicalTypeValues(), 21, "PhysicalType", value)); -} - -const StringUtil::EnumStringLiteral *GetPragmaTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PragmaType::PRAGMA_STATEMENT), "PRAGMA_STATEMENT" }, - { static_cast(PragmaType::PRAGMA_CALL), "PRAGMA_CALL" } - }; - return values; + if (StringUtil::Equals(value, "BOOL")) { + return PhysicalType::BOOL; + } + if (StringUtil::Equals(value, "UINT8")) { + return PhysicalType::UINT8; + } + if (StringUtil::Equals(value, "INT8")) { + return PhysicalType::INT8; + } + if (StringUtil::Equals(value, "UINT16")) { + return PhysicalType::UINT16; + } + if (StringUtil::Equals(value, "INT16")) { + return PhysicalType::INT16; + } + if (StringUtil::Equals(value, "UINT32")) { + return PhysicalType::UINT32; + } + if (StringUtil::Equals(value, "INT32")) { + return PhysicalType::INT32; + } + if (StringUtil::Equals(value, "UINT64")) { + return PhysicalType::UINT64; + } + if (StringUtil::Equals(value, "INT64")) { + return PhysicalType::INT64; + } + if (StringUtil::Equals(value, "FLOAT")) { + return PhysicalType::FLOAT; + } + if (StringUtil::Equals(value, "DOUBLE")) { + return PhysicalType::DOUBLE; + } + if (StringUtil::Equals(value, "INTERVAL")) { + return PhysicalType::INTERVAL; + } + if (StringUtil::Equals(value, "LIST")) { + return PhysicalType::LIST; + } + if (StringUtil::Equals(value, "STRUCT")) { + return PhysicalType::STRUCT; + } + if (StringUtil::Equals(value, "ARRAY")) { + return PhysicalType::ARRAY; + } + if (StringUtil::Equals(value, "VARCHAR")) { + return PhysicalType::VARCHAR; + } + if (StringUtil::Equals(value, "UINT128")) { + return PhysicalType::UINT128; + } + if (StringUtil::Equals(value, "INT128")) { + return PhysicalType::INT128; + } + if (StringUtil::Equals(value, "UNKNOWN")) { + return PhysicalType::UNKNOWN; + } + if (StringUtil::Equals(value, "BIT")) { + return PhysicalType::BIT; + } + if (StringUtil::Equals(value, "INVALID")) { + return PhysicalType::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PragmaType value) { - return StringUtil::EnumToString(GetPragmaTypeValues(), 2, "PragmaType", static_cast(value)); + switch(value) { + case PragmaType::PRAGMA_STATEMENT: + return "PRAGMA_STATEMENT"; + case PragmaType::PRAGMA_CALL: + return "PRAGMA_CALL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PragmaType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPragmaTypeValues(), 2, "PragmaType", value)); -} - -const StringUtil::EnumStringLiteral *GetPreparedParamTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PreparedParamType::AUTO_INCREMENT), "AUTO_INCREMENT" }, - { static_cast(PreparedParamType::POSITIONAL), "POSITIONAL" }, - { static_cast(PreparedParamType::NAMED), "NAMED" }, - { static_cast(PreparedParamType::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "PRAGMA_STATEMENT")) { + return PragmaType::PRAGMA_STATEMENT; + } + if (StringUtil::Equals(value, "PRAGMA_CALL")) { + return PragmaType::PRAGMA_CALL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PreparedParamType value) { - return StringUtil::EnumToString(GetPreparedParamTypeValues(), 4, "PreparedParamType", static_cast(value)); + switch(value) { + case PreparedParamType::AUTO_INCREMENT: + return "AUTO_INCREMENT"; + case PreparedParamType::POSITIONAL: + return "POSITIONAL"; + case PreparedParamType::NAMED: + return "NAMED"; + case PreparedParamType::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PreparedParamType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPreparedParamTypeValues(), 4, "PreparedParamType", value)); -} - -const StringUtil::EnumStringLiteral *GetPreparedStatementModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(PreparedStatementMode::PREPARE_ONLY), "PREPARE_ONLY" }, - { static_cast(PreparedStatementMode::PREPARE_AND_EXECUTE), "PREPARE_AND_EXECUTE" } - }; - return values; + if (StringUtil::Equals(value, "AUTO_INCREMENT")) { + return PreparedParamType::AUTO_INCREMENT; + } + if (StringUtil::Equals(value, "POSITIONAL")) { + return PreparedParamType::POSITIONAL; + } + if (StringUtil::Equals(value, "NAMED")) { + return PreparedParamType::NAMED; + } + if (StringUtil::Equals(value, "INVALID")) { + return PreparedParamType::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(PreparedStatementMode value) { - return StringUtil::EnumToString(GetPreparedStatementModeValues(), 2, "PreparedStatementMode", static_cast(value)); + switch(value) { + case PreparedStatementMode::PREPARE_ONLY: + return "PREPARE_ONLY"; + case PreparedStatementMode::PREPARE_AND_EXECUTE: + return "PREPARE_AND_EXECUTE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> PreparedStatementMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetPreparedStatementModeValues(), 2, "PreparedStatementMode", value)); -} - -const StringUtil::EnumStringLiteral *GetProfilerPrintFormatValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ProfilerPrintFormat::QUERY_TREE), "QUERY_TREE" }, - { static_cast(ProfilerPrintFormat::JSON), "JSON" }, - { static_cast(ProfilerPrintFormat::QUERY_TREE_OPTIMIZER), "QUERY_TREE_OPTIMIZER" }, - { static_cast(ProfilerPrintFormat::NO_OUTPUT), "NO_OUTPUT" }, - { static_cast(ProfilerPrintFormat::HTML), "HTML" }, - { static_cast(ProfilerPrintFormat::GRAPHVIZ), "GRAPHVIZ" } - }; - return values; + if (StringUtil::Equals(value, "PREPARE_ONLY")) { + return PreparedStatementMode::PREPARE_ONLY; + } + if (StringUtil::Equals(value, "PREPARE_AND_EXECUTE")) { + return PreparedStatementMode::PREPARE_AND_EXECUTE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ProfilerPrintFormat value) { - return StringUtil::EnumToString(GetProfilerPrintFormatValues(), 6, "ProfilerPrintFormat", static_cast(value)); + switch(value) { + case ProfilerPrintFormat::QUERY_TREE: + return "QUERY_TREE"; + case ProfilerPrintFormat::JSON: + return "JSON"; + case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: + return "QUERY_TREE_OPTIMIZER"; + case ProfilerPrintFormat::NO_OUTPUT: + return "NO_OUTPUT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ProfilerPrintFormat EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetProfilerPrintFormatValues(), 6, "ProfilerPrintFormat", value)); -} - -const StringUtil::EnumStringLiteral *GetQuantileSerializationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(QuantileSerializationType::NON_DECIMAL), "NON_DECIMAL" }, - { static_cast(QuantileSerializationType::DECIMAL_DISCRETE), "DECIMAL_DISCRETE" }, - { static_cast(QuantileSerializationType::DECIMAL_DISCRETE_LIST), "DECIMAL_DISCRETE_LIST" }, - { static_cast(QuantileSerializationType::DECIMAL_CONTINUOUS), "DECIMAL_CONTINUOUS" }, - { static_cast(QuantileSerializationType::DECIMAL_CONTINUOUS_LIST), "DECIMAL_CONTINUOUS_LIST" } - }; - return values; + if (StringUtil::Equals(value, "QUERY_TREE")) { + return ProfilerPrintFormat::QUERY_TREE; + } + if (StringUtil::Equals(value, "JSON")) { + return ProfilerPrintFormat::JSON; + } + if (StringUtil::Equals(value, "QUERY_TREE_OPTIMIZER")) { + return ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; + } + if (StringUtil::Equals(value, "NO_OUTPUT")) { + return ProfilerPrintFormat::NO_OUTPUT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(QuantileSerializationType value) { - return StringUtil::EnumToString(GetQuantileSerializationTypeValues(), 5, "QuantileSerializationType", static_cast(value)); + switch(value) { + case QuantileSerializationType::NON_DECIMAL: + return "NON_DECIMAL"; + case QuantileSerializationType::DECIMAL_DISCRETE: + return "DECIMAL_DISCRETE"; + case QuantileSerializationType::DECIMAL_DISCRETE_LIST: + return "DECIMAL_DISCRETE_LIST"; + case QuantileSerializationType::DECIMAL_CONTINUOUS: + return "DECIMAL_CONTINUOUS"; + case QuantileSerializationType::DECIMAL_CONTINUOUS_LIST: + return "DECIMAL_CONTINUOUS_LIST"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> QuantileSerializationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetQuantileSerializationTypeValues(), 5, "QuantileSerializationType", value)); -} - -const StringUtil::EnumStringLiteral *GetQueryNodeTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(QueryNodeType::SELECT_NODE), "SELECT_NODE" }, - { static_cast(QueryNodeType::SET_OPERATION_NODE), "SET_OPERATION_NODE" }, - { static_cast(QueryNodeType::BOUND_SUBQUERY_NODE), "BOUND_SUBQUERY_NODE" }, - { static_cast(QueryNodeType::RECURSIVE_CTE_NODE), "RECURSIVE_CTE_NODE" }, - { static_cast(QueryNodeType::CTE_NODE), "CTE_NODE" } - }; - return values; + if (StringUtil::Equals(value, "NON_DECIMAL")) { + return QuantileSerializationType::NON_DECIMAL; + } + if (StringUtil::Equals(value, "DECIMAL_DISCRETE")) { + return QuantileSerializationType::DECIMAL_DISCRETE; + } + if (StringUtil::Equals(value, "DECIMAL_DISCRETE_LIST")) { + return QuantileSerializationType::DECIMAL_DISCRETE_LIST; + } + if (StringUtil::Equals(value, "DECIMAL_CONTINUOUS")) { + return QuantileSerializationType::DECIMAL_CONTINUOUS; + } + if (StringUtil::Equals(value, "DECIMAL_CONTINUOUS_LIST")) { + return QuantileSerializationType::DECIMAL_CONTINUOUS_LIST; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(QueryNodeType value) { - return StringUtil::EnumToString(GetQueryNodeTypeValues(), 5, "QueryNodeType", static_cast(value)); + switch(value) { + case QueryNodeType::SELECT_NODE: + return "SELECT_NODE"; + case QueryNodeType::SET_OPERATION_NODE: + return "SET_OPERATION_NODE"; + case QueryNodeType::BOUND_SUBQUERY_NODE: + return "BOUND_SUBQUERY_NODE"; + case QueryNodeType::RECURSIVE_CTE_NODE: + return "RECURSIVE_CTE_NODE"; + case QueryNodeType::CTE_NODE: + return "CTE_NODE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> QueryNodeType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetQueryNodeTypeValues(), 5, "QueryNodeType", value)); -} - -const StringUtil::EnumStringLiteral *GetQueryResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(QueryResultType::MATERIALIZED_RESULT), "MATERIALIZED_RESULT" }, - { static_cast(QueryResultType::STREAM_RESULT), "STREAM_RESULT" }, - { static_cast(QueryResultType::PENDING_RESULT), "PENDING_RESULT" }, - { static_cast(QueryResultType::ARROW_RESULT), "ARROW_RESULT" } - }; - return values; + if (StringUtil::Equals(value, "SELECT_NODE")) { + return QueryNodeType::SELECT_NODE; + } + if (StringUtil::Equals(value, "SET_OPERATION_NODE")) { + return QueryNodeType::SET_OPERATION_NODE; + } + if (StringUtil::Equals(value, "BOUND_SUBQUERY_NODE")) { + return QueryNodeType::BOUND_SUBQUERY_NODE; + } + if (StringUtil::Equals(value, "RECURSIVE_CTE_NODE")) { + return QueryNodeType::RECURSIVE_CTE_NODE; + } + if (StringUtil::Equals(value, "CTE_NODE")) { + return QueryNodeType::CTE_NODE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(QueryResultType value) { - return StringUtil::EnumToString(GetQueryResultTypeValues(), 4, "QueryResultType", static_cast(value)); + switch(value) { + case QueryResultType::MATERIALIZED_RESULT: + return "MATERIALIZED_RESULT"; + case QueryResultType::STREAM_RESULT: + return "STREAM_RESULT"; + case QueryResultType::PENDING_RESULT: + return "PENDING_RESULT"; + case QueryResultType::ARROW_RESULT: + return "ARROW_RESULT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> QueryResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetQueryResultTypeValues(), 4, "QueryResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetQuoteRuleValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(QuoteRule::QUOTES_RFC), "QUOTES_RFC" }, - { static_cast(QuoteRule::QUOTES_OTHER), "QUOTES_OTHER" }, - { static_cast(QuoteRule::NO_QUOTES), "NO_QUOTES" } - }; - return values; + if (StringUtil::Equals(value, "MATERIALIZED_RESULT")) { + return QueryResultType::MATERIALIZED_RESULT; + } + if (StringUtil::Equals(value, "STREAM_RESULT")) { + return QueryResultType::STREAM_RESULT; + } + if (StringUtil::Equals(value, "PENDING_RESULT")) { + return QueryResultType::PENDING_RESULT; + } + if (StringUtil::Equals(value, "ARROW_RESULT")) { + return QueryResultType::ARROW_RESULT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(QuoteRule value) { - return StringUtil::EnumToString(GetQuoteRuleValues(), 3, "QuoteRule", static_cast(value)); + switch(value) { + case QuoteRule::QUOTES_RFC: + return "QUOTES_RFC"; + case QuoteRule::QUOTES_OTHER: + return "QUOTES_OTHER"; + case QuoteRule::NO_QUOTES: + return "NO_QUOTES"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> QuoteRule EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetQuoteRuleValues(), 3, "QuoteRule", value)); -} - -const StringUtil::EnumStringLiteral *GetRelationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(RelationType::INVALID_RELATION), "INVALID_RELATION" }, - { static_cast(RelationType::TABLE_RELATION), "TABLE_RELATION" }, - { static_cast(RelationType::PROJECTION_RELATION), "PROJECTION_RELATION" }, - { static_cast(RelationType::FILTER_RELATION), "FILTER_RELATION" }, - { static_cast(RelationType::EXPLAIN_RELATION), "EXPLAIN_RELATION" }, - { static_cast(RelationType::CROSS_PRODUCT_RELATION), "CROSS_PRODUCT_RELATION" }, - { static_cast(RelationType::JOIN_RELATION), "JOIN_RELATION" }, - { static_cast(RelationType::AGGREGATE_RELATION), "AGGREGATE_RELATION" }, - { static_cast(RelationType::SET_OPERATION_RELATION), "SET_OPERATION_RELATION" }, - { static_cast(RelationType::DISTINCT_RELATION), "DISTINCT_RELATION" }, - { static_cast(RelationType::LIMIT_RELATION), "LIMIT_RELATION" }, - { static_cast(RelationType::ORDER_RELATION), "ORDER_RELATION" }, - { static_cast(RelationType::CREATE_VIEW_RELATION), "CREATE_VIEW_RELATION" }, - { static_cast(RelationType::CREATE_TABLE_RELATION), "CREATE_TABLE_RELATION" }, - { static_cast(RelationType::INSERT_RELATION), "INSERT_RELATION" }, - { static_cast(RelationType::VALUE_LIST_RELATION), "VALUE_LIST_RELATION" }, - { static_cast(RelationType::MATERIALIZED_RELATION), "MATERIALIZED_RELATION" }, - { static_cast(RelationType::DELETE_RELATION), "DELETE_RELATION" }, - { static_cast(RelationType::UPDATE_RELATION), "UPDATE_RELATION" }, - { static_cast(RelationType::WRITE_CSV_RELATION), "WRITE_CSV_RELATION" }, - { static_cast(RelationType::WRITE_PARQUET_RELATION), "WRITE_PARQUET_RELATION" }, - { static_cast(RelationType::READ_CSV_RELATION), "READ_CSV_RELATION" }, - { static_cast(RelationType::SUBQUERY_RELATION), "SUBQUERY_RELATION" }, - { static_cast(RelationType::TABLE_FUNCTION_RELATION), "TABLE_FUNCTION_RELATION" }, - { static_cast(RelationType::VIEW_RELATION), "VIEW_RELATION" }, - { static_cast(RelationType::QUERY_RELATION), "QUERY_RELATION" }, - { static_cast(RelationType::DELIM_JOIN_RELATION), "DELIM_JOIN_RELATION" }, - { static_cast(RelationType::DELIM_GET_RELATION), "DELIM_GET_RELATION" } - }; - return values; + if (StringUtil::Equals(value, "QUOTES_RFC")) { + return QuoteRule::QUOTES_RFC; + } + if (StringUtil::Equals(value, "QUOTES_OTHER")) { + return QuoteRule::QUOTES_OTHER; + } + if (StringUtil::Equals(value, "NO_QUOTES")) { + return QuoteRule::NO_QUOTES; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(RelationType value) { - return StringUtil::EnumToString(GetRelationTypeValues(), 28, "RelationType", static_cast(value)); + switch(value) { + case RelationType::INVALID_RELATION: + return "INVALID_RELATION"; + case RelationType::TABLE_RELATION: + return "TABLE_RELATION"; + case RelationType::PROJECTION_RELATION: + return "PROJECTION_RELATION"; + case RelationType::FILTER_RELATION: + return "FILTER_RELATION"; + case RelationType::EXPLAIN_RELATION: + return "EXPLAIN_RELATION"; + case RelationType::CROSS_PRODUCT_RELATION: + return "CROSS_PRODUCT_RELATION"; + case RelationType::JOIN_RELATION: + return "JOIN_RELATION"; + case RelationType::AGGREGATE_RELATION: + return "AGGREGATE_RELATION"; + case RelationType::SET_OPERATION_RELATION: + return "SET_OPERATION_RELATION"; + case RelationType::DISTINCT_RELATION: + return "DISTINCT_RELATION"; + case RelationType::LIMIT_RELATION: + return "LIMIT_RELATION"; + case RelationType::ORDER_RELATION: + return "ORDER_RELATION"; + case RelationType::CREATE_VIEW_RELATION: + return "CREATE_VIEW_RELATION"; + case RelationType::CREATE_TABLE_RELATION: + return "CREATE_TABLE_RELATION"; + case RelationType::INSERT_RELATION: + return "INSERT_RELATION"; + case RelationType::VALUE_LIST_RELATION: + return "VALUE_LIST_RELATION"; + case RelationType::MATERIALIZED_RELATION: + return "MATERIALIZED_RELATION"; + case RelationType::DELETE_RELATION: + return "DELETE_RELATION"; + case RelationType::UPDATE_RELATION: + return "UPDATE_RELATION"; + case RelationType::WRITE_CSV_RELATION: + return "WRITE_CSV_RELATION"; + case RelationType::WRITE_PARQUET_RELATION: + return "WRITE_PARQUET_RELATION"; + case RelationType::READ_CSV_RELATION: + return "READ_CSV_RELATION"; + case RelationType::SUBQUERY_RELATION: + return "SUBQUERY_RELATION"; + case RelationType::TABLE_FUNCTION_RELATION: + return "TABLE_FUNCTION_RELATION"; + case RelationType::VIEW_RELATION: + return "VIEW_RELATION"; + case RelationType::QUERY_RELATION: + return "QUERY_RELATION"; + case RelationType::DELIM_JOIN_RELATION: + return "DELIM_JOIN_RELATION"; + case RelationType::DELIM_GET_RELATION: + return "DELIM_GET_RELATION"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> RelationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetRelationTypeValues(), 28, "RelationType", value)); -} - -const StringUtil::EnumStringLiteral *GetRenderModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(RenderMode::ROWS), "ROWS" }, - { static_cast(RenderMode::COLUMNS), "COLUMNS" } - }; - return values; + if (StringUtil::Equals(value, "INVALID_RELATION")) { + return RelationType::INVALID_RELATION; + } + if (StringUtil::Equals(value, "TABLE_RELATION")) { + return RelationType::TABLE_RELATION; + } + if (StringUtil::Equals(value, "PROJECTION_RELATION")) { + return RelationType::PROJECTION_RELATION; + } + if (StringUtil::Equals(value, "FILTER_RELATION")) { + return RelationType::FILTER_RELATION; + } + if (StringUtil::Equals(value, "EXPLAIN_RELATION")) { + return RelationType::EXPLAIN_RELATION; + } + if (StringUtil::Equals(value, "CROSS_PRODUCT_RELATION")) { + return RelationType::CROSS_PRODUCT_RELATION; + } + if (StringUtil::Equals(value, "JOIN_RELATION")) { + return RelationType::JOIN_RELATION; + } + if (StringUtil::Equals(value, "AGGREGATE_RELATION")) { + return RelationType::AGGREGATE_RELATION; + } + if (StringUtil::Equals(value, "SET_OPERATION_RELATION")) { + return RelationType::SET_OPERATION_RELATION; + } + if (StringUtil::Equals(value, "DISTINCT_RELATION")) { + return RelationType::DISTINCT_RELATION; + } + if (StringUtil::Equals(value, "LIMIT_RELATION")) { + return RelationType::LIMIT_RELATION; + } + if (StringUtil::Equals(value, "ORDER_RELATION")) { + return RelationType::ORDER_RELATION; + } + if (StringUtil::Equals(value, "CREATE_VIEW_RELATION")) { + return RelationType::CREATE_VIEW_RELATION; + } + if (StringUtil::Equals(value, "CREATE_TABLE_RELATION")) { + return RelationType::CREATE_TABLE_RELATION; + } + if (StringUtil::Equals(value, "INSERT_RELATION")) { + return RelationType::INSERT_RELATION; + } + if (StringUtil::Equals(value, "VALUE_LIST_RELATION")) { + return RelationType::VALUE_LIST_RELATION; + } + if (StringUtil::Equals(value, "MATERIALIZED_RELATION")) { + return RelationType::MATERIALIZED_RELATION; + } + if (StringUtil::Equals(value, "DELETE_RELATION")) { + return RelationType::DELETE_RELATION; + } + if (StringUtil::Equals(value, "UPDATE_RELATION")) { + return RelationType::UPDATE_RELATION; + } + if (StringUtil::Equals(value, "WRITE_CSV_RELATION")) { + return RelationType::WRITE_CSV_RELATION; + } + if (StringUtil::Equals(value, "WRITE_PARQUET_RELATION")) { + return RelationType::WRITE_PARQUET_RELATION; + } + if (StringUtil::Equals(value, "READ_CSV_RELATION")) { + return RelationType::READ_CSV_RELATION; + } + if (StringUtil::Equals(value, "SUBQUERY_RELATION")) { + return RelationType::SUBQUERY_RELATION; + } + if (StringUtil::Equals(value, "TABLE_FUNCTION_RELATION")) { + return RelationType::TABLE_FUNCTION_RELATION; + } + if (StringUtil::Equals(value, "VIEW_RELATION")) { + return RelationType::VIEW_RELATION; + } + if (StringUtil::Equals(value, "QUERY_RELATION")) { + return RelationType::QUERY_RELATION; + } + if (StringUtil::Equals(value, "DELIM_JOIN_RELATION")) { + return RelationType::DELIM_JOIN_RELATION; + } + if (StringUtil::Equals(value, "DELIM_GET_RELATION")) { + return RelationType::DELIM_GET_RELATION; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(RenderMode value) { - return StringUtil::EnumToString(GetRenderModeValues(), 2, "RenderMode", static_cast(value)); + switch(value) { + case RenderMode::ROWS: + return "ROWS"; + case RenderMode::COLUMNS: + return "COLUMNS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> RenderMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetRenderModeValues(), 2, "RenderMode", value)); -} - -const StringUtil::EnumStringLiteral *GetResultModifierTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ResultModifierType::LIMIT_MODIFIER), "LIMIT_MODIFIER" }, - { static_cast(ResultModifierType::ORDER_MODIFIER), "ORDER_MODIFIER" }, - { static_cast(ResultModifierType::DISTINCT_MODIFIER), "DISTINCT_MODIFIER" }, - { static_cast(ResultModifierType::LIMIT_PERCENT_MODIFIER), "LIMIT_PERCENT_MODIFIER" } - }; - return values; + if (StringUtil::Equals(value, "ROWS")) { + return RenderMode::ROWS; + } + if (StringUtil::Equals(value, "COLUMNS")) { + return RenderMode::COLUMNS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ResultModifierType value) { - return StringUtil::EnumToString(GetResultModifierTypeValues(), 4, "ResultModifierType", static_cast(value)); + switch(value) { + case ResultModifierType::LIMIT_MODIFIER: + return "LIMIT_MODIFIER"; + case ResultModifierType::ORDER_MODIFIER: + return "ORDER_MODIFIER"; + case ResultModifierType::DISTINCT_MODIFIER: + return "DISTINCT_MODIFIER"; + case ResultModifierType::LIMIT_PERCENT_MODIFIER: + return "LIMIT_PERCENT_MODIFIER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ResultModifierType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetResultModifierTypeValues(), 4, "ResultModifierType", value)); -} - -const StringUtil::EnumStringLiteral *GetSampleMethodValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SampleMethod::SYSTEM_SAMPLE), "System" }, - { static_cast(SampleMethod::BERNOULLI_SAMPLE), "Bernoulli" }, - { static_cast(SampleMethod::RESERVOIR_SAMPLE), "Reservoir" }, - { static_cast(SampleMethod::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "LIMIT_MODIFIER")) { + return ResultModifierType::LIMIT_MODIFIER; + } + if (StringUtil::Equals(value, "ORDER_MODIFIER")) { + return ResultModifierType::ORDER_MODIFIER; + } + if (StringUtil::Equals(value, "DISTINCT_MODIFIER")) { + return ResultModifierType::DISTINCT_MODIFIER; + } + if (StringUtil::Equals(value, "LIMIT_PERCENT_MODIFIER")) { + return ResultModifierType::LIMIT_PERCENT_MODIFIER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SampleMethod value) { - return StringUtil::EnumToString(GetSampleMethodValues(), 4, "SampleMethod", static_cast(value)); + switch(value) { + case SampleMethod::SYSTEM_SAMPLE: + return "System"; + case SampleMethod::BERNOULLI_SAMPLE: + return "Bernoulli"; + case SampleMethod::RESERVOIR_SAMPLE: + return "Reservoir"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SampleMethod EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSampleMethodValues(), 4, "SampleMethod", value)); -} - -const StringUtil::EnumStringLiteral *GetSampleTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SampleType::BLOCKING_SAMPLE), "BLOCKING_SAMPLE" }, - { static_cast(SampleType::RESERVOIR_SAMPLE), "RESERVOIR_SAMPLE" }, - { static_cast(SampleType::RESERVOIR_PERCENTAGE_SAMPLE), "RESERVOIR_PERCENTAGE_SAMPLE" } - }; - return values; + if (StringUtil::Equals(value, "System")) { + return SampleMethod::SYSTEM_SAMPLE; + } + if (StringUtil::Equals(value, "Bernoulli")) { + return SampleMethod::BERNOULLI_SAMPLE; + } + if (StringUtil::Equals(value, "Reservoir")) { + return SampleMethod::RESERVOIR_SAMPLE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SampleType value) { - return StringUtil::EnumToString(GetSampleTypeValues(), 3, "SampleType", static_cast(value)); + switch(value) { + case SampleType::BLOCKING_SAMPLE: + return "BLOCKING_SAMPLE"; + case SampleType::RESERVOIR_SAMPLE: + return "RESERVOIR_SAMPLE"; + case SampleType::RESERVOIR_PERCENTAGE_SAMPLE: + return "RESERVOIR_PERCENTAGE_SAMPLE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SampleType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSampleTypeValues(), 3, "SampleType", value)); -} - -const StringUtil::EnumStringLiteral *GetSamplingStateValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SamplingState::RANDOM), "RANDOM" }, - { static_cast(SamplingState::RESERVOIR), "RESERVOIR" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(SamplingState value) { - return StringUtil::EnumToString(GetSamplingStateValues(), 2, "SamplingState", static_cast(value)); -} - -template<> -SamplingState EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSamplingStateValues(), 2, "SamplingState", value)); -} - -const StringUtil::EnumStringLiteral *GetScanTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ScanType::TABLE), "TABLE" }, - { static_cast(ScanType::PARQUET), "PARQUET" }, - { static_cast(ScanType::EXTERNAL), "EXTERNAL" } - }; - return values; + if (StringUtil::Equals(value, "BLOCKING_SAMPLE")) { + return SampleType::BLOCKING_SAMPLE; + } + if (StringUtil::Equals(value, "RESERVOIR_SAMPLE")) { + return SampleType::RESERVOIR_SAMPLE; + } + if (StringUtil::Equals(value, "RESERVOIR_PERCENTAGE_SAMPLE")) { + return SampleType::RESERVOIR_PERCENTAGE_SAMPLE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ScanType value) { - return StringUtil::EnumToString(GetScanTypeValues(), 3, "ScanType", static_cast(value)); + switch(value) { + case ScanType::TABLE: + return "TABLE"; + case ScanType::PARQUET: + return "PARQUET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ScanType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetScanTypeValues(), 3, "ScanType", value)); -} - -const StringUtil::EnumStringLiteral *GetSecretDisplayTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SecretDisplayType::REDACTED), "REDACTED" }, - { static_cast(SecretDisplayType::UNREDACTED), "UNREDACTED" } - }; - return values; + if (StringUtil::Equals(value, "TABLE")) { + return ScanType::TABLE; + } + if (StringUtil::Equals(value, "PARQUET")) { + return ScanType::PARQUET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SecretDisplayType value) { - return StringUtil::EnumToString(GetSecretDisplayTypeValues(), 2, "SecretDisplayType", static_cast(value)); + switch(value) { + case SecretDisplayType::REDACTED: + return "REDACTED"; + case SecretDisplayType::UNREDACTED: + return "UNREDACTED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SecretDisplayType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSecretDisplayTypeValues(), 2, "SecretDisplayType", value)); -} - -const StringUtil::EnumStringLiteral *GetSecretPersistTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SecretPersistType::DEFAULT), "DEFAULT" }, - { static_cast(SecretPersistType::TEMPORARY), "TEMPORARY" }, - { static_cast(SecretPersistType::PERSISTENT), "PERSISTENT" } - }; - return values; + if (StringUtil::Equals(value, "REDACTED")) { + return SecretDisplayType::REDACTED; + } + if (StringUtil::Equals(value, "UNREDACTED")) { + return SecretDisplayType::UNREDACTED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SecretPersistType value) { - return StringUtil::EnumToString(GetSecretPersistTypeValues(), 3, "SecretPersistType", static_cast(value)); + switch(value) { + case SecretPersistType::DEFAULT: + return "DEFAULT"; + case SecretPersistType::TEMPORARY: + return "TEMPORARY"; + case SecretPersistType::PERSISTENT: + return "PERSISTENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SecretPersistType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSecretPersistTypeValues(), 3, "SecretPersistType", value)); -} - -const StringUtil::EnumStringLiteral *GetSecretSerializationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SecretSerializationType::CUSTOM), "CUSTOM" }, - { static_cast(SecretSerializationType::KEY_VALUE_SECRET), "KEY_VALUE_SECRET" } - }; - return values; + if (StringUtil::Equals(value, "DEFAULT")) { + return SecretPersistType::DEFAULT; + } + if (StringUtil::Equals(value, "TEMPORARY")) { + return SecretPersistType::TEMPORARY; + } + if (StringUtil::Equals(value, "PERSISTENT")) { + return SecretPersistType::PERSISTENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SecretSerializationType value) { - return StringUtil::EnumToString(GetSecretSerializationTypeValues(), 2, "SecretSerializationType", static_cast(value)); + switch(value) { + case SecretSerializationType::CUSTOM: + return "CUSTOM"; + case SecretSerializationType::KEY_VALUE_SECRET: + return "KEY_VALUE_SECRET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SecretSerializationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSecretSerializationTypeValues(), 2, "SecretSerializationType", value)); -} - -const StringUtil::EnumStringLiteral *GetSequenceInfoValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SequenceInfo::SEQ_START), "SEQ_START" }, - { static_cast(SequenceInfo::SEQ_INC), "SEQ_INC" }, - { static_cast(SequenceInfo::SEQ_MIN), "SEQ_MIN" }, - { static_cast(SequenceInfo::SEQ_MAX), "SEQ_MAX" }, - { static_cast(SequenceInfo::SEQ_CYCLE), "SEQ_CYCLE" }, - { static_cast(SequenceInfo::SEQ_OWN), "SEQ_OWN" } - }; - return values; + if (StringUtil::Equals(value, "CUSTOM")) { + return SecretSerializationType::CUSTOM; + } + if (StringUtil::Equals(value, "KEY_VALUE_SECRET")) { + return SecretSerializationType::KEY_VALUE_SECRET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SequenceInfo value) { - return StringUtil::EnumToString(GetSequenceInfoValues(), 6, "SequenceInfo", static_cast(value)); + switch(value) { + case SequenceInfo::SEQ_START: + return "SEQ_START"; + case SequenceInfo::SEQ_INC: + return "SEQ_INC"; + case SequenceInfo::SEQ_MIN: + return "SEQ_MIN"; + case SequenceInfo::SEQ_MAX: + return "SEQ_MAX"; + case SequenceInfo::SEQ_CYCLE: + return "SEQ_CYCLE"; + case SequenceInfo::SEQ_OWN: + return "SEQ_OWN"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SequenceInfo EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSequenceInfoValues(), 6, "SequenceInfo", value)); -} - -const StringUtil::EnumStringLiteral *GetSetOperationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SetOperationType::NONE), "NONE" }, - { static_cast(SetOperationType::UNION), "UNION" }, - { static_cast(SetOperationType::EXCEPT), "EXCEPT" }, - { static_cast(SetOperationType::INTERSECT), "INTERSECT" }, - { static_cast(SetOperationType::UNION_BY_NAME), "UNION_BY_NAME" } - }; - return values; + if (StringUtil::Equals(value, "SEQ_START")) { + return SequenceInfo::SEQ_START; + } + if (StringUtil::Equals(value, "SEQ_INC")) { + return SequenceInfo::SEQ_INC; + } + if (StringUtil::Equals(value, "SEQ_MIN")) { + return SequenceInfo::SEQ_MIN; + } + if (StringUtil::Equals(value, "SEQ_MAX")) { + return SequenceInfo::SEQ_MAX; + } + if (StringUtil::Equals(value, "SEQ_CYCLE")) { + return SequenceInfo::SEQ_CYCLE; + } + if (StringUtil::Equals(value, "SEQ_OWN")) { + return SequenceInfo::SEQ_OWN; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SetOperationType value) { - return StringUtil::EnumToString(GetSetOperationTypeValues(), 5, "SetOperationType", static_cast(value)); + switch(value) { + case SetOperationType::NONE: + return "NONE"; + case SetOperationType::UNION: + return "UNION"; + case SetOperationType::EXCEPT: + return "EXCEPT"; + case SetOperationType::INTERSECT: + return "INTERSECT"; + case SetOperationType::UNION_BY_NAME: + return "UNION_BY_NAME"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SetOperationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSetOperationTypeValues(), 5, "SetOperationType", value)); -} - -const StringUtil::EnumStringLiteral *GetSetScopeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SetScope::AUTOMATIC), "AUTOMATIC" }, - { static_cast(SetScope::LOCAL), "LOCAL" }, - { static_cast(SetScope::SESSION), "SESSION" }, - { static_cast(SetScope::GLOBAL), "GLOBAL" }, - { static_cast(SetScope::VARIABLE), "VARIABLE" } - }; - return values; + if (StringUtil::Equals(value, "NONE")) { + return SetOperationType::NONE; + } + if (StringUtil::Equals(value, "UNION")) { + return SetOperationType::UNION; + } + if (StringUtil::Equals(value, "EXCEPT")) { + return SetOperationType::EXCEPT; + } + if (StringUtil::Equals(value, "INTERSECT")) { + return SetOperationType::INTERSECT; + } + if (StringUtil::Equals(value, "UNION_BY_NAME")) { + return SetOperationType::UNION_BY_NAME; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SetScope value) { - return StringUtil::EnumToString(GetSetScopeValues(), 5, "SetScope", static_cast(value)); + switch(value) { + case SetScope::AUTOMATIC: + return "AUTOMATIC"; + case SetScope::LOCAL: + return "LOCAL"; + case SetScope::SESSION: + return "SESSION"; + case SetScope::GLOBAL: + return "GLOBAL"; + case SetScope::VARIABLE: + return "VARIABLE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SetScope EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSetScopeValues(), 5, "SetScope", value)); -} - -const StringUtil::EnumStringLiteral *GetSetTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SetType::SET), "SET" }, - { static_cast(SetType::RESET), "RESET" } - }; - return values; + if (StringUtil::Equals(value, "AUTOMATIC")) { + return SetScope::AUTOMATIC; + } + if (StringUtil::Equals(value, "LOCAL")) { + return SetScope::LOCAL; + } + if (StringUtil::Equals(value, "SESSION")) { + return SetScope::SESSION; + } + if (StringUtil::Equals(value, "GLOBAL")) { + return SetScope::GLOBAL; + } + if (StringUtil::Equals(value, "VARIABLE")) { + return SetScope::VARIABLE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SetType value) { - return StringUtil::EnumToString(GetSetTypeValues(), 2, "SetType", static_cast(value)); + switch(value) { + case SetType::SET: + return "SET"; + case SetType::RESET: + return "RESET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SetType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSetTypeValues(), 2, "SetType", value)); -} - -const StringUtil::EnumStringLiteral *GetSettingScopeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SettingScope::GLOBAL), "GLOBAL" }, - { static_cast(SettingScope::LOCAL), "LOCAL" }, - { static_cast(SettingScope::SECRET), "SECRET" }, - { static_cast(SettingScope::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "SET")) { + return SetType::SET; + } + if (StringUtil::Equals(value, "RESET")) { + return SetType::RESET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SettingScope value) { - return StringUtil::EnumToString(GetSettingScopeValues(), 4, "SettingScope", static_cast(value)); + switch(value) { + case SettingScope::GLOBAL: + return "GLOBAL"; + case SettingScope::LOCAL: + return "LOCAL"; + case SettingScope::SECRET: + return "SECRET"; + case SettingScope::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SettingScope EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSettingScopeValues(), 4, "SettingScope", value)); -} - -const StringUtil::EnumStringLiteral *GetShowTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(ShowType::SUMMARY), "SUMMARY" }, - { static_cast(ShowType::DESCRIBE), "DESCRIBE" } - }; - return values; + if (StringUtil::Equals(value, "GLOBAL")) { + return SettingScope::GLOBAL; + } + if (StringUtil::Equals(value, "LOCAL")) { + return SettingScope::LOCAL; + } + if (StringUtil::Equals(value, "SECRET")) { + return SettingScope::SECRET; + } + if (StringUtil::Equals(value, "INVALID")) { + return SettingScope::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(ShowType value) { - return StringUtil::EnumToString(GetShowTypeValues(), 2, "ShowType", static_cast(value)); + switch(value) { + case ShowType::SUMMARY: + return "SUMMARY"; + case ShowType::DESCRIBE: + return "DESCRIBE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> ShowType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetShowTypeValues(), 2, "ShowType", value)); -} - -const StringUtil::EnumStringLiteral *GetSimplifiedTokenTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER), "SIMPLIFIED_TOKEN_IDENTIFIER" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT), "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT), "SIMPLIFIED_TOKEN_STRING_CONSTANT" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR), "SIMPLIFIED_TOKEN_OPERATOR" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD), "SIMPLIFIED_TOKEN_KEYWORD" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT), "SIMPLIFIED_TOKEN_COMMENT" }, - { static_cast(SimplifiedTokenType::SIMPLIFIED_TOKEN_ERROR), "SIMPLIFIED_TOKEN_ERROR" } - }; - return values; + if (StringUtil::Equals(value, "SUMMARY")) { + return ShowType::SUMMARY; + } + if (StringUtil::Equals(value, "DESCRIBE")) { + return ShowType::DESCRIBE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SimplifiedTokenType value) { - return StringUtil::EnumToString(GetSimplifiedTokenTypeValues(), 7, "SimplifiedTokenType", static_cast(value)); + switch(value) { + case SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER: + return "SIMPLIFIED_TOKEN_IDENTIFIER"; + case SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT: + return "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT"; + case SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT: + return "SIMPLIFIED_TOKEN_STRING_CONSTANT"; + case SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR: + return "SIMPLIFIED_TOKEN_OPERATOR"; + case SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD: + return "SIMPLIFIED_TOKEN_KEYWORD"; + case SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT: + return "SIMPLIFIED_TOKEN_COMMENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SimplifiedTokenType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSimplifiedTokenTypeValues(), 7, "SimplifiedTokenType", value)); -} - -const StringUtil::EnumStringLiteral *GetSinkCombineResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SinkCombineResultType::FINISHED), "FINISHED" }, - { static_cast(SinkCombineResultType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_IDENTIFIER")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER; + } + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_NUMERIC_CONSTANT")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_NUMERIC_CONSTANT; + } + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_STRING_CONSTANT")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT; + } + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_OPERATOR")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_OPERATOR; + } + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_KEYWORD")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_KEYWORD; + } + if (StringUtil::Equals(value, "SIMPLIFIED_TOKEN_COMMENT")) { + return SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SinkCombineResultType value) { - return StringUtil::EnumToString(GetSinkCombineResultTypeValues(), 2, "SinkCombineResultType", static_cast(value)); + switch(value) { + case SinkCombineResultType::FINISHED: + return "FINISHED"; + case SinkCombineResultType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SinkCombineResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSinkCombineResultTypeValues(), 2, "SinkCombineResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetSinkFinalizeTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SinkFinalizeType::READY), "READY" }, - { static_cast(SinkFinalizeType::NO_OUTPUT_POSSIBLE), "NO_OUTPUT_POSSIBLE" }, - { static_cast(SinkFinalizeType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "FINISHED")) { + return SinkCombineResultType::FINISHED; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return SinkCombineResultType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SinkFinalizeType value) { - return StringUtil::EnumToString(GetSinkFinalizeTypeValues(), 3, "SinkFinalizeType", static_cast(value)); + switch(value) { + case SinkFinalizeType::READY: + return "READY"; + case SinkFinalizeType::NO_OUTPUT_POSSIBLE: + return "NO_OUTPUT_POSSIBLE"; + case SinkFinalizeType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SinkFinalizeType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSinkFinalizeTypeValues(), 3, "SinkFinalizeType", value)); -} - -const StringUtil::EnumStringLiteral *GetSinkNextBatchTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SinkNextBatchType::READY), "READY" }, - { static_cast(SinkNextBatchType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "READY")) { + return SinkFinalizeType::READY; + } + if (StringUtil::Equals(value, "NO_OUTPUT_POSSIBLE")) { + return SinkFinalizeType::NO_OUTPUT_POSSIBLE; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return SinkFinalizeType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SinkNextBatchType value) { - return StringUtil::EnumToString(GetSinkNextBatchTypeValues(), 2, "SinkNextBatchType", static_cast(value)); + switch(value) { + case SinkNextBatchType::READY: + return "READY"; + case SinkNextBatchType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SinkNextBatchType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSinkNextBatchTypeValues(), 2, "SinkNextBatchType", value)); -} - -const StringUtil::EnumStringLiteral *GetSinkResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SinkResultType::NEED_MORE_INPUT), "NEED_MORE_INPUT" }, - { static_cast(SinkResultType::FINISHED), "FINISHED" }, - { static_cast(SinkResultType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "READY")) { + return SinkNextBatchType::READY; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return SinkNextBatchType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SinkResultType value) { - return StringUtil::EnumToString(GetSinkResultTypeValues(), 3, "SinkResultType", static_cast(value)); + switch(value) { + case SinkResultType::NEED_MORE_INPUT: + return "NEED_MORE_INPUT"; + case SinkResultType::FINISHED: + return "FINISHED"; + case SinkResultType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SinkResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSinkResultTypeValues(), 3, "SinkResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetSourceResultTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SourceResultType::HAVE_MORE_OUTPUT), "HAVE_MORE_OUTPUT" }, - { static_cast(SourceResultType::FINISHED), "FINISHED" }, - { static_cast(SourceResultType::BLOCKED), "BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "NEED_MORE_INPUT")) { + return SinkResultType::NEED_MORE_INPUT; + } + if (StringUtil::Equals(value, "FINISHED")) { + return SinkResultType::FINISHED; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return SinkResultType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SourceResultType value) { - return StringUtil::EnumToString(GetSourceResultTypeValues(), 3, "SourceResultType", static_cast(value)); + switch(value) { + case SourceResultType::HAVE_MORE_OUTPUT: + return "HAVE_MORE_OUTPUT"; + case SourceResultType::FINISHED: + return "FINISHED"; + case SourceResultType::BLOCKED: + return "BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SourceResultType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSourceResultTypeValues(), 3, "SourceResultType", value)); -} - -const StringUtil::EnumStringLiteral *GetStatementReturnTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StatementReturnType::QUERY_RESULT), "QUERY_RESULT" }, - { static_cast(StatementReturnType::CHANGED_ROWS), "CHANGED_ROWS" }, - { static_cast(StatementReturnType::NOTHING), "NOTHING" } - }; - return values; + if (StringUtil::Equals(value, "HAVE_MORE_OUTPUT")) { + return SourceResultType::HAVE_MORE_OUTPUT; + } + if (StringUtil::Equals(value, "FINISHED")) { + return SourceResultType::FINISHED; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return SourceResultType::BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StatementReturnType value) { - return StringUtil::EnumToString(GetStatementReturnTypeValues(), 3, "StatementReturnType", static_cast(value)); + switch(value) { + case StatementReturnType::QUERY_RESULT: + return "QUERY_RESULT"; + case StatementReturnType::CHANGED_ROWS: + return "CHANGED_ROWS"; + case StatementReturnType::NOTHING: + return "NOTHING"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StatementReturnType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStatementReturnTypeValues(), 3, "StatementReturnType", value)); -} - -const StringUtil::EnumStringLiteral *GetStatementTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StatementType::INVALID_STATEMENT), "INVALID_STATEMENT" }, - { static_cast(StatementType::SELECT_STATEMENT), "SELECT_STATEMENT" }, - { static_cast(StatementType::INSERT_STATEMENT), "INSERT_STATEMENT" }, - { static_cast(StatementType::UPDATE_STATEMENT), "UPDATE_STATEMENT" }, - { static_cast(StatementType::CREATE_STATEMENT), "CREATE_STATEMENT" }, - { static_cast(StatementType::DELETE_STATEMENT), "DELETE_STATEMENT" }, - { static_cast(StatementType::PREPARE_STATEMENT), "PREPARE_STATEMENT" }, - { static_cast(StatementType::EXECUTE_STATEMENT), "EXECUTE_STATEMENT" }, - { static_cast(StatementType::ALTER_STATEMENT), "ALTER_STATEMENT" }, - { static_cast(StatementType::TRANSACTION_STATEMENT), "TRANSACTION_STATEMENT" }, - { static_cast(StatementType::COPY_STATEMENT), "COPY_STATEMENT" }, - { static_cast(StatementType::ANALYZE_STATEMENT), "ANALYZE_STATEMENT" }, - { static_cast(StatementType::VARIABLE_SET_STATEMENT), "VARIABLE_SET_STATEMENT" }, - { static_cast(StatementType::CREATE_FUNC_STATEMENT), "CREATE_FUNC_STATEMENT" }, - { static_cast(StatementType::EXPLAIN_STATEMENT), "EXPLAIN_STATEMENT" }, - { static_cast(StatementType::DROP_STATEMENT), "DROP_STATEMENT" }, - { static_cast(StatementType::EXPORT_STATEMENT), "EXPORT_STATEMENT" }, - { static_cast(StatementType::PRAGMA_STATEMENT), "PRAGMA_STATEMENT" }, - { static_cast(StatementType::VACUUM_STATEMENT), "VACUUM_STATEMENT" }, - { static_cast(StatementType::CALL_STATEMENT), "CALL_STATEMENT" }, - { static_cast(StatementType::SET_STATEMENT), "SET_STATEMENT" }, - { static_cast(StatementType::LOAD_STATEMENT), "LOAD_STATEMENT" }, - { static_cast(StatementType::RELATION_STATEMENT), "RELATION_STATEMENT" }, - { static_cast(StatementType::EXTENSION_STATEMENT), "EXTENSION_STATEMENT" }, - { static_cast(StatementType::LOGICAL_PLAN_STATEMENT), "LOGICAL_PLAN_STATEMENT" }, - { static_cast(StatementType::ATTACH_STATEMENT), "ATTACH_STATEMENT" }, - { static_cast(StatementType::DETACH_STATEMENT), "DETACH_STATEMENT" }, - { static_cast(StatementType::MULTI_STATEMENT), "MULTI_STATEMENT" }, - { static_cast(StatementType::COPY_DATABASE_STATEMENT), "COPY_DATABASE_STATEMENT" }, - { static_cast(StatementType::UPDATE_EXTENSIONS_STATEMENT), "UPDATE_EXTENSIONS_STATEMENT" } - }; - return values; + if (StringUtil::Equals(value, "QUERY_RESULT")) { + return StatementReturnType::QUERY_RESULT; + } + if (StringUtil::Equals(value, "CHANGED_ROWS")) { + return StatementReturnType::CHANGED_ROWS; + } + if (StringUtil::Equals(value, "NOTHING")) { + return StatementReturnType::NOTHING; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StatementType value) { - return StringUtil::EnumToString(GetStatementTypeValues(), 30, "StatementType", static_cast(value)); + switch(value) { + case StatementType::INVALID_STATEMENT: + return "INVALID_STATEMENT"; + case StatementType::SELECT_STATEMENT: + return "SELECT_STATEMENT"; + case StatementType::INSERT_STATEMENT: + return "INSERT_STATEMENT"; + case StatementType::UPDATE_STATEMENT: + return "UPDATE_STATEMENT"; + case StatementType::CREATE_STATEMENT: + return "CREATE_STATEMENT"; + case StatementType::DELETE_STATEMENT: + return "DELETE_STATEMENT"; + case StatementType::PREPARE_STATEMENT: + return "PREPARE_STATEMENT"; + case StatementType::EXECUTE_STATEMENT: + return "EXECUTE_STATEMENT"; + case StatementType::ALTER_STATEMENT: + return "ALTER_STATEMENT"; + case StatementType::TRANSACTION_STATEMENT: + return "TRANSACTION_STATEMENT"; + case StatementType::COPY_STATEMENT: + return "COPY_STATEMENT"; + case StatementType::ANALYZE_STATEMENT: + return "ANALYZE_STATEMENT"; + case StatementType::VARIABLE_SET_STATEMENT: + return "VARIABLE_SET_STATEMENT"; + case StatementType::CREATE_FUNC_STATEMENT: + return "CREATE_FUNC_STATEMENT"; + case StatementType::EXPLAIN_STATEMENT: + return "EXPLAIN_STATEMENT"; + case StatementType::DROP_STATEMENT: + return "DROP_STATEMENT"; + case StatementType::EXPORT_STATEMENT: + return "EXPORT_STATEMENT"; + case StatementType::PRAGMA_STATEMENT: + return "PRAGMA_STATEMENT"; + case StatementType::VACUUM_STATEMENT: + return "VACUUM_STATEMENT"; + case StatementType::CALL_STATEMENT: + return "CALL_STATEMENT"; + case StatementType::SET_STATEMENT: + return "SET_STATEMENT"; + case StatementType::LOAD_STATEMENT: + return "LOAD_STATEMENT"; + case StatementType::RELATION_STATEMENT: + return "RELATION_STATEMENT"; + case StatementType::EXTENSION_STATEMENT: + return "EXTENSION_STATEMENT"; + case StatementType::LOGICAL_PLAN_STATEMENT: + return "LOGICAL_PLAN_STATEMENT"; + case StatementType::ATTACH_STATEMENT: + return "ATTACH_STATEMENT"; + case StatementType::DETACH_STATEMENT: + return "DETACH_STATEMENT"; + case StatementType::MULTI_STATEMENT: + return "MULTI_STATEMENT"; + case StatementType::COPY_DATABASE_STATEMENT: + return "COPY_DATABASE_STATEMENT"; + case StatementType::UPDATE_EXTENSIONS_STATEMENT: + return "UPDATE_EXTENSIONS_STATEMENT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StatementType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStatementTypeValues(), 30, "StatementType", value)); -} - -const StringUtil::EnumStringLiteral *GetStatisticsTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StatisticsType::NUMERIC_STATS), "NUMERIC_STATS" }, - { static_cast(StatisticsType::STRING_STATS), "STRING_STATS" }, - { static_cast(StatisticsType::LIST_STATS), "LIST_STATS" }, - { static_cast(StatisticsType::STRUCT_STATS), "STRUCT_STATS" }, - { static_cast(StatisticsType::BASE_STATS), "BASE_STATS" }, - { static_cast(StatisticsType::ARRAY_STATS), "ARRAY_STATS" } - }; - return values; + if (StringUtil::Equals(value, "INVALID_STATEMENT")) { + return StatementType::INVALID_STATEMENT; + } + if (StringUtil::Equals(value, "SELECT_STATEMENT")) { + return StatementType::SELECT_STATEMENT; + } + if (StringUtil::Equals(value, "INSERT_STATEMENT")) { + return StatementType::INSERT_STATEMENT; + } + if (StringUtil::Equals(value, "UPDATE_STATEMENT")) { + return StatementType::UPDATE_STATEMENT; + } + if (StringUtil::Equals(value, "CREATE_STATEMENT")) { + return StatementType::CREATE_STATEMENT; + } + if (StringUtil::Equals(value, "DELETE_STATEMENT")) { + return StatementType::DELETE_STATEMENT; + } + if (StringUtil::Equals(value, "PREPARE_STATEMENT")) { + return StatementType::PREPARE_STATEMENT; + } + if (StringUtil::Equals(value, "EXECUTE_STATEMENT")) { + return StatementType::EXECUTE_STATEMENT; + } + if (StringUtil::Equals(value, "ALTER_STATEMENT")) { + return StatementType::ALTER_STATEMENT; + } + if (StringUtil::Equals(value, "TRANSACTION_STATEMENT")) { + return StatementType::TRANSACTION_STATEMENT; + } + if (StringUtil::Equals(value, "COPY_STATEMENT")) { + return StatementType::COPY_STATEMENT; + } + if (StringUtil::Equals(value, "ANALYZE_STATEMENT")) { + return StatementType::ANALYZE_STATEMENT; + } + if (StringUtil::Equals(value, "VARIABLE_SET_STATEMENT")) { + return StatementType::VARIABLE_SET_STATEMENT; + } + if (StringUtil::Equals(value, "CREATE_FUNC_STATEMENT")) { + return StatementType::CREATE_FUNC_STATEMENT; + } + if (StringUtil::Equals(value, "EXPLAIN_STATEMENT")) { + return StatementType::EXPLAIN_STATEMENT; + } + if (StringUtil::Equals(value, "DROP_STATEMENT")) { + return StatementType::DROP_STATEMENT; + } + if (StringUtil::Equals(value, "EXPORT_STATEMENT")) { + return StatementType::EXPORT_STATEMENT; + } + if (StringUtil::Equals(value, "PRAGMA_STATEMENT")) { + return StatementType::PRAGMA_STATEMENT; + } + if (StringUtil::Equals(value, "VACUUM_STATEMENT")) { + return StatementType::VACUUM_STATEMENT; + } + if (StringUtil::Equals(value, "CALL_STATEMENT")) { + return StatementType::CALL_STATEMENT; + } + if (StringUtil::Equals(value, "SET_STATEMENT")) { + return StatementType::SET_STATEMENT; + } + if (StringUtil::Equals(value, "LOAD_STATEMENT")) { + return StatementType::LOAD_STATEMENT; + } + if (StringUtil::Equals(value, "RELATION_STATEMENT")) { + return StatementType::RELATION_STATEMENT; + } + if (StringUtil::Equals(value, "EXTENSION_STATEMENT")) { + return StatementType::EXTENSION_STATEMENT; + } + if (StringUtil::Equals(value, "LOGICAL_PLAN_STATEMENT")) { + return StatementType::LOGICAL_PLAN_STATEMENT; + } + if (StringUtil::Equals(value, "ATTACH_STATEMENT")) { + return StatementType::ATTACH_STATEMENT; + } + if (StringUtil::Equals(value, "DETACH_STATEMENT")) { + return StatementType::DETACH_STATEMENT; + } + if (StringUtil::Equals(value, "MULTI_STATEMENT")) { + return StatementType::MULTI_STATEMENT; + } + if (StringUtil::Equals(value, "COPY_DATABASE_STATEMENT")) { + return StatementType::COPY_DATABASE_STATEMENT; + } + if (StringUtil::Equals(value, "UPDATE_EXTENSIONS_STATEMENT")) { + return StatementType::UPDATE_EXTENSIONS_STATEMENT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StatisticsType value) { - return StringUtil::EnumToString(GetStatisticsTypeValues(), 6, "StatisticsType", static_cast(value)); + switch(value) { + case StatisticsType::NUMERIC_STATS: + return "NUMERIC_STATS"; + case StatisticsType::STRING_STATS: + return "STRING_STATS"; + case StatisticsType::LIST_STATS: + return "LIST_STATS"; + case StatisticsType::STRUCT_STATS: + return "STRUCT_STATS"; + case StatisticsType::BASE_STATS: + return "BASE_STATS"; + case StatisticsType::ARRAY_STATS: + return "ARRAY_STATS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StatisticsType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStatisticsTypeValues(), 6, "StatisticsType", value)); -} - -const StringUtil::EnumStringLiteral *GetStatsInfoValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StatsInfo::CAN_HAVE_NULL_VALUES), "CAN_HAVE_NULL_VALUES" }, - { static_cast(StatsInfo::CANNOT_HAVE_NULL_VALUES), "CANNOT_HAVE_NULL_VALUES" }, - { static_cast(StatsInfo::CAN_HAVE_VALID_VALUES), "CAN_HAVE_VALID_VALUES" }, - { static_cast(StatsInfo::CANNOT_HAVE_VALID_VALUES), "CANNOT_HAVE_VALID_VALUES" }, - { static_cast(StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES), "CAN_HAVE_NULL_AND_VALID_VALUES" } - }; - return values; + if (StringUtil::Equals(value, "NUMERIC_STATS")) { + return StatisticsType::NUMERIC_STATS; + } + if (StringUtil::Equals(value, "STRING_STATS")) { + return StatisticsType::STRING_STATS; + } + if (StringUtil::Equals(value, "LIST_STATS")) { + return StatisticsType::LIST_STATS; + } + if (StringUtil::Equals(value, "STRUCT_STATS")) { + return StatisticsType::STRUCT_STATS; + } + if (StringUtil::Equals(value, "BASE_STATS")) { + return StatisticsType::BASE_STATS; + } + if (StringUtil::Equals(value, "ARRAY_STATS")) { + return StatisticsType::ARRAY_STATS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StatsInfo value) { - return StringUtil::EnumToString(GetStatsInfoValues(), 5, "StatsInfo", static_cast(value)); + switch(value) { + case StatsInfo::CAN_HAVE_NULL_VALUES: + return "CAN_HAVE_NULL_VALUES"; + case StatsInfo::CANNOT_HAVE_NULL_VALUES: + return "CANNOT_HAVE_NULL_VALUES"; + case StatsInfo::CAN_HAVE_VALID_VALUES: + return "CAN_HAVE_VALID_VALUES"; + case StatsInfo::CANNOT_HAVE_VALID_VALUES: + return "CANNOT_HAVE_VALID_VALUES"; + case StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES: + return "CAN_HAVE_NULL_AND_VALID_VALUES"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StatsInfo EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStatsInfoValues(), 5, "StatsInfo", value)); -} - -const StringUtil::EnumStringLiteral *GetStrTimeSpecifierValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME), "ABBREVIATED_WEEKDAY_NAME" }, - { static_cast(StrTimeSpecifier::FULL_WEEKDAY_NAME), "FULL_WEEKDAY_NAME" }, - { static_cast(StrTimeSpecifier::WEEKDAY_DECIMAL), "WEEKDAY_DECIMAL" }, - { static_cast(StrTimeSpecifier::DAY_OF_MONTH_PADDED), "DAY_OF_MONTH_PADDED" }, - { static_cast(StrTimeSpecifier::DAY_OF_MONTH), "DAY_OF_MONTH" }, - { static_cast(StrTimeSpecifier::ABBREVIATED_MONTH_NAME), "ABBREVIATED_MONTH_NAME" }, - { static_cast(StrTimeSpecifier::FULL_MONTH_NAME), "FULL_MONTH_NAME" }, - { static_cast(StrTimeSpecifier::MONTH_DECIMAL_PADDED), "MONTH_DECIMAL_PADDED" }, - { static_cast(StrTimeSpecifier::MONTH_DECIMAL), "MONTH_DECIMAL" }, - { static_cast(StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED), "YEAR_WITHOUT_CENTURY_PADDED" }, - { static_cast(StrTimeSpecifier::YEAR_WITHOUT_CENTURY), "YEAR_WITHOUT_CENTURY" }, - { static_cast(StrTimeSpecifier::YEAR_DECIMAL), "YEAR_DECIMAL" }, - { static_cast(StrTimeSpecifier::HOUR_24_PADDED), "HOUR_24_PADDED" }, - { static_cast(StrTimeSpecifier::HOUR_24_DECIMAL), "HOUR_24_DECIMAL" }, - { static_cast(StrTimeSpecifier::HOUR_12_PADDED), "HOUR_12_PADDED" }, - { static_cast(StrTimeSpecifier::HOUR_12_DECIMAL), "HOUR_12_DECIMAL" }, - { static_cast(StrTimeSpecifier::AM_PM), "AM_PM" }, - { static_cast(StrTimeSpecifier::MINUTE_PADDED), "MINUTE_PADDED" }, - { static_cast(StrTimeSpecifier::MINUTE_DECIMAL), "MINUTE_DECIMAL" }, - { static_cast(StrTimeSpecifier::SECOND_PADDED), "SECOND_PADDED" }, - { static_cast(StrTimeSpecifier::SECOND_DECIMAL), "SECOND_DECIMAL" }, - { static_cast(StrTimeSpecifier::MICROSECOND_PADDED), "MICROSECOND_PADDED" }, - { static_cast(StrTimeSpecifier::MILLISECOND_PADDED), "MILLISECOND_PADDED" }, - { static_cast(StrTimeSpecifier::UTC_OFFSET), "UTC_OFFSET" }, - { static_cast(StrTimeSpecifier::TZ_NAME), "TZ_NAME" }, - { static_cast(StrTimeSpecifier::DAY_OF_YEAR_PADDED), "DAY_OF_YEAR_PADDED" }, - { static_cast(StrTimeSpecifier::DAY_OF_YEAR_DECIMAL), "DAY_OF_YEAR_DECIMAL" }, - { static_cast(StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST), "WEEK_NUMBER_PADDED_SUN_FIRST" }, - { static_cast(StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST), "WEEK_NUMBER_PADDED_MON_FIRST" }, - { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME), "LOCALE_APPROPRIATE_DATE_AND_TIME" }, - { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_DATE), "LOCALE_APPROPRIATE_DATE" }, - { static_cast(StrTimeSpecifier::LOCALE_APPROPRIATE_TIME), "LOCALE_APPROPRIATE_TIME" }, - { static_cast(StrTimeSpecifier::NANOSECOND_PADDED), "NANOSECOND_PADDED" }, - { static_cast(StrTimeSpecifier::YEAR_ISO), "YEAR_ISO" }, - { static_cast(StrTimeSpecifier::WEEKDAY_ISO), "WEEKDAY_ISO" }, - { static_cast(StrTimeSpecifier::WEEK_NUMBER_ISO), "WEEK_NUMBER_ISO" } - }; - return values; + if (StringUtil::Equals(value, "CAN_HAVE_NULL_VALUES")) { + return StatsInfo::CAN_HAVE_NULL_VALUES; + } + if (StringUtil::Equals(value, "CANNOT_HAVE_NULL_VALUES")) { + return StatsInfo::CANNOT_HAVE_NULL_VALUES; + } + if (StringUtil::Equals(value, "CAN_HAVE_VALID_VALUES")) { + return StatsInfo::CAN_HAVE_VALID_VALUES; + } + if (StringUtil::Equals(value, "CANNOT_HAVE_VALID_VALUES")) { + return StatsInfo::CANNOT_HAVE_VALID_VALUES; + } + if (StringUtil::Equals(value, "CAN_HAVE_NULL_AND_VALID_VALUES")) { + return StatsInfo::CAN_HAVE_NULL_AND_VALID_VALUES; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StrTimeSpecifier value) { - return StringUtil::EnumToString(GetStrTimeSpecifierValues(), 36, "StrTimeSpecifier", static_cast(value)); + switch(value) { + case StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME: + return "ABBREVIATED_WEEKDAY_NAME"; + case StrTimeSpecifier::FULL_WEEKDAY_NAME: + return "FULL_WEEKDAY_NAME"; + case StrTimeSpecifier::WEEKDAY_DECIMAL: + return "WEEKDAY_DECIMAL"; + case StrTimeSpecifier::DAY_OF_MONTH_PADDED: + return "DAY_OF_MONTH_PADDED"; + case StrTimeSpecifier::DAY_OF_MONTH: + return "DAY_OF_MONTH"; + case StrTimeSpecifier::ABBREVIATED_MONTH_NAME: + return "ABBREVIATED_MONTH_NAME"; + case StrTimeSpecifier::FULL_MONTH_NAME: + return "FULL_MONTH_NAME"; + case StrTimeSpecifier::MONTH_DECIMAL_PADDED: + return "MONTH_DECIMAL_PADDED"; + case StrTimeSpecifier::MONTH_DECIMAL: + return "MONTH_DECIMAL"; + case StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED: + return "YEAR_WITHOUT_CENTURY_PADDED"; + case StrTimeSpecifier::YEAR_WITHOUT_CENTURY: + return "YEAR_WITHOUT_CENTURY"; + case StrTimeSpecifier::YEAR_DECIMAL: + return "YEAR_DECIMAL"; + case StrTimeSpecifier::HOUR_24_PADDED: + return "HOUR_24_PADDED"; + case StrTimeSpecifier::HOUR_24_DECIMAL: + return "HOUR_24_DECIMAL"; + case StrTimeSpecifier::HOUR_12_PADDED: + return "HOUR_12_PADDED"; + case StrTimeSpecifier::HOUR_12_DECIMAL: + return "HOUR_12_DECIMAL"; + case StrTimeSpecifier::AM_PM: + return "AM_PM"; + case StrTimeSpecifier::MINUTE_PADDED: + return "MINUTE_PADDED"; + case StrTimeSpecifier::MINUTE_DECIMAL: + return "MINUTE_DECIMAL"; + case StrTimeSpecifier::SECOND_PADDED: + return "SECOND_PADDED"; + case StrTimeSpecifier::SECOND_DECIMAL: + return "SECOND_DECIMAL"; + case StrTimeSpecifier::MICROSECOND_PADDED: + return "MICROSECOND_PADDED"; + case StrTimeSpecifier::MILLISECOND_PADDED: + return "MILLISECOND_PADDED"; + case StrTimeSpecifier::UTC_OFFSET: + return "UTC_OFFSET"; + case StrTimeSpecifier::TZ_NAME: + return "TZ_NAME"; + case StrTimeSpecifier::DAY_OF_YEAR_PADDED: + return "DAY_OF_YEAR_PADDED"; + case StrTimeSpecifier::DAY_OF_YEAR_DECIMAL: + return "DAY_OF_YEAR_DECIMAL"; + case StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST: + return "WEEK_NUMBER_PADDED_SUN_FIRST"; + case StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST: + return "WEEK_NUMBER_PADDED_MON_FIRST"; + case StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME: + return "LOCALE_APPROPRIATE_DATE_AND_TIME"; + case StrTimeSpecifier::LOCALE_APPROPRIATE_DATE: + return "LOCALE_APPROPRIATE_DATE"; + case StrTimeSpecifier::LOCALE_APPROPRIATE_TIME: + return "LOCALE_APPROPRIATE_TIME"; + case StrTimeSpecifier::NANOSECOND_PADDED: + return "NANOSECOND_PADDED"; + case StrTimeSpecifier::YEAR_ISO: + return "YEAR_ISO"; + case StrTimeSpecifier::WEEKDAY_ISO: + return "WEEKDAY_ISO"; + case StrTimeSpecifier::WEEK_NUMBER_ISO: + return "WEEK_NUMBER_ISO"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StrTimeSpecifier EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStrTimeSpecifierValues(), 36, "StrTimeSpecifier", value)); -} - -const StringUtil::EnumStringLiteral *GetStreamExecutionResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(StreamExecutionResult::CHUNK_READY), "CHUNK_READY" }, - { static_cast(StreamExecutionResult::CHUNK_NOT_READY), "CHUNK_NOT_READY" }, - { static_cast(StreamExecutionResult::EXECUTION_ERROR), "EXECUTION_ERROR" }, - { static_cast(StreamExecutionResult::EXECUTION_CANCELLED), "EXECUTION_CANCELLED" }, - { static_cast(StreamExecutionResult::BLOCKED), "BLOCKED" }, - { static_cast(StreamExecutionResult::NO_TASKS_AVAILABLE), "NO_TASKS_AVAILABLE" }, - { static_cast(StreamExecutionResult::EXECUTION_FINISHED), "EXECUTION_FINISHED" } - }; - return values; + if (StringUtil::Equals(value, "ABBREVIATED_WEEKDAY_NAME")) { + return StrTimeSpecifier::ABBREVIATED_WEEKDAY_NAME; + } + if (StringUtil::Equals(value, "FULL_WEEKDAY_NAME")) { + return StrTimeSpecifier::FULL_WEEKDAY_NAME; + } + if (StringUtil::Equals(value, "WEEKDAY_DECIMAL")) { + return StrTimeSpecifier::WEEKDAY_DECIMAL; + } + if (StringUtil::Equals(value, "DAY_OF_MONTH_PADDED")) { + return StrTimeSpecifier::DAY_OF_MONTH_PADDED; + } + if (StringUtil::Equals(value, "DAY_OF_MONTH")) { + return StrTimeSpecifier::DAY_OF_MONTH; + } + if (StringUtil::Equals(value, "ABBREVIATED_MONTH_NAME")) { + return StrTimeSpecifier::ABBREVIATED_MONTH_NAME; + } + if (StringUtil::Equals(value, "FULL_MONTH_NAME")) { + return StrTimeSpecifier::FULL_MONTH_NAME; + } + if (StringUtil::Equals(value, "MONTH_DECIMAL_PADDED")) { + return StrTimeSpecifier::MONTH_DECIMAL_PADDED; + } + if (StringUtil::Equals(value, "MONTH_DECIMAL")) { + return StrTimeSpecifier::MONTH_DECIMAL; + } + if (StringUtil::Equals(value, "YEAR_WITHOUT_CENTURY_PADDED")) { + return StrTimeSpecifier::YEAR_WITHOUT_CENTURY_PADDED; + } + if (StringUtil::Equals(value, "YEAR_WITHOUT_CENTURY")) { + return StrTimeSpecifier::YEAR_WITHOUT_CENTURY; + } + if (StringUtil::Equals(value, "YEAR_DECIMAL")) { + return StrTimeSpecifier::YEAR_DECIMAL; + } + if (StringUtil::Equals(value, "HOUR_24_PADDED")) { + return StrTimeSpecifier::HOUR_24_PADDED; + } + if (StringUtil::Equals(value, "HOUR_24_DECIMAL")) { + return StrTimeSpecifier::HOUR_24_DECIMAL; + } + if (StringUtil::Equals(value, "HOUR_12_PADDED")) { + return StrTimeSpecifier::HOUR_12_PADDED; + } + if (StringUtil::Equals(value, "HOUR_12_DECIMAL")) { + return StrTimeSpecifier::HOUR_12_DECIMAL; + } + if (StringUtil::Equals(value, "AM_PM")) { + return StrTimeSpecifier::AM_PM; + } + if (StringUtil::Equals(value, "MINUTE_PADDED")) { + return StrTimeSpecifier::MINUTE_PADDED; + } + if (StringUtil::Equals(value, "MINUTE_DECIMAL")) { + return StrTimeSpecifier::MINUTE_DECIMAL; + } + if (StringUtil::Equals(value, "SECOND_PADDED")) { + return StrTimeSpecifier::SECOND_PADDED; + } + if (StringUtil::Equals(value, "SECOND_DECIMAL")) { + return StrTimeSpecifier::SECOND_DECIMAL; + } + if (StringUtil::Equals(value, "MICROSECOND_PADDED")) { + return StrTimeSpecifier::MICROSECOND_PADDED; + } + if (StringUtil::Equals(value, "MILLISECOND_PADDED")) { + return StrTimeSpecifier::MILLISECOND_PADDED; + } + if (StringUtil::Equals(value, "UTC_OFFSET")) { + return StrTimeSpecifier::UTC_OFFSET; + } + if (StringUtil::Equals(value, "TZ_NAME")) { + return StrTimeSpecifier::TZ_NAME; + } + if (StringUtil::Equals(value, "DAY_OF_YEAR_PADDED")) { + return StrTimeSpecifier::DAY_OF_YEAR_PADDED; + } + if (StringUtil::Equals(value, "DAY_OF_YEAR_DECIMAL")) { + return StrTimeSpecifier::DAY_OF_YEAR_DECIMAL; + } + if (StringUtil::Equals(value, "WEEK_NUMBER_PADDED_SUN_FIRST")) { + return StrTimeSpecifier::WEEK_NUMBER_PADDED_SUN_FIRST; + } + if (StringUtil::Equals(value, "WEEK_NUMBER_PADDED_MON_FIRST")) { + return StrTimeSpecifier::WEEK_NUMBER_PADDED_MON_FIRST; + } + if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_DATE_AND_TIME")) { + return StrTimeSpecifier::LOCALE_APPROPRIATE_DATE_AND_TIME; + } + if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_DATE")) { + return StrTimeSpecifier::LOCALE_APPROPRIATE_DATE; + } + if (StringUtil::Equals(value, "LOCALE_APPROPRIATE_TIME")) { + return StrTimeSpecifier::LOCALE_APPROPRIATE_TIME; + } + if (StringUtil::Equals(value, "NANOSECOND_PADDED")) { + return StrTimeSpecifier::NANOSECOND_PADDED; + } + if (StringUtil::Equals(value, "YEAR_ISO")) { + return StrTimeSpecifier::YEAR_ISO; + } + if (StringUtil::Equals(value, "WEEKDAY_ISO")) { + return StrTimeSpecifier::WEEKDAY_ISO; + } + if (StringUtil::Equals(value, "WEEK_NUMBER_ISO")) { + return StrTimeSpecifier::WEEK_NUMBER_ISO; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(StreamExecutionResult value) { - return StringUtil::EnumToString(GetStreamExecutionResultValues(), 7, "StreamExecutionResult", static_cast(value)); + switch(value) { + case StreamExecutionResult::CHUNK_READY: + return "CHUNK_READY"; + case StreamExecutionResult::CHUNK_NOT_READY: + return "CHUNK_NOT_READY"; + case StreamExecutionResult::EXECUTION_ERROR: + return "EXECUTION_ERROR"; + case StreamExecutionResult::EXECUTION_CANCELLED: + return "EXECUTION_CANCELLED"; + case StreamExecutionResult::BLOCKED: + return "BLOCKED"; + case StreamExecutionResult::NO_TASKS_AVAILABLE: + return "NO_TASKS_AVAILABLE"; + case StreamExecutionResult::EXECUTION_FINISHED: + return "EXECUTION_FINISHED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> StreamExecutionResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetStreamExecutionResultValues(), 7, "StreamExecutionResult", value)); -} - -const StringUtil::EnumStringLiteral *GetSubqueryTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(SubqueryType::INVALID), "INVALID" }, - { static_cast(SubqueryType::SCALAR), "SCALAR" }, - { static_cast(SubqueryType::EXISTS), "EXISTS" }, - { static_cast(SubqueryType::NOT_EXISTS), "NOT_EXISTS" }, - { static_cast(SubqueryType::ANY), "ANY" } - }; - return values; + if (StringUtil::Equals(value, "CHUNK_READY")) { + return StreamExecutionResult::CHUNK_READY; + } + if (StringUtil::Equals(value, "CHUNK_NOT_READY")) { + return StreamExecutionResult::CHUNK_NOT_READY; + } + if (StringUtil::Equals(value, "EXECUTION_ERROR")) { + return StreamExecutionResult::EXECUTION_ERROR; + } + if (StringUtil::Equals(value, "EXECUTION_CANCELLED")) { + return StreamExecutionResult::EXECUTION_CANCELLED; + } + if (StringUtil::Equals(value, "BLOCKED")) { + return StreamExecutionResult::BLOCKED; + } + if (StringUtil::Equals(value, "NO_TASKS_AVAILABLE")) { + return StreamExecutionResult::NO_TASKS_AVAILABLE; + } + if (StringUtil::Equals(value, "EXECUTION_FINISHED")) { + return StreamExecutionResult::EXECUTION_FINISHED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(SubqueryType value) { - return StringUtil::EnumToString(GetSubqueryTypeValues(), 5, "SubqueryType", static_cast(value)); + switch(value) { + case SubqueryType::INVALID: + return "INVALID"; + case SubqueryType::SCALAR: + return "SCALAR"; + case SubqueryType::EXISTS: + return "EXISTS"; + case SubqueryType::NOT_EXISTS: + return "NOT_EXISTS"; + case SubqueryType::ANY: + return "ANY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> SubqueryType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetSubqueryTypeValues(), 5, "SubqueryType", value)); -} - -const StringUtil::EnumStringLiteral *GetTableColumnTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TableColumnType::STANDARD), "STANDARD" }, - { static_cast(TableColumnType::GENERATED), "GENERATED" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return SubqueryType::INVALID; + } + if (StringUtil::Equals(value, "SCALAR")) { + return SubqueryType::SCALAR; + } + if (StringUtil::Equals(value, "EXISTS")) { + return SubqueryType::EXISTS; + } + if (StringUtil::Equals(value, "NOT_EXISTS")) { + return SubqueryType::NOT_EXISTS; + } + if (StringUtil::Equals(value, "ANY")) { + return SubqueryType::ANY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TableColumnType value) { - return StringUtil::EnumToString(GetTableColumnTypeValues(), 2, "TableColumnType", static_cast(value)); + switch(value) { + case TableColumnType::STANDARD: + return "STANDARD"; + case TableColumnType::GENERATED: + return "GENERATED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TableColumnType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTableColumnTypeValues(), 2, "TableColumnType", value)); -} - -const StringUtil::EnumStringLiteral *GetTableFilterTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TableFilterType::CONSTANT_COMPARISON), "CONSTANT_COMPARISON" }, - { static_cast(TableFilterType::IS_NULL), "IS_NULL" }, - { static_cast(TableFilterType::IS_NOT_NULL), "IS_NOT_NULL" }, - { static_cast(TableFilterType::CONJUNCTION_OR), "CONJUNCTION_OR" }, - { static_cast(TableFilterType::CONJUNCTION_AND), "CONJUNCTION_AND" }, - { static_cast(TableFilterType::STRUCT_EXTRACT), "STRUCT_EXTRACT" }, - { static_cast(TableFilterType::OPTIONAL_FILTER), "OPTIONAL_FILTER" }, - { static_cast(TableFilterType::IN_FILTER), "IN_FILTER" }, - { static_cast(TableFilterType::DYNAMIC_FILTER), "DYNAMIC_FILTER" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD")) { + return TableColumnType::STANDARD; + } + if (StringUtil::Equals(value, "GENERATED")) { + return TableColumnType::GENERATED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TableFilterType value) { - return StringUtil::EnumToString(GetTableFilterTypeValues(), 9, "TableFilterType", static_cast(value)); + switch(value) { + case TableFilterType::CONSTANT_COMPARISON: + return "CONSTANT_COMPARISON"; + case TableFilterType::IS_NULL: + return "IS_NULL"; + case TableFilterType::IS_NOT_NULL: + return "IS_NOT_NULL"; + case TableFilterType::CONJUNCTION_OR: + return "CONJUNCTION_OR"; + case TableFilterType::CONJUNCTION_AND: + return "CONJUNCTION_AND"; + case TableFilterType::STRUCT_EXTRACT: + return "STRUCT_EXTRACT"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TableFilterType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTableFilterTypeValues(), 9, "TableFilterType", value)); -} - -const StringUtil::EnumStringLiteral *GetTablePartitionInfoValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TablePartitionInfo::NOT_PARTITIONED), "NOT_PARTITIONED" }, - { static_cast(TablePartitionInfo::SINGLE_VALUE_PARTITIONS), "SINGLE_VALUE_PARTITIONS" }, - { static_cast(TablePartitionInfo::OVERLAPPING_PARTITIONS), "OVERLAPPING_PARTITIONS" }, - { static_cast(TablePartitionInfo::DISJOINT_PARTITIONS), "DISJOINT_PARTITIONS" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(TablePartitionInfo value) { - return StringUtil::EnumToString(GetTablePartitionInfoValues(), 4, "TablePartitionInfo", static_cast(value)); -} - -template<> -TablePartitionInfo EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTablePartitionInfoValues(), 4, "TablePartitionInfo", value)); -} - -const StringUtil::EnumStringLiteral *GetTableReferenceTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TableReferenceType::INVALID), "INVALID" }, - { static_cast(TableReferenceType::BASE_TABLE), "BASE_TABLE" }, - { static_cast(TableReferenceType::SUBQUERY), "SUBQUERY" }, - { static_cast(TableReferenceType::JOIN), "JOIN" }, - { static_cast(TableReferenceType::TABLE_FUNCTION), "TABLE_FUNCTION" }, - { static_cast(TableReferenceType::EXPRESSION_LIST), "EXPRESSION_LIST" }, - { static_cast(TableReferenceType::CTE), "CTE" }, - { static_cast(TableReferenceType::EMPTY_FROM), "EMPTY" }, - { static_cast(TableReferenceType::PIVOT), "PIVOT" }, - { static_cast(TableReferenceType::SHOW_REF), "SHOW_REF" }, - { static_cast(TableReferenceType::COLUMN_DATA), "COLUMN_DATA" }, - { static_cast(TableReferenceType::DELIM_GET), "DELIM_GET" } - }; - return values; + if (StringUtil::Equals(value, "CONSTANT_COMPARISON")) { + return TableFilterType::CONSTANT_COMPARISON; + } + if (StringUtil::Equals(value, "IS_NULL")) { + return TableFilterType::IS_NULL; + } + if (StringUtil::Equals(value, "IS_NOT_NULL")) { + return TableFilterType::IS_NOT_NULL; + } + if (StringUtil::Equals(value, "CONJUNCTION_OR")) { + return TableFilterType::CONJUNCTION_OR; + } + if (StringUtil::Equals(value, "CONJUNCTION_AND")) { + return TableFilterType::CONJUNCTION_AND; + } + if (StringUtil::Equals(value, "STRUCT_EXTRACT")) { + return TableFilterType::STRUCT_EXTRACT; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TableReferenceType value) { - return StringUtil::EnumToString(GetTableReferenceTypeValues(), 12, "TableReferenceType", static_cast(value)); + switch(value) { + case TableReferenceType::INVALID: + return "INVALID"; + case TableReferenceType::BASE_TABLE: + return "BASE_TABLE"; + case TableReferenceType::SUBQUERY: + return "SUBQUERY"; + case TableReferenceType::JOIN: + return "JOIN"; + case TableReferenceType::TABLE_FUNCTION: + return "TABLE_FUNCTION"; + case TableReferenceType::EXPRESSION_LIST: + return "EXPRESSION_LIST"; + case TableReferenceType::CTE: + return "CTE"; + case TableReferenceType::EMPTY_FROM: + return "EMPTY"; + case TableReferenceType::PIVOT: + return "PIVOT"; + case TableReferenceType::SHOW_REF: + return "SHOW_REF"; + case TableReferenceType::COLUMN_DATA: + return "COLUMN_DATA"; + case TableReferenceType::DELIM_GET: + return "DELIM_GET"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TableReferenceType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTableReferenceTypeValues(), 12, "TableReferenceType", value)); -} - -const StringUtil::EnumStringLiteral *GetTableScanTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TableScanType::TABLE_SCAN_REGULAR), "TABLE_SCAN_REGULAR" }, - { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS), "TABLE_SCAN_COMMITTED_ROWS" }, - { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES), "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES" }, - { static_cast(TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED), "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED" }, - { static_cast(TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS), "TABLE_SCAN_LATEST_COMMITTED_ROWS" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return TableReferenceType::INVALID; + } + if (StringUtil::Equals(value, "BASE_TABLE")) { + return TableReferenceType::BASE_TABLE; + } + if (StringUtil::Equals(value, "SUBQUERY")) { + return TableReferenceType::SUBQUERY; + } + if (StringUtil::Equals(value, "JOIN")) { + return TableReferenceType::JOIN; + } + if (StringUtil::Equals(value, "TABLE_FUNCTION")) { + return TableReferenceType::TABLE_FUNCTION; + } + if (StringUtil::Equals(value, "EXPRESSION_LIST")) { + return TableReferenceType::EXPRESSION_LIST; + } + if (StringUtil::Equals(value, "CTE")) { + return TableReferenceType::CTE; + } + if (StringUtil::Equals(value, "EMPTY")) { + return TableReferenceType::EMPTY_FROM; + } + if (StringUtil::Equals(value, "PIVOT")) { + return TableReferenceType::PIVOT; + } + if (StringUtil::Equals(value, "SHOW_REF")) { + return TableReferenceType::SHOW_REF; + } + if (StringUtil::Equals(value, "COLUMN_DATA")) { + return TableReferenceType::COLUMN_DATA; + } + if (StringUtil::Equals(value, "DELIM_GET")) { + return TableReferenceType::DELIM_GET; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TableScanType value) { - return StringUtil::EnumToString(GetTableScanTypeValues(), 5, "TableScanType", static_cast(value)); + switch(value) { + case TableScanType::TABLE_SCAN_REGULAR: + return "TABLE_SCAN_REGULAR"; + case TableScanType::TABLE_SCAN_COMMITTED_ROWS: + return "TABLE_SCAN_COMMITTED_ROWS"; + case TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES: + return "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES"; + case TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED: + return "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED"; + case TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS: + return "TABLE_SCAN_LATEST_COMMITTED_ROWS"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TableScanType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTableScanTypeValues(), 5, "TableScanType", value)); -} - -const StringUtil::EnumStringLiteral *GetTaskExecutionModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TaskExecutionMode::PROCESS_ALL), "PROCESS_ALL" }, - { static_cast(TaskExecutionMode::PROCESS_PARTIAL), "PROCESS_PARTIAL" } - }; - return values; + if (StringUtil::Equals(value, "TABLE_SCAN_REGULAR")) { + return TableScanType::TABLE_SCAN_REGULAR; + } + if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS")) { + return TableScanType::TABLE_SCAN_COMMITTED_ROWS; + } + if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES")) { + return TableScanType::TABLE_SCAN_COMMITTED_ROWS_DISALLOW_UPDATES; + } + if (StringUtil::Equals(value, "TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED")) { + return TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED; + } + if (StringUtil::Equals(value, "TABLE_SCAN_LATEST_COMMITTED_ROWS")) { + return TableScanType::TABLE_SCAN_LATEST_COMMITTED_ROWS; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TaskExecutionMode value) { - return StringUtil::EnumToString(GetTaskExecutionModeValues(), 2, "TaskExecutionMode", static_cast(value)); + switch(value) { + case TaskExecutionMode::PROCESS_ALL: + return "PROCESS_ALL"; + case TaskExecutionMode::PROCESS_PARTIAL: + return "PROCESS_PARTIAL"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TaskExecutionMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTaskExecutionModeValues(), 2, "TaskExecutionMode", value)); -} - -const StringUtil::EnumStringLiteral *GetTaskExecutionResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TaskExecutionResult::TASK_FINISHED), "TASK_FINISHED" }, - { static_cast(TaskExecutionResult::TASK_NOT_FINISHED), "TASK_NOT_FINISHED" }, - { static_cast(TaskExecutionResult::TASK_ERROR), "TASK_ERROR" }, - { static_cast(TaskExecutionResult::TASK_BLOCKED), "TASK_BLOCKED" } - }; - return values; + if (StringUtil::Equals(value, "PROCESS_ALL")) { + return TaskExecutionMode::PROCESS_ALL; + } + if (StringUtil::Equals(value, "PROCESS_PARTIAL")) { + return TaskExecutionMode::PROCESS_PARTIAL; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TaskExecutionResult value) { - return StringUtil::EnumToString(GetTaskExecutionResultValues(), 4, "TaskExecutionResult", static_cast(value)); + switch(value) { + case TaskExecutionResult::TASK_FINISHED: + return "TASK_FINISHED"; + case TaskExecutionResult::TASK_NOT_FINISHED: + return "TASK_NOT_FINISHED"; + case TaskExecutionResult::TASK_ERROR: + return "TASK_ERROR"; + case TaskExecutionResult::TASK_BLOCKED: + return "TASK_BLOCKED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TaskExecutionResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTaskExecutionResultValues(), 4, "TaskExecutionResult", value)); -} - -const StringUtil::EnumStringLiteral *GetTemporaryBufferSizeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TemporaryBufferSize::INVALID), "INVALID" }, - { static_cast(TemporaryBufferSize::S32K), "S32K" }, - { static_cast(TemporaryBufferSize::S64K), "S64K" }, - { static_cast(TemporaryBufferSize::S96K), "S96K" }, - { static_cast(TemporaryBufferSize::S128K), "S128K" }, - { static_cast(TemporaryBufferSize::S160K), "S160K" }, - { static_cast(TemporaryBufferSize::S192K), "S192K" }, - { static_cast(TemporaryBufferSize::S224K), "S224K" }, - { static_cast(TemporaryBufferSize::DEFAULT), "DEFAULT" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(TemporaryBufferSize value) { - return StringUtil::EnumToString(GetTemporaryBufferSizeValues(), 9, "TemporaryBufferSize", static_cast(value)); -} - -template<> -TemporaryBufferSize EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTemporaryBufferSizeValues(), 9, "TemporaryBufferSize", value)); -} - -const StringUtil::EnumStringLiteral *GetTemporaryCompressionLevelValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_FIVE), "ZSTD_MINUS_FIVE" }, - { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_THREE), "ZSTD_MINUS_THREE" }, - { static_cast(TemporaryCompressionLevel::ZSTD_MINUS_ONE), "ZSTD_MINUS_ONE" }, - { static_cast(TemporaryCompressionLevel::UNCOMPRESSED), "UNCOMPRESSED" }, - { static_cast(TemporaryCompressionLevel::ZSTD_ONE), "ZSTD_ONE" }, - { static_cast(TemporaryCompressionLevel::ZSTD_THREE), "ZSTD_THREE" }, - { static_cast(TemporaryCompressionLevel::ZSTD_FIVE), "ZSTD_FIVE" } - }; - return values; -} - -template<> -const char* EnumUtil::ToChars(TemporaryCompressionLevel value) { - return StringUtil::EnumToString(GetTemporaryCompressionLevelValues(), 7, "TemporaryCompressionLevel", static_cast(value)); -} - -template<> -TemporaryCompressionLevel EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTemporaryCompressionLevelValues(), 7, "TemporaryCompressionLevel", value)); -} - -const StringUtil::EnumStringLiteral *GetTimestampCastResultValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TimestampCastResult::SUCCESS), "SUCCESS" }, - { static_cast(TimestampCastResult::ERROR_INCORRECT_FORMAT), "ERROR_INCORRECT_FORMAT" }, - { static_cast(TimestampCastResult::ERROR_NON_UTC_TIMEZONE), "ERROR_NON_UTC_TIMEZONE" }, - { static_cast(TimestampCastResult::ERROR_RANGE), "ERROR_RANGE" } - }; - return values; + if (StringUtil::Equals(value, "TASK_FINISHED")) { + return TaskExecutionResult::TASK_FINISHED; + } + if (StringUtil::Equals(value, "TASK_NOT_FINISHED")) { + return TaskExecutionResult::TASK_NOT_FINISHED; + } + if (StringUtil::Equals(value, "TASK_ERROR")) { + return TaskExecutionResult::TASK_ERROR; + } + if (StringUtil::Equals(value, "TASK_BLOCKED")) { + return TaskExecutionResult::TASK_BLOCKED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TimestampCastResult value) { - return StringUtil::EnumToString(GetTimestampCastResultValues(), 4, "TimestampCastResult", static_cast(value)); + switch(value) { + case TimestampCastResult::SUCCESS: + return "SUCCESS"; + case TimestampCastResult::ERROR_INCORRECT_FORMAT: + return "ERROR_INCORRECT_FORMAT"; + case TimestampCastResult::ERROR_NON_UTC_TIMEZONE: + return "ERROR_NON_UTC_TIMEZONE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TimestampCastResult EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTimestampCastResultValues(), 4, "TimestampCastResult", value)); -} - -const StringUtil::EnumStringLiteral *GetTransactionModifierTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER), "TRANSACTION_DEFAULT_MODIFIER" }, - { static_cast(TransactionModifierType::TRANSACTION_READ_ONLY), "TRANSACTION_READ_ONLY" }, - { static_cast(TransactionModifierType::TRANSACTION_READ_WRITE), "TRANSACTION_READ_WRITE" } - }; - return values; + if (StringUtil::Equals(value, "SUCCESS")) { + return TimestampCastResult::SUCCESS; + } + if (StringUtil::Equals(value, "ERROR_INCORRECT_FORMAT")) { + return TimestampCastResult::ERROR_INCORRECT_FORMAT; + } + if (StringUtil::Equals(value, "ERROR_NON_UTC_TIMEZONE")) { + return TimestampCastResult::ERROR_NON_UTC_TIMEZONE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TransactionModifierType value) { - return StringUtil::EnumToString(GetTransactionModifierTypeValues(), 3, "TransactionModifierType", static_cast(value)); + switch(value) { + case TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER: + return "TRANSACTION_DEFAULT_MODIFIER"; + case TransactionModifierType::TRANSACTION_READ_ONLY: + return "TRANSACTION_READ_ONLY"; + case TransactionModifierType::TRANSACTION_READ_WRITE: + return "TRANSACTION_READ_WRITE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TransactionModifierType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTransactionModifierTypeValues(), 3, "TransactionModifierType", value)); -} - -const StringUtil::EnumStringLiteral *GetTransactionTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TransactionType::INVALID), "INVALID" }, - { static_cast(TransactionType::BEGIN_TRANSACTION), "BEGIN_TRANSACTION" }, - { static_cast(TransactionType::COMMIT), "COMMIT" }, - { static_cast(TransactionType::ROLLBACK), "ROLLBACK" } - }; - return values; + if (StringUtil::Equals(value, "TRANSACTION_DEFAULT_MODIFIER")) { + return TransactionModifierType::TRANSACTION_DEFAULT_MODIFIER; + } + if (StringUtil::Equals(value, "TRANSACTION_READ_ONLY")) { + return TransactionModifierType::TRANSACTION_READ_ONLY; + } + if (StringUtil::Equals(value, "TRANSACTION_READ_WRITE")) { + return TransactionModifierType::TRANSACTION_READ_WRITE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TransactionType value) { - return StringUtil::EnumToString(GetTransactionTypeValues(), 4, "TransactionType", static_cast(value)); + switch(value) { + case TransactionType::INVALID: + return "INVALID"; + case TransactionType::BEGIN_TRANSACTION: + return "BEGIN_TRANSACTION"; + case TransactionType::COMMIT: + return "COMMIT"; + case TransactionType::ROLLBACK: + return "ROLLBACK"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TransactionType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTransactionTypeValues(), 4, "TransactionType", value)); -} - -const StringUtil::EnumStringLiteral *GetTupleDataPinPropertiesValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(TupleDataPinProperties::INVALID), "INVALID" }, - { static_cast(TupleDataPinProperties::KEEP_EVERYTHING_PINNED), "KEEP_EVERYTHING_PINNED" }, - { static_cast(TupleDataPinProperties::UNPIN_AFTER_DONE), "UNPIN_AFTER_DONE" }, - { static_cast(TupleDataPinProperties::DESTROY_AFTER_DONE), "DESTROY_AFTER_DONE" }, - { static_cast(TupleDataPinProperties::ALREADY_PINNED), "ALREADY_PINNED" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return TransactionType::INVALID; + } + if (StringUtil::Equals(value, "BEGIN_TRANSACTION")) { + return TransactionType::BEGIN_TRANSACTION; + } + if (StringUtil::Equals(value, "COMMIT")) { + return TransactionType::COMMIT; + } + if (StringUtil::Equals(value, "ROLLBACK")) { + return TransactionType::ROLLBACK; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(TupleDataPinProperties value) { - return StringUtil::EnumToString(GetTupleDataPinPropertiesValues(), 5, "TupleDataPinProperties", static_cast(value)); + switch(value) { + case TupleDataPinProperties::INVALID: + return "INVALID"; + case TupleDataPinProperties::KEEP_EVERYTHING_PINNED: + return "KEEP_EVERYTHING_PINNED"; + case TupleDataPinProperties::UNPIN_AFTER_DONE: + return "UNPIN_AFTER_DONE"; + case TupleDataPinProperties::DESTROY_AFTER_DONE: + return "DESTROY_AFTER_DONE"; + case TupleDataPinProperties::ALREADY_PINNED: + return "ALREADY_PINNED"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> TupleDataPinProperties EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetTupleDataPinPropertiesValues(), 5, "TupleDataPinProperties", value)); -} - -const StringUtil::EnumStringLiteral *GetUndoFlagsValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(UndoFlags::EMPTY_ENTRY), "EMPTY_ENTRY" }, - { static_cast(UndoFlags::CATALOG_ENTRY), "CATALOG_ENTRY" }, - { static_cast(UndoFlags::INSERT_TUPLE), "INSERT_TUPLE" }, - { static_cast(UndoFlags::DELETE_TUPLE), "DELETE_TUPLE" }, - { static_cast(UndoFlags::UPDATE_TUPLE), "UPDATE_TUPLE" }, - { static_cast(UndoFlags::SEQUENCE_VALUE), "SEQUENCE_VALUE" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return TupleDataPinProperties::INVALID; + } + if (StringUtil::Equals(value, "KEEP_EVERYTHING_PINNED")) { + return TupleDataPinProperties::KEEP_EVERYTHING_PINNED; + } + if (StringUtil::Equals(value, "UNPIN_AFTER_DONE")) { + return TupleDataPinProperties::UNPIN_AFTER_DONE; + } + if (StringUtil::Equals(value, "DESTROY_AFTER_DONE")) { + return TupleDataPinProperties::DESTROY_AFTER_DONE; + } + if (StringUtil::Equals(value, "ALREADY_PINNED")) { + return TupleDataPinProperties::ALREADY_PINNED; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(UndoFlags value) { - return StringUtil::EnumToString(GetUndoFlagsValues(), 6, "UndoFlags", static_cast(value)); + switch(value) { + case UndoFlags::EMPTY_ENTRY: + return "EMPTY_ENTRY"; + case UndoFlags::CATALOG_ENTRY: + return "CATALOG_ENTRY"; + case UndoFlags::INSERT_TUPLE: + return "INSERT_TUPLE"; + case UndoFlags::DELETE_TUPLE: + return "DELETE_TUPLE"; + case UndoFlags::UPDATE_TUPLE: + return "UPDATE_TUPLE"; + case UndoFlags::SEQUENCE_VALUE: + return "SEQUENCE_VALUE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> UndoFlags EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetUndoFlagsValues(), 6, "UndoFlags", value)); -} - -const StringUtil::EnumStringLiteral *GetUnionInvalidReasonValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(UnionInvalidReason::VALID), "VALID" }, - { static_cast(UnionInvalidReason::TAG_OUT_OF_RANGE), "TAG_OUT_OF_RANGE" }, - { static_cast(UnionInvalidReason::NO_MEMBERS), "NO_MEMBERS" }, - { static_cast(UnionInvalidReason::VALIDITY_OVERLAP), "VALIDITY_OVERLAP" }, - { static_cast(UnionInvalidReason::TAG_MISMATCH), "TAG_MISMATCH" }, - { static_cast(UnionInvalidReason::NULL_TAG), "NULL_TAG" } - }; - return values; + if (StringUtil::Equals(value, "EMPTY_ENTRY")) { + return UndoFlags::EMPTY_ENTRY; + } + if (StringUtil::Equals(value, "CATALOG_ENTRY")) { + return UndoFlags::CATALOG_ENTRY; + } + if (StringUtil::Equals(value, "INSERT_TUPLE")) { + return UndoFlags::INSERT_TUPLE; + } + if (StringUtil::Equals(value, "DELETE_TUPLE")) { + return UndoFlags::DELETE_TUPLE; + } + if (StringUtil::Equals(value, "UPDATE_TUPLE")) { + return UndoFlags::UPDATE_TUPLE; + } + if (StringUtil::Equals(value, "SEQUENCE_VALUE")) { + return UndoFlags::SEQUENCE_VALUE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(UnionInvalidReason value) { - return StringUtil::EnumToString(GetUnionInvalidReasonValues(), 6, "UnionInvalidReason", static_cast(value)); + switch(value) { + case UnionInvalidReason::VALID: + return "VALID"; + case UnionInvalidReason::TAG_OUT_OF_RANGE: + return "TAG_OUT_OF_RANGE"; + case UnionInvalidReason::NO_MEMBERS: + return "NO_MEMBERS"; + case UnionInvalidReason::VALIDITY_OVERLAP: + return "VALIDITY_OVERLAP"; + case UnionInvalidReason::TAG_MISMATCH: + return "TAG_MISMATCH"; + case UnionInvalidReason::NULL_TAG: + return "NULL_TAG"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> UnionInvalidReason EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetUnionInvalidReasonValues(), 6, "UnionInvalidReason", value)); -} - -const StringUtil::EnumStringLiteral *GetVectorAuxiliaryDataTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(VectorAuxiliaryDataType::ARROW_AUXILIARY), "ARROW_AUXILIARY" } - }; - return values; + if (StringUtil::Equals(value, "VALID")) { + return UnionInvalidReason::VALID; + } + if (StringUtil::Equals(value, "TAG_OUT_OF_RANGE")) { + return UnionInvalidReason::TAG_OUT_OF_RANGE; + } + if (StringUtil::Equals(value, "NO_MEMBERS")) { + return UnionInvalidReason::NO_MEMBERS; + } + if (StringUtil::Equals(value, "VALIDITY_OVERLAP")) { + return UnionInvalidReason::VALIDITY_OVERLAP; + } + if (StringUtil::Equals(value, "TAG_MISMATCH")) { + return UnionInvalidReason::TAG_MISMATCH; + } + if (StringUtil::Equals(value, "NULL_TAG")) { + return UnionInvalidReason::NULL_TAG; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(VectorAuxiliaryDataType value) { - return StringUtil::EnumToString(GetVectorAuxiliaryDataTypeValues(), 1, "VectorAuxiliaryDataType", static_cast(value)); + switch(value) { + case VectorAuxiliaryDataType::ARROW_AUXILIARY: + return "ARROW_AUXILIARY"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> VectorAuxiliaryDataType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVectorAuxiliaryDataTypeValues(), 1, "VectorAuxiliaryDataType", value)); -} - -const StringUtil::EnumStringLiteral *GetVectorBufferTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(VectorBufferType::STANDARD_BUFFER), "STANDARD_BUFFER" }, - { static_cast(VectorBufferType::DICTIONARY_BUFFER), "DICTIONARY_BUFFER" }, - { static_cast(VectorBufferType::VECTOR_CHILD_BUFFER), "VECTOR_CHILD_BUFFER" }, - { static_cast(VectorBufferType::STRING_BUFFER), "STRING_BUFFER" }, - { static_cast(VectorBufferType::FSST_BUFFER), "FSST_BUFFER" }, - { static_cast(VectorBufferType::STRUCT_BUFFER), "STRUCT_BUFFER" }, - { static_cast(VectorBufferType::LIST_BUFFER), "LIST_BUFFER" }, - { static_cast(VectorBufferType::MANAGED_BUFFER), "MANAGED_BUFFER" }, - { static_cast(VectorBufferType::OPAQUE_BUFFER), "OPAQUE_BUFFER" }, - { static_cast(VectorBufferType::ARRAY_BUFFER), "ARRAY_BUFFER" } - }; - return values; + if (StringUtil::Equals(value, "ARROW_AUXILIARY")) { + return VectorAuxiliaryDataType::ARROW_AUXILIARY; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(VectorBufferType value) { - return StringUtil::EnumToString(GetVectorBufferTypeValues(), 10, "VectorBufferType", static_cast(value)); + switch(value) { + case VectorBufferType::STANDARD_BUFFER: + return "STANDARD_BUFFER"; + case VectorBufferType::DICTIONARY_BUFFER: + return "DICTIONARY_BUFFER"; + case VectorBufferType::VECTOR_CHILD_BUFFER: + return "VECTOR_CHILD_BUFFER"; + case VectorBufferType::STRING_BUFFER: + return "STRING_BUFFER"; + case VectorBufferType::FSST_BUFFER: + return "FSST_BUFFER"; + case VectorBufferType::STRUCT_BUFFER: + return "STRUCT_BUFFER"; + case VectorBufferType::LIST_BUFFER: + return "LIST_BUFFER"; + case VectorBufferType::MANAGED_BUFFER: + return "MANAGED_BUFFER"; + case VectorBufferType::OPAQUE_BUFFER: + return "OPAQUE_BUFFER"; + case VectorBufferType::ARRAY_BUFFER: + return "ARRAY_BUFFER"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> VectorBufferType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVectorBufferTypeValues(), 10, "VectorBufferType", value)); -} - -const StringUtil::EnumStringLiteral *GetVectorTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(VectorType::FLAT_VECTOR), "FLAT_VECTOR" }, - { static_cast(VectorType::FSST_VECTOR), "FSST_VECTOR" }, - { static_cast(VectorType::CONSTANT_VECTOR), "CONSTANT_VECTOR" }, - { static_cast(VectorType::DICTIONARY_VECTOR), "DICTIONARY_VECTOR" }, - { static_cast(VectorType::SEQUENCE_VECTOR), "SEQUENCE_VECTOR" } - }; - return values; + if (StringUtil::Equals(value, "STANDARD_BUFFER")) { + return VectorBufferType::STANDARD_BUFFER; + } + if (StringUtil::Equals(value, "DICTIONARY_BUFFER")) { + return VectorBufferType::DICTIONARY_BUFFER; + } + if (StringUtil::Equals(value, "VECTOR_CHILD_BUFFER")) { + return VectorBufferType::VECTOR_CHILD_BUFFER; + } + if (StringUtil::Equals(value, "STRING_BUFFER")) { + return VectorBufferType::STRING_BUFFER; + } + if (StringUtil::Equals(value, "FSST_BUFFER")) { + return VectorBufferType::FSST_BUFFER; + } + if (StringUtil::Equals(value, "STRUCT_BUFFER")) { + return VectorBufferType::STRUCT_BUFFER; + } + if (StringUtil::Equals(value, "LIST_BUFFER")) { + return VectorBufferType::LIST_BUFFER; + } + if (StringUtil::Equals(value, "MANAGED_BUFFER")) { + return VectorBufferType::MANAGED_BUFFER; + } + if (StringUtil::Equals(value, "OPAQUE_BUFFER")) { + return VectorBufferType::OPAQUE_BUFFER; + } + if (StringUtil::Equals(value, "ARRAY_BUFFER")) { + return VectorBufferType::ARRAY_BUFFER; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(VectorType value) { - return StringUtil::EnumToString(GetVectorTypeValues(), 5, "VectorType", static_cast(value)); + switch(value) { + case VectorType::FLAT_VECTOR: + return "FLAT_VECTOR"; + case VectorType::FSST_VECTOR: + return "FSST_VECTOR"; + case VectorType::CONSTANT_VECTOR: + return "CONSTANT_VECTOR"; + case VectorType::DICTIONARY_VECTOR: + return "DICTIONARY_VECTOR"; + case VectorType::SEQUENCE_VECTOR: + return "SEQUENCE_VECTOR"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> VectorType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVectorTypeValues(), 5, "VectorType", value)); -} - -const StringUtil::EnumStringLiteral *GetVerificationTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(VerificationType::ORIGINAL), "ORIGINAL" }, - { static_cast(VerificationType::COPIED), "COPIED" }, - { static_cast(VerificationType::DESERIALIZED), "DESERIALIZED" }, - { static_cast(VerificationType::PARSED), "PARSED" }, - { static_cast(VerificationType::UNOPTIMIZED), "UNOPTIMIZED" }, - { static_cast(VerificationType::NO_OPERATOR_CACHING), "NO_OPERATOR_CACHING" }, - { static_cast(VerificationType::PREPARED), "PREPARED" }, - { static_cast(VerificationType::EXTERNAL), "EXTERNAL" }, - { static_cast(VerificationType::FETCH_ROW_AS_SCAN), "FETCH_ROW_AS_SCAN" }, - { static_cast(VerificationType::INVALID), "INVALID" } - }; - return values; + if (StringUtil::Equals(value, "FLAT_VECTOR")) { + return VectorType::FLAT_VECTOR; + } + if (StringUtil::Equals(value, "FSST_VECTOR")) { + return VectorType::FSST_VECTOR; + } + if (StringUtil::Equals(value, "CONSTANT_VECTOR")) { + return VectorType::CONSTANT_VECTOR; + } + if (StringUtil::Equals(value, "DICTIONARY_VECTOR")) { + return VectorType::DICTIONARY_VECTOR; + } + if (StringUtil::Equals(value, "SEQUENCE_VECTOR")) { + return VectorType::SEQUENCE_VECTOR; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(VerificationType value) { - return StringUtil::EnumToString(GetVerificationTypeValues(), 10, "VerificationType", static_cast(value)); + switch(value) { + case VerificationType::ORIGINAL: + return "ORIGINAL"; + case VerificationType::COPIED: + return "COPIED"; + case VerificationType::DESERIALIZED: + return "DESERIALIZED"; + case VerificationType::PARSED: + return "PARSED"; + case VerificationType::UNOPTIMIZED: + return "UNOPTIMIZED"; + case VerificationType::NO_OPERATOR_CACHING: + return "NO_OPERATOR_CACHING"; + case VerificationType::PREPARED: + return "PREPARED"; + case VerificationType::EXTERNAL: + return "EXTERNAL"; + case VerificationType::FETCH_ROW_AS_SCAN: + return "FETCH_ROW_AS_SCAN"; + case VerificationType::INVALID: + return "INVALID"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> VerificationType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVerificationTypeValues(), 10, "VerificationType", value)); -} - -const StringUtil::EnumStringLiteral *GetVerifyExistenceTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(VerifyExistenceType::APPEND), "APPEND" }, - { static_cast(VerifyExistenceType::APPEND_FK), "APPEND_FK" }, - { static_cast(VerifyExistenceType::DELETE_FK), "DELETE_FK" } - }; - return values; + if (StringUtil::Equals(value, "ORIGINAL")) { + return VerificationType::ORIGINAL; + } + if (StringUtil::Equals(value, "COPIED")) { + return VerificationType::COPIED; + } + if (StringUtil::Equals(value, "DESERIALIZED")) { + return VerificationType::DESERIALIZED; + } + if (StringUtil::Equals(value, "PARSED")) { + return VerificationType::PARSED; + } + if (StringUtil::Equals(value, "UNOPTIMIZED")) { + return VerificationType::UNOPTIMIZED; + } + if (StringUtil::Equals(value, "NO_OPERATOR_CACHING")) { + return VerificationType::NO_OPERATOR_CACHING; + } + if (StringUtil::Equals(value, "PREPARED")) { + return VerificationType::PREPARED; + } + if (StringUtil::Equals(value, "EXTERNAL")) { + return VerificationType::EXTERNAL; + } + if (StringUtil::Equals(value, "FETCH_ROW_AS_SCAN")) { + return VerificationType::FETCH_ROW_AS_SCAN; + } + if (StringUtil::Equals(value, "INVALID")) { + return VerificationType::INVALID; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(VerifyExistenceType value) { - return StringUtil::EnumToString(GetVerifyExistenceTypeValues(), 3, "VerifyExistenceType", static_cast(value)); + switch(value) { + case VerifyExistenceType::APPEND: + return "APPEND"; + case VerifyExistenceType::APPEND_FK: + return "APPEND_FK"; + case VerifyExistenceType::DELETE_FK: + return "DELETE_FK"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> VerifyExistenceType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetVerifyExistenceTypeValues(), 3, "VerifyExistenceType", value)); -} - -const StringUtil::EnumStringLiteral *GetWALTypeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(WALType::INVALID), "INVALID" }, - { static_cast(WALType::CREATE_TABLE), "CREATE_TABLE" }, - { static_cast(WALType::DROP_TABLE), "DROP_TABLE" }, - { static_cast(WALType::CREATE_SCHEMA), "CREATE_SCHEMA" }, - { static_cast(WALType::DROP_SCHEMA), "DROP_SCHEMA" }, - { static_cast(WALType::CREATE_VIEW), "CREATE_VIEW" }, - { static_cast(WALType::DROP_VIEW), "DROP_VIEW" }, - { static_cast(WALType::CREATE_SEQUENCE), "CREATE_SEQUENCE" }, - { static_cast(WALType::DROP_SEQUENCE), "DROP_SEQUENCE" }, - { static_cast(WALType::SEQUENCE_VALUE), "SEQUENCE_VALUE" }, - { static_cast(WALType::CREATE_MACRO), "CREATE_MACRO" }, - { static_cast(WALType::DROP_MACRO), "DROP_MACRO" }, - { static_cast(WALType::CREATE_TYPE), "CREATE_TYPE" }, - { static_cast(WALType::DROP_TYPE), "DROP_TYPE" }, - { static_cast(WALType::ALTER_INFO), "ALTER_INFO" }, - { static_cast(WALType::CREATE_TABLE_MACRO), "CREATE_TABLE_MACRO" }, - { static_cast(WALType::DROP_TABLE_MACRO), "DROP_TABLE_MACRO" }, - { static_cast(WALType::CREATE_INDEX), "CREATE_INDEX" }, - { static_cast(WALType::DROP_INDEX), "DROP_INDEX" }, - { static_cast(WALType::USE_TABLE), "USE_TABLE" }, - { static_cast(WALType::INSERT_TUPLE), "INSERT_TUPLE" }, - { static_cast(WALType::DELETE_TUPLE), "DELETE_TUPLE" }, - { static_cast(WALType::UPDATE_TUPLE), "UPDATE_TUPLE" }, - { static_cast(WALType::ROW_GROUP_DATA), "ROW_GROUP_DATA" }, - { static_cast(WALType::WAL_VERSION), "WAL_VERSION" }, - { static_cast(WALType::CHECKPOINT), "CHECKPOINT" }, - { static_cast(WALType::WAL_FLUSH), "WAL_FLUSH" } - }; - return values; + if (StringUtil::Equals(value, "APPEND")) { + return VerifyExistenceType::APPEND; + } + if (StringUtil::Equals(value, "APPEND_FK")) { + return VerifyExistenceType::APPEND_FK; + } + if (StringUtil::Equals(value, "DELETE_FK")) { + return VerifyExistenceType::DELETE_FK; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(WALType value) { - return StringUtil::EnumToString(GetWALTypeValues(), 27, "WALType", static_cast(value)); + switch(value) { + case WALType::INVALID: + return "INVALID"; + case WALType::CREATE_TABLE: + return "CREATE_TABLE"; + case WALType::DROP_TABLE: + return "DROP_TABLE"; + case WALType::CREATE_SCHEMA: + return "CREATE_SCHEMA"; + case WALType::DROP_SCHEMA: + return "DROP_SCHEMA"; + case WALType::CREATE_VIEW: + return "CREATE_VIEW"; + case WALType::DROP_VIEW: + return "DROP_VIEW"; + case WALType::CREATE_SEQUENCE: + return "CREATE_SEQUENCE"; + case WALType::DROP_SEQUENCE: + return "DROP_SEQUENCE"; + case WALType::SEQUENCE_VALUE: + return "SEQUENCE_VALUE"; + case WALType::CREATE_MACRO: + return "CREATE_MACRO"; + case WALType::DROP_MACRO: + return "DROP_MACRO"; + case WALType::CREATE_TYPE: + return "CREATE_TYPE"; + case WALType::DROP_TYPE: + return "DROP_TYPE"; + case WALType::ALTER_INFO: + return "ALTER_INFO"; + case WALType::CREATE_TABLE_MACRO: + return "CREATE_TABLE_MACRO"; + case WALType::DROP_TABLE_MACRO: + return "DROP_TABLE_MACRO"; + case WALType::CREATE_INDEX: + return "CREATE_INDEX"; + case WALType::DROP_INDEX: + return "DROP_INDEX"; + case WALType::USE_TABLE: + return "USE_TABLE"; + case WALType::INSERT_TUPLE: + return "INSERT_TUPLE"; + case WALType::DELETE_TUPLE: + return "DELETE_TUPLE"; + case WALType::UPDATE_TUPLE: + return "UPDATE_TUPLE"; + case WALType::ROW_GROUP_DATA: + return "ROW_GROUP_DATA"; + case WALType::WAL_VERSION: + return "WAL_VERSION"; + case WALType::CHECKPOINT: + return "CHECKPOINT"; + case WALType::WAL_FLUSH: + return "WAL_FLUSH"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> WALType EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetWALTypeValues(), 27, "WALType", value)); -} - -const StringUtil::EnumStringLiteral *GetWindowAggregationModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(WindowAggregationMode::WINDOW), "WINDOW" }, - { static_cast(WindowAggregationMode::COMBINE), "COMBINE" }, - { static_cast(WindowAggregationMode::SEPARATE), "SEPARATE" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return WALType::INVALID; + } + if (StringUtil::Equals(value, "CREATE_TABLE")) { + return WALType::CREATE_TABLE; + } + if (StringUtil::Equals(value, "DROP_TABLE")) { + return WALType::DROP_TABLE; + } + if (StringUtil::Equals(value, "CREATE_SCHEMA")) { + return WALType::CREATE_SCHEMA; + } + if (StringUtil::Equals(value, "DROP_SCHEMA")) { + return WALType::DROP_SCHEMA; + } + if (StringUtil::Equals(value, "CREATE_VIEW")) { + return WALType::CREATE_VIEW; + } + if (StringUtil::Equals(value, "DROP_VIEW")) { + return WALType::DROP_VIEW; + } + if (StringUtil::Equals(value, "CREATE_SEQUENCE")) { + return WALType::CREATE_SEQUENCE; + } + if (StringUtil::Equals(value, "DROP_SEQUENCE")) { + return WALType::DROP_SEQUENCE; + } + if (StringUtil::Equals(value, "SEQUENCE_VALUE")) { + return WALType::SEQUENCE_VALUE; + } + if (StringUtil::Equals(value, "CREATE_MACRO")) { + return WALType::CREATE_MACRO; + } + if (StringUtil::Equals(value, "DROP_MACRO")) { + return WALType::DROP_MACRO; + } + if (StringUtil::Equals(value, "CREATE_TYPE")) { + return WALType::CREATE_TYPE; + } + if (StringUtil::Equals(value, "DROP_TYPE")) { + return WALType::DROP_TYPE; + } + if (StringUtil::Equals(value, "ALTER_INFO")) { + return WALType::ALTER_INFO; + } + if (StringUtil::Equals(value, "CREATE_TABLE_MACRO")) { + return WALType::CREATE_TABLE_MACRO; + } + if (StringUtil::Equals(value, "DROP_TABLE_MACRO")) { + return WALType::DROP_TABLE_MACRO; + } + if (StringUtil::Equals(value, "CREATE_INDEX")) { + return WALType::CREATE_INDEX; + } + if (StringUtil::Equals(value, "DROP_INDEX")) { + return WALType::DROP_INDEX; + } + if (StringUtil::Equals(value, "USE_TABLE")) { + return WALType::USE_TABLE; + } + if (StringUtil::Equals(value, "INSERT_TUPLE")) { + return WALType::INSERT_TUPLE; + } + if (StringUtil::Equals(value, "DELETE_TUPLE")) { + return WALType::DELETE_TUPLE; + } + if (StringUtil::Equals(value, "UPDATE_TUPLE")) { + return WALType::UPDATE_TUPLE; + } + if (StringUtil::Equals(value, "ROW_GROUP_DATA")) { + return WALType::ROW_GROUP_DATA; + } + if (StringUtil::Equals(value, "WAL_VERSION")) { + return WALType::WAL_VERSION; + } + if (StringUtil::Equals(value, "CHECKPOINT")) { + return WALType::CHECKPOINT; + } + if (StringUtil::Equals(value, "WAL_FLUSH")) { + return WALType::WAL_FLUSH; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(WindowAggregationMode value) { - return StringUtil::EnumToString(GetWindowAggregationModeValues(), 3, "WindowAggregationMode", static_cast(value)); + switch(value) { + case WindowAggregationMode::WINDOW: + return "WINDOW"; + case WindowAggregationMode::COMBINE: + return "COMBINE"; + case WindowAggregationMode::SEPARATE: + return "SEPARATE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> WindowAggregationMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetWindowAggregationModeValues(), 3, "WindowAggregationMode", value)); -} - -const StringUtil::EnumStringLiteral *GetWindowBoundaryValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(WindowBoundary::INVALID), "INVALID" }, - { static_cast(WindowBoundary::UNBOUNDED_PRECEDING), "UNBOUNDED_PRECEDING" }, - { static_cast(WindowBoundary::UNBOUNDED_FOLLOWING), "UNBOUNDED_FOLLOWING" }, - { static_cast(WindowBoundary::CURRENT_ROW_RANGE), "CURRENT_ROW_RANGE" }, - { static_cast(WindowBoundary::CURRENT_ROW_ROWS), "CURRENT_ROW_ROWS" }, - { static_cast(WindowBoundary::EXPR_PRECEDING_ROWS), "EXPR_PRECEDING_ROWS" }, - { static_cast(WindowBoundary::EXPR_FOLLOWING_ROWS), "EXPR_FOLLOWING_ROWS" }, - { static_cast(WindowBoundary::EXPR_PRECEDING_RANGE), "EXPR_PRECEDING_RANGE" }, - { static_cast(WindowBoundary::EXPR_FOLLOWING_RANGE), "EXPR_FOLLOWING_RANGE" } - }; - return values; + if (StringUtil::Equals(value, "WINDOW")) { + return WindowAggregationMode::WINDOW; + } + if (StringUtil::Equals(value, "COMBINE")) { + return WindowAggregationMode::COMBINE; + } + if (StringUtil::Equals(value, "SEPARATE")) { + return WindowAggregationMode::SEPARATE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(WindowBoundary value) { - return StringUtil::EnumToString(GetWindowBoundaryValues(), 9, "WindowBoundary", static_cast(value)); + switch(value) { + case WindowBoundary::INVALID: + return "INVALID"; + case WindowBoundary::UNBOUNDED_PRECEDING: + return "UNBOUNDED_PRECEDING"; + case WindowBoundary::UNBOUNDED_FOLLOWING: + return "UNBOUNDED_FOLLOWING"; + case WindowBoundary::CURRENT_ROW_RANGE: + return "CURRENT_ROW_RANGE"; + case WindowBoundary::CURRENT_ROW_ROWS: + return "CURRENT_ROW_ROWS"; + case WindowBoundary::EXPR_PRECEDING_ROWS: + return "EXPR_PRECEDING_ROWS"; + case WindowBoundary::EXPR_FOLLOWING_ROWS: + return "EXPR_FOLLOWING_ROWS"; + case WindowBoundary::EXPR_PRECEDING_RANGE: + return "EXPR_PRECEDING_RANGE"; + case WindowBoundary::EXPR_FOLLOWING_RANGE: + return "EXPR_FOLLOWING_RANGE"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> WindowBoundary EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetWindowBoundaryValues(), 9, "WindowBoundary", value)); -} - -const StringUtil::EnumStringLiteral *GetWindowExcludeModeValues() { - static constexpr StringUtil::EnumStringLiteral values[] { - { static_cast(WindowExcludeMode::NO_OTHER), "NO_OTHER" }, - { static_cast(WindowExcludeMode::CURRENT_ROW), "CURRENT_ROW" }, - { static_cast(WindowExcludeMode::GROUP), "GROUP" }, - { static_cast(WindowExcludeMode::TIES), "TIES" } - }; - return values; + if (StringUtil::Equals(value, "INVALID")) { + return WindowBoundary::INVALID; + } + if (StringUtil::Equals(value, "UNBOUNDED_PRECEDING")) { + return WindowBoundary::UNBOUNDED_PRECEDING; + } + if (StringUtil::Equals(value, "UNBOUNDED_FOLLOWING")) { + return WindowBoundary::UNBOUNDED_FOLLOWING; + } + if (StringUtil::Equals(value, "CURRENT_ROW_RANGE")) { + return WindowBoundary::CURRENT_ROW_RANGE; + } + if (StringUtil::Equals(value, "CURRENT_ROW_ROWS")) { + return WindowBoundary::CURRENT_ROW_ROWS; + } + if (StringUtil::Equals(value, "EXPR_PRECEDING_ROWS")) { + return WindowBoundary::EXPR_PRECEDING_ROWS; + } + if (StringUtil::Equals(value, "EXPR_FOLLOWING_ROWS")) { + return WindowBoundary::EXPR_FOLLOWING_ROWS; + } + if (StringUtil::Equals(value, "EXPR_PRECEDING_RANGE")) { + return WindowBoundary::EXPR_PRECEDING_RANGE; + } + if (StringUtil::Equals(value, "EXPR_FOLLOWING_RANGE")) { + return WindowBoundary::EXPR_FOLLOWING_RANGE; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } template<> const char* EnumUtil::ToChars(WindowExcludeMode value) { - return StringUtil::EnumToString(GetWindowExcludeModeValues(), 4, "WindowExcludeMode", static_cast(value)); + switch(value) { + case WindowExcludeMode::NO_OTHER: + return "NO_OTHER"; + case WindowExcludeMode::CURRENT_ROW: + return "CURRENT_ROW"; + case WindowExcludeMode::GROUP: + return "GROUP"; + case WindowExcludeMode::TIES: + return "TIES"; + default: + throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented in ToChars", value)); + } } template<> WindowExcludeMode EnumUtil::FromString(const char *value) { - return static_cast(StringUtil::StringToEnum(GetWindowExcludeModeValues(), 4, "WindowExcludeMode", value)); + if (StringUtil::Equals(value, "NO_OTHER")) { + return WindowExcludeMode::NO_OTHER; + } + if (StringUtil::Equals(value, "CURRENT_ROW")) { + return WindowExcludeMode::CURRENT_ROW; + } + if (StringUtil::Equals(value, "GROUP")) { + return WindowExcludeMode::GROUP; + } + if (StringUtil::Equals(value, "TIES")) { + return WindowExcludeMode::TIES; + } + throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented in FromString", value)); } } diff --git a/src/duckdb/src/common/enums/compression_type.cpp b/src/duckdb/src/common/enums/compression_type.cpp index 3bc66fe08..3b9930cfa 100644 --- a/src/duckdb/src/common/enums/compression_type.cpp +++ b/src/duckdb/src/common/enums/compression_type.cpp @@ -24,8 +24,6 @@ bool CompressionTypeIsDeprecated(CompressionType compression_type) { CompressionType CompressionTypeFromString(const string &str) { auto compression = StringUtil::Lower(str); - //! NOTE: this explicitly does not include 'constant' and 'empty validity', these are internal compression functions - //! not general purpose if (compression == "uncompressed") { return CompressionType::COMPRESSION_UNCOMPRESSED; } else if (compression == "rle") { @@ -42,14 +40,10 @@ CompressionType CompressionTypeFromString(const string &str) { return CompressionType::COMPRESSION_CHIMP; } else if (compression == "patas") { return CompressionType::COMPRESSION_PATAS; - } else if (compression == "zstd") { - return CompressionType::COMPRESSION_ZSTD; } else if (compression == "alp") { return CompressionType::COMPRESSION_ALP; } else if (compression == "alprd") { return CompressionType::COMPRESSION_ALPRD; - } else if (compression == "roaring") { - return CompressionType::COMPRESSION_ROARING; } else { return CompressionType::COMPRESSION_AUTO; } @@ -77,16 +71,10 @@ string CompressionTypeToString(CompressionType type) { return "Chimp"; case CompressionType::COMPRESSION_PATAS: return "Patas"; - case CompressionType::COMPRESSION_ZSTD: - return "ZSTD"; case CompressionType::COMPRESSION_ALP: return "ALP"; case CompressionType::COMPRESSION_ALPRD: return "ALPRD"; - case CompressionType::COMPRESSION_ROARING: - return "Roaring"; - case CompressionType::COMPRESSION_EMPTY: - return "Empty Validity"; default: throw InternalException("Unrecognized compression type!"); } diff --git a/src/duckdb/src/common/enums/metric_type.cpp b/src/duckdb/src/common/enums/metric_type.cpp index 94a75cc1e..a317f2d6a 100644 --- a/src/duckdb/src/common/enums/metric_type.cpp +++ b/src/duckdb/src/common/enums/metric_type.cpp @@ -16,7 +16,6 @@ profiler_settings_t MetricsUtils::GetOptimizerMetrics() { MetricsType::OPTIMIZER_EXPRESSION_REWRITER, MetricsType::OPTIMIZER_FILTER_PULLUP, MetricsType::OPTIMIZER_FILTER_PUSHDOWN, - MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP, MetricsType::OPTIMIZER_CTE_FILTER_PUSHER, MetricsType::OPTIMIZER_REGEX_RANGE, MetricsType::OPTIMIZER_IN_CLAUSE, @@ -34,11 +33,9 @@ profiler_settings_t MetricsUtils::GetOptimizerMetrics() { MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION, MetricsType::OPTIMIZER_DUPLICATE_GROUPS, MetricsType::OPTIMIZER_REORDER_FILTER, - MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN, MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN, MetricsType::OPTIMIZER_EXTENSION, MetricsType::OPTIMIZER_MATERIALIZED_CTE, - MetricsType::OPTIMIZER_SUM_REWRITER, }; } @@ -63,8 +60,6 @@ MetricsType MetricsUtils::GetOptimizerMetricByType(OptimizerType type) { return MetricsType::OPTIMIZER_FILTER_PULLUP; case OptimizerType::FILTER_PUSHDOWN: return MetricsType::OPTIMIZER_FILTER_PUSHDOWN; - case OptimizerType::EMPTY_RESULT_PULLUP: - return MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP; case OptimizerType::CTE_FILTER_PUSHER: return MetricsType::OPTIMIZER_CTE_FILTER_PUSHER; case OptimizerType::REGEX_RANGE: @@ -99,16 +94,12 @@ MetricsType MetricsUtils::GetOptimizerMetricByType(OptimizerType type) { return MetricsType::OPTIMIZER_DUPLICATE_GROUPS; case OptimizerType::REORDER_FILTER: return MetricsType::OPTIMIZER_REORDER_FILTER; - case OptimizerType::SAMPLING_PUSHDOWN: - return MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN; case OptimizerType::JOIN_FILTER_PUSHDOWN: return MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN; case OptimizerType::EXTENSION: return MetricsType::OPTIMIZER_EXTENSION; case OptimizerType::MATERIALIZED_CTE: return MetricsType::OPTIMIZER_MATERIALIZED_CTE; - case OptimizerType::SUM_REWRITER: - return MetricsType::OPTIMIZER_SUM_REWRITER; default: throw InternalException("OptimizerType %s cannot be converted to a MetricsType", EnumUtil::ToString(type)); }; @@ -122,8 +113,6 @@ OptimizerType MetricsUtils::GetOptimizerTypeByMetric(MetricsType type) { return OptimizerType::FILTER_PULLUP; case MetricsType::OPTIMIZER_FILTER_PUSHDOWN: return OptimizerType::FILTER_PUSHDOWN; - case MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP: - return OptimizerType::EMPTY_RESULT_PULLUP; case MetricsType::OPTIMIZER_CTE_FILTER_PUSHER: return OptimizerType::CTE_FILTER_PUSHER; case MetricsType::OPTIMIZER_REGEX_RANGE: @@ -158,16 +147,12 @@ OptimizerType MetricsUtils::GetOptimizerTypeByMetric(MetricsType type) { return OptimizerType::DUPLICATE_GROUPS; case MetricsType::OPTIMIZER_REORDER_FILTER: return OptimizerType::REORDER_FILTER; - case MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN: - return OptimizerType::SAMPLING_PUSHDOWN; case MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN: return OptimizerType::JOIN_FILTER_PUSHDOWN; case MetricsType::OPTIMIZER_EXTENSION: return OptimizerType::EXTENSION; case MetricsType::OPTIMIZER_MATERIALIZED_CTE: return OptimizerType::MATERIALIZED_CTE; - case MetricsType::OPTIMIZER_SUM_REWRITER: - return OptimizerType::SUM_REWRITER; default: return OptimizerType::INVALID; }; @@ -178,7 +163,6 @@ bool MetricsUtils::IsOptimizerMetric(MetricsType type) { case MetricsType::OPTIMIZER_EXPRESSION_REWRITER: case MetricsType::OPTIMIZER_FILTER_PULLUP: case MetricsType::OPTIMIZER_FILTER_PUSHDOWN: - case MetricsType::OPTIMIZER_EMPTY_RESULT_PULLUP: case MetricsType::OPTIMIZER_CTE_FILTER_PUSHER: case MetricsType::OPTIMIZER_REGEX_RANGE: case MetricsType::OPTIMIZER_IN_CLAUSE: @@ -196,11 +180,9 @@ bool MetricsUtils::IsOptimizerMetric(MetricsType type) { case MetricsType::OPTIMIZER_COMPRESSED_MATERIALIZATION: case MetricsType::OPTIMIZER_DUPLICATE_GROUPS: case MetricsType::OPTIMIZER_REORDER_FILTER: - case MetricsType::OPTIMIZER_SAMPLING_PUSHDOWN: case MetricsType::OPTIMIZER_JOIN_FILTER_PUSHDOWN: case MetricsType::OPTIMIZER_EXTENSION: case MetricsType::OPTIMIZER_MATERIALIZED_CTE: - case MetricsType::OPTIMIZER_SUM_REWRITER: return true; default: return false; diff --git a/src/duckdb/src/common/enums/optimizer_type.cpp b/src/duckdb/src/common/enums/optimizer_type.cpp index f2555dc58..460bbb3a0 100644 --- a/src/duckdb/src/common/enums/optimizer_type.cpp +++ b/src/duckdb/src/common/enums/optimizer_type.cpp @@ -15,7 +15,6 @@ static const DefaultOptimizerType internal_optimizer_types[] = { {"expression_rewriter", OptimizerType::EXPRESSION_REWRITER}, {"filter_pullup", OptimizerType::FILTER_PULLUP}, {"filter_pushdown", OptimizerType::FILTER_PUSHDOWN}, - {"empty_result_pullup", OptimizerType::EMPTY_RESULT_PULLUP}, {"cte_filter_pusher", OptimizerType::CTE_FILTER_PUSHER}, {"regex_range", OptimizerType::REGEX_RANGE}, {"in_clause", OptimizerType::IN_CLAUSE}, @@ -33,11 +32,9 @@ static const DefaultOptimizerType internal_optimizer_types[] = { {"compressed_materialization", OptimizerType::COMPRESSED_MATERIALIZATION}, {"duplicate_groups", OptimizerType::DUPLICATE_GROUPS}, {"reorder_filter", OptimizerType::REORDER_FILTER}, - {"sampling_pushdown", OptimizerType::SAMPLING_PUSHDOWN}, {"join_filter_pushdown", OptimizerType::JOIN_FILTER_PUSHDOWN}, {"extension", OptimizerType::EXTENSION}, {"materialized_cte", OptimizerType::MATERIALIZED_CTE}, - {"sum_rewriter", OptimizerType::SUM_REWRITER}, {nullptr, OptimizerType::INVALID}}; string OptimizerTypeToString(OptimizerType type) { diff --git a/src/duckdb/src/common/enums/physical_operator_type.cpp b/src/duckdb/src/common/enums/physical_operator_type.cpp index f520cb448..a48f44070 100644 --- a/src/duckdb/src/common/enums/physical_operator_type.cpp +++ b/src/duckdb/src/common/enums/physical_operator_type.cpp @@ -41,8 +41,6 @@ string PhysicalOperatorToString(PhysicalOperatorType type) { return "HASH_GROUP_BY"; case PhysicalOperatorType::PERFECT_HASH_GROUP_BY: return "PERFECT_HASH_GROUP_BY"; - case PhysicalOperatorType::PARTITIONED_AGGREGATE: - return "PARTITIONED_AGGREGATE"; case PhysicalOperatorType::FILTER: return "FILTER"; case PhysicalOperatorType::PROJECTION: diff --git a/src/duckdb/src/common/error_data.cpp b/src/duckdb/src/common/error_data.cpp index 9cca3264c..d0a427cca 100644 --- a/src/duckdb/src/common/error_data.cpp +++ b/src/duckdb/src/common/error_data.cpp @@ -4,7 +4,6 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/common/to_string.hpp" #include "duckdb/common/types.hpp" -#include "duckdb/common/stacktrace.hpp" #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/parser/query_error_context.hpp" #include "duckdb/parser/tableref.hpp" @@ -99,32 +98,16 @@ void ErrorData::ConvertErrorToJSON() { // empty or already JSON return; } - raw_message = StringUtil::ExceptionToJSONMap(type, raw_message, extra_info); + raw_message = StringUtil::ToJSONMap(type, raw_message, extra_info); final_message = raw_message; } -void ErrorData::FinalizeError() { - auto entry = extra_info.find("stack_trace_pointers"); - if (entry != extra_info.end()) { - auto stack_trace = StackTrace::ResolveStacktraceSymbols(entry->second); - extra_info["stack_trace"] = std::move(stack_trace); - extra_info.erase("stack_trace_pointers"); - } -} - void ErrorData::AddErrorLocation(const string &query) { - if (!query.empty()) { - auto entry = extra_info.find("position"); - if (entry != extra_info.end()) { - raw_message = QueryErrorContext::Format(query, raw_message, std::stoull(entry->second)); - } - } - { - auto entry = extra_info.find("stack_trace"); - if (entry != extra_info.end()) { - raw_message += "\n\nStack Trace:\n" + entry->second; - } + auto entry = extra_info.find("position"); + if (entry == extra_info.end()) { + return; } + raw_message = QueryErrorContext::Format(query, raw_message, std::stoull(entry->second)); final_message = ConstructFinalMessage(); } @@ -137,7 +120,7 @@ void ErrorData::AddQueryLocation(QueryErrorContext error_context) { } void ErrorData::AddQueryLocation(const ParsedExpression &ref) { - AddQueryLocation(ref.GetQueryLocation()); + AddQueryLocation(ref.query_location); } void ErrorData::AddQueryLocation(const TableRef &ref) { diff --git a/src/duckdb/src/common/exception.cpp b/src/duckdb/src/common/exception.cpp index 991f929f2..4527f3ff5 100644 --- a/src/duckdb/src/common/exception.cpp +++ b/src/duckdb/src/common/exception.cpp @@ -11,7 +11,9 @@ #include #include #endif -#include "duckdb/common/stacktrace.hpp" +#ifdef DUCKDB_DEBUG_STACKTRACE +#include +#endif namespace duckdb { @@ -30,16 +32,13 @@ string Exception::ToJSON(ExceptionType type, const string &message) { } string Exception::ToJSON(ExceptionType type, const string &message, const unordered_map &extra_info) { -#ifndef DUCKDB_DEBUG_STACKTRACE - // by default we only enable stack traces for internal exceptions - if (type == ExceptionType::INTERNAL) +#ifdef DUCKDB_DEBUG_STACKTRACE + auto extended_extra_info = extra_info; + extended_extra_info["stack_trace"] = Exception::GetStackTrace(); + return StringUtil::ToJSONMap(type, message, extended_extra_info); +#else + return StringUtil::ToJSONMap(type, message, extra_info); #endif - { - auto extended_extra_info = extra_info; - extended_extra_info["stack_trace_pointers"] = StackTrace::GetStacktracePointers(); - return StringUtil::ExceptionToJSONMap(type, message, extended_extra_info); - } - return StringUtil::ExceptionToJSONMap(type, message, extra_info); } bool Exception::UncaughtException() { @@ -66,6 +65,7 @@ bool Exception::InvalidatesTransaction(ExceptionType exception_type) { bool Exception::InvalidatesDatabase(ExceptionType exception_type) { switch (exception_type) { + case ExceptionType::INTERNAL: case ExceptionType::FATAL: return true; default: @@ -73,8 +73,22 @@ bool Exception::InvalidatesDatabase(ExceptionType exception_type) { } } -string Exception::GetStackTrace(idx_t max_depth) { - return StackTrace::GetStackTrace(max_depth); +string Exception::GetStackTrace(int max_depth) { +#ifdef DUCKDB_DEBUG_STACKTRACE + string result; + auto callstack = unique_ptr(new void *[max_depth]); + int frames = backtrace(callstack.get(), max_depth); + char **strs = backtrace_symbols(callstack.get(), frames); + for (int i = 0; i < frames; i++) { + result += strs[i]; + result += "\n"; + } + free(strs); + return "\n" + result; +#else + // Stack trace not available. Toggle DUCKDB_DEBUG_STACKTRACE in exception.cpp to enable stack traces. + return ""; +#endif } string Exception::ConstructMessageRecursive(const string &msg, std::vector &values) { @@ -168,11 +182,11 @@ ExceptionType Exception::StringToExceptionType(const string &type) { } unordered_map Exception::InitializeExtraInfo(const Expression &expr) { - return InitializeExtraInfo(expr.GetQueryLocation()); + return InitializeExtraInfo(expr.query_location); } unordered_map Exception::InitializeExtraInfo(const ParsedExpression &expr) { - return InitializeExtraInfo(expr.GetQueryLocation()); + return InitializeExtraInfo(expr.query_location); } unordered_map Exception::InitializeExtraInfo(const QueryErrorContext &error_context) { @@ -319,7 +333,6 @@ FatalException::FatalException(ExceptionType type, const string &msg) : Exceptio InternalException::InternalException(const string &msg) : Exception(ExceptionType::INTERNAL, msg) { #ifdef DUCKDB_CRASH_ON_ASSERT Printer::Print("ABORT THROWN BY INTERNAL EXCEPTION: " + msg); - Printer::Print(StackTrace::GetStackTrace()); abort(); #endif } diff --git a/src/duckdb/src/common/exception/binder_exception.cpp b/src/duckdb/src/common/exception/binder_exception.cpp index cc4e08722..55db8386a 100644 --- a/src/duckdb/src/common/exception/binder_exception.cpp +++ b/src/duckdb/src/common/exception/binder_exception.cpp @@ -45,7 +45,7 @@ BinderException BinderException::NoMatchingFunction(const string &name, const ve } BinderException BinderException::Unsupported(ParsedExpression &expr, const string &message) { - auto extra_info = Exception::InitializeExtraInfo("UNSUPPORTED", expr.GetQueryLocation()); + auto extra_info = Exception::InitializeExtraInfo("UNSUPPORTED", expr.query_location); return BinderException(message, extra_info); } diff --git a/src/duckdb/src/common/extra_type_info.cpp b/src/duckdb/src/common/extra_type_info.cpp index 117f9b0f7..54f03447c 100644 --- a/src/duckdb/src/common/extra_type_info.cpp +++ b/src/duckdb/src/common/extra_type_info.cpp @@ -9,71 +9,6 @@ namespace duckdb { -//===--------------------------------------------------------------------===// -// Extension Type Info -//===--------------------------------------------------------------------===// - -bool ExtensionTypeInfo::Equals(optional_ptr lhs, optional_ptr rhs) { - // Either both are null, or both are the same, so they are equal - if (lhs.get() == rhs.get()) { - return true; - } - // If one is null, then we cant compare them - if (lhs == nullptr || rhs == nullptr) { - return true; - } - - // Both are not null, so we can compare them - D_ASSERT(lhs != nullptr && rhs != nullptr); - - // Compare modifiers - const auto &lhs_mods = lhs->modifiers; - const auto &rhs_mods = rhs->modifiers; - const auto common_mods = MinValue(lhs_mods.size(), rhs_mods.size()); - for (idx_t i = 0; i < common_mods; i++) { - // If the types are not strictly equal, they are not equal - auto &lhs_val = lhs_mods[i].value; - auto &rhs_val = rhs_mods[i].value; - - if (lhs_val.type() != rhs_val.type()) { - return false; - } - - // If both are null, its fine - if (lhs_val.IsNull() && rhs_val.IsNull()) { - continue; - } - - // If one is null, the other must be null too - if (lhs_val.IsNull() != rhs_val.IsNull()) { - return false; - } - - if (lhs_val != rhs_val) { - return false; - } - } - - // Properties are optional, so only compare those present in both - const auto &lhs_props = lhs->properties; - const auto &rhs_props = rhs->properties; - - for (const auto &kv : lhs_props) { - auto it = rhs_props.find(kv.first); - if (it == rhs_props.end()) { - // Continue - continue; - } - if (kv.second != it->second) { - // Mismatch! - return false; - } - } - - // All ok! - return true; -} - //===--------------------------------------------------------------------===// // Extra Type Info //===--------------------------------------------------------------------===// @@ -83,24 +18,27 @@ ExtraTypeInfo::ExtraTypeInfo(ExtraTypeInfoType type, string alias) : type(type), } ExtraTypeInfo::~ExtraTypeInfo() { } - -ExtraTypeInfo::ExtraTypeInfo(const ExtraTypeInfo &other) : type(other.type), alias(other.alias) { - if (other.extension_info) { - extension_info = make_uniq(*other.extension_info); - } +shared_ptr ExtraTypeInfo::Copy() const { + return make_shared_ptr(*this); } -ExtraTypeInfo &ExtraTypeInfo::operator=(const ExtraTypeInfo &other) { - type = other.type; - alias = other.alias; - if (other.extension_info) { - extension_info = make_uniq(*other.extension_info); +static bool CompareModifiers(const vector &left, const vector &right) { + // Check if the common prefix of the properties is the same for both types + auto common_props = MinValue(left.size(), right.size()); + for (idx_t i = 0; i < common_props; i++) { + if (left[i].type() != right[i].type()) { + return false; + } + // Special case for nulls: + // For type modifiers, NULL is equivalent to ANY + if (left[i].IsNull() || right[i].IsNull()) { + continue; + } + if (left[i] != right[i]) { + return false; + } } - return *this; -} - -shared_ptr ExtraTypeInfo::Copy() const { - return shared_ptr(new ExtraTypeInfo(*this)); + return true; } bool ExtraTypeInfo::Equals(ExtraTypeInfo *other_p) const { @@ -110,16 +48,13 @@ bool ExtraTypeInfo::Equals(ExtraTypeInfo *other_p) const { if (!alias.empty()) { return false; } - if (extension_info) { - return false; - } //! We only need to compare aliases when both types have them in this case return true; } if (alias != other_p->alias) { return false; } - if (!ExtensionTypeInfo::Equals(extension_info, other_p->extension_info)) { + if (!CompareModifiers(modifiers, other_p->modifiers)) { return false; } return true; @@ -133,7 +68,7 @@ bool ExtraTypeInfo::Equals(ExtraTypeInfo *other_p) const { if (alias != other_p->alias) { return false; } - if (!ExtensionTypeInfo::Equals(extension_info, other_p->extension_info)) { + if (!CompareModifiers(modifiers, other_p->modifiers)) { return false; } return EqualsInternal(other_p); diff --git a/src/duckdb/src/common/file_buffer.cpp b/src/duckdb/src/common/file_buffer.cpp index b1b1febb3..7cde4c6f8 100644 --- a/src/duckdb/src/common/file_buffer.cpp +++ b/src/duckdb/src/common/file_buffer.cpp @@ -42,22 +42,19 @@ FileBuffer::~FileBuffer() { allocator.FreeData(internal_buffer, internal_size); } -void FileBuffer::ReallocBuffer(idx_t new_size) { +void FileBuffer::ReallocBuffer(size_t new_size) { data_ptr_t new_buffer; if (internal_buffer) { new_buffer = allocator.ReallocateData(internal_buffer, internal_size, new_size); } else { new_buffer = allocator.AllocateData(new_size); } - - // FIXME: should we throw one of our exceptions here? if (!new_buffer) { throw std::bad_alloc(); } internal_buffer = new_buffer; internal_size = new_size; - - // The caller must update these. + // Caller must update these. buffer = nullptr; size = 0; } diff --git a/src/duckdb/src/common/file_system.cpp b/src/duckdb/src/common/file_system.cpp index fbcf0cede..6e68402bc 100644 --- a/src/duckdb/src/common/file_system.cpp +++ b/src/duckdb/src/common/file_system.cpp @@ -115,7 +115,7 @@ string FileSystem::GetEnvVariable(const string &name) { bool FileSystem::IsPathAbsolute(const string &path) { auto path_separator = PathSeparator(path); - return PathMatched(path, path_separator) || StringUtil::StartsWith(path, "file:/"); + return PathMatched(path, path_separator); } string FileSystem::PathSeparator(const string &path) { @@ -237,11 +237,7 @@ string FileSystem::NormalizeAbsolutePath(const string &path) { } string FileSystem::PathSeparator(const string &path) { - if (StringUtil::StartsWith(path, "file:")) { - return "/"; - } else { - return "\\"; - } + return "\\"; } void FileSystem::SetWorkingDirectory(const string &path) { @@ -555,8 +551,7 @@ bool FileSystem::OnDiskFile(FileHandle &handle) { } // LCOV_EXCL_STOP -FileHandle::FileHandle(FileSystem &file_system, string path_p, FileOpenFlags flags) - : file_system(file_system), path(std::move(path_p)), flags(flags) { +FileHandle::FileHandle(FileSystem &file_system, string path_p) : file_system(file_system), path(std::move(path_p)) { } FileHandle::~FileHandle() { diff --git a/src/duckdb/src/common/fsst.cpp b/src/duckdb/src/common/fsst.cpp index 1e28ad5ab..74b747dea 100644 --- a/src/duckdb/src/common/fsst.cpp +++ b/src/duckdb/src/common/fsst.cpp @@ -20,8 +20,8 @@ string_t FSSTPrimitives::DecompressValue(void *duckdb_fsst_decoder, Vector &resu decompressed_string_size); } -string FSSTPrimitives::DecompressValue(void *duckdb_fsst_decoder, const char *compressed_string, - const idx_t compressed_string_len, vector &decompress_buffer) { +Value FSSTPrimitives::DecompressValue(void *duckdb_fsst_decoder, const char *compressed_string, + const idx_t compressed_string_len, vector &decompress_buffer) { auto compressed_string_ptr = (unsigned char *)compressed_string; // NOLINT auto fsst_decoder = reinterpret_cast(duckdb_fsst_decoder); @@ -30,7 +30,7 @@ string FSSTPrimitives::DecompressValue(void *duckdb_fsst_decoder, const char *co D_ASSERT(!decompress_buffer.empty()); D_ASSERT(decompressed_string_size <= decompress_buffer.size() - 1); - return string(char_ptr_cast(decompress_buffer.data()), decompressed_string_size); + return Value(string(char_ptr_cast(decompress_buffer.data()), decompressed_string_size)); } } // namespace duckdb diff --git a/src/duckdb/src/common/hive_partitioning.cpp b/src/duckdb/src/common/hive_partitioning.cpp index c84d0505d..8ae9b6850 100644 --- a/src/duckdb/src/common/hive_partitioning.cpp +++ b/src/duckdb/src/common/hive_partitioning.cpp @@ -51,7 +51,7 @@ GetKnownColumnValues(const string &filename, const HivePartitioningFilterInfo &f static void ConvertKnownColRefToConstants(ClientContext &context, unique_ptr &expr, const unordered_map &known_column_values, idx_t table_index) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_colref = expr->Cast(); // This bound column ref is for another table diff --git a/src/duckdb/src/common/local_file_system.cpp b/src/duckdb/src/common/local_file_system.cpp index 83e242526..70246d26a 100644 --- a/src/duckdb/src/common/local_file_system.cpp +++ b/src/duckdb/src/common/local_file_system.cpp @@ -6,7 +6,7 @@ #include "duckdb/common/helper.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/windows.hpp" -#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" @@ -59,13 +59,13 @@ extern "C" WINBASEAPI BOOL QueryFullProcessImageNameW(HANDLE, DWORD, LPWSTR, PDW #endif namespace duckdb { + #ifndef _WIN32 bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { if (!filename.empty()) { - auto normalized_file = NormalizeLocalPath(filename); - if (access(normalized_file, 0) == 0) { + if (access(filename.c_str(), 0) == 0) { struct stat status; - stat(normalized_file, &status); + stat(filename.c_str(), &status); if (S_ISREG(status.st_mode)) { return true; } @@ -77,10 +77,9 @@ bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { if (!filename.empty()) { - auto normalized_file = NormalizeLocalPath(filename); - if (access(normalized_file, 0) == 0) { + if (access(filename.c_str(), 0) == 0) { struct stat status; - stat(normalized_file, &status); + stat(filename.c_str(), &status); if (S_ISFIFO(status.st_mode)) { return true; } @@ -91,21 +90,8 @@ bool LocalFileSystem::IsPipe(const string &filename, optional_ptr op } #else -static std::wstring NormalizePathAndConvertToUnicode(const string &path) { - string normalized_path_copy; - const char *normalized_path; - if (StringUtil::StartsWith(path, "file:/")) { - normalized_path_copy = LocalFileSystem::NormalizeLocalPath(path); - normalized_path_copy = LocalFileSystem().ConvertSeparators(normalized_path_copy); - normalized_path = normalized_path_copy.c_str(); - } else { - normalized_path = path.c_str(); - } - return WindowsUtil::UTF8ToUnicode(normalized_path); -} - bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = WindowsUtil::UTF8ToUnicode(filename.c_str()); const wchar_t *wpath = unicode_path.c_str(); if (_waccess(wpath, 0) == 0) { struct _stati64 status; @@ -117,7 +103,7 @@ bool LocalFileSystem::FileExists(const string &filename, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = WindowsUtil::UTF8ToUnicode(filename.c_str()); const wchar_t *wpath = unicode_path.c_str(); if (_waccess(wpath, 0) == 0) { struct _stati64 status; @@ -143,8 +129,7 @@ bool LocalFileSystem::IsPipe(const string &filename, optional_ptr op struct UnixFileHandle : public FileHandle { public: - UnixFileHandle(FileSystem &file_system, string path, int fd, FileOpenFlags flags) - : FileHandle(file_system, std::move(path), flags), fd(fd) { + UnixFileHandle(FileSystem &file_system, string path, int fd) : FileHandle(file_system, std::move(path)), fd(fd) { } ~UnixFileHandle() override { UnixFileHandle::Close(); @@ -194,7 +179,7 @@ static string AdditionalProcessInfo(FileSystem &fs, pid_t pid) { } string process_name, process_owner; - // macOS >= 10.7 has PROC_PIDT_SHORTBSDINFO +// macOS >= 10.7 has PROC_PIDT_SHORTBSDINFO #ifdef PROC_PIDT_SHORTBSDINFO // try to find out more about the process holding the lock struct proc_bsdshortinfo proc; @@ -275,11 +260,10 @@ static string AdditionalProcessInfo(FileSystem &fs, pid_t pid) { bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { auto path = FileSystem::ExpandPath(path_p, opener); - auto normalized_path = NormalizeLocalPath(path); struct stat st; - if (lstat(normalized_path, &st) != 0) { + if (lstat(path.c_str(), &st) != 0) { throw IOException( "Failed to stat '%s' when checking file permissions, file may be missing or have incorrect permissions", path.c_str()); @@ -296,7 +280,6 @@ bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenFlags flags, optional_ptr opener) { auto path = FileSystem::ExpandPath(path_p, opener); - auto normalized_path = NormalizeLocalPath(path); if (flags.Compression() != FileCompressionType::UNCOMPRESSED) { throw NotImplementedException("Unsupported compression type for default file system"); } @@ -335,8 +318,9 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF #endif #if defined(__DARWIN__) || defined(__APPLE__) || defined(__OpenBSD__) // OSX does not have O_DIRECT, instead we need to use fcntl afterwards to support direct IO + open_flags |= O_SYNC; #else - open_flags |= O_DIRECT; + open_flags |= O_DIRECT | O_SYNC; #endif } @@ -354,7 +338,7 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF } // Open the file - int fd = open(normalized_path, open_flags, filesec); + int fd = open(path.c_str(), open_flags, filesec); if (fd == -1) { if (flags.ReturnNullIfNotExists() && errno == ENOENT) { @@ -365,17 +349,15 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF } throw IOException("Cannot open file \"%s\": %s", {{"errno", std::to_string(errno)}}, path, strerror(errno)); } - -#if defined(__DARWIN__) || defined(__APPLE__) - if (flags.DirectIO()) { - // OSX requires fcntl for Direct IO - rc = fcntl(fd, F_NOCACHE, 1); - if (rc == -1) { - throw IOException("Could not enable direct IO for file \"%s\": %s", path, strerror(errno)); - } - } -#endif - + // #if defined(__DARWIN__) || defined(__APPLE__) + // if (flags & FileFlags::FILE_FLAGS_DIRECT_IO) { + // // OSX requires fcntl for Direct IO + // rc = fcntl(fd, F_NOCACHE, 1); + // if (fd == -1) { + // throw IOException("Could not enable direct IO for file \"%s\": %s", path, strerror(errno)); + // } + // } + // #endif if (flags.Lock() != FileLockType::NO_LOCK) { // set lock on file // but only if it is not an input/output stream @@ -435,7 +417,7 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF } } } - return make_uniq(*this, path, fd, flags); + return make_uniq(*this, path, fd); } void LocalFileSystem::SetFilePointer(FileHandle &handle, idx_t location) { @@ -545,8 +527,7 @@ int64_t LocalFileSystem::GetFileSize(FileHandle &handle) { int fd = handle.Cast().fd; struct stat s; if (fstat(fd, &s) == -1) { - throw IOException("Failed to get file size for file \"%s\": %s", {{"errno", std::to_string(errno)}}, - handle.path, strerror(errno)); + return -1; } return s.st_size; } @@ -555,8 +536,7 @@ time_t LocalFileSystem::GetLastModifiedTime(FileHandle &handle) { int fd = handle.Cast().fd; struct stat s; if (fstat(fd, &s) == -1) { - throw IOException("Failed to get last modified time for file \"%s\": %s", {{"errno", std::to_string(errno)}}, - handle.path, strerror(errno)); + return -1; } return s.st_mtime; } @@ -576,10 +556,9 @@ void LocalFileSystem::Truncate(FileHandle &handle, int64_t new_size) { bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { if (!directory.empty()) { - auto normalized_dir = NormalizeLocalPath(directory); - if (access(normalized_dir, 0) == 0) { + if (access(directory.c_str(), 0) == 0) { struct stat status; - stat(normalized_dir, &status); + stat(directory.c_str(), &status); if (status.st_mode & S_IFDIR) { return true; } @@ -592,10 +571,9 @@ bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { struct stat st; - auto normalized_dir = NormalizeLocalPath(directory); - if (stat(normalized_dir, &st) != 0) { + if (stat(directory.c_str(), &st) != 0) { /* Directory does not exist. EEXIST for race condition */ - if (mkdir(normalized_dir, 0755) != 0 && errno != EEXIST) { + if (mkdir(directory.c_str(), 0755) != 0 && errno != EEXIST) { throw IOException("Failed to create directory \"%s\": %s", {{"errno", std::to_string(errno)}}, directory, strerror(errno)); } @@ -646,13 +624,11 @@ int RemoveDirectoryRecursive(const char *path) { } void LocalFileSystem::RemoveDirectory(const string &directory, optional_ptr opener) { - auto normalized_dir = NormalizeLocalPath(directory); - RemoveDirectoryRecursive(normalized_dir); + RemoveDirectoryRecursive(directory.c_str()); } void LocalFileSystem::RemoveFile(const string &filename, optional_ptr opener) { - auto normalized_file = NormalizeLocalPath(filename); - if (std::remove(normalized_file) != 0) { + if (std::remove(filename.c_str()) != 0) { throw IOException("Could not remove file \"%s\": %s", {{"errno", std::to_string(errno)}}, filename, strerror(errno)); } @@ -660,8 +636,7 @@ void LocalFileSystem::RemoveFile(const string &filename, optional_ptr &callback, FileOpener *opener) { - auto normalized_dir = NormalizeLocalPath(directory); - auto dir = opendir(normalized_dir); + auto dir = opendir(directory.c_str()); if (!dir) { return false; } @@ -678,7 +653,7 @@ bool LocalFileSystem::ListFiles(const string &directory, const std::function opener) { - auto normalized_source = NormalizeLocalPath(source); - auto normalized_target = NormalizeLocalPath(target); //! FIXME: rename does not guarantee atomicity or overwriting target file if it exists - if (rename(normalized_source, normalized_target) != 0) { + if (rename(source.c_str(), target.c_str()) != 0) { throw IOException("Could not rename file!", {{"errno", std::to_string(errno)}}); } } @@ -741,8 +714,8 @@ std::string LocalFileSystem::GetLastErrorAsString() { struct WindowsFileHandle : public FileHandle { public: - WindowsFileHandle(FileSystem &file_system, string path, HANDLE fd, FileOpenFlags flags) - : FileHandle(file_system, path, flags), position(0), fd(fd) { + WindowsFileHandle(FileSystem &file_system, string path, HANDLE fd) + : FileHandle(file_system, path), position(0), fd(fd) { } ~WindowsFileHandle() override { Close(); @@ -831,7 +804,6 @@ bool LocalFileSystem::IsPrivateFile(const string &path_p, FileOpener *opener) { unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenFlags flags, optional_ptr opener) { auto path = FileSystem::ExpandPath(path_p, opener); - auto unicode_path = NormalizePathAndConvertToUnicode(path); if (flags.Compression() != FileCompressionType::UNCOMPRESSED) { throw NotImplementedException("Unsupported compression type for default file system"); } @@ -865,6 +837,7 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF if (flags.DirectIO()) { flags_and_attributes |= FILE_FLAG_NO_BUFFERING; } + auto unicode_path = WindowsUtil::UTF8ToUnicode(path.c_str()); HANDLE hFile = CreateFileW(unicode_path.c_str(), desired_access, share_mode, NULL, creation_disposition, flags_and_attributes, NULL); if (hFile == INVALID_HANDLE_VALUE) { @@ -880,7 +853,7 @@ unique_ptr LocalFileSystem::OpenFile(const string &path_p, FileOpenF throw IOException("Cannot open file \"%s\": %s", path.c_str(), error); } } - auto handle = make_uniq(*this, path.c_str(), hFile, flags); + auto handle = make_uniq(*this, path.c_str(), hFile); if (flags.OpenForAppending()) { auto file_size = GetFileSize(*handle); SetFilePointer(*handle, file_size); @@ -994,8 +967,7 @@ int64_t LocalFileSystem::GetFileSize(FileHandle &handle) { HANDLE hFile = handle.Cast().fd; LARGE_INTEGER result; if (!GetFileSizeEx(hFile, &result)) { - auto error = LocalFileSystem::GetLastErrorAsString(); - throw IOException("Failed to get file size for file \"%s\": %s", handle.path, error); + return -1; } return result.QuadPart; } @@ -1006,8 +978,7 @@ time_t LocalFileSystem::GetLastModifiedTime(FileHandle &handle) { // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletime FILETIME last_write; if (GetFileTime(hFile, nullptr, nullptr, &last_write) == 0) { - auto error = LocalFileSystem::GetLastErrorAsString(); - throw IOException("Failed to get last modified time for file \"%s\": %s", handle.path, error); + return -1; } // https://stackoverflow.com/questions/29266743/what-is-dwlowdatetime-and-dwhighdatetime @@ -1039,14 +1010,10 @@ void LocalFileSystem::Truncate(FileHandle &handle, int64_t new_size) { } static DWORD WindowsGetFileAttributes(const string &filename) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = WindowsUtil::UTF8ToUnicode(filename.c_str()); return GetFileAttributesW(unicode_path.c_str()); } -static DWORD WindowsGetFileAttributes(const std::wstring &filename) { - return GetFileAttributesW(filename.c_str()); -} - bool LocalFileSystem::DirectoryExists(const string &directory, optional_ptr opener) { DWORD attrs = WindowsGetFileAttributes(directory); return (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)); @@ -1056,7 +1023,7 @@ void LocalFileSystem::CreateDirectory(const string &directory, optional_ptr opener) { - auto unicode_path = NormalizePathAndConvertToUnicode(filename); + auto unicode_path = WindowsUtil::UTF8ToUnicode(filename.c_str()); if (!DeleteFileW(unicode_path.c_str())) { auto error = LocalFileSystem::GetLastErrorAsString(); throw IOException("Failed to delete file \"%s\": %s", filename, error); @@ -1099,7 +1066,8 @@ void LocalFileSystem::RemoveFile(const string &filename, optional_ptr &callback, FileOpener *opener) { string search_dir = JoinPath(directory, "*"); - auto unicode_path = NormalizePathAndConvertToUnicode(search_dir); + + auto unicode_path = WindowsUtil::UTF8ToUnicode(search_dir.c_str()); WIN32_FIND_DATAW ffd; HANDLE hFind = FindFirstFileW(unicode_path.c_str(), &ffd); @@ -1132,9 +1100,8 @@ void LocalFileSystem::FileSync(FileHandle &handle) { } void LocalFileSystem::MoveFile(const string &source, const string &target, optional_ptr opener) { - auto source_unicode = NormalizePathAndConvertToUnicode(source); - auto target_unicode = NormalizePathAndConvertToUnicode(target); - + auto source_unicode = WindowsUtil::UTF8ToUnicode(source.c_str()); + auto target_unicode = WindowsUtil::UTF8ToUnicode(target.c_str()); if (!MoveFileW(source_unicode.c_str(), target_unicode.c_str())) { throw IOException("Could not move file: %s", GetLastErrorAsString()); } @@ -1146,8 +1113,7 @@ FileType LocalFileSystem::GetFileType(FileHandle &handle) { if (strncmp(path.c_str(), PIPE_PREFIX, strlen(PIPE_PREFIX)) == 0) { return FileType::FILE_TYPE_FIFO; } - auto normalized_path = NormalizePathAndConvertToUnicode(path); - DWORD attrs = WindowsGetFileAttributes(normalized_path); + DWORD attrs = WindowsGetFileAttributes(path.c_str()); if (attrs != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { return FileType::FILE_TYPE_DIR; @@ -1189,10 +1155,9 @@ static bool HasMultipleCrawl(const vector &splits) { return std::count(splits.begin(), splits.end(), "**") > 1; } static bool IsSymbolicLink(const string &path) { - auto normalized_path = LocalFileSystem::NormalizeLocalPath(path); #ifndef _WIN32 struct stat status; - return (lstat(normalized_path, &status) != -1 && S_ISLNK(status.st_mode)); + return (lstat(path.c_str(), &status) != -1 && S_ISLNK(status.st_mode)); #else auto attributes = WindowsGetFileAttributes(path); if (attributes == INVALID_FILE_ATTRIBUTES) @@ -1229,7 +1194,7 @@ static void GlobFilesInternal(FileSystem &fs, const string &path, const string & if (is_directory != match_directory) { return; } - if (Glob(fname.c_str(), fname.size(), glob.c_str(), glob.size())) { + if (LikeFun::Glob(fname.c_str(), fname.size(), glob.c_str(), glob.size())) { if (join_path) { result.push_back(fs.JoinPath(path, fname)); } else { @@ -1259,59 +1224,14 @@ vector LocalFileSystem::FetchFileWithoutGlob(const string &path, FileOpe return result; } -// Helper function to handle file:/ URLs -static idx_t GetFileUrlOffset(const string &path) { - if (!StringUtil::StartsWith(path, "file:/")) { - return 0; - } - - // Url without host: file:/some/path - if (path[6] != '/') { -#ifdef _WIN32 - return 6; -#else - return 5; -#endif - } - - // Url with empty host: file:///some/path - if (path[7] == '/') { -#ifdef _WIN32 - return 8; -#else - return 7; -#endif - } - - // Url with localhost: file://localhost/some/path - if (path.compare(7, 10, "localhost/") == 0) { -#ifdef _WIN32 - return 17; -#else - return 16; -#endif - } - - // unkown file:/ url format - return 0; -} - -const char *LocalFileSystem::NormalizeLocalPath(const string &path) { - return path.c_str() + GetFileUrlOffset(path); -} - vector LocalFileSystem::Glob(const string &path, FileOpener *opener) { if (path.empty()) { return vector(); } // split up the path into separate chunks vector splits; - - bool is_file_url = StringUtil::StartsWith(path, "file:/"); - idx_t file_url_path_offset = GetFileUrlOffset(path); - idx_t last_pos = 0; - for (idx_t i = file_url_path_offset; i < path.size(); i++) { + for (idx_t i = 0; i < path.size(); i++) { if (path[i] == '\\' || path[i] == '/') { if (i == last_pos) { // empty: skip this position @@ -1319,7 +1239,6 @@ vector LocalFileSystem::Glob(const string &path, FileOpener *opener) { continue; } if (splits.empty()) { - // splits.push_back(path.substr(file_url_path_offset, i-file_url_path_offset)); splits.push_back(path.substr(0, i)); } else { splits.push_back(path.substr(last_pos, i - last_pos)); @@ -1330,10 +1249,10 @@ vector LocalFileSystem::Glob(const string &path, FileOpener *opener) { splits.push_back(path.substr(last_pos, path.size() - last_pos)); // handle absolute paths bool absolute_path = false; - if (IsPathAbsolute(path)) { + if (path[0] == '/') { // first character is a slash - unix absolute path absolute_path = true; - } else if (StringUtil::Contains(splits[0], ":")) { // TODO: this is weird? shouldn't IsPathAbsolute handle this? + } else if (StringUtil::Contains(splits[0], ":")) { // first split has a colon - windows absolute path absolute_path = true; } else if (splits[0] == "~") { @@ -1373,16 +1292,7 @@ vector LocalFileSystem::Glob(const string &path, FileOpener *opener) { throw IOException("Cannot use multiple \'**\' in one path"); } - idx_t start_index; - if (is_file_url) { - start_index = 1; - } else if (absolute_path) { - start_index = 1; - } else { - start_index = 0; - } - - for (idx_t i = start_index ? 1 : 0; i < splits.size(); i++) { + for (idx_t i = absolute_path ? 1 : 0; i < splits.size(); i++) { bool is_last_chunk = i + 1 == splits.size(); bool has_glob = HasGlob(splits[i]); // if it's the last chunk we need to find files, otherwise we find directories diff --git a/src/duckdb/src/common/multi_file_list.cpp b/src/duckdb/src/common/multi_file_list.cpp index 668a5b363..9c57b5e84 100644 --- a/src/duckdb/src/common/multi_file_list.cpp +++ b/src/duckdb/src/common/multi_file_list.cpp @@ -14,11 +14,8 @@ namespace duckdb { MultiFilePushdownInfo::MultiFilePushdownInfo(LogicalGet &get) - : table_index(get.table_index), column_names(get.names), column_indexes(get.GetColumnIds()), + : table_index(get.table_index), column_names(get.names), column_ids(get.GetColumnIds()), extra_info(get.extra_info) { - for (auto &col_id : column_indexes) { - column_ids.push_back(col_id.GetPrimaryIndex()); - } } MultiFilePushdownInfo::MultiFilePushdownInfo(idx_t table_index, const vector &column_names, diff --git a/src/duckdb/src/common/multi_file_reader.cpp b/src/duckdb/src/common/multi_file_reader.cpp index 97eba1014..b964a9357 100644 --- a/src/duckdb/src/common/multi_file_reader.cpp +++ b/src/duckdb/src/common/multi_file_reader.cpp @@ -23,7 +23,7 @@ MultiFileReader::~MultiFileReader() { unique_ptr MultiFileReader::Create(const TableFunction &table_function) { unique_ptr res; if (table_function.get_multi_file_reader) { - res = table_function.get_multi_file_reader(table_function); + res = table_function.get_multi_file_reader(); res->function_name = table_function.name; } else { res = make_uniq(); @@ -43,7 +43,7 @@ Value MultiFileReader::CreateValueFromFileList(const vector &file_list) for (auto &file : file_list) { files.push_back(file); } - return Value::LIST(LogicalType::VARCHAR, std::move(files)); + return Value::LIST(std::move(files)); } void MultiFileReader::AddParameters(TableFunction &table_function) { @@ -78,8 +78,12 @@ vector MultiFileReader::ParsePaths(const Value &input) { } } -shared_ptr MultiFileReader::CreateFileList(ClientContext &context, const vector &paths, +unique_ptr MultiFileReader::CreateFileList(ClientContext &context, const vector &paths, FileGlobOptions options) { + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("Scanning %s files is disabled through configuration", function_name); + } vector result_files; auto res = make_uniq(context, paths, options); @@ -89,7 +93,7 @@ shared_ptr MultiFileReader::CreateFileList(ClientContext &context return std::move(res); } -shared_ptr MultiFileReader::CreateFileList(ClientContext &context, const Value &input, +unique_ptr MultiFileReader::CreateFileList(ClientContext &context, const Value &input, FileGlobOptions options) { auto paths = ParsePaths(input); return CreateFileList(context, paths, options); @@ -215,9 +219,7 @@ void MultiFileReader::BindOptions(MultiFileReaderOptions &options, MultiFileList for (auto &part : partitions) { idx_t hive_partitioning_index; - auto lookup = std::find_if(names.begin(), names.end(), [&](const string &col_name) { - return StringUtil::CIEquals(col_name, part.first); - }); + auto lookup = std::find(names.begin(), names.end(), part.first); if (lookup != names.end()) { // hive partitioning column also exists in file - override auto idx = NumericCast(lookup - names.begin()); @@ -237,7 +239,7 @@ void MultiFileReader::BindOptions(MultiFileReaderOptions &options, MultiFileList void MultiFileReader::FinalizeBind(const MultiFileReaderOptions &file_options, const MultiFileReaderBindData &options, const string &filename, const vector &local_names, const vector &global_types, const vector &global_names, - const vector &global_column_ids, MultiFileReaderData &reader_data, + const vector &global_column_ids, MultiFileReaderData &reader_data, ClientContext &context, optional_ptr global_state) { // create a map of name -> column index @@ -248,13 +250,12 @@ void MultiFileReader::FinalizeBind(const MultiFileReaderOptions &file_options, c } } for (idx_t i = 0; i < global_column_ids.size(); i++) { - auto &col_idx = global_column_ids[i]; - if (col_idx.IsRowIdColumn()) { + auto column_id = global_column_ids[i]; + if (IsRowIdColumnId(column_id)) { // row-id reader_data.constant_map.emplace_back(i, Value::BIGINT(42)); continue; } - auto column_id = col_idx.GetPrimaryIndex(); if (column_id == options.filename_idx) { // filename reader_data.constant_map.emplace_back(i, Value(filename)); @@ -295,16 +296,15 @@ unique_ptr MultiFileReader::InitializeGlobalState(ClientContext &context, const MultiFileReaderOptions &file_options, const MultiFileReaderBindData &bind_data, const MultiFileList &file_list, const vector &global_types, const vector &global_names, - const vector &global_column_ids) { + const vector &global_column_ids) { // By default, the multifilereader does not require any global state return nullptr; } void MultiFileReader::CreateNameMapping(const string &file_name, const vector &local_types, const vector &local_names, const vector &global_types, - const vector &global_names, - const vector &global_column_ids, MultiFileReaderData &reader_data, - const string &initial_file, + const vector &global_names, const vector &global_column_ids, + MultiFileReaderData &reader_data, const string &initial_file, optional_ptr global_state) { D_ASSERT(global_types.size() == global_names.size()); D_ASSERT(local_types.size() == local_names.size()); @@ -327,8 +327,7 @@ void MultiFileReader::CreateNameMapping(const string &file_name, const vector= global_types.size()) { throw InternalException( "MultiFileReader::CreatePositionalMapping - global_id is out of range in global_types for this file"); @@ -356,25 +355,20 @@ void MultiFileReader::CreateNameMapping(const string &file_name, const vector &local_types, const vector &local_names, const vector &global_types, - const vector &global_names, const vector &global_column_ids, + const vector &global_names, const vector &global_column_ids, optional_ptr filters, MultiFileReaderData &reader_data, const string &initial_file, const MultiFileReaderBindData &options, optional_ptr global_state) { @@ -416,53 +410,10 @@ void MultiFileReader::FinalizeChunk(ClientContext &context, const MultiFileReade chunk.Verify(); } -void MultiFileReader::GetPartitionData(ClientContext &context, const MultiFileReaderBindData &bind_data, - const MultiFileReaderData &reader_data, - optional_ptr global_state, - const OperatorPartitionInfo &partition_info, - OperatorPartitionData &partition_data) { - for (auto &col : partition_info.partition_columns) { - bool found_constant = false; - for (auto &constant : reader_data.constant_map) { - if (constant.column_id == col) { - found_constant = true; - partition_data.partition_data.emplace_back(constant.value); - break; - } - } - if (!found_constant) { - throw InternalException( - "MultiFileReader::GetPartitionData - did not find constant for the given partition"); - } - } -} - -TablePartitionInfo MultiFileReader::GetPartitionInfo(ClientContext &context, const MultiFileReaderBindData &bind_data, - TableFunctionPartitionInput &input) { - // check if all of the columns are in the hive partition set - for (auto &partition_col : input.partition_ids) { - // check if this column is in the hive partitioned set - bool found = false; - for (auto &partition : bind_data.hive_partitioning_indexes) { - if (partition.index == partition_col) { - found = true; - break; - } - } - if (!found) { - // the column is not partitioned - hive partitioning alone can't guarantee the groups are partitioned - return TablePartitionInfo::NOT_PARTITIONED; - } - } - // if all columns are in the hive partitioning set, we know that each partition will only have a single value - // i.e. if the hive partitioning is by (YEAR, MONTH), each partition will have a single unique (YEAR, MONTH) - return TablePartitionInfo::SINGLE_VALUE_PARTITIONS; -} - TableFunctionSet MultiFileReader::CreateFunctionSet(TableFunction table_function) { TableFunctionSet function_set(table_function.name); function_set.AddFunction(table_function); - D_ASSERT(table_function.arguments.size() >= 1 && table_function.arguments[0] == LogicalType::VARCHAR); + D_ASSERT(table_function.arguments.size() == 1 && table_function.arguments[0] == LogicalType::VARCHAR); table_function.arguments[0] = LogicalType::LIST(LogicalType::VARCHAR); function_set.AddFunction(std::move(table_function)); return function_set; diff --git a/src/duckdb/src/common/opener_file_system.cpp b/src/duckdb/src/common/opener_file_system.cpp deleted file mode 100644 index 8f55d6898..000000000 --- a/src/duckdb/src/common/opener_file_system.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "duckdb/common/opener_file_system.hpp" -#include "duckdb/common/file_opener.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/main/config.hpp" - -namespace duckdb { - -void OpenerFileSystem::VerifyNoOpener(optional_ptr opener) { - if (opener) { - throw InternalException("OpenerFileSystem cannot take an opener - the opener is pushed automatically"); - } -} -void OpenerFileSystem::VerifyCanAccessFileInternal(const string &path, FileType type) { - auto opener = GetOpener(); - if (!opener) { - return; - } - auto db = opener->TryGetDatabase(); - if (!db) { - return; - } - auto &config = db->config; - if (!config.CanAccessFile(path, type)) { - throw PermissionException("Cannot access %s \"%s\" - file system operations are disabled by configuration", - type == FileType::FILE_TYPE_DIR ? "directory" : "file", path); - } -} - -void OpenerFileSystem::VerifyCanAccessFile(const string &path) { - VerifyCanAccessFileInternal(path, FileType::FILE_TYPE_REGULAR); -} - -void OpenerFileSystem::VerifyCanAccessDirectory(const string &path) { - VerifyCanAccessFileInternal(path, FileType::FILE_TYPE_DIR); -} - -} // namespace duckdb diff --git a/src/duckdb/src/common/operator/cast_operators.cpp b/src/duckdb/src/common/operator/cast_operators.cpp index 9742c6087..87adfba46 100644 --- a/src/duckdb/src/common/operator/cast_operators.cpp +++ b/src/duckdb/src/common/operator/cast_operators.cpp @@ -1066,59 +1066,6 @@ bool TryCast::Operation(timestamp_t input, timestamp_t &result, bool strict) { return true; } -template <> -bool TryCast::Operation(timestamp_sec_t input, timestamp_sec_t &result, bool strict) { - result.value = input.value; - return true; -} - -template <> -bool TryCast::Operation(timestamp_t input, timestamp_sec_t &result, bool strict) { - D_ASSERT(Timestamp::IsFinite(input)); - result.value = input.value / Interval::MICROS_PER_SEC; - return true; -} - -template <> -bool TryCast::Operation(timestamp_ms_t input, timestamp_ms_t &result, bool strict) { - result.value = input.value; - return true; -} - -template <> -bool TryCast::Operation(timestamp_t input, timestamp_ms_t &result, bool strict) { - D_ASSERT(Timestamp::IsFinite(input)); - result.value = input.value / Interval::MICROS_PER_MSEC; - return true; -} - -template <> -bool TryCast::Operation(timestamp_ns_t input, timestamp_ns_t &result, bool strict) { - result.value = input.value; - return true; -} - -template <> -bool TryCast::Operation(timestamp_t input, timestamp_ns_t &result, bool strict) { - D_ASSERT(Timestamp::IsFinite(input)); - if (!TryMultiplyOperator::Operation(input.value, Interval::NANOS_PER_MSEC, result.value)) { - throw ConversionException("Could not convert TIMESTAMP to TIMESTAMP_NS"); - } - return true; -} - -template <> -bool TryCast::Operation(timestamp_tz_t input, timestamp_tz_t &result, bool strict) { - result.value = input.value; - return true; -} - -template <> -bool TryCast::Operation(timestamp_t input, timestamp_tz_t &result, bool strict) { - result.value = input.value; - return true; -} - template <> bool TryCast::Operation(timestamp_t input, dtime_tz_t &result, bool strict) { if (!Timestamp::IsFinite(input)) { @@ -1470,16 +1417,8 @@ bool TryCastToUUID::Operation(string_t input, hugeint_t &result, Vector &result_ //===--------------------------------------------------------------------===// template <> bool TryCastErrorMessage::Operation(string_t input, date_t &result, CastParameters ¶meters) { - idx_t pos; - bool special = false; - switch (Date::TryConvertDate(input.GetData(), input.GetSize(), pos, result, special, parameters.strict)) { - case DateCastResult::SUCCESS: - break; - case DateCastResult::ERROR_INCORRECT_FORMAT: - HandleCastError::AssignError(Date::FormatError(input), parameters); - return false; - case DateCastResult::ERROR_RANGE: - HandleCastError::AssignError(Date::RangeError(input), parameters); + if (!TryCast::Operation(input, result, parameters.strict)) { + HandleCastError::AssignError(Date::ConversionError(input), parameters); return false; } return true; @@ -1489,8 +1428,7 @@ template <> bool TryCast::Operation(string_t input, date_t &result, bool strict) { idx_t pos; bool special = false; - return Date::TryConvertDate(input.GetData(), input.GetSize(), pos, result, special, strict) == - DateCastResult::SUCCESS; + return Date::TryConvertDate(input.GetData(), input.GetSize(), pos, result, special, strict); } template <> @@ -1554,18 +1492,14 @@ dtime_tz_t Cast::Operation(string_t input) { //===--------------------------------------------------------------------===// template <> bool TryCastErrorMessage::Operation(string_t input, timestamp_t &result, CastParameters ¶meters) { - switch (Timestamp::TryConvertTimestamp(input.GetData(), input.GetSize(), result)) { - case TimestampCastResult::SUCCESS: + auto cast_result = Timestamp::TryConvertTimestamp(input.GetData(), input.GetSize(), result); + if (cast_result == TimestampCastResult::SUCCESS) { return true; - case TimestampCastResult::ERROR_INCORRECT_FORMAT: - HandleCastError::AssignError(Timestamp::FormatError(input), parameters); - break; - case TimestampCastResult::ERROR_NON_UTC_TIMEZONE: + } + if (cast_result == TimestampCastResult::ERROR_INCORRECT_FORMAT) { + HandleCastError::AssignError(Timestamp::ConversionError(input), parameters); + } else { HandleCastError::AssignError(Timestamp::UnsupportedTimezoneError(input), parameters); - break; - case TimestampCastResult::ERROR_RANGE: - HandleCastError::AssignError(Timestamp::RangeError(input), parameters); - break; } return false; } @@ -1591,7 +1525,7 @@ timestamp_ns_t Cast::Operation(string_t input) { const auto ts = Timestamp::FromCString(input.GetData(), input.GetSize(), &nanos); timestamp_ns_t result; if (!Timestamp::TryFromTimestampNanos(ts, nanos, result)) { - throw ConversionException(Timestamp::RangeError(input)); + throw ConversionException(Timestamp::ConversionError(input)); } return result; } @@ -2311,7 +2245,7 @@ bool DoubleToDecimalCast(SRC input, DST &result, CastParameters ¶meters, uin double roundedValue = round(value); if (roundedValue <= -NumericHelper::DOUBLE_POWERS_OF_TEN[width] || roundedValue >= NumericHelper::DOUBLE_POWERS_OF_TEN[width]) { - string error = StringUtil::Format("Could not cast value %f to DECIMAL(%d,%d)", input, width, scale); + string error = StringUtil::Format("Could not cast value %f to DECIMAL(%d,%d)", value, width, scale); HandleCastError::AssignError(error, parameters); return false; } diff --git a/src/duckdb/src/common/operator/string_cast.cpp b/src/duckdb/src/common/operator/string_cast.cpp index e152c71bf..64d9c53e3 100644 --- a/src/duckdb/src/common/operator/string_cast.cpp +++ b/src/duckdb/src/common/operator/string_cast.cpp @@ -129,11 +129,9 @@ template duckdb::string_t StringFromTimestamp(timestamp_t input, Vector &vector) { if (input == timestamp_t::infinity()) { return StringVector::AddString(vector, Date::PINF); - } - if (input == timestamp_t::ninfinity()) { + } else if (input == timestamp_t::ninfinity()) { return StringVector::AddString(vector, Date::NINF); } - date_t date_entry; dtime_t time_entry; int32_t picos = 0; @@ -262,11 +260,9 @@ template <> string_t StringCastTZ::Operation(timestamp_t input, Vector &vector) { if (input == timestamp_t::infinity()) { return StringVector::AddString(vector, Date::PINF); - } - if (input == timestamp_t::ninfinity()) { + } else if (input == timestamp_t::ninfinity()) { return StringVector::AddString(vector, Date::NINF); } - date_t date_entry; dtime_t time_entry; Timestamp::Convert(input, date_entry, time_entry); diff --git a/src/duckdb/src/common/pipe_file_system.cpp b/src/duckdb/src/common/pipe_file_system.cpp index 3345e4987..d6eb2c6af 100644 --- a/src/duckdb/src/common/pipe_file_system.cpp +++ b/src/duckdb/src/common/pipe_file_system.cpp @@ -7,9 +7,8 @@ namespace duckdb { class PipeFile : public FileHandle { public: - explicit PipeFile(unique_ptr child_handle_p) - : FileHandle(pipe_fs, child_handle_p->path, child_handle_p->GetFlags()), - child_handle(std::move(child_handle_p)) { + PipeFile(unique_ptr child_handle_p, const string &path) + : FileHandle(pipe_fs, path), child_handle(std::move(child_handle_p)) { } PipeFileSystem pipe_fs; @@ -52,7 +51,8 @@ void PipeFileSystem::FileSync(FileHandle &handle) { } unique_ptr PipeFileSystem::OpenPipe(unique_ptr handle) { - return make_uniq(std::move(handle)); + auto path = handle->path; + return make_uniq(std::move(handle), path); } } // namespace duckdb diff --git a/src/duckdb/src/common/progress_bar/progress_bar.cpp b/src/duckdb/src/common/progress_bar/progress_bar.cpp index 4a3de66fb..13d1d509d 100644 --- a/src/duckdb/src/common/progress_bar/progress_bar.cpp +++ b/src/duckdb/src/common/progress_bar/progress_bar.cpp @@ -83,16 +83,8 @@ bool ProgressBar::ShouldPrint(bool final) const { // Don't print progress at all return false; } - if (!supported) { - return false; - } - - double elapsed_time = -1.0; - if (elapsed_time < 0.0) { - elapsed_time = profiler.Elapsed(); - } - - auto sufficient_time_elapsed = elapsed_time > static_cast(show_progress_after) / 1000.0; + // FIXME - do we need to check supported before running `profiler.Elapsed()` ? + auto sufficient_time_elapsed = profiler.Elapsed() > static_cast(show_progress_after) / 1000.0; if (!sufficient_time_elapsed) { // Don't print yet return false; @@ -101,6 +93,9 @@ bool ProgressBar::ShouldPrint(bool final) const { // Print the last completed bar return true; } + if (!supported) { + return false; + } return query_progress.percentage > -1; } @@ -108,33 +103,27 @@ void ProgressBar::Update(bool final) { if (!final && !supported) { return; } + double new_percentage = -1; + auto rows_processed = query_progress.rows_processed.load(); + auto total_rows_to_process = query_progress.total_rows_to_process.load(); + supported = executor.GetPipelinesProgress(new_percentage, rows_processed, total_rows_to_process); + query_progress.rows_processed = rows_processed; + query_progress.total_rows_to_process = total_rows_to_process; - ProgressData progress; - idx_t invalid_pipelines = executor.GetPipelinesProgress(progress); - - double new_percentage = 0.0; - if (invalid_pipelines == 0 && progress.IsValid()) { - if (progress.total > 1e15) { - progress.Normalize(1e15); - } - query_progress.rows_processed = idx_t(progress.done); - query_progress.total_rows_to_process = idx_t(progress.total); - new_percentage = progress.ProgressDone() * 100; - } - - if (!final && invalid_pipelines > 0) { + if (!final && !supported) { return; } - if (new_percentage > query_progress.percentage) { query_progress.percentage = new_percentage; } if (ShouldPrint(final)) { +#ifndef DUCKDB_DISABLE_PRINT if (final) { FinishProgressBarPrint(); } else { PrintProgress(LossyNumericCast(query_progress.percentage.load())); } +#endif } } diff --git a/src/duckdb/src/common/radix_partitioning.cpp b/src/duckdb/src/common/radix_partitioning.cpp index 8b091a803..3e8dee30d 100644 --- a/src/duckdb/src/common/radix_partitioning.cpp +++ b/src/duckdb/src/common/radix_partitioning.cpp @@ -60,25 +60,27 @@ RETURN_TYPE RadixBitsSwitch(const idx_t radix_bits, ARGS &&... args) { } // LCOV_EXCL_STOP } +template +struct RadixLessThan { + static inline bool Operation(hash_t hash, hash_t cutoff) { + using CONSTANTS = RadixPartitioningConstants; + return CONSTANTS::ApplyMask(hash) < cutoff; + } +}; + struct SelectFunctor { template - static idx_t Operation(Vector &hashes, const SelectionVector *sel, const idx_t count, - const ValidityMask &partition_mask, SelectionVector *true_sel, SelectionVector *false_sel) { - using CONSTANTS = RadixPartitioningConstants; - return UnaryExecutor::Select( - hashes, sel, count, - [&](const hash_t hash) { - const auto partition_idx = CONSTANTS::ApplyMask(hash); - return partition_mask.RowIsValidUnsafe(partition_idx); - }, - true_sel, false_sel); + static idx_t Operation(Vector &hashes, const SelectionVector *sel, const idx_t count, const idx_t cutoff, + SelectionVector *true_sel, SelectionVector *false_sel) { + Vector cutoff_vector(Value::HASH(cutoff)); + return BinaryExecutor::Select>(hashes, cutoff_vector, sel, count, + true_sel, false_sel); } }; idx_t RadixPartitioning::Select(Vector &hashes, const SelectionVector *sel, const idx_t count, const idx_t radix_bits, - const ValidityMask &partition_mask, SelectionVector *true_sel, - SelectionVector *false_sel) { - return RadixBitsSwitch(radix_bits, hashes, sel, count, partition_mask, true_sel, false_sel); + const idx_t cutoff, SelectionVector *true_sel, SelectionVector *false_sel) { + return RadixBitsSwitch(radix_bits, hashes, sel, count, cutoff, true_sel, false_sel); } struct ComputePartitionIndicesFunctor { @@ -110,7 +112,6 @@ RadixPartitionedColumnData::RadixPartitionedColumnData(ClientContext &context_p, allocators->allocators.reserve(num_partitions); for (idx_t i = 0; i < num_partitions; i++) { CreateAllocator(); - allocators->allocators.back()->SetPartitionIndex(i); } D_ASSERT(allocators->allocators.size() == num_partitions); } @@ -173,10 +174,8 @@ RadixPartitionedTupleData::~RadixPartitionedTupleData() { } void RadixPartitionedTupleData::Initialize() { - const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); - for (idx_t i = 0; i < num_partitions; i++) { + for (idx_t i = 0; i < RadixPartitioning::NumberOfPartitions(radix_bits); i++) { partitions.emplace_back(CreatePartitionCollection(i)); - partitions.back()->SetPartitionIndex(i); } } diff --git a/src/duckdb/src/common/random_engine.cpp b/src/duckdb/src/common/random_engine.cpp index cf558ea7a..e51f71001 100644 --- a/src/duckdb/src/common/random_engine.cpp +++ b/src/duckdb/src/common/random_engine.cpp @@ -1,13 +1,8 @@ #include "duckdb/common/random_engine.hpp" #include "duckdb/common/numeric_utils.hpp" #include "pcg_random.hpp" - -#ifdef __linux__ -#include -#include -#else #include -#endif + namespace duckdb { struct RandomState { @@ -19,18 +14,7 @@ struct RandomState { RandomEngine::RandomEngine(int64_t seed) : random_state(make_uniq()) { if (seed < 0) { -#ifdef __linux__ - idx_t random_seed = 0; - auto result = syscall(SYS_getrandom, &random_seed, sizeof(random_seed), 0); - if (result == -1) { - // Something went wrong with the syscall, we use chrono - const auto now = std::chrono::high_resolution_clock::now(); - random_seed = now.time_since_epoch().count(); - } - random_state->pcg.seed(random_seed); -#else random_state->pcg.seed(pcg_extras::seed_seq_from()); -#endif } else { random_state->pcg.seed(NumericCast(seed)); } @@ -45,37 +29,17 @@ double RandomEngine::NextRandom(double min, double max) { } double RandomEngine::NextRandom() { - auto uint64 = NextRandomInteger64(); - return std::ldexp(uint64, -64); -} - -double RandomEngine::NextRandom32(double min, double max) { - D_ASSERT(max >= min); - return min + (NextRandom32() * (max - min)); -} - -double RandomEngine::NextRandom32() { - auto uint32 = NextRandomInteger(); - return std::ldexp(uint32, -32); + return std::ldexp(random_state->pcg(), -32); } - uint32_t RandomEngine::NextRandomInteger() { return random_state->pcg(); } -uint64_t RandomEngine::NextRandomInteger64() { - return (static_cast(NextRandomInteger()) << UINT64_C(32)) | static_cast(NextRandomInteger()); -} - uint32_t RandomEngine::NextRandomInteger(uint32_t min, uint32_t max) { return min + static_cast(NextRandom() * double(max - min)); } -uint32_t RandomEngine::NextRandomInteger32(uint32_t min, uint32_t max) { - return min + static_cast(NextRandom32() * double(max - min)); -} - -void RandomEngine::SetSeed(uint64_t seed) { +void RandomEngine::SetSeed(uint32_t seed) { random_state->pcg.seed(seed); } diff --git a/src/duckdb/src/common/render_tree.cpp b/src/duckdb/src/common/render_tree.cpp index 582d5e1ad..6942d6fce 100644 --- a/src/duckdb/src/common/render_tree.cpp +++ b/src/duckdb/src/common/render_tree.cpp @@ -41,13 +41,29 @@ class TreeChildrenIterator { template <> bool TreeChildrenIterator::HasChildren(const PhysicalOperator &op) { - return !op.GetChildren().empty(); + switch (op.type) { + case PhysicalOperatorType::LEFT_DELIM_JOIN: + case PhysicalOperatorType::RIGHT_DELIM_JOIN: + case PhysicalOperatorType::POSITIONAL_SCAN: + return true; + default: + return !op.children.empty(); + } } template <> void TreeChildrenIterator::Iterate(const PhysicalOperator &op, const std::function &callback) { - for (auto &child : op.GetChildren()) { - callback(child); + for (auto &child : op.children) { + callback(*child); + } + if (op.type == PhysicalOperatorType::LEFT_DELIM_JOIN || op.type == PhysicalOperatorType::RIGHT_DELIM_JOIN) { + auto &delim = op.Cast(); + callback(*delim.join); + } else if ((op.type == PhysicalOperatorType::POSITIONAL_SCAN)) { + auto &pscan = op.Cast(); + for (auto &table : pscan.child_tables) { + callback(*table); + } } } diff --git a/src/duckdb/src/common/row_operations/row_external.cpp b/src/duckdb/src/common/row_operations/row_external.cpp index 161fa7501..5aef76a00 100644 --- a/src/duckdb/src/common/row_operations/row_external.cpp +++ b/src/duckdb/src/common/row_operations/row_external.cpp @@ -107,7 +107,7 @@ static inline void VerifyUnswizzledString(const RowLayout &layout, const idx_t & idx_t idx_in_entry; ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry); - ValidityBytes row_mask(row_ptr, layout.ColumnCount()); + ValidityBytes row_mask(row_ptr); if (row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) { auto str = Load(row_ptr + layout.GetOffsets()[col_idx]); str.Verify(); diff --git a/src/duckdb/src/common/row_operations/row_gather.cpp b/src/duckdb/src/common/row_operations/row_gather.cpp index 40743279b..b421fc1c9 100644 --- a/src/duckdb/src/common/row_operations/row_gather.cpp +++ b/src/duckdb/src/common/row_operations/row_gather.cpp @@ -35,7 +35,7 @@ static void TemplatedGatherLoop(Vector &rows, const SelectionVector &row_sel, Ve auto row = ptrs[row_idx]; auto col_idx = col_sel.get_index(i); data[col_idx] = Load(row + col_offset); - ValidityBytes row_mask(row, layout.ColumnCount()); + ValidityBytes row_mask(row); if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) { if (build_size > STANDARD_VECTOR_SIZE && col_mask.AllValid()) { //! We need to initialize the mask with the vector size. @@ -67,7 +67,7 @@ static void GatherVarchar(Vector &rows, const SelectionVector &row_sel, Vector & auto col_idx = col_sel.get_index(i); auto col_ptr = row + col_offset; data[col_idx] = Load(col_ptr); - ValidityBytes row_mask(row, layout.ColumnCount()); + ValidityBytes row_mask(row); if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) { if (build_size > STANDARD_VECTOR_SIZE && col_mask.AllValid()) { //! We need to initialize the mask with the vector size. @@ -178,4 +178,60 @@ void RowOperations::Gather(Vector &rows, const SelectionVector &row_sel, Vector } } +template +static void TemplatedFullScanLoop(Vector &rows, Vector &col, idx_t count, idx_t col_offset, idx_t col_no) { + // Precompute mask indexes + idx_t entry_idx; + idx_t idx_in_entry; + ValidityBytes::GetEntryIndex(col_no, entry_idx, idx_in_entry); + + auto ptrs = FlatVector::GetData(rows); + auto data = FlatVector::GetData(col); + // auto &col_mask = FlatVector::Validity(col); + + for (idx_t i = 0; i < count; i++) { + auto row = ptrs[i]; + data[i] = Load(row + col_offset); + ValidityBytes row_mask(row); + if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) { + throw InternalException("Null value comparisons not implemented for perfect hash table yet"); + // col_mask.SetInvalid(i); + } + } +} + +void RowOperations::FullScanColumn(const TupleDataLayout &layout, Vector &rows, Vector &col, idx_t count, + idx_t col_no) { + const auto col_offset = layout.GetOffsets()[col_no]; + col.SetVectorType(VectorType::FLAT_VECTOR); + switch (col.GetType().InternalType()) { + case PhysicalType::UINT8: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::UINT16: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::UINT32: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::UINT64: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::INT8: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::INT16: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::INT32: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + case PhysicalType::INT64: + TemplatedFullScanLoop(rows, col, count, col_offset, col_no); + break; + default: + throw NotImplementedException("Unimplemented type for RowOperations::FullScanColumn"); + } +} + } // namespace duckdb diff --git a/src/duckdb/src/common/row_operations/row_matcher.cpp b/src/duckdb/src/common/row_operations/row_matcher.cpp index d08ab9d4e..41b9f2114 100644 --- a/src/duckdb/src/common/row_operations/row_matcher.cpp +++ b/src/duckdb/src/common/row_operations/row_matcher.cpp @@ -34,7 +34,7 @@ static idx_t TemplatedMatchLoop(const TupleDataVectorFormat &lhs_format, Selecti const auto lhs_null = LHS_ALL_VALID ? false : !lhs_validity.RowIsValid(lhs_idx); const auto &rhs_location = rhs_locations[idx]; - const ValidityBytes rhs_mask(rhs_location, rhs_layout.ColumnCount()); + const ValidityBytes rhs_mask(rhs_location); const auto rhs_null = !rhs_mask.RowIsValid(rhs_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry); if (COMPARISON_OP::template Operation(lhs_data[lhs_idx], Load(rhs_location + rhs_offset_in_row), lhs_null, @@ -85,7 +85,7 @@ static idx_t StructMatchEquality(Vector &lhs_vector, const TupleDataVectorFormat const auto lhs_null = lhs_validity.AllValid() ? false : !lhs_validity.RowIsValid(lhs_idx); const auto &rhs_location = rhs_locations[idx]; - const ValidityBytes rhs_mask(rhs_location, rhs_layout.ColumnCount()); + const ValidityBytes rhs_mask(rhs_location); const auto rhs_null = !rhs_mask.RowIsValid(rhs_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry); // For structs there is no value to compare, here we match NULLs and let recursion do the rest diff --git a/src/duckdb/src/common/row_operations/row_radix_scatter.cpp b/src/duckdb/src/common/row_operations/row_radix_scatter.cpp index a85a71997..95a230efb 100644 --- a/src/duckdb/src/common/row_operations/row_radix_scatter.cpp +++ b/src/duckdb/src/common/row_operations/row_radix_scatter.cpp @@ -251,13 +251,11 @@ void RadixScatterStructVector(Vector &v, UnifiedVectorFormat &vdata, idx_t vcoun for (idx_t i = 0; i < add_count; i++) { auto idx = sel.get_index(i); auto source_idx = vdata.sel->get_index(idx) + offset; - // write validity and according value if (validity.RowIsValid(source_idx)) { key_locations[i][0] = valid; } else { key_locations[i][0] = invalid; - memset(key_locations[i] + 1, '\0', width - 1); } key_locations[i]++; } diff --git a/src/duckdb/src/common/row_operations/row_scatter.cpp b/src/duckdb/src/common/row_operations/row_scatter.cpp index a535e1a27..6195df237 100644 --- a/src/duckdb/src/common/row_operations/row_scatter.cpp +++ b/src/duckdb/src/common/row_operations/row_scatter.cpp @@ -20,7 +20,7 @@ using ValidityBytes = RowLayout::ValidityBytes; template static void TemplatedScatter(UnifiedVectorFormat &col, Vector &rows, const SelectionVector &sel, const idx_t count, - const idx_t col_offset, const idx_t col_no, const idx_t col_count) { + const idx_t col_offset, const idx_t col_no) { auto data = UnifiedVectorFormat::GetData(col); auto ptrs = FlatVector::GetData(rows); @@ -34,7 +34,7 @@ static void TemplatedScatter(UnifiedVectorFormat &col, Vector &rows, const Selec T store_value = isnull ? NullValue() : data[col_idx]; Store(store_value, row + col_offset); if (isnull) { - ValidityBytes col_mask(ptrs[idx], col_count); + ValidityBytes col_mask(ptrs[idx]); col_mask.SetInvalidUnsafe(col_no); } } @@ -64,7 +64,7 @@ static void ComputeStringEntrySizes(const UnifiedVectorFormat &col, idx_t entry_ static void ScatterStringVector(UnifiedVectorFormat &col, Vector &rows, data_ptr_t str_locations[], const SelectionVector &sel, const idx_t count, const idx_t col_offset, - const idx_t col_no, const idx_t col_count) { + const idx_t col_no) { auto string_data = UnifiedVectorFormat::GetData(col); auto ptrs = FlatVector::GetData(rows); @@ -75,7 +75,7 @@ static void ScatterStringVector(UnifiedVectorFormat &col, Vector &rows, data_ptr auto col_idx = col.sel->get_index(idx); auto row = ptrs[idx]; if (!col.validity.RowIsValid(col_idx)) { - ValidityBytes col_mask(row, col_count); + ValidityBytes col_mask(row); col_mask.SetInvalidUnsafe(col_no); Store(null, row + col_offset); } else if (string_data[col_idx].IsInlined()) { @@ -118,12 +118,11 @@ void RowOperations::Scatter(DataChunk &columns, UnifiedVectorFormat col_data[], } // Set the validity mask for each row before inserting data - idx_t column_count = layout.ColumnCount(); auto ptrs = FlatVector::GetData(rows); for (idx_t i = 0; i < count; ++i) { auto row_idx = sel.get_index(i); auto row = ptrs[row_idx]; - ValidityBytes(row, column_count).SetAllValid(layout.ColumnCount()); + ValidityBytes(row).SetAllValid(layout.ColumnCount()); } const auto vcount = columns.size(); @@ -181,46 +180,46 @@ void RowOperations::Scatter(DataChunk &columns, UnifiedVectorFormat col_data[], switch (types[col_no].InternalType()) { case PhysicalType::BOOL: case PhysicalType::INT8: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::INT16: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::INT32: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::INT64: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::UINT8: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::UINT16: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::UINT32: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::UINT64: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::INT128: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::UINT128: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::FLOAT: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::DOUBLE: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::INTERVAL: - TemplatedScatter(col, rows, sel, count, col_offset, col_no, column_count); + TemplatedScatter(col, rows, sel, count, col_offset, col_no); break; case PhysicalType::VARCHAR: - ScatterStringVector(col, rows, data_locations, sel, count, col_offset, col_no, column_count); + ScatterStringVector(col, rows, data_locations, sel, count, col_offset, col_no); break; case PhysicalType::LIST: case PhysicalType::STRUCT: diff --git a/src/duckdb/src/common/serializer/buffered_file_writer.cpp b/src/duckdb/src/common/serializer/buffered_file_writer.cpp index f0d811921..a378c4ac3 100644 --- a/src/duckdb/src/common/serializer/buffered_file_writer.cpp +++ b/src/duckdb/src/common/serializer/buffered_file_writer.cpp @@ -21,7 +21,7 @@ idx_t BufferedFileWriter::GetFileSize() { return NumericCast(fs.GetFileSize(*handle)) + offset; } -idx_t BufferedFileWriter::GetTotalWritten() const { +idx_t BufferedFileWriter::GetTotalWritten() { return total_written + offset; } diff --git a/src/duckdb/src/common/serializer/memory_stream.cpp b/src/duckdb/src/common/serializer/memory_stream.cpp index e5f0455e3..a48696963 100644 --- a/src/duckdb/src/common/serializer/memory_stream.cpp +++ b/src/duckdb/src/common/serializer/memory_stream.cpp @@ -21,42 +21,6 @@ MemoryStream::~MemoryStream() { } } -MemoryStream::MemoryStream(MemoryStream &&other) noexcept { - // Move the data from the other stream into this stream - data = other.data; - position = other.position; - capacity = other.capacity; - owns_data = other.owns_data; - - // Reset the other stream - other.data = nullptr; - other.position = 0; - other.capacity = 0; - other.owns_data = false; -} - -MemoryStream &MemoryStream::operator=(MemoryStream &&other) noexcept { - if (this != &other) { - // Free the current data - if (owns_data) { - free(data); - } - - // Move the data from the other stream into this stream - data = other.data; - position = other.position; - capacity = other.capacity; - owns_data = other.owns_data; - - // Reset the other stream - other.data = nullptr; - other.position = 0; - other.capacity = 0; - other.owns_data = false; - } - return *this; -} - void MemoryStream::WriteData(const_data_ptr_t source, idx_t write_size) { while (position + write_size > capacity) { if (owns_data) { diff --git a/src/duckdb/src/common/sort/comparators.cpp b/src/duckdb/src/common/sort/comparators.cpp index 4df4cccc4..560b44cc3 100644 --- a/src/duckdb/src/common/sort/comparators.cpp +++ b/src/duckdb/src/common/sort/comparators.cpp @@ -9,7 +9,7 @@ namespace duckdb { bool Comparators::TieIsBreakable(const idx_t &tie_col, const data_ptr_t &row_ptr, const SortLayout &sort_layout) { const auto &col_idx = sort_layout.sorting_to_blob_col.at(tie_col); // Check if the blob is NULL - ValidityBytes row_mask(row_ptr, sort_layout.column_count); + ValidityBytes row_mask(row_ptr); idx_t entry_idx; idx_t idx_in_entry; ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry); @@ -195,8 +195,8 @@ int Comparators::CompareStructAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right const child_list_t &types, bool valid) { idx_t count = types.size(); // Load validity masks - ValidityBytes left_validity(left_ptr, types.size()); - ValidityBytes right_validity(right_ptr, types.size()); + ValidityBytes left_validity(left_ptr); + ValidityBytes right_validity(right_ptr); left_ptr += (count + 7) / 8; right_ptr += (count + 7) / 8; // Initialize variables @@ -235,8 +235,8 @@ int Comparators::CompareArrayAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ } // Load array validity masks - ValidityBytes left_validity(left_ptr, array_size); - ValidityBytes right_validity(right_ptr, array_size); + ValidityBytes left_validity(left_ptr); + ValidityBytes right_validity(right_ptr); left_ptr += (array_size + 7) / 8; right_ptr += (array_size + 7) / 8; @@ -352,8 +352,8 @@ int Comparators::CompareListAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_p left_ptr += sizeof(idx_t); right_ptr += sizeof(idx_t); // Load list validity masks - ValidityBytes left_validity(left_ptr, left_len); - ValidityBytes right_validity(right_ptr, right_len); + ValidityBytes left_validity(left_ptr); + ValidityBytes right_validity(right_ptr); left_ptr += (left_len + 7) / 8; right_ptr += (right_len + 7) / 8; // Compare diff --git a/src/duckdb/src/common/sort/partition_state.cpp b/src/duckdb/src/common/sort/partition_state.cpp index 9c4379695..d87e31fd7 100644 --- a/src/duckdb/src/common/sort/partition_state.cpp +++ b/src/duckdb/src/common/sort/partition_state.cpp @@ -92,7 +92,7 @@ PartitionGlobalSinkState::PartitionGlobalSinkState(ClientContext &context, GenerateOrderings(partitions, orders, partition_bys, order_bys, partition_stats); memory_per_thread = PhysicalOperator::GetMaxThreadMemory(context); - external = ClientConfig::GetConfig(context).GetSetting(context); + external = ClientConfig::GetConfig(context).force_external; const auto thread_pages = PreviousPowerOfTwo(memory_per_thread / (4 * buffer_manager.GetBlockAllocSize())); while (max_bits < 10 && (thread_pages >> max_bits) > 1) { @@ -148,7 +148,7 @@ void PartitionGlobalSinkState::ResizeGroupingData(idx_t cardinality) { return; } // Is the average partition size too large? - const idx_t partition_size = DEFAULT_ROW_GROUP_SIZE; + const idx_t partition_size = STANDARD_ROW_GROUPS_SIZE; const auto bits = grouping_data ? grouping_data->GetRadixBits() : 0; auto new_bits = bits ? bits : 4; while (new_bits < max_bits && (cardinality / RadixPartitioning::NumberOfPartitions(new_bits)) > partition_size) { diff --git a/src/duckdb/src/common/stacktrace.cpp b/src/duckdb/src/common/stacktrace.cpp deleted file mode 100644 index 7a42b35cf..000000000 --- a/src/duckdb/src/common/stacktrace.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "duckdb/common/stacktrace.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/common/to_string.hpp" - -#if defined(__GLIBC__) || defined(__APPLE__) -#include -#include -#endif - -namespace duckdb { - -#if defined(__GLIBC__) || defined(__APPLE__) -static string UnmangleSymbol(string symbol) { - // find the mangled name - idx_t mangle_start = symbol.size(); - idx_t mangle_end = 0; - for (idx_t i = 0; i < symbol.size(); ++i) { - if (symbol[i] == '_') { - mangle_start = i; - break; - } - } - for (idx_t i = mangle_start; i < symbol.size(); i++) { - if (StringUtil::CharacterIsSpace(symbol[i]) || symbol[i] == ')' || symbol[i] == '+') { - mangle_end = i; - break; - } - } - if (mangle_start >= mangle_end) { - return symbol; - } - string mangled_symbol = symbol.substr(mangle_start, mangle_end - mangle_start); - - int status; - auto demangle_result = abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, nullptr, &status); - if (status != 0 || !demangle_result) { - return symbol; - } - string result; - result += symbol.substr(0, mangle_start); - result += demangle_result; - result += symbol.substr(mangle_end); - free(demangle_result); - return result; -} - -static string CleanupStackTrace(string symbol) { -#ifdef __APPLE__ - // structure of frame pointers is [depth] [library] [pointer] [symbol] - // we are only interested in [depth] and [symbol] - - // find the depth - idx_t start; - for (start = 0; start < symbol.size(); start++) { - if (!StringUtil::CharacterIsDigit(symbol[start])) { - break; - } - } - - // now scan forward until we find the frame pointer - idx_t frame_end = symbol.size(); - for (idx_t i = start; i + 1 < symbol.size(); ++i) { - if (symbol[i] == '0' && symbol[i + 1] == 'x') { - idx_t k; - for (k = i + 2; k < symbol.size(); ++k) { - if (!StringUtil::CharacterIsHex(symbol[k])) { - break; - } - } - frame_end = k; - break; - } - } - static constexpr idx_t STACK_TRACE_INDENTATION = 8; - if (frame_end == symbol.size() || start >= STACK_TRACE_INDENTATION) { - // frame pointer not found - just preserve the original frame - return symbol; - } - idx_t space_count = STACK_TRACE_INDENTATION - start; - return symbol.substr(0, start) + string(space_count, ' ') + symbol.substr(frame_end, symbol.size() - frame_end); -#else - return symbol; -#endif -} - -string StackTrace::GetStacktracePointers(idx_t max_depth) { - string result; - auto callstack = unique_ptr(new void *[max_depth]); - int frames = backtrace(callstack.get(), NumericCast(max_depth)); - // skip two frames (these are always StackTrace::...) - for (idx_t i = 2; i < NumericCast(frames); i++) { - if (!result.empty()) { - result += ";"; - } - result += to_string(CastPointerToValue(callstack[i])); - } - return result; -} - -string StackTrace::ResolveStacktraceSymbols(const string &pointers) { - auto splits = StringUtil::Split(pointers, ";"); - idx_t frame_count = splits.size(); - auto callstack = unique_ptr(new void *[frame_count]); - for (idx_t i = 0; i < frame_count; i++) { - callstack[i] = cast_uint64_to_pointer(StringUtil::ToUnsigned(splits[i])); - } - string result; - char **strs = backtrace_symbols(callstack.get(), NumericCast(frame_count)); - for (idx_t i = 0; i < frame_count; i++) { - result += CleanupStackTrace(UnmangleSymbol(strs[i])); - result += "\n"; - } - free(reinterpret_cast(strs)); - return "\n" + result; -} - -#else -string StackTrace::GetStacktracePointers(idx_t max_depth) { - return string(); -} - -string StackTrace::ResolveStacktraceSymbols(const string &pointers) { - return string(); -} -#endif - -} // namespace duckdb diff --git a/src/duckdb/src/common/string_util.cpp b/src/duckdb/src/common/string_util.cpp index f96e3d64e..dd57bda7b 100644 --- a/src/duckdb/src/common/string_util.cpp +++ b/src/duckdb/src/common/string_util.cpp @@ -2,13 +2,10 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/pair.hpp" -#include "duckdb/common/stack.hpp" #include "duckdb/common/to_string.hpp" #include "duckdb/common/helper.hpp" -#include "duckdb/common/exception/parser_exception.hpp" -#include "duckdb/common/random_engine.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "jaro_winkler.hpp" -#include "utf8proc_wrapper.hpp" #include #include @@ -17,7 +14,7 @@ #include #include #include -#include +#include #include "yyjson.hpp" @@ -26,32 +23,19 @@ using namespace duckdb_yyjson; // NOLINT namespace duckdb { string StringUtil::GenerateRandomName(idx_t length) { - RandomEngine engine; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(0, 15); + std::stringstream ss; for (idx_t i = 0; i < length; i++) { - ss << "0123456789abcdef"[engine.NextRandomInteger(0, 15)]; + ss << "0123456789abcdef"[dis(gen)]; } return ss.str(); } bool StringUtil::Contains(const string &haystack, const string &needle) { - return Find(haystack, needle).IsValid(); -} - -optional_idx StringUtil::Find(const string &haystack, const string &needle) { - auto index = haystack.find(needle); - if (index == string::npos) { - return optional_idx(); - } - return optional_idx(index); -} - -bool StringUtil::Contains(const string &haystack, const char &needle_char) { - return (haystack.find(needle_char) != string::npos); -} - -idx_t StringUtil::ToUnsigned(const string &str) { - return std::stoull(str); + return (haystack.find(needle) != string::npos); } void StringUtil::LTrim(string &str) { @@ -102,6 +86,16 @@ string StringUtil::Repeat(const string &str, idx_t n) { return (os.str()); } +vector StringUtil::Split(const string &str, char delimiter) { + std::stringstream ss(str); + vector lines; + string temp; + while (getline(ss, temp, delimiter)) { + lines.push_back(temp); + } + return (lines); +} + namespace string_util_internal { inline void SkipSpaces(const string &str, idx_t &index) { @@ -161,43 +155,6 @@ vector StringUtil::SplitWithQuote(const string &str, char delimiter, cha return entries; } -vector StringUtil::SplitWithParentheses(const string &str, char delimiter, char par_open, char par_close) { - vector result; - string current; - stack parentheses; - - for (size_t i = 0; i < str.size(); ++i) { - char ch = str[i]; - - // stack to keep track if we are within parentheses - if (ch == par_open) { - parentheses.push(ch); - } - if (ch == par_close) { - if (!parentheses.empty()) { - parentheses.pop(); - } else { - throw InvalidInputException("Incongruent parentheses in string: '%s'", str); - } - } - // split if not within parentheses - if (parentheses.empty() && ch == delimiter) { - result.push_back(current); - current.clear(); - } else { - current += ch; - } - } - // Add the last segment - if (!current.empty()) { - result.push_back(current); - } - if (!parentheses.empty()) { - throw InvalidInputException("Incongruent parentheses in string: '%s'", str); - } - return result; -} - string StringUtil::Join(const vector &input, const string &separator) { return StringUtil::Join(input, input.size(), separator, [](const string &s) { return s; }); } @@ -279,10 +236,6 @@ bool StringUtil::IsLower(const string &str) { return str == Lower(str); } -bool StringUtil::IsUpper(const string &str) { - return str == Upper(str); -} - // Jenkins hash function: https://en.wikipedia.org/wiki/Jenkins_hash_function uint64_t StringUtil::CIHash(const string &str) { uint32_t hash = 0; @@ -301,7 +254,7 @@ bool StringUtil::CIEquals(const string &l1, const string &l2) { if (l1.size() != l2.size()) { return false; } - const auto charmap = ASCII_TO_LOWER_MAP; + const auto charmap = LowerFun::ASCII_TO_LOWER_MAP; for (idx_t c = 0; c < l1.size(); c++) { if (charmap[(uint8_t)l1[c]] != charmap[(uint8_t)l2[c]]) { return false; @@ -311,7 +264,7 @@ bool StringUtil::CIEquals(const string &l1, const string &l2) { } bool StringUtil::CILessThan(const string &s1, const string &s2) { - const auto charmap = ASCII_TO_UPPER_MAP; + const auto charmap = UpperFun::ASCII_TO_UPPER_MAP; unsigned char u1 {}, u2 {}; @@ -337,16 +290,6 @@ idx_t StringUtil::CIFind(vector &vector, const string &search_string) { return DConstants::INVALID_INDEX; } -vector StringUtil::Split(const string &str, char delimiter) { - std::stringstream ss(str); - vector lines; - string temp; - while (getline(ss, temp, delimiter)) { - lines.push_back(temp); - } - return (lines); -} - vector StringUtil::Split(const string &input, const string &split) { vector splits; @@ -566,12 +509,23 @@ unordered_map StringUtil::ParseJSONMap(const string &json) { return result; } -string ToJsonMapInternal(const unordered_map &map, yyjson_mut_doc *doc, yyjson_mut_val *root) { +string StringUtil::ToJSONMap(ExceptionType type, const string &message, const unordered_map &map) { + D_ASSERT(map.find("exception_type") == map.end()); + D_ASSERT(map.find("exception_message") == map.end()); + + yyjson_mut_doc *doc = yyjson_mut_doc_new(nullptr); + yyjson_mut_val *root = yyjson_mut_obj(doc); + yyjson_mut_doc_set_root(doc, root); + + auto except_str = Exception::ExceptionTypeToString(type); + yyjson_mut_obj_add_strncpy(doc, root, "exception_type", except_str.c_str(), except_str.size()); + yyjson_mut_obj_add_strncpy(doc, root, "exception_message", message.c_str(), message.size()); for (auto &entry : map) { auto key = yyjson_mut_strncpy(doc, entry.first.c_str(), entry.first.size()); auto value = yyjson_mut_strncpy(doc, entry.second.c_str(), entry.second.size()); yyjson_mut_obj_add(root, key, value); } + yyjson_write_err err; size_t len; constexpr yyjson_write_flag flags = YYJSON_WRITE_ALLOW_INVALID_UNICODE; @@ -590,29 +544,6 @@ string ToJsonMapInternal(const unordered_map &map, yyjson_mut_do // Return the result return result; } -string StringUtil::ToJSONMap(const unordered_map &map) { - yyjson_mut_doc *doc = yyjson_mut_doc_new(nullptr); - yyjson_mut_val *root = yyjson_mut_obj(doc); - yyjson_mut_doc_set_root(doc, root); - - return ToJsonMapInternal(map, doc, root); -} - -string StringUtil::ExceptionToJSONMap(ExceptionType type, const string &message, - const unordered_map &map) { - D_ASSERT(map.find("exception_type") == map.end()); - D_ASSERT(map.find("exception_message") == map.end()); - - yyjson_mut_doc *doc = yyjson_mut_doc_new(nullptr); - yyjson_mut_val *root = yyjson_mut_obj(doc); - yyjson_mut_doc_set_root(doc, root); - - auto except_str = Exception::ExceptionTypeToString(type); - yyjson_mut_obj_add_strncpy(doc, root, "exception_type", except_str.c_str(), except_str.size()); - yyjson_mut_obj_add_strncpy(doc, root, "exception_message", message.c_str(), message.size()); - - return ToJsonMapInternal(map, doc, root); -} string StringUtil::GetFileName(const string &file_path) { @@ -782,60 +713,4 @@ string StringUtil::URLDecode(const string &input, bool plus_to_space) { return string(result_data.get(), result_size); } -uint32_t StringUtil::StringToEnum(const EnumStringLiteral enum_list[], idx_t enum_count, const char *enum_name, - const char *str_value) { - for (idx_t i = 0; i < enum_count; i++) { - if (CIEquals(enum_list[i].string, str_value)) { - return enum_list[i].number; - } - } - // string to enum conversion failed - generate candidates - vector candidates; - for (idx_t i = 0; i < enum_count; i++) { - candidates.push_back(enum_list[i].string); - } - auto closest_values = TopNJaroWinkler(candidates, str_value); - auto message = CandidatesMessage(closest_values, "Candidates"); - throw NotImplementedException("Enum value: unrecognized value \"%s\" for enum \"%s\"\n%s", str_value, enum_name, - message); -} - -const char *StringUtil::EnumToString(const EnumStringLiteral enum_list[], idx_t enum_count, const char *enum_name, - uint32_t enum_value) { - for (idx_t i = 0; i < enum_count; i++) { - if (enum_list[i].number == enum_value) { - return enum_list[i].string; - } - } - throw NotImplementedException("Enum value: unrecognized enum value \"%d\" for enum \"%s\"", enum_value, enum_name); -} - -const uint8_t StringUtil::ASCII_TO_UPPER_MAP[] = { - 0, 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, 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, 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}; - -const uint8_t StringUtil::ASCII_TO_LOWER_MAP[] = { - 0, 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, 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, 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}; - } // namespace duckdb diff --git a/src/duckdb/src/common/tree_renderer/text_tree_renderer.cpp b/src/duckdb/src/common/tree_renderer/text_tree_renderer.cpp index fa24ee103..8e0fa4253 100644 --- a/src/duckdb/src/common/tree_renderer/text_tree_renderer.cpp +++ b/src/duckdb/src/common/tree_renderer/text_tree_renderer.cpp @@ -168,12 +168,13 @@ void TextTreeRenderer::RenderBoxContent(RenderTree &root, std::ostream &ss, idx_ for (idx_t x = 0; x < root.width; x++) { auto node = root.GetNode(x, y); if (node) { - SplitUpExtraInfo(node->extra_text, extra_info[x], config.max_extra_lines); + SplitUpExtraInfo(node->extra_text, extra_info[x]); if (extra_info[x].size() > extra_height) { extra_height = extra_info[x].size(); } } } + extra_height = MinValue(extra_height, config.max_extra_lines); idx_t halfway_point = (extra_height + 1) / 2; // now we render the actual node for (idx_t render_y = 0; render_y <= extra_height; render_y++) { @@ -404,8 +405,7 @@ void TextTreeRenderer::SplitStringBuffer(const string &source, vector &r } } -void TextTreeRenderer::SplitUpExtraInfo(const InsertionOrderPreservingMap &extra_info, vector &result, - idx_t max_lines) { +void TextTreeRenderer::SplitUpExtraInfo(const InsertionOrderPreservingMap &extra_info, vector &result) { if (extra_info.empty()) { return; } @@ -467,18 +467,6 @@ void TextTreeRenderer::SplitUpExtraInfo(const InsertionOrderPreservingMap max_lines) { - // truncate this entry - vector truncated_splits; - for (idx_t i = 0; i < max_lines / 2; i++) { - truncated_splits.push_back(std::move(splits[i])); - } - truncated_splits.push_back("..."); - for (idx_t i = splits.size() - max_lines / 2; i < splits.size(); i++) { - truncated_splits.push_back(std::move(splits[i])); - } - splits = std::move(truncated_splits); - } for (auto &split : splits) { SplitStringBuffer(split, result); } diff --git a/src/duckdb/src/common/types.cpp b/src/duckdb/src/common/types.cpp index 342a84bc0..a440b4961 100644 --- a/src/duckdb/src/common/types.cpp +++ b/src/duckdb/src/common/types.cpp @@ -13,7 +13,6 @@ #include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/string_util.hpp" -#include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types/decimal.hpp" #include "duckdb/common/types/hash.hpp" #include "duckdb/common/types/string_type.hpp" @@ -25,12 +24,11 @@ #include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" -#include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" #include "duckdb/main/database_manager.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/parser/parser.hpp" - +#include "duckdb/main/config.hpp" #include namespace duckdb { @@ -172,7 +170,6 @@ string LogicalTypeIdToString(LogicalTypeId type) { constexpr const LogicalTypeId LogicalType::INVALID; constexpr const LogicalTypeId LogicalType::SQLNULL; -constexpr const LogicalTypeId LogicalType::UNKNOWN; constexpr const LogicalTypeId LogicalType::BOOLEAN; constexpr const LogicalTypeId LogicalType::TINYINT; constexpr const LogicalTypeId LogicalType::UTINYINT; @@ -365,29 +362,21 @@ bool TypeIsInteger(PhysicalType type) { type == PhysicalType::UINT128; } -static string TypeModifierListToString(const vector &mod_list) { - string result; - if (mod_list.empty()) { - return result; - } - result = "("; - for (idx_t i = 0; i < mod_list.size(); i++) { - result += mod_list[i].ToString(); - if (i < mod_list.size() - 1) { - result += ", "; - } - } - result += ")"; - return result; -} - string LogicalType::ToString() const { if (id_ != LogicalTypeId::USER) { auto alias = GetAlias(); if (!alias.empty()) { - if (HasExtensionInfo()) { - auto &ext_info = *GetExtensionInfo(); - alias += TypeModifierListToString(ext_info.modifiers); + auto mods_ptr = GetModifiers(); + if (mods_ptr && !mods_ptr->empty()) { + auto &mods = *mods_ptr; + alias += "("; + for (idx_t i = 0; i < mods.size(); i++) { + alias += mods[i].ToString(); + if (i < mods.size() - 1) { + alias += ", "; + } + } + alias += ")"; } return alias; } @@ -570,7 +559,7 @@ LogicalType TransformStringToLogicalType(const string &str) { "INT2", "SHORT", "TIME", - "TIMESTAMPTZ", + "TIMESTAMPTZ ", "TIMESTAMP", "DATETIME", "TINYINT", @@ -689,80 +678,6 @@ bool LogicalType::IsValid() const { return id() != LogicalTypeId::INVALID && id() != LogicalTypeId::UNKNOWN; } -bool LogicalType::IsComplete() const { - // Check if type does not contain incomplete types - return !TypeVisitor::Contains(*this, [](const LogicalType &type) { - switch (type.id()) { - case LogicalTypeId::INVALID: - case LogicalTypeId::UNKNOWN: - case LogicalTypeId::ANY: - return true; // These are incomplete by default - case LogicalTypeId::LIST: - case LogicalTypeId::MAP: - if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::LIST_TYPE_INFO) { - return true; // Missing or incorrect type info - } - break; - case LogicalTypeId::STRUCT: - case LogicalTypeId::UNION: - if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::STRUCT_TYPE_INFO) { - return true; // Missing or incorrect type info - } - break; - case LogicalTypeId::ARRAY: - if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::ARRAY_TYPE_INFO) { - return true; // Missing or incorrect type info - } - break; - case LogicalTypeId::DECIMAL: - if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::DECIMAL_TYPE_INFO) { - return true; // Missing or incorrect type info - } - break; - case LogicalTypeId::ENUM: - if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::ENUM_TYPE_INFO) { - return true; // Missing or incorrect type info - } - break; - default: - return false; - } - - // Type has type info, check if it is complete - D_ASSERT(type.AuxInfo()); - switch (type.AuxInfo()->type) { - case ExtraTypeInfoType::STRUCT_TYPE_INFO: - return type.AuxInfo()->Cast().child_types.empty(); // Cannot be empty - case ExtraTypeInfoType::DECIMAL_TYPE_INFO: - return DecimalType::GetWidth(type) >= 1 && DecimalType::GetWidth(type) <= Decimal::MAX_WIDTH_DECIMAL && - DecimalType::GetScale(type) <= DecimalType::GetWidth(type); - default: - return false; // Nested types are checked by TypeVisitor recursion - } - }); -} - -bool LogicalType::SupportsRegularUpdate() const { - switch (id()) { - case LogicalTypeId::LIST: - case LogicalTypeId::ARRAY: - case LogicalTypeId::MAP: - case LogicalTypeId::UNION: - return false; - case LogicalTypeId::STRUCT: { - auto &child_types = StructType::GetChildTypes(*this); - for (auto &entry : child_types) { - if (!entry.second.SupportsRegularUpdate()) { - return false; - } - } - return true; - } - default: - return true; - } -} - bool LogicalType::GetDecimalProperties(uint8_t &width, uint8_t &scale) const { switch (id_) { case LogicalTypeId::SQLNULL: @@ -921,8 +836,14 @@ LogicalType LogicalType::NormalizeType(const LogicalType &type) { template static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &right, LogicalType &result) { // left and right are not equal - // NULL/unknown (parameter) types always take the other type - LogicalTypeId other_types[] = {LogicalTypeId::SQLNULL, LogicalTypeId::UNKNOWN}; + // for enums, match the varchar rules + if (left.id() == LogicalTypeId::ENUM) { + return OP::Operation(LogicalType::VARCHAR, right, result); + } else if (right.id() == LogicalTypeId::ENUM) { + return OP::Operation(left, LogicalType::VARCHAR, result); + } + // NULL/string literals/unknown (parameter) types always take the other type + LogicalTypeId other_types[] = {LogicalTypeId::SQLNULL, LogicalTypeId::UNKNOWN, LogicalTypeId::STRING_LITERAL}; for (auto &other_type : other_types) { if (left.id() == other_type) { result = LogicalType::NormalizeType(right); @@ -933,22 +854,6 @@ static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &righ } } - // for enums, match the varchar rules - if (left.id() == LogicalTypeId::ENUM) { - return OP::Operation(LogicalType::VARCHAR, right, result); - } else if (right.id() == LogicalTypeId::ENUM) { - return OP::Operation(left, LogicalType::VARCHAR, result); - } - - // for everything but enums - string literals also take the other type - if (left.id() == LogicalTypeId::STRING_LITERAL) { - result = LogicalType::NormalizeType(right); - return true; - } else if (right.id() == LogicalTypeId::STRING_LITERAL) { - result = LogicalType::NormalizeType(left); - return true; - } - // for other types - use implicit cast rules to check if we can combine the types auto left_to_right_cost = CastRules::ImplicitCast(left, right); auto right_to_left_cost = CastRules::ImplicitCast(right, left); @@ -995,72 +900,6 @@ static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &righ return false; } -template -static bool CombineStructTypes(const LogicalType &left, const LogicalType &right, LogicalType &result) { - auto &left_children = StructType::GetChildTypes(left); - auto &right_children = StructType::GetChildTypes(right); - - auto left_unnamed = StructType::IsUnnamed(left); - auto is_unnamed = left_unnamed || StructType::IsUnnamed(right); - child_list_t child_types; - - // At least one side is unnamed, so we attempt positional casting. - if (is_unnamed) { - if (left_children.size() != right_children.size()) { - // We can't cast, or create the super-set. - return false; - } - - for (idx_t i = 0; i < left_children.size(); i++) { - LogicalType child_type; - if (!OP::Operation(left_children[i].second, right_children[i].second, child_type)) { - return false; - } - auto &child_name = left_unnamed ? right_children[i].first : left_children[i].first; - child_types.emplace_back(child_name, std::move(child_type)); - } - result = LogicalType::STRUCT(child_types); - return true; - } - - // Create a super-set of the STRUCT fields. - // First, create a name->index map of the right children. - case_insensitive_map_t right_children_map; - for (idx_t i = 0; i < right_children.size(); i++) { - auto &name = right_children[i].first; - right_children_map[name] = i; - } - - for (idx_t i = 0; i < left_children.size(); i++) { - auto &left_child = left_children[i]; - auto right_child_it = right_children_map.find(left_child.first); - - if (right_child_it == right_children_map.end()) { - // We can directly put the left child. - child_types.emplace_back(left_child.first, left_child.second); - continue; - } - - // We need to recurse to ensure the children have a maximum logical type. - LogicalType child_type; - auto &right_child = right_children[right_child_it->second]; - if (!OP::Operation(left_child.second, right_child.second, child_type)) { - return false; - } - child_types.emplace_back(left_child.first, std::move(child_type)); - right_children_map.erase(right_child_it); - } - - // Add all remaining right children. - for (const auto &right_child_it : right_children_map) { - auto &right_child = right_children[right_child_it.second]; - child_types.emplace_back(right_child.first, right_child.second); - } - - result = LogicalType::STRUCT(child_types); - return true; -} - template static bool CombineEqualTypes(const LogicalType &left, const LogicalType &right, LogicalType &result) { // Since both left and right are equal we get the left type as our type_id for checks @@ -1132,7 +971,31 @@ static bool CombineEqualTypes(const LogicalType &left, const LogicalType &right, return true; } case LogicalTypeId::STRUCT: { - return CombineStructTypes(left, right, result); + // struct: perform recursively on each child + auto &left_child_types = StructType::GetChildTypes(left); + auto &right_child_types = StructType::GetChildTypes(right); + bool left_unnamed = StructType::IsUnnamed(left); + auto any_unnamed = left_unnamed || StructType::IsUnnamed(right); + if (left_child_types.size() != right_child_types.size()) { + // child types are not of equal size, we can't cast + // return false + return false; + } + child_list_t child_types; + for (idx_t i = 0; i < left_child_types.size(); i++) { + LogicalType child_type; + // Child names must be in the same order OR either one of the structs must be unnamed + if (!any_unnamed && !StringUtil::CIEquals(left_child_types[i].first, right_child_types[i].first)) { + return false; + } + if (!OP::Operation(left_child_types[i].second, right_child_types[i].second, child_type)) { + return false; + } + auto &child_name = left_unnamed ? right_child_types[i].first : left_child_types[i].first; + child_types.emplace_back(child_name, std::move(child_type)); + } + result = LogicalType::STRUCT(child_types); + return true; } case LogicalTypeId::UNION: { auto left_member_count = UnionType::GetMemberCount(left); @@ -1410,32 +1273,51 @@ bool LogicalType::HasAlias() const { return false; } -bool LogicalType::HasExtensionInfo() const { - if (type_info_ && type_info_->extension_info) { - return true; +void LogicalType::SetModifiers(vector modifiers) { + if (!type_info_ && !modifiers.empty()) { + type_info_ = make_shared_ptr(ExtraTypeInfoType::GENERIC_TYPE_INFO); + } + type_info_->modifiers = std::move(modifiers); +} + +bool LogicalType::HasModifiers() const { + if (id() == LogicalTypeId::USER) { + return !UserType::GetTypeModifiers(*this).empty(); + } + if (type_info_) { + return !type_info_->modifiers.empty(); } return false; } -optional_ptr LogicalType::GetExtensionInfo() const { - if (type_info_ && type_info_->extension_info) { - return type_info_->extension_info.get(); +vector LogicalType::GetModifiersCopy() const { + if (id() == LogicalTypeId::USER) { + return UserType::GetTypeModifiers(*this); } - return nullptr; + if (type_info_) { + return type_info_->modifiers; + } + return {}; } -optional_ptr LogicalType::GetExtensionInfo() { - if (type_info_ && type_info_->extension_info) { - return type_info_->extension_info.get(); +optional_ptr> LogicalType::GetModifiers() { + if (id() == LogicalTypeId::USER) { + return UserType::GetTypeModifiers(*this); + } + if (type_info_) { + return type_info_->modifiers; } return nullptr; } -void LogicalType::SetExtensionInfo(unique_ptr info) { - if (!type_info_) { - type_info_ = make_shared_ptr(ExtraTypeInfoType::GENERIC_TYPE_INFO); +optional_ptr> LogicalType::GetModifiers() const { + if (id() == LogicalTypeId::USER) { + return UserType::GetTypeModifiers(*this); + } + if (type_info_) { + return type_info_->modifiers; } - type_info_->extension_info = std::move(info); + return nullptr; } //===--------------------------------------------------------------------===// @@ -1663,30 +1545,35 @@ const child_list_t UnionType::CopyMemberTypes(const LogicalType &ty const string &UserType::GetCatalog(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::USER); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().catalog; } const string &UserType::GetSchema(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::USER); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().schema; } const string &UserType::GetTypeName(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::USER); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().user_type_name; } const vector &UserType::GetTypeModifiers(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::USER); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().user_type_modifiers; } vector &UserType::GetTypeModifiers(LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::USER); auto info = type.GetAuxInfoShrPtr(); + D_ASSERT(info); return info->Cast().user_type_modifiers; } @@ -1726,18 +1613,21 @@ const string EnumType::GetValue(const Value &val) { const Vector &EnumType::GetValuesInsertOrder(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ENUM); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().GetValuesInsertOrder(); } idx_t EnumType::GetSize(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ENUM); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().GetDictSize(); } PhysicalType EnumType::GetPhysicalType(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ENUM); auto aux_info = type.AuxInfo(); + D_ASSERT(aux_info); auto &info = aux_info->Cast(); D_ASSERT(info.GetEnumDictType() == EnumDictType::VECTOR_DICT); return EnumTypeInfo::DictType(info.GetDictSize()); @@ -1763,18 +1653,21 @@ bool LogicalType::IsJSONType() const { const LogicalType &ArrayType::GetChildType(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ARRAY); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().child_type; } idx_t ArrayType::GetSize(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ARRAY); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().size; } bool ArrayType::IsAnySize(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::ARRAY); auto info = type.AuxInfo(); + D_ASSERT(info); return info->Cast().size == 0; } @@ -1855,7 +1748,7 @@ idx_t AnyType::GetCastScore(const LogicalType &type) { LogicalType IntegerLiteral::GetType(const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::INTEGER_LITERAL); auto info = type.AuxInfo(); - D_ASSERT(info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO); + D_ASSERT(info && info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO); return info->Cast().constant_value.type(); } @@ -1870,7 +1763,7 @@ bool IntegerLiteral::FitsInType(const LogicalType &type, const LogicalType &targ } // we can cast to integral types if the constant value fits within that type auto info = type.AuxInfo(); - D_ASSERT(info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO); + D_ASSERT(info && info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO); auto &literal_info = info->Cast(); Value copy = literal_info.constant_value; return copy.DefaultTryCastAs(target); diff --git a/src/duckdb/src/common/types/column/column_data_allocator.cpp b/src/duckdb/src/common/types/column/column_data_allocator.cpp index 66a1e612f..bec0751e0 100644 --- a/src/duckdb/src/common/types/column/column_data_allocator.cpp +++ b/src/duckdb/src/common/types/column/column_data_allocator.cpp @@ -1,6 +1,5 @@ #include "duckdb/common/types/column/column_data_allocator.hpp" -#include "duckdb/common/radix_partitioning.hpp" #include "duckdb/common/types/column/column_data_collection_segment.hpp" #include "duckdb/storage/buffer/block_handle.hpp" #include "duckdb/storage/buffer/buffer_pool.hpp" @@ -85,9 +84,6 @@ BufferHandle ColumnDataAllocator::AllocateBlock(idx_t size) { auto pin = alloc.buffer_manager->Allocate(MemoryTag::COLUMN_DATA, max_size, false); data.handle = pin.GetBlockHandle(); blocks.push_back(std::move(data)); - if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - blocks.back().handle->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); - } allocated_size += max_size; return pin; } diff --git a/src/duckdb/src/common/types/column/column_data_collection.cpp b/src/duckdb/src/common/types/column/column_data_collection.cpp index d6e01e5a6..c3740444a 100644 --- a/src/duckdb/src/common/types/column/column_data_collection.cpp +++ b/src/duckdb/src/common/types/column/column_data_collection.cpp @@ -1,14 +1,14 @@ #include "duckdb/common/types/column/column_data_collection.hpp" #include "duckdb/common/printer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/column/column_data_collection_segment.hpp" #include "duckdb/common/types/value_map.hpp" #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/storage/buffer_manager.hpp" +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" namespace duckdb { @@ -119,13 +119,6 @@ idx_t ColumnDataCollection::AllocationSize() const { return total_size; } -void ColumnDataCollection::SetPartitionIndex(const idx_t index) { - D_ASSERT(!partition_index.IsValid()); - D_ASSERT(Count() == 0); - partition_index = index; - allocator->SetPartitionIndex(index); -} - //===--------------------------------------------------------------------===// // ColumnDataRow //===--------------------------------------------------------------------===// @@ -318,7 +311,7 @@ void ColumnDataCollection::InitializeAppend(ColumnDataAppendState &state) { void ColumnDataCopyValidity(const UnifiedVectorFormat &source_data, validity_t *target, idx_t source_offset, idx_t target_offset, idx_t copy_count) { - ValidityMask validity(target, STANDARD_VECTOR_SIZE); + ValidityMask validity(target); if (target_offset == 0) { // first time appending to this vector // all data here is still uninitialized @@ -408,9 +401,9 @@ static void TemplatedColumnDataCopy(ColumnDataMetaData &meta_data, const Unified auto base_ptr = segment.allocator->GetDataPointer(append_state.current_chunk_state, current_segment.block_id, current_segment.offset); - auto validity_data = ColumnDataCollectionSegment::GetValidityPointerForWriting(base_ptr, OP::TypeSize()); + auto validity_data = ColumnDataCollectionSegment::GetValidityPointer(base_ptr, OP::TypeSize()); - ValidityMask result_validity(validity_data, STANDARD_VECTOR_SIZE); + ValidityMask result_validity(validity_data); if (current_segment.count == 0) { // first time appending to this vector // all data here is still uninitialized @@ -524,8 +517,8 @@ void ColumnDataCopy(ColumnDataMetaData &meta_data, const UnifiedVector auto ¤t_segment = segment.GetVectorData(current_index); auto base_ptr = segment.allocator->GetDataPointer(append_state.current_chunk_state, current_segment.block_id, current_segment.offset); - auto validity_data = ColumnDataCollectionSegment::GetValidityPointerForWriting(base_ptr, sizeof(string_t)); - ValidityMask target_validity(validity_data, STANDARD_VECTOR_SIZE); + auto validity_data = ColumnDataCollectionSegment::GetValidityPointer(base_ptr, sizeof(string_t)); + ValidityMask target_validity(validity_data); if (current_segment.count == 0) { // first time appending to this vector // all data here is still uninitialized @@ -779,8 +772,7 @@ ColumnDataCopyFunction ColumnDataCollection::GetCopyFunction(const LogicalType & break; } default: - throw InternalException("Unsupported type %s for ColumnDataCollection::GetCopyFunction", - EnumUtil::ToString(type.InternalType())); + throw InternalException("Unsupported type for ColumnDataCollection::GetCopyFunction"); } result.function = function; return result; @@ -931,29 +923,6 @@ bool ColumnDataCollection::NextScanIndex(ColumnDataScanState &state, idx_t &chun return true; } -bool ColumnDataCollection::PrevScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, - idx_t &row_index) const { - // check within the current segment if we still have chunks to scan - // Note that state.chunk_index is 1-indexed, with 0 as undefined. - while (state.chunk_index <= 1) { - if (!state.segment_index) { - return false; - } - - --state.segment_index; - state.chunk_index = segments[state.segment_index]->chunk_data.size() + 1; - state.current_chunk_state.handles.clear(); - } - - --state.chunk_index; - segment_index = state.segment_index; - chunk_index = state.chunk_index - 1; - state.next_row_index = state.current_row_index; - state.current_row_index -= segments[state.segment_index]->chunk_data[chunk_index].count; - row_index = state.current_row_index; - return true; -} - void ColumnDataCollection::ScanAtIndex(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result, idx_t chunk_index, idx_t segment_index, idx_t row_index) const { @@ -986,38 +955,6 @@ bool ColumnDataCollection::Scan(ColumnDataScanState &state, DataChunk &result) c return true; } -bool ColumnDataCollection::Seek(idx_t seek_idx, ColumnDataScanState &state, DataChunk &result) const { - // Idempotency: Don't change anything if the row is already in range - if (state.current_row_index <= seek_idx && seek_idx < state.next_row_index) { - return true; - } - - result.Reset(); - - // Linear scan for now. We could use a current_row_index => chunk map at some point - // but most use cases should be pretty local - idx_t chunk_index; - idx_t segment_index; - idx_t row_index; - while (seek_idx < state.current_row_index) { - if (!PrevScanIndex(state, chunk_index, segment_index, row_index)) { - return false; - } - } - while (state.next_row_index <= seek_idx) { - if (!NextScanIndex(state, chunk_index, segment_index, row_index)) { - return false; - } - } - - // found a chunk to scan -> scan it - auto &segment = *segments[segment_index]; - state.current_chunk_state.properties = state.properties; - segment.ReadChunk(chunk_index, state.current_chunk_state, result, state.column_ids); - result.Verify(); - return true; -} - ColumnDataRowCollection ColumnDataCollection::GetRows() const { return ColumnDataRowCollection(*this); } diff --git a/src/duckdb/src/common/types/column/column_data_collection_segment.cpp b/src/duckdb/src/common/types/column/column_data_collection_segment.cpp index 1ec0f6f45..fd2e39fff 100644 --- a/src/duckdb/src/common/types/column/column_data_collection_segment.cpp +++ b/src/duckdb/src/common/types/column/column_data_collection_segment.cpp @@ -14,31 +14,10 @@ idx_t ColumnDataCollectionSegment::GetDataSize(idx_t type_size) { return AlignValue(type_size * STANDARD_VECTOR_SIZE); } -validity_t *ColumnDataCollectionSegment::GetValidityPointerForWriting(data_ptr_t base_ptr, idx_t type_size) { +validity_t *ColumnDataCollectionSegment::GetValidityPointer(data_ptr_t base_ptr, idx_t type_size) { return reinterpret_cast(base_ptr + GetDataSize(type_size)); } -validity_t *ColumnDataCollectionSegment::GetValidityPointer(data_ptr_t base_ptr, idx_t type_size, idx_t count) { - auto validity_mask = reinterpret_cast(base_ptr + GetDataSize(type_size)); - - // Optimized check to see if all entries are valid - for (idx_t i = 0; i < (count / ValidityMask::BITS_PER_VALUE); i++) { - if (!ValidityMask::AllValid(validity_mask[i])) { - return validity_mask; - } - } - - if ((count % ValidityMask::BITS_PER_VALUE) != 0) { - // Create a mask with the lower `bits_to_check` bits set to 1 - validity_t mask = (1ULL << (count % ValidityMask::BITS_PER_VALUE)) - 1; - if ((validity_mask[(count / ValidityMask::BITS_PER_VALUE)] & mask) != mask) { - return validity_mask; - } - } - // All entries are valid, no need to initialize the validity mask - return nullptr; -} - VectorDataIndex ColumnDataCollectionSegment::AllocateVectorInternal(const LogicalType &type, ChunkMetaData &chunk_meta, ChunkManagementState *chunk_state) { VectorMetaData meta_data; @@ -162,11 +141,11 @@ idx_t ColumnDataCollectionSegment::ReadVectorInternal(ChunkManagementState &stat auto &vdata = GetVectorData(vector_index); auto base_ptr = allocator->GetDataPointer(state, vdata.block_id, vdata.offset); - auto validity_data = GetValidityPointer(base_ptr, type_size, vdata.count); + auto validity_data = GetValidityPointer(base_ptr, type_size); if (!vdata.next_data.IsValid() && state.properties != ColumnDataScanProperties::DISALLOW_ZERO_COPY) { // no next data, we can do a zero-copy read of this vector FlatVector::SetData(result, base_ptr); - FlatVector::Validity(result).Initialize(validity_data, STANDARD_VECTOR_SIZE); + FlatVector::Validity(result).Initialize(validity_data); return vdata.count; } @@ -190,11 +169,11 @@ idx_t ColumnDataCollectionSegment::ReadVectorInternal(ChunkManagementState &stat while (next_index.IsValid()) { auto ¤t_vdata = GetVectorData(next_index); base_ptr = allocator->GetDataPointer(state, current_vdata.block_id, current_vdata.offset); - validity_data = GetValidityPointer(base_ptr, type_size, current_vdata.count); + validity_data = GetValidityPointer(base_ptr, type_size); if (type_size > 0) { memcpy(target_data + current_offset * type_size, base_ptr, current_vdata.count * type_size); } - ValidityMask current_validity(validity_data, STANDARD_VECTOR_SIZE); + ValidityMask current_validity(validity_data); target_validity.SliceInPlace(current_validity, current_offset, 0, current_vdata.count); current_offset += current_vdata.count; next_index = current_vdata.next_data; @@ -216,6 +195,7 @@ idx_t ColumnDataCollectionSegment::ReadVector(ChunkManagementState &state, Vecto auto &child_vector = ListVector::GetEntry(result); auto child_count = ReadVector(state, GetChildIndex(vdata.child_index), child_vector); ListVector::SetListSize(result, child_count); + } else if (internal_type == PhysicalType::ARRAY) { auto &child_vector = ArrayVector::GetEntry(result); auto child_count = ReadVector(state, GetChildIndex(vdata.child_index), child_vector); @@ -255,7 +235,6 @@ void ColumnDataCollectionSegment::ReadChunk(idx_t chunk_index, ChunkManagementSt const vector &column_ids) { D_ASSERT(chunk.ColumnCount() == column_ids.size()); D_ASSERT(state.properties != ColumnDataScanProperties::INVALID); - chunk.Reset(); InitializeChunkState(chunk_index, state); auto &chunk_meta = chunk_data[chunk_index]; for (idx_t i = 0; i < column_ids.size(); i++) { diff --git a/src/duckdb/src/common/types/conflict_manager.cpp b/src/duckdb/src/common/types/conflict_manager.cpp index 409d0278f..8e7ce0b9b 100644 --- a/src/duckdb/src/common/types/conflict_manager.cpp +++ b/src/duckdb/src/common/types/conflict_manager.cpp @@ -212,24 +212,6 @@ idx_t ConflictManager::ConflictCount() const { return conflicts.Count(); } -void ConflictManager::AddIndex(BoundIndex &index, optional_ptr delete_index) { - matched_indexes.push_back(index); - matched_delete_indexes.push_back(delete_index); - matched_index_names.insert(index.name); -} - -bool ConflictManager::MatchedIndex(BoundIndex &index) { - return matched_index_names.find(index.name) != matched_index_names.end(); -} - -const vector> &ConflictManager::MatchedIndexes() const { - return matched_indexes; -} - -const vector> &ConflictManager::MatchedDeleteIndexes() const { - return matched_delete_indexes; -} - void ConflictManager::Finalize() { D_ASSERT(!finalized); if (SingleIndexTarget()) { @@ -252,8 +234,8 @@ void ConflictManager::Finalize() { } } // Now create the row_ids Vector, aligned with the selection vector - auto &internal_row_ids = InternalRowIds(); - auto row_id_data = FlatVector::GetData(internal_row_ids); + auto &row_ids = InternalRowIds(); + auto row_id_data = FlatVector::GetData(row_ids); for (idx_t i = 0; i < selection.Count(); i++) { D_ASSERT(!row_id_map.empty()); @@ -266,7 +248,11 @@ void ConflictManager::Finalize() { } VerifyExistenceType ConflictManager::LookupType() const { - return lookup_type; + return this->lookup_type; +} + +void ConflictManager::SetIndexCount(idx_t count) { + index_count = count; } } // namespace duckdb diff --git a/src/duckdb/src/common/types/date.cpp b/src/duckdb/src/common/types/date.cpp index 429ee0311..7c9f78ca8 100644 --- a/src/duckdb/src/common/types/date.cpp +++ b/src/duckdb/src/common/types/date.cpp @@ -205,12 +205,11 @@ bool Date::TryConvertDateSpecial(const char *buf, idx_t len, idx_t &pos, const c return true; } -DateCastResult Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date_t &result, bool &special, - bool strict) { +bool Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date_t &result, bool &special, bool strict) { special = false; pos = 0; if (len == 0) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } int32_t day = 0; @@ -225,13 +224,13 @@ DateCastResult Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date } if (pos >= len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } if (buf[pos] == '-') { yearneg = true; pos++; if (pos >= len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } } if (!StringUtil::CharacterIsDigit(buf[pos])) { @@ -241,62 +240,62 @@ DateCastResult Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date } else if (TryConvertDateSpecial(buf, len, pos, EPOCH)) { result = date_t::epoch(); } else { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } // skip trailing spaces - parsing must be strict here while (pos < len && StringUtil::CharacterIsSpace(buf[pos])) { pos++; } special = true; - return (pos == len) ? DateCastResult::SUCCESS : DateCastResult::ERROR_INCORRECT_FORMAT; + return pos == len; } // first parse the year idx_t year_length = 0; for (; pos < len && StringUtil::CharacterIsDigit(buf[pos]); pos++) { if (year >= 100000000) { - return DateCastResult::ERROR_RANGE; + return false; } year = (buf[pos] - '0') + year * 10; year_length++; } if (year_length < 2 && strict) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } if (yearneg) { year = -year; } if (pos >= len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } // fetch the separator sep = buf[pos++]; if (sep != ' ' && sep != '-' && sep != '/' && sep != '\\') { // invalid separator - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } // parse the month if (!Date::ParseDoubleDigit(buf, len, pos, month)) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } if (pos >= len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } if (buf[pos++] != sep) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } if (pos >= len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } // now parse the day if (!Date::ParseDoubleDigit(buf, len, pos, day)) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } // check for an optional trailing " (BC)"" @@ -304,7 +303,7 @@ DateCastResult Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date StringUtil::CharacterToLower(buf[pos + 2]) == 'b' && StringUtil::CharacterToLower(buf[pos + 3]) == 'c' && buf[pos + 4] == ')') { if (yearneg || year == 0) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } year = -year + 1; pos += 5; @@ -318,47 +317,34 @@ DateCastResult Date::TryConvertDate(const char *buf, idx_t len, idx_t &pos, date } // check position. if end was not reached, non-space chars remaining if (pos < len) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } } else { // in non-strict mode, check for any direct trailing digits if (pos < len && StringUtil::CharacterIsDigit(buf[pos])) { - return DateCastResult::ERROR_INCORRECT_FORMAT; + return false; } } - return Date::TryFromDate(year, month, day, result) ? DateCastResult::SUCCESS : DateCastResult::ERROR_RANGE; + return Date::TryFromDate(year, month, day, result); } -string Date::FormatError(const string &str) { - return StringUtil::Format("invalid date field format: \"%s\", " +string Date::ConversionError(const string &str) { + return StringUtil::Format("date field value out of range: \"%s\", " "expected format is (YYYY-MM-DD)", str); } -string Date::RangeError(const string &str) { - return StringUtil::Format("date field value out of range: \"%s\"", str); -} - -string Date::RangeError(string_t str) { - return RangeError(str.GetString()); -} - -string Date::FormatError(string_t str) { - return FormatError(str.GetString()); +string Date::ConversionError(string_t str) { + return ConversionError(str.GetString()); } date_t Date::FromCString(const char *buf, idx_t len, bool strict) { date_t result; idx_t pos; bool special = false; - switch (TryConvertDate(buf, len, pos, result, special, strict)) { - case DateCastResult::ERROR_INCORRECT_FORMAT: - throw ConversionException(FormatError(string(buf, len))); - case DateCastResult::ERROR_RANGE: - throw ConversionException(RangeError(string(buf, len))); - case DateCastResult::SUCCESS: - break; + if (!TryConvertDate(buf, len, pos, result, special, strict)) { + throw ConversionException(ConversionError(string(buf, len))); } return result; } diff --git a/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp b/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp index b77463d8c..17cd306f4 100644 --- a/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp +++ b/src/duckdb/src/common/types/row/partitioned_tuple_data.cpp @@ -262,8 +262,15 @@ void PartitionedTupleData::Repartition(PartitionedTupleData &new_partitioned_dat PartitionedTupleDataAppendState append_state; new_partitioned_data.InitializeAppendState(append_state); - for (idx_t partition_idx = 0; partition_idx < partitions.size(); partition_idx++) { - auto &partition = *partitions[partition_idx]; + const auto reverse = RepartitionReverseOrder(); + const idx_t start_idx = reverse ? partitions.size() : 0; + const idx_t end_idx = reverse ? 0 : partitions.size(); + const int64_t update = reverse ? -1 : 1; + const int64_t adjustment = reverse ? -1 : 0; + + for (idx_t partition_idx = start_idx; partition_idx != end_idx; partition_idx += idx_t(update)) { + auto actual_partition_idx = partition_idx + idx_t(adjustment); + auto &partition = *partitions[actual_partition_idx]; if (partition.Count() > 0) { TupleDataChunkIterator iterator(partition, TupleDataPinProperties::DESTROY_AFTER_DONE, true); @@ -272,9 +279,9 @@ void PartitionedTupleData::Repartition(PartitionedTupleData &new_partitioned_dat new_partitioned_data.Append(append_state, chunk_state, iterator.GetCurrentChunkCount()); } while (iterator.Next()); - RepartitionFinalizeStates(*this, new_partitioned_data, append_state, partition_idx); + RepartitionFinalizeStates(*this, new_partitioned_data, append_state, actual_partition_idx); } - partitions[partition_idx]->Reset(); + partitions[actual_partition_idx]->Reset(); } new_partitioned_data.FlushAppendState(append_state); diff --git a/src/duckdb/src/common/types/row/tuple_data_allocator.cpp b/src/duckdb/src/common/types/row/tuple_data_allocator.cpp index ed9145a11..8f391c498 100644 --- a/src/duckdb/src/common/types/row/tuple_data_allocator.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_allocator.cpp @@ -1,7 +1,6 @@ #include "duckdb/common/types/row/tuple_data_allocator.hpp" #include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/radix_partitioning.hpp" #include "duckdb/common/types/row/tuple_data_segment.hpp" #include "duckdb/common/types/row/tuple_data_states.hpp" #include "duckdb/storage/buffer/block_handle.hpp" @@ -74,12 +73,6 @@ idx_t TupleDataAllocator::HeapBlockCount() const { return heap_blocks.size(); } -void TupleDataAllocator::SetPartitionIndex(const idx_t index) { - D_ASSERT(!partition_index.IsValid()); - D_ASSERT(row_blocks.empty() && heap_blocks.empty()); - partition_index = index; -} - void TupleDataAllocator::Build(TupleDataSegment &segment, TupleDataPinState &pin_state, TupleDataChunkState &chunk_state, const idx_t append_offset, const idx_t append_count) { D_ASSERT(this == segment.allocator.get()); @@ -149,9 +142,6 @@ TupleDataChunkPart TupleDataAllocator::BuildChunkPart(TupleDataPinState &pin_sta // Allocate row block (if needed) if (row_blocks.empty() || row_blocks.back().RemainingCapacity() < layout.GetRowWidth()) { row_blocks.emplace_back(buffer_manager, block_size); - if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - row_blocks.back().handle->SetEvictionQueueIndex(RadixPartitioning::RadixBits(partition_index.GetIndex())); - } } result.row_block_index = NumericCast(row_blocks.size() - 1); auto &row_block = row_blocks[result.row_block_index]; @@ -198,10 +188,6 @@ TupleDataChunkPart TupleDataAllocator::BuildChunkPart(TupleDataPinState &pin_sta if (heap_blocks.empty() || heap_blocks.back().RemainingCapacity() < heap_sizes[append_offset]) { const auto size = MaxValue(block_size, heap_sizes[append_offset]); heap_blocks.emplace_back(buffer_manager, size); - if (partition_index.IsValid()) { // Set the eviction queue index logarithmically using RadixBits - heap_blocks.back().handle->SetEvictionQueueIndex( - RadixPartitioning::RadixBits(partition_index.GetIndex())); - } } result.heap_block_index = NumericCast(heap_blocks.size() - 1); auto &heap_block = heap_blocks[result.heap_block_index]; @@ -329,9 +315,9 @@ void TupleDataAllocator::InitializeChunkStateInternal(TupleDataPinState &pin_sta D_ASSERT(offset <= STANDARD_VECTOR_SIZE); } -static inline void VerifyStrings(const TupleDataLayout &layout, const LogicalTypeId type_id, - const data_ptr_t row_locations[], const idx_t col_idx, const idx_t base_col_offset, - const idx_t col_offset, const idx_t offset, const idx_t count) { +static inline void VerifyStrings(const LogicalTypeId type_id, const data_ptr_t row_locations[], const idx_t col_idx, + const idx_t base_col_offset, const idx_t col_offset, const idx_t offset, + const idx_t count) { #ifdef DEBUG if (type_id != LogicalTypeId::VARCHAR) { // Make sure we don't verify BLOB / AGGREGATE_STATE @@ -342,7 +328,7 @@ static inline void VerifyStrings(const TupleDataLayout &layout, const LogicalTyp ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry); for (idx_t i = 0; i < count; i++) { const auto &row_location = row_locations[offset + i] + base_col_offset; - ValidityBytes row_mask(row_location, layout.ColumnCount()); + ValidityBytes row_mask(row_location); if (row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { auto recomputed_string = Load(row_location + col_offset); recomputed_string.Verify(); @@ -376,7 +362,7 @@ void TupleDataAllocator::RecomputeHeapPointers(Vector &old_heap_ptrs, const Sele for (idx_t i = 0; i < count; i++) { const auto idx = offset + i; const auto &row_location = row_locations[idx] + base_col_offset; - ValidityBytes row_mask(row_location, layout.ColumnCount()); + ValidityBytes row_mask(row_location); if (!row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { continue; } @@ -393,7 +379,7 @@ void TupleDataAllocator::RecomputeHeapPointers(Vector &old_heap_ptrs, const Sele Store(new_heap_ptr + diff, string_ptr_location); } } - VerifyStrings(layout, type.id(), row_locations, col_idx, base_col_offset, col_offset, offset, count); + VerifyStrings(type.id(), row_locations, col_idx, base_col_offset, col_offset, offset, count); break; } case PhysicalType::LIST: @@ -401,7 +387,7 @@ void TupleDataAllocator::RecomputeHeapPointers(Vector &old_heap_ptrs, const Sele for (idx_t i = 0; i < count; i++) { const auto idx = offset + i; const auto &row_location = row_locations[idx] + base_col_offset; - ValidityBytes row_mask(row_location, layout.ColumnCount()); + ValidityBytes row_mask(row_location); if (!row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { continue; } diff --git a/src/duckdb/src/common/types/row/tuple_data_collection.cpp b/src/duckdb/src/common/types/row/tuple_data_collection.cpp index 7db3ba37a..a5215d030 100644 --- a/src/duckdb/src/common/types/row/tuple_data_collection.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_collection.cpp @@ -79,13 +79,6 @@ void TupleDataCollection::Unpin() { } } -void TupleDataCollection::SetPartitionIndex(const idx_t index) { - D_ASSERT(!partition_index.IsValid()); - D_ASSERT(Count() == 0); - partition_index = index; - allocator->SetPartitionIndex(index); -} - // LCOV_EXCL_START void VerifyAppendColumns(const TupleDataLayout &layout, const vector &column_ids) { #ifdef DEBUG @@ -169,8 +162,6 @@ void TupleDataCollection::InitializeChunkState(TupleDataChunkState &chunk_state, } InitializeVectorFormat(chunk_state.vector_data, types); - chunk_state.cached_cast_vectors.clear(); - chunk_state.cached_cast_vector_cache.clear(); for (auto &col : column_ids) { auto &type = types[col]; if (TypeVisitor::Contains(type, LogicalTypeId::ARRAY)) { @@ -255,7 +246,7 @@ static inline void ToUnifiedFormatInternal(TupleDataVectorFormat &format, Vector // Make sure we round up so its all covered auto child_array_total_size = ArrayVector::GetTotalSize(vector); auto list_entry_t_count = - MaxValue((child_array_total_size + array_size) / array_size, format.unified.validity.Capacity()); + MaxValue((child_array_total_size + array_size) / array_size, format.unified.validity.TargetCount()); // Create list entries! format.array_list_entries = make_unsafe_uniq_array(list_entry_t_count); diff --git a/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp b/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp index a735d90b0..fb9e8a6d1 100644 --- a/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp +++ b/src/duckdb/src/common/types/row/tuple_data_scatter_gather.cpp @@ -646,7 +646,7 @@ static void TupleDataTemplatedScatter(const Vector &, const TupleDataVectorForma TupleDataValueStore(data[source_idx], target_locations[i], offset_in_row, target_heap_locations[i]); } else { TupleDataValueStore(NullValue(), target_locations[i], offset_in_row, target_heap_locations[i]); - ValidityBytes(target_locations[i], layout.ColumnCount()).SetInvalidUnsafe(entry_idx, idx_in_entry); + ValidityBytes(target_locations[i]).SetInvalidUnsafe(entry_idx, idx_in_entry); } } } @@ -675,7 +675,7 @@ static void TupleDataStructScatter(const Vector &source, const TupleDataVectorFo for (idx_t i = 0; i < append_count; i++) { const auto source_idx = source_sel.get_index(append_sel.get_index(i)); if (!validity.RowIsValid(source_idx)) { - ValidityBytes(target_locations[i], layout.ColumnCount()).SetInvalidUnsafe(entry_idx, idx_in_entry); + ValidityBytes(target_locations[i]).SetInvalidUnsafe(entry_idx, idx_in_entry); } } } @@ -742,7 +742,7 @@ static void TupleDataListScatter(const Vector &source, const TupleDataVectorForm Store(data[source_idx].length, target_heap_location); target_heap_location += sizeof(uint64_t); } else { - ValidityBytes(target_locations[i], layout.ColumnCount()).SetInvalidUnsafe(entry_idx, idx_in_entry); + ValidityBytes(target_locations[i]).SetInvalidUnsafe(entry_idx, idx_in_entry); } } @@ -791,7 +791,7 @@ static void TupleDataArrayScatter(const Vector &source, const TupleDataVectorFor Store(data[source_idx].length, target_heap_location); target_heap_location += sizeof(uint64_t); } else { - ValidityBytes(target_locations[i], layout.ColumnCount()).SetInvalidUnsafe(entry_idx, idx_in_entry); + ValidityBytes(target_locations[i]).SetInvalidUnsafe(entry_idx, idx_in_entry); } } @@ -843,7 +843,7 @@ static void TupleDataTemplatedWithinCollectionScatter(const Vector &, const Tupl // Initialize validity mask and skip heap pointer over it auto &target_heap_location = target_heap_locations[i]; - ValidityBytes child_mask(target_heap_location, list_length); + ValidityBytes child_mask(target_heap_location); child_mask.SetAllValid(list_length); target_heap_location += ValidityBytes::SizeInBytes(list_length); @@ -901,7 +901,7 @@ static void TupleDataStructWithinCollectionScatter(const Vector &source, const T // Initialize validity mask and skip the heap pointer over it auto &target_heap_location = target_heap_locations[i]; - ValidityBytes child_mask(target_heap_location, list_length); + ValidityBytes child_mask(target_heap_location); child_mask.SetAllValid(list_length); target_heap_location += ValidityBytes::SizeInBytes(list_length); @@ -964,7 +964,7 @@ static void TupleDataCollectionWithinCollectionScatter(const Vector &child_list, // Initialize validity mask and skip heap pointer over it auto &target_heap_location = target_heap_locations[i]; - ValidityBytes child_mask(target_heap_location, list_length); + ValidityBytes child_mask(target_heap_location); child_mask.SetAllValid(list_length); target_heap_location += ValidityBytes::SizeInBytes(list_length); @@ -1129,7 +1129,7 @@ static void TupleDataTemplatedGather(const TupleDataLayout &layout, Vector &row_ const auto &source_row = source_locations[scan_sel.get_index(i)]; const auto target_idx = target_sel.get_index(i); target_data[target_idx] = Load(source_row + offset_in_row); - ValidityBytes row_mask(source_row, layout.ColumnCount()); + ValidityBytes row_mask(source_row); if (!row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { target_validity.SetInvalid(target_idx); } @@ -1165,7 +1165,7 @@ static void TupleDataStructGather(const TupleDataLayout &layout, Vector &row_loc const auto &source_row = source_locations[source_idx]; // Set the validity - ValidityBytes row_mask(source_row, layout.ColumnCount()); + ValidityBytes row_mask(source_row); if (!row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { const auto target_idx = target_sel.get_index(i); target_validity.SetInvalid(target_idx); @@ -1214,11 +1214,10 @@ static void TupleDataListGather(const TupleDataLayout &layout, Vector &row_locat const auto source_heap_locations = FlatVector::GetData(heap_locations); const auto offset_in_row = layout.GetOffsets()[col_idx]; - auto list_size_before = ListVector::GetListSize(target); - uint64_t target_list_offset = list_size_before; + uint64_t target_list_offset = 0; for (idx_t i = 0; i < scan_count; i++) { const auto &source_row = source_locations[scan_sel.get_index(i)]; - ValidityBytes row_mask(source_row, layout.ColumnCount()); + ValidityBytes row_mask(source_row); const auto target_idx = target_sel.get_index(i); if (row_mask.RowIsValid(row_mask.GetValidityEntryUnsafe(entry_idx), idx_in_entry)) { @@ -1238,8 +1237,9 @@ static void TupleDataListGather(const TupleDataLayout &layout, Vector &row_locat target_list_validity.SetInvalid(target_idx); } } - ListVector::Reserve(target, target_list_offset); - ListVector::SetListSize(target, target_list_offset); + auto list_size_before = ListVector::GetListSize(target); + ListVector::Reserve(target, list_size_before + target_list_offset); + ListVector::SetListSize(target, list_size_before + target_list_offset); // Recurse D_ASSERT(child_functions.size() == 1); @@ -1282,7 +1282,7 @@ TupleDataTemplatedWithinCollectionGather(const TupleDataLayout &, Vector &heap_l // Initialize validity mask auto &source_heap_location = source_heap_locations[i]; - ValidityBytes source_mask(source_heap_location, list_length); + ValidityBytes source_mask(source_heap_location); source_heap_location += ValidityBytes::SizeInBytes(list_length); // Get the start to the fixed-size data and skip the heap pointer over it @@ -1333,7 +1333,7 @@ static void TupleDataStructWithinCollectionGather(const TupleDataLayout &layout, // Initialize validity mask and skip over it auto &source_heap_location = source_heap_locations[i]; - ValidityBytes source_mask(source_heap_location, list_length); + ValidityBytes source_mask(source_heap_location); source_heap_location += ValidityBytes::SizeInBytes(list_length); // Load the child validity belonging to this list entry @@ -1398,7 +1398,7 @@ static void TupleDataCollectionWithinCollectionGather(const TupleDataLayout &lay // Initialize validity mask and skip over it auto &source_heap_location = source_heap_locations[i]; - ValidityBytes source_mask(source_heap_location, list_length); + ValidityBytes source_mask(source_heap_location); source_heap_location += ValidityBytes::SizeInBytes(list_length); // Get the start to the fixed-size data and skip the heap pointer over it diff --git a/src/duckdb/src/common/types/timestamp.cpp b/src/duckdb/src/common/types/timestamp.cpp index d596e7530..d6b3f822b 100644 --- a/src/duckdb/src/common/types/timestamp.cpp +++ b/src/duckdb/src/common/types/timestamp.cpp @@ -17,15 +17,6 @@ namespace duckdb { static_assert(sizeof(timestamp_t) == sizeof(int64_t), "timestamp_t was padded"); -// Temporal values need to round down when changing precision, -// but C/C++ rounds towrds 0 when you simply divide. -// This piece of bit banging solves that problem. -template -static inline T TemporalRound(T value, T scale) { - const auto negative = int(value < 0); - return UnsafeNumericCast((value + negative) / scale - negative); -} - // timestamp/datetime uses 64 bits, high 32 bits for date and low 32 bits for time // string format is YYYY-MM-DDThh:mm:ssZ // T may be a space @@ -64,31 +55,25 @@ timestamp_t ×tamp_t::operator-=(const int64_t &delta) { return *this; } -TimestampCastResult Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &result, bool &has_offset, - string_t &tz, optional_ptr nanos) { +bool Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &result, bool &has_offset, string_t &tz, + optional_ptr nanos) { idx_t pos; date_t date; dtime_t time; has_offset = false; - switch (Date::TryConvertDate(str, len, pos, date, has_offset)) { - case DateCastResult::ERROR_INCORRECT_FORMAT: - return TimestampCastResult::ERROR_INCORRECT_FORMAT; - case DateCastResult::ERROR_RANGE: - return TimestampCastResult::ERROR_RANGE; - default: - break; + if (!Date::TryConvertDate(str, len, pos, date, has_offset)) { + return false; } if (pos == len) { // no time: only a date or special if (date == date_t::infinity()) { result = timestamp_t::infinity(); - return TimestampCastResult::SUCCESS; + return true; } else if (date == date_t::ninfinity()) { result = timestamp_t::ninfinity(); - return TimestampCastResult::SUCCESS; + return true; } - return Timestamp::TryFromDatetime(date, dtime_t(0), result) ? TimestampCastResult::SUCCESS - : TimestampCastResult::ERROR_RANGE; + return Timestamp::TryFromDatetime(date, dtime_t(0), result); } // try to parse a time field if (str[pos] == ' ' || str[pos] == 'T') { @@ -99,15 +84,15 @@ TimestampCastResult Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, // operation. Note that we can't pass strict== true here because we // want to process any suffix. if (!Time::TryConvertInterval(str + pos, len - pos, time_pos, time, false, nanos)) { - return TimestampCastResult::ERROR_INCORRECT_FORMAT; + return false; } // We parsed an interval, so make sure it is in range. if (time.micros > Interval::MICROS_PER_DAY) { - return TimestampCastResult::ERROR_RANGE; + return false; } pos += time_pos; if (!Timestamp::TryFromDatetime(date, time, result)) { - return TimestampCastResult::ERROR_RANGE; + return false; } if (pos < len) { // skip a "Z" at the end (as per the ISO8601 specs) @@ -118,13 +103,13 @@ TimestampCastResult Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, } else if (Timestamp::TryParseUTCOffset(str, pos, len, hour_offset, minute_offset)) { const int64_t delta = hour_offset * Interval::MICROS_PER_HOUR + minute_offset * Interval::MICROS_PER_MINUTE; if (!TrySubtractOperator::Operation(result.value, delta, result.value)) { - return TimestampCastResult::ERROR_RANGE; + return false; } has_offset = true; } else { // Parse a time zone: / [A-Za-z0-9/_]+/ if (str[pos++] != ' ') { - return TimestampCastResult::ERROR_NON_UTC_TIMEZONE; + return false; } auto tz_name = str + pos; for (; pos < len && CharacterIsTimeZone(str[pos]); ++pos) { @@ -142,10 +127,10 @@ TimestampCastResult Timestamp::TryConvertTimestampTZ(const char *str, idx_t len, pos++; } if (pos < len) { - return TimestampCastResult::ERROR_INCORRECT_FORMAT; + return false; } } - return TimestampCastResult::SUCCESS; + return true; } TimestampCastResult Timestamp::TryConvertTimestamp(const char *str, idx_t len, timestamp_t &result, @@ -154,8 +139,8 @@ TimestampCastResult Timestamp::TryConvertTimestamp(const char *str, idx_t len, t bool has_offset = false; // We don't understand TZ without an extension, so fail if one was provided. auto success = TryConvertTimestampTZ(str, len, result, has_offset, tz, nanos); - if (success != TimestampCastResult::SUCCESS) { - return success; + if (!success) { + return TimestampCastResult::ERROR_INCORRECT_FORMAT; } if (tz.GetSize() == 0) { // no timezone provided - success! @@ -182,11 +167,7 @@ bool Timestamp::TryFromTimestampNanos(timestamp_t input, int32_t nanos, timestam return false; } - if (!TryAddOperator::Operation(result.value, int64_t(nanos), result.value)) { - return false; - } - - return IsFinite(result); + return TryAddOperator::Operation(result.value, int64_t(nanos), result.value); } TimestampCastResult Timestamp::TryConvertTimestamp(const char *str, idx_t len, timestamp_ns_t &result) { @@ -201,8 +182,8 @@ TimestampCastResult Timestamp::TryConvertTimestamp(const char *str, idx_t len, t return TimestampCastResult::SUCCESS; } -string Timestamp::FormatError(const string &str) { - return StringUtil::Format("invalid timestamp field format: \"%s\", " +string Timestamp::ConversionError(const string &str) { + return StringUtil::Format("timestamp field value out of range: \"%s\", " "expected format is (YYYY-MM-DD HH:MM:SS[.US][±HH:MM| ZONE])", str); } @@ -213,35 +194,25 @@ string Timestamp::UnsupportedTimezoneError(const string &str) { str); } -string Timestamp::RangeError(const string &str) { - return StringUtil::Format("timestamp field value out of range: \"%s\"", str); -} - -string Timestamp::FormatError(string_t str) { - return Timestamp::FormatError(str.GetString()); +string Timestamp::ConversionError(string_t str) { + return Timestamp::ConversionError(str.GetString()); } string Timestamp::UnsupportedTimezoneError(string_t str) { return Timestamp::UnsupportedTimezoneError(str.GetString()); } -string Timestamp::RangeError(string_t str) { - return Timestamp::RangeError(str.GetString()); -} - timestamp_t Timestamp::FromCString(const char *str, idx_t len, optional_ptr nanos) { timestamp_t result; - switch (Timestamp::TryConvertTimestamp(str, len, result, nanos)) { - case TimestampCastResult::SUCCESS: - break; - case TimestampCastResult::ERROR_NON_UTC_TIMEZONE: - throw ConversionException(UnsupportedTimezoneError(string(str, len))); - case TimestampCastResult::ERROR_INCORRECT_FORMAT: - throw ConversionException(FormatError(string(str, len))); - case TimestampCastResult::ERROR_RANGE: - throw ConversionException(RangeError(string(str, len))); + auto cast_result = Timestamp::TryConvertTimestamp(str, len, result, nanos); + if (cast_result == TimestampCastResult::SUCCESS) { + return result; + } + if (cast_result == TimestampCastResult::ERROR_NON_UTC_TIMEZONE) { + throw ConversionException(Timestamp::UnsupportedTimezoneError(string(str, len))); + } else { + throw ConversionException(Timestamp::ConversionError(string(str, len))); } - return result; } bool Timestamp::TryParseUTCOffset(const char *str, idx_t &pos, idx_t len, int &hour_offset, int &minute_offset) { @@ -299,11 +270,9 @@ timestamp_t Timestamp::FromString(const string &str) { string Timestamp::ToString(timestamp_t timestamp) { if (timestamp == timestamp_t::infinity()) { return Date::PINF; - } - if (timestamp == timestamp_t::ninfinity()) { + } else if (timestamp == timestamp_t::ninfinity()) { return Date::NINF; } - date_t date; dtime_t time; Timestamp::Convert(timestamp, date, time); @@ -313,8 +282,7 @@ string Timestamp::ToString(timestamp_t timestamp) { date_t Timestamp::GetDate(timestamp_t timestamp) { if (DUCKDB_UNLIKELY(timestamp == timestamp_t::infinity())) { return date_t::infinity(); - } - if (DUCKDB_UNLIKELY(timestamp == timestamp_t::ninfinity())) { + } else if (DUCKDB_UNLIKELY(timestamp == timestamp_t::ninfinity())) { return date_t::ninfinity(); } return date_t(UnsafeNumericCast((timestamp.value + (timestamp.value < 0)) / Interval::MICROS_PER_DAY - @@ -354,7 +322,7 @@ bool Timestamp::TryFromDatetime(date_t date, dtime_tz_t timetz, timestamp_t &res timestamp_t Timestamp::FromDatetime(date_t date, dtime_t time) { timestamp_t result; if (!TryFromDatetime(date, time, result)) { - throw ConversionException("Date and time not in timestamp range"); + throw ConversionException("Overflow exception in date/time -> timestamp conversion"); } return result; } @@ -371,7 +339,7 @@ void Timestamp::Convert(timestamp_t timestamp, date_t &out_date, dtime_t &out_ti } void Timestamp::Convert(timestamp_ns_t input, date_t &out_date, dtime_t &out_time, int32_t &out_nanos) { - timestamp_t ms(TemporalRound(input.value, Interval::NANOS_PER_MICRO)); + timestamp_t ms(input.value / Interval::NANOS_PER_MICRO); out_date = Timestamp::GetDate(ms); int64_t days_nanos; if (!TryMultiplyOperator::Operation(out_date.days, Interval::NANOS_PER_DAY, @@ -477,11 +445,6 @@ int64_t Timestamp::GetEpochNanoSeconds(timestamp_t timestamp) { return result; } -int64_t Timestamp::GetEpochNanoSeconds(timestamp_ns_t timestamp) { - D_ASSERT(Timestamp::IsFinite(timestamp)); - return timestamp.value; -} - int64_t Timestamp::GetEpochRounded(timestamp_t input, int64_t power_of_ten) { D_ASSERT(Timestamp::IsFinite(input)); // Round away from the epoch. diff --git a/src/duckdb/src/common/types/uuid.cpp b/src/duckdb/src/common/types/uuid.cpp index a0196ae81..eb50f2090 100644 --- a/src/duckdb/src/common/types/uuid.cpp +++ b/src/duckdb/src/common/types/uuid.cpp @@ -97,17 +97,6 @@ hugeint_t UUID::FromUHugeint(uhugeint_t input) { return result; } -uhugeint_t UUID::ToUHugeint(hugeint_t input) { - uhugeint_t result; - result.lower = input.lower; - if (input.upper >= 0) { - result.upper = uint64_t(input.upper) + uint64_t(NumericLimits::Maximum()) + 1; - } else { - result.upper = uint64_t(input.upper + NumericLimits::Maximum() + 1); - } - return result; -} - hugeint_t UUID::GenerateRandomUUID(RandomEngine &engine) { uint8_t bytes[16]; for (int i = 0; i < 16; i += 4) { diff --git a/src/duckdb/src/common/types/validity_mask.cpp b/src/duckdb/src/common/types/validity_mask.cpp index c4a526b59..fac6fea4b 100644 --- a/src/duckdb/src/common/types/validity_mask.cpp +++ b/src/duckdb/src/common/types/validity_mask.cpp @@ -51,18 +51,11 @@ string ValidityMask::ToString(idx_t count) const { result += "]"; return result; } - -string ValidityMask::ToString() const { - return ValidityMask::ToString(capacity); -} // LCOV_EXCL_STOP -void ValidityMask::Resize(idx_t new_size) { - idx_t old_size = capacity; - if (new_size <= old_size) { - return; - } - capacity = new_size; +void ValidityMask::Resize(idx_t old_size, idx_t new_size) { + D_ASSERT(new_size >= old_size); + target_count = new_size; if (validity_mask) { auto new_size_count = EntryCount(new_size); auto old_size_count = EntryCount(old_size); @@ -79,8 +72,8 @@ void ValidityMask::Resize(idx_t new_size) { } } -idx_t ValidityMask::Capacity() const { - return capacity; +idx_t ValidityMask::TargetCount() const { + return target_count; } void ValidityMask::Slice(const ValidityMask &other, idx_t source_offset, idx_t count) { @@ -121,10 +114,6 @@ void ValidityMask::CopySel(const ValidityMask &other, const SelectionVector &sel } void ValidityMask::SliceInPlace(const ValidityMask &other, idx_t target_offset, idx_t source_offset, idx_t count) { - if (AllValid() && other.AllValid()) { - // Both validity masks are uninitialized, nothing to do - return; - } EnsureWritable(); const idx_t ragged = count % BITS_PER_VALUE; const idx_t entire_units = count / BITS_PER_VALUE; diff --git a/src/duckdb/src/common/types/value.cpp b/src/duckdb/src/common/types/value.cpp index 4e8566c9a..5d893b6c2 100644 --- a/src/duckdb/src/common/types/value.cpp +++ b/src/duckdb/src/common/types/value.cpp @@ -1,8 +1,11 @@ #include "duckdb/common/types/value.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/to_string.hpp" #include "duckdb/common/limits.hpp" +#include "duckdb/common/operator/aggregate_operators.hpp" #include "duckdb/common/operator/cast_operators.hpp" +#include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/uhugeint.hpp" #include "utf8proc_wrapper.hpp" @@ -14,6 +17,7 @@ #include "duckdb/common/types/hugeint.hpp" #include "duckdb/common/types/uuid.hpp" #include "duckdb/common/types/interval.hpp" +#include "duckdb/common/types/null_value.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/types/bit.hpp" @@ -22,6 +26,7 @@ #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/cast_helpers.hpp" +#include "duckdb/common/types/hash.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/main/error_manager.hpp" #include "duckdb/common/types/varint.hpp" @@ -222,37 +227,32 @@ Value Value::MinimumValue(const LogicalType &type) { return Value::DATE(Date::FromDate(Date::DATE_MIN_YEAR, Date::DATE_MIN_MONTH, Date::DATE_MIN_DAY)); case LogicalTypeId::TIME: return Value::TIME(dtime_t(0)); - case LogicalTypeId::TIMESTAMP: { - const auto date = Date::FromDate(Timestamp::MIN_YEAR, Timestamp::MIN_MONTH, Timestamp::MIN_DAY); - return Value::TIMESTAMP(date, dtime_t(0)); - } + case LogicalTypeId::TIMESTAMP: + return Value::TIMESTAMP(Date::FromDate(Timestamp::MIN_YEAR, Timestamp::MIN_MONTH, Timestamp::MIN_DAY), + dtime_t(0)); case LogicalTypeId::TIMESTAMP_SEC: { - // Get the minimum timestamp and cast it to timestamp_sec_t. - const auto min_ts = MinimumValue(LogicalType::TIMESTAMP).GetValue(); - const auto ts = Cast::Operation(min_ts); - return Value::TIMESTAMPSEC(ts); + // Casting rounds up, which will overflow + const auto min_us = MinimumValue(LogicalType::TIMESTAMP).GetValue(); + return Value::TIMESTAMPSEC(timestamp_t(Timestamp::GetEpochSeconds(min_us))); } case LogicalTypeId::TIMESTAMP_MS: { - // Get the minimum timestamp and cast it to timestamp_ms_t. - const auto min_ts = MinimumValue(LogicalType::TIMESTAMP).GetValue(); - const auto ts = Cast::Operation(min_ts); - return Value::TIMESTAMPMS(ts); + // Casting rounds up, which will overflow + const auto min_us = MinimumValue(LogicalType::TIMESTAMP).GetValue(); + return Value::TIMESTAMPMS(timestamp_t(Timestamp::GetEpochMs(min_us))); } case LogicalTypeId::TIMESTAMP_NS: { // Clear the fractional day. auto min_ns = NumericLimits::Minimum(); min_ns /= Interval::NANOS_PER_DAY; min_ns *= Interval::NANOS_PER_DAY; - return Value::TIMESTAMPNS(timestamp_ns_t(min_ns)); + return Value::TIMESTAMPNS(timestamp_t(min_ns)); } case LogicalTypeId::TIME_TZ: // "00:00:00+1559" from the PG docs, but actually 00:00:00+15:59:59 return Value::TIMETZ(dtime_tz_t(dtime_t(0), dtime_tz_t::MAX_OFFSET)); - case LogicalTypeId::TIMESTAMP_TZ: { - const auto date = Date::FromDate(Timestamp::MIN_YEAR, Timestamp::MIN_MONTH, Timestamp::MIN_DAY); - const auto ts = Timestamp::FromDatetime(date, dtime_t(0)); - return Value::TIMESTAMPTZ(timestamp_tz_t(ts)); - } + case LogicalTypeId::TIMESTAMP_TZ: + return Value::TIMESTAMPTZ(Timestamp::FromDatetime( + Date::FromDate(Timestamp::MIN_YEAR, Timestamp::MIN_MONTH, Timestamp::MIN_DAY), dtime_t(0))); case LogicalTypeId::FLOAT: return Value::FLOAT(NumericLimits::Minimum()); case LogicalTypeId::DOUBLE: @@ -319,27 +319,23 @@ Value Value::MaximumValue(const LogicalType &type) { return Value::TIME(dtime_t(Interval::MICROS_PER_DAY)); case LogicalTypeId::TIMESTAMP: return Value::TIMESTAMP(timestamp_t(NumericLimits::Maximum() - 1)); - case LogicalTypeId::TIMESTAMP_SEC: { - // Get the maximum timestamp and cast it to timestamp_s_t. - const auto max_ts = MaximumValue(LogicalType::TIMESTAMP).GetValue(); - const auto ts = Cast::Operation(max_ts); - return Value::TIMESTAMPSEC(ts); - } case LogicalTypeId::TIMESTAMP_MS: { - // Get the maximum timestamp and cast it to timestamp_ms_t. - const auto max_ts = MaximumValue(LogicalType::TIMESTAMP).GetValue(); - const auto ts = Cast::Operation(max_ts); - return Value::TIMESTAMPMS(ts); + // Casting rounds up, which will overflow + const auto max_us = MaximumValue(LogicalType::TIMESTAMP).GetValue(); + return Value::TIMESTAMPMS(timestamp_t(Timestamp::GetEpochMs(max_us))); } - case LogicalTypeId::TIMESTAMP_NS: { - const auto ts = timestamp_ns_t(NumericLimits::Maximum() - 1); - return Value::TIMESTAMPNS(ts); + case LogicalTypeId::TIMESTAMP_NS: + return Value::TIMESTAMPNS(timestamp_t(NumericLimits::Maximum() - 1)); + case LogicalTypeId::TIMESTAMP_SEC: { + // Casting rounds up, which will overflow + const auto max_us = MaximumValue(LogicalType::TIMESTAMP).GetValue(); + return Value::TIMESTAMPSEC(timestamp_t(Timestamp::GetEpochSeconds(max_us))); } - case LogicalTypeId::TIMESTAMP_TZ: - return Value::TIMESTAMPTZ(timestamp_tz_t(NumericLimits::Maximum() - 1)); case LogicalTypeId::TIME_TZ: - // "24:00:00-1559" from the PG docs but actually "24:00:00-15:59:59". + // "24:00:00-1559" from the PG docs but actually "24:00:00-15:59:59" return Value::TIMETZ(dtime_tz_t(dtime_t(Interval::MICROS_PER_DAY), dtime_tz_t::MIN_OFFSET)); + case LogicalTypeId::TIMESTAMP_TZ: + return MaximumValue(LogicalType::TIMESTAMP); case LogicalTypeId::FLOAT: return Value::FLOAT(NumericLimits::Maximum()); case LogicalTypeId::DOUBLE: @@ -380,14 +376,14 @@ Value Value::Infinity(const LogicalType &type) { return Value::DATE(date_t::infinity()); case LogicalTypeId::TIMESTAMP: return Value::TIMESTAMP(timestamp_t::infinity()); - case LogicalTypeId::TIMESTAMP_SEC: - return Value::TIMESTAMPSEC(timestamp_sec_t(timestamp_t::infinity().value)); case LogicalTypeId::TIMESTAMP_MS: - return Value::TIMESTAMPMS(timestamp_ms_t(timestamp_t::infinity().value)); + return Value::TIMESTAMPMS(timestamp_t::infinity()); case LogicalTypeId::TIMESTAMP_NS: - return Value::TIMESTAMPNS(timestamp_ns_t(timestamp_t::infinity().value)); + return Value::TIMESTAMPNS(timestamp_t::infinity()); + case LogicalTypeId::TIMESTAMP_SEC: + return Value::TIMESTAMPSEC(timestamp_t::infinity()); case LogicalTypeId::TIMESTAMP_TZ: - return Value::TIMESTAMPTZ(timestamp_tz_t(timestamp_t::infinity())); + return Value::TIMESTAMPTZ(timestamp_t::infinity()); case LogicalTypeId::FLOAT: return Value::FLOAT(std::numeric_limits::infinity()); case LogicalTypeId::DOUBLE: @@ -403,14 +399,14 @@ Value Value::NegativeInfinity(const LogicalType &type) { return Value::DATE(date_t::ninfinity()); case LogicalTypeId::TIMESTAMP: return Value::TIMESTAMP(timestamp_t::ninfinity()); - case LogicalTypeId::TIMESTAMP_SEC: - return Value::TIMESTAMPSEC(timestamp_sec_t(timestamp_t::ninfinity().value)); case LogicalTypeId::TIMESTAMP_MS: - return Value::TIMESTAMPMS(timestamp_ms_t(timestamp_t::ninfinity().value)); + return Value::TIMESTAMPMS(timestamp_t::ninfinity()); case LogicalTypeId::TIMESTAMP_NS: - return Value::TIMESTAMPNS(timestamp_ns_t(timestamp_t::ninfinity().value)); + return Value::TIMESTAMPNS(timestamp_t::ninfinity()); + case LogicalTypeId::TIMESTAMP_SEC: + return Value::TIMESTAMPSEC(timestamp_t::ninfinity()); case LogicalTypeId::TIMESTAMP_TZ: - return Value::TIMESTAMPTZ(timestamp_tz_t(timestamp_t::ninfinity())); + return Value::TIMESTAMPTZ(timestamp_t::ninfinity()); case LogicalTypeId::FLOAT: return Value::FLOAT(-std::numeric_limits::infinity()); case LogicalTypeId::DOUBLE: @@ -549,26 +545,6 @@ bool Value::IsFinite(timestamp_t input) { return Timestamp::IsFinite(input); } -template <> -bool Value::IsFinite(timestamp_sec_t input) { - return Timestamp::IsFinite(input); -} - -template <> -bool Value::IsFinite(timestamp_ms_t input) { - return Timestamp::IsFinite(input); -} - -template <> -bool Value::IsFinite(timestamp_ns_t input) { - return Timestamp::IsFinite(input); -} - -template <> -bool Value::IsFinite(timestamp_tz_t input) { - return Timestamp::IsFinite(input); -} - bool Value::StringIsValid(const char *str, idx_t length) { auto utf_type = Utf8Proc::Analyze(str, length); return utf_type != UnicodeType::INVALID; @@ -676,30 +652,30 @@ Value Value::TIMESTAMP(timestamp_t value) { return result; } -Value Value::TIMESTAMPSEC(timestamp_sec_t timestamp) { - Value result(LogicalType::TIMESTAMP_S); - result.value_.timestamp_s = timestamp; +Value Value::TIMESTAMPTZ(timestamp_t value) { + Value result(LogicalType::TIMESTAMP_TZ); + result.value_.timestamp = value; result.is_null = false; return result; } -Value Value::TIMESTAMPMS(timestamp_ms_t timestamp) { - Value result(LogicalType::TIMESTAMP_MS); - result.value_.timestamp_ms = timestamp; +Value Value::TIMESTAMPNS(timestamp_t timestamp) { + Value result(LogicalType::TIMESTAMP_NS); + result.value_.timestamp = timestamp; result.is_null = false; return result; } -Value Value::TIMESTAMPNS(timestamp_ns_t timestamp) { - Value result(LogicalType::TIMESTAMP_NS); - result.value_.timestamp_ns = timestamp; +Value Value::TIMESTAMPMS(timestamp_t timestamp) { + Value result(LogicalType::TIMESTAMP_MS); + result.value_.timestamp = timestamp; result.is_null = false; return result; } -Value Value::TIMESTAMPTZ(timestamp_tz_t value) { - Value result(LogicalType::TIMESTAMP_TZ); - result.value_.timestamp_tz = value; +Value Value::TIMESTAMPSEC(timestamp_t timestamp) { + Value result(LogicalType::TIMESTAMP_S); + result.value_.timestamp = timestamp; result.is_null = false; return result; } @@ -710,9 +686,7 @@ Value Value::TIMESTAMP(date_t date, dtime_t time) { Value Value::TIMESTAMP(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t micros) { - auto date = Date::FromDate(year, month, day); - auto time = Time::FromTime(hour, min, sec, micros); - auto val = Value::TIMESTAMP(date, time); + auto val = Value::TIMESTAMP(Date::FromDate(year, month, day), Time::FromTime(hour, min, sec, micros)); val.type_ = LogicalType::TIMESTAMP; return val; } @@ -728,7 +702,6 @@ Value Value::STRUCT(const LogicalType &type, vector struct_values) { result.is_null = false; return result; } - Value Value::STRUCT(child_list_t values) { child_list_t child_types; vector struct_values; @@ -739,37 +712,16 @@ Value Value::STRUCT(child_list_t values) { return Value::STRUCT(LogicalType::STRUCT(child_types), std::move(struct_values)); } -void MapKeyCheck(unordered_set &unique_keys, const Value &key) { - // NULL key check. - if (key.IsNull()) { - MapVector::EvalMapInvalidReason(MapInvalidReason::NULL_KEY); - } - - // Duplicate key check. - auto key_hash = key.Hash(); - if (unique_keys.find(key_hash) != unique_keys.end()) { - MapVector::EvalMapInvalidReason(MapInvalidReason::DUPLICATE_KEY); - } - unique_keys.insert(key_hash); -} - Value Value::MAP(const LogicalType &child_type, vector values) { // NOLINT vector map_keys; vector map_values; - unordered_set unique_keys; - for (auto &val : values) { D_ASSERT(val.type().InternalType() == PhysicalType::STRUCT); auto &children = StructValue::GetChildren(val); D_ASSERT(children.size() == 2); - - auto &key = children[0]; - MapKeyCheck(unique_keys, key); - - map_keys.push_back(key); + map_keys.push_back(children[0]); map_values.push_back(children[1]); } - auto &key_type = StructType::GetChildType(child_type, 0); auto &value_type = StructType::GetChildType(child_type, 1); return Value::MAP(key_type, value_type, std::move(map_keys), std::move(map_values)); @@ -781,26 +733,13 @@ Value Value::MAP(const LogicalType &key_type, const LogicalType &value_type, vec result.type_ = LogicalType::MAP(key_type, value_type); result.is_null = false; - unordered_set unique_keys; - for (idx_t i = 0; i < keys.size(); i++) { - child_list_t struct_types; - vector new_children; - struct_types.reserve(2); + child_list_t new_children; new_children.reserve(2); - - struct_types.push_back(make_pair("key", key_type)); - struct_types.push_back(make_pair("value", value_type)); - - auto key = keys[i].DefaultCastAs(key_type); - MapKeyCheck(unique_keys, key); - - new_children.push_back(key); - new_children.push_back(values[i]); - auto struct_type = LogicalType::STRUCT(std::move(struct_types)); - values[i] = Value::STRUCT(struct_type, std::move(new_children)); + new_children.push_back(std::make_pair("key", std::move(keys[i]))); + new_children.push_back(std::make_pair("value", std::move(values[i]))); + values[i] = Value::STRUCT(std::move(new_children)); } - result.value_info_ = make_shared_ptr(std::move(values)); return result; } @@ -842,33 +781,72 @@ Value Value::UNION(child_list_t members, uint8_t tag, Value value) return result; } -Value Value::LIST(const LogicalType &child_type, vector values) { +Value Value::LIST(vector values) { + if (values.empty()) { + throw InternalException("Value::LIST without providing a child-type requires a non-empty list of values. Use " + "Value::LIST(child_type, list) instead."); + } +#ifdef DEBUG + for (idx_t i = 1; i < values.size(); i++) { + D_ASSERT(values[i].type() == values[0].type()); + } +#endif Value result; - result.type_ = LogicalType::LIST(child_type); + result.type_ = LogicalType::LIST(values[0].type()); + result.value_info_ = make_shared_ptr(std::move(values)); result.is_null = false; + return result; +} + +Value Value::LIST(const LogicalType &child_type, vector values) { + if (values.empty()) { + return Value::EMPTYLIST(child_type); + } for (auto &val : values) { val = val.DefaultCastAs(child_type); } - result.value_info_ = make_shared_ptr(std::move(values)); + return Value::LIST(std::move(values)); +} + +Value Value::EMPTYLIST(const LogicalType &child_type) { + Value result; + result.type_ = LogicalType::LIST(child_type); + result.value_info_ = make_shared_ptr(); + result.is_null = false; return result; } -Value Value::LIST(vector values) { +Value Value::ARRAY(vector values) { if (values.empty()) { - throw InternalException( - "Value::LIST(values) cannot be used to make an empty list - use Value::LIST(type, values) instead"); + throw InternalException("Value::ARRAY without providing a child-type requires a non-empty list of values. Use " + "Value::ARRAY(child_type, list) instead."); } - auto &type = values[0].type(); - return Value::LIST(type, std::move(values)); +#ifdef DEBUG + for (idx_t i = 1; i < values.size(); i++) { + D_ASSERT(values[i].type() == values[0].type()); + } +#endif + Value result; + result.type_ = LogicalType::ARRAY(values[0].type(), values.size()); + result.value_info_ = make_shared_ptr(std::move(values)); + result.is_null = false; + return result; } Value Value::ARRAY(const LogicalType &child_type, vector values) { - Value result; - result.type_ = LogicalType::ARRAY(child_type, values.size()); + if (values.empty()) { + return Value::EMPTYARRAY(child_type, 0); + } for (auto &val : values) { val = val.DefaultCastAs(child_type); } - result.value_info_ = make_shared_ptr(std::move(values)); + return Value::ARRAY(std::move(values)); +} + +Value Value::EMPTYARRAY(const LogicalType &child_type, uint32_t size) { + Value result; + result.type_ = LogicalType::ARRAY(child_type, size); + result.value_info_ = make_shared_ptr(); result.is_null = false; return result; } @@ -1116,21 +1094,17 @@ T Value::GetValueInternal() const { case LogicalTypeId::TIME_TZ: return Cast::Operation(value_.timetz); case LogicalTypeId::TIMESTAMP: - return Cast::Operation(value_.timestamp); - case LogicalTypeId::TIMESTAMP_SEC: - return Cast::Operation(value_.timestamp_s); - case LogicalTypeId::TIMESTAMP_MS: - return Cast::Operation(value_.timestamp_ms); - case LogicalTypeId::TIMESTAMP_NS: - return Cast::Operation(value_.timestamp_ns); case LogicalTypeId::TIMESTAMP_TZ: - return Cast::Operation(value_.timestamp_tz); + return Cast::Operation(value_.timestamp); case LogicalTypeId::UTINYINT: return Cast::Operation(value_.utinyint); case LogicalTypeId::USMALLINT: return Cast::Operation(value_.usmallint); case LogicalTypeId::UINTEGER: return Cast::Operation(value_.uinteger); + case LogicalTypeId::TIMESTAMP_MS: + case LogicalTypeId::TIMESTAMP_NS: + case LogicalTypeId::TIMESTAMP_SEC: case LogicalTypeId::UBIGINT: return Cast::Operation(value_.ubigint); case LogicalTypeId::FLOAT: @@ -1186,16 +1160,11 @@ int64_t Value::GetValue() const { } switch (type_.id()) { case LogicalTypeId::TIMESTAMP: - return value_.timestamp.value; case LogicalTypeId::TIMESTAMP_SEC: - return value_.timestamp_s.value; - case LogicalTypeId::TIMESTAMP_MS: - return value_.timestamp_ms.value; case LogicalTypeId::TIMESTAMP_NS: - return value_.timestamp_ns.value; - case LogicalTypeId::TIMESTAMP_TZ: - return value_.timestamp_tz.value; + case LogicalTypeId::TIMESTAMP_MS: case LogicalTypeId::TIME: + case LogicalTypeId::TIMESTAMP_TZ: return value_.bigint; default: return GetValueInternal(); @@ -1245,32 +1214,10 @@ template <> dtime_t Value::GetValue() const { return GetValueInternal(); } - template <> timestamp_t Value::GetValue() const { return GetValueInternal(); } - -template <> -timestamp_sec_t Value::GetValue() const { - return GetValueInternal(); -} - -template <> -timestamp_ms_t Value::GetValue() const { - return GetValueInternal(); -} - -template <> -timestamp_ns_t Value::GetValue() const { - return GetValueInternal(); -} - -template <> -timestamp_tz_t Value::GetValue() const { - return GetValueInternal(); -} - template <> dtime_tz_t Value::GetValue() const { return GetValueInternal(); @@ -1338,14 +1285,14 @@ Value Value::Numeric(const LogicalType &type, int64_t value) { return Value::TIME(dtime_t(value)); case LogicalTypeId::TIMESTAMP: return Value::TIMESTAMP(timestamp_t(value)); - case LogicalTypeId::TIMESTAMP_SEC: - return Value::TIMESTAMPSEC(timestamp_sec_t(value)); - case LogicalTypeId::TIMESTAMP_MS: - return Value::TIMESTAMPMS(timestamp_ms_t(value)); case LogicalTypeId::TIMESTAMP_NS: - return Value::TIMESTAMPNS(timestamp_ns_t(value)); + return Value::TIMESTAMPNS(timestamp_t(value)); + case LogicalTypeId::TIMESTAMP_MS: + return Value::TIMESTAMPMS(timestamp_t(value)); + case LogicalTypeId::TIMESTAMP_SEC: + return Value::TIMESTAMPSEC(timestamp_t(value)); case LogicalTypeId::TIMESTAMP_TZ: - return Value::TIMESTAMPTZ(timestamp_tz_t(value)); + return Value::TIMESTAMPTZ(timestamp_t(value)); case LogicalTypeId::ENUM: switch (type.InternalType()) { case PhysicalType::UINT8: @@ -1510,30 +1457,6 @@ timestamp_t Value::GetValueUnsafe() const { return value_.timestamp; } -template <> -timestamp_sec_t Value::GetValueUnsafe() const { - D_ASSERT(type_.InternalType() == PhysicalType::INT64); - return value_.timestamp_s; -} - -template <> -timestamp_ms_t Value::GetValueUnsafe() const { - D_ASSERT(type_.InternalType() == PhysicalType::INT64); - return value_.timestamp_ms; -} - -template <> -timestamp_ns_t Value::GetValueUnsafe() const { - D_ASSERT(type_.InternalType() == PhysicalType::INT64); - return value_.timestamp_ns; -} - -template <> -timestamp_tz_t Value::GetValueUnsafe() const { - D_ASSERT(type_.InternalType() == PhysicalType::INT64); - return value_.timestamp_tz; -} - template <> interval_t Value::GetValueUnsafe() const { D_ASSERT(type_.InternalType() == PhysicalType::INTERVAL); @@ -1548,7 +1471,7 @@ hash_t Value::Hash() const { return 0; } Vector input(*this); - Vector result(LogicalType::HASH, 1); + Vector result(LogicalType::HASH); VectorOperations::Hash(input, result, 1); auto data = FlatVector::GetData(result); @@ -1580,13 +1503,8 @@ string Value::ToSQLString() const { case LogicalTypeId::BLOB: return "'" + ToString() + "'::" + type_.ToString(); case LogicalTypeId::VARCHAR: - case LogicalTypeId::ENUM: { - auto str_val = ToString(); - if (str_val.size() == 1 && str_val[0] == '\0') { - return "chr(0)"; - } + case LogicalTypeId::ENUM: return "'" + StringUtil::Replace(ToString(), "'", "''") + "'"; - } case LogicalTypeId::STRUCT: { bool is_unnamed = StructType::IsUnnamed(type_); string ret = is_unnamed ? "(" : "{"; @@ -1730,22 +1648,6 @@ timestamp_t TimestampValue::Get(const Value &value) { return value.GetValueUnsafe(); } -timestamp_sec_t TimestampSValue::Get(const Value &value) { - return value.GetValueUnsafe(); -} - -timestamp_ms_t TimestampMSValue::Get(const Value &value) { - return value.GetValueUnsafe(); -} - -timestamp_ns_t TimestampNSValue::Get(const Value &value) { - return value.GetValueUnsafe(); -} - -timestamp_tz_t TimestampTZValue::Get(const Value &value) { - return value.GetValueUnsafe(); -} - interval_t IntervalValue::Get(const Value &value) { return value.GetValueUnsafe(); } @@ -1915,9 +1817,6 @@ bool Value::DefaultTryCastAs(const LogicalType &target_type, Value &new_value, s Value Value::CastAs(CastFunctionSet &set, GetCastFunctionInput &get_input, const LogicalType &target_type, bool strict) const { - if (target_type.id() == LogicalTypeId::ANY) { - return *this; - } Value new_value; string error_message; if (!TryCastAs(set, get_input, target_type, new_value, &error_message, strict)) { @@ -1966,136 +1865,89 @@ void Value::Reinterpret(LogicalType new_type) { this->type_ = std::move(new_type); } -const LogicalType &GetChildType(const LogicalType &parent_type, idx_t i) { - switch (parent_type.InternalType()) { - case PhysicalType::LIST: - return ListType::GetChildType(parent_type); - case PhysicalType::STRUCT: - return StructType::GetChildType(parent_type, i); - case PhysicalType::ARRAY: - return ArrayType::GetChildType(parent_type); - default: - throw InternalException("Parent type is not a nested type"); - } -} - -bool SerializeTypeMatches(const LogicalType &expected_type, const LogicalType &actual_type) { - if (expected_type.id() != actual_type.id()) { - // type id needs to be the same - return false; - } - if (expected_type.IsNested()) { - // for nested types that is enough - we will recurse into the children and check there again anyway - return true; - } - // otherwise we do a deep comparison of the type (e.g. decimal flags need to be consistent) - return expected_type == actual_type; -} - -void Value::SerializeChildren(Serializer &serializer, const vector &children, const LogicalType &parent_type) { - serializer.WriteObject(102, "value", [&](Serializer &child_serializer) { - child_serializer.WriteList(100, "children", children.size(), [&](Serializer::List &list, idx_t i) { - auto &value_type = GetChildType(parent_type, i); - bool serialize_type = value_type.InternalType() == PhysicalType::INVALID; - if (!serialize_type && !SerializeTypeMatches(value_type, children[i].type())) { - throw InternalException("Error when serializing type - serializing a child of a nested value with type " - "%s, but expected type %s", - children[i].type(), value_type); +void Value::Serialize(Serializer &serializer) const { + serializer.WriteProperty(100, "type", type_); + serializer.WriteProperty(101, "is_null", is_null); + if (!IsNull()) { + switch (type_.InternalType()) { + case PhysicalType::BIT: + throw InternalException("BIT type should not be serialized"); + case PhysicalType::BOOL: + serializer.WriteProperty(102, "value", value_.boolean); + break; + case PhysicalType::INT8: + serializer.WriteProperty(102, "value", value_.tinyint); + break; + case PhysicalType::INT16: + serializer.WriteProperty(102, "value", value_.smallint); + break; + case PhysicalType::INT32: + serializer.WriteProperty(102, "value", value_.integer); + break; + case PhysicalType::INT64: + serializer.WriteProperty(102, "value", value_.bigint); + break; + case PhysicalType::UINT8: + serializer.WriteProperty(102, "value", value_.utinyint); + break; + case PhysicalType::UINT16: + serializer.WriteProperty(102, "value", value_.usmallint); + break; + case PhysicalType::UINT32: + serializer.WriteProperty(102, "value", value_.uinteger); + break; + case PhysicalType::UINT64: + serializer.WriteProperty(102, "value", value_.ubigint); + break; + case PhysicalType::INT128: + serializer.WriteProperty(102, "value", value_.hugeint); + break; + case PhysicalType::UINT128: + serializer.WriteProperty(102, "value", value_.uhugeint); + break; + case PhysicalType::FLOAT: + serializer.WriteProperty(102, "value", value_.float_); + break; + case PhysicalType::DOUBLE: + serializer.WriteProperty(102, "value", value_.double_); + break; + case PhysicalType::INTERVAL: + serializer.WriteProperty(102, "value", value_.interval); + break; + case PhysicalType::VARCHAR: { + if (type_.id() == LogicalTypeId::BLOB) { + auto blob_str = Blob::ToString(StringValue::Get(*this)); + serializer.WriteProperty(102, "value", blob_str); + } else { + serializer.WriteProperty(102, "value", StringValue::Get(*this)); } - list.WriteObject([&](Serializer &element_serializer) { - children[i].SerializeInternal(element_serializer, serialize_type); + } break; + case PhysicalType::LIST: { + serializer.WriteObject(102, "value", [&](Serializer &serializer) { + auto &children = ListValue::GetChildren(*this); + serializer.WriteProperty(100, "children", children); }); - }); - }); -} - -void Value::SerializeInternal(Serializer &serializer, bool serialize_type) const { - if (serialize_type || !serializer.ShouldSerialize(4)) { - // only the root value needs to serialize its type - // for forwards compatibility reasons, we also serialize the type always when targeting versions < v1.2.0 - serializer.WriteProperty(100, "type", type_); - } - serializer.WriteProperty(101, "is_null", is_null); - if (IsNull()) { - return; - } - switch (type_.InternalType()) { - case PhysicalType::BIT: - throw InternalException("BIT type should not be serialized"); - case PhysicalType::BOOL: - serializer.WriteProperty(102, "value", value_.boolean); - break; - case PhysicalType::INT8: - serializer.WriteProperty(102, "value", value_.tinyint); - break; - case PhysicalType::INT16: - serializer.WriteProperty(102, "value", value_.smallint); - break; - case PhysicalType::INT32: - serializer.WriteProperty(102, "value", value_.integer); - break; - case PhysicalType::INT64: - serializer.WriteProperty(102, "value", value_.bigint); - break; - case PhysicalType::UINT8: - serializer.WriteProperty(102, "value", value_.utinyint); - break; - case PhysicalType::UINT16: - serializer.WriteProperty(102, "value", value_.usmallint); - break; - case PhysicalType::UINT32: - serializer.WriteProperty(102, "value", value_.uinteger); - break; - case PhysicalType::UINT64: - serializer.WriteProperty(102, "value", value_.ubigint); - break; - case PhysicalType::INT128: - serializer.WriteProperty(102, "value", value_.hugeint); - break; - case PhysicalType::UINT128: - serializer.WriteProperty(102, "value", value_.uhugeint); - break; - case PhysicalType::FLOAT: - serializer.WriteProperty(102, "value", value_.float_); - break; - case PhysicalType::DOUBLE: - serializer.WriteProperty(102, "value", value_.double_); - break; - case PhysicalType::INTERVAL: - serializer.WriteProperty(102, "value", value_.interval); - break; - case PhysicalType::VARCHAR: { - if (type_.id() == LogicalTypeId::BLOB) { - auto blob_str = Blob::ToString(StringValue::Get(*this)); - serializer.WriteProperty(102, "value", blob_str); - } else { - serializer.WriteProperty(102, "value", StringValue::Get(*this)); + } break; + case PhysicalType::STRUCT: { + serializer.WriteObject(102, "value", [&](Serializer &serializer) { + auto &children = StructValue::GetChildren(*this); + serializer.WriteProperty(100, "children", children); + }); + } break; + case PhysicalType::ARRAY: { + serializer.WriteObject(102, "value", [&](Serializer &serializer) { + auto &children = ArrayValue::GetChildren(*this); + serializer.WriteProperty(100, "children", children); + }); + } break; + default: + throw NotImplementedException("Unimplemented type for Serialize"); } - } break; - case PhysicalType::LIST: - SerializeChildren(serializer, ListValue::GetChildren(*this), type_); - break; - case PhysicalType::STRUCT: - SerializeChildren(serializer, StructValue::GetChildren(*this), type_); - break; - case PhysicalType::ARRAY: - SerializeChildren(serializer, ArrayValue::GetChildren(*this), type_); - break; - default: - throw NotImplementedException("Unimplemented type for Serialize"); } } -void Value::Serialize(Serializer &serializer) const { - // serialize the value - the top-level value always needs to serialize its type - SerializeInternal(serializer, true); -} - Value Value::Deserialize(Deserializer &deserializer) { - auto type = deserializer.ReadPropertyWithExplicitDefault(100, "type", LogicalTypeId::INVALID); - if (type.InternalType() == PhysicalType::INVALID) { - type = deserializer.Get(); - } + auto type = deserializer.ReadProperty(100, "type"); auto is_null = deserializer.ReadProperty(101, "is_null"); Value new_value = Value(type); if (is_null) { @@ -2156,32 +2008,22 @@ Value Value::Deserialize(Deserializer &deserializer) { } } break; case PhysicalType::LIST: { - deserializer.Set(ListType::GetChildType(type)); deserializer.ReadObject(102, "value", [&](Deserializer &obj) { auto children = obj.ReadProperty>(100, "children"); new_value.value_info_ = make_shared_ptr(children); }); - deserializer.Unset(); } break; case PhysicalType::STRUCT: { deserializer.ReadObject(102, "value", [&](Deserializer &obj) { - vector children; - obj.ReadList(100, "children", [&](Deserializer::List &list, idx_t i) { - deserializer.Set(StructType::GetChildType(type, i)); - auto child = list.ReadElement(); - deserializer.Unset(); - children.push_back(std::move(child)); - }); + auto children = obj.ReadProperty>(100, "children"); new_value.value_info_ = make_shared_ptr(children); }); } break; case PhysicalType::ARRAY: { - deserializer.Set(ArrayType::GetChildType(type)); deserializer.ReadObject(102, "value", [&](Deserializer &obj) { auto children = obj.ReadProperty>(100, "children"); new_value.value_info_ = make_shared_ptr(children); }); - deserializer.Unset(); } break; default: throw NotImplementedException("Unimplemented type for Deserialize"); diff --git a/src/duckdb/src/common/types/varint.cpp b/src/duckdb/src/common/types/varint.cpp index b92ded113..121b9a3cd 100644 --- a/src/duckdb/src/common/types/varint.cpp +++ b/src/duckdb/src/common/types/varint.cpp @@ -168,22 +168,6 @@ void Varint::GetByteArray(vector &byte_array, bool &is_negative, const } } -string Varint::FromByteArray(uint8_t *data, idx_t size, bool is_negative) { - string result(VARINT_HEADER_SIZE + size, '0'); - SetHeader(&result[0], size, is_negative); - uint8_t *result_data = reinterpret_cast(&result[VARINT_HEADER_SIZE]); - if (is_negative) { - for (idx_t i = 0; i < size; i++) { - result_data[i] = ~data[i]; - } - } else { - for (idx_t i = 0; i < size; i++) { - result_data[i] = data[i]; - } - } - return result; -} - string Varint::VarIntToVarchar(const string_t &blob) { string decimal_string; vector byte_array; diff --git a/src/duckdb/src/common/types/vector.cpp b/src/duckdb/src/common/types/vector.cpp index 722b8b699..29e0a9551 100644 --- a/src/duckdb/src/common/types/vector.cpp +++ b/src/duckdb/src/common/types/vector.cpp @@ -15,7 +15,6 @@ #include "duckdb/common/types/sel_cache.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/common/types/value_map.hpp" -#include "duckdb/common/types/varint.hpp" #include "duckdb/common/types/vector_cache.hpp" #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" @@ -23,6 +22,7 @@ #include "duckdb/storage/buffer/buffer_handle.hpp" #include "duckdb/storage/string_uncompressed.hpp" #include "fsst.h" +#include "duckdb/common/types/varint.hpp" #include // strlen() on Solaris @@ -54,10 +54,10 @@ UnifiedVectorFormat &UnifiedVectorFormat::operator=(UnifiedVectorFormat &&other) return *this; } -Vector::Vector(LogicalType type_p, bool create_data, bool initialize_to_zero, idx_t capacity) +Vector::Vector(LogicalType type_p, bool create_data, bool zero_data, idx_t capacity) : vector_type(VectorType::FLAT_VECTOR), type(std::move(type_p)), data(nullptr), validity(capacity) { if (create_data) { - Initialize(initialize_to_zero, capacity); + Initialize(zero_data, capacity); } } @@ -231,8 +231,6 @@ void Vector::Slice(const SelectionVector &sel, idx_t count) { if (GetVectorType() == VectorType::DICTIONARY_VECTOR) { // already a dictionary, slice the current dictionary auto ¤t_sel = DictionaryVector::SelVector(*this); - auto dictionary_size = DictionaryVector::DictionarySize(*this); - auto dictionary_id = DictionaryVector::DictionaryId(*this); auto sliced_dictionary = current_sel.Slice(sel, count); buffer = make_buffer(std::move(sliced_dictionary)); if (GetType().InternalType() == PhysicalType::STRUCT) { @@ -242,11 +240,6 @@ void Vector::Slice(const SelectionVector &sel, idx_t count) { new_child.auxiliary = make_buffer(new_child, sel, count); auxiliary = make_buffer(std::move(new_child)); } - if (dictionary_size.IsValid()) { - auto &dict_buffer = buffer->Cast(); - dict_buffer.SetDictionarySize(dictionary_size.GetIndex()); - dict_buffer.SetDictionaryId(std::move(dictionary_id)); - } return; } @@ -267,25 +260,11 @@ void Vector::Slice(const SelectionVector &sel, idx_t count) { auxiliary = std::move(child_ref); } -void Vector::Dictionary(idx_t dictionary_size, const SelectionVector &sel, idx_t count) { - Slice(sel, count); - if (GetVectorType() == VectorType::DICTIONARY_VECTOR) { - buffer->Cast().SetDictionarySize(dictionary_size); - } -} - -void Vector::Dictionary(const Vector &dict, idx_t dictionary_size, const SelectionVector &sel, idx_t count) { - Reference(dict); - Dictionary(dictionary_size, sel, count); -} - void Vector::Slice(const SelectionVector &sel, idx_t count, SelCache &cache) { if (GetVectorType() == VectorType::DICTIONARY_VECTOR && GetType().InternalType() != PhysicalType::STRUCT) { // dictionary vector: need to merge dictionaries // check if we have a cached entry auto ¤t_sel = DictionaryVector::SelVector(*this); - auto dictionary_size = DictionaryVector::DictionarySize(*this); - auto dictionary_id = DictionaryVector::DictionaryId(*this); auto target_data = current_sel.data(); auto entry = cache.cache.find(target_data); if (entry != cache.cache.end()) { @@ -296,17 +275,12 @@ void Vector::Slice(const SelectionVector &sel, idx_t count, SelCache &cache) { Slice(sel, count); cache.cache[target_data] = this->buffer; } - if (dictionary_size.IsValid()) { - auto &dict_buffer = buffer->Cast(); - dict_buffer.SetDictionarySize(dictionary_size.GetIndex()); - dict_buffer.SetDictionaryId(std::move(dictionary_id)); - } } else { Slice(sel, count); } } -void Vector::Initialize(bool initialize_to_zero, idx_t capacity) { +void Vector::Initialize(bool zero_data, idx_t capacity) { auxiliary.reset(); validity.Reset(); auto &type = GetType(); @@ -325,13 +299,13 @@ void Vector::Initialize(bool initialize_to_zero, idx_t capacity) { if (type_size > 0) { buffer = VectorBuffer::CreateStandardVector(type, capacity); data = buffer->GetData(); - if (initialize_to_zero) { + if (zero_data) { memset(data, 0, capacity * type_size); } } - if (capacity > validity.Capacity()) { - validity.Resize(capacity); + if (capacity > validity.TargetCount()) { + validity.Resize(validity.TargetCount(), capacity); } } @@ -388,7 +362,7 @@ void Vector::Resize(idx_t current_size, idx_t new_size) { for (auto &resize_info_entry : resize_infos) { // Resize the validity mask. auto new_validity_size = new_size * resize_info_entry.multiplier; - resize_info_entry.vec.validity.Resize(new_validity_size); + resize_info_entry.vec.validity.Resize(current_size, new_validity_size); // For nested data types, we only need to resize the validity mask. if (!resize_info_entry.data) { @@ -601,16 +575,9 @@ Value Vector::GetValueInternal(const Vector &v_p, idx_t index_p) { auto str_compressed = reinterpret_cast(data)[index]; auto decoder = FSSTVector::GetDecoder(*vector); auto &decompress_buffer = FSSTVector::GetDecompressBuffer(*vector); - auto string_val = FSSTPrimitives::DecompressValue(decoder, str_compressed.GetData(), str_compressed.GetSize(), - decompress_buffer); - switch (vector->GetType().id()) { - case LogicalTypeId::VARCHAR: - return Value(std::move(string_val)); - case LogicalTypeId::BLOB: - return Value::BLOB_RAW(string_val); - default: - throw InternalException("Unsupported vector type for FSST vector"); - } + Value result = FSSTPrimitives::DecompressValue(decoder, str_compressed.GetData(), str_compressed.GetSize(), + decompress_buffer); + return result; } switch (vector->GetType().id()) { @@ -641,13 +608,13 @@ Value Vector::GetValueInternal(const Vector &v_p, idx_t index_p) { case LogicalTypeId::TIMESTAMP: return Value::TIMESTAMP(reinterpret_cast(data)[index]); case LogicalTypeId::TIMESTAMP_NS: - return Value::TIMESTAMPNS(reinterpret_cast(data)[index]); + return Value::TIMESTAMPNS(reinterpret_cast(data)[index]); case LogicalTypeId::TIMESTAMP_MS: - return Value::TIMESTAMPMS(reinterpret_cast(data)[index]); + return Value::TIMESTAMPMS(reinterpret_cast(data)[index]); case LogicalTypeId::TIMESTAMP_SEC: - return Value::TIMESTAMPSEC(reinterpret_cast(data)[index]); + return Value::TIMESTAMPSEC(reinterpret_cast(data)[index]); case LogicalTypeId::TIMESTAMP_TZ: - return Value::TIMESTAMPTZ(reinterpret_cast(data)[index]); + return Value::TIMESTAMPTZ(reinterpret_cast(data)[index]); case LogicalTypeId::HUGEINT: return Value::HUGEINT(reinterpret_cast(data)[index]); case LogicalTypeId::UHUGEINT: @@ -759,7 +726,7 @@ Value Vector::GetValueInternal(const Vector &v_p, idx_t index_p) { for (idx_t i = offset; i < offset + stride; i++) { children.push_back(child_vec.GetValue(i)); } - return Value::ARRAY(ArrayType::GetChildType(type), std::move(children)); + return Value::ARRAY(std::move(children)); } default: throw InternalException("Unimplemented type for value access"); @@ -1302,11 +1269,10 @@ void Vector::Deserialize(Deserializer &deserializer, idx_t count) { auto &logical_type = GetType(); auto &validity = FlatVector::Validity(*this); - auto validity_count = MaxValue(count, STANDARD_VECTOR_SIZE); - validity.Reset(validity_count); + validity.Reset(); const auto has_validity_mask = deserializer.ReadProperty(100, "has_validity_mask"); if (has_validity_mask) { - validity.Initialize(validity_count); + validity.Initialize(MaxValue(count, STANDARD_VECTOR_SIZE)); deserializer.ReadProperty(101, "validity", data_ptr_cast(validity.GetData()), validity.ValidityMaskSize(count)); } @@ -1374,10 +1340,10 @@ void Vector::Deserialize(Deserializer &deserializer, idx_t count) { } void Vector::SetVectorType(VectorType vector_type_p) { - vector_type = vector_type_p; + this->vector_type = vector_type_p; auto physical_type = GetType().InternalType(); - auto flat_or_const = GetVectorType() == VectorType::CONSTANT_VECTOR || GetVectorType() == VectorType::FLAT_VECTOR; - if (TypeIsConstantSize(physical_type) && flat_or_const) { + if (TypeIsConstantSize(physical_type) && + (GetVectorType() == VectorType::CONSTANT_VECTOR || GetVectorType() == VectorType::FLAT_VECTOR)) { auxiliary.reset(); } if (vector_type == VectorType::CONSTANT_VECTOR && physical_type == PhysicalType::STRUCT) { @@ -1782,29 +1748,23 @@ void Vector::DebugShuffleNestedVector(Vector &vector, idx_t count) { void FlatVector::SetNull(Vector &vector, idx_t idx, bool is_null) { D_ASSERT(vector.GetVectorType() == VectorType::FLAT_VECTOR); vector.validity.Set(idx, !is_null); - if (!is_null) { - return; - } - - auto &type = vector.GetType(); - auto internal_type = type.InternalType(); - - // Set all child entries to NULL. - if (internal_type == PhysicalType::STRUCT) { - auto &entries = StructVector::GetEntries(vector); - for (auto &entry : entries) { - FlatVector::SetNull(*entry, idx, is_null); - } - return; - } - - // Set all child entries to NULL. - if (internal_type == PhysicalType::ARRAY) { - auto &child = ArrayVector::GetEntry(vector); - auto array_size = ArrayType::GetSize(type); - auto child_offset = idx * array_size; - for (idx_t i = 0; i < array_size; i++) { - FlatVector::SetNull(child, child_offset + i, is_null); + if (is_null) { + auto &type = vector.GetType(); + auto internal_type = type.InternalType(); + if (internal_type == PhysicalType::STRUCT) { + // set all child entries to null as well + auto &entries = StructVector::GetEntries(vector); + for (auto &entry : entries) { + FlatVector::SetNull(*entry, idx, is_null); + } + } else if (internal_type == PhysicalType::ARRAY) { + // set the child element in the array to null as well + auto &child = ArrayVector::GetEntry(vector); + auto array_size = ArrayType::GetSize(type); + auto child_offset = idx * array_size; + for (idx_t i = 0; i < array_size; i++) { + FlatVector::SetNull(child, child_offset + i, is_null); + } } } } diff --git a/src/duckdb/src/common/vector_operations/comparison_operators.cpp b/src/duckdb/src/common/vector_operations/comparison_operators.cpp index 9c5c3d662..8a56cdfc3 100644 --- a/src/duckdb/src/common/vector_operations/comparison_operators.cpp +++ b/src/duckdb/src/common/vector_operations/comparison_operators.cpp @@ -223,8 +223,7 @@ struct ComparisonExecutor { public: template static inline void Execute(Vector &left, Vector &right, Vector &result, idx_t count) { - D_ASSERT(left.GetType().InternalType() == right.GetType().InternalType() && - result.GetType() == LogicalType::BOOLEAN); + D_ASSERT(left.GetType() == right.GetType() && result.GetType() == LogicalType::BOOLEAN); // the inplace loops take the result as the last parameter switch (left.GetType().InternalType()) { case PhysicalType::BOOL: diff --git a/src/duckdb/src/common/vector_operations/is_distinct_from.cpp b/src/duckdb/src/common/vector_operations/is_distinct_from.cpp index b250eddc7..e9a31ee0e 100644 --- a/src/duckdb/src/common/vector_operations/is_distinct_from.cpp +++ b/src/duckdb/src/common/vector_operations/is_distinct_from.cpp @@ -65,26 +65,17 @@ static void DistinctExecute(Vector &left, Vector &right, Vector &result, idx_t c DistinctExecuteSwitch(left, right, result, count); } -#ifndef DUCKDB_SMALLER_BINARY template -#else -template -#endif static inline idx_t DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lmask, ValidityMask &rmask, SelectionVector *true_sel, SelectionVector *false_sel) { -#ifdef DUCKDB_SMALLER_BINARY - bool HAS_TRUE_SEL = true_sel; - bool HAS_FALSE_SEL = false_sel; -#endif idx_t true_count = 0, false_count = 0; for (idx_t i = 0; i < count; i++) { auto result_idx = result_sel->get_index(i); auto lindex = lsel->get_index(i); auto rindex = rsel->get_index(i); -#ifndef DUCKDB_SMALLER_BINARY if (NO_NULL) { if (OP::Operation(ldata[lindex], rdata[rindex], false, false)) { if (HAS_TRUE_SEL) { @@ -95,9 +86,7 @@ DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *_ false_sel->set_index(false_count++, result_idx); } } - } else -#endif - { + } else { if (OP::Operation(ldata[lindex], rdata[rindex], !lmask.RowIsValid(lindex), !rmask.RowIsValid(rindex))) { if (HAS_TRUE_SEL) { true_sel->set_index(true_count++, result_idx); @@ -115,8 +104,6 @@ DistinctSelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *_ return count - false_count; } } - -#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t DistinctSelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -135,7 +122,6 @@ DistinctSelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGH ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); } } -#endif template static inline idx_t @@ -143,7 +129,6 @@ DistinctSelectGenericLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_T const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lmask, ValidityMask &rmask, SelectionVector *true_sel, SelectionVector *false_sel) { -#ifndef DUCKDB_SMALLER_BINARY if (!lmask.AllValid() || !rmask.AllValid()) { return DistinctSelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); @@ -151,10 +136,6 @@ DistinctSelectGenericLoopSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_T return DistinctSelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lmask, rmask, true_sel, false_sel); } -#else - return DistinctSelectGenericLoop(ldata, rdata, lsel, rsel, result_sel, count, lmask, - rmask, true_sel, false_sel); -#endif } template @@ -169,8 +150,6 @@ static idx_t DistinctSelectGeneric(Vector &left, Vector &right, const SelectionV UnifiedVectorFormat::GetData(ldata), UnifiedVectorFormat::GetData(rdata), ldata.sel, rdata.sel, sel, count, ldata.validity, rdata.validity, true_sel, false_sel); } - -#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t DistinctSelectFlatLoop(LEFT_TYPE *__restrict ldata, RIGHT_TYPE *__restrict rdata, @@ -226,7 +205,6 @@ static inline idx_t DistinctSelectFlatLoopSwitch(LEFT_TYPE *__restrict ldata, RI return DistinctSelectFlatLoopSelSwitch( ldata, rdata, sel, count, lmask, rmask, true_sel, false_sel); } - template static idx_t DistinctSelectFlat(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { @@ -251,8 +229,6 @@ static idx_t DistinctSelectFlat(Vector &left, Vector &right, const SelectionVect ldata, rdata, sel, count, FlatVector::Validity(left), FlatVector::Validity(right), true_sel, false_sel); } } -#endif - template static idx_t DistinctSelectConstant(Vector &left, Vector &right, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { @@ -311,7 +287,6 @@ static idx_t DistinctSelect(Vector &left, Vector &right, const SelectionVector * if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::CONSTANT_VECTOR) { return DistinctSelectConstant(left, right, sel, count, true_sel, false_sel); -#ifndef DUCKDB_SMALLER_BINARY } else if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return DistinctSelectFlat(left, right, sel, count, true_sel, false_sel); @@ -321,7 +296,6 @@ static idx_t DistinctSelect(Vector &left, Vector &right, const SelectionVector * } else if (left.GetVectorType() == VectorType::FLAT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return DistinctSelectFlat(left, right, sel, count, true_sel, false_sel); -#endif } else { return DistinctSelectGeneric(left, right, sel, count, true_sel, false_sel); } @@ -558,7 +532,7 @@ static void ExtractNestedMask(const SelectionVector &slice_sel, const idx_t coun } } - child_mask->Reset(null_mask->Capacity()); + child_mask->Reset(null_mask->TargetCount()); } static void DensifyNestedSelection(const SelectionVector &dense_sel, const idx_t count, SelectionVector &slice_sel) { @@ -596,7 +570,7 @@ static idx_t DistinctSelectStruct(Vector &left, Vector &right, idx_t count, cons ValidityMask *child_mask = nullptr; if (null_mask) { child_mask = &child_validity; - child_mask->Reset(null_mask->Capacity()); + child_mask->Reset(null_mask->TargetCount()); } idx_t match_count = 0; @@ -734,7 +708,7 @@ static idx_t DistinctSelectList(Vector &left, Vector &right, idx_t count, const ValidityMask *child_mask = nullptr; if (null_mask) { child_mask = &child_validity; - child_mask->Reset(null_mask->Capacity()); + child_mask->Reset(null_mask->TargetCount()); } idx_t match_count = 0; @@ -870,7 +844,7 @@ static idx_t DistinctSelectArray(Vector &left, Vector &right, idx_t count, const ValidityMask *child_mask = nullptr; if (null_mask) { child_mask = &child_validity; - child_mask->Reset(null_mask->Capacity()); + child_mask->Reset(null_mask->TargetCount()); } idx_t match_count = 0; @@ -1207,7 +1181,6 @@ idx_t VectorOperations::DistinctGreaterThanNullsFirst(Vector &left, Vector &righ return TemplatedDistinctSelectOperation(left, right, sel, count, true_sel, false_sel, null_mask); } - // true := A >= B with nulls being maximal idx_t VectorOperations::DistinctGreaterThanEquals(Vector &left, Vector &right, optional_ptr sel, idx_t count, optional_ptr true_sel, diff --git a/src/duckdb/src/common/vector_operations/vector_hash.cpp b/src/duckdb/src/common/vector_operations/vector_hash.cpp index c82422c23..e6ef5f5fc 100644 --- a/src/duckdb/src/common/vector_operations/vector_hash.cpp +++ b/src/duckdb/src/common/vector_operations/vector_hash.cpp @@ -21,9 +21,7 @@ struct HashOp { }; static inline hash_t CombineHashScalar(hash_t a, hash_t b) { - a ^= a >> 32; - a *= 0xd6e8feb86659fd93U; - return a ^ b; + return (a * UINT64_C(0xbf58476d1ce4e5b9)) ^ b; } template diff --git a/src/duckdb/extension/core_functions/aggregate/algebraic/avg.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/algebraic/avg.cpp rename to src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp index f242b2770..d00e743ff 100644 --- a/src/duckdb/extension/core_functions/aggregate/algebraic/avg.cpp +++ b/src/duckdb/src/core_functions/aggregate/algebraic/avg.cpp @@ -1,5 +1,5 @@ -#include "core_functions/aggregate/algebraic_functions.hpp" -#include "core_functions/aggregate/sum_helpers.hpp" +#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" +#include "duckdb/core_functions/aggregate/sum_helpers.hpp" #include "duckdb/common/types/hugeint.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/function/function_set.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/algebraic/corr.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp similarity index 53% rename from src/duckdb/extension/core_functions/aggregate/algebraic/corr.cpp rename to src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp index bf53a5ad3..61678684a 100644 --- a/src/duckdb/extension/core_functions/aggregate/algebraic/corr.cpp +++ b/src/duckdb/src/core_functions/aggregate/algebraic/corr.cpp @@ -1,7 +1,7 @@ -#include "core_functions/aggregate/algebraic_functions.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" -#include "core_functions/aggregate/algebraic/stddev.hpp" -#include "core_functions/aggregate/algebraic/corr.hpp" +#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" +#include "duckdb/core_functions/aggregate/algebraic/corr.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/algebraic/covar.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp similarity index 80% rename from src/duckdb/extension/core_functions/aggregate/algebraic/covar.cpp rename to src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp index fddb9ed28..ced7d8be6 100644 --- a/src/duckdb/extension/core_functions/aggregate/algebraic/covar.cpp +++ b/src/duckdb/src/core_functions/aggregate/algebraic/covar.cpp @@ -1,6 +1,6 @@ -#include "core_functions/aggregate/algebraic_functions.hpp" +#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" #include "duckdb/common/types/null_value.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/algebraic/stddev.cpp b/src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp similarity index 91% rename from src/duckdb/extension/core_functions/aggregate/algebraic/stddev.cpp rename to src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp index e9d14ee25..b21467eeb 100644 --- a/src/duckdb/extension/core_functions/aggregate/algebraic/stddev.cpp +++ b/src/duckdb/src/core_functions/aggregate/algebraic/stddev.cpp @@ -1,7 +1,7 @@ -#include "core_functions/aggregate/algebraic_functions.hpp" +#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/function_set.hpp" -#include "core_functions/aggregate/algebraic/stddev.hpp" +#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" #include namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/approx_count.cpp b/src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/distributive/approx_count.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp index 37f05b208..13d33220b 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/approx_count.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/approx_count.cpp @@ -1,7 +1,7 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/types/hash.hpp" #include "duckdb/common/types/hyperloglog.hpp" -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/function/function_set.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "hyperloglog.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp b/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp similarity index 90% rename from src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp index 63c112b3c..be64b065f 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/arg_min_max.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/arg_min_max.cpp @@ -1,14 +1,14 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/function/function_set.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression_binder.hpp" -#include "duckdb/function/create_sort_key.hpp" -#include "duckdb/function/aggregate/minmax_n_helpers.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" +#include "duckdb/core_functions/aggregate/minmax_n_helpers.hpp" namespace duckdb { @@ -285,6 +285,7 @@ struct VectorArgMinMaxBase : ArgMinMaxBase { target.arg_null = source.arg_null; if (!target.arg_null) { STATE::template AssignValue(target.arg, source.arg); + ; } target.is_initialized = true; } @@ -302,43 +303,21 @@ struct VectorArgMinMaxBase : ArgMinMaxBase { static unique_ptr Bind(ClientContext &context, AggregateFunction &function, vector> &arguments) { - if (arguments[1]->return_type.InternalType() == PhysicalType::VARCHAR) { - ExpressionBinder::PushCollation(context, arguments[1], arguments[1]->return_type); - } function.arguments[0] = arguments[0]->return_type; function.return_type = arguments[0]->return_type; return nullptr; } }; -template -AggregateFunction GetGenericArgMinMaxFunction() { - using STATE = ArgMinMaxState; - return AggregateFunction( - {LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, OP::template Update, - AggregateFunction::StateCombine, AggregateFunction::StateVoidFinalize, nullptr, OP::Bind, - AggregateFunction::StateDestroy); -} - template AggregateFunction GetVectorArgMinMaxFunctionInternal(const LogicalType &by_type, const LogicalType &type) { -#ifndef DUCKDB_SMALLER_BINARY using STATE = ArgMinMaxState; - return AggregateFunction({type, by_type}, type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - OP::template Update, AggregateFunction::StateCombine, - AggregateFunction::StateVoidFinalize, nullptr, OP::Bind, - AggregateFunction::StateDestroy); -#else - auto function = GetGenericArgMinMaxFunction(); - function.arguments = {type, by_type}; - function.return_type = type; - return function; -#endif + return AggregateFunction( + {type, by_type}, type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, + OP::template Update, AggregateFunction::StateCombine, + AggregateFunction::StateVoidFinalize, nullptr, OP::Bind, AggregateFunction::StateDestroy); } -#ifndef DUCKDB_SMALLER_BINARY template AggregateFunction GetVectorArgMinMaxFunctionBy(const LogicalType &by_type, const LogicalType &type) { switch (by_type.InternalType()) { @@ -356,7 +335,6 @@ AggregateFunction GetVectorArgMinMaxFunctionBy(const LogicalType &by_type, const throw InternalException("Unimplemented arg_min/arg_max aggregate"); } } -#endif static const vector ArgMaxByTypes() { vector types = {LogicalType::INTEGER, LogicalType::BIGINT, LogicalType::HUGEINT, @@ -369,34 +347,21 @@ template void AddVectorArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType &type) { auto by_types = ArgMaxByTypes(); for (const auto &by_type : by_types) { -#ifndef DUCKDB_SMALLER_BINARY fun.AddFunction(GetVectorArgMinMaxFunctionBy(by_type, type)); -#else - fun.AddFunction(GetVectorArgMinMaxFunctionInternal(by_type, type)); -#endif } } template AggregateFunction GetArgMinMaxFunctionInternal(const LogicalType &by_type, const LogicalType &type) { -#ifndef DUCKDB_SMALLER_BINARY using STATE = ArgMinMaxState; - auto function = - AggregateFunction::BinaryAggregate( - type, by_type, type); + auto function = AggregateFunction::BinaryAggregate(type, by_type, type); if (type.InternalType() == PhysicalType::VARCHAR || by_type.InternalType() == PhysicalType::VARCHAR) { function.destructor = AggregateFunction::StateDestroy; } function.bind = OP::Bind; -#else - auto function = GetGenericArgMinMaxFunction(); - function.arguments = {type, by_type}; - function.return_type = type; -#endif return function; } -#ifndef DUCKDB_SMALLER_BINARY template AggregateFunction GetArgMinMaxFunctionBy(const LogicalType &by_type, const LogicalType &type) { switch (by_type.InternalType()) { @@ -414,24 +379,18 @@ AggregateFunction GetArgMinMaxFunctionBy(const LogicalType &by_type, const Logic throw InternalException("Unimplemented arg_min/arg_max by aggregate"); } } -#endif template void AddArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType &type) { auto by_types = ArgMaxByTypes(); for (const auto &by_type : by_types) { -#ifndef DUCKDB_SMALLER_BINARY fun.AddFunction(GetArgMinMaxFunctionBy(by_type, type)); -#else - fun.AddFunction(GetArgMinMaxFunctionInternal(by_type, type)); -#endif } } template static AggregateFunction GetDecimalArgMinMaxFunction(const LogicalType &by_type, const LogicalType &type) { D_ASSERT(type.id() == LogicalTypeId::DECIMAL); -#ifndef DUCKDB_SMALLER_BINARY switch (type.InternalType()) { case PhysicalType::INT16: return GetArgMinMaxFunctionBy(by_type, type); @@ -442,9 +401,6 @@ static AggregateFunction GetDecimalArgMinMaxFunction(const LogicalType &by_type, default: return GetArgMinMaxFunctionBy(by_type, type); } -#else - return GetArgMinMaxFunctionInternal(by_type, type); -#endif } template @@ -493,19 +449,17 @@ void AddDecimalArgMinMaxFunctionBy(AggregateFunctionSet &fun, const LogicalType template void AddGenericArgMinMaxFunction(AggregateFunctionSet &fun) { - fun.AddFunction(GetGenericArgMinMaxFunction()); + using STATE = ArgMinMaxState; + fun.AddFunction( + AggregateFunction({LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, AggregateFunction::StateSize, + AggregateFunction::StateInitialize, OP::template Update, + AggregateFunction::StateCombine, AggregateFunction::StateVoidFinalize, + nullptr, OP::Bind, AggregateFunction::StateDestroy)); } template static void AddArgMinMaxFunctions(AggregateFunctionSet &fun) { - using GENERIC_VECTOR_OP = VectorArgMinMaxBase>; -#ifndef DUCKDB_SMALLER_BINARY using OP = ArgMinMaxBase; - using VECTOR_OP = VectorArgMinMaxBase; -#else - using OP = GENERIC_VECTOR_OP; - using VECTOR_OP = GENERIC_VECTOR_OP; -#endif AddArgMinMaxFunctionBy(fun, LogicalType::INTEGER); AddArgMinMaxFunctionBy(fun, LogicalType::BIGINT); AddArgMinMaxFunctionBy(fun, LogicalType::DOUBLE); @@ -520,9 +474,11 @@ static void AddArgMinMaxFunctions(AggregateFunctionSet &fun) { AddDecimalArgMinMaxFunctionBy(fun, by_type); } + using VECTOR_OP = VectorArgMinMaxBase; AddVectorArgMinMaxFunctionBy(fun, LogicalType::ANY); // we always use LessThan when using sort keys because the ORDER_TYPE takes care of selecting the lowest or highest + using GENERIC_VECTOR_OP = VectorArgMinMaxBase>; AddGenericArgMinMaxFunction(fun); } @@ -621,7 +577,7 @@ static void SpecializeArgMinMaxNFunction(AggregateFunction &function) { using OP = MinMaxNOperation; function.state_size = AggregateFunction::StateSize; - function.initialize = AggregateFunction::StateInitialize; + function.initialize = AggregateFunction::StateInitialize; function.combine = AggregateFunction::StateCombine; function.destructor = AggregateFunction::StateDestroy; @@ -632,7 +588,6 @@ static void SpecializeArgMinMaxNFunction(AggregateFunction &function) { template static void SpecializeArgMinMaxNFunction(PhysicalType arg_type, AggregateFunction &function) { switch (arg_type) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::VARCHAR: SpecializeArgMinMaxNFunction(function); break; @@ -648,7 +603,6 @@ static void SpecializeArgMinMaxNFunction(PhysicalType arg_type, AggregateFunctio case PhysicalType::DOUBLE: SpecializeArgMinMaxNFunction, COMPARATOR>(function); break; -#endif default: SpecializeArgMinMaxNFunction(function); break; @@ -658,7 +612,6 @@ static void SpecializeArgMinMaxNFunction(PhysicalType arg_type, AggregateFunctio template static void SpecializeArgMinMaxNFunction(PhysicalType val_type, PhysicalType arg_type, AggregateFunction &function) { switch (val_type) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::VARCHAR: SpecializeArgMinMaxNFunction(arg_type, function); break; @@ -674,7 +627,6 @@ static void SpecializeArgMinMaxNFunction(PhysicalType val_type, PhysicalType arg case PhysicalType::DOUBLE: SpecializeArgMinMaxNFunction, COMPARATOR>(arg_type, function); break; -#endif default: SpecializeArgMinMaxNFunction(arg_type, function); break; diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/bitagg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp similarity index 99% rename from src/duckdb/extension/core_functions/aggregate/distributive/bitagg.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp index 241d25692..af3056359 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/bitagg.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/bitagg.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/null_value.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/bitstring_agg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp similarity index 95% rename from src/duckdb/extension/core_functions/aggregate/distributive/bitstring_agg.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp index c9e399835..f01cc50a8 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/bitstring_agg.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/bitstring_agg.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/null_value.hpp" #include "duckdb/common/vector_operations/aggregate_executor.hpp" @@ -234,11 +234,13 @@ idx_t BitStringAggOperation::GetRange(uhugeint_t min, uhugeint_t max) { unique_ptr BitstringPropagateStats(ClientContext &context, BoundAggregateExpression &expr, AggregateStatisticsInput &input) { - if (NumericStats::HasMinMax(input.child_stats[0])) { - auto &bind_agg_data = input.bind_data->Cast(); - bind_agg_data.min = NumericStats::Min(input.child_stats[0]); - bind_agg_data.max = NumericStats::Max(input.child_stats[0]); + if (!NumericStats::HasMinMax(input.child_stats[0])) { + throw BinderException("Could not retrieve required statistics. Alternatively, try by providing the statistics " + "explicitly: BITSTRING_AGG(col, min, max) "); } + auto &bind_agg_data = input.bind_data->Cast(); + bind_agg_data.min = NumericStats::Min(input.child_stats[0]); + bind_agg_data.max = NumericStats::Max(input.child_stats[0]); return nullptr; } diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/bool.cpp b/src/duckdb/src/core_functions/aggregate/distributive/bool.cpp similarity index 93% rename from src/duckdb/extension/core_functions/aggregate/distributive/bool.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/bool.cpp index 9b781f848..20f2f3bac 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/bool.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/bool.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" @@ -95,7 +95,6 @@ AggregateFunction BoolOrFun::GetFunction() { auto fun = AggregateFunction::UnaryAggregate( LogicalType(LogicalTypeId::BOOLEAN), LogicalType::BOOLEAN); fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.distinct_dependent = AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT; return fun; } @@ -103,7 +102,6 @@ AggregateFunction BoolAndFun::GetFunction() { auto fun = AggregateFunction::UnaryAggregate( LogicalType(LogicalTypeId::BOOLEAN), LogicalType::BOOLEAN); fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - fun.distinct_dependent = AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT; return fun; } diff --git a/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp b/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp new file mode 100644 index 000000000..426d4498c --- /dev/null +++ b/src/duckdb/src/core_functions/aggregate/distributive/entropy.cpp @@ -0,0 +1,183 @@ +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/common/exception.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/planner/expression/bound_aggregate_expression.hpp" +#include "duckdb/function/function_set.hpp" +#include "duckdb/common/algorithm.hpp" +#include "duckdb/common/unordered_map.hpp" + +namespace duckdb { + +template +struct EntropyState { + using DistinctMap = unordered_map; + + idx_t count; + DistinctMap *distinct; + + EntropyState &operator=(const EntropyState &other) = delete; + + EntropyState &Assign(const EntropyState &other) { + D_ASSERT(!distinct); + distinct = new DistinctMap(*other.distinct); + count = other.count; + return *this; + } +}; + +struct EntropyFunctionBase { + template + static void Initialize(STATE &state) { + state.distinct = nullptr; + state.count = 0; + } + + template + static void Combine(const STATE &source, STATE &target, AggregateInputData &) { + if (!source.distinct) { + return; + } + if (!target.distinct) { + target.Assign(source); + return; + } + for (auto &val : *source.distinct) { + auto value = val.first; + (*target.distinct)[value] += val.second; + } + target.count += source.count; + } + + template + static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { + double count = static_cast(state.count); + if (state.distinct) { + double entropy = 0; + for (auto &val : *state.distinct) { + double val_sec = static_cast(val.second); + entropy += (val_sec / count) * log2(count / val_sec); + } + target = entropy; + } else { + target = 0; + } + } + + static bool IgnoreNull() { + return true; + } + template + static void Destroy(STATE &state, AggregateInputData &aggr_input_data) { + if (state.distinct) { + delete state.distinct; + } + } +}; + +struct EntropyFunction : EntropyFunctionBase { + template + static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { + if (!state.distinct) { + state.distinct = new unordered_map(); + } + (*state.distinct)[input]++; + state.count++; + } + template + static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, + idx_t count) { + for (idx_t i = 0; i < count; i++) { + Operation(state, input, unary_input); + } + } +}; + +struct EntropyFunctionString : EntropyFunctionBase { + template + static void Operation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) { + if (!state.distinct) { + state.distinct = new unordered_map(); + } + auto value = input.GetString(); + (*state.distinct)[value]++; + state.count++; + } + + template + static void ConstantOperation(STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input, + idx_t count) { + for (idx_t i = 0; i < count; i++) { + Operation(state, input, unary_input); + } + } +}; + +template +AggregateFunction GetEntropyFunction(const LogicalType &input_type, const LogicalType &result_type) { + auto fun = + AggregateFunction::UnaryAggregateDestructor, INPUT_TYPE, RESULT_TYPE, EntropyFunction>( + input_type, result_type); + fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + return fun; +} + +AggregateFunction GetEntropyFunctionInternal(PhysicalType type) { + switch (type) { + case PhysicalType::UINT16: + return AggregateFunction::UnaryAggregateDestructor, uint16_t, double, EntropyFunction>( + LogicalType::USMALLINT, LogicalType::DOUBLE); + case PhysicalType::UINT32: + return AggregateFunction::UnaryAggregateDestructor, uint32_t, double, EntropyFunction>( + LogicalType::UINTEGER, LogicalType::DOUBLE); + case PhysicalType::UINT64: + return AggregateFunction::UnaryAggregateDestructor, uint64_t, double, EntropyFunction>( + LogicalType::UBIGINT, LogicalType::DOUBLE); + case PhysicalType::INT16: + return AggregateFunction::UnaryAggregateDestructor, int16_t, double, EntropyFunction>( + LogicalType::SMALLINT, LogicalType::DOUBLE); + case PhysicalType::INT32: + return AggregateFunction::UnaryAggregateDestructor, int32_t, double, EntropyFunction>( + LogicalType::INTEGER, LogicalType::DOUBLE); + case PhysicalType::INT64: + return AggregateFunction::UnaryAggregateDestructor, int64_t, double, EntropyFunction>( + LogicalType::BIGINT, LogicalType::DOUBLE); + case PhysicalType::FLOAT: + return AggregateFunction::UnaryAggregateDestructor, float, double, EntropyFunction>( + LogicalType::FLOAT, LogicalType::DOUBLE); + case PhysicalType::DOUBLE: + return AggregateFunction::UnaryAggregateDestructor, double, double, EntropyFunction>( + LogicalType::DOUBLE, LogicalType::DOUBLE); + case PhysicalType::VARCHAR: { + return AggregateFunction::UnaryAggregateDestructor, string_t, double, + EntropyFunctionString>( + LogicalType::ANY_PARAMS(LogicalType::VARCHAR, 150), LogicalType::DOUBLE); + } + + default: + throw InternalException("Unimplemented approximate_count aggregate"); + } +} + +AggregateFunction GetEntropyFunction(PhysicalType type) { + auto fun = GetEntropyFunctionInternal(type); + fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + return fun; +} + +AggregateFunctionSet EntropyFun::GetFunctions() { + AggregateFunctionSet entropy("entropy"); + entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT16)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT32)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::UINT64)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::FLOAT)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::INT16)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::INT32)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::INT64)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::DOUBLE)); + entropy.AddFunction(GetEntropyFunction(PhysicalType::VARCHAR)); + entropy.AddFunction(GetEntropyFunction(LogicalType::TIMESTAMP, LogicalType::DOUBLE)); + entropy.AddFunction(GetEntropyFunction(LogicalType::TIMESTAMP_TZ, LogicalType::DOUBLE)); + return entropy; +} + +} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/kurtosis.cpp b/src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/distributive/kurtosis.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp index 4f9f6f30c..bca51bd16 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/kurtosis.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/kurtosis.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" diff --git a/src/duckdb/src/function/aggregate/distributive/minmax.cpp b/src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp similarity index 95% rename from src/duckdb/src/function/aggregate/distributive/minmax.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp index b862bf6d9..9642da156 100644 --- a/src/duckdb/src/function/aggregate/distributive/minmax.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/minmax.cpp @@ -1,17 +1,16 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" -#include "duckdb/function/aggregate/minmax_n_helpers.hpp" -#include "duckdb/function/aggregate/sort_key_helpers.hpp" -#include "duckdb/function/function_binder.hpp" #include "duckdb/main/config.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/function/function_binder.hpp" +#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" +#include "duckdb/core_functions/aggregate/minmax_n_helpers.hpp" namespace duckdb { @@ -337,14 +336,8 @@ unique_ptr BindMinMax(ClientContext &context, AggregateFunction &f // to make sure the result's correctness. string function_name = function.name == "min" ? "arg_min" : "arg_max"; QueryErrorContext error_context; - auto func = Catalog::GetEntry(context, CatalogType::AGGREGATE_FUNCTION_ENTRY, "", "", function_name, + auto func = Catalog::GetEntry(context, CatalogType::SCALAR_FUNCTION_ENTRY, "", "", function_name, OnEntryNotFound::RETURN_NULL, error_context); - if (!func) { - throw NotImplementedException( - "Failure while binding function \"%s\" using collations - arg_min/arg_max do not exist in the " - "catalog - load the core_functions module to fix this issue", - function.name); - } auto &func_entry = func->Cast(); @@ -377,7 +370,6 @@ unique_ptr BindMinMax(ClientContext &context, AggregateFunction &f function = GetMinMaxOperator(input_type); function.name = std::move(name); function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - function.distinct_dependent = AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT; if (function.bind) { return function.bind(context, function, arguments); } else { @@ -391,11 +383,11 @@ static AggregateFunction GetMinMaxOperator(string name) { nullptr, nullptr, BindMinMax); } -AggregateFunction MinFunction::GetFunction() { +AggregateFunction MinFun::GetFunction() { return GetMinMaxOperator("min"); } -AggregateFunction MaxFunction::GetFunction() { +AggregateFunction MaxFun::GetFunction() { return GetMinMaxOperator("max"); } @@ -479,7 +471,7 @@ static void SpecializeMinMaxNFunction(AggregateFunction &function) { using OP = MinMaxNOperation; function.state_size = AggregateFunction::StateSize; - function.initialize = AggregateFunction::StateInitialize; + function.initialize = AggregateFunction::StateInitialize; function.combine = AggregateFunction::StateCombine; function.destructor = AggregateFunction::StateDestroy; @@ -539,16 +531,17 @@ static AggregateFunction GetMinMaxNFunction() { //--------------------------------------------------- // Function Registration //---------------------------------------------------s + AggregateFunctionSet MinFun::GetFunctions() { AggregateFunctionSet min("min"); - min.AddFunction(MinFunction::GetFunction()); + min.AddFunction(GetFunction()); min.AddFunction(GetMinMaxNFunction()); return min; } AggregateFunctionSet MaxFun::GetFunctions() { AggregateFunctionSet max("max"); - max.AddFunction(MaxFunction::GetFunction()); + max.AddFunction(GetFunction()); max.AddFunction(GetMinMaxNFunction()); return max; } diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/product.cpp b/src/duckdb/src/core_functions/aggregate/distributive/product.cpp similarity index 95% rename from src/duckdb/extension/core_functions/aggregate/distributive/product.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/product.cpp index 324893f60..fbe76617a 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/product.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/product.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/skew.cpp b/src/duckdb/src/core_functions/aggregate/distributive/skew.cpp similarity index 96% rename from src/duckdb/extension/core_functions/aggregate/distributive/skew.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/skew.cpp index 12f237610..ef42dce44 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/skew.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/skew.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" @@ -62,7 +62,7 @@ struct SkewnessOperation { } double div = std::sqrt(p); if (div == 0) { - target = NAN; + finalize_data.ReturnNull(); return; } double temp1 = std::sqrt(n * (n - 1)) / (n - 2); diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/string_agg.cpp b/src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/distributive/string_agg.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp index b694a2365..f2caa8901 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/string_agg.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/string_agg.cpp @@ -1,4 +1,4 @@ -#include "core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/null_value.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/distributive/sum.cpp b/src/duckdb/src/core_functions/aggregate/distributive/sum.cpp similarity index 94% rename from src/duckdb/extension/core_functions/aggregate/distributive/sum.cpp rename to src/duckdb/src/core_functions/aggregate/distributive/sum.cpp index be37d5df1..3aa254e34 100644 --- a/src/duckdb/extension/core_functions/aggregate/distributive/sum.cpp +++ b/src/duckdb/src/core_functions/aggregate/distributive/sum.cpp @@ -1,5 +1,5 @@ -#include "core_functions/aggregate/distributive_functions.hpp" -#include "core_functions/aggregate/sum_helpers.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/sum_helpers.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/decimal.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" @@ -157,12 +157,6 @@ unique_ptr SumPropagateStats(ClientContext &context, BoundAggreg AggregateFunction GetSumAggregate(PhysicalType type) { switch (type) { - case PhysicalType::BOOL: { - auto function = AggregateFunction::UnaryAggregate, bool, hugeint_t, IntegerSumOperation>( - LogicalType::BOOLEAN, LogicalType::HUGEINT); - function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; - return function; - } case PhysicalType::INT16: { auto function = AggregateFunction::UnaryAggregate, int16_t, hugeint_t, IntegerSumOperation>( LogicalType::SMALLINT, LogicalType::HUGEINT); @@ -215,7 +209,6 @@ AggregateFunctionSet SumFun::GetFunctions() { sum.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL}, LogicalTypeId::DECIMAL, nullptr, nullptr, nullptr, nullptr, nullptr, FunctionNullHandling::DEFAULT_NULL_HANDLING, nullptr, BindDecimalSum)); - sum.AddFunction(GetSumAggregate(PhysicalType::BOOL)); sum.AddFunction(GetSumAggregate(PhysicalType::INT16)); sum.AddFunction(GetSumAggregate(PhysicalType::INT32)); sum.AddFunction(GetSumAggregate(PhysicalType::INT64)); @@ -225,10 +218,6 @@ AggregateFunctionSet SumFun::GetFunctions() { return sum; } -AggregateFunction CountIfFun::GetFunction() { - return GetSumAggregate(PhysicalType::BOOL); -} - AggregateFunctionSet SumNoOverflowFun::GetFunctions() { AggregateFunctionSet sum_no_overflow; sum_no_overflow.AddFunction(GetSumAggregateNoOverflow(PhysicalType::INT32)); diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/approx_top_k.cpp b/src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/holistic/approx_top_k.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp index 4eb2b9d30..b1cf41e08 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/approx_top_k.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/approx_top_k.cpp @@ -1,6 +1,6 @@ -#include "core_functions/aggregate/histogram_helpers.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/function/aggregate/sort_key_helpers.hpp" +#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/common/string_map_set.hpp" #include "duckdb/common/printer.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/approximate_quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp similarity index 88% rename from src/duckdb/extension/core_functions/aggregate/holistic/approximate_quantile.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp index 23d2cf479..5b6abcd20 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/approximate_quantile.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/approximate_quantile.cpp @@ -1,5 +1,5 @@ #include "duckdb/execution/expression_executor.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" #include "t_digest.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/common/operator/cast_operators.hpp" @@ -230,18 +230,13 @@ unique_ptr BindApproxQuantile(ClientContext &context, AggregateFun return make_uniq(quantiles); } -AggregateFunction ApproxQuantileDecimalFunction(const LogicalType &type) { - auto function = GetApproximateQuantileDecimalAggregateFunction(type); - function.name = "approx_quantile"; - function.serialize = ApproximateQuantileBindData::Serialize; - function.deserialize = ApproximateQuantileBindData::Deserialize; - return function; -} - unique_ptr BindApproxQuantileDecimal(ClientContext &context, AggregateFunction &function, vector> &arguments) { auto bind_data = BindApproxQuantile(context, function, arguments); - function = ApproxQuantileDecimalFunction(arguments[0]->return_type); + function = GetApproximateQuantileDecimalAggregateFunction(arguments[0]->return_type); + function.name = "approx_quantile"; + function.serialize = ApproximateQuantileBindData::Serialize; + function.deserialize = ApproximateQuantileBindData::Deserialize; return bind_data; } @@ -349,18 +344,13 @@ AggregateFunction GetApproxQuantileListAggregateFunction(const LogicalType &type } } -AggregateFunction ApproxQuantileDecimalListFunction(const LogicalType &type) { - auto function = GetApproxQuantileListAggregateFunction(type); - function.name = "approx_quantile"; - function.serialize = ApproximateQuantileBindData::Serialize; - function.deserialize = ApproximateQuantileBindData::Deserialize; - return function; -} - unique_ptr BindApproxQuantileDecimalList(ClientContext &context, AggregateFunction &function, vector> &arguments) { auto bind_data = BindApproxQuantile(context, function, arguments); - function = ApproxQuantileDecimalListFunction(arguments[0]->return_type); + function = GetApproxQuantileListAggregateFunction(arguments[0]->return_type); + function.name = "approx_quantile"; + function.serialize = ApproximateQuantileBindData::Serialize; + function.deserialize = ApproximateQuantileBindData::Deserialize; return bind_data; } @@ -375,39 +365,11 @@ AggregateFunction GetApproxQuantileListAggregate(const LogicalType &type) { return fun; } -unique_ptr ApproxQuantileDecimalDeserialize(Deserializer &deserializer, AggregateFunction &function) { - auto bind_data = ApproximateQuantileBindData::Deserialize(deserializer, function); - auto &return_type = deserializer.Get(); - if (return_type.id() == LogicalTypeId::LIST) { - function = ApproxQuantileDecimalListFunction(function.arguments[0]); - } else { - function = ApproxQuantileDecimalFunction(function.arguments[0]); - } - return bind_data; -} - -AggregateFunction GetApproxQuantileDecimal() { - // stub function - the actual function is set during bind or deserialize - AggregateFunction fun({LogicalTypeId::DECIMAL, LogicalType::FLOAT}, LogicalTypeId::DECIMAL, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, BindApproxQuantileDecimal); - fun.serialize = ApproximateQuantileBindData::Serialize; - fun.deserialize = ApproxQuantileDecimalDeserialize; - return fun; -} - -AggregateFunction GetApproxQuantileDecimalList() { - // stub function - the actual function is set during bind or deserialize - AggregateFunction fun({LogicalTypeId::DECIMAL, LogicalType::LIST(LogicalType::FLOAT)}, - LogicalType::LIST(LogicalTypeId::DECIMAL), nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, BindApproxQuantileDecimalList); - fun.serialize = ApproximateQuantileBindData::Serialize; - fun.deserialize = ApproxQuantileDecimalDeserialize; - return fun; -} - AggregateFunctionSet ApproxQuantileFun::GetFunctions() { AggregateFunctionSet approx_quantile; - approx_quantile.AddFunction(GetApproxQuantileDecimal()); + approx_quantile.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL, LogicalType::FLOAT}, LogicalTypeId::DECIMAL, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + BindApproxQuantileDecimal)); approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::SMALLINT)); approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::INTEGER)); @@ -422,7 +384,9 @@ AggregateFunctionSet ApproxQuantileFun::GetFunctions() { approx_quantile.AddFunction(GetApproximateQuantileAggregate(LogicalType::TIMESTAMP_TZ)); // List variants - approx_quantile.AddFunction(GetApproxQuantileDecimalList()); + approx_quantile.AddFunction(AggregateFunction({LogicalTypeId::DECIMAL, LogicalType::LIST(LogicalType::FLOAT)}, + LogicalType::LIST(LogicalTypeId::DECIMAL), nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, BindApproxQuantileDecimalList)); approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::TINYINT)); approx_quantile.AddFunction(GetApproxQuantileListAggregate(LogicalTypeId::SMALLINT)); diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/mad.cpp b/src/duckdb/src/core_functions/aggregate/holistic/mad.cpp similarity index 90% rename from src/duckdb/extension/core_functions/aggregate/holistic/mad.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/mad.cpp index dedb74297..8be7415ff 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/mad.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/mad.cpp @@ -1,9 +1,9 @@ #include "duckdb/execution/expression_executor.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/abs.hpp" -#include "core_functions/aggregate/quantile_state.hpp" +#include "duckdb/core_functions/aggregate/quantile_state.hpp" namespace duckdb { @@ -190,18 +190,12 @@ struct MedianAbsoluteDeviationOperation : QuantileOperation { } template - static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &frames, Vector &result, - idx_t ridx) { - auto &state = *reinterpret_cast(l_state); - auto gstate = reinterpret_cast(g_state); - - auto &data = state.GetOrCreateWindowCursor(partition); - const auto &fmask = partition.filter_mask; - + static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, + AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, + idx_t ridx, const STATE *gstate) { auto rdata = FlatVector::GetData(result); - QuantileIncluded included(fmask, data); + QuantileIncluded included(fmask, dmask); const auto n = FrameSize(included, frames); if (!n) { @@ -218,7 +212,7 @@ struct MedianAbsoluteDeviationOperation : QuantileOperation { const auto &quantile = bind_data.quantiles[0]; auto &window_state = state.GetOrCreateWindowState(); MEDIAN_TYPE med; - if (gstate && gstate->HasTree()) { + if (gstate && gstate->HasTrees()) { med = gstate->GetWindowState().template WindowScalar(data, frames, n, result, quantile); } else { window_state.UpdateSkip(data, frames, included); @@ -265,18 +259,15 @@ AggregateFunction GetTypedMedianAbsoluteDeviationAggregateFunction(const Logical const LogicalType &target_type) { using STATE = QuantileState; using OP = MedianAbsoluteDeviationOperation; - auto fun = AggregateFunction::UnaryAggregateDestructor(input_type, target_type); + auto fun = AggregateFunction::UnaryAggregateDestructor(input_type, target_type); fun.bind = BindMAD; fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; -#ifndef DUCKDB_SMALLER_BINARY - fun.window = OP::template Window; + fun.window = AggregateFunction::UnaryWindow; fun.window_init = OP::template WindowInit; -#endif return fun; } -AggregateFunction GetMedianAbsoluteDeviationAggregateFunctionInternal(const LogicalType &type) { +AggregateFunction GetMedianAbsoluteDeviationAggregateFunction(const LogicalType &type) { switch (type.id()) { case LogicalTypeId::FLOAT: return GetTypedMedianAbsoluteDeviationAggregateFunction(type, type); @@ -314,12 +305,6 @@ AggregateFunction GetMedianAbsoluteDeviationAggregateFunctionInternal(const Logi } } -AggregateFunction GetMedianAbsoluteDeviationAggregateFunction(const LogicalType &type) { - auto result = GetMedianAbsoluteDeviationAggregateFunctionInternal(type); - result.errors = FunctionErrors::CAN_THROW_RUNTIME_ERROR; - return result; -} - unique_ptr BindMedianAbsoluteDeviationDecimal(ClientContext &context, AggregateFunction &function, vector> &arguments) { function = GetMedianAbsoluteDeviationAggregateFunction(arguments[0]->return_type); diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/mode.cpp b/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp similarity index 60% rename from src/duckdb/extension/core_functions/aggregate/holistic/mode.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/mode.cpp index 8c35fc8c9..a8d0dbf1e 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/mode.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp @@ -2,22 +2,45 @@ #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/operator/comparison_operators.hpp" -#include "duckdb/common/types/column/column_data_collection.hpp" -#include "core_functions/aggregate/distributive_functions.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/owning_string_map.hpp" -#include "duckdb/function/create_sort_key.hpp" -#include "duckdb/function/aggregate/sort_key_helpers.hpp" -#include "duckdb/common/algorithm.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" +#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" #include // MODE( ) // Returns the most frequent value for the values within expr1. // NULL values are ignored. If all the values are NULL, or there are 0 rows, then the function returns NULL. -namespace std {} // namespace std +namespace std { + +template <> +struct hash { + inline size_t operator()(const duckdb::interval_t &val) const { + int64_t months, days, micros; + val.Normalize(months, days, micros); + return hash {}(duckdb::UnsafeNumericCast(days)) ^ + hash {}(duckdb::UnsafeNumericCast(months)) ^ hash {}(micros); + } +}; + +template <> +struct hash { + inline size_t operator()(const duckdb::hugeint_t &val) const { + return hash {}(val.upper) ^ hash {}(val.lower); + } +}; + +template <> +struct hash { + inline size_t operator()(const duckdb::uhugeint_t &val) const { + return hash {}(val.upper) ^ hash {}(val.lower); + } +}; + +} // namespace std namespace duckdb { @@ -75,17 +98,6 @@ struct ModeState { bool valid = false; size_t count = 0; - //! The collection being read - const ColumnDataCollection *inputs; - //! The state used for reading the collection on this thread - ColumnDataScanState *scan = nullptr; - //! The data chunk paged into into - DataChunk page; - //! The data pointer - const KEY_TYPE *data = nullptr; - //! The validity mask - const ValidityMask *validity = nullptr; - ~ModeState() { if (frequency_map) { delete frequency_map; @@ -93,51 +105,6 @@ struct ModeState { if (mode) { delete mode; } - if (scan) { - delete scan; - } - } - - void InitializePage(const WindowPartitionInput &partition) { - if (!scan) { - scan = new ColumnDataScanState(); - } - if (page.ColumnCount() == 0) { - D_ASSERT(partition.inputs); - inputs = partition.inputs; - D_ASSERT(partition.column_ids.size() == 1); - inputs->InitializeScan(*scan, partition.column_ids); - inputs->InitializeScanChunk(*scan, page); - } - } - - inline sel_t RowOffset(idx_t row_idx) const { - D_ASSERT(RowIsVisible(row_idx)); - return UnsafeNumericCast(row_idx - scan->current_row_index); - } - - inline bool RowIsVisible(idx_t row_idx) const { - return (row_idx < scan->next_row_index && scan->current_row_index <= row_idx); - } - - inline idx_t Seek(idx_t row_idx) { - if (!RowIsVisible(row_idx)) { - D_ASSERT(inputs); - inputs->Seek(row_idx, *scan, page); - data = FlatVector::GetData(page.data[0]); - validity = &FlatVector::Validity(page.data[0]); - } - return RowOffset(row_idx); - } - - inline const KEY_TYPE &GetCell(idx_t row_idx) { - const auto offset = Seek(row_idx); - return data[offset]; - } - - inline bool RowIsValid(idx_t row_idx) { - const auto offset = Seek(row_idx); - return validity->RowIsValid(offset); } void Reset() { @@ -149,8 +116,7 @@ struct ModeState { valid = false; } - void ModeAdd(idx_t row) { - const auto &key = GetCell(row); + void ModeAdd(const KEY_TYPE &key, idx_t row) { auto &attr = (*frequency_map)[key]; auto new_count = (attr.count += 1); if (new_count == 1) { @@ -170,8 +136,7 @@ struct ModeState { } } - void ModeRm(idx_t frame) { - const auto &key = GetCell(frame); + void ModeRm(const KEY_TYPE &key, idx_t frame) { auto &attr = (*frequency_map)[key]; auto old_count = attr.count; nonzero -= size_t(old_count == 1); @@ -197,16 +162,16 @@ struct ModeState { } }; -template struct ModeIncluded { - inline explicit ModeIncluded(const ValidityMask &fmask_p, STATE &state) : fmask(fmask_p), state(state) { + inline explicit ModeIncluded(const ValidityMask &fmask_p, const ValidityMask &dmask_p) + : fmask(fmask_p), dmask(dmask_p) { } inline bool operator()(const idx_t &idx) const { - return fmask.RowIsValid(idx) && state.RowIsValid(idx); + return fmask.RowIsValid(idx) && dmask.RowIsValid(idx); } const ValidityMask &fmask; - STATE &state; + const ValidityMask &dmask; }; template @@ -240,7 +205,6 @@ struct BaseModeFunction { if (!target.frequency_map) { // Copy - don't destroy! Otherwise windowing will break. target.frequency_map = new typename STATE::Counts(*source.frequency_map); - target.count = source.count; return; } for (auto &val : *source.frequency_map) { @@ -262,21 +226,7 @@ struct BaseModeFunction { }; template -struct TypedModeFunction : BaseModeFunction { - template - static void ConstantOperation(STATE &state, const INPUT_TYPE &key, AggregateUnaryInput &aggr_input, idx_t count) { - if (!state.frequency_map) { - state.frequency_map = TYPE_OP::CreateEmpty(aggr_input.input.allocator); - } - auto &i = (*state.frequency_map)[key]; - i.count += count; - i.first_row = MinValue(i.first_row, state.count); - state.count += count; - } -}; - -template -struct ModeFunction : TypedModeFunction { +struct ModeFunction : BaseModeFunction { template static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { if (!state.frequency_map) { @@ -291,12 +241,25 @@ struct ModeFunction : TypedModeFunction { } } + template + static void ConstantOperation(STATE &state, const INPUT_TYPE &key, AggregateUnaryInput &aggr_input, idx_t count) { + if (!state.frequency_map) { + state.frequency_map = TYPE_OP::CreateEmpty(aggr_input.input.allocator); + } + auto &i = (*state.frequency_map)[key]; + i.count += count; + i.first_row = MinValue(i.first_row, state.count); + state.count += count; + } + template struct UpdateWindowState { STATE &state; - ModeIncluded &included; + const INPUT_TYPE *data; + ModeIncluded &included; - inline UpdateWindowState(STATE &state, ModeIncluded &included) : state(state), included(included) { + inline UpdateWindowState(STATE &state, const INPUT_TYPE *data, ModeIncluded &included) + : state(state), data(data), included(included) { } inline void Neither(idx_t begin, idx_t end) { @@ -305,7 +268,7 @@ struct ModeFunction : TypedModeFunction { inline void Left(idx_t begin, idx_t end) { for (; begin < end; ++begin) { if (included(begin)) { - state.ModeRm(begin); + state.ModeRm(data[begin], begin); } } } @@ -313,7 +276,7 @@ struct ModeFunction : TypedModeFunction { inline void Right(idx_t begin, idx_t end) { for (; begin < end; ++begin) { if (included(begin)) { - state.ModeAdd(begin); + state.ModeAdd(data[begin], begin); } } } @@ -323,14 +286,9 @@ struct ModeFunction : TypedModeFunction { }; template - static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &frames, Vector &result, - idx_t rid) { - auto &state = *reinterpret_cast(l_state); - - state.InitializePage(partition); - const auto &fmask = partition.filter_mask; - + static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, + AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, + idx_t rid, const STATE *gstate) { auto rdata = FlatVector::GetData(result); auto &rmask = FlatVector::Validity(result); auto &prevs = state.prevs; @@ -338,7 +296,7 @@ struct ModeFunction : TypedModeFunction { prevs.resize(1); } - ModeIncluded included(fmask, state); + ModeIncluded included(fmask, dmask); if (!state.frequency_map) { state.frequency_map = TYPE_OP::CreateEmpty(Allocator::DefaultAllocator()); @@ -351,13 +309,13 @@ struct ModeFunction : TypedModeFunction { for (const auto &frame : frames) { for (auto i = frame.start; i < frame.end; ++i) { if (included(i)) { - state.ModeAdd(i); + state.ModeAdd(data[i], i); } } } } else { using Updater = UpdateWindowState; - Updater updater(state, included); + Updater updater(state, data, included); AggregateExecutor::IntersectFrames(prevs, frames, updater); } @@ -400,31 +358,28 @@ struct ModeFallbackFunction : BaseModeFunction { } }; +template > +AggregateFunction GetTypedModeFunction(const LogicalType &type) { + using STATE = ModeState; + using OP = ModeFunction; + auto func = AggregateFunction::UnaryAggregateDestructor(type, type); + func.window = AggregateFunction::UnaryWindow; + return func; +} + AggregateFunction GetFallbackModeFunction(const LogicalType &type) { using STATE = ModeState; using OP = ModeFallbackFunction; AggregateFunction aggr({type}, type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + AggregateFunction::StateInitialize, AggregateSortKeyHelpers::UnaryUpdate, AggregateFunction::StateCombine, AggregateFunction::StateVoidFinalize, nullptr); aggr.destructor = AggregateFunction::StateDestroy; return aggr; } -template > -AggregateFunction GetTypedModeFunction(const LogicalType &type) { - using STATE = ModeState; - using OP = ModeFunction; - auto func = - AggregateFunction::UnaryAggregateDestructor( - type, type); - func.window = OP::template Window; - return func; -} - AggregateFunction GetModeAggregate(const LogicalType &type) { switch (type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::INT8: return GetTypedModeFunction(type); case PhysicalType::UINT8: @@ -453,7 +408,6 @@ AggregateFunction GetModeAggregate(const LogicalType &type) { return GetTypedModeFunction(type); case PhysicalType::VARCHAR: return GetTypedModeFunction(type); -#endif default: return GetFallbackModeFunction(type); } @@ -467,107 +421,9 @@ unique_ptr BindModeAggregate(ClientContext &context, AggregateFunc } AggregateFunctionSet ModeFun::GetFunctions() { - AggregateFunctionSet mode("mode"); + AggregateFunctionSet mode; mode.AddFunction(AggregateFunction({LogicalTypeId::ANY}, LogicalTypeId::ANY, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, BindModeAggregate)); return mode; } - -//===--------------------------------------------------------------------===// -// Entropy -//===--------------------------------------------------------------------===// -template -static double FinalizeEntropy(STATE &state) { - if (!state.frequency_map) { - return 0; - } - double count = static_cast(state.count); - double entropy = 0; - for (auto &val : *state.frequency_map) { - double val_sec = static_cast(val.second.count); - entropy += (val_sec / count) * log2(count / val_sec); - } - return entropy; -} - -template -struct EntropyFunction : TypedModeFunction { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - target = FinalizeEntropy(state); - } -}; - -template -struct EntropyFallbackFunction : BaseModeFunction { - template - static void Finalize(STATE &state, T &target, AggregateFinalizeData &finalize_data) { - target = FinalizeEntropy(state); - } -}; - -template > -AggregateFunction GetTypedEntropyFunction(const LogicalType &type) { - using STATE = ModeState; - using OP = EntropyFunction; - auto func = - AggregateFunction::UnaryAggregateDestructor( - type, LogicalType::DOUBLE); - func.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return func; -} - -AggregateFunction GetFallbackEntropyFunction(const LogicalType &type) { - using STATE = ModeState; - using OP = EntropyFallbackFunction; - AggregateFunction func({type}, LogicalType::DOUBLE, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateSortKeyHelpers::UnaryUpdate, AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, nullptr); - func.destructor = AggregateFunction::StateDestroy; - func.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return func; -} - -AggregateFunction GetEntropyFunction(const LogicalType &type) { - switch (type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY - case PhysicalType::UINT16: - return GetTypedEntropyFunction(type); - case PhysicalType::UINT32: - return GetTypedEntropyFunction(type); - case PhysicalType::UINT64: - return GetTypedEntropyFunction(type); - case PhysicalType::INT16: - return GetTypedEntropyFunction(type); - case PhysicalType::INT32: - return GetTypedEntropyFunction(type); - case PhysicalType::INT64: - return GetTypedEntropyFunction(type); - case PhysicalType::FLOAT: - return GetTypedEntropyFunction(type); - case PhysicalType::DOUBLE: - return GetTypedEntropyFunction(type); - case PhysicalType::VARCHAR: - return GetTypedEntropyFunction(type); -#endif - default: - return GetFallbackEntropyFunction(type); - } -} - -unique_ptr BindEntropyAggregate(ClientContext &context, AggregateFunction &function, - vector> &arguments) { - function = GetEntropyFunction(arguments[0]->return_type); - function.name = "entropy"; - return nullptr; -} - -AggregateFunctionSet EntropyFun::GetFunctions() { - AggregateFunctionSet entropy("entropy"); - entropy.AddFunction(AggregateFunction({LogicalTypeId::ANY}, LogicalType::DOUBLE, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, BindEntropyAggregate)); - return entropy; -} - } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp similarity index 90% rename from src/duckdb/extension/core_functions/aggregate/holistic/quantile.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp index 98ca4d5be..779ce4de4 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/quantile.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp @@ -1,15 +1,15 @@ #include "duckdb/execution/expression_executor.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" -#include "duckdb/common/enums/quantile_enum.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/quantile_enum.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/abs.hpp" -#include "core_functions/aggregate/quantile_state.hpp" +#include "duckdb/core_functions/aggregate/quantile_state.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/queue.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/function/aggregate/sort_key_helpers.hpp" +#include "duckdb/core_functions/aggregate/sort_key_helpers.hpp" namespace duckdb { @@ -208,16 +208,10 @@ struct QuantileScalarOperation : public QuantileOperation { } template - static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &frames, Vector &result, - idx_t ridx) { - auto &state = *reinterpret_cast(l_state); - auto gstate = reinterpret_cast(g_state); - - auto &data = state.GetOrCreateWindowCursor(partition); - const auto &fmask = partition.filter_mask; - - QuantileIncluded included(fmask, data); + static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, + AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &result, + idx_t ridx, const STATE *gstate) { + QuantileIncluded included(fmask, dmask); const auto n = FrameSize(included, frames); D_ASSERT(aggr_input_data.bind_data); @@ -232,7 +226,7 @@ struct QuantileScalarOperation : public QuantileOperation { } const auto &quantile = bind_data.quantiles[0]; - if (gstate && gstate->HasTree()) { + if (gstate && gstate->HasTrees()) { rdata[ridx] = gstate->GetWindowState().template WindowScalar(data, frames, n, result, quantile); } else { @@ -311,19 +305,13 @@ struct QuantileListOperation : QuantileOperation { } template - static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, - const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &frames, Vector &list, - idx_t lidx) { - auto &state = *reinterpret_cast(l_state); - auto gstate = reinterpret_cast(g_state); - - auto &data = state.GetOrCreateWindowCursor(partition); - const auto &fmask = partition.filter_mask; - + static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask, + AggregateInputData &aggr_input_data, STATE &state, const SubFrames &frames, Vector &list, + idx_t lidx, const STATE *gstate) { D_ASSERT(aggr_input_data.bind_data); auto &bind_data = aggr_input_data.bind_data->Cast(); - QuantileIncluded included(fmask, data); + QuantileIncluded included(fmask, dmask); const auto n = FrameSize(included, frames); // Result is a constant LIST with a fixed length @@ -333,7 +321,7 @@ struct QuantileListOperation : QuantileOperation { return; } - if (gstate && gstate->HasTree()) { + if (gstate && gstate->HasTrees()) { gstate->GetWindowState().template WindowList(data, frames, n, list, lidx, bind_data); } else { auto &window_state = state.GetOrCreateWindowState(); @@ -390,7 +378,6 @@ struct QuantileListFallback : QuantileOperation { template AggregateFunction GetDiscreteQuantileTemplated(const LogicalType &type) { switch (type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::INT8: return OP::template GetFunction(type); case PhysicalType::INT16: @@ -409,7 +396,6 @@ AggregateFunction GetDiscreteQuantileTemplated(const LogicalType &type) { return OP::template GetFunction(type); case PhysicalType::VARCHAR: return OP::template GetFunction(type); -#endif default: return OP::GetFallback(type); } @@ -420,12 +406,9 @@ struct ScalarDiscreteQuantile { static AggregateFunction GetFunction(const LogicalType &type) { using STATE = QuantileState; using OP = QuantileScalarOperation; - auto fun = AggregateFunction::UnaryAggregateDestructor(type, type); -#ifndef DUCKDB_SMALLER_BINARY - fun.window = OP::Window; + auto fun = AggregateFunction::UnaryAggregateDestructor(type, type); + fun.window = AggregateFunction::UnaryWindow; fun.window_init = OP::WindowInit; -#endif return fun; } @@ -433,12 +416,11 @@ struct ScalarDiscreteQuantile { using STATE = QuantileState; using OP = QuantileScalarFallback; - AggregateFunction fun({type}, type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateSortKeyHelpers::UnaryUpdate, - AggregateFunction::StateCombine, - AggregateFunction::StateVoidFinalize, nullptr, nullptr, - AggregateFunction::StateDestroy); + AggregateFunction fun( + {type}, type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, + AggregateSortKeyHelpers::UnaryUpdate, AggregateFunction::StateCombine, + AggregateFunction::StateVoidFinalize, nullptr, nullptr, + AggregateFunction::StateDestroy); return fun; } }; @@ -447,8 +429,7 @@ template static AggregateFunction QuantileListAggregate(const LogicalType &input_type, const LogicalType &child_type) { // NOLINT LogicalType result_type = LogicalType::LIST(child_type); return AggregateFunction( - {input_type}, result_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + {input_type}, result_type, AggregateFunction::StateSize, AggregateFunction::StateInitialize, AggregateFunction::UnaryScatterUpdate, AggregateFunction::StateCombine, AggregateFunction::StateFinalize, AggregateFunction::UnaryUpdate, nullptr, AggregateFunction::StateDestroy); @@ -461,10 +442,8 @@ struct ListDiscreteQuantile { using OP = QuantileListOperation; auto fun = QuantileListAggregate(type, type); fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; -#ifndef DUCKDB_SMALLER_BINARY - fun.window = OP::template Window; + fun.window = AggregateFunction::UnaryWindow; fun.window_init = OP::template WindowInit; -#endif return fun; } @@ -472,12 +451,11 @@ struct ListDiscreteQuantile { using STATE = QuantileState; using OP = QuantileListFallback; - AggregateFunction fun({type}, LogicalType::LIST(type), AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateSortKeyHelpers::UnaryUpdate, - AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, nullptr, nullptr, - AggregateFunction::StateDestroy); + AggregateFunction fun( + {type}, LogicalType::LIST(type), AggregateFunction::StateSize, + AggregateFunction::StateInitialize, AggregateSortKeyHelpers::UnaryUpdate, + AggregateFunction::StateCombine, AggregateFunction::StateFinalize, + nullptr, nullptr, AggregateFunction::StateDestroy); return fun; } }; @@ -551,13 +529,10 @@ struct ScalarContinuousQuantile { using STATE = QuantileState; using OP = QuantileScalarOperation; auto fun = - AggregateFunction::UnaryAggregateDestructor(input_type, target_type); + AggregateFunction::UnaryAggregateDestructor(input_type, target_type); fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; -#ifndef DUCKDB_SMALLER_BINARY - fun.window = OP::template Window; + fun.window = AggregateFunction::UnaryWindow; fun.window_init = OP::template WindowInit; -#endif return fun; } }; @@ -569,10 +544,8 @@ struct ListContinuousQuantile { using OP = QuantileListOperation; auto fun = QuantileListAggregate(input_type, target_type); fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT; -#ifndef DUCKDB_SMALLER_BINARY - fun.window = OP::template Window; + fun.window = AggregateFunction::UnaryWindow; fun.window_init = OP::template WindowInit; -#endif return fun; } }; diff --git a/src/duckdb/extension/core_functions/aggregate/holistic/reservoir_quantile.cpp b/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp similarity index 99% rename from src/duckdb/extension/core_functions/aggregate/holistic/reservoir_quantile.cpp rename to src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp index 8c332500d..b96100ded 100644 --- a/src/duckdb/extension/core_functions/aggregate/holistic/reservoir_quantile.cpp +++ b/src/duckdb/src/core_functions/aggregate/holistic/reservoir_quantile.cpp @@ -1,6 +1,6 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/reservoir_sample.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/common/queue.hpp" #include "duckdb/common/serializer/serializer.hpp" @@ -39,7 +39,7 @@ struct ReservoirQuantileState { void FillReservoir(idx_t sample_size, T element) { if (pos < sample_size) { v[pos++] = element; - r_samp->InitializeReservoirWeights(pos, len); + r_samp->InitializeReservoir(pos, len); } else { D_ASSERT(r_samp->next_index_to_sample >= r_samp->num_entries_to_skip_b4_next_sample); if (r_samp->next_index_to_sample == r_samp->num_entries_to_skip_b4_next_sample) { diff --git a/src/duckdb/extension/core_functions/aggregate/nested/binned_histogram.cpp b/src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp similarity index 97% rename from src/duckdb/extension/core_functions/aggregate/nested/binned_histogram.cpp rename to src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp index fc184b8bb..b639475ab 100644 --- a/src/duckdb/extension/core_functions/aggregate/nested/binned_histogram.cpp +++ b/src/duckdb/src/core_functions/aggregate/nested/binned_histogram.cpp @@ -1,9 +1,9 @@ #include "duckdb/function/scalar/nested_functions.hpp" -#include "core_functions/aggregate/nested_functions.hpp" +#include "duckdb/core_functions/aggregate/nested_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/common/types/vector.hpp" -#include "core_functions/aggregate/histogram_helpers.hpp" -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/algorithm.hpp" @@ -249,7 +249,7 @@ static Value OtherBucketValue(const LogicalType &type) { return Value::STRUCT(std::move(child_list)); } case LogicalTypeId::LIST: - return Value::LIST(ListType::GetChildType(type), vector()); + return Value::EMPTYLIST(ListType::GetChildType(type)); default: throw InternalException("Unsupported type for other bucket"); } @@ -342,11 +342,7 @@ static AggregateFunction GetHistogramBinFunction(const LogicalType &type) { template AggregateFunction GetHistogramBinFunction(const LogicalType &type) { - if (type.id() == LogicalTypeId::DECIMAL) { - return GetHistogramBinFunction(LogicalType::DOUBLE); - } switch (type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::BOOL: return GetHistogramBinFunction(type); case PhysicalType::UINT8: @@ -371,7 +367,6 @@ AggregateFunction GetHistogramBinFunction(const LogicalType &type) { return GetHistogramBinFunction(type); case PhysicalType::VARCHAR: return GetHistogramBinFunction(type); -#endif default: return GetHistogramBinFunction(type); } diff --git a/src/duckdb/extension/core_functions/aggregate/nested/histogram.cpp b/src/duckdb/src/core_functions/aggregate/nested/histogram.cpp similarity index 98% rename from src/duckdb/extension/core_functions/aggregate/nested/histogram.cpp rename to src/duckdb/src/core_functions/aggregate/nested/histogram.cpp index 8a736f235..447e8d0d2 100644 --- a/src/duckdb/extension/core_functions/aggregate/nested/histogram.cpp +++ b/src/duckdb/src/core_functions/aggregate/nested/histogram.cpp @@ -1,8 +1,8 @@ #include "duckdb/function/scalar/nested_functions.hpp" -#include "core_functions/aggregate/nested_functions.hpp" +#include "duckdb/core_functions/aggregate/nested_functions.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/string_map_set.hpp" -#include "core_functions/aggregate/histogram_helpers.hpp" +#include "duckdb/core_functions/aggregate/histogram_helpers.hpp" #include "duckdb/common/owning_string_map.hpp" namespace duckdb { @@ -175,7 +175,6 @@ AggregateFunction GetStringMapType(const LogicalType &type) { template AggregateFunction GetHistogramFunction(const LogicalType &type) { switch (type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::BOOL: return GetMapType(type); case PhysicalType::UINT8: @@ -200,7 +199,6 @@ AggregateFunction GetHistogramFunction(const LogicalType &type) { return GetMapType(type); case PhysicalType::VARCHAR: return GetStringMapType(type); -#endif default: return GetStringMapType(type); } diff --git a/src/duckdb/extension/core_functions/aggregate/nested/list.cpp b/src/duckdb/src/core_functions/aggregate/nested/list.cpp similarity index 99% rename from src/duckdb/extension/core_functions/aggregate/nested/list.cpp rename to src/duckdb/src/core_functions/aggregate/nested/list.cpp index 7b23987d6..3ac865739 100644 --- a/src/duckdb/extension/core_functions/aggregate/nested/list.cpp +++ b/src/duckdb/src/core_functions/aggregate/nested/list.cpp @@ -1,6 +1,6 @@ #include "duckdb/common/pair.hpp" #include "duckdb/common/types/list_segment.hpp" -#include "core_functions/aggregate/nested_functions.hpp" +#include "duckdb/core_functions/aggregate/nested_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_avg.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp similarity index 96% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_avg.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp index b4b43af21..4136ab034 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_avg.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_avg.cpp @@ -1,6 +1,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/function/function_set.hpp" diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_count.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp similarity index 81% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_count.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp index 9215fcfb8..333bef41b 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_count.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_count.cpp @@ -1,8 +1,8 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "core_functions/aggregate/regression/regr_count.hpp" +#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_intercept.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp similarity index 89% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_intercept.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp index e727d2669..a3a117456 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_intercept.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_intercept.cpp @@ -1,7 +1,7 @@ //! AVG(y)-REGR_SLOPE(y,x)*AVG(x) -#include "core_functions/aggregate/regression_functions.hpp" -#include "core_functions/aggregate/regression/regr_slope.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression/regr_slope.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { @@ -45,10 +45,6 @@ struct RegrInterceptOperation { return; } RegrSlopeOperation::Finalize(state.slope, target, finalize_data); - if (Value::IsNan(target)) { - finalize_data.ReturnNull(); - return; - } auto x_avg = state.sum_x / state.count; auto y_avg = state.sum_y / state.count; target = y_avg - target * x_avg; diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_r2.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp similarity index 95% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_r2.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp index ba89a8a6e..4d68225e8 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_r2.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_r2.cpp @@ -5,9 +5,9 @@ // 1 if var_pop(y) = 0 and var_pop(x) <> 0, else // power(corr(y,x), 2) -#include "core_functions/aggregate/algebraic/corr.hpp" +#include "duckdb/core_functions/aggregate/algebraic/corr.hpp" #include "duckdb/function/function_set.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" namespace duckdb { struct RegrR2State { diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_slope.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp similarity index 80% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_slope.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp index c58593990..1e86b011d 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_slope.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_slope.cpp @@ -6,9 +6,9 @@ //! Input : Any numeric type //! Output : Double -#include "core_functions/aggregate/regression/regr_slope.hpp" +#include "duckdb/core_functions/aggregate/regression/regr_slope.hpp" #include "duckdb/function/function_set.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_sxx_syy.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp similarity index 94% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_sxx_syy.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp index 72202c2be..e789172d2 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_sxx_syy.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_sxx_syy.cpp @@ -3,9 +3,9 @@ // REGR_SYY(y, x) // Returns REGR_COUNT(y, x) * VAR_POP(y) for non-null pairs. -#include "core_functions/aggregate/regression/regr_count.hpp" +#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" #include "duckdb/function/function_set.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/aggregate/regression/regr_sxy.cpp b/src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp similarity index 89% rename from src/duckdb/extension/core_functions/aggregate/regression/regr_sxy.cpp rename to src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp index 1ab726e82..e3f3d4ae9 100644 --- a/src/duckdb/extension/core_functions/aggregate/regression/regr_sxy.cpp +++ b/src/duckdb/src/core_functions/aggregate/regression/regr_sxy.cpp @@ -1,9 +1,9 @@ // REGR_SXY(y, x) // Returns REGR_COUNT(expr1, expr2) * COVAR_POP(expr1, expr2) for non-null pairs. -#include "core_functions/aggregate/regression/regr_count.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" -#include "core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/aggregate/regression/regr_count.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/register_function_list.cpp b/src/duckdb/src/core_functions/core_functions.cpp similarity index 66% rename from src/duckdb/src/function/register_function_list.cpp rename to src/duckdb/src/core_functions/core_functions.cpp index 1aeebbbbb..ef1687dc6 100644 --- a/src/duckdb/src/function/register_function_list.cpp +++ b/src/duckdb/src/core_functions/core_functions.cpp @@ -1,20 +1,20 @@ -#include "duckdb/catalog/default/default_types.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/function/function_list.hpp" -#include "duckdb/function/register_function_list_helper.hpp" +#include "duckdb/core_functions/core_functions.hpp" +#include "duckdb/core_functions/function_list.hpp" #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" namespace duckdb { template -static void FillExtraInfo(const StaticFunctionDefinition &function, T &info) { +void FillExtraInfo(const StaticFunctionDefinition &function, T &info) { info.internal = true; - FillFunctionDescriptions(function, info); + info.description = function.description; + info.parameter_names = StringUtil::Split(function.parameters, ","); + info.example = function.example; } -static void RegisterFunctionList(Catalog &catalog, CatalogTransaction transaction, - const StaticFunctionDefinition *functions) { +void CoreFunctions::RegisterFunctions(Catalog &catalog, CatalogTransaction transaction) { + auto functions = StaticFunctionDefinition::GetFunctionList(); for (idx_t i = 0; functions[i].name; i++) { auto &function = functions[i]; if (function.get_function || function.get_function_set) { @@ -47,8 +47,4 @@ static void RegisterFunctionList(Catalog &catalog, CatalogTransaction transactio } } -void FunctionList::RegisterFunctions(Catalog &catalog, CatalogTransaction transaction) { - RegisterFunctionList(catalog, transaction, FunctionList::GetInternalFunctionList()); -} - } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/function_list.cpp b/src/duckdb/src/core_functions/function_list.cpp similarity index 86% rename from src/duckdb/extension/core_functions/function_list.cpp rename to src/duckdb/src/core_functions/function_list.cpp index 53d96feb0..ca77e0309 100644 --- a/src/duckdb/extension/core_functions/function_list.cpp +++ b/src/duckdb/src/core_functions/function_list.cpp @@ -1,25 +1,25 @@ -#include "core_functions/function_list.hpp" -#include "core_functions/aggregate/algebraic_functions.hpp" -#include "core_functions/aggregate/distributive_functions.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" -#include "core_functions/aggregate/nested_functions.hpp" -#include "core_functions/aggregate/regression_functions.hpp" -#include "core_functions/scalar/bit_functions.hpp" -#include "core_functions/scalar/blob_functions.hpp" -#include "core_functions/scalar/date_functions.hpp" -#include "core_functions/scalar/enum_functions.hpp" -#include "core_functions/scalar/generic_functions.hpp" -#include "core_functions/scalar/list_functions.hpp" -#include "core_functions/scalar/map_functions.hpp" -#include "core_functions/scalar/math_functions.hpp" -#include "core_functions/scalar/operators_functions.hpp" -#include "core_functions/scalar/random_functions.hpp" -#include "core_functions/scalar/secret_functions.hpp" -#include "core_functions/scalar/string_functions.hpp" -#include "core_functions/scalar/struct_functions.hpp" -#include "core_functions/scalar/union_functions.hpp" -#include "core_functions/scalar/array_functions.hpp" -#include "core_functions/scalar/debug_functions.hpp" +#include "duckdb/core_functions/function_list.hpp" +#include "duckdb/core_functions/aggregate/algebraic_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/nested_functions.hpp" +#include "duckdb/core_functions/aggregate/regression_functions.hpp" +#include "duckdb/core_functions/scalar/bit_functions.hpp" +#include "duckdb/core_functions/scalar/blob_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/enum_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/math_functions.hpp" +#include "duckdb/core_functions/scalar/operators_functions.hpp" +#include "duckdb/core_functions/scalar/random_functions.hpp" +#include "duckdb/core_functions/scalar/secret_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/struct_functions.hpp" +#include "duckdb/core_functions/scalar/union_functions.hpp" +#include "duckdb/core_functions/scalar/array_functions.hpp" +#include "duckdb/core_functions/scalar/debug_functions.hpp" namespace duckdb { @@ -47,7 +47,7 @@ namespace duckdb { { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } // this list is generated by scripts/generate_functions.py -static const StaticFunctionDefinition core_functions[] = { +static const StaticFunctionDefinition internal_functions[] = { DUCKDB_SCALAR_FUNCTION(FactorialOperatorFun), DUCKDB_SCALAR_FUNCTION_SET(BitwiseAndFun), DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasAnyFunAlias), @@ -131,11 +131,11 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION(CosFun), DUCKDB_SCALAR_FUNCTION(CoshFun), DUCKDB_SCALAR_FUNCTION(CotFun), - DUCKDB_AGGREGATE_FUNCTION(CountIfFun), - DUCKDB_AGGREGATE_FUNCTION_ALIAS(CountifFun), DUCKDB_AGGREGATE_FUNCTION(CovarPopFun), DUCKDB_AGGREGATE_FUNCTION(CovarSampFun), + DUCKDB_SCALAR_FUNCTION(CreateSortKeyFun), DUCKDB_SCALAR_FUNCTION(CurrentDatabaseFun), + DUCKDB_SCALAR_FUNCTION(CurrentDateFun), DUCKDB_SCALAR_FUNCTION(CurrentQueryFun), DUCKDB_SCALAR_FUNCTION(CurrentSchemaFun), DUCKDB_SCALAR_FUNCTION(CurrentSchemasFun), @@ -172,6 +172,7 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(EpochUsFun), DUCKDB_SCALAR_FUNCTION_SET(EquiWidthBinsFun), DUCKDB_SCALAR_FUNCTION_SET(EraFun), + DUCKDB_SCALAR_FUNCTION(ErrorFun), DUCKDB_SCALAR_FUNCTION(EvenFun), DUCKDB_SCALAR_FUNCTION(ExpFun), DUCKDB_SCALAR_FUNCTION_ALIAS(FactorialFun), @@ -192,6 +193,7 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_ALIAS(GenRandomUuidFun), DUCKDB_SCALAR_FUNCTION_SET(GenerateSeriesFun), DUCKDB_SCALAR_FUNCTION(GetBitFun), + DUCKDB_SCALAR_FUNCTION(CurrentTimeFun), DUCKDB_SCALAR_FUNCTION(GetCurrentTimestampFun), DUCKDB_SCALAR_FUNCTION_SET_ALIAS(GradeUpFun), DUCKDB_SCALAR_FUNCTION_SET(GreatestFun), @@ -212,8 +214,8 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(ISODayOfWeekFun), DUCKDB_SCALAR_FUNCTION_SET(ISOYearFun), DUCKDB_SCALAR_FUNCTION(JaccardFun), - DUCKDB_SCALAR_FUNCTION_SET(JaroSimilarityFun), - DUCKDB_SCALAR_FUNCTION_SET(JaroWinklerSimilarityFun), + DUCKDB_SCALAR_FUNCTION(JaroSimilarityFun), + DUCKDB_SCALAR_FUNCTION(JaroWinklerSimilarityFun), DUCKDB_SCALAR_FUNCTION_SET(JulianDayFun), DUCKDB_AGGREGATE_FUNCTION(KahanSumFun), DUCKDB_AGGREGATE_FUNCTION(KurtosisFun), @@ -261,20 +263,24 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(MakeDateFun), DUCKDB_SCALAR_FUNCTION(MakeTimeFun), DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampFun), - DUCKDB_SCALAR_FUNCTION_SET(MakeTimestampNsFun), DUCKDB_SCALAR_FUNCTION(MapFun), DUCKDB_SCALAR_FUNCTION(MapConcatFun), + DUCKDB_SCALAR_FUNCTION(MapContainsFun), DUCKDB_SCALAR_FUNCTION(MapEntriesFun), DUCKDB_SCALAR_FUNCTION(MapExtractFun), DUCKDB_SCALAR_FUNCTION(MapFromEntriesFun), DUCKDB_SCALAR_FUNCTION(MapKeysFun), DUCKDB_SCALAR_FUNCTION(MapValuesFun), + DUCKDB_AGGREGATE_FUNCTION_SET(MaxFun), DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MaxByFun), + DUCKDB_SCALAR_FUNCTION_SET(MD5Fun), + DUCKDB_SCALAR_FUNCTION_SET(MD5NumberFun), DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MeanFun), DUCKDB_AGGREGATE_FUNCTION_SET(MedianFun), DUCKDB_SCALAR_FUNCTION_SET(MicrosecondsFun), DUCKDB_SCALAR_FUNCTION_SET(MillenniumFun), DUCKDB_SCALAR_FUNCTION_SET(MillisecondsFun), + DUCKDB_AGGREGATE_FUNCTION_SET(MinFun), DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(MinByFun), DUCKDB_SCALAR_FUNCTION_SET(MinutesFun), DUCKDB_SCALAR_FUNCTION_ALIAS(MismatchesFun), @@ -283,7 +289,6 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION_SET(MonthNameFun), DUCKDB_SCALAR_FUNCTION_SET(NanosecondsFun), DUCKDB_SCALAR_FUNCTION_SET(NextAfterFun), - DUCKDB_SCALAR_FUNCTION(NormalizedIntervalFun), DUCKDB_SCALAR_FUNCTION_ALIAS(NowFun), DUCKDB_SCALAR_FUNCTION_ALIAS(OrdFun), DUCKDB_SCALAR_FUNCTION_SET(ParseDirnameFun), @@ -304,6 +309,8 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION(RandomFun), DUCKDB_SCALAR_FUNCTION_SET(ListRangeFun), DUCKDB_SCALAR_FUNCTION_ALIAS(ReduceFun), + DUCKDB_SCALAR_FUNCTION(RegexpEscapeFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(RegexpSplitToArrayFun), DUCKDB_AGGREGATE_FUNCTION(RegrAvgxFun), DUCKDB_AGGREGATE_FUNCTION(RegrAvgyFun), DUCKDB_AGGREGATE_FUNCTION(RegrCountFun), @@ -320,26 +327,38 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION(RightFun), DUCKDB_SCALAR_FUNCTION(RightGraphemeFun), DUCKDB_SCALAR_FUNCTION_SET(RoundFun), + DUCKDB_SCALAR_FUNCTION(RowFun), DUCKDB_SCALAR_FUNCTION(RpadFun), DUCKDB_SCALAR_FUNCTION_SET(RtrimFun), DUCKDB_SCALAR_FUNCTION_SET(SecondsFun), DUCKDB_AGGREGATE_FUNCTION(StandardErrorOfTheMeanFun), DUCKDB_SCALAR_FUNCTION(SetBitFun), DUCKDB_SCALAR_FUNCTION(SetseedFun), + DUCKDB_SCALAR_FUNCTION_SET(SHA1Fun), + DUCKDB_SCALAR_FUNCTION_SET(SHA256Fun), DUCKDB_SCALAR_FUNCTION_SET(SignFun), DUCKDB_SCALAR_FUNCTION_SET(SignBitFun), DUCKDB_SCALAR_FUNCTION(SinFun), DUCKDB_SCALAR_FUNCTION(SinhFun), DUCKDB_AGGREGATE_FUNCTION(SkewnessFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(SplitFun), DUCKDB_SCALAR_FUNCTION(SqrtFun), DUCKDB_SCALAR_FUNCTION_ALIAS(StartsWithFun), DUCKDB_SCALAR_FUNCTION(StatsFun), DUCKDB_AGGREGATE_FUNCTION_ALIAS(StddevFun), DUCKDB_AGGREGATE_FUNCTION(StdDevPopFun), DUCKDB_AGGREGATE_FUNCTION(StdDevSampFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(StrSplitFun), + DUCKDB_SCALAR_FUNCTION_SET_ALIAS(StrSplitRegexFun), + DUCKDB_SCALAR_FUNCTION_SET(StrfTimeFun), DUCKDB_AGGREGATE_FUNCTION_SET(StringAggFun), + DUCKDB_SCALAR_FUNCTION(StringSplitFun), + DUCKDB_SCALAR_FUNCTION_SET(StringSplitRegexFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(StringToArrayFun), DUCKDB_SCALAR_FUNCTION_ALIAS(StrposFun), + DUCKDB_SCALAR_FUNCTION_SET(StrpTimeFun), DUCKDB_SCALAR_FUNCTION(StructInsertFun), + DUCKDB_SCALAR_FUNCTION(StructPackFun), DUCKDB_AGGREGATE_FUNCTION_SET(SumFun), DUCKDB_AGGREGATE_FUNCTION_SET(SumNoOverflowFun), DUCKDB_AGGREGATE_FUNCTION_ALIAS(SumkahanFun), @@ -368,10 +387,12 @@ static const StaticFunctionDefinition core_functions[] = { DUCKDB_SCALAR_FUNCTION(ToTimestampFun), DUCKDB_SCALAR_FUNCTION(ToWeeksFun), DUCKDB_SCALAR_FUNCTION(ToYearsFun), + DUCKDB_SCALAR_FUNCTION_ALIAS(TodayFun), DUCKDB_SCALAR_FUNCTION_ALIAS(TransactionTimestampFun), DUCKDB_SCALAR_FUNCTION(TranslateFun), DUCKDB_SCALAR_FUNCTION_SET(TrimFun), DUCKDB_SCALAR_FUNCTION_SET(TruncFun), + DUCKDB_SCALAR_FUNCTION_SET(TryStrpTimeFun), DUCKDB_SCALAR_FUNCTION(CurrentTransactionIdFun), DUCKDB_SCALAR_FUNCTION(TypeOfFun), DUCKDB_SCALAR_FUNCTION(UnbinFun), @@ -401,7 +422,7 @@ static const StaticFunctionDefinition core_functions[] = { }; const StaticFunctionDefinition *StaticFunctionDefinition::GetFunctionList() { - return core_functions; + return internal_functions; } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/lambda_functions.cpp b/src/duckdb/src/core_functions/lambda_functions.cpp similarity index 99% rename from src/duckdb/extension/core_functions/lambda_functions.cpp rename to src/duckdb/src/core_functions/lambda_functions.cpp index b5549914a..9a3a03102 100644 --- a/src/duckdb/extension/core_functions/lambda_functions.cpp +++ b/src/duckdb/src/core_functions/lambda_functions.cpp @@ -1,4 +1,4 @@ -#include "duckdb/function/lambda_functions.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/array/array_functions.cpp b/src/duckdb/src/core_functions/scalar/array/array_functions.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/array/array_functions.cpp rename to src/duckdb/src/core_functions/scalar/array/array_functions.cpp index af7d0ee03..347ffcbd1 100644 --- a/src/duckdb/extension/core_functions/scalar/array/array_functions.cpp +++ b/src/duckdb/src/core_functions/scalar/array/array_functions.cpp @@ -1,5 +1,5 @@ -#include "core_functions/scalar/array_functions.hpp" -#include "core_functions/array_kernels.hpp" +#include "duckdb/core_functions/scalar/array_functions.hpp" +#include "duckdb/core_functions/array_kernels.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { @@ -210,13 +210,9 @@ template static void AddArrayFoldFunction(ScalarFunctionSet &set, const LogicalType &type) { const auto array = LogicalType::ARRAY(type, optional_idx()); if (type.id() == LogicalTypeId::FLOAT) { - ScalarFunction function({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind); - BaseScalarFunction::SetReturnsError(function); - set.AddFunction(function); + set.AddFunction(ScalarFunction({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind)); } else if (type.id() == LogicalTypeId::DOUBLE) { - ScalarFunction function({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind); - BaseScalarFunction::SetReturnsError(function); - set.AddFunction(function); + set.AddFunction(ScalarFunction({array, array}, type, ArrayGenericFold, ArrayGenericBinaryBind)); } else { throw NotImplementedException("Array function not implemented for type %s", type.ToString()); } @@ -271,9 +267,6 @@ ScalarFunctionSet ArrayCrossProductFun::GetFunctions() { ScalarFunction({float_array, float_array}, float_array, ArrayFixedCombine)); set.AddFunction( ScalarFunction({double_array, double_array}, double_array, ArrayFixedCombine)); - for (auto &func : set.functions) { - BaseScalarFunction::SetReturnsError(func); - } return set; } diff --git a/src/duckdb/extension/core_functions/scalar/array/array_value.cpp b/src/duckdb/src/core_functions/scalar/array/array_value.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/array/array_value.cpp rename to src/duckdb/src/core_functions/scalar/array/array_value.cpp index e7f715f75..ac4f0bd24 100644 --- a/src/duckdb/extension/core_functions/scalar/array/array_value.cpp +++ b/src/duckdb/src/core_functions/scalar/array/array_value.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/array_functions.hpp" +#include "duckdb/core_functions/scalar/array_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/storage/statistics/array_stats.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -29,7 +29,7 @@ static void ArrayValueFunction(DataChunk &args, ExpressionState &state, Vector & // Ensure that the child has a validity mask of the correct size // The SetValue call below expects the validity mask to be initialized auto &child_validity = FlatVector::Validity(child); - child_validity.Resize(num_rows * num_columns); + child_validity.Resize(num_rows, num_rows * num_columns); } for (idx_t i = 0; i < num_rows; i++) { diff --git a/src/duckdb/extension/core_functions/scalar/bit/bitstring.cpp b/src/duckdb/src/core_functions/scalar/bit/bitstring.cpp similarity index 87% rename from src/duckdb/extension/core_functions/scalar/bit/bitstring.cpp rename to src/duckdb/src/core_functions/scalar/bit/bitstring.cpp index 0dbcb8ebc..9a9a5eae0 100644 --- a/src/duckdb/extension/core_functions/scalar/bit/bitstring.cpp +++ b/src/duckdb/src/core_functions/scalar/bit/bitstring.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/bit_functions.hpp" +#include "duckdb/core_functions/scalar/bit_functions.hpp" #include "duckdb/common/types/bit.hpp" #include "duckdb/common/types/cast_helpers.hpp" @@ -46,9 +46,6 @@ ScalarFunctionSet BitStringFun::GetFunctions() { ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER}, LogicalType::BIT, BitStringFunction)); bitstring.AddFunction( ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitStringFunction)); - for (auto &func : bitstring.functions) { - BaseScalarFunction::SetReturnsError(func); - } return bitstring; } @@ -67,10 +64,8 @@ struct GetBitOperator { }; ScalarFunction GetBitFun::GetFunction() { - ScalarFunction func({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::INTEGER, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::INTEGER, + ScalarFunction::BinaryFunction); } //===--------------------------------------------------------------------===// @@ -95,10 +90,8 @@ static void SetBitOperation(DataChunk &args, ExpressionState &state, Vector &res } ScalarFunction SetBitFun::GetFunction() { - ScalarFunction function({LogicalType::BIT, LogicalType::INTEGER, LogicalType::INTEGER}, LogicalType::BIT, - SetBitOperation); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BIT, LogicalType::INTEGER, LogicalType::INTEGER}, LogicalType::BIT, + SetBitOperation); } //===--------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/scalar/blob/base64.cpp b/src/duckdb/src/core_functions/scalar/blob/base64.cpp similarity index 88% rename from src/duckdb/extension/core_functions/scalar/blob/base64.cpp rename to src/duckdb/src/core_functions/scalar/blob/base64.cpp index fb903fa80..3545f3b56 100644 --- a/src/duckdb/extension/core_functions/scalar/blob/base64.cpp +++ b/src/duckdb/src/core_functions/scalar/blob/base64.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/blob_functions.hpp" +#include "duckdb/core_functions/scalar/blob_functions.hpp" #include "duckdb/common/types/blob.hpp" namespace duckdb { @@ -39,9 +39,7 @@ ScalarFunction ToBase64Fun::GetFunction() { } ScalarFunction FromBase64Fun::GetFunction() { - ScalarFunction function({LogicalType::VARCHAR}, LogicalType::BLOB, Base64DecodeFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, Base64DecodeFunction); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/create_sort_key.cpp b/src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp similarity index 89% rename from src/duckdb/src/function/scalar/create_sort_key.cpp rename to src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp index 1cb2acdde..5a6438094 100644 --- a/src/duckdb/src/function/scalar/create_sort_key.cpp +++ b/src/duckdb/src/core_functions/scalar/blob/create_sort_key.cpp @@ -1,11 +1,10 @@ -#include "duckdb/function/create_sort_key.hpp" - +#include "duckdb/core_functions/scalar/blob_functions.hpp" +#include "duckdb/execution/expression_executor.hpp" #include "duckdb/common/enums/order_type.hpp" #include "duckdb/common/radix.hpp" -#include "duckdb/function/scalar/generic_functions.hpp" -#include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" namespace duckdb { @@ -730,15 +729,6 @@ void CreateSortKeyHelpers::CreateSortKey(Vector &input, idx_t input_count, Order CreateSortKeyInternal(sort_key_data, modifiers, result, input_count); } -void CreateSortKeyHelpers::CreateSortKey(DataChunk &input, const vector &modifiers, Vector &result) { - vector> sort_key_data; - D_ASSERT(modifiers.size() == input.ColumnCount()); - for (idx_t r = 0; r < modifiers.size(); r++) { - sort_key_data.push_back(make_uniq(input.data[r], input.size(), modifiers[r])); - } - CreateSortKeyInternal(sort_key_data, modifiers, result, input.size()); -} - void CreateSortKeyHelpers::CreateSortKeyWithValidity(Vector &input, Vector &result, const OrderModifiers &modifiers, const idx_t count) { CreateSortKey(input, count, modifiers, result); @@ -772,65 +762,23 @@ static void CreateSortKeyFunction(DataChunk &args, ExpressionState &state, Vecto //===--------------------------------------------------------------------===// // Decode Sort Key //===--------------------------------------------------------------------===// -struct DecodeSortKeyVectorData { - DecodeSortKeyVectorData(const LogicalType &type, OrderModifiers modifiers) - : flip_bytes(modifiers.order_type == OrderType::DESCENDING) { - null_byte = SortKeyVectorData::NULL_FIRST_BYTE; - valid_byte = SortKeyVectorData::NULL_LAST_BYTE; - if (modifiers.null_type == OrderByNullType::NULLS_LAST) { - std::swap(null_byte, valid_byte); - } - - // NULLS FIRST/NULLS LAST passed in by the user are only respected at the top level - // within nested types NULLS LAST/NULLS FIRST is dependent on ASC/DESC order instead - // don't blame me this is what Postgres does - auto child_null_type = - modifiers.order_type == OrderType::ASCENDING ? OrderByNullType::NULLS_LAST : OrderByNullType::NULLS_FIRST; - OrderModifiers child_modifiers(modifiers.order_type, child_null_type); - switch (type.InternalType()) { - case PhysicalType::STRUCT: { - auto &children = StructType::GetChildTypes(type); - for (auto &child_type : children) { - child_data.emplace_back(child_type.second, child_modifiers); - } - break; - } - case PhysicalType::ARRAY: { - auto &child_type = ArrayType::GetChildType(type); - child_data.emplace_back(child_type, child_modifiers); - break; - } - case PhysicalType::LIST: { - auto &child_type = ListType::GetChildType(type); - child_data.emplace_back(child_type, child_modifiers); - break; - } - default: - break; - } - } - - data_t null_byte; - data_t valid_byte; - vector child_data; - bool flip_bytes; -}; - struct DecodeSortKeyData { - explicit DecodeSortKeyData(string_t &sort_key) - : data(const_data_ptr_cast(sort_key.GetData())), size(sort_key.GetSize()), position(0) { + explicit DecodeSortKeyData(OrderModifiers modifiers, string_t &sort_key) + : data(const_data_ptr_cast(sort_key.GetData())), size(sort_key.GetSize()), position(0), + flip_bytes(modifiers.order_type == OrderType::DESCENDING) { } const_data_ptr_t data; idx_t size; idx_t position; + bool flip_bytes; }; -void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx); template -void TemplatedDecodeSortKey(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void TemplatedDecodeSortKey(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx) { auto validity_byte = decode_data.data[decode_data.position]; decode_data.position++; @@ -839,11 +787,11 @@ void TemplatedDecodeSortKey(DecodeSortKeyData &decode_data, DecodeSortKeyVectorD FlatVector::Validity(result).SetInvalid(result_idx); return; } - idx_t increment = OP::Decode(decode_data.data + decode_data.position, result, result_idx, vector_data.flip_bytes); + idx_t increment = OP::Decode(decode_data.data + decode_data.position, result, result_idx, decode_data.flip_bytes); decode_data.position += increment; } -void DecodeSortKeyStruct(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void DecodeSortKeyStruct(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx) { // check if the top-level is valid or not auto validity_byte = decode_data.data[decode_data.position]; @@ -857,11 +805,11 @@ void DecodeSortKeyStruct(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData auto &child_entries = StructVector::GetEntries(result); for (idx_t c = 0; c < child_entries.size(); c++) { auto &child_entry = child_entries[c]; - DecodeSortKeyRecursive(decode_data, vector_data.child_data[c], *child_entry, result_idx); + DecodeSortKeyRecursive(decode_data, *vector_data.child_data[c], *child_entry, result_idx); } } -void DecodeSortKeyList(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void DecodeSortKeyList(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx) { // check if the top-level is valid or not auto validity_byte = decode_data.data[decode_data.position]; @@ -875,7 +823,7 @@ void DecodeSortKeyList(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData & // we don't know how many there will be // decode child elements until we encounter the list delimiter auto list_delimiter = SortKeyVectorData::LIST_DELIMITER; - if (vector_data.flip_bytes) { + if (decode_data.flip_bytes) { list_delimiter = ~list_delimiter; } auto list_data = FlatVector::GetData(result); @@ -891,7 +839,7 @@ void DecodeSortKeyList(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData & ListVector::Reserve(result, new_list_size); // now decode the entry - DecodeSortKeyRecursive(decode_data, vector_data.child_data[0], child_vector, new_list_size - 1); + DecodeSortKeyRecursive(decode_data, *vector_data.child_data[0], child_vector, new_list_size - 1); } // skip the list delimiter decode_data.position++; @@ -901,7 +849,7 @@ void DecodeSortKeyList(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData & ListVector::SetListSize(result, new_list_size); } -void DecodeSortKeyArray(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void DecodeSortKeyArray(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx) { // check if the top-level is valid or not auto validity_byte = decode_data.data[decode_data.position]; @@ -916,7 +864,7 @@ void DecodeSortKeyArray(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData // however the decoded data still contains a list delimiter // we use this delimiter to verify we successfully decoded the entire array auto list_delimiter = SortKeyVectorData::LIST_DELIMITER; - if (vector_data.flip_bytes) { + if (decode_data.flip_bytes) { list_delimiter = ~list_delimiter; } auto &child_vector = ArrayVector::GetEntry(result); @@ -932,7 +880,7 @@ void DecodeSortKeyArray(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData break; } // now decode the entry - DecodeSortKeyRecursive(decode_data, vector_data.child_data[0], child_vector, child_start + found_elements - 1); + DecodeSortKeyRecursive(decode_data, *vector_data.child_data[0], child_vector, child_start + found_elements - 1); } // skip the list delimiter decode_data.position++; @@ -942,7 +890,7 @@ void DecodeSortKeyArray(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData } } -void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, DecodeSortKeyVectorData &vector_data, Vector &result, +void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, SortKeyVectorData &vector_data, Vector &result, idx_t result_idx) { switch (result.GetType().InternalType()) { case PhysicalType::BOOL: @@ -988,7 +936,7 @@ void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, DecodeSortKeyVectorD TemplatedDecodeSortKey>(decode_data, vector_data, result, result_idx); break; case PhysicalType::VARCHAR: - if (result.GetType().id() == LogicalTypeId::VARCHAR) { + if (vector_data.vec.GetType().id() == LogicalTypeId::VARCHAR) { TemplatedDecodeSortKey(decode_data, vector_data, result, result_idx); } else { TemplatedDecodeSortKey(decode_data, vector_data, result, result_idx); @@ -1004,28 +952,17 @@ void DecodeSortKeyRecursive(DecodeSortKeyData &decode_data, DecodeSortKeyVectorD DecodeSortKeyArray(decode_data, vector_data, result, result_idx); break; default: - throw NotImplementedException("Unsupported type %s in DecodeSortKey", result.GetType()); + throw NotImplementedException("Unsupported type %s in DecodeSortKey", vector_data.vec.GetType()); } } void CreateSortKeyHelpers::DecodeSortKey(string_t sort_key, Vector &result, idx_t result_idx, OrderModifiers modifiers) { - DecodeSortKeyVectorData sort_key_data(result.GetType(), modifiers); - DecodeSortKeyData decode_data(sort_key); + SortKeyVectorData sort_key_data(result, 0, modifiers); + DecodeSortKeyData decode_data(modifiers, sort_key); DecodeSortKeyRecursive(decode_data, sort_key_data, result, result_idx); } -void CreateSortKeyHelpers::DecodeSortKey(string_t sort_key, DataChunk &result, idx_t result_idx, - const vector &modifiers) { - DecodeSortKeyData decode_data(sort_key); - D_ASSERT(modifiers.size() == result.ColumnCount()); - for (idx_t c = 0; c < result.ColumnCount(); c++) { - auto &vec = result.data[c]; - DecodeSortKeyVectorData vector_data(vec.GetType(), modifiers[c]); - DecodeSortKeyRecursive(decode_data, vector_data, vec, result_idx); - } -} - ScalarFunction CreateSortKeyFun::GetFunction() { ScalarFunction sort_key_function("create_sort_key", {LogicalType::ANY}, LogicalType::BLOB, CreateSortKeyFunction, CreateSortKeyBind); diff --git a/src/duckdb/extension/core_functions/scalar/blob/encode.cpp b/src/duckdb/src/core_functions/scalar/blob/encode.cpp similarity index 86% rename from src/duckdb/extension/core_functions/scalar/blob/encode.cpp rename to src/duckdb/src/core_functions/scalar/blob/encode.cpp index 66cedb0b5..ff11f2f6c 100644 --- a/src/duckdb/extension/core_functions/scalar/blob/encode.cpp +++ b/src/duckdb/src/core_functions/scalar/blob/encode.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/blob_functions.hpp" +#include "duckdb/core_functions/scalar/blob_functions.hpp" #include "utf8proc_wrapper.hpp" #include "duckdb/common/exception/conversion_exception.hpp" @@ -34,9 +34,7 @@ ScalarFunction EncodeFun::GetFunction() { } ScalarFunction DecodeFun::GetFunction() { - ScalarFunction function({LogicalType::BLOB}, LogicalType::VARCHAR, DecodeFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BLOB}, LogicalType::VARCHAR, DecodeFunction); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/date/age.cpp b/src/duckdb/src/core_functions/scalar/date/age.cpp similarity index 77% rename from src/duckdb/extension/core_functions/scalar/date/age.cpp rename to src/duckdb/src/core_functions/scalar/date/age.cpp index cf7281f08..f8db919fc 100644 --- a/src/duckdb/extension/core_functions/scalar/date/age.cpp +++ b/src/duckdb/src/core_functions/scalar/date/age.cpp @@ -1,27 +1,21 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/types/interval.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" #include "duckdb/common/vector_operations/binary_executor.hpp" -#include "duckdb/transaction/meta_transaction.hpp" namespace duckdb { static void AgeFunctionStandard(DataChunk &input, ExpressionState &state, Vector &result) { D_ASSERT(input.ColumnCount() == 1); - // Subtract argument from current_date (at midnight) - // Theoretically, this should be TZ-sensitive, but since we have to be able to handle - // plain TZ when ICU is not loaded, we implement this in UTC (like everything else) - // To get the PG behaviour, we overload these functions in ICU for TSTZ arguments. - auto current_date = Timestamp::FromDatetime( - Timestamp::GetDate(MetaTransaction::Get(state.GetContext()).start_timestamp), dtime_t(0)); + auto current_timestamp = Timestamp::GetCurrentTimestamp(); UnaryExecutor::ExecuteWithNulls(input.data[0], result, input.size(), [&](timestamp_t input, ValidityMask &mask, idx_t idx) { if (Timestamp::IsFinite(input)) { - return Interval::GetAge(current_date, input); + return Interval::GetAge(current_timestamp, input); } else { mask.SetInvalid(idx); return interval_t(); diff --git a/src/duckdb/src/core_functions/scalar/date/current.cpp b/src/duckdb/src/core_functions/scalar/date/current.cpp new file mode 100644 index 000000000..159575315 --- /dev/null +++ b/src/duckdb/src/core_functions/scalar/date/current.cpp @@ -0,0 +1,54 @@ +#include "duckdb/core_functions/scalar/date_functions.hpp" + +#include "duckdb/common/exception.hpp" +#include "duckdb/common/types/timestamp.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/transaction/meta_transaction.hpp" + +namespace duckdb { + +static timestamp_t GetTransactionTimestamp(ExpressionState &state) { + return MetaTransaction::Get(state.GetContext()).start_timestamp; +} + +static void CurrentTimeFunction(DataChunk &input, ExpressionState &state, Vector &result) { + D_ASSERT(input.ColumnCount() == 0); + auto val = Value::TIME(Timestamp::GetTime(GetTransactionTimestamp(state))); + result.Reference(val); +} + +static void CurrentDateFunction(DataChunk &input, ExpressionState &state, Vector &result) { + D_ASSERT(input.ColumnCount() == 0); + + auto val = Value::DATE(Timestamp::GetDate(GetTransactionTimestamp(state))); + result.Reference(val); +} + +static void CurrentTimestampFunction(DataChunk &input, ExpressionState &state, Vector &result) { + D_ASSERT(input.ColumnCount() == 0); + + auto val = Value::TIMESTAMPTZ(GetTransactionTimestamp(state)); + result.Reference(val); +} + +ScalarFunction CurrentTimeFun::GetFunction() { + ScalarFunction current_time({}, LogicalType::TIME, CurrentTimeFunction); + current_time.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; + return current_time; +} + +ScalarFunction CurrentDateFun::GetFunction() { + ScalarFunction current_date({}, LogicalType::DATE, CurrentDateFunction); + current_date.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; + return current_date; +} + +ScalarFunction GetCurrentTimestampFun::GetFunction() { + ScalarFunction current_timestamp({}, LogicalType::TIMESTAMP_TZ, CurrentTimestampFunction); + current_timestamp.stability = FunctionStability::CONSISTENT_WITHIN_QUERY; + return current_timestamp; +} + +} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/date/date_diff.cpp b/src/duckdb/src/core_functions/scalar/date/date_diff.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/date/date_diff.cpp rename to src/duckdb/src/core_functions/scalar/date/date_diff.cpp index c0e4ba1da..36376a2b5 100644 --- a/src/duckdb/extension/core_functions/scalar/date/date_diff.cpp +++ b/src/duckdb/src/core_functions/scalar/date/date_diff.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/enums/date_part_specifier.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/subtract.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/date/date_part.cpp b/src/duckdb/src/core_functions/scalar/date/date_part.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/date/date_part.cpp rename to src/duckdb/src/core_functions/scalar/date/date_part.cpp index 1aeb4550c..ebe65f788 100644 --- a/src/duckdb/extension/core_functions/scalar/date/date_part.cpp +++ b/src/duckdb/src/core_functions/scalar/date/date_part.cpp @@ -1,19 +1,18 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/common/enum_util.hpp" #include "duckdb/common/enums/date_part_specifier.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/exception/conversion_exception.hpp" -#include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/string_util.hpp" +#include "duckdb/common/enum_util.hpp" #include "duckdb/common/types/date.hpp" -#include "duckdb/common/types/date_lookup_cache.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/common/types/date_lookup_cache.hpp" namespace duckdb { @@ -401,7 +400,7 @@ struct DatePart { struct EpochMillisOperator { template static inline TR Operation(TA input) { - return Cast::Operation(input); + return Timestamp::GetEpochMs(input); } template @@ -1063,7 +1062,7 @@ int64_t DatePart::EpochMicrosecondsOperator::Operation(interval_t input) { template <> int64_t DatePart::EpochMillisOperator::Operation(timestamp_t input) { D_ASSERT(Timestamp::IsFinite(input)); - return Cast::Operation(input).value; + return Timestamp::GetEpochMs(input); } template <> @@ -1705,9 +1704,6 @@ ScalarFunctionSet GetGenericDatePartFunction(scalar_function_t date_func, scalar operator_set.AddFunction(ScalarFunction({LogicalType::TIMESTAMP}, LogicalType::BIGINT, std::move(ts_func), nullptr, nullptr, ts_stats, DATE_CACHE)); operator_set.AddFunction(ScalarFunction({LogicalType::INTERVAL}, LogicalType::BIGINT, std::move(interval_func))); - for (auto &func : operator_set.functions) { - BaseScalarFunction::SetReturnsError(func); - } return operator_set; } @@ -2022,11 +2018,7 @@ ScalarFunctionSet QuarterFun::GetFunctions() { } ScalarFunctionSet DayOfWeekFun::GetFunctions() { - auto set = GetDatePartFunction(); - for (auto &func : set.functions) { - BaseScalarFunction::SetReturnsError(func); - } - return set; + return GetDatePartFunction(); } ScalarFunctionSet ISODayOfWeekFun::GetFunctions() { @@ -2053,14 +2045,9 @@ ScalarFunctionSet TimezoneFun::GetFunctions() { auto operator_set = GetDatePartFunction(); // PG also defines timezone(INTERVAL, TIME_TZ) => TIME_TZ - ScalarFunction function({LogicalType::INTERVAL, LogicalType::TIME_TZ}, LogicalType::TIME_TZ, - DatePart::TimezoneOperator::BinaryFunction); - - operator_set.AddFunction(function); - - for (auto &func : operator_set.functions) { - BaseScalarFunction::SetReturnsError(func); - } + operator_set.AddFunction( + ScalarFunction({LogicalType::INTERVAL, LogicalType::TIME_TZ}, LogicalType::TIME_TZ, + DatePart::TimezoneOperator::BinaryFunction)); return operator_set; } @@ -2077,19 +2064,6 @@ ScalarFunctionSet EpochFun::GetFunctions() { return GetTimePartFunction(LogicalType::DOUBLE); } -struct GetEpochNanosOperator { - static int64_t Operation(timestamp_ns_t timestamp) { - return Timestamp::GetEpochNanoSeconds(timestamp); - } -}; - -static void ExecuteGetNanosFromTimestampNs(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - auto func = GetEpochNanosOperator::Operation; - UnaryExecutor::Execute(input.data[0], result, input.size(), func); -} - ScalarFunctionSet EpochNsFun::GetFunctions() { using OP = DatePart::EpochNanosecondsOperator; auto operator_set = GetTimePartFunction(); @@ -2099,9 +2073,6 @@ ScalarFunctionSet EpochNsFun::GetFunctions() { auto tstz_stats = OP::template PropagateStatistics; operator_set.AddFunction( ScalarFunction({LogicalType::TIMESTAMP_TZ}, LogicalType::BIGINT, tstz_func, nullptr, nullptr, tstz_stats)); - - operator_set.AddFunction( - ScalarFunction({LogicalType::TIMESTAMP_NS}, LogicalType::BIGINT, ExecuteGetNanosFromTimestampNs)); return operator_set; } @@ -2253,10 +2224,6 @@ ScalarFunctionSet DatePartFun::GetFunctions() { date_part.AddFunction(StructDatePart::GetFunction(LogicalType::INTERVAL)); date_part.AddFunction(StructDatePart::GetFunction(LogicalType::TIME_TZ)); - for (auto &func : date_part.functions) { - BaseScalarFunction::SetReturnsError(func); - } - return date_part; } diff --git a/src/duckdb/extension/core_functions/scalar/date/date_sub.cpp b/src/duckdb/src/core_functions/scalar/date/date_sub.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/date/date_sub.cpp rename to src/duckdb/src/core_functions/scalar/date/date_sub.cpp index acfb2c796..6d4c4e249 100644 --- a/src/duckdb/extension/core_functions/scalar/date/date_sub.cpp +++ b/src/duckdb/src/core_functions/scalar/date/date_sub.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/enums/date_part_specifier.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/subtract.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp b/src/duckdb/src/core_functions/scalar/date/date_trunc.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp rename to src/duckdb/src/core_functions/scalar/date/date_trunc.cpp index cb54e30de..6e5bcc700 100644 --- a/src/duckdb/extension/core_functions/scalar/date/date_trunc.cpp +++ b/src/duckdb/src/core_functions/scalar/date/date_trunc.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/enums/date_part_specifier.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/cast_operators.hpp" @@ -728,9 +728,6 @@ ScalarFunctionSet DateTruncFun::GetFunctions() { DateTruncFunction, DateTruncBind)); date_trunc.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTERVAL}, LogicalType::INTERVAL, DateTruncFunction)); - for (auto &func : date_trunc.functions) { - BaseScalarFunction::SetReturnsError(func); - } return date_trunc; } diff --git a/src/duckdb/extension/core_functions/scalar/date/epoch.cpp b/src/duckdb/src/core_functions/scalar/date/epoch.cpp similarity index 67% rename from src/duckdb/extension/core_functions/scalar/date/epoch.cpp rename to src/duckdb/src/core_functions/scalar/date/epoch.cpp index cda3232a4..0944335de 100644 --- a/src/duckdb/extension/core_functions/scalar/date/epoch.cpp +++ b/src/duckdb/src/core_functions/scalar/date/epoch.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" @@ -11,7 +11,7 @@ struct EpochSecOperator { static RESULT_TYPE Operation(INPUT_TYPE sec) { int64_t result; if (!TryCast::Operation(sec * Interval::MICROS_PER_SEC, result)) { - throw ConversionException("Epoch seconds out of range for TIMESTAMP WITH TIME ZONE"); + throw ConversionException("Could not convert epoch seconds to TIMESTAMP WITH TIME ZONE"); } return timestamp_t(result); } @@ -28,23 +28,6 @@ ScalarFunction ToTimestampFun::GetFunction() { return ScalarFunction({LogicalType::DOUBLE}, LogicalType::TIMESTAMP_TZ, EpochSecFunction); } -struct NormalizedIntervalOperator { - template - static RESULT_TYPE Operation(INPUT_TYPE input) { - return input.Normalize(); - } -}; - -static void NormalizedIntervalFunction(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - UnaryExecutor::Execute(input.data[0], result, input.size()); -} - -ScalarFunction NormalizedIntervalFun::GetFunction() { - return ScalarFunction({LogicalType::INTERVAL}, LogicalType::INTERVAL, NormalizedIntervalFunction); -} - struct TimeTZSortKeyOperator { template static RESULT_TYPE Operation(INPUT_TYPE input) { @@ -61,4 +44,5 @@ static void TimeTZSortKeyFunction(DataChunk &input, ExpressionState &state, Vect ScalarFunction TimeTZSortKeyFun::GetFunction() { return ScalarFunction({LogicalType::TIME_TZ}, LogicalType::UBIGINT, TimeTZSortKeyFunction); } + } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/date/make_date.cpp b/src/duckdb/src/core_functions/scalar/date/make_date.cpp similarity index 77% rename from src/duckdb/extension/core_functions/scalar/date/make_date.cpp rename to src/duckdb/src/core_functions/scalar/date/make_date.cpp index 0fe00a920..1ef81e376 100644 --- a/src/duckdb/extension/core_functions/scalar/date/make_date.cpp +++ b/src/duckdb/src/core_functions/scalar/date/make_date.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/types/date.hpp" #include "duckdb/common/types/time.hpp" @@ -11,11 +11,6 @@ namespace duckdb { -static void MakeDateFromEpoch(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - result.Reinterpret(input.data[0]); -} - struct MakeDateOperator { template static RESULT_TYPE Operation(YYYY yyyy, MM mm, DD dd) { @@ -102,12 +97,8 @@ struct MakeTimestampOperator { } template - static RESULT_TYPE Operation(T value) { - const auto result = RESULT_TYPE(value); - if (!Timestamp::IsFinite(result)) { - throw ConversionException("Timestamp microseconds out of range: %ld", value); - } - return RESULT_TYPE(value); + static RESULT_TYPE Operation(T micros) { + return timestamp_t(micros); } }; @@ -125,18 +116,8 @@ static void ExecuteMakeTimestamp(DataChunk &input, ExpressionState &state, Vecto SenaryExecutor::Execute(input, result, func); } -template -static void ExecuteMakeTimestampNs(DataChunk &input, ExpressionState &state, Vector &result) { - D_ASSERT(input.ColumnCount() == 1); - - auto func = MakeTimestampOperator::Operation; - UnaryExecutor::Execute(input.data[0], result, input.size(), func); - return; -} - ScalarFunctionSet MakeDateFun::GetFunctions() { ScalarFunctionSet make_date("make_date"); - make_date.AddFunction(ScalarFunction({LogicalType::INTEGER}, LogicalType::DATE, MakeDateFromEpoch)); make_date.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::DATE, ExecuteMakeDate)); @@ -144,17 +125,12 @@ ScalarFunctionSet MakeDateFun::GetFunctions() { {"year", LogicalType::BIGINT}, {"month", LogicalType::BIGINT}, {"day", LogicalType::BIGINT}}; make_date.AddFunction( ScalarFunction({LogicalType::STRUCT(make_date_children)}, LogicalType::DATE, ExecuteStructMakeDate)); - for (auto &func : make_date.functions) { - BaseScalarFunction::SetReturnsError(func); - } return make_date; } ScalarFunction MakeTimeFun::GetFunction() { - ScalarFunction function({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::DOUBLE}, LogicalType::TIME, - ExecuteMakeTime); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::DOUBLE}, LogicalType::TIME, + ExecuteMakeTime); } ScalarFunctionSet MakeTimestampFun::GetFunctions() { @@ -164,17 +140,6 @@ ScalarFunctionSet MakeTimestampFun::GetFunctions() { LogicalType::TIMESTAMP, ExecuteMakeTimestamp)); operator_set.AddFunction( ScalarFunction({LogicalType::BIGINT}, LogicalType::TIMESTAMP, ExecuteMakeTimestamp)); - - for (auto &func : operator_set.functions) { - BaseScalarFunction::SetReturnsError(func); - } - return operator_set; -} - -ScalarFunctionSet MakeTimestampNsFun::GetFunctions() { - ScalarFunctionSet operator_set("make_timestamp_ns"); - operator_set.AddFunction( - ScalarFunction({LogicalType::BIGINT}, LogicalType::TIMESTAMP_NS, ExecuteMakeTimestampNs)); return operator_set; } diff --git a/src/duckdb/src/function/scalar/date/strftime.cpp b/src/duckdb/src/core_functions/scalar/date/strftime.cpp similarity index 98% rename from src/duckdb/src/function/scalar/date/strftime.cpp rename to src/duckdb/src/core_functions/scalar/date/strftime.cpp index 32222f191..8aa34d325 100644 --- a/src/duckdb/src/function/scalar/date/strftime.cpp +++ b/src/duckdb/src/core_functions/scalar/date/strftime.cpp @@ -4,7 +4,7 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" -#include "duckdb/function/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include #include @@ -94,7 +94,7 @@ static void StrfTimeFunctionTimestampNS(DataChunk &args, ExpressionState &state, } ScalarFunctionSet StrfTimeFun::GetFunctions() { - ScalarFunctionSet strftime("strftime"); + ScalarFunctionSet strftime; strftime.AddFunction(ScalarFunction({LogicalType::DATE, LogicalType::VARCHAR}, LogicalType::VARCHAR, StrfTimeFunctionDate, StrfTimeBindFunction)); @@ -296,25 +296,23 @@ struct StrpTimeFunction { }; ScalarFunctionSet StrpTimeFun::GetFunctions() { - ScalarFunctionSet strptime("strptime"); + ScalarFunctionSet strptime; const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::TIMESTAMP, StrpTimeFunction::Parse, StrpTimeFunction::Bind); fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(fun); strptime.AddFunction(fun); fun = ScalarFunction({LogicalType::VARCHAR, list_type}, LogicalType::TIMESTAMP, StrpTimeFunction::Parse, StrpTimeFunction::Bind); - BaseScalarFunction::SetReturnsError(fun); fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; strptime.AddFunction(fun); return strptime; } ScalarFunctionSet TryStrpTimeFun::GetFunctions() { - ScalarFunctionSet try_strptime("try_strptime"); + ScalarFunctionSet try_strptime; const auto list_type = LogicalType::LIST(LogicalType::VARCHAR); auto fun = ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::TIMESTAMP, diff --git a/src/duckdb/extension/core_functions/scalar/date/time_bucket.cpp b/src/duckdb/src/core_functions/scalar/date/time_bucket.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/date/time_bucket.cpp rename to src/duckdb/src/core_functions/scalar/date/time_bucket.cpp index 726d6b54f..31ae5f539 100644 --- a/src/duckdb/extension/core_functions/scalar/date/time_bucket.cpp +++ b/src/duckdb/src/core_functions/scalar/date/time_bucket.cpp @@ -9,7 +9,7 @@ #include "duckdb/common/vector_operations/binary_executor.hpp" #include "duckdb/common/vector_operations/ternary_executor.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" namespace duckdb { @@ -364,9 +364,6 @@ ScalarFunctionSet TimeBucketFun::GetFunctions() { LogicalType::DATE, TimeBucketOriginFunction)); time_bucket.AddFunction(ScalarFunction({LogicalType::INTERVAL, LogicalType::TIMESTAMP, LogicalType::TIMESTAMP}, LogicalType::TIMESTAMP, TimeBucketOriginFunction)); - for (auto &func : time_bucket.functions) { - BaseScalarFunction::SetReturnsError(func); - } return time_bucket; } diff --git a/src/duckdb/extension/core_functions/scalar/date/to_interval.cpp b/src/duckdb/src/core_functions/scalar/date/to_interval.cpp similarity index 63% rename from src/duckdb/extension/core_functions/scalar/date/to_interval.cpp rename to src/duckdb/src/core_functions/scalar/date/to_interval.cpp index c8d508883..e16111f8e 100644 --- a/src/duckdb/extension/core_functions/scalar/date/to_interval.cpp +++ b/src/duckdb/src/core_functions/scalar/date/to_interval.cpp @@ -1,8 +1,8 @@ -#include "core_functions/scalar/date_functions.hpp" +#include "duckdb/core_functions/scalar/date_functions.hpp" #include "duckdb/common/types/interval.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/multiply.hpp" -#include "duckdb/function/to_interval.hpp" +#include "duckdb/core_functions/to_interval.hpp" namespace duckdb { @@ -165,94 +165,68 @@ struct ToMicroSecondsOperator { }; ScalarFunction ToMillenniaFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToCenturiesFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToDecadesFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToYearsFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToQuartersFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToMonthsFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToWeeksFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToDaysFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToHoursFun::GetFunction() { - ScalarFunction function({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToMinutesFun::GetFunction() { - ScalarFunction function({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToSecondsFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToMillisecondsFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } ScalarFunction ToMicrosecondsFun::GetFunction() { - ScalarFunction function({LogicalType::BIGINT}, LogicalType::INTERVAL, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::BIGINT}, LogicalType::INTERVAL, + ScalarFunction::UnaryFunction); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/debug/vector_type.cpp b/src/duckdb/src/core_functions/scalar/debug/vector_type.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/debug/vector_type.cpp rename to src/duckdb/src/core_functions/scalar/debug/vector_type.cpp index 627d7ac28..625273cde 100644 --- a/src/duckdb/extension/core_functions/scalar/debug/vector_type.cpp +++ b/src/duckdb/src/core_functions/scalar/debug/vector_type.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/debug_functions.hpp" +#include "duckdb/core_functions/scalar/debug_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/enum/enum_functions.cpp b/src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/enum/enum_functions.cpp rename to src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp index a10ec381c..ddf07c3d1 100644 --- a/src/duckdb/extension/core_functions/scalar/enum/enum_functions.cpp +++ b/src/duckdb/src/core_functions/scalar/enum/enum_functions.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/enum_functions.hpp" +#include "duckdb/core_functions/scalar/enum_functions.hpp" namespace duckdb { @@ -56,7 +56,12 @@ static void EnumRangeBoundaryFunction(DataChunk &input, ExpressionState &state, for (idx_t i = start; i < end; i++) { enum_values.emplace_back(enum_vector.GetValue(i)); } - auto val = Value::LIST(LogicalType::VARCHAR, enum_values); + Value val; + if (enum_values.empty()) { + val = Value::EMPTYLIST(LogicalType::VARCHAR); + } else { + val = Value::LIST(enum_values); + } result.Reference(val); } diff --git a/src/duckdb/extension/core_functions/scalar/generic/alias.cpp b/src/duckdb/src/core_functions/scalar/generic/alias.cpp similarity index 75% rename from src/duckdb/extension/core_functions/scalar/generic/alias.cpp rename to src/duckdb/src/core_functions/scalar/generic/alias.cpp index 4edadcaaf..e7065ba5b 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/alias.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/alias.cpp @@ -1,11 +1,11 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { static void AliasFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &func_expr = state.expr.Cast(); - Value v(state.expr.GetAlias().empty() ? func_expr.children[0]->GetName() : state.expr.GetAlias()); + Value v(state.expr.alias.empty() ? func_expr.children[0]->GetName() : state.expr.alias); result.Reference(v); } diff --git a/src/duckdb/extension/core_functions/scalar/generic/can_implicitly_cast.cpp b/src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/generic/can_implicitly_cast.cpp rename to src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp index 5db38d601..37b25d489 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/can_implicitly_cast.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/can_implicitly_cast.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/function/cast/cast_function_set.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/generic/current_setting.cpp b/src/duckdb/src/core_functions/scalar/generic/current_setting.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/generic/current_setting.cpp rename to src/duckdb/src/core_functions/scalar/generic/current_setting.cpp index b983b27cd..43bbdcfbe 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/current_setting.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/current_setting.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/main/database.hpp" #include "duckdb/main/client_context.hpp" diff --git a/src/duckdb/src/function/scalar/generic/error.cpp b/src/duckdb/src/core_functions/scalar/generic/error.cpp similarity index 84% rename from src/duckdb/src/function/scalar/generic/error.cpp rename to src/duckdb/src/core_functions/scalar/generic/error.cpp index 2d42cfced..e90473784 100644 --- a/src/duckdb/src/function/scalar/generic/error.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/error.cpp @@ -1,5 +1,4 @@ -#include "duckdb/function/scalar/generic_functions.hpp" - +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include namespace duckdb { @@ -16,7 +15,6 @@ ScalarFunction ErrorFun::GetFunction() { ScalarFunction::UnaryFunction); // Set the function with side effects to avoid the optimization. fun.stability = FunctionStability::VOLATILE; - BaseScalarFunction::SetReturnsError(fun); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/generic/hash.cpp b/src/duckdb/src/core_functions/scalar/generic/hash.cpp similarity index 88% rename from src/duckdb/extension/core_functions/scalar/generic/hash.cpp rename to src/duckdb/src/core_functions/scalar/generic/hash.cpp index 184919447..b99e97049 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/hash.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/hash.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/generic/least.cpp b/src/duckdb/src/core_functions/scalar/generic/least.cpp similarity index 90% rename from src/duckdb/extension/core_functions/scalar/generic/least.cpp rename to src/duckdb/src/core_functions/scalar/generic/least.cpp index 40a943101..d91b49392 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/least.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/least.cpp @@ -1,26 +1,10 @@ #include "duckdb/common/operator/comparison_operators.hpp" -#include "core_functions/scalar/generic_functions.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { -struct LeastOp { - using OP = LessThan; - - static OrderByNullType NullOrdering() { - return OrderByNullType::NULLS_LAST; - } -}; - -struct GreaterOp { - using OP = GreaterThan; - - static OrderByNullType NullOrdering() { - return OrderByNullType::NULLS_FIRST; - } -}; - template struct LeastOperator { template @@ -30,8 +14,8 @@ struct LeastOperator { }; struct LeastGreatestSortKeyState : public FunctionLocalState { - explicit LeastGreatestSortKeyState(idx_t column_count, OrderByNullType null_ordering) - : intermediate(LogicalType::BLOB), modifiers(OrderType::ASCENDING, null_ordering) { + explicit LeastGreatestSortKeyState(idx_t column_count) + : intermediate(LogicalType::BLOB), modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST) { vector types; // initialize sort key chunk for (idx_t i = 0; i < column_count; i++) { @@ -45,10 +29,9 @@ struct LeastGreatestSortKeyState : public FunctionLocalState { OrderModifiers modifiers; }; -template unique_ptr LeastGreatestSortKeyInit(ExpressionState &state, const BoundFunctionExpression &expr, FunctionData *bind_data) { - return make_uniq(expr.children.size(), OP::NullOrdering()); + return make_uniq(expr.children.size()); } template @@ -172,14 +155,14 @@ static void LeastGreatestFunction(DataChunk &args, ExpressionState &state, Vecto result.SetVectorType(result_type); } -template +template unique_ptr BindLeastGreatest(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { LogicalType child_type = ExpressionBinder::GetExpressionReturnType(*arguments[0]); for (idx_t i = 1; i < arguments.size(); i++) { auto arg_type = ExpressionBinder::GetExpressionReturnType(*arguments[i]); if (!LogicalType::TryGetMaxLogicalType(context, child_type, arg_type, child_type)) { - throw BinderException(arguments[i]->GetQueryLocation(), + throw BinderException(arguments[i]->query_location, "Cannot combine types of %s and %s - an explicit cast is required", child_type.ToString(), arg_type.ToString()); } @@ -196,9 +179,7 @@ unique_ptr BindLeastGreatest(ClientContext &context, ScalarFunctio default: break; } - using OP = typename LEAST_GREATER_OP::OP; switch (child_type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::BOOL: case PhysicalType::INT8: bound_function.function = LeastGreatestFunction; @@ -221,11 +202,10 @@ unique_ptr BindLeastGreatest(ClientContext &context, ScalarFunctio case PhysicalType::VARCHAR: bound_function.function = LeastGreatestFunction>; break; -#endif default: // fallback with sort keys bound_function.function = LeastGreatestFunction; - bound_function.init_local_state = LeastGreatestSortKeyInit; + bound_function.init_local_state = LeastGreatestSortKeyInit; break; } bound_function.arguments[0] = child_type; @@ -249,11 +229,11 @@ static ScalarFunctionSet GetLeastGreatestFunctions() { } ScalarFunctionSet LeastFun::GetFunctions() { - return GetLeastGreatestFunctions(); + return GetLeastGreatestFunctions(); } ScalarFunctionSet GreatestFun::GetFunctions() { - return GetLeastGreatestFunctions(); + return GetLeastGreatestFunctions(); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/generic/stats.cpp b/src/duckdb/src/core_functions/scalar/generic/stats.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/generic/stats.cpp rename to src/duckdb/src/core_functions/scalar/generic/stats.cpp index ad3f4cd09..f547ca78d 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/stats.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/stats.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/generic/system_functions.cpp b/src/duckdb/src/core_functions/scalar/generic/system_functions.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/generic/system_functions.cpp rename to src/duckdb/src/core_functions/scalar/generic/system_functions.cpp index 5e4251c0b..97fb3fbdf 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/system_functions.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/system_functions.cpp @@ -1,5 +1,5 @@ #include "duckdb/catalog/catalog_search_path.hpp" -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/main/database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp b/src/duckdb/src/core_functions/scalar/generic/typeof.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/generic/typeof.cpp rename to src/duckdb/src/core_functions/scalar/generic/typeof.cpp index 1f7caef84..b74a0cef5 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/typeof.cpp +++ b/src/duckdb/src/core_functions/scalar/generic/typeof.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/list/array_slice.cpp b/src/duckdb/src/core_functions/scalar/list/array_slice.cpp similarity index 73% rename from src/duckdb/extension/core_functions/scalar/list/array_slice.cpp rename to src/duckdb/src/core_functions/scalar/list/array_slice.cpp index 0962b3c2e..3cc0960d9 100644 --- a/src/duckdb/extension/core_functions/scalar/list/array_slice.cpp +++ b/src/duckdb/src/core_functions/scalar/list/array_slice.cpp @@ -1,10 +1,9 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/common/swap.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" @@ -59,68 +58,20 @@ static idx_t CalculateSliceLength(idx_t begin, idx_t end, INDEX_TYPE step, bool return (end - begin) / UnsafeNumericCast(step); } -struct BlobSliceOperations { - static int64_t ValueLength(const string_t &value) { - return UnsafeNumericCast(value.GetSize()); - } - - static string_t SliceValue(Vector &result, string_t input, int64_t begin, int64_t end) { - return SubstringASCII(result, input, begin + 1, end - begin); - } - - static string_t SliceValueWithSteps(Vector &result, SelectionVector &sel, string_t input, int64_t begin, - int64_t end, int64_t step, idx_t &sel_idx) { - throw InternalException("Slicing with steps is not supported for strings"); - } -}; - -struct StringSliceOperations { - static int64_t ValueLength(const string_t &value) { - return Length(value); - } - - static string_t SliceValue(Vector &result, string_t input, int64_t begin, int64_t end) { - return SubstringUnicode(result, input, begin + 1, end - begin); - } - - static string_t SliceValueWithSteps(Vector &result, SelectionVector &sel, string_t input, int64_t begin, - int64_t end, int64_t step, idx_t &sel_idx) { - throw InternalException("Slicing with steps is not supported for strings"); - } -}; - -struct ListSliceOperations { - static int64_t ValueLength(const list_entry_t &value) { - return UnsafeNumericCast(value.length); - } +template +INDEX_TYPE ValueLength(const INPUT_TYPE &value) { + return 0; +} - static list_entry_t SliceValue(Vector &result, list_entry_t input, int64_t begin, int64_t end) { - input.offset = UnsafeNumericCast(UnsafeNumericCast(input.offset) + begin); - input.length = UnsafeNumericCast(end - begin); - return input; - } +template <> +int64_t ValueLength(const list_entry_t &value) { + return UnsafeNumericCast(value.length); +} - static list_entry_t SliceValueWithSteps(Vector &result, SelectionVector &sel, list_entry_t input, int64_t begin, - int64_t end, int64_t step, idx_t &sel_idx) { - if (end - begin == 0) { - input.length = 0; - input.offset = sel_idx; - return input; - } - input.length = CalculateSliceLength(UnsafeNumericCast(begin), UnsafeNumericCast(end), step, true); - idx_t child_idx = input.offset + UnsafeNumericCast(begin); - if (step < 0) { - child_idx = input.offset + UnsafeNumericCast(end) - 1; - } - input.offset = sel_idx; - for (idx_t i = 0; i < input.length; i++) { - sel.set_index(sel_idx, child_idx); - child_idx += static_cast(step); // intentional overflow?? - sel_idx++; - } - return input; - } -}; +template <> +int64_t ValueLength(const string_t &value) { + return LengthFun::Length(value); +} template static void ClampIndex(INDEX_TYPE &index, const INPUT_TYPE &value, const INDEX_TYPE length, bool is_min) { @@ -134,7 +85,7 @@ static void ClampIndex(INDEX_TYPE &index, const INPUT_TYPE &value, const INDEX_T return; } -template +template static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &end) { // Clamp offsets begin = (begin != 0 && begin != (INDEX_TYPE)NumericLimits::Minimum()) ? begin - 1 : begin; @@ -145,7 +96,7 @@ static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &e is_min = true; } - const auto length = OP::ValueLength(value); + const auto length = ValueLength(value); if (begin < 0 && -begin > length && end < 0 && end < -length) { begin = 0; end = 0; @@ -161,7 +112,53 @@ static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &e return true; } -template +template +INPUT_TYPE SliceValue(Vector &result, INPUT_TYPE input, INDEX_TYPE begin, INDEX_TYPE end) { + return input; +} + +template <> +list_entry_t SliceValue(Vector &result, list_entry_t input, int64_t begin, int64_t end) { + input.offset = UnsafeNumericCast(UnsafeNumericCast(input.offset) + begin); + input.length = UnsafeNumericCast(end - begin); + return input; +} + +template <> +string_t SliceValue(Vector &result, string_t input, int64_t begin, int64_t end) { + // one-based - zero has strange semantics + return SubstringFun::SubstringUnicode(result, input, begin + 1, end - begin); +} + +template +INPUT_TYPE SliceValueWithSteps(Vector &result, SelectionVector &sel, INPUT_TYPE input, INDEX_TYPE begin, INDEX_TYPE end, + INDEX_TYPE step, idx_t &sel_idx) { + return input; +} + +template <> +list_entry_t SliceValueWithSteps(Vector &result, SelectionVector &sel, list_entry_t input, int64_t begin, int64_t end, + int64_t step, idx_t &sel_idx) { + if (end - begin == 0) { + input.length = 0; + input.offset = sel_idx; + return input; + } + input.length = CalculateSliceLength(UnsafeNumericCast(begin), UnsafeNumericCast(end), step, true); + idx_t child_idx = input.offset + UnsafeNumericCast(begin); + if (step < 0) { + child_idx = input.offset + UnsafeNumericCast(end) - 1; + } + input.offset = sel_idx; + for (idx_t i = 0; i < input.length; i++) { + sel.set_index(sel_idx, child_idx); + child_idx += static_cast(step); // intentional overflow?? + sel_idx++; + } + return input; +} + +template static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &begin_vector, Vector &end_vector, optional_ptr step_vector, const idx_t count, SelectionVector &sel, idx_t &sel_idx, optional_ptr result_child_vector, bool begin_is_empty, @@ -186,19 +183,19 @@ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &beg auto str = str_data[0]; auto begin = begin_is_empty ? 0 : begin_data[0]; - auto end = end_is_empty ? OP::ValueLength(str) : end_data[0]; + auto end = end_is_empty ? ValueLength(str) : end_data[0]; auto step = step_data ? step_data[0] : 1; if (step < 0) { swap(begin, end); begin = end_is_empty ? 0 : begin; - end = begin_is_empty ? OP::ValueLength(str) : end; + end = begin_is_empty ? ValueLength(str) : end; } // Clamp offsets bool clamp_result = false; if (step_valid || step == 1) { - clamp_result = ClampSlice(str, begin, end); + clamp_result = ClampSlice(str, begin, end); } idx_t sel_length = 0; @@ -214,9 +211,9 @@ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &beg if (!clamp_result) { ConstantVector::SetNull(result, true); } else if (step == 1) { - result_data[0] = OP::SliceValue(result, str, begin, end); + result_data[0] = SliceValue(result, str, begin, end); } else { - result_data[0] = OP::SliceValueWithSteps(result, sel, str, begin, end, step, sel_idx); + result_data[0] = SliceValueWithSteps(result, sel, str, begin, end, step, sel_idx); } if (sel_valid) { @@ -226,7 +223,7 @@ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &beg } } -template +template static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_vector, Vector &end_vector, optional_ptr step_vector, const idx_t count, SelectionVector &sel, idx_t &sel_idx, optional_ptr result_child_vector, bool begin_is_empty, bool end_is_empty) { @@ -262,18 +259,19 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_ auto sliced = reinterpret_cast(list_data.data)[list_idx]; auto begin = begin_is_empty ? 0 : reinterpret_cast(begin_data.data)[begin_idx]; - auto end = end_is_empty ? OP::ValueLength(sliced) : reinterpret_cast(end_data.data)[end_idx]; + auto end = end_is_empty ? ValueLength(sliced) + : reinterpret_cast(end_data.data)[end_idx]; auto step = step_vector ? reinterpret_cast(step_data.data)[step_idx] : 1; if (step < 0) { swap(begin, end); begin = end_is_empty ? 0 : begin; - end = begin_is_empty ? OP::ValueLength(sliced) : end; + end = begin_is_empty ? ValueLength(sliced) : end; } bool clamp_result = false; if (step_valid || step == 1) { - clamp_result = ClampSlice(sliced, begin, end); + clamp_result = ClampSlice(sliced, begin, end); } idx_t length = 0; @@ -286,9 +284,10 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_ if (!clamp_result) { result_mask.SetInvalid(i); } else if (!step_vector) { - result_data[i] = OP::SliceValue(result, sliced, begin, end); + result_data[i] = SliceValue(result, sliced, begin, end); } else { - result_data[i] = OP::SliceValueWithSteps(result, sel, sliced, begin, end, step, sel_idx); + result_data[i] = + SliceValueWithSteps(result, sel, sliced, begin, end, step, sel_idx); } } if (step_vector) { @@ -302,7 +301,7 @@ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_ } } -template +template static void ExecuteSlice(Vector &result, Vector &list_or_str_vector, Vector &begin_vector, Vector &end_vector, optional_ptr step_vector, const idx_t count, bool begin_is_empty, bool end_is_empty) { optional_ptr result_child_vector; @@ -314,13 +313,13 @@ static void ExecuteSlice(Vector &result, Vector &list_or_str_vector, Vector &beg idx_t sel_idx = 0; if (result.GetVectorType() == VectorType::CONSTANT_VECTOR) { - ExecuteConstantSlice(result, list_or_str_vector, begin_vector, end_vector, - step_vector, count, sel, sel_idx, result_child_vector, - begin_is_empty, end_is_empty); - } else { - ExecuteFlatSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, + ExecuteConstantSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, count, sel, sel_idx, result_child_vector, begin_is_empty, end_is_empty); + } else { + ExecuteFlatSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, + count, sel, sel_idx, result_child_vector, begin_is_empty, + end_is_empty); } result.Verify(count); } @@ -361,18 +360,15 @@ static void ArraySliceFunction(DataChunk &args, ExpressionState &state, Vector & list_or_str_vector.GetVectorType() != VectorType::CONSTANT_VECTOR) { list_or_str_vector.Flatten(count); } - ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, - step_vector, count, begin_is_empty, end_is_empty); + ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, count, + begin_is_empty, end_is_empty); break; } - case LogicalTypeId::BLOB: - ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, - step_vector, count, begin_is_empty, end_is_empty); - break; - case LogicalTypeId::VARCHAR: - ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, - step_vector, count, begin_is_empty, end_is_empty); + case LogicalTypeId::VARCHAR: { + ExecuteSlice(result, list_or_str_vector, begin_vector, end_vector, step_vector, count, + begin_is_empty, end_is_empty); break; + } default: throw NotImplementedException("Specifier type not implemented"); } @@ -408,7 +404,6 @@ static unique_ptr ArraySliceBind(ClientContext &context, ScalarFun // The result is the same type bound_function.return_type = arguments[0]->return_type; break; - case LogicalTypeId::BLOB: case LogicalTypeId::VARCHAR: // string slice returns a string if (bound_function.arguments.size() == 4) { @@ -449,7 +444,7 @@ ScalarFunctionSet ListSliceFun::GetFunctions() { ScalarFunction fun({LogicalType::ANY, LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, ArraySliceFunction, ArraySliceBind); fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(fun); + ScalarFunctionSet set; set.AddFunction(fun); fun.arguments.push_back(LogicalType::BIGINT); diff --git a/src/duckdb/extension/core_functions/scalar/list/flatten.cpp b/src/duckdb/src/core_functions/scalar/list/flatten.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/list/flatten.cpp rename to src/duckdb/src/core_functions/scalar/list/flatten.cpp index 849c20d16..4833dc7a5 100644 --- a/src/duckdb/extension/core_functions/scalar/list/flatten.cpp +++ b/src/duckdb/src/core_functions/scalar/list/flatten.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/storage/statistics/list_stats.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp b/src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp rename to src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp index 1b2aab71d..e423c1a78 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_aggregates.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_aggregates.cpp @@ -1,5 +1,5 @@ -#include "core_functions/scalar/list_functions.hpp" -#include "core_functions/aggregate/nested_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/aggregate/nested_functions.hpp" #include "duckdb/catalog/catalog.hpp" #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/execution/expression_executor.hpp" @@ -10,7 +10,7 @@ #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression_binder.hpp" #include "duckdb/function/function_binder.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/common/owning_string_map.hpp" namespace duckdb { @@ -294,7 +294,6 @@ static void ListAggregatesFunction(DataChunk &args, ExpressionState &state, Vect auto key_type = aggr.function.arguments[0]; switch (key_type.InternalType()) { -#ifndef DUCKDB_SMALLER_BINARY case PhysicalType::BOOL: FUNCTION_FUNCTOR::template ListExecuteFunction( result, state_vector.state_vector, count); @@ -344,7 +343,6 @@ static void ListAggregatesFunction(DataChunk &args, ExpressionState &state, Vect OwningStringMap>(result, state_vector.state_vector, count); break; -#endif default: FUNCTION_FUNCTOR::template ListExecuteFunction>(result, state_vector.state_vector, @@ -468,7 +466,6 @@ static unique_ptr ListAggregatesBind(ClientContext &context, Scala // found a matching function, bind it as an aggregate auto best_function = func.functions.GetFunctionByOffset(best_function_idx.GetIndex()); if (IS_AGGR) { - bound_function.errors = best_function.errors; return ListAggregatesBindFunction(context, bound_function, child_type, best_function, arguments); } @@ -513,7 +510,6 @@ static unique_ptr ListUniqueBind(ClientContext &context, ScalarFun ScalarFunction ListAggregateFun::GetFunction() { auto result = ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::VARCHAR}, LogicalType::ANY, ListAggregateFunction, ListAggregateBind); - BaseScalarFunction::SetReturnsError(result); result.null_handling = FunctionNullHandling::SPECIAL_HANDLING; result.varargs = LogicalType::ANY; result.serialize = ListAggregatesBindData::SerializeFunction; diff --git a/src/duckdb/extension/core_functions/scalar/list/list_distance.cpp b/src/duckdb/src/core_functions/scalar/list/list_distance.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/list/list_distance.cpp rename to src/duckdb/src/core_functions/scalar/list/list_distance.cpp index 5c3513b2a..23e19f871 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_distance.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_distance.cpp @@ -1,5 +1,5 @@ -#include "core_functions/scalar/list_functions.hpp" -#include "core_functions/array_kernels.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/array_kernels.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { @@ -87,9 +87,6 @@ ScalarFunctionSet ListDistanceFun::GetFunctions() { for (auto &type : LogicalType::Real()) { AddListFoldFunction(set, type); } - for (auto &func : set.functions) { - BaseScalarFunction::SetReturnsError(func); - } return set; } @@ -114,9 +111,6 @@ ScalarFunctionSet ListCosineSimilarityFun::GetFunctions() { for (auto &type : LogicalType::Real()) { AddListFoldFunction(set, type); } - for (auto &func : set.functions) { - BaseScalarFunction::SetReturnsError(func); - } return set; } diff --git a/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp b/src/duckdb/src/core_functions/scalar/list/list_filter.cpp similarity index 90% rename from src/duckdb/extension/core_functions/scalar/list/list_filter.cpp rename to src/duckdb/src/core_functions/scalar/list/list_filter.cpp index 30ac79db1..9dbab0981 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_filter.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_filter.cpp @@ -1,6 +1,6 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/function/lambda_functions.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" namespace duckdb { @@ -10,7 +10,7 @@ static unique_ptr ListFilterBind(ClientContext &context, ScalarFun // the list column and the bound lambda expression D_ASSERT(arguments.size() == 2); - if (arguments[1]->GetExpressionClass() != ExpressionClass::BOUND_LAMBDA) { + if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { throw BinderException("Invalid lambda expression!"); } diff --git a/src/duckdb/extension/core_functions/scalar/list/list_has_any_or_all.cpp b/src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/list/list_has_any_or_all.cpp rename to src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp index dd15edc93..4a3e35090 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_has_any_or_all.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_has_any_or_all.cpp @@ -1,6 +1,6 @@ -#include "duckdb/function/lambda_functions.hpp" -#include "core_functions/scalar/list_functions.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/common/string_map_set.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp b/src/duckdb/src/core_functions/scalar/list/list_reduce.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp rename to src/duckdb/src/core_functions/scalar/list/list_reduce.cpp index 173b52699..a3b4e01d8 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_reduce.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_reduce.cpp @@ -1,5 +1,5 @@ -#include "core_functions/scalar/list_functions.hpp" -#include "duckdb/function/lambda_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -9,7 +9,7 @@ struct ReduceExecuteInfo { ReduceExecuteInfo(LambdaFunctions::LambdaInfo &info, ClientContext &context) : left_slice(make_uniq(*info.child_vector)) { SelectionVector left_vector(info.row_count); - active_rows.Resize(info.row_count); + active_rows.Resize(0, info.row_count); active_rows.SetAllValid(info.row_count); left_sel.Initialize(info.row_count); @@ -101,7 +101,7 @@ static bool ExecuteReduce(idx_t loops, ReduceExecuteInfo &execute_info, LambdaFu } // create the index vector - Vector index_vector(Value::BIGINT(UnsafeNumericCast(loops + 2))); + Vector index_vector(Value::BIGINT(UnsafeNumericCast(loops + 1))); // slice the left and right slice execute_info.left_slice->Slice(*execute_info.left_slice, execute_info.left_sel, reduced_row_idx); @@ -184,7 +184,7 @@ static unique_ptr ListReduceBind(ClientContext &context, ScalarFun // the list column and the bound lambda expression D_ASSERT(arguments.size() == 2); - if (arguments[1]->GetExpressionClass() != ExpressionClass::BOUND_LAMBDA) { + if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { throw BinderException("Invalid lambda expression!"); } diff --git a/src/duckdb/extension/core_functions/scalar/list/list_sort.cpp b/src/duckdb/src/core_functions/scalar/list/list_sort.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/list/list_sort.cpp rename to src/duckdb/src/core_functions/scalar/list/list_sort.cpp index 5ab523d20..0fbe54ba9 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_sort.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_sort.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" #include "duckdb/common/enum_util.hpp" #include "duckdb/common/numeric_utils.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp b/src/duckdb/src/core_functions/scalar/list/list_transform.cpp similarity index 89% rename from src/duckdb/extension/core_functions/scalar/list/list_transform.cpp rename to src/duckdb/src/core_functions/scalar/list/list_transform.cpp index 26c6ad4b3..01f10641e 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_transform.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_transform.cpp @@ -1,6 +1,6 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" -#include "duckdb/function/lambda_functions.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" namespace duckdb { @@ -10,7 +10,7 @@ static unique_ptr ListTransformBind(ClientContext &context, Scalar // the list column and the bound lambda expression D_ASSERT(arguments.size() == 2); - if (arguments[1]->GetExpressionClass() != ExpressionClass::BOUND_LAMBDA) { + if (arguments[1]->expression_class != ExpressionClass::BOUND_LAMBDA) { throw BinderException("Invalid lambda expression!"); } diff --git a/src/duckdb/extension/core_functions/scalar/list/list_value.cpp b/src/duckdb/src/core_functions/scalar/list/list_value.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/list/list_value.cpp rename to src/duckdb/src/core_functions/scalar/list/list_value.cpp index 01b342ec4..cc7a5df6f 100644 --- a/src/duckdb/extension/core_functions/scalar/list/list_value.cpp +++ b/src/duckdb/src/core_functions/scalar/list/list_value.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" @@ -156,10 +156,10 @@ static unique_ptr ListValueBind(ClientContext &context, ScalarFunc auto error = StringUtil::Format("Cannot unpivot columns of types %s and %s - an explicit cast is required", child_type.ToString(), arg_type.ToString()); - throw BinderException(arguments[i]->GetQueryLocation(), + throw BinderException(arguments[i]->query_location, QueryErrorContext::Format(list_arguments, error, error_index, false)); } else { - throw BinderException(arguments[i]->GetQueryLocation(), + throw BinderException(arguments[i]->query_location, "Cannot create a list of types %s and %s - an explicit cast is required", child_type.ToString(), arg_type.ToString()); } diff --git a/src/duckdb/extension/core_functions/scalar/list/range.cpp b/src/duckdb/src/core_functions/scalar/list/range.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/list/range.cpp rename to src/duckdb/src/core_functions/scalar/list/range.cpp index 8c641d13d..d965eb30d 100644 --- a/src/duckdb/extension/core_functions/scalar/list/range.cpp +++ b/src/duckdb/src/core_functions/scalar/list/range.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/list_functions.hpp" +#include "duckdb/core_functions/scalar/list_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/types/vector.hpp" @@ -253,9 +253,6 @@ ScalarFunctionSet ListRangeFun::GetFunctions() { range_set.AddFunction(ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, LogicalType::LIST(LogicalType::TIMESTAMP), ListRangeFunction)); - for (auto &func : range_set.functions) { - BaseScalarFunction::SetReturnsError(func); - } return range_set; } @@ -272,9 +269,6 @@ ScalarFunctionSet GenerateSeriesFun::GetFunctions() { generate_series.AddFunction(ScalarFunction({LogicalType::TIMESTAMP, LogicalType::TIMESTAMP, LogicalType::INTERVAL}, LogicalType::LIST(LogicalType::TIMESTAMP), ListRangeFunction)); - for (auto &func : generate_series.functions) { - BaseScalarFunction::SetReturnsError(func); - } return generate_series; } diff --git a/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp b/src/duckdb/src/core_functions/scalar/map/cardinality.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/map/cardinality.cpp rename to src/duckdb/src/core_functions/scalar/map/cardinality.cpp index 9c81223e7..8bf0dbd11 100644 --- a/src/duckdb/extension/core_functions/scalar/map/cardinality.cpp +++ b/src/duckdb/src/core_functions/scalar/map/cardinality.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/map/map.cpp b/src/duckdb/src/core_functions/scalar/map/map.cpp similarity index 95% rename from src/duckdb/extension/core_functions/scalar/map/map.cpp rename to src/duckdb/src/core_functions/scalar/map/map.cpp index b83a4a081..ab67475d1 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" @@ -10,8 +10,9 @@ namespace duckdb { static void MapFunctionEmptyInput(Vector &result, const idx_t row_count) { - // If no chunk is set in ExpressionExecutor::ExecuteExpression (args.data.empty(), e.g., in SELECT MAP()), - // then we always pass a row_count of 1. + + // if no chunk is set in ExpressionExecutor::ExecuteExpression (args.data.empty(), e.g., + // in SELECT MAP()), then we always pass a row_count of 1 result.SetVectorType(VectorType::CONSTANT_VECTOR); ListVector::SetListSize(result, 0); @@ -164,7 +165,6 @@ static void MapFunction(DataChunk &args, ExpressionState &, Vector &result) { result_key_vector.Flatten(offset); result_value_vector.Slice(values_child_vector, sel_values, offset); result_value_vector.Flatten(offset); - FlatVector::Validity(ListVector::GetEntry(result)).Resize(result_child_size); if (args.AllConstant()) { result.SetVectorType(VectorType::CONSTANT_VECTOR); @@ -215,7 +215,6 @@ static unique_ptr MapBind(ClientContext &, ScalarFunction &bound_f ScalarFunction MapFun::GetFunction() { ScalarFunction fun({}, LogicalTypeId::MAP, MapFunction, MapBind); fun.varargs = LogicalType::ANY; - BaseScalarFunction::SetReturnsError(fun); fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp b/src/duckdb/src/core_functions/scalar/map/map_concat.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/map/map_concat.cpp rename to src/duckdb/src/core_functions/scalar/map/map_concat.cpp index c958f41b9..b3ffc1740 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_concat.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_concat.cpp @@ -6,7 +6,7 @@ #include "duckdb/common/pair.hpp" #include "duckdb/common/types.hpp" #include "duckdb/common/unordered_map.hpp" -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/scalar/map/map_contains.cpp b/src/duckdb/src/core_functions/scalar/map/map_contains.cpp similarity index 97% rename from src/duckdb/src/function/scalar/map/map_contains.cpp rename to src/duckdb/src/core_functions/scalar/map/map_contains.cpp index 068e67bc7..19a46015c 100644 --- a/src/duckdb/src/function/scalar/map/map_contains.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_contains.cpp @@ -1,6 +1,6 @@ +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/function/scalar/list/contains_or_position.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/function/scalar/map_functions.hpp" namespace duckdb { @@ -48,9 +48,9 @@ static unique_ptr MapContainsBind(ClientContext &context, ScalarFu } ScalarFunction MapContainsFun::GetFunction() { + ScalarFunction fun("map_contains", {LogicalType::MAP(LogicalType::ANY, LogicalType::ANY), LogicalType::ANY}, LogicalType::BOOLEAN, MapContainsFunction, MapContainsBind); return fun; } - } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/map/map_entries.cpp b/src/duckdb/src/core_functions/scalar/map/map_entries.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/map/map_entries.cpp rename to src/duckdb/src/core_functions/scalar/map/map_entries.cpp index 487fd75fa..47e653993 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_entries.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_entries.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/map/map_extract.cpp b/src/duckdb/src/core_functions/scalar/map/map_extract.cpp similarity index 73% rename from src/duckdb/extension/core_functions/scalar/map/map_extract.cpp rename to src/duckdb/src/core_functions/scalar/map/map_extract.cpp index 170f2b7da..79056cd0b 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_extract.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_extract.cpp @@ -1,12 +1,13 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" +#include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/common/string_util.hpp" +#include "duckdb/parser/expression/bound_expression.hpp" #include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/list/contains_or_position.hpp" #include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" - +#include "duckdb/function/scalar/list/contains_or_position.hpp" namespace duckdb { -static unique_ptr MapExtractBind(ClientContext &, ScalarFunction &bound_function, +static unique_ptr MapExtractBind(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { if (arguments.size() != 2) { throw BinderException("MAP_EXTRACT must have exactly two arguments"); @@ -16,7 +17,7 @@ static unique_ptr MapExtractBind(ClientContext &, ScalarFunction & auto &input_type = arguments[1]->return_type; if (map_type.id() == LogicalTypeId::SQLNULL) { - bound_function.return_type = LogicalTypeId::SQLNULL; + bound_function.return_type = LogicalType::LIST(LogicalTypeId::SQLNULL); return make_uniq(bound_function.return_type); } @@ -26,7 +27,7 @@ static unique_ptr MapExtractBind(ClientContext &, ScalarFunction & auto &value_type = MapType::ValueType(map_type); //! Here we have to construct the List Type that will be returned - bound_function.return_type = value_type; + bound_function.return_type = LogicalType::LIST(value_type); auto key_type = MapType::KeyType(map_type); if (key_type.id() != LogicalTypeId::SQLNULL && input_type.id() != LogicalTypeId::SQLNULL) { bound_function.arguments[1] = MapType::KeyType(map_type); @@ -45,8 +46,9 @@ static void MapExtractFunc(DataChunk &args, ExpressionState &state, Vector &resu if (map_is_null || arg_is_null) { // Short-circuit if either the map or the arg is NULL + ListVector::SetListSize(result, 0); result.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(result, true); + ConstantVector::GetData(result)[0] = {0, 0}; result.Verify(count); return; } @@ -58,16 +60,19 @@ static void MapExtractFunc(DataChunk &args, ExpressionState &state, Vector &resu Vector pos_vec(LogicalType::INTEGER, count); ListSearchOp(map_vec, key_vec, arg_vec, pos_vec, args.size()); + UnifiedVectorFormat val_format; UnifiedVectorFormat pos_format; UnifiedVectorFormat lst_format; + val_vec.ToUnifiedFormat(ListVector::GetListSize(map_vec), val_format); pos_vec.ToUnifiedFormat(count, pos_format); map_vec.ToUnifiedFormat(count, lst_format); const auto pos_data = UnifiedVectorFormat::GetData(pos_format); const auto inc_list_data = ListVector::GetData(map_vec); + const auto out_list_data = ListVector::GetData(result); - auto &result_validity = FlatVector::Validity(result); + idx_t offset = 0; for (idx_t row_idx = 0; row_idx < count; row_idx++) { auto lst_idx = lst_format.sel->get_index(row_idx); if (!lst_format.validity.RowIsValid(lst_idx)) { @@ -75,16 +80,23 @@ static void MapExtractFunc(DataChunk &args, ExpressionState &state, Vector &resu continue; } + auto &inc_list = inc_list_data[lst_idx]; + auto &out_list = out_list_data[row_idx]; + const auto pos_idx = pos_format.sel->get_index(row_idx); if (!pos_format.validity.RowIsValid(pos_idx)) { - // We didnt find the key in the map, so return NULL - result_validity.SetInvalid(row_idx); + // We didnt find the key in the map, so return an empty list + out_list.offset = offset; + out_list.length = 0; continue; } // Compute the actual position of the value in the map value vector - const auto pos = inc_list_data[lst_idx].offset + UnsafeNumericCast(pos_data[pos_idx] - 1); - VectorOperations::Copy(val_vec, result, pos + 1, pos, row_idx); + const auto pos = inc_list.offset + UnsafeNumericCast(pos_data[pos_idx] - 1); + out_list.offset = offset; + out_list.length = 1; + ListVector::Append(result, val_vec, pos + 1, pos); + offset++; } if (args.size() == 1) { diff --git a/src/duckdb/extension/core_functions/scalar/map/map_from_entries.cpp b/src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp similarity index 95% rename from src/duckdb/extension/core_functions/scalar/map/map_from_entries.cpp rename to src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp index edbe1d4fb..fbaf1663d 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_from_entries.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_from_entries.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" @@ -53,7 +53,6 @@ ScalarFunction MapFromEntriesFun::GetFunction() { ScalarFunction fun({}, LogicalTypeId::MAP, MapFromEntriesFunction, MapFromEntriesBind); fun.null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING; fun.varargs = LogicalType::ANY; - BaseScalarFunction::SetReturnsError(fun); return fun; } diff --git a/src/duckdb/extension/core_functions/scalar/map/map_keys_values.cpp b/src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp similarity index 86% rename from src/duckdb/extension/core_functions/scalar/map/map_keys_values.cpp rename to src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp index 6d99a353e..c5578895d 100644 --- a/src/duckdb/extension/core_functions/scalar/map/map_keys_values.cpp +++ b/src/duckdb/src/core_functions/scalar/map/map_keys_values.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/map_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" @@ -94,19 +94,17 @@ static unique_ptr MapValuesBind(ClientContext &context, ScalarFunc ScalarFunction MapKeysFun::GetFunction() { //! the arguments and return types are actually set in the binder function - ScalarFunction function({}, LogicalTypeId::LIST, MapKeysFunction, MapKeysBind); - function.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(function); - function.varargs = LogicalType::ANY; - return function; + ScalarFunction fun({}, LogicalTypeId::LIST, MapKeysFunction, MapKeysBind); + fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + fun.varargs = LogicalType::ANY; + return fun; } ScalarFunction MapValuesFun::GetFunction() { - ScalarFunction function({}, LogicalTypeId::LIST, MapValuesFunction, MapValuesBind); - function.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(function); - function.varargs = LogicalType::ANY; - return function; + ScalarFunction fun({}, LogicalTypeId::LIST, MapValuesFunction, MapValuesBind); + fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + fun.varargs = LogicalType::ANY; + return fun; } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/math/numeric.cpp b/src/duckdb/src/core_functions/scalar/math/numeric.cpp similarity index 92% rename from src/duckdb/extension/core_functions/scalar/math/numeric.cpp rename to src/duckdb/src/core_functions/scalar/math/numeric.cpp index 47eed7a79..1c47fbd95 100644 --- a/src/duckdb/extension/core_functions/scalar/math/numeric.cpp +++ b/src/duckdb/src/core_functions/scalar/math/numeric.cpp @@ -1,25 +1,16 @@ +#include "duckdb/core_functions/scalar/math_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/algorithm.hpp" -#include "duckdb/common/likely.hpp" #include "duckdb/common/operator/abs.hpp" #include "duckdb/common/operator/multiply.hpp" -#include "duckdb/common/operator/numeric_binary_operators.hpp" -#include "duckdb/common/types/bit.hpp" -#include "duckdb/common/types/cast_helpers.hpp" #include "duckdb/common/types/hugeint.hpp" -#include "duckdb/common/types/uhugeint.hpp" -#include "duckdb/common/types/validity_mask.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/common/vector_operations/unary_executor.hpp" -#include "core_functions/scalar/math_functions.hpp" -#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/common/types/cast_helpers.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" - +#include "duckdb/common/algorithm.hpp" +#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/common/likely.hpp" +#include "duckdb/common/types/bit.hpp" #include -#include #include -#include -#include namespace duckdb { @@ -178,9 +169,9 @@ ScalarFunctionSet AbsOperatorFun::GetFunctions() { case LogicalTypeId::INTEGER: case LogicalTypeId::BIGINT: case LogicalTypeId::HUGEINT: { - ScalarFunction function({type}, type, ScalarFunction::GetScalarUnaryFunction(type)); - function.statistics = PropagateAbsStats; - abs.AddFunction(function); + ScalarFunction func({type}, type, ScalarFunction::GetScalarUnaryFunction(type)); + func.statistics = PropagateAbsStats; + abs.AddFunction(func); break; } case LogicalTypeId::UTINYINT: @@ -194,9 +185,6 @@ ScalarFunctionSet AbsOperatorFun::GetFunctions() { break; } } - for (auto &func : abs.functions) { - BaseScalarFunction::SetReturnsError(func); - } return abs; } @@ -768,10 +756,8 @@ struct SqrtOperator { }; ScalarFunction SqrtFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -807,10 +793,8 @@ struct LnOperator { }; ScalarFunction LnFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -830,10 +814,8 @@ struct Log10Operator { }; ScalarFunction Log10Fun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -856,9 +838,6 @@ ScalarFunctionSet LogFun::GetFunctions() { ScalarFunction::UnaryFunction)); funcs.AddFunction(ScalarFunction({LogicalType::DOUBLE, LogicalType::DOUBLE}, LogicalType::DOUBLE, ScalarFunction::BinaryFunction)); - for (auto &function : funcs.functions) { - BaseScalarFunction::SetReturnsError(function); - } return funcs; } @@ -879,10 +858,8 @@ struct Log2Operator { }; ScalarFunction Log2Fun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -1051,10 +1028,8 @@ struct SinOperator { }; ScalarFunction SinFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1068,10 +1043,8 @@ struct CosOperator { }; ScalarFunction CosFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1085,10 +1058,8 @@ struct TanOperator { }; ScalarFunction TanFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1105,10 +1076,8 @@ struct ASinOperator { }; ScalarFunction AsinFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1155,10 +1124,8 @@ struct ACos { }; ScalarFunction AcosFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1253,10 +1220,8 @@ struct AtanhOperator { }; ScalarFunction AtanhFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -1287,10 +1252,8 @@ struct CotOperator { }; ScalarFunction CotFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction>); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction>); } //===--------------------------------------------------------------------===// @@ -1307,10 +1270,8 @@ struct GammaOperator { }; ScalarFunction GammaFun::GetFunction() { - auto func = ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -1327,10 +1288,8 @@ struct LogGammaOperator { }; ScalarFunction LogGammaFun::GetFunction() { - ScalarFunction function({LogicalType::DOUBLE}, LogicalType::DOUBLE, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::DOUBLE}, LogicalType::DOUBLE, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -1350,10 +1309,8 @@ struct FactorialOperator { }; ScalarFunction FactorialOperatorFun::GetFunction() { - ScalarFunction function({LogicalType::INTEGER}, LogicalType::HUGEINT, - ScalarFunction::UnaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::INTEGER}, LogicalType::HUGEINT, + ScalarFunction::UnaryFunction); } //===--------------------------------------------------------------------===// @@ -1460,9 +1417,6 @@ ScalarFunctionSet LeastCommonMultipleFun::GetFunctions() { funcs.AddFunction( ScalarFunction({LogicalType::HUGEINT, LogicalType::HUGEINT}, LogicalType::HUGEINT, ScalarFunction::BinaryFunction)); - for (auto &function : funcs.functions) { - BaseScalarFunction::SetReturnsError(function); - } return funcs; } diff --git a/src/duckdb/extension/core_functions/scalar/operators/bitwise.cpp b/src/duckdb/src/core_functions/scalar/operators/bitwise.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/operators/bitwise.cpp rename to src/duckdb/src/core_functions/scalar/operators/bitwise.cpp index 103e0c2ab..6e9415aad 100644 --- a/src/duckdb/extension/core_functions/scalar/operators/bitwise.cpp +++ b/src/duckdb/src/core_functions/scalar/operators/bitwise.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/operators_functions.hpp" +#include "duckdb/core_functions/scalar/operators_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/types/cast_helpers.hpp" #include "duckdb/common/types/bit.hpp" @@ -112,9 +112,6 @@ ScalarFunctionSet BitwiseAndFun::GetFunctions() { ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); } functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseANDOperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } @@ -145,9 +142,6 @@ ScalarFunctionSet BitwiseOrFun::GetFunctions() { ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); } functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseOROperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } @@ -178,9 +172,6 @@ ScalarFunctionSet BitwiseXorFun::GetFunctions() { ScalarFunction({type, type}, type, GetScalarIntegerBinaryFunction(type))); } functions.AddFunction(ScalarFunction({LogicalType::BIT, LogicalType::BIT}, LogicalType::BIT, BitwiseXOROperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } @@ -209,9 +200,6 @@ ScalarFunctionSet BitwiseNotFun::GetFunctions() { functions.AddFunction(ScalarFunction({type}, type, GetScalarIntegerUnaryFunction(type))); } functions.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIT, BitwiseNOTOperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } @@ -275,9 +263,6 @@ ScalarFunctionSet LeftShiftFun::GetFunctions() { } functions.AddFunction( ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitwiseShiftLeftOperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } @@ -321,9 +306,6 @@ ScalarFunctionSet RightShiftFun::GetFunctions() { } functions.AddFunction( ScalarFunction({LogicalType::BIT, LogicalType::INTEGER}, LogicalType::BIT, BitwiseShiftRightOperation)); - for (auto &function : functions.functions) { - BaseScalarFunction::SetReturnsError(function); - } return functions; } diff --git a/src/duckdb/extension/core_functions/scalar/random/random.cpp b/src/duckdb/src/core_functions/scalar/random/random.cpp similarity index 93% rename from src/duckdb/extension/core_functions/scalar/random/random.cpp rename to src/duckdb/src/core_functions/scalar/random/random.cpp index 3054170ff..02567a486 100644 --- a/src/duckdb/extension/core_functions/scalar/random/random.cpp +++ b/src/duckdb/src/core_functions/scalar/random/random.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/random_functions.hpp" +#include "duckdb/core_functions/scalar/random_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/main/client_context.hpp" @@ -9,8 +9,7 @@ namespace duckdb { struct RandomLocalState : public FunctionLocalState { - explicit RandomLocalState(uint64_t seed) : random_engine(0) { - random_engine.SetSeed(seed); + explicit RandomLocalState(uint32_t seed) : random_engine(seed) { } RandomEngine random_engine; @@ -31,7 +30,7 @@ static unique_ptr RandomInitLocalState(ExpressionState &stat FunctionData *bind_data) { auto &random_engine = RandomEngine::Get(state.GetContext()); lock_guard guard(random_engine.lock); - return make_uniq(random_engine.NextRandomInteger64()); + return make_uniq(random_engine.NextRandomInteger()); } ScalarFunction RandomFun::GetFunction() { diff --git a/src/duckdb/extension/core_functions/scalar/random/setseed.cpp b/src/duckdb/src/core_functions/scalar/random/setseed.cpp similarity index 95% rename from src/duckdb/extension/core_functions/scalar/random/setseed.cpp rename to src/duckdb/src/core_functions/scalar/random/setseed.cpp index ca2865284..a4e1d01d8 100644 --- a/src/duckdb/extension/core_functions/scalar/random/setseed.cpp +++ b/src/duckdb/src/core_functions/scalar/random/setseed.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/random_functions.hpp" +#include "duckdb/core_functions/scalar/random_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" @@ -55,7 +55,6 @@ unique_ptr SetSeedBind(ClientContext &context, ScalarFunction &bou ScalarFunction SetseedFun::GetFunction() { ScalarFunction setseed("setseed", {LogicalType::DOUBLE}, LogicalType::SQLNULL, SetSeedFunction, SetSeedBind); setseed.stability = FunctionStability::VOLATILE; - BaseScalarFunction::SetReturnsError(setseed); return setseed; } diff --git a/src/duckdb/extension/core_functions/scalar/string/ascii.cpp b/src/duckdb/src/core_functions/scalar/string/ascii.cpp similarity index 90% rename from src/duckdb/extension/core_functions/scalar/string/ascii.cpp rename to src/duckdb/src/core_functions/scalar/string/ascii.cpp index 4083c85de..5f41338bb 100644 --- a/src/duckdb/extension/core_functions/scalar/string/ascii.cpp +++ b/src/duckdb/src/core_functions/scalar/string/ascii.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "utf8proc.hpp" #include "utf8proc_wrapper.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/bar.cpp b/src/duckdb/src/core_functions/scalar/string/bar.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/string/bar.cpp rename to src/duckdb/src/core_functions/scalar/string/bar.cpp index 957b8c624..b571e7ac2 100644 --- a/src/duckdb/extension/core_functions/scalar/string/bar.cpp +++ b/src/duckdb/src/core_functions/scalar/string/bar.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/types/string_type.hpp" @@ -39,26 +39,24 @@ static string_t BarScalarFunction(double x, double min, double max, double max_w } result.clear(); - idx_t used_blocks = 0; auto width_as_int = LossyNumericCast(width * PARTIAL_BLOCKS_COUNT); idx_t full_blocks_count = (width_as_int / PARTIAL_BLOCKS_COUNT); for (idx_t i = 0; i < full_blocks_count; i++) { - used_blocks++; result += FULL_BLOCK; } idx_t remaining = width_as_int % PARTIAL_BLOCKS_COUNT; if (remaining) { - used_blocks++; result += PARTIAL_BLOCKS[remaining]; } const idx_t integer_max_width = (idx_t)max_width; - if (used_blocks < integer_max_width) { - result += std::string(integer_max_width - used_blocks, ' '); + if (result.size() < integer_max_width) { + result += std::string(integer_max_width - result.size(), ' '); } + return string_t(result); } diff --git a/src/duckdb/extension/core_functions/scalar/string/chr.cpp b/src/duckdb/src/core_functions/scalar/string/chr.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/string/chr.cpp rename to src/duckdb/src/core_functions/scalar/string/chr.cpp index bca2de6d8..34f897eb6 100644 --- a/src/duckdb/extension/core_functions/scalar/string/chr.cpp +++ b/src/duckdb/src/core_functions/scalar/string/chr.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "utf8proc.hpp" #include "utf8proc_wrapper.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/damerau_levenshtein.cpp b/src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/string/damerau_levenshtein.cpp rename to src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp index 91b0fbd33..20bb7dfcd 100644 --- a/src/duckdb/extension/core_functions/scalar/string/damerau_levenshtein.cpp +++ b/src/duckdb/src/core_functions/scalar/string/damerau_levenshtein.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/map.hpp" #include "duckdb/common/vector.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/format_bytes.cpp b/src/duckdb/src/core_functions/scalar/string/format_bytes.cpp similarity index 94% rename from src/duckdb/extension/core_functions/scalar/string/format_bytes.cpp rename to src/duckdb/src/core_functions/scalar/string/format_bytes.cpp index 46db22f25..7a5117997 100644 --- a/src/duckdb/extension/core_functions/scalar/string/format_bytes.cpp +++ b/src/duckdb/src/core_functions/scalar/string/format_bytes.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/string_util.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/hamming.cpp b/src/duckdb/src/core_functions/scalar/string/hamming.cpp similarity index 95% rename from src/duckdb/extension/core_functions/scalar/string/hamming.cpp rename to src/duckdb/src/core_functions/scalar/string/hamming.cpp index b32a80199..892430da3 100644 --- a/src/duckdb/extension/core_functions/scalar/string/hamming.cpp +++ b/src/duckdb/src/core_functions/scalar/string/hamming.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include diff --git a/src/duckdb/extension/core_functions/scalar/string/hex.cpp b/src/duckdb/src/core_functions/scalar/string/hex.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/hex.cpp rename to src/duckdb/src/core_functions/scalar/string/hex.cpp index cbf541e1b..6f982f261 100644 --- a/src/duckdb/extension/core_functions/scalar/string/hex.cpp +++ b/src/duckdb/src/core_functions/scalar/string/hex.cpp @@ -6,7 +6,7 @@ #include "duckdb/common/vector_operations/unary_executor.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" namespace duckdb { @@ -408,9 +408,7 @@ ScalarFunctionSet HexFun::GetFunctions() { } ScalarFunction UnhexFun::GetFunction() { - ScalarFunction function({LogicalType::VARCHAR}, LogicalType::BLOB, FromHexFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, FromHexFunction); } ScalarFunctionSet BinFun::GetFunctions() { @@ -432,9 +430,7 @@ ScalarFunctionSet BinFun::GetFunctions() { } ScalarFunction UnbinFun::GetFunction() { - ScalarFunction function({LogicalType::VARCHAR}, LogicalType::BLOB, FromBinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction({LogicalType::VARCHAR}, LogicalType::BLOB, FromBinaryFunction); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/string/instr.cpp b/src/duckdb/src/core_functions/scalar/string/instr.cpp similarity index 89% rename from src/duckdb/extension/core_functions/scalar/string/instr.cpp rename to src/duckdb/src/core_functions/scalar/string/instr.cpp index 77539e7c0..66608db60 100644 --- a/src/duckdb/extension/core_functions/scalar/string/instr.cpp +++ b/src/duckdb/src/core_functions/scalar/string/instr.cpp @@ -1,9 +1,9 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "utf8proc.hpp" namespace duckdb { @@ -13,7 +13,7 @@ struct InstrOperator { static inline TR Operation(TA haystack, TB needle) { int64_t string_position = 0; - auto location = FindStrInStr(haystack, needle); + auto location = ContainsFun::Find(haystack, needle); if (location != DConstants::INVALID_INDEX) { auto len = (utf8proc_ssize_t)location; auto str = reinterpret_cast(haystack.GetData()); @@ -32,7 +32,7 @@ struct InstrOperator { struct InstrAsciiOperator { template static inline TR Operation(TA haystack, TB needle) { - auto location = FindStrInStr(haystack, needle); + auto location = ContainsFun::Find(haystack, needle); return UnsafeNumericCast(location == DConstants::INVALID_INDEX ? 0U : location + 1U); } }; diff --git a/src/duckdb/extension/core_functions/scalar/string/jaccard.cpp b/src/duckdb/src/core_functions/scalar/string/jaccard.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/string/jaccard.cpp rename to src/duckdb/src/core_functions/scalar/string/jaccard.cpp index eae31dc9c..e3f081b6a 100644 --- a/src/duckdb/extension/core_functions/scalar/string/jaccard.cpp +++ b/src/duckdb/src/core_functions/scalar/string/jaccard.cpp @@ -1,6 +1,6 @@ #include "duckdb/common/map.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include #include diff --git a/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp b/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp new file mode 100644 index 000000000..3c54b411f --- /dev/null +++ b/src/duckdb/src/core_functions/scalar/string/jaro_winkler.cpp @@ -0,0 +1,71 @@ +#include "jaro_winkler.hpp" + +#include "duckdb/core_functions/scalar/string_functions.hpp" + +namespace duckdb { + +static inline double JaroScalarFunction(const string_t &s1, const string_t &s2) { + auto s1_begin = s1.GetData(); + auto s2_begin = s2.GetData(); + return duckdb_jaro_winkler::jaro_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, s2_begin + s2.GetSize()); +} + +static inline double JaroWinklerScalarFunction(const string_t &s1, const string_t &s2) { + auto s1_begin = s1.GetData(); + auto s2_begin = s2.GetData(); + return duckdb_jaro_winkler::jaro_winkler_similarity(s1_begin, s1_begin + s1.GetSize(), s2_begin, + s2_begin + s2.GetSize()); +} + +template +static void CachedFunction(Vector &constant, Vector &other, Vector &result, idx_t count) { + auto val = constant.GetValue(0); + if (val.IsNull()) { + auto &result_validity = FlatVector::Validity(result); + result_validity.SetAllInvalid(count); + return; + } + + auto str_val = StringValue::Get(val); + auto cached = CACHED_SIMILARITY(str_val); + UnaryExecutor::Execute(other, result, count, [&](const string_t &other_str) { + auto other_str_begin = other_str.GetData(); + return cached.similarity(other_str_begin, other_str_begin + other_str.GetSize()); + }); +} + +template > +static void TemplatedJaroWinklerFunction(DataChunk &args, Vector &result, SIMILARITY_FUNCTION fun) { + bool arg0_constant = args.data[0].GetVectorType() == VectorType::CONSTANT_VECTOR; + bool arg1_constant = args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR; + if (!(arg0_constant ^ arg1_constant)) { + // We can't optimize by caching one of the two strings + BinaryExecutor::Execute(args.data[0], args.data[1], result, args.size(), fun); + return; + } + + if (arg0_constant) { + CachedFunction(args.data[0], args.data[1], result, args.size()); + } else { + CachedFunction(args.data[1], args.data[0], result, args.size()); + } +} + +static void JaroFunction(DataChunk &args, ExpressionState &state, Vector &result) { + TemplatedJaroWinklerFunction>(args, result, JaroScalarFunction); +} + +static void JaroWinklerFunction(DataChunk &args, ExpressionState &state, Vector &result) { + TemplatedJaroWinklerFunction>(args, result, + JaroWinklerScalarFunction); +} + +ScalarFunction JaroSimilarityFun::GetFunction() { + return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroFunction); +} + +ScalarFunction JaroWinklerSimilarityFun::GetFunction() { + return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::DOUBLE, JaroWinklerFunction); +} + +} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/string/left_right.cpp b/src/duckdb/src/core_functions/scalar/string/left_right.cpp similarity index 89% rename from src/duckdb/extension/core_functions/scalar/string/left_right.cpp rename to src/duckdb/src/core_functions/scalar/string/left_right.cpp index b13ff9560..886559b62 100644 --- a/src/duckdb/extension/core_functions/scalar/string/left_right.cpp +++ b/src/duckdb/src/core_functions/scalar/string/left_right.cpp @@ -1,7 +1,7 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/limits.hpp" -#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include #include @@ -11,22 +11,22 @@ namespace duckdb { struct LeftRightUnicode { template static inline TR Operation(TA input) { - return Length(input); + return LengthFun::Length(input); } static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringUnicode(result, input, offset, length); + return SubstringFun::SubstringUnicode(result, input, offset, length); } }; struct LeftRightGrapheme { template static inline TR Operation(TA input) { - return GraphemeCount(input); + return LengthFun::GraphemeCount(input); } static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringGrapheme(result, input, offset, length); + return SubstringFun::SubstringGrapheme(result, input, offset, length); } }; diff --git a/src/duckdb/extension/core_functions/scalar/string/levenshtein.cpp b/src/duckdb/src/core_functions/scalar/string/levenshtein.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/levenshtein.cpp rename to src/duckdb/src/core_functions/scalar/string/levenshtein.cpp index 24e28b89c..13731e385 100644 --- a/src/duckdb/extension/core_functions/scalar/string/levenshtein.cpp +++ b/src/duckdb/src/core_functions/scalar/string/levenshtein.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/string_util.hpp" diff --git a/src/duckdb/src/function/scalar/string/md5.cpp b/src/duckdb/src/core_functions/scalar/string/md5.cpp similarity index 96% rename from src/duckdb/src/function/scalar/string/md5.cpp rename to src/duckdb/src/core_functions/scalar/string/md5.cpp index 837f97c12..399e3a90a 100644 --- a/src/duckdb/src/function/scalar/string/md5.cpp +++ b/src/duckdb/src/core_functions/scalar/string/md5.cpp @@ -1,7 +1,7 @@ -#include "duckdb/common/crypto/md5.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" +#include "duckdb/common/crypto/md5.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/string/pad.cpp b/src/duckdb/src/core_functions/scalar/string/pad.cpp similarity index 90% rename from src/duckdb/extension/core_functions/scalar/string/pad.cpp rename to src/duckdb/src/core_functions/scalar/string/pad.cpp index 586e1605a..856544ea7 100644 --- a/src/duckdb/extension/core_functions/scalar/string/pad.cpp +++ b/src/duckdb/src/core_functions/scalar/string/pad.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/algorithm.hpp" #include "duckdb/common/exception.hpp" @@ -131,17 +131,13 @@ static void PadFunction(DataChunk &args, ExpressionState &state, Vector &result) } ScalarFunction LpadFun::GetFunction() { - ScalarFunction func({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, - PadFunction); - BaseScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, + PadFunction); } ScalarFunction RpadFun::GetFunction() { - ScalarFunction func({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, - PadFunction); - BaseScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction({LogicalType::VARCHAR, LogicalType::INTEGER, LogicalType::VARCHAR}, LogicalType::VARCHAR, + PadFunction); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/string/parse_path.cpp b/src/duckdb/src/core_functions/scalar/string/parse_path.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/parse_path.cpp rename to src/duckdb/src/core_functions/scalar/string/parse_path.cpp index 9ed926b4a..cc304d512 100644 --- a/src/duckdb/extension/core_functions/scalar/string/parse_path.cpp +++ b/src/duckdb/src/core_functions/scalar/string/parse_path.cpp @@ -1,5 +1,5 @@ -#include "core_functions/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/local_file_system.hpp" #include @@ -56,11 +56,11 @@ static idx_t Find(const char *input_data, idx_t input_size, const string &sep_da if (sep_data.empty()) { return 0; } - auto pos = FindStrInStr(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[0]), 1); + auto pos = ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[0]), 1); // both_slash option if (sep_data.size() > 1) { auto sec_pos = - FindStrInStr(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[1]), 1); + ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(&sep_data[1]), 1); // choose the leftmost valid position if (sec_pos != DConstants::INVALID_INDEX && (sec_pos < pos || pos == DConstants::INVALID_INDEX)) { return sec_pos; diff --git a/src/duckdb/extension/core_functions/scalar/string/printf.cpp b/src/duckdb/src/core_functions/scalar/string/printf.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/printf.cpp rename to src/duckdb/src/core_functions/scalar/string/printf.cpp index 1db25b0df..8b670b5ad 100644 --- a/src/duckdb/extension/core_functions/scalar/string/printf.cpp +++ b/src/duckdb/src/core_functions/scalar/string/printf.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/limits.hpp" #include "fmt/format.h" @@ -173,7 +173,6 @@ ScalarFunction PrintfFun::GetFunction() { ScalarFunction printf_fun({LogicalType::VARCHAR}, LogicalType::VARCHAR, PrintfFunction, BindPrintfFunction); printf_fun.varargs = LogicalType::ANY; - BaseScalarFunction::SetReturnsError(printf_fun); return printf_fun; } @@ -182,7 +181,6 @@ ScalarFunction FormatFun::GetFunction() { ScalarFunction format_fun({LogicalType::VARCHAR}, LogicalType::VARCHAR, PrintfFunction, BindPrintfFunction); format_fun.varargs = LogicalType::ANY; - BaseScalarFunction::SetReturnsError(format_fun); return format_fun; } diff --git a/src/duckdb/src/function/scalar/string/regexp_escape.cpp b/src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp similarity index 77% rename from src/duckdb/src/function/scalar/string/regexp_escape.cpp rename to src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp index 3d72fe681..32517c9c8 100644 --- a/src/duckdb/src/function/scalar/string/regexp_escape.cpp +++ b/src/duckdb/src/core_functions/scalar/string/regexp_escape.cpp @@ -1,4 +1,4 @@ -#include "duckdb/function/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "re2/re2.h" namespace duckdb { @@ -16,7 +16,7 @@ static void RegexpEscapeFunction(DataChunk &args, ExpressionState &state, Vector } ScalarFunction RegexpEscapeFun::GetFunction() { - return ScalarFunction("regexp_escape", {LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexpEscapeFunction); + return ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexpEscapeFunction); } } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/string/repeat.cpp b/src/duckdb/src/core_functions/scalar/string/repeat.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/string/repeat.cpp rename to src/duckdb/src/core_functions/scalar/string/repeat.cpp index 154634f94..31318290f 100644 --- a/src/duckdb/extension/core_functions/scalar/string/repeat.cpp +++ b/src/duckdb/src/core_functions/scalar/string/repeat.cpp @@ -1,5 +1,5 @@ #include "duckdb/common/vector_operations/binary_executor.hpp" -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/operator/multiply.hpp" namespace duckdb { @@ -81,9 +81,6 @@ ScalarFunctionSet RepeatFun::GetFunctions() { } repeat.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::LIST(LogicalType::ANY), RepeatListFunction, RepeatBindFunction)); - for (auto &func : repeat.functions) { - BaseScalarFunction::SetReturnsError(func); - } return repeat; } diff --git a/src/duckdb/extension/core_functions/scalar/string/replace.cpp b/src/duckdb/src/core_functions/scalar/string/replace.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/replace.cpp rename to src/duckdb/src/core_functions/scalar/string/replace.cpp index 4702292c5..a85d390f7 100644 --- a/src/duckdb/extension/core_functions/scalar/string/replace.cpp +++ b/src/duckdb/src/core_functions/scalar/string/replace.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/reverse.cpp b/src/duckdb/src/core_functions/scalar/string/reverse.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/string/reverse.cpp rename to src/duckdb/src/core_functions/scalar/string/reverse.cpp index 4ff654909..cef1441fa 100644 --- a/src/duckdb/extension/core_functions/scalar/string/reverse.cpp +++ b/src/duckdb/src/core_functions/scalar/string/reverse.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/src/function/scalar/string/sha1.cpp b/src/duckdb/src/core_functions/scalar/string/sha1.cpp similarity index 94% rename from src/duckdb/src/function/scalar/string/sha1.cpp rename to src/duckdb/src/core_functions/scalar/string/sha1.cpp index c59dcf252..82ec9b7ab 100644 --- a/src/duckdb/src/function/scalar/string/sha1.cpp +++ b/src/duckdb/src/core_functions/scalar/string/sha1.cpp @@ -1,6 +1,6 @@ -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "mbedtls_wrapper.hpp" namespace duckdb { diff --git a/src/duckdb/src/function/scalar/string/sha256.cpp b/src/duckdb/src/core_functions/scalar/string/sha256.cpp similarity index 94% rename from src/duckdb/src/function/scalar/string/sha256.cpp rename to src/duckdb/src/core_functions/scalar/string/sha256.cpp index a48ccf93f..32ca5f5c2 100644 --- a/src/duckdb/src/function/scalar/string/sha256.cpp +++ b/src/duckdb/src/core_functions/scalar/string/sha256.cpp @@ -1,6 +1,6 @@ -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "mbedtls_wrapper.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/string/starts_with.cpp b/src/duckdb/src/core_functions/scalar/string/starts_with.cpp similarity index 76% rename from src/duckdb/extension/core_functions/scalar/string/starts_with.cpp rename to src/duckdb/src/core_functions/scalar/string/starts_with.cpp index 7ef277292..c4661b913 100644 --- a/src/duckdb/extension/core_functions/scalar/string/starts_with.cpp +++ b/src/duckdb/src/core_functions/scalar/string/starts_with.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" @@ -37,10 +37,8 @@ struct StartsWithOperator { }; ScalarFunction StartsWithOperatorFun::GetFunction() { - ScalarFunction starts_with({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction); - starts_with.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return starts_with; + return ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/string_split.cpp b/src/duckdb/src/core_functions/scalar/string/string_split.cpp similarity index 96% rename from src/duckdb/src/function/scalar/string/string_split.cpp rename to src/duckdb/src/core_functions/scalar/string/string_split.cpp index 9673eca96..c62cacd75 100644 --- a/src/duckdb/src/function/scalar/string/string_split.cpp +++ b/src/duckdb/src/core_functions/scalar/string/string_split.cpp @@ -1,10 +1,10 @@ -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/vector_size.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/function/scalar/regexp.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" namespace duckdb { @@ -36,7 +36,8 @@ struct RegularStringSplit { if (delim_size == 0) { return 0; } - return FindStrInStr(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(delim_data), delim_size); + return ContainsFun::Find(const_uchar_ptr_cast(input_data), input_size, const_uchar_ptr_cast(delim_data), + delim_size); } }; @@ -83,7 +84,7 @@ struct StringSplitter { // special case: 0 length match and pos is 0 // move to the next character for (pos++; pos < input_size; pos++) { - if (IsCharacter(input_data[pos])) { + if (LengthFun::IsCharacter(input_data[pos])) { break; } } diff --git a/src/duckdb/extension/core_functions/scalar/string/to_base.cpp b/src/duckdb/src/core_functions/scalar/string/to_base.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/string/to_base.cpp rename to src/duckdb/src/core_functions/scalar/string/to_base.cpp index f85f54be9..963f4f562 100644 --- a/src/duckdb/extension/core_functions/scalar/string/to_base.cpp +++ b/src/duckdb/src/core_functions/scalar/string/to_base.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/translate.cpp b/src/duckdb/src/core_functions/scalar/string/translate.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/string/translate.cpp rename to src/duckdb/src/core_functions/scalar/string/translate.cpp index ca661cb3d..c01ec2a25 100644 --- a/src/duckdb/extension/core_functions/scalar/string/translate.cpp +++ b/src/duckdb/src/core_functions/scalar/string/translate.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/trim.cpp b/src/duckdb/src/core_functions/scalar/string/trim.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/string/trim.cpp rename to src/duckdb/src/core_functions/scalar/string/trim.cpp index 5553d75e3..d89ebbaff 100644 --- a/src/duckdb/extension/core_functions/scalar/string/trim.cpp +++ b/src/duckdb/src/core_functions/scalar/string/trim.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/unicode.cpp b/src/duckdb/src/core_functions/scalar/string/unicode.cpp similarity index 92% rename from src/duckdb/extension/core_functions/scalar/string/unicode.cpp rename to src/duckdb/src/core_functions/scalar/string/unicode.cpp index 902c7c5e7..b62a129aa 100644 --- a/src/duckdb/extension/core_functions/scalar/string/unicode.cpp +++ b/src/duckdb/src/core_functions/scalar/string/unicode.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/string/url_encode.cpp b/src/duckdb/src/core_functions/scalar/string/url_encode.cpp similarity index 96% rename from src/duckdb/extension/core_functions/scalar/string/url_encode.cpp rename to src/duckdb/src/core_functions/scalar/string/url_encode.cpp index 17b9ad3cc..51d49079c 100644 --- a/src/duckdb/extension/core_functions/scalar/string/url_encode.cpp +++ b/src/duckdb/src/core_functions/scalar/string/url_encode.cpp @@ -1,5 +1,5 @@ #include "duckdb/common/vector_operations/unary_executor.hpp" -#include "core_functions/scalar/string_functions.hpp" +#include "duckdb/core_functions/scalar/string_functions.hpp" #include "duckdb/common/string_util.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp b/src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp similarity index 66% rename from src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp rename to src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp index c83a83e3c..6a44d12a7 100644 --- a/src/duckdb/extension/core_functions/scalar/struct/struct_insert.cpp +++ b/src/duckdb/src/core_functions/scalar/struct/struct_insert.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/struct_functions.hpp" +#include "duckdb/core_functions/scalar/struct_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" @@ -11,23 +11,25 @@ namespace duckdb { static void StructInsertFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &starting_vec = args.data[0]; + starting_vec.Verify(args.size()); auto &starting_child_entries = StructVector::GetEntries(starting_vec); auto &result_child_entries = StructVector::GetEntries(result); - // Assign the original child entries to the STRUCT. - for (idx_t i = 0; i < starting_child_entries.size(); i++) { + // Assign the starting vector entries to the result vector + for (size_t i = 0; i < starting_child_entries.size(); i++) { auto &starting_child = starting_child_entries[i]; result_child_entries[i]->Reference(*starting_child); } - // Assign the new children to the result vector. - for (idx_t i = 1; i < args.ColumnCount(); i++) { + // Assign the new entries to the result vector + for (size_t i = 1; i < args.ColumnCount(); i++) { result_child_entries[starting_child_entries.size() + i - 1]->Reference(args.data[i]); } result.Verify(args.size()); + if (args.AllConstant()) { result.SetVectorType(VectorType::CONSTANT_VECTOR); } @@ -35,65 +37,69 @@ static void StructInsertFunction(DataChunk &args, ExpressionState &state, Vector static unique_ptr StructInsertBind(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { + case_insensitive_set_t name_collision_set; + if (arguments.empty()) { throw InvalidInputException("Missing required arguments for struct_insert function."); } + if (LogicalTypeId::STRUCT != arguments[0]->return_type.id()) { throw InvalidInputException("The first argument to struct_insert must be a STRUCT"); } + if (arguments.size() < 2) { - throw InvalidInputException("Can't insert nothing into a STRUCT"); + throw InvalidInputException("Can't insert nothing into a struct"); } - case_insensitive_set_t name_collision_set; - child_list_t new_children; - auto &existing_children = StructType::GetChildTypes(arguments[0]->return_type); + child_list_t new_struct_children; - for (idx_t i = 0; i < existing_children.size(); i++) { - auto &child = existing_children[i]; + auto &existing_struct_children = StructType::GetChildTypes(arguments[0]->return_type); + + for (size_t i = 0; i < existing_struct_children.size(); i++) { + auto &child = existing_struct_children[i]; name_collision_set.insert(child.first); - new_children.push_back(make_pair(child.first, child.second)); + new_struct_children.push_back(make_pair(child.first, child.second)); } // Loop through the additional arguments (name/value pairs) for (idx_t i = 1; i < arguments.size(); i++) { auto &child = arguments[i]; - if (child->GetAlias().empty()) { - throw BinderException("Need named argument for struct insert, e.g., a := b"); + if (child->alias.empty() && bound_function.name == "struct_insert") { + throw BinderException("Need named argument for struct insert, e.g. STRUCT_PACK(a := b)"); } - if (name_collision_set.find(child->GetAlias()) != name_collision_set.end()) { - throw BinderException("Duplicate struct entry name \"%s\"", child->GetAlias()); + if (name_collision_set.find(child->alias) != name_collision_set.end()) { + throw BinderException("Duplicate struct entry name \"%s\"", child->alias); } - name_collision_set.insert(child->GetAlias()); - new_children.push_back(make_pair(child->GetAlias(), arguments[i]->return_type)); + name_collision_set.insert(child->alias); + new_struct_children.push_back(make_pair(child->alias, arguments[i]->return_type)); } - bound_function.return_type = LogicalType::STRUCT(new_children); + // this is more for completeness reasons + bound_function.return_type = LogicalType::STRUCT(new_struct_children); return make_uniq(bound_function.return_type); } unique_ptr StructInsertStats(ClientContext &context, FunctionStatisticsInput &input) { auto &child_stats = input.child_stats; auto &expr = input.expr; - auto new_stats = StructStats::CreateUnknown(expr.return_type); + auto new_struct_stats = StructStats::CreateUnknown(expr.return_type); auto existing_count = StructType::GetChildCount(child_stats[0].GetType()); auto existing_stats = StructStats::GetChildStats(child_stats[0]); for (idx_t i = 0; i < existing_count; i++) { - StructStats::SetChildStats(new_stats, i, existing_stats[i]); + StructStats::SetChildStats(new_struct_stats, i, existing_stats[i]); } - auto new_count = StructType::GetChildCount(expr.return_type); auto offset = new_count - child_stats.size(); for (idx_t i = 1; i < child_stats.size(); i++) { - StructStats::SetChildStats(new_stats, offset + i, child_stats[i]); + StructStats::SetChildStats(new_struct_stats, offset + i, child_stats[i]); } - return new_stats.ToUnique(); + return new_struct_stats.ToUnique(); } ScalarFunction StructInsertFun::GetFunction() { + // the arguments and return types are actually set in the binder function ScalarFunction fun({}, LogicalTypeId::STRUCT, StructInsertFunction, StructInsertBind, nullptr, StructInsertStats); - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; fun.varargs = LogicalType::ANY; fun.serialize = VariableReturnBindData::Serialize; fun.deserialize = VariableReturnBindData::Deserialize; diff --git a/src/duckdb/src/function/scalar/struct/struct_pack.cpp b/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp similarity index 96% rename from src/duckdb/src/function/scalar/struct/struct_pack.cpp rename to src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp index 51a3e34ca..4e71ea36f 100644 --- a/src/duckdb/src/function/scalar/struct/struct_pack.cpp +++ b/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp @@ -1,11 +1,11 @@ -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/struct_functions.hpp" -#include "duckdb/common/case_insensitive_map.hpp" +#include "duckdb/core_functions/scalar/struct_functions.hpp" +#include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/expression/bound_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/expression_binder.hpp" +#include "duckdb/function/scalar/nested_functions.hpp" +#include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/storage/statistics/struct_stats.hpp" +#include "duckdb/planner/expression_binder.hpp" namespace duckdb { @@ -43,10 +43,10 @@ static unique_ptr StructPackBind(ClientContext &context, ScalarFun auto &child = arguments[i]; string alias; if (IS_STRUCT_PACK) { - if (child->GetAlias().empty()) { + if (child->alias.empty()) { throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)"); } - alias = child->GetAlias(); + alias = child->alias; if (name_collision_set.find(alias) != name_collision_set.end()) { throw BinderException("Duplicate struct entry name \"%s\"", alias); } diff --git a/src/duckdb/extension/core_functions/scalar/union/union_extract.cpp b/src/duckdb/src/core_functions/scalar/union/union_extract.cpp similarity index 98% rename from src/duckdb/extension/core_functions/scalar/union/union_extract.cpp rename to src/duckdb/src/core_functions/scalar/union/union_extract.cpp index 2a5371076..8478ad0fd 100644 --- a/src/duckdb/extension/core_functions/scalar/union/union_extract.cpp +++ b/src/duckdb/src/core_functions/scalar/union/union_extract.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/union_functions.hpp" +#include "duckdb/core_functions/scalar/union_functions.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/union/union_tag.cpp b/src/duckdb/src/core_functions/scalar/union/union_tag.cpp similarity index 97% rename from src/duckdb/extension/core_functions/scalar/union/union_tag.cpp rename to src/duckdb/src/core_functions/scalar/union/union_tag.cpp index 173e36d6c..431df0ad2 100644 --- a/src/duckdb/extension/core_functions/scalar/union/union_tag.cpp +++ b/src/duckdb/src/core_functions/scalar/union/union_tag.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/union_functions.hpp" +#include "duckdb/core_functions/scalar/union_functions.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" diff --git a/src/duckdb/extension/core_functions/scalar/union/union_value.cpp b/src/duckdb/src/core_functions/scalar/union/union_value.cpp similarity index 92% rename from src/duckdb/extension/core_functions/scalar/union/union_value.cpp rename to src/duckdb/src/core_functions/scalar/union/union_value.cpp index 655003da9..6ba7070a5 100644 --- a/src/duckdb/extension/core_functions/scalar/union/union_value.cpp +++ b/src/duckdb/src/core_functions/scalar/union/union_value.cpp @@ -1,4 +1,4 @@ -#include "core_functions/scalar/union_functions.hpp" +#include "duckdb/core_functions/scalar/union_functions.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/scalar/nested_functions.hpp" @@ -44,13 +44,13 @@ static unique_ptr UnionValueBind(ClientContext &context, ScalarFun } auto &child = arguments[0]; - if (child->GetAlias().empty()) { + if (child->alias.empty()) { throw BinderException("Need named argument for union tag, e.g. UNION_VALUE(a := b)"); } child_list_t union_members; - union_members.push_back(make_pair(child->GetAlias(), child->return_type)); + union_members.push_back(make_pair(child->alias, child->return_type)); bound_function.return_type = LogicalType::UNION(std::move(union_members)); return make_uniq(bound_function.return_type); diff --git a/src/duckdb/src/execution/adaptive_filter.cpp b/src/duckdb/src/execution/adaptive_filter.cpp index 6077ae3ff..ce4025d25 100644 --- a/src/duckdb/src/execution/adaptive_filter.cpp +++ b/src/duckdb/src/execution/adaptive_filter.cpp @@ -11,9 +11,6 @@ AdaptiveFilter::AdaptiveFilter(const Expression &expr) : observe_interval(10), e D_ASSERT(conj_expr.children.size() > 1); for (idx_t idx = 0; idx < conj_expr.children.size(); idx++) { permutation.push_back(idx); - if (conj_expr.children[idx]->CanThrow()) { - disable_permutations = true; - } if (idx != conj_expr.children.size() - 1) { swap_likeliness.push_back(100); } @@ -32,7 +29,7 @@ AdaptiveFilter::AdaptiveFilter(const TableFilterSet &table_filters) } AdaptiveFilterState AdaptiveFilter::BeginFilter() const { - if (permutation.size() <= 1 || disable_permutations) { + if (permutation.size() <= 1) { return AdaptiveFilterState(); } AdaptiveFilterState state; @@ -41,7 +38,7 @@ AdaptiveFilterState AdaptiveFilter::BeginFilter() const { } void AdaptiveFilter::EndFilter(AdaptiveFilterState state) { - if (permutation.size() <= 1 || disable_permutations) { + if (permutation.size() <= 1) { // nothing to permute return; } @@ -53,7 +50,6 @@ void AdaptiveFilter::AdaptRuntimeStatistics(double duration) { iteration_count++; runtime_sum += duration; - D_ASSERT(!disable_permutations); if (!warmup) { // the last swap was observed if (observe && iteration_count == observe_interval) { diff --git a/src/duckdb/src/execution/aggregate_hashtable.cpp b/src/duckdb/src/execution/aggregate_hashtable.cpp index 198b77fac..e09fd9b70 100644 --- a/src/duckdb/src/execution/aggregate_hashtable.cpp +++ b/src/duckdb/src/execution/aggregate_hashtable.cpp @@ -41,8 +41,7 @@ GroupedAggregateHashTable::GroupedAggregateHashTable(ClientContext &context, All vector aggregate_objects_p, idx_t initial_capacity, idx_t radix_bits) : BaseAggregateHashTable(context, allocator, aggregate_objects_p, std::move(payload_types_p)), - radix_bits(radix_bits), count(0), capacity(0), skip_lookups(false), - aggregate_allocator(make_shared_ptr(allocator)) { + radix_bits(radix_bits), count(0), capacity(0), aggregate_allocator(make_shared_ptr(allocator)) { // Append hash column to the end and initialise the row layout group_types_p.emplace_back(LogicalType::HASH); @@ -52,9 +51,6 @@ GroupedAggregateHashTable::GroupedAggregateHashTable(ClientContext &context, All // Partitioned data and pointer table InitializePartitionedData(); - if (radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD) { - InitializeUnpartitionedData(); - } Resize(initial_capacity); // Predicates @@ -63,8 +59,7 @@ GroupedAggregateHashTable::GroupedAggregateHashTable(ClientContext &context, All } void GroupedAggregateHashTable::InitializePartitionedData() { - if (!partitioned_data || - RadixPartitioning::RadixBitsOfPowerOfTwo(partitioned_data->PartitionCount()) != radix_bits) { + if (!partitioned_data || RadixPartitioning::RadixBits(partitioned_data->PartitionCount()) != radix_bits) { D_ASSERT(!partitioned_data || partitioned_data->Count() == 0); partitioned_data = make_uniq(buffer_manager, layout, radix_bits, layout.ColumnCount() - 1); @@ -76,70 +71,11 @@ void GroupedAggregateHashTable::InitializePartitionedData() { D_ASSERT(GetLayout().GetDataWidth() == layout.GetDataWidth()); D_ASSERT(GetLayout().GetRowWidth() == layout.GetRowWidth()); - partitioned_data->InitializeAppendState(state.partitioned_append_state, - TupleDataPinProperties::KEEP_EVERYTHING_PINNED); -} - -void GroupedAggregateHashTable::InitializeUnpartitionedData() { - D_ASSERT(radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD); - if (!unpartitioned_data) { - unpartitioned_data = - make_uniq(buffer_manager, layout, 0ULL, layout.ColumnCount() - 1); - } else { - unpartitioned_data->Reset(); - } - unpartitioned_data->InitializeAppendState(state.unpartitioned_append_state, - TupleDataPinProperties::KEEP_EVERYTHING_PINNED); -} - -const PartitionedTupleData &GroupedAggregateHashTable::GetPartitionedData() const { - return *partitioned_data; -} - -unique_ptr GroupedAggregateHashTable::AcquirePartitionedData() { - // Flush/unpin partitioned data - partitioned_data->FlushAppendState(state.partitioned_append_state); - partitioned_data->Unpin(); - - if (radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD) { - // Flush/unpin unpartitioned data and append to partitioned data - if (unpartitioned_data) { - unpartitioned_data->FlushAppendState(state.unpartitioned_append_state); - unpartitioned_data->Unpin(); - unpartitioned_data->Repartition(*partitioned_data); - } - InitializeUnpartitionedData(); - } - - // Return and re-initialize - auto result = std::move(partitioned_data); - InitializePartitionedData(); - return result; -} - -void GroupedAggregateHashTable::Abandon() { - if (radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD) { - // Flush/unpin unpartitioned data and append to partitioned data - if (unpartitioned_data) { - unpartitioned_data->FlushAppendState(state.unpartitioned_append_state); - unpartitioned_data->Unpin(); - unpartitioned_data->Repartition(*partitioned_data); - } - InitializeUnpartitionedData(); - } - - // Start over - ClearPointerTable(); - count = 0; - - // Resetting the id ensures the dict state is reset properly when needed - state.dict_state.dictionary_id = string(); + partitioned_data->InitializeAppendState(state.append_state, TupleDataPinProperties::KEEP_EVERYTHING_PINNED); } -void GroupedAggregateHashTable::Repartition() { - auto old = AcquirePartitionedData(); - D_ASSERT(old->GetPartitions().size() != partitioned_data->GetPartitions().size()); - old->Repartition(*partitioned_data); +unique_ptr &GroupedAggregateHashTable::GetPartitionedData() { + return partitioned_data; } shared_ptr GroupedAggregateHashTable::GetAggregateAllocator() { @@ -195,11 +131,7 @@ idx_t GroupedAggregateHashTable::Capacity() const { } idx_t GroupedAggregateHashTable::ResizeThreshold() const { - return ResizeThreshold(Capacity()); -} - -idx_t GroupedAggregateHashTable::ResizeThreshold(const idx_t capacity) { - return LossyNumericCast(static_cast(capacity) / LOAD_FACTOR); + return LossyNumericCast(static_cast(Capacity()) / LOAD_FACTOR); } idx_t GroupedAggregateHashTable::ApplyBitMask(hash_t hash) const { @@ -208,9 +140,6 @@ idx_t GroupedAggregateHashTable::ApplyBitMask(hash_t hash) const { void GroupedAggregateHashTable::Verify() { #ifdef DEBUG - if (skip_lookups) { - return; - } idx_t total_count = 0; for (idx_t i = 0; i < capacity; i++) { const auto &entry = entries[i]; @@ -226,30 +155,22 @@ void GroupedAggregateHashTable::Verify() { } void GroupedAggregateHashTable::ClearPointerTable() { - std::fill_n(entries, capacity, ht_entry_t()); -} - -void GroupedAggregateHashTable::SetRadixBits(idx_t radix_bits_p) { - radix_bits = radix_bits_p; -} - -idx_t GroupedAggregateHashTable::GetRadixBits() const { - return radix_bits; + std::fill_n(entries, capacity, ht_entry_t::GetEmptyEntry()); } -idx_t GroupedAggregateHashTable::GetSinkCount() const { - return sink_count; +void GroupedAggregateHashTable::ResetCount() { + count = 0; } -void GroupedAggregateHashTable::SkipLookups() { - skip_lookups = true; +void GroupedAggregateHashTable::SetRadixBits(idx_t radix_bits_p) { + radix_bits = radix_bits_p; } void GroupedAggregateHashTable::Resize(idx_t size) { D_ASSERT(size >= STANDARD_VECTOR_SIZE); D_ASSERT(IsPowerOfTwo(size)); - if (Count() != 0 && size < capacity) { - throw InternalException("Cannot downsize a non-empty hash table!"); + if (size < capacity) { + throw InternalException("Cannot downsize a hash table!"); } capacity = size; @@ -259,43 +180,39 @@ void GroupedAggregateHashTable::Resize(idx_t size) { bitmask = capacity - 1; if (Count() != 0) { - ReinsertTuples(*partitioned_data); - if (radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD) { - ReinsertTuples(*unpartitioned_data); + for (auto &data_collection : partitioned_data->GetPartitions()) { + if (data_collection->Count() == 0) { + continue; + } + TupleDataChunkIterator iterator(*data_collection, TupleDataPinProperties::ALREADY_PINNED, false); + const auto row_locations = iterator.GetRowLocations(); + do { + for (idx_t i = 0; i < iterator.GetCurrentChunkCount(); i++) { + const auto &row_location = row_locations[i]; + const auto hash = Load(row_location + hash_offset); + + // Find an empty entry + auto entry_idx = ApplyBitMask(hash); + D_ASSERT(entry_idx == hash % capacity); + while (entries[entry_idx].IsOccupied()) { + entry_idx++; + if (entry_idx >= capacity) { + entry_idx = 0; + } + } + auto &entry = entries[entry_idx]; + D_ASSERT(!entry.IsOccupied()); + entry.SetSalt(ht_entry_t::ExtractSalt(hash)); + entry.SetPointer(row_location); + D_ASSERT(entry.IsOccupied()); + } + } while (iterator.Next()); } } Verify(); } -void GroupedAggregateHashTable::ReinsertTuples(PartitionedTupleData &data) { - for (auto &data_collection : data.GetPartitions()) { - if (data_collection->Count() == 0) { - continue; - } - TupleDataChunkIterator iterator(*data_collection, TupleDataPinProperties::ALREADY_PINNED, false); - const auto row_locations = iterator.GetRowLocations(); - do { - for (idx_t i = 0; i < iterator.GetCurrentChunkCount(); i++) { - const auto &row_location = row_locations[i]; - const auto hash = Load(row_location + hash_offset); - - // Find an empty entry - auto ht_offset = ApplyBitMask(hash); - D_ASSERT(ht_offset == hash % capacity); - while (entries[ht_offset].IsOccupied()) { - IncrementAndWrap(ht_offset, bitmask); - } - auto &entry = entries[ht_offset]; - D_ASSERT(!entry.IsOccupied()); - entry.SetSalt(ht_entry_t::ExtractSalt(hash)); - entry.SetPointer(row_location); - D_ASSERT(entry.IsOccupied()); - } - } while (iterator.Next()); - } -} - idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, DataChunk &payload, AggregateType filter) { unsafe_vector aggregate_filter; @@ -309,185 +226,29 @@ idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, DataChunk &payload, return AddChunk(groups, payload, aggregate_filter); } -GroupedAggregateHashTable::AggregateDictionaryState::AggregateDictionaryState() - : hashes(LogicalType::HASH), new_dictionary_pointers(LogicalType::POINTER), unique_entries(STANDARD_VECTOR_SIZE) { -} - -optional_idx GroupedAggregateHashTable::TryAddDictionaryGroups(DataChunk &groups, DataChunk &payload, - const unsafe_vector &filter) { - static constexpr idx_t MAX_DICTIONARY_SIZE_THRESHOLD = 20000; - static constexpr idx_t DICTIONARY_THRESHOLD = 2; - // dictionary vector - check if this is a duplicate eliminated dictionary from the storage - auto &dict_col = groups.data[0]; - auto opt_dict_size = DictionaryVector::DictionarySize(dict_col); - if (!opt_dict_size.IsValid()) { - // dict size not known - this is not a dictionary that comes from the storage - return optional_idx(); - } - idx_t dict_size = opt_dict_size.GetIndex(); - auto &dictionary_id = DictionaryVector::DictionaryId(dict_col); - if (dictionary_id.empty()) { - // dictionary has no id, we can't cache across vectors - // only use dictionary compression if there are fewer entries than groups - if (dict_size >= groups.size() * DICTIONARY_THRESHOLD) { - // dictionary is too large - use regular aggregation - return optional_idx(); - } - } else { - // dictionary has an id - we can cache across vectors - // use a much larger limit for dictionary - if (dict_size >= MAX_DICTIONARY_SIZE_THRESHOLD) { - // dictionary is too large - use regular aggregation - return optional_idx(); - } - } - auto &dictionary_vector = DictionaryVector::Child(dict_col); - auto &offsets = DictionaryVector::SelVector(dict_col); - auto &dict_state = state.dict_state; - if (dict_state.dictionary_id.empty() || dict_state.dictionary_id != dictionary_id) { - // new dictionary - initialize the index state - if (dict_size > dict_state.capacity) { - dict_state.dictionary_addresses = make_uniq(LogicalType::POINTER, dict_size); - dict_state.found_entry = make_unsafe_uniq_array(dict_size); - dict_state.capacity = dict_size; - } - memset(dict_state.found_entry.get(), 0, dict_size * sizeof(bool)); - dict_state.dictionary_id = dictionary_id; - } else if (dict_size > dict_state.capacity) { - throw InternalException("AggregateHT - using cached dictionary data but dictionary has changed (dictionary id " - "%s - dict size %d, current capacity %d)", - dict_state.dictionary_id, dict_size, dict_state.capacity); - } - - auto &found_entry = dict_state.found_entry; - auto &unique_entries = dict_state.unique_entries; - idx_t unique_count = 0; - // for each of the dictionary entries - check if we have already done a look-up into the hash table - // if we have, we can just use the cached group pointers - for (idx_t i = 0; i < groups.size(); i++) { - auto dict_idx = offsets.get_index(i); - unique_entries.set_index(unique_count, dict_idx); - unique_count += !found_entry[dict_idx]; - found_entry[dict_idx] = true; - } - auto &new_dictionary_pointers = dict_state.new_dictionary_pointers; - idx_t new_group_count = 0; - if (unique_count > 0) { - auto &unique_values = dict_state.unique_values; - if (unique_values.ColumnCount() == 0) { - unique_values.InitializeEmpty(groups.GetTypes()); - } - // slice the dictionary - unique_values.data[0].Slice(dictionary_vector, unique_entries, unique_count); - unique_values.SetCardinality(unique_count); - // now we know which entries we are going to add - hash them - auto &hashes = dict_state.hashes; - unique_values.Hash(hashes); - - // add the dictionary groups to the hash table - new_group_count = FindOrCreateGroups(unique_values, hashes, new_dictionary_pointers, state.new_groups); - } - auto &aggregates = layout.GetAggregates(); - if (aggregates.empty()) { - // early-out - no aggregates to update - return new_group_count; - } - - // set the addresses that we found for each of the unique groups in the main addresses vector - auto new_dict_addresses = FlatVector::GetData(new_dictionary_pointers); - // for each of the new groups, add them to the global (cached) list of addresses for the dictionary - auto &dictionary_addresses = *dict_state.dictionary_addresses; - auto dict_addresses = FlatVector::GetData(dictionary_addresses); - for (idx_t i = 0; i < unique_count; i++) { - auto dict_idx = unique_entries.get_index(i); - dict_addresses[dict_idx] = new_dict_addresses[i] + layout.GetAggrOffset(); - } - // now set up the addresses for the aggregates - auto result_addresses = FlatVector::GetData(state.addresses); - for (idx_t i = 0; i < groups.size(); i++) { - auto dict_idx = offsets.get_index(i); - result_addresses[i] = dict_addresses[dict_idx]; - } - - // finally process the aggregates - UpdateAggregates(payload, filter); - - return new_group_count; -} - -optional_idx GroupedAggregateHashTable::TryAddConstantGroups(DataChunk &groups, DataChunk &payload, - const unsafe_vector &filter) { -#ifndef DEBUG - if (groups.size() <= 1) { - // this only has a point if we have multiple groups - return optional_idx(); - } -#endif - auto &dict_state = state.dict_state; - auto &unique_values = dict_state.unique_values; - if (unique_values.ColumnCount() == 0) { - unique_values.InitializeEmpty(groups.GetTypes()); - } - // slice the dictionary - unique_values.Reference(groups); - unique_values.SetCardinality(1); - unique_values.Flatten(); - - auto &hashes = dict_state.hashes; - unique_values.Hash(hashes); - - // add the single constant group to the hash table - auto &new_dictionary_pointers = dict_state.new_dictionary_pointers; - auto new_group_count = FindOrCreateGroups(unique_values, hashes, new_dictionary_pointers, state.new_groups); - - auto &aggregates = layout.GetAggregates(); - if (aggregates.empty()) { - // early-out - no aggregates to update - return new_group_count; - } - - auto new_dict_addresses = FlatVector::GetData(new_dictionary_pointers); - auto result_addresses = FlatVector::GetData(state.addresses); - uintptr_t aggregate_address = new_dict_addresses[0] + layout.GetAggrOffset(); - for (idx_t i = 0; i < payload.size(); i++) { - result_addresses[i] = aggregate_address; - } - - // process the aggregates - // FIXME: we can use simple_update here if the aggregates support it - UpdateAggregates(payload, filter); +idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter) { + Vector hashes(LogicalType::HASH); + groups.Hash(hashes); - return new_group_count; + return AddChunk(groups, hashes, payload, filter); } -optional_idx GroupedAggregateHashTable::TryAddCompressedGroups(DataChunk &groups, DataChunk &payload, - const unsafe_vector &filter) { - // all groups must be compressed - if (groups.AllConstant()) { - return TryAddConstantGroups(groups, payload, filter); - } - if (groups.ColumnCount() == 1 && groups.data[0].GetVectorType() == VectorType::DICTIONARY_VECTOR) { - return TryAddDictionaryGroups(groups, payload, filter); +idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, Vector &group_hashes, DataChunk &payload, + const unsafe_vector &filter) { + if (groups.size() == 0) { + return 0; } - return optional_idx(); -} -idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter) { - sink_count += groups.size(); - - // check if we can use an optimized path that utilizes compressed vectors - auto result = TryAddCompressedGroups(groups, payload, filter); - if (result.IsValid()) { - return result.GetIndex(); +#ifdef DEBUG + D_ASSERT(groups.ColumnCount() + 1 == layout.ColumnCount()); + for (idx_t i = 0; i < groups.ColumnCount(); i++) { + D_ASSERT(groups.GetTypes()[i] == layout.GetTypes()[i]); } - // otherwise append the raw values - Vector hashes(LogicalType::HASH); - groups.Hash(hashes); +#endif - return AddChunk(groups, hashes, payload, filter); -} + const auto new_group_count = FindOrCreateGroups(groups, group_hashes, state.addresses, state.new_groups); + VectorOperations::AddInPlace(state.addresses, NumericCast(layout.GetAggrOffset()), payload.size()); -void GroupedAggregateHashTable::UpdateAggregates(DataChunk &payload, const unsafe_vector &filter) { // Now every cell has an entry, update the aggregates auto &aggregates = layout.GetAggregates(); idx_t filter_idx = 0; @@ -517,26 +278,6 @@ void GroupedAggregateHashTable::UpdateAggregates(DataChunk &payload, const unsaf } Verify(); -} - -idx_t GroupedAggregateHashTable::AddChunk(DataChunk &groups, Vector &group_hashes, DataChunk &payload, - const unsafe_vector &filter) { - if (groups.size() == 0) { - return 0; - } - -#ifdef DEBUG - D_ASSERT(groups.ColumnCount() + 1 == layout.ColumnCount()); - for (idx_t i = 0; i < groups.ColumnCount(); i++) { - D_ASSERT(groups.GetTypes()[i] == layout.GetTypes()[i]); - } -#endif - - const auto new_group_count = FindOrCreateGroups(groups, group_hashes, state.addresses, state.new_groups); - VectorOperations::AddInPlace(state.addresses, NumericCast(layout.GetAggrOffset()), payload.size()); - - UpdateAggregates(payload, filter); - return new_group_count; } @@ -573,14 +314,30 @@ idx_t GroupedAggregateHashTable::FindOrCreateGroupsInternal(DataChunk &groups, V D_ASSERT(state.hash_salts.GetType() == LogicalType::HASH); // Need to fit the entire vector, and resize at threshold - const auto chunk_size = groups.size(); - if (Count() + chunk_size > capacity || Count() + chunk_size > ResizeThreshold()) { + if (Count() + groups.size() > capacity || Count() + groups.size() > ResizeThreshold()) { Verify(); Resize(capacity * 2); } - D_ASSERT(capacity - Count() >= chunk_size); // we need to be able to fit at least one vector of data + D_ASSERT(capacity - Count() >= groups.size()); // we need to be able to fit at least one vector of data + + group_hashes_v.Flatten(groups.size()); + auto hashes = FlatVector::GetData(group_hashes_v); + + addresses_v.Flatten(groups.size()); + auto addresses = FlatVector::GetData(addresses_v); + + // Compute the entry in the table based on the hash using a modulo, + // and precompute the hash salts for faster comparison below + auto ht_offsets = FlatVector::GetData(state.ht_offsets); + const auto hash_salts = FlatVector::GetData(state.hash_salts); + for (idx_t r = 0; r < groups.size(); r++) { + const auto &hash = hashes[r]; + ht_offsets[r] = ApplyBitMask(hash); + D_ASSERT(ht_offsets[r] == hash % capacity); + hash_salts[r] = ht_entry_t::ExtractSalt(hash); + } - // we start out with all entries [0, 1, 2, ..., chunk_size] + // we start out with all entries [0, 1, 2, ..., groups.size()] const SelectionVector *sel_vector = FlatVector::IncrementalSelectionVector(); // Make a chunk that references the groups and the hashes and convert to unified format @@ -595,57 +352,15 @@ idx_t GroupedAggregateHashTable::FindOrCreateGroupsInternal(DataChunk &groups, V state.group_chunk.SetCardinality(groups); // convert all vectors to unified format - TupleDataCollection::ToUnifiedFormat(state.partitioned_append_state.chunk_state, state.group_chunk); + auto &chunk_state = state.append_state.chunk_state; + TupleDataCollection::ToUnifiedFormat(chunk_state, state.group_chunk); if (!state.group_data) { state.group_data = make_unsafe_uniq_array_uninitialized(state.group_chunk.ColumnCount()); } - TupleDataCollection::GetVectorData(state.partitioned_append_state.chunk_state, state.group_data.get()); - - group_hashes_v.Flatten(chunk_size); - const auto hashes = FlatVector::GetData(group_hashes_v); - - addresses_v.Flatten(chunk_size); - const auto addresses = FlatVector::GetData(addresses_v); - - if (skip_lookups) { - // Just appending now - partitioned_data->AppendUnified(state.partitioned_append_state, state.group_chunk, - *FlatVector::IncrementalSelectionVector(), chunk_size); - RowOperations::InitializeStates(layout, state.partitioned_append_state.chunk_state.row_locations, - *FlatVector::IncrementalSelectionVector(), chunk_size); - - const auto row_locations = - FlatVector::GetData(state.partitioned_append_state.chunk_state.row_locations); - const auto &row_sel = state.partitioned_append_state.reverse_partition_sel; - for (idx_t i = 0; i < chunk_size; i++) { - const auto &row_idx = row_sel[i]; - const auto &row_location = row_locations[row_idx]; - addresses[i] = row_location; - } - count += chunk_size; - return chunk_size; - } - - // Compute the entry in the table based on the hash using a modulo, - // and precompute the hash salts for faster comparison below - const auto ht_offsets = FlatVector::GetData(state.ht_offsets); - const auto hash_salts = FlatVector::GetData(state.hash_salts); - - // We also compute the occupied count, which is essentially useless. - // However, this loop is branchless, while the main lookup loop below is not. - // So, by doing the lookups here, we better amortize cache misses. - idx_t occupied_count = 0; - for (idx_t r = 0; r < chunk_size; r++) { - const auto &hash = hashes[r]; - auto &ht_offset = ht_offsets[r]; - ht_offset = ApplyBitMask(hash); - occupied_count += entries[ht_offset].IsOccupied(); // Lookup - D_ASSERT(ht_offset == hash % capacity); - hash_salts[r] = ht_entry_t::ExtractSalt(hash); - } + TupleDataCollection::GetVectorData(chunk_state, state.group_data.get()); idx_t new_group_count = 0; - idx_t remaining_entries = chunk_size; + idx_t remaining_entries = groups.size(); idx_t iteration_count; for (iteration_count = 0; remaining_entries > 0 && iteration_count < capacity; iteration_count++) { idx_t new_entry_count = 0; @@ -655,62 +370,46 @@ idx_t GroupedAggregateHashTable::FindOrCreateGroupsInternal(DataChunk &groups, V // For each remaining entry, figure out whether or not it belongs to a full or empty group for (idx_t i = 0; i < remaining_entries; i++) { const auto index = sel_vector->get_index(i); - const auto salt = hash_salts[index]; + const auto &salt = hash_salts[index]; auto &ht_offset = ht_offsets[index]; idx_t inner_iteration_count; for (inner_iteration_count = 0; inner_iteration_count < capacity; inner_iteration_count++) { auto &entry = entries[ht_offset]; - if (!entry.IsOccupied()) { // Unoccupied: claim it + if (entry.IsOccupied()) { // Cell is occupied: Compare salts + if (entry.GetSalt() == salt) { + // Same salt, compare group keys + state.group_compare_vector.set_index(need_compare_count++, index); + break; + } + // Different salts, move to next entry (linear probing) + IncrementAndWrap(ht_offset, bitmask); + } else { // Cell is unoccupied, let's claim it + // Set salt (also marks as occupied) entry.SetSalt(salt); + // Update selection lists for outer loops state.empty_vector.set_index(new_entry_count++, index); new_groups_out.set_index(new_group_count++, index); break; } - - if (DUCKDB_LIKELY(entry.GetSalt() == salt)) { // Matching salt: compare groups - state.group_compare_vector.set_index(need_compare_count++, index); - break; - } - - // Linear probing - IncrementAndWrap(ht_offset, bitmask); } - if (DUCKDB_UNLIKELY(inner_iteration_count == capacity)) { + if (inner_iteration_count == capacity) { throw InternalException("Maximum inner iteration count reached in GroupedAggregateHashTable"); } } - if (DUCKDB_UNLIKELY(occupied_count > new_entry_count + need_compare_count)) { - // We use the useless occupied_count we summed above here so the variable is used, - // and the compiler cannot optimize away the vectorized lookups above. This should never be triggered. - throw InternalException("Internal validation failed in GroupedAggregateHashTable"); - } - occupied_count = 0; // Have to set to 0 for next iterations - if (new_entry_count != 0) { // Append everything that belongs to an empty group - optional_ptr data; - optional_ptr append_state; - if (radix_bits >= UNPARTITIONED_RADIX_BITS_THRESHOLD && - new_entry_count / RadixPartitioning::NumberOfPartitions(radix_bits) <= 4) { - TupleDataCollection::ToUnifiedFormat(state.unpartitioned_append_state.chunk_state, state.group_chunk); - data = unpartitioned_data.get(); - append_state = &state.unpartitioned_append_state; - } else { - data = partitioned_data.get(); - append_state = &state.partitioned_append_state; - } - data->AppendUnified(*append_state, state.group_chunk, state.empty_vector, new_entry_count); - RowOperations::InitializeStates(layout, append_state->chunk_state.row_locations, + partitioned_data->AppendUnified(state.append_state, state.group_chunk, state.empty_vector, new_entry_count); + RowOperations::InitializeStates(layout, chunk_state.row_locations, *FlatVector::IncrementalSelectionVector(), new_entry_count); // Set the entry pointers in the 1st part of the HT now that the data has been appended - const auto row_locations = FlatVector::GetData(append_state->chunk_state.row_locations); - const auto &row_sel = append_state->reverse_partition_sel; + const auto row_locations = FlatVector::GetData(chunk_state.row_locations); + const auto &row_sel = state.append_state.reverse_partition_sel; for (idx_t new_entry_idx = 0; new_entry_idx < new_entry_count; new_entry_idx++) { - const auto &index = state.empty_vector[new_entry_idx]; - const auto &row_idx = row_sel[index]; + const auto index = state.empty_vector.get_index(new_entry_idx); + const auto row_idx = row_sel.get_index(index); const auto &row_location = row_locations[row_idx]; auto &entry = entries[ht_offsets[index]]; @@ -723,20 +422,19 @@ idx_t GroupedAggregateHashTable::FindOrCreateGroupsInternal(DataChunk &groups, V if (need_compare_count != 0) { // Get the pointers to the rows that need to be compared for (idx_t need_compare_idx = 0; need_compare_idx < need_compare_count; need_compare_idx++) { - const auto &index = state.group_compare_vector[need_compare_idx]; + const auto index = state.group_compare_vector.get_index(need_compare_idx); const auto &entry = entries[ht_offsets[index]]; addresses[index] = entry.GetPointer(); } // Perform group comparisons - row_matcher.Match(state.group_chunk, state.partitioned_append_state.chunk_state.vector_data, - state.group_compare_vector, need_compare_count, layout, addresses_v, - &state.no_match_vector, no_match_count); + row_matcher.Match(state.group_chunk, chunk_state.vector_data, state.group_compare_vector, + need_compare_count, layout, addresses_v, &state.no_match_vector, no_match_count); } // Linear probing: each of the entries that do not match move to the next entry in the HT for (idx_t i = 0; i < no_match_count; i++) { - const auto &index = state.no_match_vector[i]; + const auto index = state.no_match_vector.get_index(i); auto &ht_offset = ht_offsets[index]; IncrementAndWrap(ht_offset, bitmask); } @@ -808,8 +506,7 @@ struct FlushMoveState { }; void GroupedAggregateHashTable::Combine(GroupedAggregateHashTable &other) { - auto other_partitioned_data = other.AcquirePartitionedData(); - auto other_data = other_partitioned_data->GetUnpartitioned(); + auto other_data = other.partitioned_data->GetUnpartitioned(); Combine(*other_data); // Inherit ownership to all stored aggregate allocators @@ -834,21 +531,25 @@ void GroupedAggregateHashTable::Combine(TupleDataCollection &other_data, optiona idx_t chunk_idx = 0; const auto chunk_count = other_data.ChunkCount(); while (fm_state.Scan()) { - const auto input_chunk_size = fm_state.groups.size(); FindOrCreateGroups(fm_state.groups, fm_state.hashes, fm_state.group_addresses, fm_state.new_groups_sel); RowOperations::CombineStates(row_state, layout, fm_state.scan_state.chunk_state.row_locations, - fm_state.group_addresses, input_chunk_size); + fm_state.group_addresses, fm_state.groups.size()); if (layout.HasDestructor()) { RowOperations::DestroyStates(row_state, layout, fm_state.scan_state.chunk_state.row_locations, - input_chunk_size); + fm_state.groups.size()); } if (progress) { - *progress = static_cast(++chunk_idx) / static_cast(chunk_count); + *progress = double(++chunk_idx) / double(chunk_count); } } Verify(); } +void GroupedAggregateHashTable::UnpinData() { + partitioned_data->FlushAppendState(state.append_state); + partitioned_data->Unpin(); +} + } // namespace duckdb diff --git a/src/duckdb/src/execution/column_binding_resolver.cpp b/src/duckdb/src/execution/column_binding_resolver.cpp index 3a931a3f5..568381503 100644 --- a/src/duckdb/src/execution/column_binding_resolver.cpp +++ b/src/duckdb/src/execution/column_binding_resolver.cpp @@ -156,13 +156,13 @@ unique_ptr ColumnBindingResolver::VisitReplace(BoundColumnRefExpress // in verification mode return nullptr; } - return make_uniq(expr.GetAlias(), expr.return_type, i); + return make_uniq(expr.alias, expr.return_type, i); } } // LCOV_EXCL_START // could not bind the column reference, this should never happen and indicates a bug in the code // generate an error message - throw InternalException("Failed to bind column reference \"%s\" [%d.%d] (bindings: %s)", expr.GetAlias(), + throw InternalException("Failed to bind column reference \"%s\" [%d.%d] (bindings: %s)", expr.alias, expr.binding.table_index, expr.binding.column_index, LogicalOperator::ColumnBindingsToString(bindings)); // LCOV_EXCL_STOP diff --git a/src/duckdb/src/execution/expression_executor.cpp b/src/duckdb/src/execution/expression_executor.cpp index 567deb326..458348bea 100644 --- a/src/duckdb/src/execution/expression_executor.cpp +++ b/src/duckdb/src/execution/expression_executor.cpp @@ -141,7 +141,7 @@ void ExpressionExecutor::Verify(const Expression &expr, Vector &vector, idx_t co unique_ptr ExpressionExecutor::InitializeState(const Expression &expr, ExpressionExecutorState &state) { - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BOUND_REF: return InitializeState(expr.Cast(), state); case ExpressionClass::BOUND_BETWEEN: @@ -191,7 +191,7 @@ void ExpressionExecutor::Execute(const Expression &expr, ExpressionState *state, "ExpressionExecutor::Execute called with a result vector of type %s that does not match expression type %s", result.GetType(), expr.return_type); } - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BOUND_BETWEEN: Execute(expr.Cast(), state, sel, count, result); break; @@ -235,11 +235,9 @@ idx_t ExpressionExecutor::Select(const Expression &expr, ExpressionState *state, } D_ASSERT(true_sel || false_sel); D_ASSERT(expr.return_type.id() == LogicalTypeId::BOOLEAN); - switch (expr.GetExpressionClass()) { -#ifndef DUCKDB_SMALLER_BINARY + switch (expr.expression_class) { case ExpressionClass::BOUND_BETWEEN: return Select(expr.Cast(), state, sel, count, true_sel, false_sel); -#endif case ExpressionClass::BOUND_COMPARISON: return Select(expr.Cast(), state, sel, count, true_sel, false_sel); case ExpressionClass::BOUND_CONJUNCTION: diff --git a/src/duckdb/src/execution/expression_executor/execute_between.cpp b/src/duckdb/src/execution/expression_executor/execute_between.cpp index 341835136..95ff45070 100644 --- a/src/duckdb/src/execution/expression_executor/execute_between.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_between.cpp @@ -7,7 +7,6 @@ namespace duckdb { -#ifndef DUCKDB_SMALLER_BINARY struct BothInclusiveBetweenOperator { template static inline bool Operation(T input, T lower, T upper) { @@ -86,7 +85,6 @@ static idx_t BetweenLoopTypeSwitch(Vector &input, Vector &lower, Vector &upper, throw InvalidTypeException(input.GetType(), "Invalid type for BETWEEN"); } } -#endif unique_ptr ExpressionExecutor::InitializeState(const BoundBetweenExpression &expr, ExpressionExecutorState &root) { @@ -133,9 +131,6 @@ void ExpressionExecutor::Execute(const BoundBetweenExpression &expr, ExpressionS idx_t ExpressionExecutor::Select(const BoundBetweenExpression &expr, ExpressionState *state, const SelectionVector *sel, idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { -#ifdef DUCKDB_SMALLER_BINARY - throw InternalException("ExpressionExecutor::Select not available with DUCKDB_SMALLER_BINARY"); -#else // resolve the children Vector input(state->intermediate_chunk.data[0]); Vector lower(state->intermediate_chunk.data[1]); @@ -157,7 +152,6 @@ idx_t ExpressionExecutor::Select(const BoundBetweenExpression &expr, ExpressionS } else { return BetweenLoopTypeSwitch(input, lower, upper, sel, count, true_sel, false_sel); } -#endif } } // namespace duckdb diff --git a/src/duckdb/src/execution/expression_executor/execute_cast.cpp b/src/duckdb/src/execution/expression_executor/execute_cast.cpp index 0627dcf51..c0cca5889 100644 --- a/src/duckdb/src/execution/expression_executor/execute_cast.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_cast.cpp @@ -12,8 +12,7 @@ unique_ptr ExpressionExecutor::InitializeState(const BoundCastE result->Finalize(); if (expr.bound_cast.init_local_state) { - auto context_ptr = root.executor->HasContext() ? &root.executor->GetContext() : nullptr; - CastLocalStateParameters parameters(context_ptr, expr.bound_cast.cast_data); + CastLocalStateParameters parameters(root.executor->GetContext(), expr.bound_cast.cast_data); result->local_state = expr.bound_cast.init_local_state(parameters); } return std::move(result); @@ -33,13 +32,13 @@ void ExpressionExecutor::Execute(const BoundCastExpression &expr, ExpressionStat if (expr.try_cast) { string error_message; CastParameters parameters(expr.bound_cast.cast_data.get(), false, &error_message, lstate); - parameters.query_location = expr.GetQueryLocation(); + parameters.query_location = expr.query_location; expr.bound_cast.function(child, result, count, parameters); } else { // cast it to the type specified by the cast expression D_ASSERT(result.GetType() == expr.return_type); CastParameters parameters(expr.bound_cast.cast_data.get(), false, nullptr, lstate); - parameters.query_location = expr.GetQueryLocation(); + parameters.query_location = expr.query_location; expr.bound_cast.function(child, result, count, parameters); } } diff --git a/src/duckdb/src/execution/expression_executor/execute_comparison.cpp b/src/duckdb/src/execution/expression_executor/execute_comparison.cpp index 6e78de49c..949bc7ab5 100644 --- a/src/duckdb/src/execution/expression_executor/execute_comparison.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_comparison.cpp @@ -29,7 +29,7 @@ void ExpressionExecutor::Execute(const BoundComparisonExpression &expr, Expressi Execute(*expr.left, state->child_states[0].get(), sel, count, left); Execute(*expr.right, state->child_states[1].get(), sel, count, right); - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::COMPARE_EQUAL: VectorOperations::Equals(left, right, result, count); break; @@ -357,7 +357,7 @@ idx_t ExpressionExecutor::Select(const BoundComparisonExpression &expr, Expressi Execute(*expr.left, state->child_states[0].get(), sel, count, left); Execute(*expr.right, state->child_states[1].get(), sel, count, right); - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::COMPARE_EQUAL: return VectorOperations::Equals(left, right, sel, count, true_sel, false_sel); case ExpressionType::COMPARE_NOTEQUAL: diff --git a/src/duckdb/src/execution/expression_executor/execute_conjunction.cpp b/src/duckdb/src/execution/expression_executor/execute_conjunction.cpp index 1b2bc3a4e..8ea55d63b 100644 --- a/src/duckdb/src/execution/expression_executor/execute_conjunction.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_conjunction.cpp @@ -38,7 +38,7 @@ void ExpressionExecutor::Execute(const BoundConjunctionExpression &expr, Express } else { Vector intermediate(LogicalType::BOOLEAN); // AND/OR together - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::CONJUNCTION_AND: VectorOperations::And(current_result, result, intermediate, count); break; @@ -58,7 +58,7 @@ idx_t ExpressionExecutor::Select(const BoundConjunctionExpression &expr, Express SelectionVector *false_sel) { auto &state = state_p->Cast(); - if (expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (expr.type == ExpressionType::CONJUNCTION_AND) { // get runtime statistics auto filter_state = state.adaptive_filter->BeginFilter(); const SelectionVector *current_sel = sel; diff --git a/src/duckdb/src/execution/expression_executor/execute_function.cpp b/src/duckdb/src/execution/expression_executor/execute_function.cpp index 5a95d27a3..7fe9df2f5 100644 --- a/src/duckdb/src/execution/expression_executor/execute_function.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_function.cpp @@ -76,7 +76,6 @@ void ExpressionExecutor::Execute(const BoundFunctionExpression &expr, Expression arguments.Verify(); D_ASSERT(expr.function.function); - // #ifdef DEBUG expr.function.function(arguments, *state, result); VerifyNullHandling(expr, arguments, result); diff --git a/src/duckdb/src/execution/expression_executor/execute_operator.cpp b/src/duckdb/src/execution/expression_executor/execute_operator.cpp index b543679e8..7db874783 100644 --- a/src/duckdb/src/execution/expression_executor/execute_operator.cpp +++ b/src/duckdb/src/execution/expression_executor/execute_operator.cpp @@ -19,8 +19,7 @@ void ExpressionExecutor::Execute(const BoundOperatorExpression &expr, Expression const SelectionVector *sel, idx_t count, Vector &result) { // special handling for special snowflake 'IN' // IN has n children - if (expr.GetExpressionType() == ExpressionType::COMPARE_IN || - expr.GetExpressionType() == ExpressionType::COMPARE_NOT_IN) { + if (expr.type == ExpressionType::COMPARE_IN || expr.type == ExpressionType::COMPARE_NOT_IN) { if (expr.children.size() < 2) { throw InvalidInputException("IN needs at least two children"); } @@ -54,14 +53,14 @@ void ExpressionExecutor::Execute(const BoundOperatorExpression &expr, Expression intermediate.Reference(new_result); } } - if (expr.GetExpressionType() == ExpressionType::COMPARE_NOT_IN) { + if (expr.type == ExpressionType::COMPARE_NOT_IN) { // NOT IN: invert result VectorOperations::Not(intermediate, result, count); } else { // directly use the result result.Reference(intermediate); } - } else if (expr.GetExpressionType() == ExpressionType::OPERATOR_COALESCE) { + } else if (expr.type == ExpressionType::OPERATOR_COALESCE) { SelectionVector sel_a(count); SelectionVector sel_b(count); SelectionVector slice_sel(count); @@ -116,7 +115,7 @@ void ExpressionExecutor::Execute(const BoundOperatorExpression &expr, Expression auto &child = state->intermediate_chunk.data[0]; Execute(*expr.children[0], state->child_states[0].get(), sel, count, child); - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::OPERATOR_NOT: { VectorOperations::Not(child, result, count); break; diff --git a/src/duckdb/src/execution/index/art/art.cpp b/src/duckdb/src/execution/index/art/art.cpp index a92f2eebf..be4beef19 100644 --- a/src/duckdb/src/execution/index/art/art.cpp +++ b/src/duckdb/src/execution/index/art/art.cpp @@ -45,7 +45,7 @@ ART::ART(const string &name, const IndexConstraintType index_constraint_type, co const shared_ptr, ALLOCATOR_COUNT>> &allocators_ptr, const IndexStorageInfo &info) : BoundIndex(name, ART::TYPE_NAME, index_constraint_type, column_ids, table_io_manager, unbound_expressions, db), - allocators(allocators_ptr), owns_data(false), append_mode(ARTAppendMode::DEFAULT) { + allocators(allocators_ptr), owns_data(false) { // FIXME: Use the new byte representation function to support nested types. for (idx_t i = 0; i < types.size(); i++) { @@ -138,10 +138,8 @@ unique_ptr ART::TryInitializeScan(const Expression &expr, const // Try to find a matching index for any of the filter expressions. ComparisonExpressionMatcher matcher; - // Match on a comparison type. matcher.expr_type = make_uniq(); - // Match on a constant comparison with the indexed expression. matcher.matchers.push_back(make_uniq(expr)); matcher.matchers.push_back(make_uniq()); @@ -157,9 +155,9 @@ unique_ptr ART::TryInitializeScan(const Expression &expr, const // bindings[2] = the constant auto &comparison = bindings[0].get().Cast(); auto constant_value = bindings[2].get().Cast().value; - auto comparison_type = comparison.GetExpressionType(); + auto comparison_type = comparison.type; - if (comparison.left->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (comparison.left->type == ExpressionType::VALUE_CONSTANT) { // The expression is on the right side, we flip the comparison expression. comparison_type = FlipComparisonExpression(comparison_type); } @@ -178,15 +176,15 @@ unique_ptr ART::TryInitializeScan(const Expression &expr, const high_comparison_type = comparison_type; } - } else if (filter_expr.GetExpressionType() == ExpressionType::COMPARE_BETWEEN) { + } else if (filter_expr.type == ExpressionType::COMPARE_BETWEEN) { auto &between = filter_expr.Cast(); if (!between.input->Equals(expr)) { // The expression does not match the index expression. return nullptr; } - if (between.lower->GetExpressionType() != ExpressionType::VALUE_CONSTANT || - between.upper->GetExpressionType() != ExpressionType::VALUE_CONSTANT) { + if (between.lower->type != ExpressionType::VALUE_CONSTANT || + between.upper->type != ExpressionType::VALUE_CONSTANT) { // Not a constant expression. return nullptr; } @@ -479,44 +477,32 @@ bool ART::Construct(unsafe_vector &keys, unsafe_vector &row_ids, // Insert and Constraint Checking //===--------------------------------------------------------------------===// -ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids) { - return Insert(l, chunk, row_ids, nullptr); -} - -ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ptr delete_index) { +ErrorData ART::Insert(IndexLock &lock, DataChunk &input, Vector &row_ids) { D_ASSERT(row_ids.GetType().InternalType() == ROW_TYPE); - auto row_count = chunk.size(); + auto row_count = input.size(); ArenaAllocator allocator(BufferAllocator::Get(db)); unsafe_vector keys(row_count); unsafe_vector row_id_keys(row_count); - GenerateKeyVectors(allocator, chunk, row_ids, keys, row_id_keys); - - optional_ptr delete_art; - if (delete_index) { - delete_art = delete_index->Cast(); - } - - auto conflict_type = ARTConflictType::NO_CONFLICT; - optional_idx conflict_idx; - auto was_empty = !tree.HasMetadata(); + GenerateKeyVectors(allocator, input, row_ids, keys, row_id_keys); // Insert the entries into the index. + idx_t failed_index = DConstants::INVALID_INDEX; + auto was_empty = !tree.HasMetadata(); for (idx_t i = 0; i < row_count; i++) { if (keys[i].Empty()) { continue; } - conflict_type = Insert(tree, keys[i], 0, row_id_keys[i], tree.GetGateStatus(), delete_art); - if (conflict_type != ARTConflictType::NO_CONFLICT) { - conflict_idx = i; + if (!Insert(tree, keys[i], 0, row_id_keys[i], tree.GetGateStatus())) { + // Insertion failure due to a constraint violation. + failed_index = i; break; } } // Remove any previously inserted entries. - if (conflict_type != ARTConflictType::NO_CONFLICT) { - D_ASSERT(conflict_idx.IsValid()); - for (idx_t i = 0; i < conflict_idx.GetIndex(); i++) { + if (failed_index != DConstants::INVALID_INDEX) { + for (idx_t i = 0; i < failed_index; i++) { if (keys[i].Empty()) { continue; } @@ -529,14 +515,9 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ VerifyAllocationsInternal(); } - if (conflict_type == ARTConflictType::TRANSACTION) { - auto msg = AppendRowError(chunk, conflict_idx.GetIndex()); - return ErrorData(TransactionException("write-write conflict on key: \"%s\"", msg)); - } - - if (conflict_type == ARTConflictType::CONSTRAINT) { - auto msg = AppendRowError(chunk, conflict_idx.GetIndex()); - return ErrorData(ConstraintException("PRIMARY KEY or UNIQUE constraint violation: duplicate key \"%s\"", msg)); + if (failed_index != DConstants::INVALID_INDEX) { + auto msg = AppendRowError(input, failed_index); + return ErrorData(ConstraintException("PRIMARY KEY or UNIQUE constraint violated: duplicate key \"%s\"", msg)); } #ifdef DEBUG @@ -550,34 +531,22 @@ ErrorData ART::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ return ErrorData(); } -ErrorData ART::Append(IndexLock &l, DataChunk &chunk, Vector &row_ids) { +ErrorData ART::Append(IndexLock &lock, DataChunk &input, Vector &row_ids) { // Execute all column expressions before inserting the data chunk. DataChunk expr_chunk; expr_chunk.Initialize(Allocator::DefaultAllocator(), logical_types); - ExecuteExpressions(chunk, expr_chunk); - - // Now insert the data chunk. - return Insert(l, expr_chunk, row_ids, nullptr); + ExecuteExpressions(input, expr_chunk); + return Insert(lock, expr_chunk, row_ids); } -ErrorData ART::AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids, - optional_ptr delete_index) { - // Execute all column expressions before inserting the data chunk. - DataChunk expr_chunk; - expr_chunk.Initialize(Allocator::DefaultAllocator(), logical_types); - ExecuteExpressions(chunk, expr_chunk); - - // Now insert the data chunk. - return Insert(l, expr_chunk, row_ids, delete_index); +void ART::VerifyAppend(DataChunk &chunk) { + ConflictManager conflict_manager(VerifyExistenceType::APPEND, chunk.size()); + CheckConstraintsForChunk(chunk, conflict_manager); } -void ART::VerifyAppend(DataChunk &chunk, optional_ptr delete_index, optional_ptr manager) { - if (manager) { - D_ASSERT(manager->LookupType() == VerifyExistenceType::APPEND); - return VerifyConstraint(chunk, delete_index, *manager); - } - ConflictManager local_manager(VerifyExistenceType::APPEND, chunk.size()); - VerifyConstraint(chunk, delete_index, local_manager); +void ART::VerifyAppend(DataChunk &chunk, ConflictManager &conflict_manager) { + D_ASSERT(conflict_manager.LookupType() == VerifyExistenceType::APPEND); + CheckConstraintsForChunk(chunk, conflict_manager); } void ART::InsertIntoEmpty(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, @@ -597,61 +566,26 @@ void ART::InsertIntoEmpty(Node &node, const ARTKey &key, const idx_t depth, cons Leaf::New(ref, row_id.GetRowId()); } -ARTConflictType ART::InsertIntoInlined(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art) { - - if (!IsUnique() || append_mode == ARTAppendMode::INSERT_DUPLICATES) { - Leaf::InsertIntoInlined(*this, node, row_id, depth, status); - return ARTConflictType::NO_CONFLICT; - } - - if (!delete_art) { - if (append_mode == ARTAppendMode::IGNORE_DUPLICATES) { - return ARTConflictType::NO_CONFLICT; - } - return ARTConflictType::CONSTRAINT; - } - - // Lookup in the delete_art. - auto delete_leaf = delete_art->Lookup(delete_art->tree, key, 0); - if (!delete_leaf) { - return ARTConflictType::CONSTRAINT; - } - - // The row ID has changed. - // Thus, the local index has a newer (local) row ID, and this is a constraint violation. - D_ASSERT(delete_leaf->GetType() == NType::LEAF_INLINED); - auto deleted_row_id = delete_leaf->GetRowId(); - auto this_row_id = node.GetRowId(); - if (deleted_row_id != this_row_id) { - return ARTConflictType::CONSTRAINT; - } - - // The deleted key and its row ID match the current key and its row ID. - Leaf::InsertIntoInlined(*this, node, row_id, depth, status); - return ARTConflictType::NO_CONFLICT; -} - -ARTConflictType ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art) { +bool ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, + const GateStatus status) { D_ASSERT(depth < key.len); auto child = node.GetChildMutable(*this, key[depth]); // Recurse, if a child exists at key[depth]. if (child) { D_ASSERT(child->HasMetadata()); - auto conflict_type = Insert(*child, key, depth + 1, row_id, status, delete_art); + bool success = Insert(*child, key, depth + 1, row_id, status); node.ReplaceChild(*this, key[depth], *child); - return conflict_type; + return success; } // Create an inlined prefix at key[depth]. if (status == GateStatus::GATE_SET) { Node remainder; auto byte = key[depth]; - auto conflict_type = Insert(remainder, key, depth + 1, row_id, status, delete_art); + auto success = Insert(remainder, key, depth + 1, row_id, status); Node::InsertChild(*this, node, byte, remainder); - return conflict_type; + return success; } // Insert an inlined leaf at key[depth]. @@ -667,56 +601,49 @@ ARTConflictType ART::InsertIntoNode(Node &node, const ARTKey &key, const idx_t d // Create the inlined leaf. Leaf::New(ref, row_id.GetRowId()); Node::InsertChild(*this, node, key[depth], leaf); - return ARTConflictType::NO_CONFLICT; + return true; } -ARTConflictType ART::Insert(Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, const GateStatus status, - optional_ptr delete_art) { +bool ART::Insert(Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, const GateStatus status) { if (!node.HasMetadata()) { InsertIntoEmpty(node, key, depth, row_id, status); - return ARTConflictType::NO_CONFLICT; + return true; } // Enter a nested leaf. if (status == GateStatus::GATE_NOT_SET && node.GetGateStatus() == GateStatus::GATE_SET) { - if (IsUnique()) { - // Unique indexes can have duplicates, if another transaction DELETE + INSERT - // the same key. In that case, the previous value must be kept alive until all - // other transactions do not depend on it anymore. - - // We restrict this transactionality to two-value leaves, so any subsequent - // incoming transaction must fail here. - return ARTConflictType::TRANSACTION; - } - return Insert(node, row_id, 0, row_id, GateStatus::GATE_SET, delete_art); + return Insert(node, row_id, 0, row_id, GateStatus::GATE_SET); } auto type = node.GetType(); switch (type) { case NType::LEAF_INLINED: { - return InsertIntoInlined(node, key, depth, row_id, status, delete_art); + if (IsUnique()) { + return false; + } + Leaf::InsertIntoInlined(*this, node, row_id, depth, status); + return true; } case NType::LEAF: { Leaf::TransformToNested(*this, node); - return Insert(node, key, depth, row_id, status, delete_art); + return Insert(node, key, depth, row_id, status); } case NType::NODE_7_LEAF: case NType::NODE_15_LEAF: case NType::NODE_256_LEAF: { - // Row IDs are unique, so there are never any duplicate byte conflicts here. auto byte = key[Prefix::ROW_ID_COUNT]; Node::InsertChild(*this, node, byte); - return ARTConflictType::NO_CONFLICT; + return true; } case NType::NODE_4: case NType::NODE_16: case NType::NODE_48: case NType::NODE_256: - return InsertIntoNode(node, key, depth, row_id, status, delete_art); + return InsertIntoNode(node, key, depth, row_id, status); case NType::PREFIX: - return Prefix::Insert(*this, node, key, depth, row_id, status, delete_art); + return Prefix::Insert(*this, node, key, depth, row_id, status); default: - throw InternalException("Invalid node type for ART::Insert."); + throw InternalException("Invalid node type for Insert."); } } @@ -1026,7 +953,11 @@ string ART::GenerateConstraintErrorMessage(VerifyExistenceType verify_type, cons case VerifyExistenceType::APPEND: { // APPEND to PK/UNIQUE table, but node/key already exists in PK/UNIQUE table. string type = IsPrimary() ? "primary key" : "unique"; - return StringUtil::Format("Duplicate key \"%s\" violates %s constraint.", key_name, type); + return StringUtil::Format("Duplicate key \"%s\" violates %s constraint. " + "If this is an unexpected constraint violation please double " + "check with the known index limitations section in our documentation " + "(https://duckdb.org/docs/sql/indexes).", + key_name, type); } case VerifyExistenceType::APPEND_FK: { // APPEND_FK to FK table, node/key does not exist in PK/UNIQUE table. @@ -1044,117 +975,50 @@ string ART::GenerateConstraintErrorMessage(VerifyExistenceType verify_type, cons } } -void ART::VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr delete_art, ConflictManager &manager, - optional_idx &conflict_idx, idx_t i) { - // Fast path, the leaf is inlined, and the delete ART does not exist. - if (leaf.GetType() == NType::LEAF_INLINED && !delete_art) { - if (manager.AddHit(i, leaf.GetRowId())) { - conflict_idx = i; - } - return; - } - - // Get the delete_leaf. - // All leaves in the delete ART are inlined. - auto deleted_leaf = delete_art->Lookup(delete_art->tree, key, 0); - - // The leaf is inlined, and the same key does not exist in the delete ART. - if (leaf.GetType() == NType::LEAF_INLINED && !deleted_leaf) { - if (manager.AddHit(i, leaf.GetRowId())) { - conflict_idx = i; - } - return; - } - - // The leaf is inlined, and the same key exists in the delete ART. - if (leaf.GetType() == NType::LEAF_INLINED && deleted_leaf) { - auto deleted_row_id = deleted_leaf->GetRowId(); - auto this_row_id = leaf.GetRowId(); - - if (deleted_row_id == this_row_id) { - if (manager.AddMiss(i)) { - conflict_idx = i; - } - return; - } - - if (manager.AddHit(i, this_row_id)) { - conflict_idx = i; - } - return; - } - - // Scan the two row IDs in the leaf. - Iterator it(*this); - it.FindMinimum(leaf); - ARTKey empty_key = ARTKey(); - unsafe_vector row_ids; - it.Scan(empty_key, 2, row_ids, false); - - if (!deleted_leaf) { - if (manager.AddHit(i, row_ids[0]) || manager.AddHit(i, row_ids[0])) { - conflict_idx = i; - } - return; - } - - auto deleted_row_id = deleted_leaf->GetRowId(); - - if (deleted_row_id == row_ids[0] || deleted_row_id == row_ids[1]) { - if (manager.AddMiss(i)) { - conflict_idx = i; - } - return; - } - - if (manager.AddHit(i, row_ids[0]) || manager.AddHit(i, row_ids[1])) { - conflict_idx = i; - } -} - -void ART::VerifyConstraint(DataChunk &chunk, optional_ptr delete_index, ConflictManager &manager) { +void ART::CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_manager) { // Lock the index during constraint checking. lock_guard l(lock); DataChunk expr_chunk; expr_chunk.Initialize(Allocator::DefaultAllocator(), logical_types); - ExecuteExpressions(chunk, expr_chunk); + ExecuteExpressions(input, expr_chunk); ArenaAllocator arena_allocator(BufferAllocator::Get(db)); unsafe_vector keys(expr_chunk.size()); GenerateKeys<>(arena_allocator, expr_chunk, keys); - optional_ptr delete_art; - if (delete_index) { - delete_art = delete_index->Cast(); - } - - optional_idx conflict_idx; - for (idx_t i = 0; !conflict_idx.IsValid() && i < chunk.size(); i++) { + auto found_conflict = DConstants::INVALID_INDEX; + for (idx_t i = 0; found_conflict == DConstants::INVALID_INDEX && i < input.size(); i++) { if (keys[i].Empty()) { - if (manager.AddNull(i)) { - conflict_idx = i; + if (conflict_manager.AddNull(i)) { + found_conflict = i; } continue; } auto leaf = Lookup(tree, keys[i], 0); if (!leaf) { - if (manager.AddMiss(i)) { - conflict_idx = i; + if (conflict_manager.AddMiss(i)) { + found_conflict = i; } continue; } - VerifyLeaf(*leaf, keys[i], delete_art, manager, conflict_idx, i); + + // If we find a node, we need to update the 'matches' and 'row_ids'. + // We only perform constraint checking on unique indexes, i.e., all leaves are inlined. + D_ASSERT(leaf->GetType() == NType::LEAF_INLINED); + if (conflict_manager.AddHit(i, leaf->GetRowId())) { + found_conflict = i; + } } - manager.FinishLookup(); - if (!conflict_idx.IsValid()) { + conflict_manager.FinishLookup(); + if (found_conflict == DConstants::INVALID_INDEX) { return; } - auto key_name = GenerateErrorKeyName(chunk, conflict_idx.GetIndex()); - auto exception_msg = GenerateConstraintErrorMessage(manager.LookupType(), key_name); + auto key_name = GenerateErrorKeyName(input, found_conflict); + auto exception_msg = GenerateConstraintErrorMessage(conflict_manager.LookupType(), key_name); throw ConstraintException(exception_msg); } diff --git a/src/duckdb/src/execution/index/art/base_leaf.cpp b/src/duckdb/src/execution/index/art/base_leaf.cpp index 5034a0399..59492bb46 100644 --- a/src/duckdb/src/execution/index/art/base_leaf.cpp +++ b/src/duckdb/src/execution/index/art/base_leaf.cpp @@ -154,7 +154,7 @@ void Node15Leaf::ShrinkNode256Leaf(ART &art, Node &node15_leaf, Node &node256_le auto &n256 = Node::Ref(art, node256_leaf, NType::NODE_256_LEAF); node15_leaf.SetGateStatus(node256_leaf.GetGateStatus()); - ValidityMask mask(&n256.mask[0], Node256::CAPACITY); + ValidityMask mask(&n256.mask[0]); for (uint16_t i = 0; i < Node256::CAPACITY; i++) { if (mask.RowIsValid(i)) { n15.key[n15.count] = UnsafeNumericCast(i); diff --git a/src/duckdb/src/execution/index/art/leaf.cpp b/src/duckdb/src/execution/index/art/leaf.cpp index 5cde0d5d0..4a5b346c7 100644 --- a/src/duckdb/src/execution/index/art/leaf.cpp +++ b/src/duckdb/src/execution/index/art/leaf.cpp @@ -13,9 +13,13 @@ namespace duckdb { void Leaf::New(Node &node, const row_t row_id) { D_ASSERT(row_id < MAX_ROW_ID_LOCAL); + + auto status = node.GetGateStatus(); node.Clear(); + node.SetMetadata(static_cast(INLINED)); node.SetRowId(row_id); + node.SetGateStatus(status); } void Leaf::New(ART &art, reference &node, const unsafe_vector &row_ids, const idx_t start, @@ -26,7 +30,7 @@ void Leaf::New(ART &art, reference &node, const unsafe_vector &row // We cannot recurse into the leaf during Construct(...) because row IDs are not sorted. for (idx_t i = 0; i < count; i++) { idx_t offset = start + i; - art.Insert(node, row_ids[offset], 0, row_ids[offset], GateStatus::GATE_SET, nullptr); + art.Insert(node, row_ids[offset], 0, row_ids[offset], GateStatus::GATE_SET); } node.get().SetGateStatus(GateStatus::GATE_SET); } @@ -36,7 +40,7 @@ void Leaf::MergeInlined(ART &art, Node &l_node, Node &r_node) { ArenaAllocator arena_allocator(Allocator::Get(art.db)); auto key = ARTKey::CreateARTKey(arena_allocator, r_node.GetRowId()); - art.Insert(l_node, key, 0, key, l_node.GetGateStatus(), nullptr); + art.Insert(l_node, key, 0, key, l_node.GetGateStatus()); r_node.Clear(); } @@ -96,26 +100,17 @@ void Leaf::TransformToNested(ART &art, Node &node) { ArenaAllocator allocator(Allocator::Get(art.db)); Node root = Node(); - // Temporarily disable constraint checking. - if (art.IsUnique() && art.append_mode == ARTAppendMode::DEFAULT) { - art.append_mode = ARTAppendMode::INSERT_DUPLICATES; - } - // Move all row IDs into the nested leaf. reference leaf_ref(node); while (leaf_ref.get().HasMetadata()) { auto &leaf = Node::Ref(art, leaf_ref, LEAF); for (uint8_t i = 0; i < leaf.count; i++) { auto row_id = ARTKey::CreateARTKey(allocator, leaf.row_ids[i]); - auto conflict_type = art.Insert(root, row_id, 0, row_id, GateStatus::GATE_SET, nullptr); - if (conflict_type != ARTConflictType::NO_CONFLICT) { - throw InternalException("invalid conflict type in Leaf::TransformToNested"); - } + art.Insert(root, row_id, 0, row_id, GateStatus::GATE_SET); } leaf_ref = leaf.ptr; } - art.append_mode = ARTAppendMode::DEFAULT; root.SetGateStatus(GateStatus::GATE_SET); Node::Free(art, node); node = root; diff --git a/src/duckdb/src/execution/index/art/node.cpp b/src/duckdb/src/execution/index/art/node.cpp index 25c1dd5ff..8a39d8322 100644 --- a/src/duckdb/src/execution/index/art/node.cpp +++ b/src/duckdb/src/execution/index/art/node.cpp @@ -572,7 +572,7 @@ bool Node::MergeInternal(ART &art, Node &other, const GateStatus status) { ArenaAllocator allocator(Allocator::Get(art.db)); for (idx_t i = 0; i < row_ids.size(); i++) { auto row_id = ARTKey::CreateARTKey(allocator, row_ids[i]); - art.Insert(*this, row_id, 0, row_id, GateStatus::GATE_SET, nullptr); + art.Insert(*this, row_id, 0, row_id, GateStatus::GATE_SET); } return true; } @@ -649,7 +649,6 @@ void Node::TransformToDeprecated(ART &art, Node &node, unsafe_unique_ptr(art, node, NODE_256_LEAF); n256.count = 0; - ValidityMask mask(&n256.mask[0], Node256::CAPACITY); + ValidityMask mask(&n256.mask[0]); mask.SetAllInvalid(CAPACITY); return n256; } @@ -19,14 +19,14 @@ Node256Leaf &Node256Leaf::New(ART &art, Node &node) { void Node256Leaf::InsertByte(ART &art, Node &node, const uint8_t byte) { auto &n256 = Node::Ref(art, node, NODE_256_LEAF); n256.count++; - ValidityMask mask(&n256.mask[0], Node256::CAPACITY); + ValidityMask mask(&n256.mask[0]); mask.SetValid(byte); } void Node256Leaf::DeleteByte(ART &art, Node &node, const uint8_t byte) { auto &n256 = Node::Ref(art, node, NODE_256_LEAF); n256.count--; - ValidityMask mask(&n256.mask[0], Node256::CAPACITY); + ValidityMask mask(&n256.mask[0]); mask.SetInvalid(byte); // Shrink node to Node15 @@ -37,12 +37,12 @@ void Node256Leaf::DeleteByte(ART &art, Node &node, const uint8_t byte) { } bool Node256Leaf::HasByte(uint8_t &byte) { - ValidityMask v_mask(&mask[0], Node256::CAPACITY); + ValidityMask v_mask(&mask[0]); return v_mask.RowIsValid(byte); } bool Node256Leaf::GetNextByte(uint8_t &byte) { - ValidityMask v_mask(&mask[0], Node256::CAPACITY); + ValidityMask v_mask(&mask[0]); for (uint16_t i = byte; i < CAPACITY; i++) { if (v_mask.RowIsValid(i)) { byte = UnsafeNumericCast(i); @@ -58,7 +58,7 @@ Node256Leaf &Node256Leaf::GrowNode15Leaf(ART &art, Node &node256_leaf, Node &nod node256_leaf.SetGateStatus(node15_leaf.GetGateStatus()); n256.count = n15.count; - ValidityMask mask(&n256.mask[0], Node256::CAPACITY); + ValidityMask mask(&n256.mask[0]); for (uint8_t i = 0; i < n15.count; i++) { mask.SetValid(n15.key[i]); } diff --git a/src/duckdb/src/execution/index/art/plan_art.cpp b/src/duckdb/src/execution/index/art/plan_art.cpp index ce459b290..2acc56995 100644 --- a/src/duckdb/src/execution/index/art/plan_art.cpp +++ b/src/duckdb/src/execution/index/art/plan_art.cpp @@ -1,18 +1,24 @@ -#include "duckdb/execution/index/art/art.hpp" -#include "duckdb/execution/operator/filter/physical_filter.hpp" + #include "duckdb/execution/operator/order/physical_order.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" +#include "duckdb/execution/operator/filter/physical_filter.hpp" #include "duckdb/execution/operator/schema/physical_create_art_index.hpp" + #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/operator/logical_create_index.hpp" +#include "duckdb/execution/index/art/art.hpp" + namespace duckdb { unique_ptr ART::CreatePlan(PlanIndexInput &input) { + // generate a physical plan for the parallel index creation which consists of the following operators + // table scan - projection (for expression execution) - filter (NOT NULL) - order (if applicable) - create index + auto &op = input.op; + auto &table_scan = input.table_scan; - // PROJECTION on indexed columns. vector new_column_types; vector> select_list; for (idx_t i = 0; i < op.expressions.size(); i++) { @@ -23,66 +29,65 @@ unique_ptr ART::CreatePlan(PlanIndexInput &input) { select_list.push_back(make_uniq(LogicalType::ROW_TYPE, op.info->scan_types.size() - 1)); auto projection = make_uniq(new_column_types, std::move(select_list), op.estimated_cardinality); - projection->children.push_back(std::move(input.table_scan)); - - // Optional NOT NULL filter. - unique_ptr prev_operator; - auto is_alter = op.alter_table_info != nullptr; - if (!is_alter) { - vector filter_types; - vector> filter_select_list; - auto not_null_type = ExpressionType::OPERATOR_IS_NOT_NULL; + projection->children.push_back(std::move(table_scan)); - for (idx_t i = 0; i < new_column_types.size() - 1; i++) { - filter_types.push_back(new_column_types[i]); - auto is_not_null_expr = make_uniq(not_null_type, LogicalType::BOOLEAN); - auto bound_ref = make_uniq(new_column_types[i], i); - is_not_null_expr->children.push_back(std::move(bound_ref)); - filter_select_list.push_back(std::move(is_not_null_expr)); - } + // filter operator for IS_NOT_NULL on each key column - prev_operator = - make_uniq(std::move(filter_types), std::move(filter_select_list), op.estimated_cardinality); - prev_operator->types.emplace_back(LogicalType::ROW_TYPE); - prev_operator->children.push_back(std::move(projection)); + vector filter_types; + vector> filter_select_list; - } else { - prev_operator = std::move(projection); + for (idx_t i = 0; i < new_column_types.size() - 1; i++) { + filter_types.push_back(new_column_types[i]); + auto is_not_null_expr = + make_uniq(ExpressionType::OPERATOR_IS_NOT_NULL, LogicalType::BOOLEAN); + auto bound_ref = make_uniq(new_column_types[i], i); + is_not_null_expr->children.push_back(std::move(bound_ref)); + filter_select_list.push_back(std::move(is_not_null_expr)); } - // Determine whether to push an ORDER BY operator. - auto sort = true; + auto null_filter = + make_uniq(std::move(filter_types), std::move(filter_select_list), op.estimated_cardinality); + null_filter->types.emplace_back(LogicalType::ROW_TYPE); + null_filter->children.push_back(std::move(projection)); + + // determine if we sort the data prior to index creation + // we don't sort, if either VARCHAR or compound key + auto perform_sorting = true; if (op.unbound_expressions.size() > 1) { - sort = false; + perform_sorting = false; } else if (op.unbound_expressions[0]->return_type.InternalType() == PhysicalType::VARCHAR) { - sort = false; + perform_sorting = false; } - // CREATE INDEX operator. - auto physical_create_index = make_uniq( - op, op.table, op.info->column_ids, std::move(op.info), std::move(op.unbound_expressions), - op.estimated_cardinality, sort, std::move(op.alter_table_info)); + // actual physical create index operator - if (!sort) { - physical_create_index->children.push_back(std::move(prev_operator)); - return std::move(physical_create_index); - } + auto physical_create_index = + make_uniq(op, op.table, op.info->column_ids, std::move(op.info), + std::move(op.unbound_expressions), op.estimated_cardinality, perform_sorting); - // ORDER BY operator. - vector orders; - vector projections; - for (idx_t i = 0; i < new_column_types.size() - 1; i++) { - auto col_expr = make_uniq_base(new_column_types[i], i); - orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr)); - projections.emplace_back(i); - } - projections.emplace_back(new_column_types.size() - 1); + if (perform_sorting) { + + // optional order operator + vector orders; + vector projections; + for (idx_t i = 0; i < new_column_types.size() - 1; i++) { + auto col_expr = make_uniq_base(new_column_types[i], i); + orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(col_expr)); + projections.emplace_back(i); + } + projections.emplace_back(new_column_types.size() - 1); + + auto physical_order = make_uniq(new_column_types, std::move(orders), std::move(projections), + op.estimated_cardinality); + physical_order->children.push_back(std::move(null_filter)); - auto physical_order = - make_uniq(new_column_types, std::move(orders), std::move(projections), op.estimated_cardinality); + physical_create_index->children.push_back(std::move(physical_order)); + } else { + + // no ordering + physical_create_index->children.push_back(std::move(null_filter)); + } - physical_order->children.push_back(std::move(prev_operator)); - physical_create_index->children.push_back(std::move(physical_order)); return std::move(physical_create_index); } diff --git a/src/duckdb/src/execution/index/art/prefix.cpp b/src/duckdb/src/execution/index/art/prefix.cpp index f0821be04..cfdf89856 100644 --- a/src/duckdb/src/execution/index/art/prefix.cpp +++ b/src/duckdb/src/execution/index/art/prefix.cpp @@ -134,8 +134,14 @@ void Prefix::Concat(ART &art, Node &parent, uint8_t byte, const GateStatus old_s if (status == GateStatus::GATE_SET && child.GetType() == NType::LEAF_INLINED) { auto row_id = child.GetRowId(); - Free(art, parent); - Leaf::New(parent, row_id); + if (parent.GetType() == PREFIX) { + auto parent_status = parent.GetGateStatus(); + Free(art, parent); + Leaf::New(parent, row_id); + parent.SetGateStatus(parent_status); + } else { + Leaf::New(parent, row_id); + } return; } @@ -291,8 +297,8 @@ GateStatus Prefix::Split(ART &art, reference &node, Node &child, const uin return GateStatus::GATE_NOT_SET; } -ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art) { +bool Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, + const GateStatus status) { reference next(node); auto pos = TraverseMutable(art, next, key, depth); @@ -301,7 +307,7 @@ ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t de // (2) we reach a gate. if (pos == DConstants::INVALID_INDEX) { if (next.get().GetType() != NType::PREFIX || next.get().GetGateStatus() == GateStatus::GATE_SET) { - return art.Insert(next, key, depth, row_id, status, delete_art); + return art.Insert(next, key, depth, row_id, status); } } @@ -319,7 +325,7 @@ ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t de Node new_row_id; Leaf::New(new_row_id, key.GetRowId()); Node::InsertChild(art, next, key[depth], new_row_id); - return ARTConflictType::NO_CONFLICT; + return true; } Node leaf; @@ -332,7 +338,7 @@ ARTConflictType Prefix::Insert(ART &art, Node &node, const ARTKey &key, idx_t de // Create the inlined leaf. Leaf::New(ref, row_id.GetRowId()); Node4::InsertChild(art, next, key[depth], leaf); - return ARTConflictType::NO_CONFLICT; + return true; } string Prefix::VerifyAndToString(ART &art, const Node &node, const bool only_verify) { diff --git a/src/duckdb/src/execution/index/bound_index.cpp b/src/duckdb/src/execution/index/bound_index.cpp index 199cc4bdd..017f7f5be 100644 --- a/src/duckdb/src/execution/index/bound_index.cpp +++ b/src/duckdb/src/execution/index/bound_index.cpp @@ -32,31 +32,10 @@ void BoundIndex::InitializeLock(IndexLock &state) { state.index_lock = unique_lock(lock); } -ErrorData BoundIndex::Append(DataChunk &chunk, Vector &row_ids) { - IndexLock l; - InitializeLock(l); - return Append(l, chunk, row_ids); -} - -ErrorData BoundIndex::AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids, - optional_ptr delete_index) { - // Fallback to the old Append. - return Append(l, chunk, row_ids); -} - -ErrorData BoundIndex::AppendWithDeleteIndex(DataChunk &chunk, Vector &row_ids, optional_ptr delete_index) { - IndexLock l; - InitializeLock(l); - return AppendWithDeleteIndex(l, chunk, row_ids, delete_index); -} - -void BoundIndex::VerifyAppend(DataChunk &chunk, optional_ptr delete_index, - optional_ptr manager) { - throw NotImplementedException("this implementation of VerifyAppend does not exist."); -} - -void BoundIndex::VerifyConstraint(DataChunk &chunk, optional_ptr delete_index, ConflictManager &manager) { - throw NotImplementedException("this implementation of VerifyConstraint does not exist."); +ErrorData BoundIndex::Append(DataChunk &entries, Vector &row_identifiers) { + IndexLock state; + InitializeLock(state); + return Append(state, entries, row_identifiers); } void BoundIndex::CommitDrop() { @@ -71,10 +50,6 @@ void BoundIndex::Delete(DataChunk &entries, Vector &row_identifiers) { Delete(state, entries, row_identifiers); } -ErrorData BoundIndex::Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ptr delete_index) { - throw NotImplementedException("this implementation of Insert does not exist."); -} - bool BoundIndex::MergeIndexes(BoundIndex &other_index) { IndexLock state; InitializeLock(state); @@ -110,7 +85,7 @@ void BoundIndex::ExecuteExpressions(DataChunk &input, DataChunk &result) { } unique_ptr BoundIndex::BindExpression(unique_ptr expr) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_colref = expr->Cast(); return make_uniq(expr->return_type, column_ids[bound_colref.binding.column_index]); } diff --git a/src/duckdb/src/execution/index/fixed_size_allocator.cpp b/src/duckdb/src/execution/index/fixed_size_allocator.cpp index 24ea09181..a6ad0f381 100644 --- a/src/duckdb/src/execution/index/fixed_size_allocator.cpp +++ b/src/duckdb/src/execution/index/fixed_size_allocator.cpp @@ -44,6 +44,7 @@ FixedSizeAllocator::FixedSizeAllocator(const idx_t segment_size, BlockManager &b } IndexPointer FixedSizeAllocator::New() { + // no more segments available if (buffers_with_free_space.empty()) { @@ -56,7 +57,7 @@ IndexPointer FixedSizeAllocator::New() { // set the bitmask D_ASSERT(buffers.find(buffer_id) != buffers.end()); auto &buffer = buffers.find(buffer_id)->second; - ValidityMask mask(reinterpret_cast(buffer.Get()), available_segments_per_buffer); + ValidityMask mask(reinterpret_cast(buffer.Get())); // zero-initialize the bitmask to avoid leaking memory to disk auto data = mask.GetData(); @@ -74,7 +75,7 @@ IndexPointer FixedSizeAllocator::New() { D_ASSERT(buffers.find(buffer_id) != buffers.end()); auto &buffer = buffers.find(buffer_id)->second; - auto offset = buffer.GetOffset(bitmask_count, available_segments_per_buffer); + auto offset = buffer.GetOffset(bitmask_count); total_segment_count++; buffer.segment_count++; @@ -99,7 +100,7 @@ void FixedSizeAllocator::Free(const IndexPointer ptr) { auto &buffer = buffers.find(buffer_id)->second; auto bitmask_ptr = reinterpret_cast(buffer.Get()); - ValidityMask mask(bitmask_ptr, offset + 1); // FIXME + ValidityMask mask(bitmask_ptr); D_ASSERT(!mask.RowIsValid(offset)); mask.SetValid(offset); @@ -288,6 +289,7 @@ vector FixedSizeAllocator::InitSerializationToWAL() { } void FixedSizeAllocator::Init(const FixedSizeAllocatorInfo &info) { + segment_size = info.segment_size; total_segment_count = 0; diff --git a/src/duckdb/src/execution/index/fixed_size_buffer.cpp b/src/duckdb/src/execution/index/fixed_size_buffer.cpp index 336d96396..7647a4533 100644 --- a/src/duckdb/src/execution/index/fixed_size_buffer.cpp +++ b/src/duckdb/src/execution/index/fixed_size_buffer.cpp @@ -106,25 +106,21 @@ void FixedSizeBuffer::Serialize(PartialBlockManager &partial_block_manager, cons auto &p_block_for_index = allocation.partial_block->Cast(); auto dst_handle = buffer_manager.Pin(p_block_for_index.block_handle); memcpy(dst_handle.Ptr() + block_pointer.offset, buffer_handle.Ptr(), allocation_size); - SetUninitializedRegions(p_block_for_index, segment_size, block_pointer.offset, bitmask_offset, - available_segments); + SetUninitializedRegions(p_block_for_index, segment_size, block_pointer.offset, bitmask_offset); } else { // create a new block that can potentially be used as a partial block D_ASSERT(block_handle); D_ASSERT(!block_pointer.offset); auto p_block_for_index = make_uniq(allocation.state, block_manager, block_handle); - SetUninitializedRegions(*p_block_for_index, segment_size, block_pointer.offset, bitmask_offset, - available_segments); + SetUninitializedRegions(*p_block_for_index, segment_size, block_pointer.offset, bitmask_offset); allocation.partial_block = std::move(p_block_for_index); } - // resetting this buffer - buffer_handle.Destroy(); - - // register the partial block partial_block_manager.RegisterPartialBlock(std::move(allocation)); + // resetting this buffer + buffer_handle.Destroy(); block_handle = block_manager.RegisterBlock(block_pointer.block_id); D_ASSERT(block_handle->BlockId() < MAXIMUM_BLOCK); @@ -150,11 +146,11 @@ void FixedSizeBuffer::Pin() { block_handle = std::move(new_block_handle); } -uint32_t FixedSizeBuffer::GetOffset(const idx_t bitmask_count, const idx_t available_segments) { +uint32_t FixedSizeBuffer::GetOffset(const idx_t bitmask_count) { // get the bitmask data auto bitmask_ptr = reinterpret_cast(Get()); - ValidityMask mask(bitmask_ptr, available_segments); + ValidityMask mask(bitmask_ptr); auto data = mask.GetData(); // fills up a buffer sequentially before searching for free bits @@ -208,7 +204,7 @@ void FixedSizeBuffer::SetAllocationSize(const idx_t available_segments, const id // We traverse from the back. A binary search would be faster. // However, buffers are often (almost) full, so the overhead is acceptable. auto bitmask_ptr = reinterpret_cast(Get()); - ValidityMask mask(bitmask_ptr, available_segments); + ValidityMask mask(bitmask_ptr); auto max_offset = available_segments; for (idx_t i = available_segments; i > 0; i--) { @@ -221,14 +217,13 @@ void FixedSizeBuffer::SetAllocationSize(const idx_t available_segments, const id } void FixedSizeBuffer::SetUninitializedRegions(PartialBlockForIndex &p_block_for_index, const idx_t segment_size, - const idx_t offset, const idx_t bitmask_offset, - const idx_t available_segments) { + const idx_t offset, const idx_t bitmask_offset) { // this function calls Get() on the buffer D_ASSERT(InMemory()); auto bitmask_ptr = reinterpret_cast(Get()); - ValidityMask mask(bitmask_ptr, available_segments); + ValidityMask mask(bitmask_ptr); idx_t i = 0; idx_t max_offset = offset + allocation_size; diff --git a/src/duckdb/src/execution/join_hashtable.cpp b/src/duckdb/src/execution/join_hashtable.cpp index 14abdc61e..095745c31 100644 --- a/src/duckdb/src/execution/join_hashtable.cpp +++ b/src/duckdb/src/execution/join_hashtable.cpp @@ -14,13 +14,13 @@ using ProbeSpill = JoinHashTable::ProbeSpill; using ProbeSpillLocalState = JoinHashTable::ProbeSpillLocalAppendState; JoinHashTable::SharedState::SharedState() - : rhs_row_locations(LogicalType::POINTER), salt_v(LogicalType::UBIGINT), salt_match_sel(STANDARD_VECTOR_SIZE), + : rhs_row_locations(LogicalType::POINTER), salt_match_sel(STANDARD_VECTOR_SIZE), key_no_match_sel(STANDARD_VECTOR_SIZE) { } JoinHashTable::ProbeState::ProbeState() - : SharedState(), ht_offsets_v(LogicalType::UBIGINT), ht_offsets_dense_v(LogicalType::UBIGINT), - non_empty_sel(STANDARD_VECTOR_SIZE) { + : SharedState(), salt_v(LogicalType::UBIGINT), ht_offsets_v(LogicalType::UBIGINT), + ht_offsets_dense_v(LogicalType::UBIGINT), non_empty_sel(STANDARD_VECTOR_SIZE) { } JoinHashTable::InsertState::InsertState(const JoinHashTable &ht) @@ -34,7 +34,7 @@ JoinHashTable::JoinHashTable(ClientContext &context, const vector : buffer_manager(BufferManager::GetBufferManager(context)), conditions(conditions_p), build_types(std::move(btypes)), output_columns(output_columns_p), entry_size(0), tuple_size(0), vfound(Value::BOOLEAN(false)), join_type(type_p), finalized(false), has_null(false), - radix_bits(INITIAL_RADIX_BITS) { + radix_bits(INITIAL_RADIX_BITS), partition_start(0), partition_end(0) { for (idx_t i = 0; i < conditions.size(); ++i) { auto &condition = conditions[i]; D_ASSERT(condition.left->return_type == condition.right->return_type); @@ -108,8 +108,6 @@ JoinHashTable::JoinHashTable(ClientContext &context, const vector auto &config = ClientConfig::GetConfig(context); single_join_error_on_multiple_rows = config.scalar_subquery_error_on_multiple_rows; } - - InitializePartitionMasks(); } JoinHashTable::~JoinHashTable() { @@ -134,23 +132,21 @@ void JoinHashTable::Merge(JoinHashTable &other) { sink_collection->Combine(*other.sink_collection); } -static void ApplyBitmaskAndGetSaltBuild(Vector &hashes_v, Vector &salt_v, const idx_t &count, const idx_t &bitmask) { +static void ApplyBitmaskAndGetSaltBuild(Vector &hashes_v, const idx_t &count, const idx_t &bitmask) { if (hashes_v.GetVectorType() == VectorType::CONSTANT_VECTOR) { - auto &hash = *ConstantVector::GetData(hashes_v); - salt_v.SetVectorType(VectorType::CONSTANT_VECTOR); - - *ConstantVector::GetData(salt_v) = ht_entry_t::ExtractSalt(hash); - salt_v.Flatten(count); - - hash = hash & bitmask; + D_ASSERT(!ConstantVector::IsNull(hashes_v)); + auto indices = ConstantVector::GetData(hashes_v); + hash_t salt = ht_entry_t::ExtractSaltWithNulls(*indices); + idx_t offset = *indices & bitmask; + *indices = offset | salt; hashes_v.Flatten(count); } else { hashes_v.Flatten(count); - auto salts = FlatVector::GetData(salt_v); auto hashes = FlatVector::GetData(hashes_v); for (idx_t i = 0; i < count; i++) { - salts[i] = ht_entry_t::ExtractSalt(hashes[i]); - hashes[i] &= bitmask; + idx_t salt = ht_entry_t::ExtractSaltWithNulls(hashes[i]); + idx_t offset = hashes[i] & bitmask; + hashes[i] = offset | salt; } } } @@ -160,7 +156,7 @@ static void ApplyBitmaskAndGetSaltBuild(Vector &hashes_v, Vector &salt_v, const template static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState &key_state, JoinHashTable::ProbeState &state, Vector &hashes_v, - const SelectionVector &sel, idx_t &count, JoinHashTable &ht, + const SelectionVector &sel, idx_t &count, JoinHashTable *ht, ht_entry_t *entries, Vector &pointers_result_v, SelectionVector &match_sel) { UnifiedVectorFormat hashes_v_unified; hashes_v.ToUnifiedFormat(count, hashes_v_unified); @@ -177,7 +173,7 @@ static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState & for (idx_t i = 0; i < count; i++) { const auto row_index = sel.get_index(i); auto uvf_index = hashes_v_unified.sel->get_index(row_index); - auto ht_offset = hashes[uvf_index] & ht.bitmask; + auto ht_offset = hashes[uvf_index] & ht->bitmask; ht_offsets_dense[i] = ht_offset; ht_offsets[row_index] = ht_offset; } @@ -243,7 +239,7 @@ static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState & break; } - IncrementAndWrap(ht_offset, ht.bitmask); + IncrementAndWrap(ht_offset, ht->bitmask); } } else { entry = entries[ht_offset]; @@ -262,9 +258,9 @@ static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState & if (salt_match_count != 0) { // Perform row comparisons, after function call salt_match_sel will point to the keys that match - idx_t key_match_count = ht.row_matcher_build.Match(keys, key_state.vector_data, state.salt_match_sel, - salt_match_count, ht.layout, state.rhs_row_locations, - &state.key_no_match_sel, key_no_match_count); + idx_t key_match_count = ht->row_matcher_build.Match(keys, key_state.vector_data, state.salt_match_sel, + salt_match_count, ht->layout, state.rhs_row_locations, + &state.key_no_match_sel, key_no_match_count); D_ASSERT(key_match_count + key_no_match_count == salt_match_count); @@ -282,7 +278,7 @@ static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState & const auto row_index = state.key_no_match_sel.get_index(i); auto &ht_offset = ht_offsets[row_index]; - IncrementAndWrap(ht_offset, ht.bitmask); + IncrementAndWrap(ht_offset, ht->bitmask); } } @@ -292,18 +288,19 @@ static inline void GetRowPointersInternal(DataChunk &keys, TupleDataChunkState & } inline bool JoinHashTable::UseSalt() const { - // only use salt for large hash tables - return this->capacity > USE_SALT_THRESHOLD; + // only use salt for large hash tables and if there is only one equality condition as otherwise + // we potentially need to compare multiple keys + return this->capacity > USE_SALT_THRESHOLD && this->equality_predicate_columns.size() == 1; } void JoinHashTable::GetRowPointers(DataChunk &keys, TupleDataChunkState &key_state, ProbeState &state, Vector &hashes_v, const SelectionVector &sel, idx_t &count, Vector &pointers_result_v, SelectionVector &match_sel) { if (UseSalt()) { - GetRowPointersInternal(keys, key_state, state, hashes_v, sel, count, *this, entries, pointers_result_v, + GetRowPointersInternal(keys, key_state, state, hashes_v, sel, count, this, entries, pointers_result_v, match_sel); } else { - GetRowPointersInternal(keys, key_state, state, hashes_v, sel, count, *this, entries, pointers_result_v, + GetRowPointersInternal(keys, key_state, state, hashes_v, sel, count, this, entries, pointers_result_v, match_sel); } } @@ -423,10 +420,6 @@ idx_t JoinHashTable::PrepareKeys(DataChunk &keys, vector } for (idx_t col_idx = 0; col_idx < keys.ColumnCount(); col_idx++) { - // see internal issue 3717. - if (join_type == JoinType::MARK && !correlated_mark_join_info.correlated_types.empty()) { - continue; - } if (null_values_are_equal[col_idx]) { continue; } @@ -441,11 +434,11 @@ idx_t JoinHashTable::PrepareKeys(DataChunk &keys, vector return added_count; } -static void StorePointer(const const_data_ptr_t &pointer, const data_ptr_t &target) { +static void StorePointer(const_data_ptr_t pointer, data_ptr_t target) { Store(cast_pointer_to_uint64(pointer), target); } -static data_ptr_t LoadPointer(const const_data_ptr_t &source) { +static data_ptr_t LoadPointer(const_data_ptr_t source) { return cast_uint64_to_pointer(Load(source)); } @@ -455,36 +448,44 @@ static data_ptr_t LoadPointer(const const_data_ptr_t &source) { template static inline data_ptr_t InsertRowToEntry(atomic &entry, const data_ptr_t &row_ptr_to_insert, const hash_t &salt, const idx_t &pointer_offset) { - const ht_entry_t desired_entry(salt, row_ptr_to_insert); + if (PARALLEL) { + // if we expect the entry to be empty, if the operation fails we need to cancel the whole operation as another + // key might have been inserted in the meantime that does not match the current key if (EXPECT_EMPTY) { - // Add nullptr to the end of the list to mark the end + // add nullptr to the end of the list to mark the end StorePointer(nullptr, row_ptr_to_insert + pointer_offset); - ht_entry_t expected_entry; - entry.compare_exchange_strong(expected_entry, desired_entry, std::memory_order_acquire, + ht_entry_t new_empty_entry = ht_entry_t::GetDesiredEntry(row_ptr_to_insert, salt); + ht_entry_t expected_empty_entry = ht_entry_t::GetEmptyEntry(); + entry.compare_exchange_strong(expected_empty_entry, new_empty_entry, std::memory_order_acquire, std::memory_order_relaxed); - // The expected entry is updated with the encountered entry by the compare exchange - // So, this returns a nullptr if it was empty, and a non-null if it was not (which cancels the insert) - return expected_entry.GetPointerOrNull(); + // if the expected empty entry actually was null, we can just return the pointer, and it will be a nullptr + // if the expected entry was filled in the meantime, we need to cancel the operation and will return the + // pointer to the next entry + return expected_empty_entry.GetPointerOrNull(); } else { - // At this point we know that the keys match, so we can try to insert until we succeed - ht_entry_t expected_entry = entry.load(std::memory_order_relaxed); - D_ASSERT(expected_entry.IsOccupied()); + // if we expect the entry to be full, we know that even if the insert fails the keys still match so we can + // just keep trying until we succeed + ht_entry_t expected_current_entry = entry.load(std::memory_order_relaxed); + ht_entry_t desired_new_entry = ht_entry_t::GetDesiredEntry(row_ptr_to_insert, salt); + D_ASSERT(expected_current_entry.IsOccupied()); + do { - data_ptr_t current_row_pointer = expected_entry.GetPointer(); + data_ptr_t current_row_pointer = expected_current_entry.GetPointer(); StorePointer(current_row_pointer, row_ptr_to_insert + pointer_offset); - } while (!entry.compare_exchange_weak(expected_entry, desired_entry, std::memory_order_release, + } while (!entry.compare_exchange_weak(expected_current_entry, desired_new_entry, std::memory_order_release, std::memory_order_relaxed)); return nullptr; } } else { - // If we are not in parallel mode, we can just do the operation without any checks - data_ptr_t current_row_pointer = entry.load(std::memory_order_relaxed).GetPointerOrNull(); + // if we are not in parallel mode, we can just do the operation without any checks + ht_entry_t current_entry = entry.load(std::memory_order_relaxed); + data_ptr_t current_row_pointer = current_entry.GetPointerOrNull(); StorePointer(current_row_pointer, row_ptr_to_insert + pointer_offset); - entry = desired_entry; + entry = ht_entry_t::GetDesiredEntry(row_ptr_to_insert, salt); return nullptr; } } @@ -517,9 +518,8 @@ static inline void PerformKeyComparison(JoinHashTable::InsertState &state, JoinH template static inline void InsertMatchesAndIncrementMisses(atomic entries[], JoinHashTable::InsertState &state, JoinHashTable &ht, const data_ptr_t lhs_row_locations[], - idx_t ht_offsets[], const hash_t hash_salts[], - const idx_t capacity_mask, const idx_t key_match_count, - const idx_t key_no_match_count) { + idx_t ht_offsets_and_salts[], const idx_t capacity_mask, + const idx_t key_match_count, const idx_t key_no_match_count) { if (key_match_count != 0) { ht.chains_longer_than_one = true; } @@ -529,11 +529,11 @@ static inline void InsertMatchesAndIncrementMisses(atomic entries[], const auto need_compare_idx = state.key_match_sel.get_index(i); const auto entry_index = state.salt_match_sel.get_index(need_compare_idx); - const auto &ht_offset = ht_offsets[entry_index]; + const auto &ht_offset = ht_offsets_and_salts[entry_index] & ht_entry_t::POINTER_MASK; auto &entry = entries[ht_offset]; - const auto row_ptr_to_insert = lhs_row_locations[entry_index]; + const data_ptr_t row_ptr_to_insert = lhs_row_locations[entry_index]; - const auto salt = hash_salts[entry_index]; + const auto salt = ht_offsets_and_salts[entry_index]; InsertRowToEntry(entry, row_ptr_to_insert, salt, ht.pointer_offset); } @@ -542,8 +542,8 @@ static inline void InsertMatchesAndIncrementMisses(atomic entries[], const auto need_compare_idx = state.key_no_match_sel.get_index(i); const auto entry_index = state.salt_match_sel.get_index(need_compare_idx); - auto &ht_offset = ht_offsets[entry_index]; - IncrementAndWrap(ht_offset, capacity_mask); + idx_t &ht_offset_and_salt = ht_offsets_and_salts[entry_index]; + IncrementAndWrap(ht_offset_and_salt, capacity_mask); state.remaining_sel.set_index(i, entry_index); } @@ -554,11 +554,10 @@ static void InsertHashesLoop(atomic entries[], Vector &row_locations JoinHashTable::InsertState &state, const TupleDataCollection &data_collection, JoinHashTable &ht) { D_ASSERT(hashes_v.GetType().id() == LogicalType::HASH); - ApplyBitmaskAndGetSaltBuild(hashes_v, state.salt_v, count, ht.bitmask); + ApplyBitmaskAndGetSaltBuild(hashes_v, count, ht.bitmask); - // the salts offset for each row to insert - const auto ht_offsets = FlatVector::GetData(hashes_v); - const auto hash_salts = FlatVector::GetData(state.salt_v); + // the offset for each row to insert + const auto ht_offsets_and_salts = FlatVector::GetData(hashes_v); // the row locations of the rows that are already in the hash table const auto rhs_row_locations = FlatVector::GetData(state.rhs_row_locations); // the row locations of the rows that are to be inserted @@ -584,7 +583,7 @@ static void InsertHashesLoop(atomic entries[], Vector &row_locations idx_t new_remaining_count = 0; for (idx_t i = 0; i < remaining_count; i++) { const auto idx = remaining_sel->get_index(i); - if (ValidityBytes(lhs_row_locations[idx], count).RowIsValidUnsafe(col_idx)) { + if (ValidityBytes(lhs_row_locations[idx]).RowIsValidUnsafe(col_idx)) { state.remaining_sel.set_index(new_remaining_count++, idx); } } @@ -601,13 +600,15 @@ static void InsertHashesLoop(atomic entries[], Vector &row_locations // iterate over each entry to find out whether it belongs to an existing list or will start a new list for (idx_t i = 0; i < remaining_count; i++) { const idx_t row_index = remaining_sel->get_index(i); - auto &ht_offset = ht_offsets[row_index]; - auto &salt = hash_salts[row_index]; + idx_t &ht_offset_and_salt = ht_offsets_and_salts[row_index]; + const hash_t salt = ht_entry_t::ExtractSalt(ht_offset_and_salt); - // increment the ht_offset of the entry as long as next entry is occupied and salt does not match + // increment the ht_offset_and_salt of the entry as long as next entry is occupied and salt does not match + idx_t ht_offset; ht_entry_t entry; bool occupied; while (true) { + ht_offset = ht_offset_and_salt & ht_entry_t::POINTER_MASK; atomic &atomic_entry = entries[ht_offset]; entry = atomic_entry.load(std::memory_order_relaxed); occupied = entry.IsOccupied(); @@ -620,7 +621,7 @@ static void InsertHashesLoop(atomic entries[], Vector &row_locations break; } - IncrementAndWrap(ht_offset, capacity_mask); + IncrementAndWrap(ht_offset_and_salt, capacity_mask); } if (!occupied) { // insert into free @@ -655,7 +656,7 @@ static void InsertHashesLoop(atomic entries[], Vector &row_locations idx_t key_match_count = 0; PerformKeyComparison(state, ht, data_collection, row_locations, salt_match_count, key_match_count, key_no_match_count); - InsertMatchesAndIncrementMisses(entries, state, ht, lhs_row_locations, ht_offsets, hash_salts, + InsertMatchesAndIncrementMisses(entries, state, ht, lhs_row_locations, ht_offsets_and_salts, capacity_mask, key_match_count, key_no_match_count); } @@ -700,7 +701,7 @@ void JoinHashTable::InitializePointerTable() { D_ASSERT(hash_map.GetSize() == capacity * sizeof(ht_entry_t)); // initialize HT with all-zero entries - std::fill_n(entries, capacity, ht_entry_t()); + std::fill_n(entries, capacity, ht_entry_t::GetEmptyEntry()); bitmask = capacity - 1; } @@ -771,12 +772,10 @@ ScanStructure::ScanStructure(JoinHashTable &ht_p, TupleDataChunkState &key_state : key_state(key_state_p), pointers(LogicalType::POINTER), count(0), sel_vector(STANDARD_VECTOR_SIZE), chain_match_sel_vector(STANDARD_VECTOR_SIZE), chain_no_match_sel_vector(STANDARD_VECTOR_SIZE), found_match(make_unsafe_uniq_array_uninitialized(STANDARD_VECTOR_SIZE)), ht(ht_p), finished(false), - is_null(true), rhs_pointers(LogicalType::POINTER), lhs_sel_vector(STANDARD_VECTOR_SIZE), last_match_count(0), - last_sel_vector(STANDARD_VECTOR_SIZE) { + is_null(true) { } void ScanStructure::Next(DataChunk &keys, DataChunk &left, DataChunk &result) { - D_ASSERT(keys.size() == left.size()); if (finished) { return; } @@ -897,100 +896,46 @@ void ScanStructure::GatherResult(Vector &result, const SelectionVector &sel_vect GatherResult(result, *FlatVector::IncrementalSelectionVector(), sel_vector, count, col_idx); } -void ScanStructure::GatherResult(Vector &result, const idx_t count, const idx_t col_idx) { - ht.data_collection->Gather(rhs_pointers, *FlatVector::IncrementalSelectionVector(), count, col_idx, result, - *FlatVector::IncrementalSelectionVector(), nullptr); -} - -void ScanStructure::UpdateCompactionBuffer(idx_t base_count, SelectionVector &result_vector, idx_t result_count) { - // matches were found - // record the result - // on the LHS, we store result vector - for (idx_t i = 0; i < result_count; i++) { - lhs_sel_vector.set_index(base_count + i, result_vector.get_index(i)); - } - - // on the RHS, we collect their pointers - VectorOperations::Copy(pointers, rhs_pointers, result_vector, result_count, 0, base_count); -} - void ScanStructure::NextInnerJoin(DataChunk &keys, DataChunk &left, DataChunk &result) { if (ht.join_type != JoinType::RIGHT_SEMI && ht.join_type != JoinType::RIGHT_ANTI) { D_ASSERT(result.ColumnCount() == left.ColumnCount() + ht.output_columns.size()); } + if (this->count == 0) { + // no pointers left to chase + return; + } - idx_t base_count = 0; - idx_t result_count; - while (this->count > 0) { - // if we have saved the match result, we need not call ScanInnerJoin again - if (last_match_count == 0) { - result_count = ScanInnerJoin(keys, chain_match_sel_vector); - } else { - chain_match_sel_vector.Initialize(last_sel_vector); - result_count = last_match_count; - last_match_count = 0; - } - - if (result_count > 0) { - // the result chunk cannot contain more data, we record the match result for future use - if (base_count + result_count > STANDARD_VECTOR_SIZE) { - last_sel_vector.Initialize(chain_match_sel_vector); - last_match_count = result_count; - break; - } + idx_t result_count = ScanInnerJoin(keys, chain_match_sel_vector); - if (PropagatesBuildSide(ht.join_type)) { - // full/right outer join: mark join matches as FOUND in the HT - auto ptrs = FlatVector::GetData(pointers); - for (idx_t i = 0; i < result_count; i++) { - auto idx = chain_match_sel_vector.get_index(i); - // NOTE: threadsan reports this as a data race because this can be set concurrently by separate - // threads Technically it is, but it does not matter, since the only value that can be written is - // "true" - Store(true, ptrs[idx] + ht.tuple_size); - } + if (result_count > 0) { + if (PropagatesBuildSide(ht.join_type)) { + // full/right outer join: mark join matches as FOUND in the HT + auto ptrs = FlatVector::GetData(pointers); + for (idx_t i = 0; i < result_count; i++) { + auto idx = chain_match_sel_vector.get_index(i); + // NOTE: threadsan reports this as a data race because this can be set concurrently by separate + // threads Technically it is, but it does not matter, since the only value that can be written is + // "true" + Store(true, ptrs[idx] + ht.tuple_size); } - - if (ht.join_type != JoinType::RIGHT_SEMI && ht.join_type != JoinType::RIGHT_ANTI) { - // Fast Path: if there is NO more than one element in the chain, we construct the result chunk directly - if (!ht.chains_longer_than_one) { - // matches were found - // on the LHS, we create a slice using the result vector - result.Slice(left, chain_match_sel_vector, result_count); - - // on the RHS, we need to fetch the data from the hash table - for (idx_t i = 0; i < ht.output_columns.size(); i++) { - auto &vector = result.data[left.ColumnCount() + i]; - const auto output_col_idx = ht.output_columns[i]; - D_ASSERT(vector.GetType() == ht.layout.GetTypes()[output_col_idx]); - GatherResult(vector, chain_match_sel_vector, result_count, output_col_idx); - } - - AdvancePointers(); - return; - } - - // Common Path: use a buffer to store temporary data - UpdateCompactionBuffer(base_count, chain_match_sel_vector, result_count); - base_count += result_count; + } + // for right semi join, just mark the entry as found and move on. Propagation happens later + if (ht.join_type != JoinType::RIGHT_SEMI && ht.join_type != JoinType::RIGHT_ANTI) { + // matches were found + // construct the result + // on the LHS, we create a slice using the result vector + result.Slice(left, chain_match_sel_vector, result_count); + + // on the RHS, we need to fetch the data from the hash table + for (idx_t i = 0; i < ht.output_columns.size(); i++) { + auto &vector = result.data[left.ColumnCount() + i]; + const auto output_col_idx = ht.output_columns[i]; + D_ASSERT(vector.GetType() == ht.layout.GetTypes()[output_col_idx]); + GatherResult(vector, chain_match_sel_vector, result_count, output_col_idx); } } AdvancePointers(); } - - if (base_count > 0) { - // create result chunk, we have two steps: - // 1) slice LHS vectors - result.Slice(left, lhs_sel_vector, base_count); - - // 2) gather RHS vectors - for (idx_t i = 0; i < ht.output_columns.size(); i++) { - auto &vector = result.data[left.ColumnCount() + i]; - const auto output_col_idx = ht.output_columns[i]; - D_ASSERT(vector.GetType() == ht.layout.GetTypes()[output_col_idx]); - GatherResult(vector, base_count, output_col_idx); - } - } } void ScanStructure::ScanKeyMatches(DataChunk &keys) { @@ -1018,6 +963,7 @@ void ScanStructure::ScanKeyMatches(DataChunk &keys) { template void ScanStructure::NextSemiOrAntiJoin(DataChunk &keys, DataChunk &left, DataChunk &result) { D_ASSERT(left.ColumnCount() == result.ColumnCount()); + D_ASSERT(keys.size() == left.size()); // create the selection vector from the matches that were found SelectionVector sel(STANDARD_VECTOR_SIZE); idx_t result_count = 0; @@ -1432,10 +1378,7 @@ idx_t JoinHashTable::GetRemainingSize() const { idx_t count = 0; idx_t data_size = 0; - for (idx_t partition_idx = 0; partition_idx < num_partitions; partition_idx++) { - if (completed_partitions.RowIsValidUnsafe(partition_idx)) { - continue; - } + for (idx_t partition_idx = partition_end; partition_idx < num_partitions; partition_idx++) { count += partitions[partition_idx]->Count(); data_size += partitions[partition_idx]->SizeInBytes(); } @@ -1469,32 +1412,6 @@ void JoinHashTable::SetRepartitionRadixBits(const idx_t max_ht_size, const idx_t radix_bits += added_bits; sink_collection = make_uniq(buffer_manager, layout, radix_bits, layout.ColumnCount() - 1); - - // Need to initialize again after changing the number of bits - InitializePartitionMasks(); -} - -void JoinHashTable::InitializePartitionMasks() { - const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); - - current_partitions.Initialize(num_partitions); - current_partitions.SetAllInvalid(num_partitions); - - completed_partitions.Initialize(num_partitions); - completed_partitions.SetAllInvalid(num_partitions); -} - -idx_t JoinHashTable::CurrentPartitionCount() const { - const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); - D_ASSERT(current_partitions.Capacity() == num_partitions); - return current_partitions.CountValid(num_partitions); -} - -idx_t JoinHashTable::FinishedPartitionCount() const { - const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); - D_ASSERT(completed_partitions.Capacity() == num_partitions); - // We already marked the active partitions as done, so we have to subtract them here - return completed_partitions.CountValid(num_partitions) - CurrentPartitionCount(); } void JoinHashTable::Repartition(JoinHashTable &global_ht) { @@ -1508,7 +1425,6 @@ void JoinHashTable::Repartition(JoinHashTable &global_ht) { void JoinHashTable::Reset() { data_collection->Reset(); hash_map.Reset(); - current_partitions.SetAllInvalid(RadixPartitioning::NumberOfPartitions(radix_bits)); finalized = false; } @@ -1518,98 +1434,90 @@ bool JoinHashTable::PrepareExternalFinalize(const idx_t max_ht_size) { } const auto num_partitions = RadixPartitioning::NumberOfPartitions(radix_bits); - D_ASSERT(current_partitions.Capacity() == num_partitions); - D_ASSERT(completed_partitions.Capacity() == num_partitions); - D_ASSERT(current_partitions.CheckAllInvalid(num_partitions)); - - if (completed_partitions.CheckAllValid(num_partitions)) { - return false; // All partitions are done + if (partition_end == num_partitions) { + return false; } - // Create vector with unfinished partition indices + // Start where we left off auto &partitions = sink_collection->GetPartitions(); - auto min_partition_size = NumericLimits::Maximum(); - vector partition_indices; - partition_indices.reserve(num_partitions); - for (idx_t partition_idx = 0; partition_idx < num_partitions; partition_idx++) { - if (completed_partitions.RowIsValidUnsafe(partition_idx)) { - continue; - } - partition_indices.push_back(partition_idx); - // Keep track of min partition size - const auto size = - partitions[partition_idx]->SizeInBytes() + PointerTableSize(partitions[partition_idx]->Count()); - min_partition_size = MinValue(min_partition_size, size); - } - - // Sort partitions by size, from small to large - std::stable_sort(partition_indices.begin(), partition_indices.end(), [&](const idx_t &lhs, const idx_t &rhs) { - const auto lhs_size = partitions[lhs]->SizeInBytes() + PointerTableSize(partitions[lhs]->Count()); - const auto rhs_size = partitions[rhs]->SizeInBytes() + PointerTableSize(partitions[rhs]->Count()); - // We divide by min_partition_size, effectively rouding everything down to a multiple of min_partition_size - // Makes it so minor differences in partition sizes don't mess up the original order - // Retaining as much of the original order as possible reduces I/O (partition idx determines eviction queue idx) - return lhs_size / min_partition_size < rhs_size / min_partition_size; - }); - - // Determine which partitions should go next + partition_start = partition_end; + + // Determine how many partitions we can do next (at least one) idx_t count = 0; idx_t data_size = 0; - for (const auto &partition_idx : partition_indices) { - D_ASSERT(!completed_partitions.RowIsValidUnsafe(partition_idx)); - const auto incl_count = count + partitions[partition_idx]->Count(); - const auto incl_data_size = data_size + partitions[partition_idx]->SizeInBytes(); - const auto incl_ht_size = incl_data_size + PointerTableSize(incl_count); + idx_t partition_idx; + for (partition_idx = partition_start; partition_idx < num_partitions; partition_idx++) { + auto incl_count = count + partitions[partition_idx]->Count(); + auto incl_data_size = data_size + partitions[partition_idx]->SizeInBytes(); + auto incl_ht_size = incl_data_size + PointerTableSize(incl_count); if (count > 0 && incl_ht_size > max_ht_size) { - break; // Always add at least one partition + break; } count = incl_count; data_size = incl_data_size; - current_partitions.SetValidUnsafe(partition_idx); // Mark as currently active - data_collection->Combine(*partitions[partition_idx]); // Move partition to the main data collection - completed_partitions.SetValidUnsafe(partition_idx); // Also already mark as done + } + partition_end = partition_idx; + + // Move the partitions to the main data collection + for (partition_idx = partition_start; partition_idx < partition_end; partition_idx++) { + data_collection->Combine(*partitions[partition_idx]); } D_ASSERT(Count() == count); return true; } -void JoinHashTable::ProbeAndSpill(ScanStructure &scan_structure, DataChunk &probe_keys, TupleDataChunkState &key_state, - ProbeState &probe_state, DataChunk &probe_chunk, ProbeSpill &probe_spill, +static void CreateSpillChunk(DataChunk &spill_chunk, DataChunk &keys, DataChunk &payload, Vector &hashes) { + spill_chunk.Reset(); + idx_t spill_col_idx = 0; + for (idx_t col_idx = 0; col_idx < keys.ColumnCount(); col_idx++) { + spill_chunk.data[col_idx].Reference(keys.data[col_idx]); + } + spill_col_idx += keys.ColumnCount(); + for (idx_t col_idx = 0; col_idx < payload.data.size(); col_idx++) { + spill_chunk.data[spill_col_idx + col_idx].Reference(payload.data[col_idx]); + } + spill_col_idx += payload.ColumnCount(); + spill_chunk.data[spill_col_idx].Reference(hashes); +} + +void JoinHashTable::ProbeAndSpill(ScanStructure &scan_structure, DataChunk &keys, TupleDataChunkState &key_state, + ProbeState &probe_state, DataChunk &payload, ProbeSpill &probe_spill, ProbeSpillLocalAppendState &spill_state, DataChunk &spill_chunk) { // hash all the keys Vector hashes(LogicalType::HASH); - Hash(probe_keys, *FlatVector::IncrementalSelectionVector(), probe_keys.size(), hashes); + Hash(keys, *FlatVector::IncrementalSelectionVector(), keys.size(), hashes); // find out which keys we can match with the current pinned partitions - SelectionVector true_sel(STANDARD_VECTOR_SIZE); - SelectionVector false_sel(STANDARD_VECTOR_SIZE); - const auto true_count = - RadixPartitioning::Select(hashes, FlatVector::IncrementalSelectionVector(), probe_keys.size(), radix_bits, - current_partitions, &true_sel, &false_sel); - const auto false_count = probe_keys.size() - true_count; + SelectionVector true_sel; + SelectionVector false_sel; + true_sel.Initialize(); + false_sel.Initialize(); + auto true_count = RadixPartitioning::Select(hashes, FlatVector::IncrementalSelectionVector(), keys.size(), + radix_bits, partition_end, &true_sel, &false_sel); + auto false_count = keys.size() - true_count; + + CreateSpillChunk(spill_chunk, keys, payload, hashes); // can't probe these values right now, append to spill - spill_chunk.Reset(); - spill_chunk.Reference(probe_chunk); - spill_chunk.data.back().Reference(hashes); spill_chunk.Slice(false_sel, false_count); + spill_chunk.Verify(); probe_spill.Append(spill_chunk, spill_state); // slice the stuff we CAN probe right now hashes.Slice(true_sel, true_count); - probe_keys.Slice(true_sel, true_count); - probe_chunk.Slice(true_sel, true_count); + keys.Slice(true_sel, true_count); + payload.Slice(true_sel, true_count); const SelectionVector *current_sel; - InitializeScanStructure(scan_structure, probe_keys, key_state, current_sel); + InitializeScanStructure(scan_structure, keys, key_state, current_sel); if (scan_structure.count == 0) { return; } // now initialize the pointers of the scan structure based on the hashes - GetRowPointers(probe_keys, key_state, probe_state, hashes, *current_sel, scan_structure.count, - scan_structure.pointers, scan_structure.sel_vector); + GetRowPointers(keys, key_state, probe_state, hashes, *current_sel, scan_structure.count, scan_structure.pointers, + scan_structure.sel_vector); } ProbeSpill::ProbeSpill(JoinHashTable &ht, ClientContext &context, const vector &probe_types) @@ -1651,25 +1559,21 @@ void ProbeSpill::Finalize() { } void ProbeSpill::PrepareNextProbe() { - global_spill_collection.reset(); auto &partitions = global_partitions->GetPartitions(); - if (partitions.empty() || ht.current_partitions.CheckAllInvalid(partitions.size())) { + if (partitions.empty() || ht.partition_start == partitions.size()) { // Can't probe, just make an empty one global_spill_collection = make_uniq(BufferManager::GetBufferManager(context), probe_types); } else { - // Move current partitions to the global spill collection - for (idx_t partition_idx = 0; partition_idx < partitions.size(); partition_idx++) { - if (!ht.current_partitions.RowIsValidUnsafe(partition_idx)) { - continue; - } - auto &partition = partitions[partition_idx]; - if (!global_spill_collection) { + // Move specific partitions to the global spill collection + global_spill_collection = std::move(partitions[ht.partition_start]); + for (idx_t i = ht.partition_start + 1; i < ht.partition_end; i++) { + auto &partition = partitions[i]; + if (global_spill_collection->Count() == 0) { global_spill_collection = std::move(partition); - } else if (partition->Count() != 0) { + } else { global_spill_collection->Combine(*partition); } - partition.reset(); } } consumer = make_uniq(*global_spill_collection, column_ids); diff --git a/src/duckdb/src/execution/operator/aggregate/grouped_aggregate_data.cpp b/src/duckdb/src/execution/operator/aggregate/grouped_aggregate_data.cpp index 088a0f59a..d0b52a606 100644 --- a/src/duckdb/src/execution/operator/aggregate/grouped_aggregate_data.cpp +++ b/src/duckdb/src/execution/operator/aggregate/grouped_aggregate_data.cpp @@ -20,7 +20,7 @@ void GroupedAggregateData::InitializeGroupby(vector> grou filter_count = 0; for (auto &expr : expressions) { - D_ASSERT(expr->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_AGGREGATE); D_ASSERT(expr->IsAggregate()); auto &aggr = expr->Cast(); bindings.push_back(&aggr); diff --git a/src/duckdb/src/execution/operator/aggregate/physical_hash_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_hash_aggregate.cpp index 6636389ea..e7d0c7563 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_hash_aggregate.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_hash_aggregate.cpp @@ -75,7 +75,7 @@ static vector CreateGroupChunkTypes(vector> } for (auto &group : groups) { - D_ASSERT(group->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(group->type == ExpressionType::BOUND_REF); auto &bound_ref = group->Cast(); group_indices.insert(bound_ref.index); } @@ -366,7 +366,7 @@ SinkResultType PhysicalHashAggregate::Sink(ExecutionContext &context, DataChunk for (auto &aggregate : aggregates) { auto &aggr = aggregate->Cast(); for (auto &child_expr : aggr.children) { - D_ASSERT(child_expr->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(child_expr->type == ExpressionType::BOUND_REF); auto &bound_ref_expr = child_expr->Cast(); D_ASSERT(bound_ref_expr.index < chunk.data.size()); aggregate_input_chunk.data[aggregate_input_idx++].Reference(chunk.data[bound_ref_expr.index]); @@ -885,15 +885,15 @@ SourceResultType PhysicalHashAggregate::GetData(ExecutionContext &context, DataC return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } -ProgressData PhysicalHashAggregate::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { +double PhysicalHashAggregate::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { auto &sink_gstate = sink_state->Cast(); auto &gstate = gstate_p.Cast(); - ProgressData progress; + double total_progress = 0; for (idx_t radix_idx = 0; radix_idx < groupings.size(); radix_idx++) { - progress.Add(groupings[radix_idx].table_data.GetProgress( - context, *sink_gstate.grouping_states[radix_idx].table_state, *gstate.radix_states[radix_idx])); + total_progress += groupings[radix_idx].table_data.GetProgress( + context, *sink_gstate.grouping_states[radix_idx].table_state, *gstate.radix_states[radix_idx]); } - return progress; + return total_progress / double(groupings.size()); } InsertionOrderPreservingMap PhysicalHashAggregate::ParamsToString() const { diff --git a/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp deleted file mode 100644 index 32bf4ecc2..000000000 --- a/src/duckdb/src/execution/operator/aggregate/physical_partitioned_aggregate.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include "duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp" -#include "duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp" -#include "duckdb/common/types/value_map.hpp" - -namespace duckdb { - -PhysicalPartitionedAggregate::PhysicalPartitionedAggregate(ClientContext &context, vector types, - vector> aggregates_p, - vector> groups_p, - vector partitions_p, idx_t estimated_cardinality) - : PhysicalOperator(PhysicalOperatorType::PARTITIONED_AGGREGATE, std::move(types), estimated_cardinality), - partitions(std::move(partitions_p)), groups(std::move(groups_p)), aggregates(std::move(aggregates_p)) { -} - -OperatorPartitionInfo PhysicalPartitionedAggregate::RequiredPartitionInfo() const { - return OperatorPartitionInfo::PartitionColumns(partitions); -} -//===--------------------------------------------------------------------===// -// Global State -//===--------------------------------------------------------------------===// -class PartitionedAggregateLocalSinkState : public LocalSinkState { -public: - PartitionedAggregateLocalSinkState(const PhysicalPartitionedAggregate &op, const vector &child_types, - ExecutionContext &context) - : execute_state(context.client, op.aggregates, child_types) { - } - - //! The current partition - Value current_partition; - //! The local aggregate state for the current partition - unique_ptr state; - //! The ungrouped aggregate execute state - UngroupedAggregateExecuteState execute_state; -}; - -class PartitionedAggregateGlobalSinkState : public GlobalSinkState { -public: - PartitionedAggregateGlobalSinkState(const PhysicalPartitionedAggregate &op, ClientContext &context) - : op(op), aggregate_result(BufferAllocator::Get(context), op.types) { - } - - mutex lock; - const PhysicalPartitionedAggregate &op; - //! The per-partition aggregate states - value_map_t> aggregate_states; - //! Final aggregate result - ColumnDataCollection aggregate_result; - - GlobalUngroupedAggregateState &GetOrCreatePartition(ClientContext &context, const Value &partition) { - lock_guard l(lock); - // find the state that corresponds to this partition and combine - auto entry = aggregate_states.find(partition); - if (entry != aggregate_states.end()) { - return *entry->second; - } - // no state yet for this partition - allocate a new one - auto new_global_state = make_uniq(BufferAllocator::Get(context), op.aggregates); - auto &result = *new_global_state; - aggregate_states.insert(make_pair(partition, std::move(new_global_state))); - return result; - } - - void Combine(ClientContext &context, PartitionedAggregateLocalSinkState &lstate) { - if (!lstate.state) { - // no aggregate state - return; - } - auto &global_state = GetOrCreatePartition(context, lstate.current_partition); - global_state.Combine(*lstate.state); - // clear the local aggregate state - lstate.state.reset(); - } -}; - -unique_ptr PhysicalPartitionedAggregate::GetGlobalSinkState(ClientContext &context) const { - return make_uniq(*this, context); -} - -//===--------------------------------------------------------------------===// -// Local State -//===--------------------------------------------------------------------===// - -unique_ptr PhysicalPartitionedAggregate::GetLocalSinkState(ExecutionContext &context) const { - D_ASSERT(sink_state); - return make_uniq(*this, children[0]->GetTypes(), context); -} - -//===--------------------------------------------------------------------===// -// Sink -//===--------------------------------------------------------------------===// -SinkResultType PhysicalPartitionedAggregate::Sink(ExecutionContext &context, DataChunk &chunk, - OperatorSinkInput &input) const { - auto &gstate = input.global_state.Cast(); - auto &lstate = input.local_state.Cast(); - if (!lstate.state) { - // the local state is not yet initialized for this partition - // initialize the partition - child_list_t partition_values; - for (idx_t partition_idx = 0; partition_idx < groups.size(); partition_idx++) { - auto column_name = to_string(partition_idx); - auto &partition = input.local_state.partition_info.partition_data[partition_idx]; - D_ASSERT(Value::NotDistinctFrom(partition.min_val, partition.max_val)); - partition_values.emplace_back(make_pair(std::move(column_name), partition.min_val)); - } - lstate.current_partition = Value::STRUCT(std::move(partition_values)); - - // initialize the state - auto &global_aggregate_state = gstate.GetOrCreatePartition(context.client, lstate.current_partition); - lstate.state = make_uniq(global_aggregate_state); - } - - // perform the aggregation - lstate.execute_state.Sink(*lstate.state, chunk); - return SinkResultType::NEED_MORE_INPUT; -} - -//===--------------------------------------------------------------------===// -// Next Batch -//===--------------------------------------------------------------------===// -SinkNextBatchType PhysicalPartitionedAggregate::NextBatch(ExecutionContext &context, - OperatorSinkNextBatchInput &input) const { - // flush the local state - auto &gstate = input.global_state.Cast(); - auto &lstate = input.local_state.Cast(); - - // finalize and reset the current state (if any) - gstate.Combine(context.client, lstate); - return SinkNextBatchType::READY; -} - -//===--------------------------------------------------------------------===// -// Combine -//===--------------------------------------------------------------------===// -SinkCombineResultType PhysicalPartitionedAggregate::Combine(ExecutionContext &context, - OperatorSinkCombineInput &input) const { - auto &gstate = input.global_state.Cast(); - auto &lstate = input.local_state.Cast(); - gstate.Combine(context.client, lstate); - return SinkCombineResultType::FINISHED; -} - -//===--------------------------------------------------------------------===// -// Finalize -//===--------------------------------------------------------------------===// -SinkFinalizeType PhysicalPartitionedAggregate::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, - OperatorSinkFinalizeInput &input) const { - auto &gstate = input.global_state.Cast(); - ColumnDataAppendState append_state; - gstate.aggregate_result.InitializeAppend(append_state); - // finalize each of the partitions and append to a ColumnDataCollection - DataChunk chunk; - chunk.Initialize(context, types); - for (auto &entry : gstate.aggregate_states) { - chunk.Reset(); - // reference the partitions - auto &partitions = StructValue::GetChildren(entry.first); - for (idx_t partition_idx = 0; partition_idx < partitions.size(); partition_idx++) { - chunk.data[partition_idx].Reference(partitions[partition_idx]); - } - // finalize the aggregates - entry.second->Finalize(chunk, partitions.size()); - - // append to the CDC - gstate.aggregate_result.Append(append_state, chunk); - } - return SinkFinalizeType::READY; -} - -//===--------------------------------------------------------------------===// -// Source -//===--------------------------------------------------------------------===// -class PartitionedAggregateGlobalSourceState : public GlobalSourceState { -public: - explicit PartitionedAggregateGlobalSourceState(PartitionedAggregateGlobalSinkState &gstate) { - gstate.aggregate_result.InitializeScan(scan_state); - } - - ColumnDataScanState scan_state; - - idx_t MaxThreads() override { - return 1; - } -}; - -unique_ptr PhysicalPartitionedAggregate::GetGlobalSourceState(ClientContext &context) const { - auto &gstate = sink_state->Cast(); - return make_uniq(gstate); -} - -SourceResultType PhysicalPartitionedAggregate::GetData(ExecutionContext &context, DataChunk &chunk, - OperatorSourceInput &input) const { - auto &gstate = sink_state->Cast(); - auto &gsource = input.global_state.Cast(); - gstate.aggregate_result.Scan(gsource.scan_state, chunk); - return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; -} - -//===--------------------------------------------------------------------===// -// ParamsToString -//===--------------------------------------------------------------------===// -InsertionOrderPreservingMap PhysicalPartitionedAggregate::ParamsToString() const { - InsertionOrderPreservingMap result; - string groups_info; - for (idx_t i = 0; i < groups.size(); i++) { - if (i > 0) { - groups_info += "\n"; - } - groups_info += groups[i]->GetName(); - } - result["Groups"] = groups_info; - string aggregate_info; - for (idx_t i = 0; i < aggregates.size(); i++) { - auto &aggregate = aggregates[i]->Cast(); - if (i > 0) { - aggregate_info += "\n"; - } - aggregate_info += aggregates[i]->GetName(); - if (aggregate.filter) { - aggregate_info += " Filter: " + aggregate.filter->GetName(); - } - } - result["Aggregates"] = aggregate_info; - return result; -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp index d00b6fd9e..778e5e676 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp @@ -29,7 +29,7 @@ PhysicalPerfectHashAggregate::PhysicalPerfectHashAggregate(ClientContext &contex vector bindings; vector payload_types_filters; for (auto &expr : aggregates) { - D_ASSERT(expr->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_AGGREGATE); D_ASSERT(expr->IsAggregate()); auto &aggr = expr->Cast(); bindings.push_back(&aggr); @@ -122,7 +122,7 @@ SinkResultType PhysicalPerfectHashAggregate::Sink(ExecutionContext &context, Dat for (idx_t group_idx = 0; group_idx < groups.size(); group_idx++) { auto &group = groups[group_idx]; - D_ASSERT(group->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(group->type == ExpressionType::BOUND_REF); auto &bound_ref_expr = group->Cast(); group_chunk.data[group_idx].Reference(chunk.data[bound_ref_expr.index]); } @@ -130,7 +130,7 @@ SinkResultType PhysicalPerfectHashAggregate::Sink(ExecutionContext &context, Dat for (auto &aggregate : aggregates) { auto &aggr = aggregate->Cast(); for (auto &child_expr : aggr.children) { - D_ASSERT(child_expr->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(child_expr->type == ExpressionType::BOUND_REF); auto &bound_ref_expr = child_expr->Cast(); aggregate_input_chunk.data[aggregate_input_idx++].Reference(chunk.data[bound_ref_expr.index]); } diff --git a/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp b/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp index 8d78e6653..903247e7d 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_streaming_window.cpp @@ -129,7 +129,7 @@ class StreamingWindowState : public OperatorState { } // We can only support LEAD and LAG values within one standard vector - if (wexpr.GetExpressionType() == ExpressionType::WINDOW_LEAD) { + if (wexpr.type == ExpressionType::WINDOW_LEAD) { offset = -offset; } return idx_t(std::abs(offset)) < MAX_BUFFER; @@ -332,11 +332,11 @@ class StreamingWindowState : public OperatorState { bool PhysicalStreamingWindow::IsStreamingFunction(ClientContext &context, unique_ptr &expr) { auto &wexpr = expr->Cast(); - if (!wexpr.partitions.empty() || !wexpr.orders.empty() || wexpr.ignore_nulls || !wexpr.arg_orders.empty() || + if (!wexpr.partitions.empty() || !wexpr.orders.empty() || wexpr.ignore_nulls || wexpr.exclude_clause != WindowExcludeMode::NO_OTHER) { return false; } - switch (wexpr.GetExpressionType()) { + switch (wexpr.type) { // TODO: add more expression types here? case ExpressionType::WINDOW_AGGREGATE: // We can stream aggregates if they are "running totals" diff --git a/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp b/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp index 0ec4bd2a3..f44b2476c 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp @@ -142,75 +142,6 @@ void GlobalUngroupedAggregateState::CombineDistinct(LocalUngroupedAggregateState } } -//===--------------------------------------------------------------------===// -// Ungrouped Aggregate Execute State -//===--------------------------------------------------------------------===// -UngroupedAggregateExecuteState::UngroupedAggregateExecuteState(ClientContext &context, - const vector> &aggregates, - const vector &child_types) - : aggregates(aggregates), child_executor(context), aggregate_input_chunk(), filter_set() { - vector payload_types; - vector aggregate_objects; - auto &allocator = BufferAllocator::Get(context); - for (auto &aggregate : aggregates) { - D_ASSERT(aggregate->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); - auto &aggr = aggregate->Cast(); - // initialize the payload chunk - for (auto &child : aggr.children) { - payload_types.push_back(child->return_type); - child_executor.AddExpression(*child); - } - aggregate_objects.emplace_back(&aggr); - } - if (!payload_types.empty()) { // for select count(*) from t; there is no payload at all - aggregate_input_chunk.Initialize(allocator, payload_types); - } - filter_set.Initialize(context, aggregate_objects, child_types); -} - -void UngroupedAggregateExecuteState::Reset() { - aggregate_input_chunk.Reset(); -} - -void UngroupedAggregateExecuteState::Sink(LocalUngroupedAggregateState &state, DataChunk &input) { - DataChunk &payload_chunk = aggregate_input_chunk; - - idx_t payload_idx = 0; - idx_t next_payload_idx = 0; - - for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) { - auto &aggregate = aggregates[aggr_idx]->Cast(); - - payload_idx = next_payload_idx; - next_payload_idx = payload_idx + aggregate.children.size(); - - if (aggregate.IsDistinct()) { - continue; - } - - idx_t payload_cnt = 0; - // resolve the filter (if any) - if (aggregate.filter) { - auto &filtered_data = filter_set.GetFilterData(aggr_idx); - auto count = filtered_data.ApplyFilter(input); - - child_executor.SetChunk(filtered_data.filtered_payload); - payload_chunk.SetCardinality(count); - } else { - child_executor.SetChunk(input); - payload_chunk.SetCardinality(input); - } - - // resolve the child expressions of the aggregate (if any) - for (idx_t i = 0; i < aggregate.children.size(); ++i) { - child_executor.ExecuteExpression(payload_idx + payload_cnt, payload_chunk.data[payload_idx + payload_cnt]); - payload_cnt++; - } - - state.Sink(payload_chunk, payload_idx, aggr_idx); - } -} - //===--------------------------------------------------------------------===// // Local State //===--------------------------------------------------------------------===// @@ -222,19 +153,45 @@ class UngroupedAggregateLocalSinkState : public LocalSinkState { public: UngroupedAggregateLocalSinkState(const PhysicalUngroupedAggregate &op, const vector &child_types, UngroupedAggregateGlobalSinkState &gstate_p, ExecutionContext &context) - : state(gstate_p.state), execute_state(context.client, op.aggregates, child_types) { + : state(gstate_p.state), child_executor(context.client), aggregate_input_chunk(), filter_set() { auto &gstate = gstate_p.Cast(); + + auto &allocator = BufferAllocator::Get(context.client); InitializeDistinctAggregates(op, gstate, context); + + vector payload_types; + vector aggregate_objects; + for (auto &aggregate : op.aggregates) { + D_ASSERT(aggregate->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); + auto &aggr = aggregate->Cast(); + // initialize the payload chunk + for (auto &child : aggr.children) { + payload_types.push_back(child->return_type); + child_executor.AddExpression(*child); + } + aggregate_objects.emplace_back(&aggr); + } + if (!payload_types.empty()) { // for select count(*) from t; there is no payload at all + aggregate_input_chunk.Initialize(allocator, payload_types); + } + filter_set.Initialize(context.client, aggregate_objects, child_types); } //! The local aggregate state LocalUngroupedAggregateState state; - //! The ungrouped aggregate execute state - UngroupedAggregateExecuteState execute_state; + //! The executor + ExpressionExecutor child_executor; + //! The payload chunk, containing all the Vectors for the aggregates + DataChunk aggregate_input_chunk; + //! Aggregate filter data set + AggregateFilterDataSet filter_set; //! The local sink states of the distinct aggregates hash tables vector> radix_states; public: + void Reset() { + aggregate_input_chunk.Reset(); + } void InitializeDistinctAggregates(const PhysicalUngroupedAggregate &op, const UngroupedAggregateGlobalSinkState &gstate, ExecutionContext &context) { @@ -317,7 +274,7 @@ void PhysicalUngroupedAggregate::SinkDistinct(ExecutionContext &context, DataChu // And in our case, we need to filter the groups (the distinct aggr children) // Apply the filter before inserting into the hashtable - auto &filtered_data = sink.execute_state.filter_set.GetFilterData(idx); + auto &filtered_data = sink.filter_set.GetFilterData(idx); idx_t count = filtered_data.ApplyFilter(chunk); filtered_data.filtered_payload.SetCardinality(count); @@ -333,13 +290,49 @@ SinkResultType PhysicalUngroupedAggregate::Sink(ExecutionContext &context, DataC auto &sink = input.local_state.Cast(); // perform the aggregation inside the local state - sink.execute_state.Reset(); + sink.Reset(); if (distinct_data) { SinkDistinct(context, chunk, input); } - sink.execute_state.Sink(sink.state, chunk); + DataChunk &payload_chunk = sink.aggregate_input_chunk; + + idx_t payload_idx = 0; + idx_t next_payload_idx = 0; + + for (idx_t aggr_idx = 0; aggr_idx < aggregates.size(); aggr_idx++) { + auto &aggregate = aggregates[aggr_idx]->Cast(); + + payload_idx = next_payload_idx; + next_payload_idx = payload_idx + aggregate.children.size(); + + if (aggregate.IsDistinct()) { + continue; + } + + idx_t payload_cnt = 0; + // resolve the filter (if any) + if (aggregate.filter) { + auto &filtered_data = sink.filter_set.GetFilterData(aggr_idx); + auto count = filtered_data.ApplyFilter(chunk); + + sink.child_executor.SetChunk(filtered_data.filtered_payload); + payload_chunk.SetCardinality(count); + } else { + sink.child_executor.SetChunk(chunk); + payload_chunk.SetCardinality(chunk); + } + + // resolve the child expressions of the aggregate (if any) + for (idx_t i = 0; i < aggregate.children.size(); ++i) { + sink.child_executor.ExecuteExpression(payload_idx + payload_cnt, + payload_chunk.data[payload_idx + payload_cnt]); + payload_cnt++; + } + + sink.state.Sink(payload_chunk, payload_idx, aggr_idx); + } return SinkResultType::NEED_MORE_INPUT; } @@ -632,14 +625,14 @@ void VerifyNullHandling(DataChunk &chunk, UngroupedAggregateState &state, #endif } -void GlobalUngroupedAggregateState::Finalize(DataChunk &result, idx_t column_offset) { +void GlobalUngroupedAggregateState::Finalize(DataChunk &result) { result.SetCardinality(1); for (idx_t aggr_idx = 0; aggr_idx < state.aggregate_expressions.size(); aggr_idx++) { auto &aggregate = state.aggregate_expressions[aggr_idx]->Cast(); Vector state_vector(Value::POINTER(CastPointerToValue(state.aggregate_data[aggr_idx].get()))); AggregateInputData aggr_input_data(aggregate.bind_info.get(), allocator); - aggregate.function.finalize(state_vector, aggr_input_data, result.data[column_offset + aggr_idx], 1, 0); + aggregate.function.finalize(state_vector, aggr_input_data, result.data[aggr_idx], 1, 0); } } diff --git a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp index 8b8b2a162..e9bf471d7 100644 --- a/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +++ b/src/duckdb/src/execution/operator/aggregate/physical_window.cpp @@ -1,14 +1,30 @@ #include "duckdb/execution/operator/aggregate/physical_window.hpp" +#include "duckdb/common/operator/add.hpp" +#include "duckdb/common/operator/cast_operators.hpp" +#include "duckdb/common/operator/comparison_operators.hpp" +#include "duckdb/common/operator/subtract.hpp" +#include "duckdb/common/optional_ptr.hpp" +#include "duckdb/common/radix_partitioning.hpp" +#include "duckdb/common/row_operations/row_operations.hpp" #include "duckdb/common/sort/partition_state.hpp" -#include "duckdb/function/window/window_aggregate_function.hpp" -#include "duckdb/function/window/window_executor.hpp" -#include "duckdb/function/window/window_rank_function.hpp" -#include "duckdb/function/window/window_rownumber_function.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/function/window/window_value_function.hpp" + +#include "duckdb/common/types/column/column_data_consumer.hpp" +#include "duckdb/common/types/row/row_data_collection_scanner.hpp" +#include "duckdb/common/uhugeint.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/common/windows_undefs.hpp" +#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/execution/window_executor.hpp" +#include "duckdb/execution/window_segment_tree.hpp" +#include "duckdb/main/client_config.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/parallel/base_pipeline_event.hpp" +#include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression/bound_window_expression.hpp" -// + +#include +#include #include namespace duckdb { @@ -86,8 +102,6 @@ class WindowHashGroup { ValidityMask partition_mask; //! The order boundary mask OrderMasks order_masks; - //! The fully materialised data collection - unique_ptr collection; //! External paging bool external; // The processing stage for this group @@ -131,8 +145,6 @@ class WindowGlobalSinkState : public GlobalSinkState { unique_ptr global_partition; //! The execution functions Executors executors; - //! The shared expressions library - WindowSharedExpressions shared; }; class WindowPartitionGlobalSinkState : public PartitionGlobalSinkState { @@ -189,7 +201,7 @@ PhysicalWindow::PhysicalWindow(vector types, vectorGetExpressionClass() == ExpressionClass::BOUND_WINDOW); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_WINDOW); auto &bound_window = expr->Cast(); if (bound_window.partitions.empty() && bound_window.orders.empty()) { is_order_dependent = true; @@ -203,34 +215,34 @@ PhysicalWindow::PhysicalWindow(vector types, vector WindowExecutorFactory(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared, WindowAggregationMode mode) { - switch (wexpr.GetExpressionType()) { + WindowAggregationMode mode) { + switch (wexpr.type) { case ExpressionType::WINDOW_AGGREGATE: - return make_uniq(wexpr, context, shared, mode); + return make_uniq(wexpr, context, mode); case ExpressionType::WINDOW_ROW_NUMBER: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_RANK_DENSE: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_RANK: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_PERCENT_RANK: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_CUME_DIST: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_NTILE: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_LEAD: case ExpressionType::WINDOW_LAG: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_FIRST_VALUE: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_LAST_VALUE: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); case ExpressionType::WINDOW_NTH_VALUE: - return make_uniq(wexpr, context, shared); + return make_uniq(wexpr, context); break; default: - throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.GetExpressionType())); + throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.type)); } } @@ -244,7 +256,7 @@ WindowGlobalSinkState::WindowGlobalSinkState(const PhysicalWindow &op, ClientCon for (idx_t expr_idx = 0; expr_idx < op.select_list.size(); ++expr_idx) { D_ASSERT(op.select_list[expr_idx]->GetExpressionClass() == ExpressionClass::BOUND_WINDOW); auto &wexpr = op.select_list[expr_idx]->Cast(); - auto wexec = WindowExecutorFactory(wexpr, context, shared, mode); + auto wexec = WindowExecutorFactory(wexpr, context, mode); executors.emplace_back(std::move(wexec)); } @@ -556,15 +568,6 @@ WindowHashGroup::WindowHashGroup(WindowGlobalSinkState &gstate, const idx_t hash if (rows) { blocks = rows->blocks.size(); } - - // Set up the collection for any fully materialised data - const auto &shared = WindowSharedExpressions::GetSortedExpressions(gstate.shared.coll_shared); - vector types; - for (auto &expr : shared) { - types.emplace_back(expr->return_type); - } - auto &buffer_manager = BufferManager::GetBufferManager(gstate.context); - collection = make_uniq(buffer_manager, count, types); } // Per-thread scan state @@ -603,19 +606,6 @@ class WindowLocalSourceState : public LocalSourceState { void Sink(); void Finalize(); void GetData(DataChunk &chunk); - - //! Storage and evaluation for the fully materialised data - unique_ptr builder; - ExpressionExecutor coll_exec; - DataChunk coll_chunk; - - //! Storage and evaluation for chunks used in the sink/build phase - ExpressionExecutor sink_exec; - DataChunk sink_chunk; - - //! Storage and evaluation for chunks used in the evaluate phase - ExpressionExecutor eval_exec; - DataChunk eval_chunk; }; WindowHashGroup::ExecutorGlobalStates &WindowHashGroup::Initialize(WindowGlobalSinkState &gsink) { @@ -670,30 +660,8 @@ void WindowLocalSourceState::Sink() { break; } - // Compute fully materialised expressions - if (coll_chunk.data.empty()) { - coll_chunk.SetCardinality(input_chunk); - } else { - coll_chunk.Reset(); - coll_exec.Execute(input_chunk, coll_chunk); - auto collection = window_hash_group->collection.get(); - if (!builder || &builder->collection != collection) { - builder = make_uniq(*collection); - } - - builder->Sink(coll_chunk, input_idx); - } - - // Compute sink expressions - if (sink_chunk.data.empty()) { - sink_chunk.SetCardinality(input_chunk); - } else { - sink_chunk.Reset(); - sink_exec.Execute(input_chunk, sink_chunk); - } - for (idx_t w = 0; w < executors.size(); ++w) { - executors[w]->Sink(sink_chunk, coll_chunk, input_idx, *gestates[w], *local_states[w]); + executors[w]->Sink(input_chunk, input_idx, window_hash_group->count, *gestates[w], *local_states[w]); } window_hash_group->sunk += input_chunk.size(); @@ -709,20 +677,15 @@ void WindowLocalSourceState::Finalize() { D_ASSERT(task); D_ASSERT(task->stage == WindowGroupStage::FINALIZE); - // First finalize the collection (so the executors can use it) - auto &gsink = gsource.gsink; - if (window_hash_group->collection) { - window_hash_group->collection->Combine(gsink.shared.coll_validity); - } - // Finalize all the executors. // Parallel finalisation is handled internally by the executor, // and should not return until all threads have completed work. + auto &gsink = gsource.gsink; const auto &executors = gsink.executors; auto &gestates = window_hash_group->gestates; auto &local_states = window_hash_group->thread_states.at(task->thread_idx); for (idx_t w = 0; w < executors.size(); ++w) { - executors[w]->Finalize(*gestates[w], *local_states[w], window_hash_group->collection); + executors[w]->Finalize(*gestates[w], *local_states[w]); } // Mark this range as done @@ -730,9 +693,7 @@ void WindowLocalSourceState::Finalize() { task->begin_idx = task->end_idx; } -WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) - : gsource(gsource), batch_index(0), coll_exec(gsource.context), sink_exec(gsource.context), - eval_exec(gsource.context) { +WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) : gsource(gsource), batch_index(0) { auto &gsink = gsource.gsink; auto &global_partition = *gsink.global_partition; @@ -745,11 +706,6 @@ WindowLocalSourceState::WindowLocalSourceState(WindowGlobalSourceState &gsource) } output_chunk.Initialize(global_partition.allocator, output_types); - auto &shared = gsink.shared; - shared.PrepareCollection(coll_exec, coll_chunk); - shared.PrepareSink(sink_exec, sink_chunk); - shared.PrepareEvaluate(eval_exec, eval_chunk); - ++gsource.locals; } @@ -863,13 +819,7 @@ void WindowLocalSourceState::GetData(DataChunk &result) { auto &gstate = *gestates[expr_idx]; auto &lstate = *local_states[expr_idx]; auto &result = output_chunk.data[expr_idx]; - if (eval_chunk.data.empty()) { - eval_chunk.SetCardinality(input_chunk); - } else { - eval_chunk.Reset(); - eval_exec.Execute(input_chunk, eval_chunk); - } - executor.Evaluate(position, eval_chunk, result, lstate, gstate); + executor.Evaluate(position, input_chunk, result, lstate, gstate); } output_chunk.SetCardinality(input_chunk); output_chunk.Verify(); @@ -906,10 +856,7 @@ unique_ptr PhysicalWindow::GetGlobalSourceState(ClientContext return make_uniq(context, gsink); } -bool PhysicalWindow::SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { - if (partition_info.RequiresPartitionColumns()) { - return false; - } +bool PhysicalWindow::SupportsBatchIndex() const { // We can only preserve order for single partitioning // or work stealing causes out of order batch numbers auto &wexpr = select_list[order_idx]->Cast(); @@ -931,30 +878,19 @@ OrderPreservationType PhysicalWindow::SourceOrder() const { return OrderPreservationType::FIXED_ORDER; } -ProgressData PhysicalWindow::GetProgress(ClientContext &context, GlobalSourceState &gsource_p) const { +double PhysicalWindow::GetProgress(ClientContext &context, GlobalSourceState &gsource_p) const { auto &gsource = gsource_p.Cast(); const auto returned = gsource.returned.load(); auto &gsink = gsource.gsink; const auto count = gsink.global_partition->count.load(); - ProgressData res; - if (count) { - res.done = double(returned); - res.total = double(count); - } else { - res.SetInvalid(); - } - return res; + return count ? (double(returned) / double(count)) : -1; } -OperatorPartitionData PhysicalWindow::GetPartitionData(ExecutionContext &context, DataChunk &chunk, - GlobalSourceState &gstate_p, LocalSourceState &lstate_p, - const OperatorPartitionInfo &partition_info) const { - if (partition_info.RequiresPartitionColumns()) { - throw InternalException("PhysicalWindow::GetPartitionData: partition columns not supported"); - } +idx_t PhysicalWindow::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, + LocalSourceState &lstate_p) const { auto &lstate = lstate_p.Cast(); - return OperatorPartitionData(lstate.batch_index); + return lstate.batch_index; } SourceResultType PhysicalWindow::GetData(ExecutionContext &context, DataChunk &chunk, diff --git a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp index c18c5f61e..3677e0a75 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer.cpp @@ -58,7 +58,7 @@ void CSVBuffer::AllocateBuffer(idx_t buffer_size) { block = handle.GetBlockHandle(); } -idx_t CSVBuffer::GetBufferSize() const { +idx_t CSVBuffer::GetBufferSize() { return actual_buffer_size; } @@ -87,7 +87,7 @@ void CSVBuffer::Unpin() { } } -bool CSVBuffer::IsCSVFileLastBuffer() const { +bool CSVBuffer::IsCSVFileLastBuffer() { return last_buffer; } diff --git a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp index 811689917..064595f3c 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_buffer_manager.cpp @@ -4,18 +4,20 @@ namespace duckdb { CSVBufferManager::CSVBufferManager(ClientContext &context_p, const CSVReaderOptions &options, const string &file_path_p, - const idx_t file_idx_p, bool per_file_single_threaded_p, - unique_ptr file_handle_p) + const idx_t file_idx_p, bool per_file_single_threaded_p) : context(context_p), per_file_single_threaded(per_file_single_threaded_p), file_idx(file_idx_p), - file_path(file_path_p), buffer_size(options.buffer_size_option.GetValue()) { + file_path(file_path_p), buffer_size(CSVBuffer::CSV_BUFFER_SIZE) { D_ASSERT(!file_path.empty()); - if (file_handle_p) { - file_handle = std::move(file_handle_p); - } else { - file_handle = ReadCSV::OpenCSV(file_path, options, context); - } + file_handle = ReadCSV::OpenCSV(file_path, options.compression, context); is_pipe = file_handle->IsPipe(); skip_rows = options.dialect_options.skip_rows.GetValue(); + auto file_size = file_handle->FileSize(); + if (file_size > 0 && file_size < buffer_size) { + buffer_size = CSVBuffer::CSV_MINIMUM_BUFFER_SIZE; + } + if (options.buffer_size < buffer_size) { + buffer_size = options.buffer_size; + } Initialize(); } @@ -146,15 +148,4 @@ string CSVBufferManager::GetFilePath() const { return file_path; } -bool CSVBufferManager::IsBlockUnloaded(idx_t block_idx) { - if (block_idx < cached_buffers.size()) { - return cached_buffers[block_idx]->IsUnloaded(); - } - return false; -} - -idx_t CSVBufferManager::GetBytesRead() const { - return bytes_read; -} - } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_file_handle.cpp b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_file_handle.cpp index 73fbb4ed0..e8b502fb2 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_file_handle.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/buffer_manager/csv_file_handle.cpp @@ -3,14 +3,12 @@ #include "duckdb/common/numeric_utils.hpp" #include "duckdb/common/compressed_file_system.hpp" #include "duckdb/common/string_util.hpp" -#include "duckdb/execution/operator/csv_scanner/csv_reader_options.hpp" namespace duckdb { -CSVFileHandle::CSVFileHandle(DBConfig &config, unique_ptr file_handle_p, const string &path_p, - const CSVReaderOptions &options) - : compression_type(options.compression), file_handle(std::move(file_handle_p)), - encoder(config, options.encoding, options.buffer_size_option.GetValue()), path(path_p) { +CSVFileHandle::CSVFileHandle(FileSystem &fs, Allocator &allocator, unique_ptr file_handle_p, + const string &path_p, FileCompressionType compression) + : compression_type(compression), file_handle(std::move(file_handle_p)), path(path_p) { can_seek = file_handle->CanSeek(); on_disk_file = file_handle->OnDiskFile(); file_size = file_handle->GetFileSize(); @@ -27,21 +25,21 @@ unique_ptr CSVFileHandle::OpenFileHandle(FileSystem &fs, Allocator & return file_handle; } -unique_ptr CSVFileHandle::OpenFile(DBConfig &config, FileSystem &fs, Allocator &allocator, - const string &path, const CSVReaderOptions &options) { - auto file_handle = OpenFileHandle(fs, allocator, path, options.compression); - return make_uniq(config, std::move(file_handle), path, options); +unique_ptr CSVFileHandle::OpenFile(FileSystem &fs, Allocator &allocator, const string &path, + FileCompressionType compression) { + auto file_handle = CSVFileHandle::OpenFileHandle(fs, allocator, path, compression); + return make_uniq(fs, allocator, std::move(file_handle), path, compression); } -double CSVFileHandle::GetProgress() const { +double CSVFileHandle::GetProgress() { return static_cast(file_handle->GetProgress()); } -bool CSVFileHandle::CanSeek() const { +bool CSVFileHandle::CanSeek() { return can_seek; } -void CSVFileHandle::Seek(const idx_t position) const { +void CSVFileHandle::Seek(idx_t position) { if (!can_seek) { if (is_pipe) { throw InternalException("Trying to seek a piped CSV File."); @@ -51,7 +49,7 @@ void CSVFileHandle::Seek(const idx_t position) const { file_handle->Seek(position); } -bool CSVFileHandle::OnDiskFile() const { +bool CSVFileHandle::OnDiskFile() { return on_disk_file; } @@ -61,27 +59,22 @@ void CSVFileHandle::Reset() { requested_bytes = 0; } -bool CSVFileHandle::IsPipe() const { +bool CSVFileHandle::IsPipe() { return is_pipe; } -idx_t CSVFileHandle::FileSize() const { +idx_t CSVFileHandle::FileSize() { return file_size; } -bool CSVFileHandle::FinishedReading() const { +bool CSVFileHandle::FinishedReading() { return finished; } idx_t CSVFileHandle::Read(void *buffer, idx_t nr_bytes) { requested_bytes += nr_bytes; // if this is a plain file source OR we can seek we are not caching anything - idx_t bytes_read = 0; - if (encoder.encoding_name == "utf-8") { - bytes_read = static_cast(file_handle->Read(buffer, nr_bytes)); - } else { - bytes_read = encoder.Encode(*file_handle, static_cast(buffer), nr_bytes); - } + auto bytes_read = file_handle->Read(buffer, nr_bytes); if (!finished) { finished = bytes_read == 0; } diff --git a/src/duckdb/src/execution/operator/csv_scanner/encode/csv_encoder.cpp b/src/duckdb/src/execution/operator/csv_scanner/encode/csv_encoder.cpp deleted file mode 100644 index 89fc5df04..000000000 --- a/src/duckdb/src/execution/operator/csv_scanner/encode/csv_encoder.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp" -#include "duckdb/common/exception.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/function/encoding_function.hpp" - -namespace duckdb { - -void CSVEncoderBuffer::Initialize(idx_t encoded_size) { - encoded_buffer_size = encoded_size; - encoded_buffer = std::unique_ptr(new char[encoded_size]); -} - -char *CSVEncoderBuffer::Ptr() const { - return encoded_buffer.get(); -} - -idx_t CSVEncoderBuffer::GetCapacity() const { - return encoded_buffer_size; -} - -idx_t CSVEncoderBuffer::GetSize() const { - return actual_encoded_buffer_size; -} - -void CSVEncoderBuffer::SetSize(const idx_t buffer_size) { - D_ASSERT(buffer_size <= encoded_buffer_size); - actual_encoded_buffer_size = buffer_size; -} - -bool CSVEncoderBuffer::HasDataToRead() const { - return cur_pos < actual_encoded_buffer_size; -} - -void CSVEncoderBuffer::Reset() { - cur_pos = 0; - actual_encoded_buffer_size = 0; -} - -CSVEncoder::CSVEncoder(DBConfig &config, const string &encoding_name_to_find, idx_t buffer_size) { - encoding_name = StringUtil::Lower(encoding_name_to_find); - auto function = config.GetEncodeFunction(encoding_name_to_find); - if (!function) { - auto loaded_encodings = config.GetLoadedEncodedFunctions(); - std::ostringstream error; - error << "The CSV Reader does not support the encoding: \"" << encoding_name_to_find << "\"\n"; - error << "The currently supported encodings are: " << '\n'; - for (auto &encoding_function : loaded_encodings) { - error << "* " << encoding_function.get().GetType() << '\n'; - } - throw InvalidInputException(error.str()); - } - // We ensure that the encoded buffer size is an even number to make the two byte lookup on utf-16 work - idx_t encoded_buffer_size = buffer_size % 2 != 0 ? buffer_size - 1 : buffer_size; - D_ASSERT(encoded_buffer_size > 0); - encoded_buffer.Initialize(encoded_buffer_size); - remaining_bytes_buffer.Initialize(function->GetBytesPerIteration()); - encoding_function = function; -} - -idx_t CSVEncoder::Encode(FileHandle &file_handle_input, char *output_buffer, const idx_t decoded_buffer_size) { - idx_t output_buffer_pos = 0; - // Check if we have some left-overs. These can either be - // 1. missing decoded bytes - if (remaining_bytes_buffer.HasDataToRead()) { - D_ASSERT(remaining_bytes_buffer.cur_pos == 0); - const auto remaining_bytes_buffer_ptr = remaining_bytes_buffer.Ptr(); - for (; remaining_bytes_buffer.cur_pos < remaining_bytes_buffer.GetSize(); remaining_bytes_buffer.cur_pos++) { - output_buffer[output_buffer_pos++] = remaining_bytes_buffer_ptr[remaining_bytes_buffer.cur_pos]; - } - remaining_bytes_buffer.Reset(); - } - // 2. remaining encoded buffer - if (encoded_buffer.HasDataToRead()) { - encoding_function->GetFunction()( - encoded_buffer.Ptr(), encoded_buffer.cur_pos, encoded_buffer.GetSize(), output_buffer, output_buffer_pos, - decoded_buffer_size, remaining_bytes_buffer.Ptr(), remaining_bytes_buffer.actual_encoded_buffer_size); - } - // 3. a new encoded buffer from the file - while (output_buffer_pos < decoded_buffer_size) { - idx_t current_decoded_buffer_start = output_buffer_pos; - encoded_buffer.Reset(); - auto actual_encoded_bytes = - static_cast(file_handle_input.Read(encoded_buffer.Ptr(), encoded_buffer.GetCapacity())); - encoded_buffer.SetSize(actual_encoded_bytes); - encoding_function->GetFunction()( - encoded_buffer.Ptr(), encoded_buffer.cur_pos, encoded_buffer.GetSize(), output_buffer, output_buffer_pos, - decoded_buffer_size, remaining_bytes_buffer.Ptr(), remaining_bytes_buffer.actual_encoded_buffer_size); - if (output_buffer_pos == current_decoded_buffer_start) { - return output_buffer_pos; - } - } - return output_buffer_pos; -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/scanner/csv_schema.cpp b/src/duckdb/src/execution/operator/csv_scanner/scanner/csv_schema.cpp index f99e46a9a..139398d71 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/scanner/csv_schema.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/scanner/csv_schema.cpp @@ -43,46 +43,7 @@ bool CSVSchema::CanWeCastIt(LogicalTypeId source, LogicalTypeId destination) { } } -void CSVSchema::MergeSchemas(CSVSchema &other, bool null_padding) { - // TODO: We could also merge names, maybe by giving preference to non-generated names? - const vector candidates_by_specificity = {LogicalType::BOOLEAN, LogicalType::BIGINT, - LogicalType::DOUBLE, LogicalType::VARCHAR}; - for (idx_t i = 0; i < columns.size() && i < other.columns.size(); i++) { - auto this_type = columns[i].type.id(); - auto other_type = other.columns[i].type.id(); - if (columns[i].type != other.columns[i].type) { - if (CanWeCastIt(this_type, other_type)) { - // If we can cast this to other, this becomes other - columns[i].type = other.columns[i].type; - } else if (!CanWeCastIt(other_type, this_type)) { - // If we can't cast this to other or other to this, we see which parent they can be both cast to - for (const auto &type : candidates_by_specificity) { - if (CanWeCastIt(this_type, type.id()) && CanWeCastIt(other_type, type.id())) { - columns[i].type = type; - break; - } - } - } - } - } - - if (null_padding && other.columns.size() > columns.size()) { - for (idx_t i = columns.size(); i < other.columns.size(); i++) { - auto name = other.columns[i].name; - auto type = other.columns[i].type; - columns.push_back({name, type}); - name_idx_map[name] = i; - } - } -} - -CSVSchema::CSVSchema(vector &names, vector &types, const string &file_path, idx_t rows_read_p, - const bool empty_p) - : rows_read(rows_read_p), empty(empty_p) { - Initialize(names, types, file_path); -} - -void CSVSchema::Initialize(const vector &names, const vector &types, const string &file_path_p) { +void CSVSchema::Initialize(vector &names, vector &types, const string &file_path_p) { if (!columns.empty()) { throw InternalException("CSV Schema is already populated, this should not happen."); } @@ -90,49 +51,15 @@ void CSVSchema::Initialize(const vector &names, const vector CSVSchema::GetNames() const { - vector names; - for (auto &column : columns) { - names.push_back(column.name); - } - return names; -} - -vector CSVSchema::GetTypes() const { - vector types; - for (auto &column : columns) { - types.push_back(column.type); - } - return types; -} - bool CSVSchema::Empty() const { return columns.empty(); } -bool CSVSchema::MatchColumns(const CSVSchema &other) const { - return other.columns.size() == columns.size() || empty || other.empty; -} - -string CSVSchema::GetPath() const { - return file_path; -} - -idx_t CSVSchema::GetColumnCount() const { - return columns.size(); -} - -idx_t CSVSchema::GetRowsRead() const { - return rows_read; -} - bool CSVSchema::SchemasMatch(string &error_message, SnifferResult &sniffer_result, const string &cur_file_path, bool is_minimal_sniffer) const { D_ASSERT(sniffer_result.names.size() == sniffer_result.return_types.size()); diff --git a/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp b/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp index b0511bec6..4ddd938bb 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/scanner/scanner_boundary.cpp @@ -16,7 +16,7 @@ CSVBoundary::CSVBoundary() : buffer_idx(0), buffer_pos(0), boundary_idx(0), end_ CSVIterator::CSVIterator() : is_set(false) { } -void CSVBoundary::Print() const { +void CSVBoundary::Print() { #ifndef DUCKDB_DISABLE_PRINT std::cout << "---Boundary: " << boundary_idx << " ---" << '\n'; std::cout << "Buffer Index: " << buffer_idx << '\n'; @@ -26,39 +26,26 @@ void CSVBoundary::Print() const { #endif } -void CSVIterator::Print() const { +void CSVIterator::Print() { #ifndef DUCKDB_DISABLE_PRINT boundary.Print(); std::cout << "Is set: " << is_set << '\n'; #endif } -idx_t CSVIterator::BytesPerThread(const CSVReaderOptions &reader_options) { - const idx_t buffer_size = reader_options.buffer_size_option.GetValue(); - const idx_t max_row_size = reader_options.maximum_line_size.GetValue(); - const idx_t bytes_per_thread = buffer_size / CSVBuffer::ROWS_PER_BUFFER * ROWS_PER_THREAD; - if (bytes_per_thread < max_row_size) { - // If we are setting up the buffer size directly, we must make sure each thread will read the full buffer. - return max_row_size; - } - return bytes_per_thread; -} - -bool CSVIterator::Next(CSVBufferManager &buffer_manager, const CSVReaderOptions &reader_options) { +bool CSVIterator::Next(CSVBufferManager &buffer_manager) { if (!is_set) { return false; } - const auto bytes_per_thread = BytesPerThread(reader_options); - // If we are calling next this is not the first one anymore first_one = false; boundary.boundary_idx++; // This is our start buffer auto buffer = buffer_manager.GetBuffer(boundary.buffer_idx); - if (buffer->is_last_buffer && boundary.buffer_pos + bytes_per_thread > buffer->actual_size) { + if (buffer->is_last_buffer && boundary.buffer_pos + CSVIterator::BYTES_PER_THREAD > buffer->actual_size) { // 1) We are done with the current file return false; - } else if (boundary.buffer_pos + bytes_per_thread >= buffer->actual_size) { + } else if (boundary.buffer_pos + BYTES_PER_THREAD >= buffer->actual_size) { // 2) We still have data to scan in this file, we set the iterator accordingly. // We must move the buffer boundary.buffer_idx++; @@ -71,9 +58,9 @@ bool CSVIterator::Next(CSVBufferManager &buffer_manager, const CSVReaderOptions } else { // 3) We are not done with the current buffer, hence we just move where we start within the buffer - boundary.buffer_pos += bytes_per_thread; + boundary.buffer_pos += BYTES_PER_THREAD; } - boundary.end_pos = boundary.buffer_pos + bytes_per_thread; + boundary.end_pos = boundary.buffer_pos + BYTES_PER_THREAD; SetCurrentPositionToBoundary(); return true; } @@ -98,21 +85,20 @@ void CSVIterator::SetCurrentPositionToBoundary() { pos.buffer_pos = boundary.buffer_pos; } -void CSVIterator::SetCurrentBoundaryToPosition(bool single_threaded, const CSVReaderOptions &reader_options) { +void CSVIterator::SetCurrentBoundaryToPosition(bool single_threaded) { if (single_threaded) { is_set = false; return; } - const auto bytes_per_thread = BytesPerThread(reader_options); - boundary.buffer_idx = pos.buffer_idx; if (pos.buffer_pos == 0) { - boundary.end_pos = bytes_per_thread; + boundary.end_pos = CSVIterator::BYTES_PER_THREAD; } else { - boundary.end_pos = ((pos.buffer_pos + bytes_per_thread - 1) / bytes_per_thread) * bytes_per_thread; + boundary.end_pos = ((pos.buffer_pos + CSVIterator::BYTES_PER_THREAD - 1) / CSVIterator::BYTES_PER_THREAD) * + CSVIterator::BYTES_PER_THREAD; } - boundary.buffer_pos = boundary.end_pos - bytes_per_thread; + boundary.buffer_pos = boundary.end_pos - CSVIterator::BYTES_PER_THREAD; is_set = true; } @@ -120,18 +106,4 @@ void CSVIterator::SetStart(idx_t start) { boundary.buffer_pos = start; } -void CSVIterator::SetEnd(idx_t pos) { - boundary.end_pos = pos; -} - -void CSVIterator::CheckIfDone() { - if (IsBoundarySet() && (pos.buffer_idx > boundary.buffer_idx || pos.buffer_pos > boundary.buffer_pos)) { - done = true; - } -} - -idx_t CSVIterator::GetGlobalCurrentPos() const { - return pos.buffer_pos + buffer_size * pos.buffer_idx; -} - } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp b/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp index c1ab79dfe..9662e849b 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/scanner/string_value_scanner.cpp @@ -14,22 +14,18 @@ #include namespace duckdb { - -constexpr idx_t StringValueScanner::LINE_FINDER_ID; - StringValueResult::StringValueResult(CSVStates &states, CSVStateMachine &state_machine, const shared_ptr &buffer_handle, Allocator &buffer_allocator, idx_t result_size_p, idx_t buffer_position, CSVErrorHandler &error_hander_p, CSVIterator &iterator_p, bool store_line_size_p, shared_ptr csv_file_scan_p, idx_t &lines_read_p, bool sniffing_p, - string path_p, idx_t scan_id) + string path_p) : ScannerResult(states, state_machine, result_size_p), number_of_columns(NumericCast(state_machine.dialect_options.num_cols)), null_padding(state_machine.options.null_padding), ignore_errors(state_machine.options.ignore_errors.GetValue()), - extra_delimiter_bytes(state_machine.dialect_options.state_machine_options.delimiter.GetValue().size() - 1), error_handler(error_hander_p), iterator(iterator_p), store_line_size(store_line_size_p), csv_file_scan(std::move(csv_file_scan_p)), lines_read(lines_read_p), - current_errors(scan_id, state_machine.options.IgnoreErrors()), sniffing(sniffing_p), path(std::move(path_p)) { + current_errors(state_machine.options.IgnoreErrors()), sniffing(sniffing_p), path(std::move(path_p)) { // Vector information D_ASSERT(number_of_columns > 0); if (!buffer_handle) { @@ -243,40 +239,31 @@ void StringValueResult::AddValueToVector(const char *value_ptr, const idx_t size return; } } - - if (((quoted && state_machine.options.allow_quoted_nulls) || !quoted)) { - // Check for the occurrence of escaped null string like \N only if RFC 4180 conformance is disabled - const bool check_unquoted_escaped_null = - state_machine.state_machine_options.rfc_4180.GetValue() == false && escaped && !quoted && size == 1; - for (idx_t i = 0; i < null_str_count; i++) { - bool is_null = false; - if (null_str_size[i] == 2 && null_str_ptr[i][0] == state_machine.state_machine_options.escape.GetValue()) { - is_null = check_unquoted_escaped_null && null_str_ptr[i][1] == value_ptr[0]; - } else if (size == null_str_size[i] && !check_unquoted_escaped_null) { - is_null = IsValueNull(null_str_ptr[i], value_ptr, size); - } - if (is_null) { - bool empty = false; - if (chunk_col_id < state_machine.options.force_not_null.size()) { - empty = state_machine.options.force_not_null[chunk_col_id]; - } - if (empty) { - if (parse_types[chunk_col_id].type_id != LogicalTypeId::VARCHAR) { - // If it is not a varchar, empty values are not accepted, we must error. - current_errors.Insert(CAST_ERROR, cur_col_id, chunk_col_id, last_position); - } else { - static_cast(vector_ptr[chunk_col_id])[number_of_rows] = string_t(); + for (idx_t i = 0; i < null_str_count; i++) { + if (size == null_str_size[i]) { + if (((quoted && state_machine.options.allow_quoted_nulls) || !quoted)) { + if (IsValueNull(null_str_ptr[i], value_ptr, size)) { + bool empty = false; + if (chunk_col_id < state_machine.options.force_not_null.size()) { + empty = state_machine.options.force_not_null[chunk_col_id]; } - } else { - if (chunk_col_id == number_of_columns) { - // We check for a weird case, where we ignore an extra value, if it is a null value - return; + if (empty) { + if (parse_types[chunk_col_id].type_id != LogicalTypeId::VARCHAR) { + // If it is not a varchar, empty values are not accepted, we must error. + current_errors.Insert(CAST_ERROR, cur_col_id, chunk_col_id, last_position); + } + static_cast(vector_ptr[chunk_col_id])[number_of_rows] = string_t(); + } else { + if (chunk_col_id == number_of_columns) { + // We check for a weird case, where we ignore an extra value, if it is a null value + return; + } + validity_mask[chunk_col_id]->SetInvalid(static_cast(number_of_rows)); } - validity_mask[chunk_col_id]->SetInvalid(static_cast(number_of_rows)); + cur_col_id++; + chunk_col_id++; + return; } - cur_col_id++; - chunk_col_id++; - return; } } } @@ -334,9 +321,8 @@ void StringValueResult::AddValueToVector(const char *value_ptr, const idx_t size } else { idx_t pos; bool special; - success = Date::TryConvertDate(value_ptr, size, pos, - static_cast(vector_ptr[chunk_col_id])[number_of_rows], special, - false) == DateCastResult::SUCCESS; + success = Date::TryConvertDate( + value_ptr, size, pos, static_cast(vector_ptr[chunk_col_id])[number_of_rows], special, false); } break; } @@ -427,7 +413,7 @@ void StringValueResult::AddValueToVector(const char *value_ptr, const idx_t size if (force_error) { HandleUnicodeError(cur_col_id, last_position); } - // If we got here, we are ignoring errors, hence we must ignore this line. + // If we got here, we are ingoring errors, hence we must ignore this line. current_errors.Insert(INVALID_UNICODE, cur_col_id, chunk_col_id, last_position); break; } @@ -493,25 +479,17 @@ void StringValueResult::Reset() { } void StringValueResult::AddQuotedValue(StringValueResult &result, const idx_t buffer_pos) { - if (!result.unquoted) { - result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, result.last_position); - } - AddPossiblyEscapedValue(result, buffer_pos, result.buffer_ptr + result.quoted_position + 1, - buffer_pos - result.quoted_position - 2, buffer_pos < result.last_position.buffer_pos + 2); - result.quoted = false; -} - -void StringValueResult::AddPossiblyEscapedValue(StringValueResult &result, const idx_t buffer_pos, - const char *value_ptr, const idx_t length, const bool empty) { if (result.escaped) { if (result.projecting_columns) { if (!result.projected_columns[result.cur_col_id]) { result.cur_col_id++; + result.quoted = false; result.escaped = false; return; } } - if (!result.HandleTooManyColumnsError(value_ptr, length)) { + if (!result.HandleTooManyColumnsError(result.buffer_ptr + result.quoted_position + 1, + buffer_pos - result.quoted_position - 2)) { // If it's an escaped value we have to remove all the escapes, this is not really great // If we are going to escape, this vector must be a varchar vector if (result.parse_chunk.data[result.chunk_col_id].GetType() != LogicalType::VARCHAR) { @@ -521,8 +499,11 @@ void StringValueResult::AddPossiblyEscapedValue(StringValueResult &result, const std::ostringstream error; // Casting Error Message - error << "Could not convert string \"" << std::string(value_ptr, length) << "\" to \'" - << LogicalTypeIdToString(result.parse_types[result.chunk_col_id].type_id) << "\'"; + error << "Could not convert string \"" + << std::string(result.buffer_ptr + result.quoted_position + 1, + buffer_pos - result.quoted_position - 2) + << "\" to \'" << LogicalTypeIdToString(result.parse_types[result.chunk_col_id].type_id) + << "\'"; auto error_string = error.str(); SanitizeError(error_string); result.current_errors.ModifyErrorMessageOfLastError(error_string); @@ -531,53 +512,35 @@ void StringValueResult::AddPossiblyEscapedValue(StringValueResult &result, const result.chunk_col_id++; } else { auto value = StringValueScanner::RemoveEscape( - value_ptr, length, result.state_machine.dialect_options.state_machine_options.escape.GetValue(), - result.state_machine.dialect_options.state_machine_options.quote.GetValue(), + result.buffer_ptr + result.quoted_position + 1, buffer_pos - result.quoted_position - 2, + result.state_machine.dialect_options.state_machine_options.escape.GetValue(), result.parse_chunk.data[result.chunk_col_id]); result.AddValueToVector(value.GetData(), value.GetSize()); } } } else { - if (empty) { + if (buffer_pos < result.last_position.buffer_pos + 2) { // empty value auto value = string_t(); result.AddValueToVector(value.GetData(), value.GetSize()); } else { - result.AddValueToVector(value_ptr, length); + result.AddValueToVector(result.buffer_ptr + result.quoted_position + 1, + buffer_pos - result.quoted_position - 2); } } + result.quoted = false; result.escaped = false; } -inline idx_t StringValueResult::HandleMultiDelimiter(const idx_t buffer_pos) const { - idx_t size = buffer_pos - last_position.buffer_pos - extra_delimiter_bytes; - if (buffer_pos < last_position.buffer_pos + extra_delimiter_bytes) { - // If this is a scenario where the value is null, that is fine (e.g., delim = '||' and line is: A||) - if (buffer_pos == last_position.buffer_pos) { - size = 0; - } else { - // Otherwise something went wrong. - throw InternalException( - "Value size is lower than the number of extra delimiter bytes in the HandleMultiDelimiter(). " - "buffer_pos = %d, last_position.buffer_pos = %d, extra_delimiter_bytes = %d", - buffer_pos, last_position.buffer_pos, extra_delimiter_bytes); - } - } - return size; -} - void StringValueResult::AddValue(StringValueResult &result, const idx_t buffer_pos) { if (result.last_position.buffer_pos > buffer_pos) { return; } if (result.quoted) { - AddQuotedValue(result, buffer_pos - result.extra_delimiter_bytes); - } else if (result.escaped) { - AddPossiblyEscapedValue(result, buffer_pos, result.buffer_ptr + result.last_position.buffer_pos, - buffer_pos - result.last_position.buffer_pos, false); + StringValueResult::AddQuotedValue(result, buffer_pos); } else { result.AddValueToVector(result.buffer_ptr + result.last_position.buffer_pos, - result.HandleMultiDelimiter(buffer_pos)); + buffer_pos - result.last_position.buffer_pos); } result.last_position.buffer_pos = buffer_pos + 1; } @@ -685,28 +648,15 @@ bool LineError::HandleErrors(StringValueResult &result) { break; case MAXIMUM_LINE_SIZE: csv_error = CSVError::LineSizeError( - result.state_machine.options, lines_per_batch, borked_line, + result.state_machine.options, cur_error.current_line_size, lines_per_batch, borked_line, result.current_line_position.begin.GetGlobalPosition(result.requested_size, first_nl), result.path); break; - case INVALID_STATE: - if (result.current_line_position.begin == line_pos) { - csv_error = CSVError::InvalidState( - result.state_machine.options, col_idx, lines_per_batch, borked_line, - result.current_line_position.begin.GetGlobalPosition(result.requested_size, first_nl), - line_pos.GetGlobalPosition(result.requested_size, first_nl), result.path); - } else { - csv_error = CSVError::InvalidState( - result.state_machine.options, col_idx, lines_per_batch, borked_line, - result.current_line_position.begin.GetGlobalPosition(result.requested_size, first_nl), - line_pos.GetGlobalPosition(result.requested_size), result.path); - } - break; default: throw InvalidInputException("CSV Error not allowed when inserting row"); } result.error_handler.Error(csv_error); } - if (is_error_in_line && scan_id != StringValueScanner::LINE_FINDER_ID) { + if (is_error_in_line) { if (result.sniffing) { // If we are sniffing we just remove the line result.RemoveLastLine(); @@ -784,7 +734,7 @@ bool StringValueResult::AddRowInternal() { } current_line_position.begin = current_line_position.end; current_line_position.end = current_line_start; - if (current_line_size > state_machine.options.maximum_line_size.GetValue()) { + if (current_line_size > state_machine.options.maximum_line_size) { current_errors.Insert(MAXIMUM_LINE_SIZE, 1, chunk_col_id, last_position, current_line_size); } if (!state_machine.options.null_padding) { @@ -831,7 +781,7 @@ bool StringValueResult::AddRowInternal() { } else { // If we are not null-padding this is an error if (!state_machine.options.IgnoreErrors()) { - bool first_nl = false; + bool first_nl; auto borked_line = current_line_position.ReconstructCurrentLine(first_nl, buffer_handles, PrintErrorLine()); LinesPerBoundary lines_per_batch(iterator.GetBoundaryIdx(), lines_read); @@ -870,13 +820,8 @@ bool StringValueResult::AddRow(StringValueResult &result, const idx_t buffer_pos if (result.quoted) { AddQuotedValue(result, buffer_pos); } else { - char *value_ptr = result.buffer_ptr + result.last_position.buffer_pos; - idx_t size = buffer_pos - result.last_position.buffer_pos; - if (result.escaped) { - AddPossiblyEscapedValue(result, buffer_pos, value_ptr, size, size == 0); - } else { - result.AddValueToVector(value_ptr, size); - } + result.AddValueToVector(result.buffer_ptr + result.last_position.buffer_pos, + buffer_pos - result.last_position.buffer_pos); } if (result.state_machine.dialect_options.state_machine_options.new_line == NewLineIdentifier::CARRY_ON) { if (result.states.states[1] == CSVState::RECORD_SEPARATOR) { @@ -895,11 +840,12 @@ bool StringValueResult::AddRow(StringValueResult &result, const idx_t buffer_pos } void StringValueResult::InvalidState(StringValueResult &result) { - if (result.quoted) { - result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, result.last_position); - } else { - result.current_errors.Insert(INVALID_STATE, result.cur_col_id, result.chunk_col_id, result.last_position); + bool force_error = !result.state_machine.options.ignore_errors.GetValue() && result.sniffing; + // Invalid unicode, we must error + if (force_error) { + result.HandleUnicodeError(result.cur_col_id, result.last_position); } + result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, result.last_position); } bool StringValueResult::EmptyLine(StringValueResult &result, const idx_t buffer_pos) { @@ -942,8 +888,7 @@ StringValueScanner::StringValueScanner(idx_t scanner_idx_p, const shared_ptrcontext), result_size, iterator.pos.buffer_pos, *error_handler, iterator, buffer_manager->context.client_data->debug_set_max_line_length, csv_file_scan, lines_read, sniffing, - buffer_manager->GetFilePath(), scanner_idx_p) { - iterator.buffer_size = state_machine->options.buffer_size_option.GetValue(); + buffer_manager->GetFilePath()) { } StringValueScanner::StringValueScanner(const shared_ptr &buffer_manager, @@ -954,8 +899,7 @@ StringValueScanner::StringValueScanner(const shared_ptr &buffe result(states, *state_machine, cur_buffer_handle, Allocator::DefaultAllocator(), result_size, iterator.pos.buffer_pos, *error_handler, iterator, buffer_manager->context.client_data->debug_set_max_line_length, csv_file_scan, lines_read, sniffing, - buffer_manager->GetFilePath(), 0) { - iterator.buffer_size = state_machine->options.buffer_size_option.GetValue(); + buffer_manager->GetFilePath()) { } unique_ptr StringValueScanner::GetCSVScanner(ClientContext &context, CSVReaderOptions &options) { @@ -1068,7 +1012,7 @@ void StringValueScanner::Flush(DataChunk &insert_chunk) { } result.borked_rows.insert(line_error++); D_ASSERT(state_machine->options.ignore_errors.GetValue()); - // We are ignoring errors. We must continue but ignoring borked-rows + // We are ignoring errors. We must continue but ignoring borked rows for (; line_error < parse_chunk.size(); line_error++) { if (!inserted_column_data.validity.RowIsValid(line_error) && parse_column_data.validity.RowIsValid(line_error)) { @@ -1117,16 +1061,13 @@ void StringValueScanner::Flush(DataChunk &insert_chunk) { void StringValueScanner::Initialize() { states.Initialize(); - if (result.result_size != 1 && !(sniffing && state_machine->options.null_padding && !state_machine->options.dialect_options.skip_rows.IsSetByUser())) { SetStart(); - } else { - start_pos = iterator.GetGlobalCurrentPos(); } - result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, cur_buffer_handle->actual_size}; result.current_line_position.begin = result.last_position; + result.current_line_position.end = result.current_line_position.begin; } @@ -1193,8 +1134,6 @@ void StringValueScanner::ProcessExtraRow() { } break; case CSVState::ESCAPE: - case CSVState::UNQUOTED_ESCAPE: - case CSVState::ESCAPED_RETURN: result.SetEscaped(result); iterator.pos.buffer_pos++; break; @@ -1206,11 +1145,6 @@ void StringValueScanner::ProcessExtraRow() { iterator.pos.buffer_pos++; } break; - case CSVState::UNQUOTED: { - result.SetUnquoted(result); - iterator.pos.buffer_pos++; - break; - } case CSVState::COMMENT: result.SetComment(result, iterator.pos.buffer_pos); iterator.pos.buffer_pos++; @@ -1232,18 +1166,13 @@ void StringValueScanner::ProcessExtraRow() { } } -string_t StringValueScanner::RemoveEscape(const char *str_ptr, idx_t end, char escape, char quote, Vector &vector) { +string_t StringValueScanner::RemoveEscape(const char *str_ptr, idx_t end, char escape, Vector &vector) { // Figure out the exact size idx_t str_pos = 0; bool just_escaped = false; for (idx_t cur_pos = 0; cur_pos < end; cur_pos++) { if (str_ptr[cur_pos] == escape && !just_escaped) { just_escaped = true; - } else if (str_ptr[cur_pos] == quote) { - if (just_escaped) { - str_pos++; - } - just_escaped = false; } else { just_escaped = false; str_pos++; @@ -1256,14 +1185,9 @@ string_t StringValueScanner::RemoveEscape(const char *str_ptr, idx_t end, char e str_pos = 0; just_escaped = false; for (idx_t cur_pos = 0; cur_pos < end; cur_pos++) { - const char c = str_ptr[cur_pos]; + char c = str_ptr[cur_pos]; if (c == escape && !just_escaped) { just_escaped = true; - } else if (str_ptr[cur_pos] == quote) { - if (just_escaped) { - removed_escapes_ptr[str_pos++] = c; - } - just_escaped = false; } else { just_escaped = false; removed_escapes_ptr[str_pos++] = c; @@ -1273,14 +1197,14 @@ string_t StringValueScanner::RemoveEscape(const char *str_ptr, idx_t end, char e return removed_escapes; } -void StringValueScanner::ProcessOverBufferValue() { +void StringValueScanner::ProcessOverbufferValue() { // Process first string - if (result.last_position.buffer_pos != previous_buffer_handle->actual_size) { - states.Initialize(); - } - - string over_buffer_string; + states.Initialize(); + string overbuffer_string; auto previous_buffer = previous_buffer_handle->Ptr(); + if (result.last_position.buffer_pos == previous_buffer_handle->actual_size) { + state_machine->Transition(states, previous_buffer[result.last_position.buffer_pos - 1]); + } idx_t j = 0; result.quoted = false; for (idx_t i = result.last_position.buffer_pos; i < previous_buffer_handle->actual_size; i++) { @@ -1292,16 +1216,13 @@ void StringValueScanner::ProcessOverBufferValue() { break; } else { if (!result.comment) { - over_buffer_string += previous_buffer[i]; + overbuffer_string += previous_buffer[i]; } } if (states.IsQuoted()) { result.SetQuoted(result, j); } - if (states.IsUnquoted()) { - result.SetUnquoted(result); - } - if (states.IsEscaped() && result.state_machine.dialect_options.state_machine_options.escape != '\0') { + if (states.IsEscaped()) { result.escaped = true; } if (states.IsComment()) { @@ -1312,7 +1233,7 @@ void StringValueScanner::ProcessOverBufferValue() { } j++; } - if (over_buffer_string.empty() && + if (overbuffer_string.empty() && state_machine->dialect_options.state_machine_options.new_line == NewLineIdentifier::CARRY_ON) { if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n') { iterator.pos.buffer_pos++; @@ -1332,7 +1253,7 @@ void StringValueScanner::ProcessOverBufferValue() { break; } else { if (!result.comment && !states.IsComment()) { - over_buffer_string += buffer_handle_ptr[iterator.pos.buffer_pos]; + overbuffer_string += buffer_handle_ptr[iterator.pos.buffer_pos]; } } if (states.IsQuoted()) { @@ -1341,7 +1262,7 @@ void StringValueScanner::ProcessOverBufferValue() { if (states.IsComment()) { result.comment = true; } - if (states.IsEscaped() && result.state_machine.dialect_options.state_machine_options.escape != '\0') { + if (states.IsEscaped()) { result.escaped = true; } if (states.IsInvalid()) { @@ -1359,42 +1280,21 @@ void StringValueScanner::ProcessOverBufferValue() { if (!skip_value) { string_t value; if (result.quoted) { - value = string_t(over_buffer_string.c_str() + result.quoted_position, - UnsafeNumericCast(over_buffer_string.size() - 1 - result.quoted_position)); + value = string_t(overbuffer_string.c_str() + result.quoted_position, + UnsafeNumericCast(overbuffer_string.size() - 1 - result.quoted_position)); if (result.escaped) { - if (!result.HandleTooManyColumnsError(over_buffer_string.c_str(), over_buffer_string.size())) { - const auto str_ptr = over_buffer_string.c_str() + result.quoted_position; - value = RemoveEscape(str_ptr, over_buffer_string.size() - 2, - state_machine->dialect_options.state_machine_options.escape.GetValue(), - state_machine->dialect_options.state_machine_options.quote.GetValue(), - result.parse_chunk.data[result.chunk_col_id]); - } + const auto str_ptr = overbuffer_string.c_str() + result.quoted_position; + value = RemoveEscape(str_ptr, overbuffer_string.size() - 2, + state_machine->dialect_options.state_machine_options.escape.GetValue(), + result.parse_chunk.data[result.chunk_col_id]); } } else { - value = string_t(over_buffer_string.c_str(), UnsafeNumericCast(over_buffer_string.size())); - if (result.escaped) { - if (!result.HandleTooManyColumnsError(over_buffer_string.c_str(), over_buffer_string.size())) { - value = RemoveEscape(over_buffer_string.c_str(), over_buffer_string.size(), - state_machine->dialect_options.state_machine_options.escape.GetValue(), - state_machine->dialect_options.state_machine_options.quote.GetValue(), - result.parse_chunk.data[result.chunk_col_id]); - } - } + value = string_t(overbuffer_string.c_str(), UnsafeNumericCast(overbuffer_string.size())); } if (states.EmptyLine() && state_machine->dialect_options.num_cols == 1) { result.EmptyLine(result, iterator.pos.buffer_pos); } else if (!states.IsNotSet() && (!result.comment || !value.Empty())) { - idx_t value_size = value.GetSize(); - if (states.IsDelimiter()) { - idx_t extra_delimiter_bytes = - result.state_machine.dialect_options.state_machine_options.delimiter.GetValue().size() - 1; - if (extra_delimiter_bytes > value_size) { - throw InternalException( - "Value size is lower than the number of extra delimiter bytes in the ProcesOverBufferValue()"); - } - value_size -= extra_delimiter_bytes; - } - result.AddValueToVector(value.GetData(), value_size, true); + result.AddValueToVector(value.GetData(), value.GetSize(), true); } } else { if (states.EmptyLine() && state_machine->dialect_options.num_cols == 1) { @@ -1453,8 +1353,7 @@ bool StringValueScanner::MoveToNextBuffer() { result.AddRow(result, previous_buffer_handle->actual_size); } lines_read++; - } else if (states.IsQuotedCurrent() && - state_machine->dialect_options.state_machine_options.rfc_4180.GetValue()) { + } else if (states.IsQuotedCurrent()) { // Unterminated quote LinePosition current_line_start = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; @@ -1465,11 +1364,6 @@ bool StringValueScanner::MoveToNextBuffer() { if (result.IsCommentSet(result)) { result.UnsetComment(result, iterator.pos.buffer_pos); } else { - if (result.quoted && states.IsDelimiterBytes() && - state_machine->dialect_options.state_machine_options.rfc_4180.GetValue()) { - result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, - result.last_position); - } result.AddRow(result, previous_buffer_handle->actual_size); } lines_read++; @@ -1480,8 +1374,8 @@ bool StringValueScanner::MoveToNextBuffer() { iterator.pos.buffer_pos = 0; buffer_handle_ptr = cur_buffer_handle->Ptr(); - // Handle over-buffer value - ProcessOverBufferValue(); + // Handle overbuffer value + ProcessOverbufferValue(); result.buffer_ptr = buffer_handle_ptr; result.buffer_size = cur_buffer_handle->actual_size; return true; @@ -1514,86 +1408,38 @@ bool StringValueResult::PrintErrorLine() const { (state_machine.options.store_rejects.GetValue() || !state_machine.options.ignore_errors.GetValue()); } -bool StringValueScanner::FirstValueEndsOnQuote(CSVIterator iterator) const { - CSVStates current_state; - current_state.Initialize(CSVState::STANDARD); - const idx_t to_pos = iterator.GetEndPos(); - while (iterator.pos.buffer_pos < to_pos) { - state_machine->Transition(current_state, buffer_handle_ptr[iterator.pos.buffer_pos++]); - if ((current_state.IsState(CSVState::DELIMITER) || current_state.IsState(CSVState::CARRIAGE_RETURN) || - current_state.IsState(CSVState::RECORD_SEPARATOR))) { - return buffer_handle_ptr[iterator.pos.buffer_pos - 2] == - state_machine->dialect_options.state_machine_options.quote.GetValue(); - } - } - return false; -} - -bool StringValueScanner::SkipUntilState(CSVState initial_state, CSVState until_state, CSVIterator ¤t_iterator, - bool "ed) const { - CSVStates current_state; - current_state.Initialize(initial_state); - bool first_column = true; - const idx_t to_pos = current_iterator.GetEndPos(); - while (current_iterator.pos.buffer_pos < to_pos) { - state_machine_strict->Transition(current_state, buffer_handle_ptr[current_iterator.pos.buffer_pos++]); - if (current_state.IsState(CSVState::STANDARD) || current_state.IsState(CSVState::STANDARD_NEWLINE)) { - while (current_iterator.pos.buffer_pos + 8 < to_pos) { - uint64_t value = Load( - reinterpret_cast(&buffer_handle_ptr[current_iterator.pos.buffer_pos])); - if (ContainsZeroByte((value ^ state_machine_strict->transition_array.delimiter) & - (value ^ state_machine_strict->transition_array.new_line) & - (value ^ state_machine_strict->transition_array.carriage_return) & - (value ^ state_machine_strict->transition_array.comment))) { - break; - } - current_iterator.pos.buffer_pos += 8; - } - while (state_machine_strict->transition_array - .skip_standard[static_cast(buffer_handle_ptr[current_iterator.pos.buffer_pos])] && - current_iterator.pos.buffer_pos < to_pos - 1) { - current_iterator.pos.buffer_pos++; +void StringValueScanner::SkipUntilNewLine() { + // Now skip until next newline + if (state_machine->options.dialect_options.state_machine_options.new_line.GetValue() == + NewLineIdentifier::CARRY_ON) { + bool carriage_return = false; + bool not_carriage_return = false; + for (; iterator.pos.buffer_pos < cur_buffer_handle->actual_size; iterator.pos.buffer_pos++) { + if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\r') { + carriage_return = true; + } else if (buffer_handle_ptr[iterator.pos.buffer_pos] != '\n') { + not_carriage_return = true; } - } - if (current_state.IsState(CSVState::QUOTED)) { - while (current_iterator.pos.buffer_pos + 8 < to_pos) { - uint64_t value = Load( - reinterpret_cast(&buffer_handle_ptr[current_iterator.pos.buffer_pos])); - if (ContainsZeroByte((value ^ state_machine_strict->transition_array.quote) & - (value ^ state_machine_strict->transition_array.escape))) { - break; + if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n') { + if (carriage_return || not_carriage_return) { + iterator.pos.buffer_pos++; + return; } - current_iterator.pos.buffer_pos += 8; - } - - while (state_machine_strict->transition_array - .skip_quoted[static_cast(buffer_handle_ptr[current_iterator.pos.buffer_pos])] && - current_iterator.pos.buffer_pos < to_pos - 1) { - current_iterator.pos.buffer_pos++; } } - if ((current_state.IsState(CSVState::DELIMITER) || current_state.IsState(CSVState::CARRIAGE_RETURN) || - current_state.IsState(CSVState::RECORD_SEPARATOR)) && - first_column) { - if (buffer_handle_ptr[current_iterator.pos.buffer_pos - 1] == - state_machine_strict->dialect_options.state_machine_options.quote.GetValue()) { - quoted = true; + } else { + for (; iterator.pos.buffer_pos < cur_buffer_handle->actual_size; iterator.pos.buffer_pos++) { + if (buffer_handle_ptr[iterator.pos.buffer_pos] == '\n' || + buffer_handle_ptr[iterator.pos.buffer_pos] == '\r') { + iterator.pos.buffer_pos++; + return; } } - if (current_state.WasState(CSVState::DELIMITER)) { - first_column = false; - } - if (current_state.IsState(until_state)) { - return true; - } - if (current_state.IsState(CSVState::INVALID)) { - return false; - } } - return false; } bool StringValueScanner::CanDirectlyCast(const LogicalType &type, bool icu_loaded) { + switch (type.id()) { case LogicalTypeId::TINYINT: case LogicalTypeId::SMALLINT: @@ -1621,123 +1467,60 @@ bool StringValueScanner::CanDirectlyCast(const LogicalType &type, bool icu_loade } } -bool StringValueScanner::IsRowValid(CSVIterator ¤t_iterator) const { - if (iterator.pos.buffer_pos == cur_buffer_handle->actual_size) { - return false; - } - constexpr idx_t result_size = 1; - auto scan_finder = make_uniq(StringValueScanner::LINE_FINDER_ID, buffer_manager, - state_machine_strict, make_shared_ptr(), - csv_file_scan, false, current_iterator, result_size); - auto &tuples = scan_finder->ParseChunk(); - current_iterator.pos = scan_finder->GetIteratorPosition(); - bool has_error = false; - if (tuples.current_errors.HasError()) { - if (tuples.current_errors.Size() != 1 || !tuples.current_errors.HasErrorType(MAXIMUM_LINE_SIZE)) { - // We ignore maximum line size errors - has_error = true; - } - } - return (tuples.number_of_rows == 1 || tuples.first_line_is_comment) && !has_error && tuples.borked_rows.empty(); -} - -ValidRowInfo StringValueScanner::TryRow(CSVState state, idx_t start_pos, idx_t end_pos) const { - auto current_iterator = iterator; - current_iterator.SetStart(start_pos); - current_iterator.SetEnd(end_pos); - bool quoted = false; - if (SkipUntilState(state, CSVState::RECORD_SEPARATOR, current_iterator, quoted)) { - auto iterator_start = current_iterator; - idx_t current_pos = current_iterator.pos.buffer_pos; - current_iterator.SetEnd(iterator.GetEndPos()); - if (IsRowValid(current_iterator)) { - if (!quoted) { - quoted = FirstValueEndsOnQuote(iterator_start); - } - return {true, current_pos, current_iterator.pos.buffer_idx, current_iterator.pos.buffer_pos, quoted}; - } - } - return {false, current_iterator.pos.buffer_pos, current_iterator.pos.buffer_idx, current_iterator.pos.buffer_pos, - quoted}; -} - void StringValueScanner::SetStart() { - start_pos = iterator.GetGlobalCurrentPos(); if (iterator.first_one) { if (result.store_line_size) { result.error_handler.NewMaxLineSize(iterator.pos.buffer_pos); } return; } - if (iterator.GetEndPos() > cur_buffer_handle->actual_size) { - iterator.SetEnd(cur_buffer_handle->actual_size); - } - if (!state_machine_strict) { - // We need to initialize our strict state machine - auto &state_machine_cache = CSVStateMachineCache::Get(buffer_manager->context); - auto state_options = state_machine->state_machine_options; - // To set the state machine to be strict we ensure that rfc_4180 is set to true - if (!state_options.rfc_4180.IsSetByUser()) { - state_options.rfc_4180 = true; - } - state_machine_strict = - make_shared_ptr(state_machine_cache.Get(state_options), state_machine->options); - } - // At this point we have 3 options: - // 1. We are at the start of a valid line - ValidRowInfo best_row = TryRow(CSVState::STANDARD_NEWLINE, iterator.pos.buffer_pos, iterator.GetEndPos()); - // 2. We are in the middle of a quoted value - if (state_machine->dialect_options.state_machine_options.quote.GetValue() != '\0') { - idx_t end_pos = iterator.GetEndPos(); - if (best_row.is_valid && best_row.end_buffer_idx == iterator.pos.buffer_idx) { - // If we got a valid row from the standard state, we limit our search up to that. - end_pos = best_row.end_pos; - } - auto quoted_row = TryRow(CSVState::QUOTED, iterator.pos.buffer_pos, end_pos); - if (quoted_row.is_valid && (!best_row.is_valid || best_row.last_state_quote)) { - best_row = quoted_row; - } - if (!best_row.is_valid && !quoted_row.is_valid && best_row.start_pos < quoted_row.start_pos) { - best_row = quoted_row; - } - } - // 3. We are in an escaped value - if (!best_row.is_valid && state_machine->dialect_options.state_machine_options.escape.GetValue() != '\0' && - state_machine->dialect_options.state_machine_options.quote.GetValue() != '\0') { - auto escape_row = TryRow(CSVState::ESCAPE, iterator.pos.buffer_pos, iterator.GetEndPos()); - if (escape_row.is_valid) { - best_row = escape_row; - } else { - if (best_row.start_pos < escape_row.start_pos) { - best_row = escape_row; - } + // The result size of the data after skipping the row is one line + // We have to look for a new line that fits our schema + // 1. We walk until the next new line + bool line_found; + unique_ptr scan_finder; + do { + constexpr idx_t result_size = 1; + SkipUntilNewLine(); + if (state_machine->options.null_padding) { + // When Null Padding, we assume we start from the correct new-line + return; } - } - if (!best_row.is_valid) { - bool is_this_the_end = - best_row.start_pos >= cur_buffer_handle->actual_size && cur_buffer_handle->is_last_buffer; - if (is_this_the_end) { - iterator.pos.buffer_pos = best_row.start_pos; - iterator.done = true; - } else { - bool mock; - if (!SkipUntilState(CSVState::STANDARD_NEWLINE, CSVState::RECORD_SEPARATOR, iterator, mock)) { - iterator.CheckIfDone(); + scan_finder = + make_uniq(0U, buffer_manager, state_machine, make_shared_ptr(true), + csv_file_scan, false, iterator, result_size); + auto &tuples = scan_finder->ParseChunk(); + line_found = true; + if (tuples.number_of_rows != 1 || + (!tuples.borked_rows.empty() && !state_machine->options.ignore_errors.GetValue()) || + tuples.first_line_is_comment) { + line_found = false; + // If no tuples were parsed, this is not the correct start, we need to skip until the next new line + // Or if columns don't match, this is not the correct start, we need to skip until the next new line + if (scan_finder->previous_buffer_handle) { + if (scan_finder->iterator.pos.buffer_pos >= scan_finder->previous_buffer_handle->actual_size && + scan_finder->previous_buffer_handle->is_last_buffer) { + iterator.pos.buffer_idx = scan_finder->iterator.pos.buffer_idx; + iterator.pos.buffer_pos = scan_finder->iterator.pos.buffer_pos; + result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; + iterator.done = scan_finder->iterator.done; + return; + } + } + if (iterator.pos.buffer_pos == cur_buffer_handle->actual_size || + scan_finder->iterator.GetBufferIdx() > iterator.GetBufferIdx()) { + // If things go terribly wrong, we never loop indefinitely. + iterator.pos.buffer_idx = scan_finder->iterator.pos.buffer_idx; + iterator.pos.buffer_pos = scan_finder->iterator.pos.buffer_pos; + result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; + iterator.done = scan_finder->iterator.done; + return; } } - } else { - iterator.pos.buffer_pos = best_row.start_pos; - bool is_this_the_end = - best_row.start_pos >= cur_buffer_handle->actual_size && cur_buffer_handle->is_last_buffer; - if (is_this_the_end) { - iterator.done = true; - } - } - - // 4. We have an error, if we have an error, we let life go on, the scanner will either ignore it - // or throw. + } while (!line_found); + iterator.pos.buffer_idx = scan_finder->result.current_line_position.begin.buffer_idx; + iterator.pos.buffer_pos = scan_finder->result.current_line_position.begin.buffer_pos; result.last_position = {iterator.pos.buffer_idx, iterator.pos.buffer_pos, result.buffer_size}; - start_pos = iterator.GetGlobalCurrentPos(); } void StringValueScanner::FinalizeChunkProcess() { @@ -1754,18 +1537,11 @@ void StringValueScanner::FinalizeChunkProcess() { // If we are not done we have two options. // 1) If a boundary is set. if (iterator.IsBoundarySet()) { - bool found_error = false; - CSVErrorType type; - if (!result.current_errors.HasErrorType(UNTERMINATED_QUOTES) && - !result.current_errors.HasErrorType(INVALID_STATE)) { + bool has_unterminated_quotes = false; + if (!result.current_errors.HasErrorType(UNTERMINATED_QUOTES)) { iterator.done = true; } else { - found_error = true; - if (result.current_errors.HasErrorType(UNTERMINATED_QUOTES)) { - type = UNTERMINATED_QUOTES; - } else { - type = INVALID_STATE; - } + has_unterminated_quotes = true; } // We read until the next line or until we have nothing else to read. // Move to next buffer @@ -1784,21 +1560,17 @@ void StringValueScanner::FinalizeChunkProcess() { } } else { if (result.current_errors.HasErrorType(UNTERMINATED_QUOTES)) { - found_error = true; - type = UNTERMINATED_QUOTES; - } else if (result.current_errors.HasErrorType(INVALID_STATE)) { - found_error = true; - type = INVALID_STATE; + has_unterminated_quotes = true; } if (result.current_errors.HandleErrors(result)) { result.number_of_rows++; } } - if (states.IsQuotedCurrent() && !found_error && - state_machine->dialect_options.state_machine_options.rfc_4180.GetValue()) { + if (states.IsQuotedCurrent() && !has_unterminated_quotes) { // If we finish the execution of a buffer, and we end in a quoted state, it means we have unterminated // quotes - result.current_errors.Insert(type, result.cur_col_id, result.chunk_col_id, result.last_position); + result.current_errors.Insert(UNTERMINATED_QUOTES, result.cur_col_id, result.chunk_col_id, + result.last_position); if (result.current_errors.HandleErrors(result)) { result.number_of_rows++; } @@ -1831,9 +1603,4 @@ void StringValueScanner::FinalizeChunkProcess() { } } } - -ValidatorLine StringValueScanner::GetValidationLine() { - return {start_pos, result.iterator.GetGlobalCurrentPos()}; -} - } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp index c8740ebde..950d74891 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/csv_sniffer.cpp @@ -6,7 +6,7 @@ namespace duckdb { CSVSniffer::CSVSniffer(CSVReaderOptions &options_p, shared_ptr buffer_manager_p, CSVStateMachineCache &state_machine_cache_p, bool default_null_to_varchar_p) : state_machine_cache(state_machine_cache_p), options(options_p), buffer_manager(std::move(buffer_manager_p)), - lines_sniffed(0), default_null_to_varchar(default_null_to_varchar_p) { + default_null_to_varchar(default_null_to_varchar_p) { // Initialize Format Candidates for (const auto &format_template : format_template_candidates) { auto &logical_type = format_template.first; @@ -48,9 +48,8 @@ void MatchAndReplace(CSVOption &original, CSVOption &sniffed, const string original.Set(sniffed.GetValue(), false); } } - -void MatchAndReplaceUserSetVariables(DialectOptions &original, DialectOptions &sniffed, string &error, bool found_date, - bool found_timestamp) { +void MatchAndRepaceUserSetVariables(DialectOptions &original, DialectOptions &sniffed, string &error, bool found_date, + bool found_timestamp) { MatchAndReplace(original.header, sniffed.header, "Header", error); if (sniffed.state_machine_options.new_line.GetValue() != NewLineIdentifier::NOT_SET) { // Is sniffed line is not set (e.g., single-line file) , we don't try to replace and match. @@ -73,7 +72,7 @@ void MatchAndReplaceUserSetVariables(DialectOptions &original, DialectOptions &s } } // Set the CSV Options in the reference -void CSVSniffer::SetResultOptions() const { +void CSVSniffer::SetResultOptions() { bool found_date = false; bool found_timestamp = false; for (auto &type : detected_types) { @@ -83,8 +82,8 @@ void CSVSniffer::SetResultOptions() const { found_timestamp = true; } } - MatchAndReplaceUserSetVariables(options.dialect_options, best_candidate->GetStateMachine().dialect_options, - options.sniffer_user_mismatch_error, found_date, found_timestamp); + MatchAndRepaceUserSetVariables(options.dialect_options, best_candidate->GetStateMachine().dialect_options, + options.sniffer_user_mismatch_error, found_date, found_timestamp); options.dialect_options.num_cols = best_candidate->GetStateMachine().dialect_options.num_cols; options.dialect_options.rows_until_header = best_candidate->GetStateMachine().dialect_options.rows_until_header; } @@ -97,8 +96,9 @@ AdaptiveSnifferResult CSVSniffer::MinimalSniff() { // Return Types detected vector return_types; // Column Names detected + buffer_manager->sniffing = true; - constexpr idx_t result_size = STANDARD_VECTOR_SIZE; + constexpr idx_t result_size = 2; auto state_machine = make_shared_ptr(options, options.dialect_options.state_machine_options, state_machine_cache); @@ -114,7 +114,6 @@ AdaptiveSnifferResult CSVSniffer::MinimalSniff() { // First figure out the number of columns on this configuration auto scanner = count_scanner.UpgradeToStringValueScanner(); - scanner->error_handler->SetIgnoreErrors(true); // Parse chunk and read csv with info candidate auto &data_chunk = scanner->ParseChunk().ToChunk(); idx_t start_row = 0; @@ -131,9 +130,10 @@ AdaptiveSnifferResult CSVSniffer::MinimalSniff() { // Possibly Gather Header vector potential_header; + for (idx_t col_idx = 0; col_idx < data_chunk.ColumnCount(); col_idx++) { auto &cur_vector = data_chunk.data[col_idx]; - const auto vector_data = FlatVector::GetData(cur_vector); + auto vector_data = FlatVector::GetData(cur_vector); auto &validity = FlatVector::Validity(cur_vector); HeaderValue val; if (validity.RowIsValid(0)) { @@ -142,8 +142,8 @@ AdaptiveSnifferResult CSVSniffer::MinimalSniff() { potential_header.emplace_back(val); } - auto names = DetectHeaderInternal(buffer_manager->context, potential_header, *state_machine, set_columns, - best_sql_types_candidates_per_column_idx, options, *error_handler); + vector names = DetectHeaderInternal(buffer_manager->context, potential_header, *state_machine, set_columns, + best_sql_types_candidates_per_column_idx, options, *error_handler); for (idx_t column_idx = 0; column_idx < best_sql_types_candidates_per_column_idx.size(); column_idx++) { LogicalType d_type = best_sql_types_candidates_per_column_idx[column_idx].back(); @@ -152,6 +152,7 @@ AdaptiveSnifferResult CSVSniffer::MinimalSniff() { } detected_types.push_back(d_type); } + return {detected_types, names, sniffed_column_counts.result_position > 1}; } @@ -180,15 +181,10 @@ SnifferResult CSVSniffer::AdaptiveSniff(const CSVSchema &file_schema) { } return min_sniff_res.ToSnifferResult(); } - -SnifferResult CSVSniffer::SniffCSV(const bool force_match) { +SnifferResult CSVSniffer::SniffCSV(bool force_match) { buffer_manager->sniffing = true; // 1. Dialect Detection DetectDialect(); - if (buffer_manager->file_handle->compression_type != FileCompressionType::UNCOMPRESSED && - buffer_manager->IsBlockUnloaded(0)) { - buffer_manager->ResetBufferManager(); - } // 2. Type Detection DetectTypes(); // 3. Type Refinement @@ -205,8 +201,15 @@ SnifferResult CSVSniffer::SniffCSV(const bool force_match) { buffer_manager->ResetBufferManager(); } buffer_manager->sniffing = false; - if (best_candidate->error_handler->AnyErrors() && !options.ignore_errors.GetValue()) { - best_candidate->error_handler->ErrorIfTypeExists(MAXIMUM_LINE_SIZE); + if (!best_candidate->error_handler->errors.empty() && !options.ignore_errors.GetValue()) { + for (auto &error_vector : best_candidate->error_handler->errors) { + for (auto &error : error_vector.second) { + if (error.type == MAXIMUM_LINE_SIZE) { + // If it's a maximum line size error, we can do it now. + error_handler->Error(error); + } + } + } } D_ASSERT(best_sql_types_candidates_per_column_idx.size() == names.size()); // We are done, Set the CSV Options in the reference. Construct and return the result. diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp index 5cced646d..43cef4fc9 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/dialect_detection.cpp @@ -14,20 +14,20 @@ bool IsQuoteDefault(char quote) { return false; } -vector DialectCandidates::GetDefaultDelimiter() { - return {",", "|", ";", "\t"}; +vector DialectCandidates::GetDefaultDelimiter() { + return {',', '|', ';', '\t'}; } vector> DialectCandidates::GetDefaultQuote() { - return {{'\0'}, {'\"', '\''}, {'\"'}}; + return {{'\"'}, {'\"', '\''}, {'\0'}}; } vector DialectCandidates::GetDefaultQuoteRule() { - return {QuoteRule::NO_QUOTES, QuoteRule::QUOTES_OTHER, QuoteRule::QUOTES_RFC}; + return {QuoteRule::QUOTES_RFC, QuoteRule::QUOTES_OTHER, QuoteRule::NO_QUOTES}; } vector> DialectCandidates::GetDefaultEscape() { - return {{'\0'}, {'\\'}, {'\"', '\0', '\''}}; + return {{'\"', '\0', '\''}, {'\\'}, {'\0'}}; } vector DialectCandidates::GetDefaultComment() { @@ -51,19 +51,7 @@ string DialectCandidates::Print() { auto escape_candidate = escape_candidates_map[i]; for (idx_t j = 0; j < quote_candidate.size(); j++) { for (idx_t k = 0; k < escape_candidate.size(); k++) { - search_space << "[\'"; - if (quote_candidate[j] == '\0') { - search_space << "(no quote)"; - } else { - search_space << quote_candidate[j]; - } - search_space << "\',\'"; - if (escape_candidate[k] == '\0') { - search_space << "(no escape)"; - } else { - search_space << escape_candidate[k]; - } - search_space << "\']"; + search_space << "[\'" << quote_candidate[j] << "\',\'" << escape_candidate[k] << "\']"; if (k < escape_candidate.size() - 1) { search_space << ","; } @@ -92,11 +80,11 @@ string DialectCandidates::Print() { DialectCandidates::DialectCandidates(const CSVStateMachineOptions &options) { // assert that quotes escapes and rules have equal size - const auto default_quote = GetDefaultQuote(); - const auto default_escape = GetDefaultEscape(); - const auto default_quote_rule = GetDefaultQuoteRule(); - const auto default_delimiter = GetDefaultDelimiter(); - const auto default_comment = GetDefaultComment(); + auto default_quote = GetDefaultQuote(); + auto default_escape = GetDefaultEscape(); + auto default_quote_rule = GetDefaultQuoteRule(); + auto default_delimiter = GetDefaultDelimiter(); + auto default_comment = GetDefaultComment(); D_ASSERT(default_quote.size() == default_quote_rule.size() && default_quote_rule.size() == default_escape.size()); // fill the escapes @@ -156,11 +144,6 @@ void CSVSniffer::GenerateStateMachineSearchSpace(vector(options, state_machine_options, state_machine_cache); if (options.dialect_options.skip_rows.IsSetByUser()) { @@ -199,9 +181,6 @@ void CSVSniffer::GenerateStateMachineSearchSpace(vector scanner, idx_t num_cols = sniffed_column_counts.result_position == 0 ? 1 : sniffed_column_counts[0].number_of_columns; const bool ignore_errors = options.ignore_errors.GetValue(); // If we are ignoring errors and not null_padding , we pick the most frequent number of columns as the right one - const bool use_most_frequent_columns = ignore_errors && !options.null_padding; + bool use_most_frequent_columns = ignore_errors && !options.null_padding; if (use_most_frequent_columns) { num_cols = sniffed_column_counts.GetMostFrequentColumnCount(); } idx_t padding_count = 0; idx_t comment_rows = 0; idx_t ignored_rows = 0; - const bool allow_padding = options.null_padding; + bool allow_padding = options.null_padding; bool first_valid = false; if (sniffed_column_counts.result_position > rows_read) { rows_read = sniffed_column_counts.result_position; @@ -321,96 +300,63 @@ void CSVSniffer::AnalyzeDialectCandidate(unique_ptr scanner, consistent_rows += padding_count; // Whether there are more values (rows) available that are consistent, exceeding the current best. - const bool more_values = consistent_rows > best_consistent_rows && num_cols >= max_columns_found; + bool more_values = consistent_rows > best_consistent_rows && num_cols >= max_columns_found; - const bool more_columns = consistent_rows == best_consistent_rows && num_cols > max_columns_found; + bool more_columns = consistent_rows == best_consistent_rows && num_cols > max_columns_found; // If additional padding is required when compared to the previous padding count. - const bool require_more_padding = padding_count > prev_padding_count; + bool require_more_padding = padding_count > prev_padding_count; // If less padding is now required when compared to the previous padding count. - const bool require_less_padding = padding_count < prev_padding_count; + bool require_less_padding = padding_count < prev_padding_count; // If there was only a single column before, and the new number of columns exceeds that. - const bool single_column_before = max_columns_found < 2 && num_cols > max_columns_found * candidates.size(); + bool single_column_before = max_columns_found < 2 && num_cols > max_columns_found * candidates.size(); // If the number of rows is consistent with the calculated value after accounting for skipped rows and the // start row. - const bool rows_consistent = + bool rows_consistent = consistent_rows + (dirty_notes_minus_comments - options.dialect_options.skip_rows.GetValue()) + comment_rows == sniffed_column_counts.result_position - options.dialect_options.skip_rows.GetValue(); // If there are more than one consistent row. - const bool more_than_one_row = consistent_rows > 1; + bool more_than_one_row = consistent_rows > 1; // If there are more than one column. - const bool more_than_one_column = num_cols > 1; + bool more_than_one_column = num_cols > 1; // If the start position is valid. - const bool start_good = !candidates.empty() && - dirty_notes <= candidates.front()->GetStateMachine().dialect_options.skip_rows.GetValue(); + bool start_good = !candidates.empty() && + dirty_notes <= candidates.front()->GetStateMachine().dialect_options.skip_rows.GetValue(); // If padding happened but it is not allowed. - const bool invalid_padding = !allow_padding && padding_count > 0; + bool invalid_padding = !allow_padding && padding_count > 0; - const bool comments_are_acceptable = AreCommentsAcceptable( + bool comments_are_acceptable = AreCommentsAcceptable( sniffed_column_counts, num_cols, options.dialect_options.state_machine_options.comment.IsSetByUser()); - const bool quoted = - scanner->ever_quoted && - sniffed_column_counts.state_machine.dialect_options.state_machine_options.quote.GetValue() != '\0'; - - // For our columns to match, we either don't have them manually set, or they match in value with the sniffed value - const bool columns_match_set = - num_cols == set_columns.Size() || - (num_cols == set_columns.Size() + 1 && sniffed_column_counts[0].last_value_always_empty) || - !set_columns.IsSet(); - // If rows are consistent and no invalid padding happens, this is the best suitable candidate if one of the // following is valid: // - There's a single column before. // - There are more values and no additional padding is required. // - There's more than one column and less padding is required. - if (columns_match_set && (rows_consistent || (set_columns.IsSet() && ignore_errors)) && + if (rows_consistent && (single_column_before || ((more_values || more_columns) && !require_more_padding) || - (more_than_one_column && require_less_padding) || quoted) && + (more_than_one_column && require_less_padding)) && !invalid_padding && comments_are_acceptable) { - if (!candidates.empty() && set_columns.IsSet() && max_columns_found == set_columns.Size() && - consistent_rows <= best_consistent_rows) { + if (!candidates.empty() && set_columns.IsSet() && max_columns_found == set_columns.Size()) { // We have a candidate that fits our requirements better - if (candidates.front()->ever_quoted || !scanner->ever_quoted) { - return; - } + return; } auto &sniffing_state_machine = scanner->GetStateMachine(); - if (!candidates.empty() && candidates.front()->ever_quoted) { + if (!candidates.empty() && candidates.front()->ever_quoted && !scanner->ever_quoted) { // Give preference to quoted boys. - if (!scanner->ever_quoted) { - return; - } else { - // Give preference to one that got escaped - if (!scanner->ever_escaped && candidates.front()->ever_escaped) { - return; - } - if (best_consistent_rows == consistent_rows && num_cols >= max_columns_found) { - // If both have not been escaped, this might get solved later on. - sniffing_state_machine.dialect_options.num_cols = num_cols; - candidates.emplace_back(std::move(scanner)); - max_columns_found = num_cols; - return; - } - } + return; } if (max_columns_found == num_cols && ignored_rows > min_ignored_rows) { return; } - if (quoted && num_cols < max_columns_found) { - for (auto &candidate : candidates) { - if (candidate->ever_quoted) { - return; - } - } - } + best_consistent_rows = consistent_rows; max_columns_found = num_cols; prev_padding_count = padding_count; @@ -429,19 +375,18 @@ void CSVSniffer::AnalyzeDialectCandidate(unique_ptr scanner, candidates.clear(); sniffing_state_machine.dialect_options.num_cols = num_cols; - lines_sniffed = sniffed_column_counts.result_position; candidates.emplace_back(std::move(scanner)); return; } // If there's more than one row and column, the start is good, rows are consistent, // no additional padding is required, and there is no invalid padding, and there is not yet a candidate // with the same quote, we add this state_machine as a suitable candidate. - if (columns_match_set && more_than_one_row && more_than_one_column && start_good && rows_consistent && - !require_more_padding && !invalid_padding && num_cols == max_columns_found && comments_are_acceptable) { + if (more_than_one_row && more_than_one_column && start_good && rows_consistent && !require_more_padding && + !invalid_padding && num_cols == max_columns_found && comments_are_acceptable) { auto &sniffing_state_machine = scanner->GetStateMachine(); bool same_quote_is_candidate = false; - for (const auto &candidate : candidates) { + for (auto &candidate : candidates) { if (sniffing_state_machine.dialect_options.state_machine_options.quote == candidate->GetStateMachine().dialect_options.state_machine_options.quote) { same_quote_is_candidate = true; @@ -458,8 +403,8 @@ void CSVSniffer::AnalyzeDialectCandidate(unique_ptr scanner, } else if (!options.null_padding) { sniffing_state_machine.dialect_options.skip_rows = dirty_notes; } + sniffing_state_machine.dialect_options.num_cols = num_cols; - lines_sniffed = sniffed_column_counts.result_position; candidates.emplace_back(std::move(scanner)); } } @@ -492,35 +437,24 @@ void CSVSniffer::RefineCandidates() { // Only one candidate nothing to refine or all candidates already checked return; } - - for (idx_t i = 1; i <= options.sample_size_chunks; i++) { - vector> successful_candidates; - bool done = false; - for (auto &cur_candidate : candidates) { - const bool finished_file = cur_candidate->FinishedFile(); - if (successful_candidates.empty()) { - lines_sniffed += cur_candidate->GetResult().result_position; - } + vector> successful_candidates; + for (auto &cur_candidate : candidates) { + for (idx_t i = 1; i <= options.sample_size_chunks; i++) { + bool finished_file = cur_candidate->FinishedFile(); if (finished_file || i == options.sample_size_chunks) { // we finished the file or our chunk sample successfully - if (!cur_candidate->GetResult().error) { - successful_candidates.push_back(std::move(cur_candidate)); - } - done = true; - continue; - } - if (RefineCandidateNextChunk(*cur_candidate) && !cur_candidate->GetResult().error) { successful_candidates.push_back(std::move(cur_candidate)); + break; + } + if (!RefineCandidateNextChunk(*cur_candidate) || cur_candidate->GetResult().error) { + // This candidate failed, move to the next one + break; } - } - candidates = std::move(successful_candidates); - if (done) { - break; } } // If we have multiple candidates with quotes set, we will give the preference to ones // that have actually quoted values, otherwise we will choose quotes = \0 - vector> successful_candidates = std::move(candidates); + candidates.clear(); if (!successful_candidates.empty()) { for (idx_t i = 0; i < successful_candidates.size(); i++) { unique_ptr cc_best_candidate = std::move(successful_candidates[i]); @@ -591,7 +525,7 @@ void CSVSniffer::DetectDialect() { // if no dialect candidate was found, we throw an exception if (candidates.empty()) { auto error = CSVError::SniffingError(options, dialect_candidates.Print()); - error_handler->Error(error, true); + error_handler->Error(error); } } } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp index 424468c55..9475f5942 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/header_detection.cpp @@ -17,8 +17,8 @@ static string GenerateColumnName(const idx_t total_cols, const idx_t col_number, // Helper function for UTF-8 aware space trimming static string TrimWhitespace(const string &col_name) { utf8proc_int32_t codepoint; - const auto str = reinterpret_cast(col_name.c_str()); - const idx_t size = col_name.size(); + auto str = reinterpret_cast(col_name.c_str()); + idx_t size = col_name.size(); // Find the first character that is not left trimmed idx_t begin = 0; while (begin < size) { @@ -96,44 +96,6 @@ static string NormalizeColumnName(const string &col_name) { return col_name_cleaned; } -static void ReplaceNames(vector &detected_names, CSVStateMachine &state_machine, - unordered_map> &best_sql_types_candidates_per_column_idx, - CSVReaderOptions &options, const vector &best_header_row, - CSVErrorHandler &error_handler) { - auto &dialect_options = state_machine.dialect_options; - if (!options.columns_set) { - if (options.file_options.hive_partitioning || options.file_options.union_by_name || options.multi_file_reader) { - // Just do the replacement - for (idx_t i = 0; i < MinValue(detected_names.size(), options.name_list.size()); i++) { - detected_names[i] = options.name_list[i]; - } - return; - } - if (options.name_list.size() > dialect_options.num_cols) { - if (options.null_padding) { - // we increase our types - idx_t col = 0; - for (idx_t i = dialect_options.num_cols; i < options.name_list.size(); i++) { - detected_names.push_back(GenerateColumnName(options.name_list.size(), col++)); - best_sql_types_candidates_per_column_idx[i] = {LogicalType::VARCHAR}; - } - - dialect_options.num_cols = options.name_list.size(); - - } else { - // we throw an error - const auto error = CSVError::HeaderSniffingError( - options, best_header_row, options.name_list.size(), - state_machine.dialect_options.state_machine_options.delimiter.GetValue()); - error_handler.Error(error); - } - } - for (idx_t i = 0; i < options.name_list.size(); i++) { - detected_names[i] = options.name_list[i]; - } - } -} - // If our columns were set by the user, we verify if their names match with the first row bool CSVSniffer::DetectHeaderWithSetColumn(ClientContext &context, vector &best_header_row, const SetColumns &set_columns, CSVReaderOptions &options) { @@ -212,15 +174,17 @@ CSVSniffer::DetectHeaderInternal(ClientContext &context, vector &be CSVReaderOptions &options, CSVErrorHandler &error_handler) { vector detected_names; auto &dialect_options = state_machine.dialect_options; - dialect_options.num_cols = best_sql_types_candidates_per_column_idx.size(); if (best_header_row.empty()) { dialect_options.header = false; for (idx_t col = 0; col < dialect_options.num_cols; col++) { detected_names.push_back(GenerateColumnName(dialect_options.num_cols, col)); } // If the user provided names, we must replace our header with the user provided names - ReplaceNames(detected_names, state_machine, best_sql_types_candidates_per_column_idx, options, best_header_row, - error_handler); + if (!options.columns_set) { + for (idx_t i = 0; i < MinValue(best_header_row.size(), options.name_list.size()); i++) { + detected_names[i] = options.name_list[i]; + } + } return detected_names; } // information for header detection @@ -228,16 +192,6 @@ CSVSniffer::DetectHeaderInternal(ClientContext &context, vector &be // If null-padding is not allowed and there is a mismatch between our header candidate and the number of columns // We can't detect the dialect/type options properly if (!options.null_padding && best_sql_types_candidates_per_column_idx.size() != best_header_row.size()) { - if (options.ignore_errors.GetValue()) { - dialect_options.header = false; - for (idx_t col = 0; col < dialect_options.num_cols; col++) { - detected_names.push_back(GenerateColumnName(dialect_options.num_cols, col)); - } - dialect_options.rows_until_header += 1; - ReplaceNames(detected_names, state_machine, best_sql_types_candidates_per_column_idx, options, - best_header_row, error_handler); - return detected_names; - } auto error = CSVError::HeaderSniffingError(options, best_header_row, best_sql_types_candidates_per_column_idx.size(), state_machine.dialect_options.state_machine_options.delimiter.GetValue()); @@ -327,17 +281,16 @@ CSVSniffer::DetectHeaderInternal(ClientContext &context, vector &be } // If the user provided names, we must replace our header with the user provided names - ReplaceNames(detected_names, state_machine, best_sql_types_candidates_per_column_idx, options, best_header_row, - error_handler); + if (!options.columns_set) { + for (idx_t i = 0; i < MinValue(detected_names.size(), options.name_list.size()); i++) { + detected_names[i] = options.name_list[i]; + } + } return detected_names; } void CSVSniffer::DetectHeader() { auto &sniffer_state_machine = best_candidate->GetStateMachine(); names = DetectHeaderInternal(buffer_manager->context, best_header_row, sniffer_state_machine, set_columns, best_sql_types_candidates_per_column_idx, options, *error_handler); - for (idx_t i = max_columns_found; i < names.size(); i++) { - detected_types.push_back(LogicalType::VARCHAR); - } - max_columns_found = names.size(); } } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp b/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp index d6b2b1a6b..c4c31cbfe 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/sniffer/type_detection.cpp @@ -95,10 +95,6 @@ void CSVSniffer::SetDateFormat(CSVStateMachine &candidate, const string &format_ candidate.dialect_options.date_format[sql_type].Set(strpformat, false); } -idx_t CSVSniffer::LinesSniffed() const { - return lines_sniffed; -} - bool CSVSniffer::CanYouCastIt(ClientContext &context, const string_t value, const LogicalType &type, const DialectOptions &dialect_options, const bool is_null, const char decimal_separator) { if (is_null) { @@ -162,7 +158,7 @@ bool CSVSniffer::CanYouCastIt(ClientContext &context, const string_t value, cons idx_t pos; bool special; date_t dummy_value; - return Date::TryConvertDate(value_ptr, value_size, pos, dummy_value, special, true) == DateCastResult::SUCCESS; + return Date::TryConvertDate(value_ptr, value_size, pos, dummy_value, special, true); } case LogicalTypeId::TIMESTAMP: { timestamp_t dummy_value; @@ -296,10 +292,10 @@ void CSVSniffer::DetectDateAndTimeStampFormats(CSVStateMachine &candidate, const // check all formats and keep the first one that works StrpTimeFormat::ParseResult result; auto save_format_candidates = type_format_candidates; - const bool had_format_candidates = !save_format_candidates.empty(); - const bool initial_format_candidates = + bool had_format_candidates = !save_format_candidates.empty(); + bool initial_format_candidates = save_format_candidates.size() == original_format_candidates.at(sql_type.id()).format.size(); - const bool is_set_by_user = options.dialect_options.date_format.find(sql_type.id())->second.IsSetByUser(); + bool is_set_by_user = options.dialect_options.date_format.find(sql_type.id())->second.IsSetByUser(); while (!type_format_candidates.empty() && !is_set_by_user) { // avoid using exceptions for flow control... auto ¤t_format = candidate.dialect_options.date_format[sql_type.id()].GetValue(); @@ -371,9 +367,7 @@ void CSVSniffer::SniffTypes(DataChunk &data_chunk, CSVStateMachine &state_machin break; } - if (row_idx != start_idx_detection && - (cur_top_candidate == LogicalType::BOOLEAN || cur_top_candidate == LogicalType::DATE || - cur_top_candidate == LogicalType::TIME || cur_top_candidate == LogicalType::TIMESTAMP)) { + if (row_idx != start_idx_detection && cur_top_candidate == LogicalType::BOOLEAN) { // If we thought this was a boolean value (i.e., T,F, True, False) and it is not, we // immediately pop to varchar. while (col_type_candidates.back() != LogicalType::VARCHAR) { @@ -425,9 +419,19 @@ void CSVSniffer::DetectTypes() { SetUserDefinedDateTimeFormat(*candidate->state_machine); // Parse chunk and read csv with info candidate auto &data_chunk = candidate->ParseChunk().ToChunk(); - if (candidate->error_handler->AnyErrors() && !candidate->error_handler->HasError(MAXIMUM_LINE_SIZE) && - !candidate->state_machine->options.ignore_errors.GetValue()) { - continue; + if (!candidate->error_handler->errors.empty()) { + bool break_loop = false; + for (auto &errors : candidate->error_handler->errors) { + for (auto &error : errors.second) { + if (error.type != CSVErrorType::MAXIMUM_LINE_SIZE) { + break_loop = true; + break; + } + } + } + if (break_loop && !candidate->state_machine->options.ignore_errors.GetValue()) { + continue; + } } idx_t start_idx_detection = 0; idx_t chunk_size = data_chunk.size(); @@ -453,11 +457,11 @@ void CSVSniffer::DetectTypes() { // it's good if the dialect creates more non-varchar columns, but only if we sacrifice < 30% of // best_num_cols. - const idx_t number_of_errors = candidate->error_handler->GetSize(); - if (!best_candidate || (varchar_cols(info_sql_types_candidates.size())>( - static_cast(max_columns_found) * 0.7) && - (!options.ignore_errors.GetValue() || number_of_errors < min_errors))) { - min_errors = number_of_errors; + if (!best_candidate || + (varchar_cols(info_sql_types_candidates.size())>( + static_cast(max_columns_found) * 0.7) && + (!options.ignore_errors.GetValue() || candidate->error_handler->errors.size() < min_errors))) { + min_errors = candidate->error_handler->errors.size(); best_header_row.clear(); // we have a new best_options candidate best_candidate = std::move(candidate); diff --git a/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp b/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp index 29fda8863..9c40809cb 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/state_machine/csv_state_machine_cache.cpp @@ -22,22 +22,15 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op auto &transition_array = state_machine_cache[state_machine_options]; for (uint32_t i = 0; i < StateMachine::NUM_STATES; i++) { - const auto cur_state = static_cast(i); + CSVState cur_state = static_cast(i); switch (cur_state) { - case CSVState::MAYBE_QUOTED: case CSVState::QUOTED: case CSVState::QUOTED_NEW_LINE: case CSVState::ESCAPE: InitializeTransitionArray(transition_array, cur_state, CSVState::QUOTED); break; case CSVState::UNQUOTED: - if (state_machine_options.rfc_4180.GetValue()) { - // If we have an unquoted state, following rfc 4180, our base state is invalid - InitializeTransitionArray(transition_array, cur_state, CSVState::INVALID); - } else { - // This will allow us to accept unescaped quotes - InitializeTransitionArray(transition_array, cur_state, CSVState::UNQUOTED); - } + InitializeTransitionArray(transition_array, cur_state, CSVState::INVALID); break; case CSVState::COMMENT: InitializeTransitionArray(transition_array, cur_state, CSVState::COMMENT); @@ -48,118 +41,49 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op } } - const auto delimiter_value = state_machine_options.delimiter.GetValue(); - const auto delimiter_first_byte = static_cast(delimiter_value[0]); - const auto quote = static_cast(state_machine_options.quote.GetValue()); - const auto escape = static_cast(state_machine_options.escape.GetValue()); - const auto comment = static_cast(state_machine_options.comment.GetValue()); - - const auto new_line_id = state_machine_options.new_line.GetValue(); + uint8_t delimiter = static_cast(state_machine_options.delimiter.GetValue()); + uint8_t quote = static_cast(state_machine_options.quote.GetValue()); + uint8_t escape = static_cast(state_machine_options.escape.GetValue()); + uint8_t comment = static_cast(state_machine_options.comment.GetValue()); - const bool multi_byte_delimiter = delimiter_value.size() != 1; + auto new_line_id = state_machine_options.new_line.GetValue(); - const bool enable_unquoted_escape = state_machine_options.rfc_4180.GetValue() == false && - state_machine_options.quote != state_machine_options.escape && - state_machine_options.escape != '\0'; // Now set values depending on configuration // 1) Standard/Invalid State - const vector std_inv {static_cast(CSVState::STANDARD), static_cast(CSVState::INVALID), - static_cast(CSVState::STANDARD_NEWLINE)}; - for (const auto &state : std_inv) { - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][state] = CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][state] = CSVState::DELIMITER; - } + vector std_inv {static_cast(CSVState::STANDARD), static_cast(CSVState::INVALID)}; + for (auto &state : std_inv) { + transition_array[delimiter][state] = CSVState::DELIMITER; + transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; if (new_line_id == NewLineIdentifier::CARRY_ON) { transition_array[static_cast('\r')][state] = CSVState::CARRIAGE_RETURN; - if (state == static_cast(CSVState::STANDARD_NEWLINE)) { - transition_array[static_cast('\n')][state] = CSVState::STANDARD; - } else if (!state_machine_options.rfc_4180.GetValue()) { - transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; - } else { - transition_array[static_cast('\n')][state] = CSVState::INVALID; - } } else { transition_array[static_cast('\r')][state] = CSVState::RECORD_SEPARATOR; - transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; } if (comment != '\0') { transition_array[comment][state] = CSVState::COMMENT; } - if (enable_unquoted_escape) { - transition_array[escape][state] = CSVState::UNQUOTED_ESCAPE; - } } // 2) Field Separator State - if (quote != '\0') { - transition_array[quote][static_cast(CSVState::DELIMITER)] = CSVState::QUOTED; + transition_array[delimiter][static_cast(CSVState::DELIMITER)] = CSVState::DELIMITER; + transition_array[static_cast('\n')][static_cast(CSVState::DELIMITER)] = + CSVState::RECORD_SEPARATOR; + if (new_line_id == NewLineIdentifier::CARRY_ON) { + transition_array[static_cast('\r')][static_cast(CSVState::DELIMITER)] = + CSVState::CARRIAGE_RETURN; + } else { + transition_array[static_cast('\r')][static_cast(CSVState::DELIMITER)] = + CSVState::RECORD_SEPARATOR; } - if (delimiter_first_byte != ' ') { + transition_array[quote][static_cast(CSVState::DELIMITER)] = CSVState::QUOTED; + if (delimiter != ' ') { transition_array[' '][static_cast(CSVState::DELIMITER)] = CSVState::EMPTY_SPACE; } - - const vector delimiter_states { - static_cast(CSVState::DELIMITER), static_cast(CSVState::DELIMITER_FIRST_BYTE), - static_cast(CSVState::DELIMITER_SECOND_BYTE), static_cast(CSVState::DELIMITER_THIRD_BYTE)}; - - // These are the same transitions for all delimiter states - for (auto &state : delimiter_states) { - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][state] = CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][state] = CSVState::DELIMITER; - } - transition_array[static_cast('\n')][state] = CSVState::RECORD_SEPARATOR; - if (new_line_id == NewLineIdentifier::CARRY_ON) { - transition_array[static_cast('\r')][state] = CSVState::CARRIAGE_RETURN; - } else { - transition_array[static_cast('\r')][state] = CSVState::RECORD_SEPARATOR; - } - if (comment != '\0') { - transition_array[comment][static_cast(CSVState::DELIMITER)] = CSVState::COMMENT; - } - } - // Deal other multi-byte delimiters - if (delimiter_value.size() == 2) { - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_FIRST_BYTE)] = CSVState::DELIMITER; - } else if (delimiter_value.size() == 3) { - if (delimiter_value[0] == delimiter_value[1]) { - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_SECOND_BYTE)] = CSVState::DELIMITER_SECOND_BYTE; - } - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_FIRST_BYTE)] = CSVState::DELIMITER_SECOND_BYTE; - transition_array[static_cast(delimiter_value[2])] - [static_cast(CSVState::DELIMITER_SECOND_BYTE)] = CSVState::DELIMITER; - } else if (delimiter_value.size() == 4) { - if (delimiter_value[0] == delimiter_value[2]) { - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_THIRD_BYTE)] = CSVState::DELIMITER_SECOND_BYTE; - } - if (delimiter_value[0] == delimiter_value[1] && delimiter_value[1] == delimiter_value[2]) { - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_THIRD_BYTE)] = CSVState::DELIMITER_THIRD_BYTE; - } - transition_array[static_cast(delimiter_value[1])] - [static_cast(CSVState::DELIMITER_FIRST_BYTE)] = CSVState::DELIMITER_SECOND_BYTE; - transition_array[static_cast(delimiter_value[2])] - [static_cast(CSVState::DELIMITER_SECOND_BYTE)] = CSVState::DELIMITER_THIRD_BYTE; - transition_array[static_cast(delimiter_value[3])] - [static_cast(CSVState::DELIMITER_THIRD_BYTE)] = CSVState::DELIMITER; - } - if (enable_unquoted_escape) { - transition_array[escape][static_cast(CSVState::DELIMITER)] = CSVState::UNQUOTED_ESCAPE; + if (comment != '\0') { + transition_array[comment][static_cast(CSVState::DELIMITER)] = CSVState::COMMENT; } // 3) Record Separator State - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][static_cast(CSVState::RECORD_SEPARATOR)] = - CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::DELIMITER; - } + transition_array[delimiter][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::DELIMITER; transition_array[static_cast('\n')][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::RECORD_SEPARATOR; if (new_line_id == NewLineIdentifier::CARRY_ON) { @@ -169,44 +93,33 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array[static_cast('\r')][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::RECORD_SEPARATOR; } - if (quote != '\0') { - transition_array[quote][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::QUOTED; - } - if (delimiter_first_byte != ' ') { + transition_array[quote][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::QUOTED; + if (delimiter != ' ') { transition_array[' '][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::EMPTY_SPACE; } if (comment != '\0') { transition_array[comment][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::COMMENT; } - if (enable_unquoted_escape) { - transition_array[escape][static_cast(CSVState::RECORD_SEPARATOR)] = CSVState::UNQUOTED_ESCAPE; - } // 4) Carriage Return State transition_array[static_cast('\n')][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::RECORD_SEPARATOR; transition_array[static_cast('\r')][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::CARRIAGE_RETURN; - if (quote != '\0') { - transition_array[quote][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::QUOTED; - } - if (delimiter_first_byte != ' ') { + transition_array[quote][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::QUOTED; + if (delimiter != ' ') { transition_array[' '][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::EMPTY_SPACE; } if (comment != '\0') { transition_array[comment][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::COMMENT; } - if (enable_unquoted_escape) { - transition_array[escape][static_cast(CSVState::CARRIAGE_RETURN)] = CSVState::UNQUOTED_ESCAPE; - } // 5) Quoted State transition_array[quote][static_cast(CSVState::QUOTED)] = CSVState::UNQUOTED; transition_array['\n'][static_cast(CSVState::QUOTED)] = CSVState::QUOTED_NEW_LINE; transition_array['\r'][static_cast(CSVState::QUOTED)] = CSVState::QUOTED_NEW_LINE; - if (state_machine_options.quote != state_machine_options.escape && - state_machine_options.escape.GetValue() != '\0') { + if (state_machine_options.quote != state_machine_options.escape) { transition_array[escape][static_cast(CSVState::QUOTED)] = CSVState::ESCAPE; } // 6) Unquoted State @@ -218,38 +131,19 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array[static_cast('\r')][static_cast(CSVState::UNQUOTED)] = CSVState::RECORD_SEPARATOR; } - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][static_cast(CSVState::UNQUOTED)] = - CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][static_cast(CSVState::UNQUOTED)] = CSVState::DELIMITER; - } + transition_array[delimiter][static_cast(CSVState::UNQUOTED)] = CSVState::DELIMITER; if (state_machine_options.quote == state_machine_options.escape) { - transition_array[quote][static_cast(CSVState::UNQUOTED)] = CSVState::QUOTED; - } - if (state_machine_options.rfc_4180 == false) { - if (escape == '\0') { - // If escape is defined, it limits a bit how relaxed quotes can be in a reliable way. - transition_array[quote][static_cast(CSVState::UNQUOTED)] = CSVState::MAYBE_QUOTED; - } else { - transition_array[quote][static_cast(CSVState::UNQUOTED)] = CSVState::QUOTED; - } + transition_array[escape][static_cast(CSVState::UNQUOTED)] = CSVState::QUOTED; } if (comment != '\0') { transition_array[comment][static_cast(CSVState::UNQUOTED)] = CSVState::COMMENT; } - if (delimiter_first_byte != ' ' && quote != ' ' && escape != ' ' && comment != ' ') { - // If space is not a special character, we can safely ignore it in an unquoted state - transition_array[' '][static_cast(CSVState::UNQUOTED)] = CSVState::UNQUOTED; - } + // 7) Escaped State + transition_array[quote][static_cast(CSVState::ESCAPE)] = CSVState::QUOTED; + transition_array[escape][static_cast(CSVState::ESCAPE)] = CSVState::QUOTED; // 8) Not Set - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][static_cast(CSVState::NOT_SET)] = - CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][static_cast(CSVState::NOT_SET)] = CSVState::DELIMITER; - } + transition_array[delimiter][static_cast(CSVState::NOT_SET)] = CSVState::DELIMITER; transition_array[static_cast('\n')][static_cast(CSVState::NOT_SET)] = CSVState::RECORD_SEPARATOR; if (new_line_id == NewLineIdentifier::CARRY_ON) { transition_array[static_cast('\r')][static_cast(CSVState::NOT_SET)] = @@ -258,33 +152,21 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array[static_cast('\r')][static_cast(CSVState::NOT_SET)] = CSVState::RECORD_SEPARATOR; } - if (quote != '\0') { - transition_array[quote][static_cast(CSVState::NOT_SET)] = CSVState::QUOTED; - } - if (delimiter_first_byte != ' ') { + transition_array[quote][static_cast(CSVState::NOT_SET)] = CSVState::QUOTED; + if (delimiter != ' ') { transition_array[' '][static_cast(CSVState::NOT_SET)] = CSVState::EMPTY_SPACE; } if (comment != '\0') { transition_array[comment][static_cast(CSVState::NOT_SET)] = CSVState::COMMENT; } - if (enable_unquoted_escape) { - transition_array[escape][static_cast(CSVState::NOT_SET)] = CSVState::UNQUOTED_ESCAPE; - } - // 9) Quoted NewLine transition_array[quote][static_cast(CSVState::QUOTED_NEW_LINE)] = CSVState::UNQUOTED; - if (state_machine_options.quote != state_machine_options.escape && - state_machine_options.escape.GetValue() != '\0') { + if (state_machine_options.quote != state_machine_options.escape) { transition_array[escape][static_cast(CSVState::QUOTED_NEW_LINE)] = CSVState::ESCAPE; } // 10) Empty Value State (Not first value) - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][static_cast(CSVState::EMPTY_SPACE)] = - CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][static_cast(CSVState::EMPTY_SPACE)] = CSVState::DELIMITER; - } + transition_array[delimiter][static_cast(CSVState::EMPTY_SPACE)] = CSVState::DELIMITER; transition_array[static_cast('\n')][static_cast(CSVState::EMPTY_SPACE)] = CSVState::RECORD_SEPARATOR; if (new_line_id == NewLineIdentifier::CARRY_ON) { @@ -294,15 +176,10 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array[static_cast('\r')][static_cast(CSVState::EMPTY_SPACE)] = CSVState::RECORD_SEPARATOR; } - if (quote != '\0') { - transition_array[quote][static_cast(CSVState::EMPTY_SPACE)] = CSVState::QUOTED; - } + transition_array[quote][static_cast(CSVState::EMPTY_SPACE)] = CSVState::QUOTED; if (comment != '\0') { transition_array[comment][static_cast(CSVState::EMPTY_SPACE)] = CSVState::COMMENT; } - if (enable_unquoted_escape) { - transition_array[escape][static_cast(CSVState::EMPTY_SPACE)] = CSVState::UNQUOTED_ESCAPE; - } // 11) Comment State transition_array[static_cast('\n')][static_cast(CSVState::COMMENT)] = CSVState::RECORD_SEPARATOR; @@ -314,52 +191,6 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op CSVState::RECORD_SEPARATOR; } - // 12) Unquoted Escape State - if (enable_unquoted_escape) { - // Any character can be escaped, so default to STANDARD - if (new_line_id == NewLineIdentifier::CARRY_ON) { - transition_array[static_cast('\r')][static_cast(CSVState::UNQUOTED_ESCAPE)] = - CSVState::ESCAPED_RETURN; - } - } - - // 13) Escaped Return State - if (enable_unquoted_escape) { - // The new state is STANDARD for \r + \n and \r + ordinary character. - // Other special characters need to be handled. - transition_array[delimiter_first_byte][static_cast(CSVState::ESCAPED_RETURN)] = CSVState::DELIMITER; - if (new_line_id == NewLineIdentifier::CARRY_ON) { - transition_array[static_cast('\r')][static_cast(CSVState::ESCAPED_RETURN)] = - CSVState::CARRIAGE_RETURN; - } else { - transition_array[static_cast('\r')][static_cast(CSVState::ESCAPED_RETURN)] = - CSVState::RECORD_SEPARATOR; - } - if (comment != '\0') { - transition_array[comment][static_cast(CSVState::ESCAPED_RETURN)] = CSVState::COMMENT; - } - transition_array[escape][static_cast(CSVState::ESCAPED_RETURN)] = CSVState::UNQUOTED_ESCAPE; - } - - // 14) Maybe quoted - transition_array[quote][static_cast(CSVState::MAYBE_QUOTED)] = CSVState::MAYBE_QUOTED; - - transition_array[static_cast('\n')][static_cast(CSVState::MAYBE_QUOTED)] = - CSVState::RECORD_SEPARATOR; - if (new_line_id == NewLineIdentifier::CARRY_ON) { - transition_array[static_cast('\r')][static_cast(CSVState::MAYBE_QUOTED)] = - CSVState::CARRIAGE_RETURN; - } else { - transition_array[static_cast('\r')][static_cast(CSVState::MAYBE_QUOTED)] = - CSVState::RECORD_SEPARATOR; - } - if (multi_byte_delimiter) { - transition_array[delimiter_first_byte][static_cast(CSVState::MAYBE_QUOTED)] = - CSVState::DELIMITER_FIRST_BYTE; - } else { - transition_array[delimiter_first_byte][static_cast(CSVState::MAYBE_QUOTED)] = CSVState::DELIMITER; - } - // Initialize characters we can skip during processing, for Standard and Quoted states for (idx_t i = 0; i < StateMachine::NUM_TRANSITIONS; i++) { transition_array.skip_standard[i] = true; @@ -367,13 +198,10 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array.skip_comment[i] = true; } // For standard states we only care for delimiters \r and \n - transition_array.skip_standard[delimiter_first_byte] = false; + transition_array.skip_standard[delimiter] = false; transition_array.skip_standard[static_cast('\n')] = false; transition_array.skip_standard[static_cast('\r')] = false; transition_array.skip_standard[comment] = false; - if (enable_unquoted_escape) { - transition_array.skip_standard[escape] = false; - } // For quoted we only care about quote, escape and for delimiters \r and \n transition_array.skip_quoted[quote] = false; @@ -384,7 +212,7 @@ void CSVStateMachineCache::Insert(const CSVStateMachineOptions &state_machine_op transition_array.skip_comment[static_cast('\r')] = false; transition_array.skip_comment[static_cast('\n')] = false; - transition_array.delimiter = delimiter_first_byte; + transition_array.delimiter = delimiter; transition_array.new_line = static_cast('\n'); transition_array.carriage_return = static_cast('\r'); transition_array.quote = quote; @@ -413,11 +241,9 @@ CSVStateMachineCache::CSVStateMachineCache() { const auto &escape_candidates = default_escape[static_cast(quote_rule)]; for (const auto &escape : escape_candidates) { for (const auto &comment : default_comment) { - for (const bool rfc_4180 : {true, false}) { - Insert({delimiter, quote, escape, comment, NewLineIdentifier::SINGLE_N, rfc_4180}); - Insert({delimiter, quote, escape, comment, NewLineIdentifier::SINGLE_R, rfc_4180}); - Insert({delimiter, quote, escape, comment, NewLineIdentifier::CARRY_ON, rfc_4180}); - } + Insert({delimiter, quote, escape, comment, NewLineIdentifier::SINGLE_N}); + Insert({delimiter, quote, escape, comment, NewLineIdentifier::SINGLE_R}); + Insert({delimiter, quote, escape, comment, NewLineIdentifier::CARRY_ON}); } } } diff --git a/src/duckdb/src/execution/operator/csv_scanner/table_function/csv_file_scanner.cpp b/src/duckdb/src/execution/operator/csv_scanner/table_function/csv_file_scanner.cpp index 093e698d0..3e457580c 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/table_function/csv_file_scanner.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/table_function/csv_file_scanner.cpp @@ -10,7 +10,7 @@ CSVUnionData::~CSVUnionData() { CSVFileScan::CSVFileScan(ClientContext &context, shared_ptr buffer_manager_p, shared_ptr state_machine_p, const CSVReaderOptions &options_p, - const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema) + const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema) : file_path(options_p.file_path), file_idx(0), buffer_manager(std::move(buffer_manager_p)), state_machine(std::move(state_machine_p)), file_size(buffer_manager->file_handle->FileSize()), error_handler(make_shared_ptr(options_p.ignore_errors.GetValue())), @@ -60,7 +60,7 @@ void CSVFileScan::SetStart() { } CSVFileScan::CSVFileScan(ClientContext &context, const string &file_path_p, const CSVReaderOptions &options_p, - idx_t file_idx_p, const ReadCSVData &bind_data, const vector &column_ids, + const idx_t file_idx_p, const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema, bool per_file_single_threaded) : file_path(file_path_p), file_idx(file_idx_p), error_handler(make_shared_ptr(options_p.ignore_errors.GetValue())), options(options_p) { @@ -125,7 +125,7 @@ CSVFileScan::CSVFileScan(ClientContext &context, const string &file_path_p, cons if (file_schema.Empty()) { CSVSniffer sniffer(options, buffer_manager, state_machine_cache); auto result = sniffer.SniffCSV(); - file_schema.Initialize(bind_data.csv_names, bind_data.csv_types, options.file_path); + file_schema.Initialize(result.names, result.return_types, options.file_path); } else if (file_idx > 0 && buffer_manager->file_handle->FileSize() > 0) { options.file_path = file_path; CSVSniffer sniffer(options, buffer_manager, state_machine_cache, false); @@ -159,8 +159,7 @@ CSVFileScan::CSVFileScan(ClientContext &context, const string &file_name, const // Sniff it (We only really care about dialect detection, if types or number of columns are different this will // error out during scanning) auto &state_machine_cache = CSVStateMachineCache::Get(context); - // We sniff file if it has not been sniffed yet and either auto-detect is on, or union by name is on - if ((options.auto_detect || options.file_options.union_by_name) && options.dialect_options.num_cols == 0) { + if (options.auto_detect && options.dialect_options.num_cols == 0) { CSVSniffer sniffer(options, buffer_manager, state_machine_cache); auto sniffer_result = sniffer.SniffCSV(); if (names.empty()) { diff --git a/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp b/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp index b1a4a6165..cefb13413 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/table_function/global_csv_state.cpp @@ -1,4 +1,5 @@ #include "duckdb/execution/operator/csv_scanner/global_csv_state.hpp" + #include "duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp" #include "duckdb/execution/operator/csv_scanner/scanner_boundary.hpp" #include "duckdb/execution/operator/csv_scanner/skip_scanner.hpp" @@ -10,7 +11,7 @@ namespace duckdb { CSVGlobalState::CSVGlobalState(ClientContext &context_p, const shared_ptr &buffer_manager, const CSVReaderOptions &options, idx_t system_threads_p, const vector &files, - vector column_ids_p, const ReadCSVData &bind_data_p) + vector column_ids_p, const ReadCSVData &bind_data_p) : context(context_p), system_threads(system_threads_p), column_ids(std::move(column_ids_p)), sniffer_mismatch_error(options.sniffer_user_mismatch_error), bind_data(bind_data_p) { @@ -24,21 +25,15 @@ CSVGlobalState::CSVGlobalState(ClientContext &context_p, const shared_ptr(context, files[0], options, 0U, bind_data, column_ids, file_schema, false)); - } - idx_t cur_file_idx = 0; - while (file_scans.back()->start_iterator.done && file_scans.size() < files.size()) { - cur_file_idx++; - file_scans.emplace_back(make_uniq(context, files[cur_file_idx], options, cur_file_idx, bind_data, - column_ids, file_schema, false)); - } + }; // There are situations where we only support single threaded scanning bool many_csv_files = files.size() > 1 && files.size() > system_threads * 2; single_threaded = many_csv_files || !options.parallel; last_file_idx = 0; scanner_idx = 0; - running_threads = CSVGlobalState::MaxThreads(); + running_threads = MaxThreads(); current_boundary = file_scans.back()->start_iterator; - current_boundary.SetCurrentBoundaryToPosition(single_threaded, options); + current_boundary.SetCurrentBoundaryToPosition(single_threaded); if (current_boundary.done && context.client_data->debug_set_max_line_length) { context.client_data->debug_max_line_length = current_boundary.pos.buffer_pos; } @@ -59,7 +54,7 @@ double CSVGlobalState::GetProgress(const ReadCSVData &bind_data_p) const { if (file_scans.front()->file_size == 0) { percentage = 1.0; } else { - // for compressed files, read bytes may greater than files size. + // for compressed files, readed bytes may greater than files size. for (auto &file : file_scans) { double file_progress; if (!file->buffer_manager) { @@ -73,30 +68,14 @@ double CSVGlobalState::GetProgress(const ReadCSVData &bind_data_p) const { file_progress = static_cast(file->bytes_read); } // This file is an uncompressed file, so we use the more price bytes_read from the scanner - percentage += (static_cast(1) / static_cast(total_files)) * - std::min(1.0, file_progress / static_cast(file->file_size)); + percentage += (double(1) / double(total_files)) * std::min(1.0, file_progress / double(file->file_size)); } } return percentage * 100; } unique_ptr CSVGlobalState::Next(optional_ptr previous_scanner) { - if (previous_scanner) { - // We have to insert information for validation - lock_guard parallel_lock(main_mutex); - validator.Insert(previous_scanner->csv_file_scan->file_idx, previous_scanner->scanner_idx, - previous_scanner->GetValidationLine()); - } if (single_threaded) { - { - lock_guard parallel_lock(main_mutex); - if (previous_scanner) { - // Cleanup previous scanner. - previous_scanner->buffer_tracker.reset(); - current_buffer_in_use.reset(); - previous_scanner->csv_file_scan->Finish(); - } - } idx_t cur_idx; bool empty_file = false; do { @@ -118,16 +97,19 @@ unique_ptr CSVGlobalState::Next(optional_ptr(context, bind_data.files[cur_idx], bind_data.options, cur_idx, bind_data, column_ids, file_schema, true); empty_file = file_scan->file_size == 0; - if (!empty_file) { lock_guard parallel_lock(main_mutex); file_scans.emplace_back(std::move(file_scan)); auto current_file = file_scans.back(); current_boundary = current_file->start_iterator; - current_boundary.SetCurrentBoundaryToPosition(single_threaded, bind_data.options); + current_boundary.SetCurrentBoundaryToPosition(single_threaded); current_buffer_in_use = make_shared_ptr(*file_scans.back()->buffer_manager, current_boundary.GetBufferIdx()); - + if (previous_scanner) { + previous_scanner->buffer_tracker.reset(); + current_buffer_in_use.reset(); + previous_scanner->csv_file_scan->Finish(); + } return make_uniq(scanner_idx++, current_file->buffer_manager, current_file->state_machine, current_file->error_handler, current_file, false, current_boundary); @@ -158,7 +140,7 @@ unique_ptr CSVGlobalState::Next(optional_ptrbuffer_tracker = current_buffer_in_use; // We then produce the next boundary - if (!current_boundary.Next(*current_file.buffer_manager, bind_data.options)) { + if (!current_boundary.Next(*current_file.buffer_manager)) { // This means we are done scanning the current file do { auto current_file_idx = file_scans.back()->file_idx + 1; @@ -169,7 +151,7 @@ unique_ptr CSVGlobalState::Next(optional_ptrstart_iterator; - current_boundary.SetCurrentBoundaryToPosition(single_threaded, bind_data.options); + current_boundary.SetCurrentBoundaryToPosition(single_threaded); current_buffer_in_use = make_shared_ptr(*file_scans.back()->buffer_manager, current_boundary.GetBufferIdx()); } else { @@ -185,11 +167,11 @@ unique_ptr CSVGlobalState::Next(optional_ptron_disk_file) { + if (single_threaded) { return system_threads; } - const idx_t bytes_per_thread = CSVIterator::BytesPerThread(file_scans.front()->options); - const idx_t total_threads = file_scans.front()->file_size / bytes_per_thread + 1; + idx_t total_threads = file_scans.front()->file_size / CSVIterator::BYTES_PER_THREAD + 1; + if (total_threads < system_threads) { return total_threads; } @@ -201,13 +183,7 @@ void CSVGlobalState::DecrementThread() { D_ASSERT(running_threads > 0); running_threads--; if (running_threads == 0) { - const bool ignore_or_store_errors = - bind_data.options.ignore_errors.GetValue() || bind_data.options.store_rejects.GetValue(); - if (!single_threaded && !ignore_or_store_errors) { - // If we are running multithreaded and not ignoring errors, we must run the validator - validator.Verify(); - } - for (const auto &file : file_scans) { + for (auto &file : file_scans) { file->error_handler->ErrorIfNeeded(); } FillRejectsTable(); @@ -217,6 +193,39 @@ void CSVGlobalState::DecrementThread() { } } +bool IsCSVErrorAcceptedReject(CSVErrorType type) { + switch (type) { + case CSVErrorType::CAST_ERROR: + case CSVErrorType::TOO_MANY_COLUMNS: + case CSVErrorType::TOO_FEW_COLUMNS: + case CSVErrorType::MAXIMUM_LINE_SIZE: + case CSVErrorType::UNTERMINATED_QUOTES: + case CSVErrorType::INVALID_UNICODE: + return true; + default: + return false; + } +} + +string CSVErrorTypeToEnum(CSVErrorType type) { + switch (type) { + case CSVErrorType::CAST_ERROR: + return "CAST"; + case CSVErrorType::TOO_FEW_COLUMNS: + return "MISSING COLUMNS"; + case CSVErrorType::TOO_MANY_COLUMNS: + return "TOO MANY COLUMNS"; + case CSVErrorType::MAXIMUM_LINE_SIZE: + return "LINE SIZE OVER MAXIMUM"; + case CSVErrorType::UNTERMINATED_QUOTES: + return "UNQUOTED VALUE"; + case CSVErrorType::INVALID_UNICODE: + return "INVALID UNICODE"; + default: + throw InternalException("CSV Error is not valid to be stored in a Rejects Table"); + } +} + void FillScanErrorTable(InternalAppender &scan_appender, idx_t scan_idx, idx_t file_idx, CSVFileScan &file) { CSVReaderOptions &options = file.options; // Add the row to the rejects table @@ -276,7 +285,7 @@ void FillScanErrorTable(InternalAppender &scan_appender, idx_t scan_idx, idx_t f scan_appender.EndRow(); } -void CSVGlobalState::FillRejectsTable() const { +void CSVGlobalState::FillRejectsTable() { auto &options = bind_data.options; if (options.store_rejects.GetValue()) { @@ -290,10 +299,70 @@ void CSVGlobalState::FillRejectsTable() const { InternalAppender scans_appender(context, scans_table); idx_t scan_idx = context.transaction.GetActiveQuery(); for (auto &file : file_scans) { - const idx_t file_idx = rejects->GetCurrentFileIndex(scan_idx); + idx_t file_idx = rejects->GetCurrentFileIndex(scan_idx); auto file_name = file->file_path; - file->error_handler->FillRejectsTable(errors_appender, file_idx, scan_idx, *file, *rejects, bind_data, - limit); + auto &errors = file->error_handler->errors; + // We first insert the file into the file scans table + for (auto &error_vector : errors) { + for (auto &error : error_vector.second) { + if (!IsCSVErrorAcceptedReject(error.type)) { + continue; + } + // short circuit if we already have too many rejects + if (limit == 0 || rejects->count < limit) { + if (limit != 0 && rejects->count >= limit) { + break; + } + rejects->count++; + auto row_line = file->error_handler->GetLine(error.error_info); + auto col_idx = error.column_idx; + // Add the row to the rejects table + errors_appender.BeginRow(); + // 1. Scan Id + errors_appender.Append(scan_idx); + // 2. File Id + errors_appender.Append(file_idx); + // 3. Row Line + errors_appender.Append(row_line); + // 4. Byte Position of the row error + errors_appender.Append(error.row_byte_position + 1); + // 5. Byte Position where error occurred + if (!error.byte_position.IsValid()) { + // This means this error comes from a flush, and we don't support this yet, so we give it + // a null + errors_appender.Append(Value()); + } else { + errors_appender.Append(error.byte_position.GetIndex() + 1); + } + // 6. Column Index + if (error.type == CSVErrorType::MAXIMUM_LINE_SIZE) { + errors_appender.Append(Value()); + } else { + errors_appender.Append(col_idx + 1); + } + // 7. Column Name (If Applicable) + switch (error.type) { + case CSVErrorType::TOO_MANY_COLUMNS: + case CSVErrorType::MAXIMUM_LINE_SIZE: + errors_appender.Append(Value()); + break; + case CSVErrorType::TOO_FEW_COLUMNS: + D_ASSERT(bind_data.return_names.size() > col_idx + 1); + errors_appender.Append(string_t(bind_data.return_names[col_idx + 1])); + break; + default: + errors_appender.Append(string_t(bind_data.return_names[col_idx])); + } + // 8. Error Type + errors_appender.Append(string_t(CSVErrorTypeToEnum(error.type))); + // 9. Original CSV Line + errors_appender.Append(string_t(error.csv_row)); + // 10. Full Error Message + errors_appender.Append(string_t(error.error_message)); + errors_appender.EndRow(); + } + } + } if (rejects->count != 0) { rejects->count = 0; FillScanErrorTable(scans_appender, scan_idx, file_idx, *file); diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp index f77a93ac0..d382fdd38 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/util/csv_error.cpp @@ -1,10 +1,7 @@ #include "duckdb/execution/operator/csv_scanner/csv_error.hpp" #include "duckdb/common/exception/conversion_exception.hpp" #include "duckdb/common/string_util.hpp" -#include "duckdb/function/table/read_csv.hpp" -#include "duckdb/execution/operator/persistent/csv_rejects_table.hpp" -#include "duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp" -#include "duckdb/main/appender.hpp" + #include namespace duckdb { @@ -44,11 +41,11 @@ void CSVErrorHandler::ThrowError(const CSVError &csv_error) { } } -void CSVErrorHandler::Error(const CSVError &csv_error, bool force_error) { +void CSVErrorHandler::Error(CSVError csv_error, bool force_error) { lock_guard parallel_lock(main_mutex); if ((ignore_errors && !force_error) || (PrintLineNumber(csv_error) && !CanGetLine(csv_error.GetBoundaryIndex()))) { // We store this error, we can't throw it now, or we are ignoring it - errors.push_back(csv_error); + errors[csv_error.error_info].push_back(std::move(csv_error)); return; } // Otherwise we can throw directly @@ -61,19 +58,10 @@ void CSVErrorHandler::ErrorIfNeeded() { // Nothing to error return; } + CSVError first_error = errors.begin()->second[0]; - if (CanGetLine(errors[0].error_info.boundary_idx)) { - ThrowError(errors[0]); - } -} - -void CSVErrorHandler::ErrorIfTypeExists(CSVErrorType error_type) { - lock_guard parallel_lock(main_mutex); - for (auto &error : errors) { - if (error.type == error_type) { - // If it's a maximum line size error, we can do it now. - ThrowError(error); - } + if (CanGetLine(first_error.error_info.boundary_idx)) { + ThrowError(first_error); } } @@ -96,136 +84,6 @@ bool CSVErrorHandler::AnyErrors() { return !errors.empty(); } -bool CSVErrorHandler::HasError(const CSVErrorType error_type) { - lock_guard parallel_lock(main_mutex); - for (const auto &er : errors) { - if (er.type == error_type) { - return true; - } - } - return false; -} - -idx_t CSVErrorHandler::GetSize() { - lock_guard parallel_lock(main_mutex); - return errors.size(); -} - -bool IsCSVErrorAcceptedReject(CSVErrorType type) { - switch (type) { - case CSVErrorType::INVALID_STATE: - case CSVErrorType::CAST_ERROR: - case CSVErrorType::TOO_MANY_COLUMNS: - case CSVErrorType::TOO_FEW_COLUMNS: - case CSVErrorType::MAXIMUM_LINE_SIZE: - case CSVErrorType::UNTERMINATED_QUOTES: - case CSVErrorType::INVALID_UNICODE: - return true; - default: - return false; - } -} -string CSVErrorTypeToEnum(CSVErrorType type) { - switch (type) { - case CSVErrorType::CAST_ERROR: - return "CAST"; - case CSVErrorType::TOO_FEW_COLUMNS: - return "MISSING COLUMNS"; - case CSVErrorType::TOO_MANY_COLUMNS: - return "TOO MANY COLUMNS"; - case CSVErrorType::MAXIMUM_LINE_SIZE: - return "LINE SIZE OVER MAXIMUM"; - case CSVErrorType::UNTERMINATED_QUOTES: - return "UNQUOTED VALUE"; - case CSVErrorType::INVALID_UNICODE: - return "INVALID UNICODE"; - case CSVErrorType::INVALID_STATE: - return "INVALID STATE"; - default: - throw InternalException("CSV Error is not valid to be stored in a Rejects Table"); - } -} - -void CSVErrorHandler::FillRejectsTable(InternalAppender &errors_appender, const idx_t file_idx, const idx_t scan_idx, - const CSVFileScan &file, CSVRejectsTable &rejects, const ReadCSVData &bind_data, - const idx_t limit) { - lock_guard parallel_lock(main_mutex); - // We first insert the file into the file scans table - for (auto &error : file.error_handler->errors) { - if (!IsCSVErrorAcceptedReject(error.type)) { - continue; - } - // short circuit if we already have too many rejects - if (limit == 0 || rejects.count < limit) { - if (limit != 0 && rejects.count >= limit) { - break; - } - rejects.count++; - const auto row_line = file.error_handler->GetLineInternal(error.error_info); - const auto col_idx = error.column_idx; - // Add the row to the rejects table - errors_appender.BeginRow(); - // 1. Scan ID - errors_appender.Append(scan_idx); - // 2. File ID - errors_appender.Append(file_idx); - // 3. Row Line - errors_appender.Append(row_line); - // 4. Byte Position of the row error - errors_appender.Append(error.row_byte_position + 1); - // 5. Byte Position where error occurred - if (!error.byte_position.IsValid()) { - // This means this error comes from a flush, and we don't support this yet, so we give it - // a null - errors_appender.Append(Value()); - } else { - errors_appender.Append(error.byte_position.GetIndex() + 1); - } - // 6. Column Index - if (error.type == CSVErrorType::MAXIMUM_LINE_SIZE) { - errors_appender.Append(Value()); - } else { - errors_appender.Append(col_idx + 1); - } - // 7. Column Name (If Applicable) - switch (error.type) { - case CSVErrorType::TOO_MANY_COLUMNS: - case CSVErrorType::MAXIMUM_LINE_SIZE: - errors_appender.Append(Value()); - break; - case CSVErrorType::TOO_FEW_COLUMNS: - D_ASSERT(bind_data.return_names.size() > col_idx + 1); - errors_appender.Append(string_t(bind_data.return_names[col_idx + 1])); - break; - default: - errors_appender.Append(string_t(bind_data.return_names[col_idx])); - } - // 8. Error Type - errors_appender.Append(string_t(CSVErrorTypeToEnum(error.type))); - // 9. Original CSV Line - errors_appender.Append(string_t(error.csv_row)); - // 10. Full Error Message - errors_appender.Append(string_t(error.error_message)); - errors_appender.EndRow(); - } - } -} - -idx_t CSVErrorHandler::GetMaxLineLength() { - lock_guard parallel_lock(main_mutex); - return max_line_length; -} - -void CSVErrorHandler::DontPrintErrorLine() { - lock_guard parallel_lock(main_mutex); - print_line = false; -} - -void CSVErrorHandler::SetIgnoreErrors(bool ignore_errors_p) { - lock_guard parallel_lock(main_mutex); - ignore_errors = ignore_errors_p; -} - CSVError::CSVError(string error_message_p, CSVErrorType type_p, LinesPerBoundary error_info_p) : error_message(std::move(error_message_p)), type(type_p), error_info(error_info_p) { } @@ -252,6 +110,7 @@ CSVError CSVError::ColumnTypesError(case_insensitive_map_t sql_types_per_ auto it = sql_types_per_column.find(names[i]); if (it != sql_types_per_column.end()) { sql_types_per_column.erase(names[i]); + continue; } } if (sql_types_per_column.empty()) { @@ -301,36 +160,22 @@ CSVError CSVError::CastError(const CSVReaderOptions &options, string &column_nam how_to_fix_it.str(), current_path); } -CSVError CSVError::LineSizeError(const CSVReaderOptions &options, LinesPerBoundary error_info, string &csv_row, - idx_t byte_position, const string ¤t_path) { +CSVError CSVError::LineSizeError(const CSVReaderOptions &options, idx_t actual_size, LinesPerBoundary error_info, + string &csv_row, idx_t byte_position, const string ¤t_path) { std::ostringstream error; - error << "Maximum line size of " << options.maximum_line_size.GetValue() << " bytes exceeded. "; - error << "Actual Size:" << csv_row.size() << " bytes." << '\n'; + error << "Maximum line size of " << options.maximum_line_size << " bytes exceeded. "; + error << "Actual Size:" << actual_size << " bytes." << '\n'; std::ostringstream how_to_fix_it; - how_to_fix_it << "Possible Solution: Change the maximum length size, e.g., max_line_size=" << csv_row.size() + 2 + how_to_fix_it << "Possible Solution: Change the maximum length size, e.g., max_line_size=" << actual_size + 1 << "\n"; return CSVError(error.str(), MAXIMUM_LINE_SIZE, 0, csv_row, error_info, byte_position, byte_position, options, how_to_fix_it.str(), current_path); } -CSVError CSVError::InvalidState(const CSVReaderOptions &options, idx_t current_column, LinesPerBoundary error_info, - string &csv_row, idx_t row_byte_position, optional_idx byte_position, - const string ¤t_path) { - std::ostringstream error; - error << "The CSV Parser state machine reached an invalid state.\nThis can happen when is not possible to parse " - "your CSV File with the given options, or the CSV File is not RFC 4180 compliant "; - - std::ostringstream how_to_fix_it; - how_to_fix_it << "Possible fixes:" << '\n'; - how_to_fix_it << "* Enable scanning files that are not RFC 4180 compliant (rfc_4180=false)." << '\n'; - - return CSVError(error.str(), INVALID_STATE, current_column, csv_row, error_info, row_byte_position, byte_position, - options, how_to_fix_it.str(), current_path); -} CSVError CSVError::HeaderSniffingError(const CSVReaderOptions &options, const vector &best_header_row, - const idx_t column_count, const string &delimiter) { + idx_t column_count, char delimiter) { std::ostringstream error; // 1. Which file error << "Error when sniffing file \"" << options.file_path << "\"." << '\n'; @@ -378,7 +223,6 @@ CSVError CSVError::HeaderSniffingError(const CSVReaderOptions &options, const ve if (!options.null_padding) { error << "* Enable null padding (null_padding=true) to pad missing columns with NULL values" << '\n'; } - return CSVError(error.str(), SNIFFING, {}); } @@ -437,14 +281,7 @@ CSVError CSVError::SniffingError(const CSVReaderOptions &options, const string & } error << "* Check you are using the correct file compression, otherwise set it (e.g., compression = \'zstd\')" << '\n'; - error << "* Be sure that the maximum line size is set to an appropriate value, otherwise set it (e.g., " - "max_line_size=10000000)" - << "\n"; - if (options.dialect_options.state_machine_options.rfc_4180.GetValue() != false || - !options.dialect_options.state_machine_options.rfc_4180.IsSetByUser()) { - error << "* Enable scanning files that are not RFC 4180 compliant (rfc_4180=false). " << '\n'; - } return CSVError(error.str(), SNIFFING, {}); } @@ -467,7 +304,7 @@ CSVError CSVError::UnterminatedQuotesError(const CSVReaderOptions &options, idx_ std::ostringstream how_to_fix_it; how_to_fix_it << "Possible fixes:" << '\n'; how_to_fix_it << "* Enable ignore errors (ignore_errors=true) to skip this row" << '\n'; - how_to_fix_it << "* Set quote to empty or to a different value (e.g., quote=\'\')" << '\n'; + how_to_fix_it << "* Set quote do empty or to a different value (e.g., quote=\'\')" << '\n'; return CSVError(error.str(), UNTERMINATED_QUOTES, current_column, csv_row, error_info, row_byte_position, byte_position, options, how_to_fix_it.str(), current_path); } @@ -487,13 +324,12 @@ CSVError CSVError::IncorrectColumnAmountError(const CSVReaderOptions &options, i } // How many columns were expected and how many were found error << "Expected Number of Columns: " << options.dialect_options.num_cols << " Found: " << actual_columns + 1; - idx_t byte_pos = byte_position.GetIndex() == 0 ? 0 : byte_position.GetIndex() - 1; if (actual_columns >= options.dialect_options.num_cols) { - return CSVError(error.str(), TOO_MANY_COLUMNS, actual_columns, csv_row, error_info, row_byte_position, byte_pos, - options, how_to_fix_it.str(), current_path); + return CSVError(error.str(), TOO_MANY_COLUMNS, actual_columns, csv_row, error_info, row_byte_position, + byte_position.GetIndex() - 1, options, how_to_fix_it.str(), current_path); } else { - return CSVError(error.str(), TOO_FEW_COLUMNS, actual_columns, csv_row, error_info, row_byte_position, byte_pos, - options, how_to_fix_it.str(), current_path); + return CSVError(error.str(), TOO_FEW_COLUMNS, actual_columns, csv_row, error_info, row_byte_position, + byte_position.GetIndex() - 1, options, how_to_fix_it.str(), current_path); } } diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp index ac18d42eb..97fb22a99 100644 --- a/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp +++ b/src/duckdb/src/execution/operator/csv_scanner/util/csv_reader_options.cpp @@ -8,16 +8,6 @@ namespace duckdb { -CSVReaderOptions::CSVReaderOptions(const CSVOption single_byte_delimiter, - const CSVOption &multi_byte_delimiter) { - if (multi_byte_delimiter.GetValue().empty()) { - const char single_byte_value = single_byte_delimiter.GetValue(); - const string value(1, single_byte_value); - dialect_options.state_machine_options.delimiter = value; - } else { - dialect_options.state_machine_options.delimiter = multi_byte_delimiter; - } -} static bool ParseBoolean(const Value &value, const string &loption); static bool ParseBoolean(const vector &set, const string &loption) { @@ -32,9 +22,7 @@ static bool ParseBoolean(const vector &set, const string &loption) { } static bool ParseBoolean(const Value &value, const string &loption) { - if (value.IsNull()) { - throw BinderException("\"%s\" expects a non-null boolean value (e.g. TRUE or 1)", loption); - } + if (value.type().id() == LogicalTypeId::LIST) { auto &children = ListValue::GetChildren(value); return ParseBoolean(children, loption); @@ -64,9 +52,6 @@ static string ParseString(const Value &value, const string &loption) { } static int64_t ParseInteger(const Value &value, const string &loption) { - if (value.IsNull()) { - throw BinderException("\"%s\" expects a non-null integer value", loption); - } if (value.type().id() == LogicalTypeId::LIST) { auto &children = ListValue::GetChildren(value); if (children.size() != 1) { @@ -117,18 +102,18 @@ void CSVReaderOptions::SetSkipRows(int64_t skip_rows) { } string CSVReaderOptions::GetDelimiter() const { - return this->dialect_options.state_machine_options.delimiter.GetValue(); + return std::string(1, this->dialect_options.state_machine_options.delimiter.GetValue()); } void CSVReaderOptions::SetDelimiter(const string &input) { auto delim_str = StringUtil::Replace(input, "\\t", "\t"); - if (delim_str.size() > 4) { - throw InvalidInputException("The delimiter option cannot exceed a size of 4 bytes."); + if (delim_str.size() > 1) { + throw InvalidInputException("The delimiter option cannot exceed a size of 1 byte."); } if (input.empty()) { delim_str = string("\0", 1); } - this->dialect_options.state_machine_options.delimiter.Set(delim_str); + this->dialect_options.state_machine_options.delimiter.Set(delim_str[0]); } string CSVReaderOptions::GetQuote() const { @@ -188,26 +173,10 @@ void CSVReaderOptions::SetNewline(const string &input) { } } -bool CSVReaderOptions::GetRFC4180() const { - return this->dialect_options.state_machine_options.rfc_4180.GetValue(); -} - -void CSVReaderOptions::SetRFC4180(bool input) { - this->dialect_options.state_machine_options.rfc_4180.Set(input); -} - bool CSVReaderOptions::IgnoreErrors() const { return ignore_errors.GetValue() && !store_rejects.GetValue(); } -char CSVReaderOptions::GetSingleByteDelimiter() const { - return dialect_options.state_machine_options.delimiter.GetValue()[0]; -} - -string CSVReaderOptions::GetMultiByteDelimiter() const { - return dialect_options.state_machine_options.delimiter.GetValue(); -} - void CSVReaderOptions::SetDateFormat(LogicalTypeId type, const string &format, bool read_format) { string error; if (read_format) { @@ -229,7 +198,7 @@ void CSVReaderOptions::SetReadOption(const string &loption, const Value &value, if (loption == "auto_detect") { auto_detect = ParseBoolean(value, loption); } else if (loption == "sample_size") { - const auto sample_size_option = ParseInteger(value, loption); + auto sample_size_option = ParseInteger(value, loption); if (sample_size_option < 1 && sample_size_option != -1) { throw BinderException("Unsupported parameter for SAMPLE_SIZE: cannot be smaller than 1"); } @@ -246,11 +215,7 @@ void CSVReaderOptions::SetReadOption(const string &loption, const Value &value, } else if (loption == "skip") { SetSkipRows(ParseInteger(value, loption)); } else if (loption == "max_line_size" || loption == "maximum_line_size") { - auto line_size = ParseInteger(value, loption); - if (line_size < 0) { - throw BinderException("Invalid value for MAX_LINE_SIZE parameter: it cannot be smaller than 0"); - } - maximum_line_size.Set(NumericCast(line_size)); + maximum_line_size = NumericCast(ParseInteger(value, loption)); } else if (loption == "date_format" || loption == "dateformat") { string format = ParseString(value, loption); SetDateFormat(LogicalTypeId::DATE, format, true); @@ -260,8 +225,8 @@ void CSVReaderOptions::SetReadOption(const string &loption, const Value &value, } else if (loption == "ignore_errors") { ignore_errors.Set(ParseBoolean(value, loption)); } else if (loption == "buffer_size") { - buffer_size_option.Set(NumericCast(ParseInteger(value, loption))); - if (buffer_size_option == 0) { + buffer_size = NumericCast(ParseInteger(value, loption)); + if (buffer_size == 0) { throw InvalidInputException("Buffer Size option must be higher than 0"); } } else if (loption == "decimal_separator") { @@ -281,9 +246,6 @@ void CSVReaderOptions::SetReadOption(const string &loption, const Value &value, if (!expected_names.empty()) { force_not_null = ParseColumnList(value, expected_names, loption); } else { - if (value.IsNull()) { - throw BinderException("Invalid value for 'force_not_null' paramenter"); - } // Get the list of columns to use as a recovery key auto &children = ListValue::GetChildren(value); for (auto &child : children) { @@ -312,8 +274,6 @@ void CSVReaderOptions::SetReadOption(const string &loption, const Value &value, throw BinderException("Unsupported parameter for REJECTS_LIMIT: cannot be negative"); } rejects_limit = NumericCast(limit); - } else if (loption == "encoding") { - encoding = ParseString(value, loption); } else { throw BinderException("Unrecognized option for CSV reader \"%s\"", loption); } @@ -411,10 +371,13 @@ bool CSVReaderOptions::SetBaseOption(const string &loption, const Value &value, throw BinderException("CSV Writer function option %s only accepts one nullstr value.", loption); } + } else if (loption == "encoding") { + auto encoding = StringUtil::Lower(ParseString(value, loption)); + if (encoding != "utf8" && encoding != "utf-8") { + throw BinderException("Copy is only supported for UTF-8 encoded files, ENCODING 'UTF-8'"); + } } else if (loption == "compression") { SetCompression(ParseString(value, loption)); - } else if (loption == "rfc_4180") { - SetRFC4180(ParseBoolean(value, loption)); } else { // unrecognized option in base CSV return false; @@ -423,10 +386,9 @@ bool CSVReaderOptions::SetBaseOption(const string &loption, const Value &value, } template -string FormatOptionLine(const string &name, const CSVOption &option) { +string FormatOptionLine(const string &name, const CSVOption option) { return name + " = " + option.FormatValue() + " " + option.FormatSet() + "\n "; } - bool CSVReaderOptions::WasTypeManuallySet(idx_t i) const { if (i >= was_type_manually_set.size()) { return false; @@ -440,7 +402,6 @@ string CSVReaderOptions::ToString(const string ¤t_file_path) const { auto &escape = dialect_options.state_machine_options.escape; auto &comment = dialect_options.state_machine_options.comment; auto &new_line = dialect_options.state_machine_options.new_line; - auto &rfc_4180 = dialect_options.state_machine_options.rfc_4180; auto &skip_rows = dialect_options.skip_rows; auto &header = dialect_options.header; @@ -460,8 +421,6 @@ string CSVReaderOptions::ToString(const string ¤t_file_path) const { error += FormatOptionLine("skip_rows", skip_rows); // comment error += FormatOptionLine("comment", comment); - // rfc_4180 - error += FormatOptionLine("rfc_4180", rfc_4180); // date format error += FormatOptionLine("date_format", dialect_options.date_format.at(LogicalType::DATE)); // timestamp format @@ -488,7 +447,7 @@ static Value StringVectorToValue(const vector &vec) { for (auto &item : vec) { content.push_back(Value(item)); } - return Value::LIST(LogicalType::VARCHAR, std::move(content)); + return Value::LIST(std::move(content)); } static uint8_t GetCandidateSpecificity(const LogicalType &candidate_type) { @@ -546,25 +505,6 @@ void CSVReaderOptions::Verify() { if (rejects_limit != 0 && !store_rejects.GetValue()) { throw BinderException("REJECTS_LIMIT option is only supported when REJECTS_TABLE is set to a table name"); } - // Validate CSV Buffer and max_line_size do not conflict. - if (buffer_size_option.IsSetByUser() && maximum_line_size.IsSetByUser()) { - if (buffer_size_option.GetValue() < maximum_line_size.GetValue()) { - throw BinderException("BUFFER_SIZE option was set to %d, while MAX_LINE_SIZE was set to %d. BUFFER_SIZE " - "must have always be set to value bigger than MAX_LINE_SIZE", - buffer_size_option.GetValue(), maximum_line_size.GetValue()); - } - } else if (maximum_line_size.IsSetByUser() && maximum_line_size.GetValue() > max_line_size_default) { - // If the max line size is set by the user and bigger than we have by default, we make it part of our buffer - // size decision. - buffer_size_option.Set(CSVBuffer::ROWS_PER_BUFFER * maximum_line_size.GetValue(), false); - } -} - -bool GetBooleanValue(const pair &option) { - if (option.second.IsNull()) { - throw BinderException("read_csv %s cannot be NULL", option.first); - } - return BooleanValue::Get(option.second); } void CSVReaderOptions::FromNamedParameters(const named_parameter_map_t &in, ClientContext &context) { @@ -696,9 +636,9 @@ void CSVReaderOptions::FromNamedParameters(const named_parameter_map_t &in, Clie sql_type_list.push_back(std::move(def_type)); } } else if (loption == "all_varchar") { - all_varchar = GetBooleanValue(kv); + all_varchar = BooleanValue::Get(kv.second); } else if (loption == "normalize_names") { - normalize_names = GetBooleanValue(kv); + normalize_names = BooleanValue::Get(kv.second); } else { SetReadOption(loption, kv.second, name_list); } @@ -710,13 +650,13 @@ void CSVReaderOptions::FromNamedParameters(const named_parameter_map_t &in, Clie user_defined_parameters.erase(user_defined_parameters.size() - 2); } } + //! This function is used to remember options set by the sniffer, for use in ReadCSVRelation void CSVReaderOptions::ToNamedParameters(named_parameter_map_t &named_params) const { auto &delimiter = dialect_options.state_machine_options.delimiter; auto "e = dialect_options.state_machine_options.quote; auto &escape = dialect_options.state_machine_options.escape; auto &comment = dialect_options.state_machine_options.comment; - auto &rfc_4180 = dialect_options.state_machine_options.rfc_4180; auto &header = dialect_options.header; if (delimiter.IsSetByUser()) { named_params["delim"] = Value(GetDelimiter()); @@ -736,10 +676,7 @@ void CSVReaderOptions::ToNamedParameters(named_parameter_map_t &named_params) co if (header.IsSetByUser()) { named_params["header"] = Value(GetHeader()); } - if (rfc_4180.IsSetByUser()) { - named_params["rfc_4180"] = Value(GetRFC4180()); - } - named_params["max_line_size"] = Value::BIGINT(NumericCast(maximum_line_size.GetValue())); + named_params["max_line_size"] = Value::BIGINT(NumericCast(maximum_line_size)); if (dialect_options.skip_rows.IsSetByUser()) { named_params["skip"] = Value::UBIGINT(GetSkipRows()); } @@ -760,6 +697,7 @@ void CSVReaderOptions::ToNamedParameters(named_parameter_map_t &named_params) co named_params["column_names"] = StringVectorToValue(name_list); } named_params["all_varchar"] = Value::BOOLEAN(all_varchar); + named_params["maximum_line_size"] = Value::BIGINT(NumericCast(maximum_line_size)); } } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp b/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp deleted file mode 100644 index 1b8d3f348..000000000 --- a/src/duckdb/src/execution/operator/csv_scanner/util/csv_validator.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" -#include - -namespace duckdb { - -void ThreadLines::Insert(idx_t thread_idx, ValidatorLine line_info) { - D_ASSERT(thread_lines.find(thread_idx) == thread_lines.end()); - thread_lines.insert({thread_idx, line_info}); -} - -string ThreadLines::Print() const { - string result; - for (auto &line : thread_lines) { - result += "{start_pos: " + std::to_string(line.second.start_pos) + - ", end_pos: " + std::to_string(line.second.end_pos) + "}"; - } - return result; -} - -void ThreadLines::Verify() const { - bool initialized = false; - idx_t last_end_pos = 0; - for (auto &line_info : thread_lines) { - if (!initialized) { - // First run, we just set the initialized to true - initialized = true; - } else { - if (line_info.second.start_pos == line_info.second.end_pos) { - last_end_pos = line_info.second.end_pos; - continue; - } - if (last_end_pos + error_margin < line_info.second.start_pos || - line_info.second.start_pos < last_end_pos - error_margin) { - std::ostringstream error; - error << "The Parallel CSV Reader currently does not support a full read on this file." << '\n'; - error << "To correctly parse this file, please run with the single threaded error (i.e., parallel = " - "false)" - << '\n'; - throw NotImplementedException(error.str()); - } - } - last_end_pos = line_info.second.end_pos; - } -} - -void CSVValidator::Insert(idx_t file_idx, idx_t thread_idx, ValidatorLine line_info) { - if (per_file_thread_lines.size() <= file_idx) { - per_file_thread_lines.resize(file_idx + 1); - } - per_file_thread_lines[file_idx].Insert(thread_idx, line_info); -} - -void CSVValidator::Verify() const { - for (auto &file : per_file_thread_lines) { - file.Verify(); - } -} - -string CSVValidator::Print(idx_t file_idx) const { - return per_file_thread_lines[file_idx].Print(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp b/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp index 32785a7ab..869db44f6 100644 --- a/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_reservoir_sample.cpp @@ -15,14 +15,13 @@ class SampleGlobalSinkState : public GlobalSinkState { if (percentage == 0) { return; } - sample = make_uniq(allocator, percentage, - static_cast(options.seed.GetIndex())); + sample = make_uniq(allocator, percentage, options.seed); } else { auto size = NumericCast(options.sample_size.GetValue()); if (size == 0) { return; } - sample = make_uniq(allocator, size, static_cast(options.seed.GetIndex())); + sample = make_uniq(allocator, size, options.seed); } } @@ -50,15 +49,13 @@ SinkResultType PhysicalReservoirSample::Sink(ExecutionContext &context, DataChun if (percentage == 0) { return SinkResultType::FINISHED; } - global_state.sample = make_uniq(allocator, percentage, - static_cast(options->seed.GetIndex())); + global_state.sample = make_uniq(allocator, percentage, options->seed); } else { idx_t num_samples = options->sample_size.GetValue(); if (num_samples == 0) { return SinkResultType::FINISHED; } - global_state.sample = - make_uniq(allocator, num_samples, static_cast(options->seed.GetIndex())); + global_state.sample = make_uniq(allocator, num_samples, options->seed); } } global_state.sample->AddToReservoir(chunk); diff --git a/src/duckdb/src/execution/operator/helper/physical_set.cpp b/src/duckdb/src/execution/operator/helper/physical_set.cpp index 4a321a52e..4fe86880e 100644 --- a/src/duckdb/src/execution/operator/helper/physical_set.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_set.cpp @@ -48,7 +48,7 @@ SourceResultType PhysicalSet::GetData(ExecutionContext &context, DataChunk &chun } } - Value input_val = value.CastAs(context.client, DBConfig::ParseLogicalType(option->parameter_type)); + Value input_val = value.CastAs(context.client, option->parameter_type); switch (variable_scope) { case SetScope::GLOBAL: { if (!option->set_global) { diff --git a/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp b/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp index 345745df8..186c15411 100644 --- a/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp @@ -15,7 +15,7 @@ PhysicalVacuum::PhysicalVacuum(unique_ptr info_p, optional_ptr table) : hashes(LogicalType::HASH) { + explicit VacuumLocalSinkState(VacuumInfo &info, optional_ptr table) { for (const auto &column_name : info.columns) { auto &column = table->GetColumn(column_name); if (DistinctStatistics::TypeIsSupported(column.GetType())) { @@ -27,7 +27,6 @@ class VacuumLocalSinkState : public LocalSinkState { }; vector> column_distinct_stats; - Vector hashes; }; unique_ptr PhysicalVacuum::GetLocalSinkState(ExecutionContext &context) const { @@ -63,7 +62,7 @@ SinkResultType PhysicalVacuum::Sink(ExecutionContext &context, DataChunk &chunk, if (!DistinctStatistics::TypeIsSupported(chunk.data[col_idx].GetType())) { continue; } - lstate.column_distinct_stats[col_idx]->Update(chunk.data[col_idx], chunk.size(), lstate.hashes); + lstate.column_distinct_stats[col_idx]->Update(chunk.data[col_idx], chunk.size(), false); } return SinkResultType::NEED_MORE_INPUT; diff --git a/src/duckdb/src/execution/operator/helper/physical_verify_vector.cpp b/src/duckdb/src/execution/operator/helper/physical_verify_vector.cpp index ea19d7ca9..5fc627c92 100644 --- a/src/duckdb/src/execution/operator/helper/physical_verify_vector.cpp +++ b/src/duckdb/src/execution/operator/helper/physical_verify_vector.cpp @@ -74,14 +74,6 @@ OperatorResultType VerifyEmitSequenceVector(const DataChunk &input, DataChunk &c break; } } - bool can_be_constant = true; - switch (chunk.data[c].GetType().id()) { - case LogicalTypeId::INTERVAL: - can_be_constant = false; - break; - default: - break; - } ConstantOrSequenceInfo info; info.is_constant = true; for (idx_t k = state.const_idx; k < input.size(); k++) { @@ -89,7 +81,7 @@ OperatorResultType VerifyEmitSequenceVector(const DataChunk &input, DataChunk &c if (info.values.empty()) { info.values.push_back(std::move(val)); } else if (info.is_constant) { - if (!ValueOperations::DistinctFrom(val, info.values[0]) && can_be_constant) { + if (!ValueOperations::DistinctFrom(val, info.values[0])) { // found the same value! continue info.values.push_back(std::move(val)); continue; diff --git a/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp b/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp index 123d94161..f5ced297d 100644 --- a/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp +++ b/src/duckdb/src/execution/operator/join/perfect_hash_join_executor.cpp @@ -1,123 +1,17 @@ #include "duckdb/execution/operator/join/perfect_hash_join_executor.hpp" -#include "duckdb/common/operator/subtract.hpp" +#include "duckdb/common/types/row/row_layout.hpp" #include "duckdb/execution/operator/join/physical_hash_join.hpp" namespace duckdb { -PerfectHashJoinExecutor::PerfectHashJoinExecutor(const PhysicalHashJoin &join_p, JoinHashTable &ht_p) - : join(join_p), ht(ht_p) { +PerfectHashJoinExecutor::PerfectHashJoinExecutor(const PhysicalHashJoin &join_p, JoinHashTable &ht_p, + PerfectHashJoinStats perfect_join_stats) + : join(join_p), ht(ht_p), perfect_join_statistics(std::move(perfect_join_stats)) { } -//===--------------------------------------------------------------------===// -// Initialize -//===--------------------------------------------------------------------===// -bool ExtractNumericValue(Value val, hugeint_t &result) { - if (!val.type().IsIntegral()) { - switch (val.type().InternalType()) { - case PhysicalType::INT8: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::INT16: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::INT32: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::INT64: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::INT128: - result = val.GetValueUnsafe(); - break; - case PhysicalType::UINT8: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::UINT16: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::UINT32: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::UINT64: - result = Hugeint::Convert(val.GetValueUnsafe()); - break; - case PhysicalType::UINT128: { - const auto uhugeint_val = val.GetValueUnsafe(); - if (uhugeint_val > NumericCast(NumericLimits::Maximum())) { - return false; - } - result.lower = uhugeint_val.lower; - result.upper = NumericCast(uhugeint_val.upper); - break; - } - default: - return false; - } - } else { - if (!val.DefaultTryCastAs(LogicalType::HUGEINT)) { - return false; - } - result = val.GetValue(); - } - return true; -} - -bool PerfectHashJoinExecutor::CanDoPerfectHashJoin(const PhysicalHashJoin &op, const Value &min, const Value &max) { - if (perfect_join_statistics.is_build_small) { - return true; // Already true based on static statistics - } - - // We only do this optimization for inner joins with one integer equality condition - const auto key_type = op.conditions[0].left->return_type; - if (op.join_type != JoinType::INNER || op.conditions.size() != 1 || - op.conditions[0].comparison != ExpressionType::COMPARE_EQUAL || !TypeIsInteger(key_type.InternalType())) { - return false; - } - - // We bail out if there are nested types on the RHS - for (auto &type : op.children[1]->types) { - switch (type.InternalType()) { - case PhysicalType::STRUCT: - case PhysicalType::LIST: - case PhysicalType::ARRAY: - return false; - default: - break; - } - } - - // And when the build range is smaller than the threshold - perfect_join_statistics.build_min = min; - perfect_join_statistics.build_max = max; - hugeint_t min_value, max_value; - if (!ExtractNumericValue(perfect_join_statistics.build_min, min_value) || - !ExtractNumericValue(perfect_join_statistics.build_max, max_value)) { - return false; - } - if (max_value < min_value) { - return false; // Empty table - } - - hugeint_t build_range; - if (!TrySubtractOperator::Operation(max_value, min_value, build_range)) { - return false; - } - - // The max size our build must have to run the perfect HJ - static constexpr idx_t MAX_BUILD_SIZE = 1048576; - if (build_range > Hugeint::Convert(MAX_BUILD_SIZE)) { - return false; - } - perfect_join_statistics.build_range = NumericCast(build_range); - - // If count is larger than range (duplicates), we bail out - if (ht.Count() > perfect_join_statistics.build_range) { - return false; - } - - perfect_join_statistics.is_build_small = true; - return true; +bool PerfectHashJoinExecutor::CanDoPerfectHashJoin() { + return perfect_join_statistics.is_build_small; } //===--------------------------------------------------------------------===// @@ -126,7 +20,7 @@ bool PerfectHashJoinExecutor::CanDoPerfectHashJoin(const PhysicalHashJoin &op, c bool PerfectHashJoinExecutor::BuildPerfectHashTable(LogicalType &key_type) { // First, allocate memory for each build column auto build_size = perfect_join_statistics.build_range + 1; - for (const auto &type : join.rhs_output_columns.col_types) { + for (const auto &type : join.rhs_output_types) { perfect_hash_table.emplace_back(type, build_size); } @@ -135,6 +29,7 @@ bool PerfectHashJoinExecutor::BuildPerfectHashTable(LogicalType &key_type) { memset(bitmap_build_idx.get(), 0, sizeof(bool) * build_size); // set false // Now fill columns with build data + return FullScanHashTable(key_type); } @@ -155,8 +50,7 @@ bool PerfectHashJoinExecutor::FullScanHashTable(LogicalType &key_type) { // Scan the build keys in the hash table Vector build_vector(key_type, key_count); - data_collection.Gather(tuples_addresses, *FlatVector::IncrementalSelectionVector(), key_count, 0, build_vector, - *FlatVector::IncrementalSelectionVector(), nullptr); + RowOperations::FullScanColumn(ht.layout, tuples_addresses, build_vector, key_count, 0); // Now fill the selection vector using the build keys and create a sequential vector // TODO: add check for fast pass when probe is part of build domain @@ -175,7 +69,7 @@ bool PerfectHashJoinExecutor::FullScanHashTable(LogicalType &key_type) { // Full scan the remaining build columns and fill the perfect hash table const auto build_size = perfect_join_statistics.build_range + 1; - for (idx_t i = 0; i < join.rhs_output_columns.col_types.size(); i++) { + for (idx_t i = 0; i < join.rhs_output_types.size(); i++) { auto &vector = perfect_hash_table[i]; const auto output_col_idx = ht.output_columns[i]; D_ASSERT(vector.GetType() == ht.layout.GetTypes()[output_col_idx]); @@ -200,8 +94,6 @@ bool PerfectHashJoinExecutor::FillSelectionVectorSwitchBuild(Vector &source, Sel return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); case PhysicalType::INT64: return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); - case PhysicalType::INT128: - return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); case PhysicalType::UINT8: return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); case PhysicalType::UINT16: @@ -210,8 +102,6 @@ bool PerfectHashJoinExecutor::FillSelectionVectorSwitchBuild(Vector &source, Sel return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); case PhysicalType::UINT64: return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); - case PhysicalType::UINT128: - return TemplatedFillSelectionVectorBuild(source, sel_vec, seq_sel_vec, count); default: throw NotImplementedException("Type not supported for perfect hash join"); } @@ -276,8 +166,7 @@ unique_ptr PerfectHashJoinExecutor::GetOperatorState(ExecutionCon } OperatorResultType PerfectHashJoinExecutor::ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, - DataChunk &lhs_output_columns, DataChunk &result, - OperatorState &state_p) { + DataChunk &result, OperatorState &state_p) { auto &state = state_p.Cast(); // keeps track of how many probe keys have a match idx_t probe_sel_count = 0; @@ -293,14 +182,14 @@ OperatorResultType PerfectHashJoinExecutor::ProbePerfectHashTable(ExecutionConte // If build is dense and probe is in build's domain, just reference probe if (perfect_join_statistics.is_build_dense && keys_count == probe_sel_count) { - result.Reference(lhs_output_columns); + result.Reference(input); } else { // otherwise, filter it out the values that do not match - result.Slice(lhs_output_columns, state.probe_sel_vec, probe_sel_count, 0); + result.Slice(input, state.probe_sel_vec, probe_sel_count, 0); } // on the build side, we need to fetch the data and build dictionary vectors with the sel_vec - for (idx_t i = 0; i < join.rhs_output_columns.col_types.size(); i++) { - auto &result_vector = result.data[lhs_output_columns.ColumnCount() + i]; + for (idx_t i = 0; i < join.rhs_output_types.size(); i++) { + auto &result_vector = result.data[input.ColumnCount() + i]; D_ASSERT(result_vector.GetType() == ht.layout.GetTypes()[ht.output_columns[i]]); auto &build_vec = perfect_hash_table[i]; result_vector.Reference(build_vec); @@ -325,9 +214,6 @@ void PerfectHashJoinExecutor::FillSelectionVectorSwitchProbe(Vector &source, Sel case PhysicalType::INT64: TemplatedFillSelectionVectorProbe(source, build_sel_vec, probe_sel_vec, count, probe_sel_count); break; - case PhysicalType::INT128: - TemplatedFillSelectionVectorProbe(source, build_sel_vec, probe_sel_vec, count, probe_sel_count); - break; case PhysicalType::UINT8: TemplatedFillSelectionVectorProbe(source, build_sel_vec, probe_sel_vec, count, probe_sel_count); break; @@ -340,9 +226,6 @@ void PerfectHashJoinExecutor::FillSelectionVectorSwitchProbe(Vector &source, Sel case PhysicalType::UINT64: TemplatedFillSelectionVectorProbe(source, build_sel_vec, probe_sel_vec, count, probe_sel_count); break; - case PhysicalType::UINT128: - TemplatedFillSelectionVectorProbe(source, build_sel_vec, probe_sel_vec, count, probe_sel_count); - break; default: throw NotImplementedException("Type not supported"); } diff --git a/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp b/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp index deabb6f89..1b6eb619d 100644 --- a/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp @@ -79,28 +79,16 @@ class BlockwiseNLJoinState : public CachingOperatorState { public: explicit BlockwiseNLJoinState(ExecutionContext &context, ColumnDataCollection &rhs, const PhysicalBlockwiseNLJoin &op) - : op(op), cross_product(rhs), left_outer(IsLeftOuterJoin(op.join_type)), match_sel(STANDARD_VECTOR_SIZE), + : cross_product(rhs), left_outer(IsLeftOuterJoin(op.join_type)), match_sel(STANDARD_VECTOR_SIZE), executor(context.client, *op.condition) { left_outer.Initialize(STANDARD_VECTOR_SIZE); - ResetMatches(); } - const PhysicalBlockwiseNLJoin &op; CrossProductExecutor cross_product; OuterJoinMarker left_outer; SelectionVector match_sel; ExpressionExecutor executor; DataChunk intermediate_chunk; - bool found_match[STANDARD_VECTOR_SIZE]; - - void ResetMatches() { - if (op.join_type != JoinType::SEMI && op.join_type != JoinType::ANTI) { - return; - } - for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; i++) { - found_match[i] = false; - } - } }; unique_ptr PhysicalBlockwiseNLJoin::GetOperatorState(ExecutionContext &context) const { @@ -148,66 +136,69 @@ OperatorResultType PhysicalBlockwiseNLJoin::ExecuteInternal(ExecutionContext &co // now perform the actual join // we perform a cross product, then execute the expression directly on the cross product result idx_t result_count = 0; + bool found_match[STANDARD_VECTOR_SIZE] = {false}; + + do { + auto result = state.cross_product.Execute(input, *intermediate_chunk); + if (result == OperatorResultType::NEED_MORE_INPUT) { + // exhausted input, have to pull new LHS chunk + if (state.left_outer.Enabled()) { + // left join: before we move to the next chunk, see if we need to output any vectors that didn't + // have a match found + state.left_outer.ConstructLeftJoinResult(input, *intermediate_chunk); + state.left_outer.Reset(); + } - auto result = state.cross_product.Execute(input, *intermediate_chunk); - if (result == OperatorResultType::NEED_MORE_INPUT) { - // exhausted input, have to pull new LHS chunk - if (state.left_outer.Enabled()) { - // left join: before we move to the next chunk, see if we need to output any vectors that didn't - // have a match found - state.left_outer.ConstructLeftJoinResult(input, *intermediate_chunk); - state.left_outer.Reset(); - } + if (join_type == JoinType::SEMI) { + PhysicalJoin::ConstructSemiJoinResult(input, chunk, found_match); + } + if (join_type == JoinType::ANTI) { + PhysicalJoin::ConstructAntiJoinResult(input, chunk, found_match); + } - if (join_type == JoinType::SEMI) { - PhysicalJoin::ConstructSemiJoinResult(input, chunk, state.found_match); - } - if (join_type == JoinType::ANTI) { - PhysicalJoin::ConstructAntiJoinResult(input, chunk, state.found_match); + return OperatorResultType::NEED_MORE_INPUT; } - state.ResetMatches(); - return OperatorResultType::NEED_MORE_INPUT; - } - - // now perform the computation - result_count = state.executor.SelectExpression(*intermediate_chunk, state.match_sel); - - // handle anti and semi joins with different logic - if (result_count > 0) { - // found a match! - // handle anti semi join conditions first - if (join_type == JoinType::ANTI || join_type == JoinType::SEMI) { - if (state.cross_product.ScanLHS()) { - state.found_match[state.cross_product.PositionInChunk()] = true; + // now perform the computation + result_count = state.executor.SelectExpression(*intermediate_chunk, state.match_sel); + + // handle anti and semi joins with different logic + if (result_count > 0) { + // found a match! + // handle anti semi join conditions first + if (join_type == JoinType::ANTI || join_type == JoinType::SEMI) { + if (state.cross_product.ScanLHS()) { + found_match[state.cross_product.PositionInChunk()] = true; + } else { + for (idx_t i = 0; i < result_count; i++) { + found_match[state.match_sel.get_index(i)] = true; + } + } + intermediate_chunk->Reset(); + // trick the loop to continue as semi and anti joins will never produce more output than + // the LHS cardinality + result_count = 0; } else { - for (idx_t i = 0; i < result_count; i++) { - state.found_match[state.match_sel.get_index(i)] = true; + // check if the cross product is scanning the LHS or the RHS in its entirety + if (!state.cross_product.ScanLHS()) { + // set the match flags in the LHS + state.left_outer.SetMatches(state.match_sel, result_count); + // set the match flag in the RHS + gstate.right_outer.SetMatch(state.cross_product.ScanPosition() + + state.cross_product.PositionInChunk()); + } else { + // set the match flag in the LHS + state.left_outer.SetMatch(state.cross_product.PositionInChunk()); + // set the match flags in the RHS + gstate.right_outer.SetMatches(state.match_sel, result_count, state.cross_product.ScanPosition()); } + intermediate_chunk->Slice(state.match_sel, result_count); } - intermediate_chunk->Reset(); - // trick the loop to continue as semi and anti joins will never produce more output than - // the LHS cardinality - result_count = 0; } else { - // check if the cross product is scanning the LHS or the RHS in its entirety - if (!state.cross_product.ScanLHS()) { - // set the match flags in the LHS - state.left_outer.SetMatches(state.match_sel, result_count); - // set the match flag in the RHS - gstate.right_outer.SetMatch(state.cross_product.ScanPosition() + state.cross_product.PositionInChunk()); - } else { - // set the match flag in the LHS - state.left_outer.SetMatch(state.cross_product.PositionInChunk()); - // set the match flags in the RHS - gstate.right_outer.SetMatches(state.match_sel, result_count, state.cross_product.ScanPosition()); - } - intermediate_chunk->Slice(state.match_sel, result_count); + // no result: reset the chunk + intermediate_chunk->Reset(); } - } else { - // no result: reset the chunk - intermediate_chunk->Reset(); - } + } while (result_count == 0); return OperatorResultType::HAVE_MORE_OUTPUT; } diff --git a/src/duckdb/src/execution/operator/join/physical_hash_join.cpp b/src/duckdb/src/execution/operator/join/physical_hash_join.cpp index 3c01a4acf..3deb27b6d 100644 --- a/src/duckdb/src/execution/operator/join/physical_hash_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_hash_join.cpp @@ -1,15 +1,12 @@ #include "duckdb/execution/operator/join/physical_hash_join.hpp" #include "duckdb/common/radix_partitioning.hpp" -#include "duckdb/common/types/value_map.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/query_profiler.hpp" -#include "duckdb/optimizer/filter_combiner.hpp" #include "duckdb/parallel/base_pipeline_event.hpp" #include "duckdb/parallel/executor_task.hpp" #include "duckdb/parallel/interrupt.hpp" @@ -17,11 +14,8 @@ #include "duckdb/parallel/thread_context.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" -#include "duckdb/planner/filter/in_filter.hpp" #include "duckdb/planner/filter/null_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/buffer_manager.hpp" #include "duckdb/storage/storage_manager.hpp" @@ -33,9 +27,11 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptr right, vector cond, JoinType join_type, const vector &left_projection_map, const vector &right_projection_map, vector delim_types, idx_t estimated_cardinality, + PerfectHashJoinStats perfect_join_stats, unique_ptr pushdown_info_p) : PhysicalComparisonJoin(op, PhysicalOperatorType::HASH_JOIN, std::move(cond), join_type, estimated_cardinality), - delim_types(std::move(delim_types)) { + delim_types(std::move(delim_types)), perfect_join_statistics(std::move(perfect_join_stats)) { + D_ASSERT(left_projection_map.empty()); filter_pushdown = std::move(pushdown_info_p); @@ -52,22 +48,6 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptrGetTypes(); - - // Create a projection map for the LHS (if it was empty), for convenience - lhs_output_columns.col_idxs = left_projection_map; - if (lhs_output_columns.col_idxs.empty()) { - lhs_output_columns.col_idxs.reserve(lhs_input_types.size()); - for (idx_t i = 0; i < lhs_input_types.size(); i++) { - lhs_output_columns.col_idxs.emplace_back(i); - } - } - - for (auto &lhs_col : lhs_output_columns.col_idxs) { - auto &lhs_col_type = lhs_input_types[lhs_col]; - lhs_output_columns.col_types.push_back(lhs_col_type); - } - // For ANTI, SEMI and MARK join, we only need to store the keys, so for these the payload/RHS types are empty if (join_type == JoinType::ANTI || join_type == JoinType::SEMI || join_type == JoinType::MARK) { return; @@ -91,22 +71,22 @@ PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptrsecond); + rhs_output_columns.push_back(it->second); } - rhs_output_columns.col_types.push_back(rhs_col_type); + rhs_output_types.push_back(rhs_col_type); } } PhysicalHashJoin::PhysicalHashJoin(LogicalOperator &op, unique_ptr left, unique_ptr right, vector cond, JoinType join_type, - idx_t estimated_cardinality) + idx_t estimated_cardinality, PerfectHashJoinStats perfect_join_state) : PhysicalHashJoin(op, std::move(left), std::move(right), std::move(cond), join_type, {}, {}, {}, - estimated_cardinality, nullptr) { + estimated_cardinality, std::move(perfect_join_state), nullptr) { } //===--------------------------------------------------------------------===// @@ -122,9 +102,7 @@ unique_ptr JoinFilterPushdownInfo::GetGlobalState(ClientC const PhysicalOperator &op) const { // clear any previously set filters // we can have previous filters for this operator in case of e.g. recursive CTEs - for (auto &info : probe_info) { - info.dynamic_filters->ClearFilters(op); - } + dynamic_filters->ClearFilters(op); auto result = make_uniq(); result->global_aggregate_state = make_uniq(BufferAllocator::Get(context), min_max_aggregates); @@ -137,29 +115,20 @@ class HashJoinGlobalSinkState : public GlobalSinkState { : context(context_p), op(op_p), num_threads(NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads())), temporary_memory_state(TemporaryMemoryManager::Get(context).Register(context)), finalized(false), - active_local_states(0), total_size(0), max_partition_size(0), max_partition_count(0), - probe_side_requirement(0), scanned_data(false) { + active_local_states(0), total_size(0), max_partition_size(0), max_partition_count(0), scanned_data(false) { hash_table = op.InitializeHashTable(context); // For perfect hash join - perfect_join_executor = make_uniq(op, *hash_table); - bool use_perfect_hash = false; - if (op.conditions.size() == 1 && !op.join_stats.empty() && op.join_stats[1] && - TypeIsIntegral(op.join_stats[1]->GetType().InternalType()) && NumericStats::HasMinMax(*op.join_stats[1])) { - use_perfect_hash = perfect_join_executor->CanDoPerfectHashJoin(op, NumericStats::Min(*op.join_stats[1]), - NumericStats::Max(*op.join_stats[1])); - } + perfect_join_executor = make_uniq(op, *hash_table, op.perfect_join_statistics); // For external hash join - external = ClientConfig::GetConfig(context).GetSetting(context); + external = ClientConfig::GetConfig(context).force_external; // Set probe types - probe_types = op.children[0]->types; + const auto &payload_types = op.children[0]->types; + probe_types.insert(probe_types.end(), op.condition_types.begin(), op.condition_types.end()); + probe_types.insert(probe_types.end(), payload_types.begin(), payload_types.end()); probe_types.emplace_back(LogicalType::HASH); if (op.filter_pushdown) { - if (op.filter_pushdown->probe_info.empty() && use_perfect_hash) { - // Only computing min/max to check for perfect HJ, but we already can - skip_filter_pushdown = true; - } global_filter_state = op.filter_pushdown->GetGlobalState(context, op); } } @@ -189,7 +158,6 @@ class HashJoinGlobalSinkState : public GlobalSinkState { idx_t total_size; idx_t max_partition_size; idx_t max_partition_count; - idx_t probe_side_requirement; //! Hash tables built by each thread vector> local_hash_tables; @@ -201,7 +169,6 @@ class HashJoinGlobalSinkState : public GlobalSinkState { //! Whether or not we have started scanning data using GetData atomic scanned_data; - bool skip_filter_pushdown = false; unique_ptr global_filter_state; }; @@ -222,8 +189,8 @@ class HashJoinLocalSinkState : public LocalSinkState { } join_keys.Initialize(allocator, op.condition_types); - if (!op.payload_columns.col_types.empty()) { - payload_chunk.Initialize(allocator, op.payload_columns.col_types); + if (!op.payload_types.empty()) { + payload_chunk.Initialize(allocator, op.payload_types); } hash_table = op.InitializeHashTable(context); @@ -251,8 +218,7 @@ class HashJoinLocalSinkState : public LocalSinkState { }; unique_ptr PhysicalHashJoin::InitializeHashTable(ClientContext &context) const { - auto result = make_uniq(context, conditions, payload_columns.col_types, join_type, - rhs_output_columns.col_idxs); + auto result = make_uniq(context, conditions, payload_types, join_type, rhs_output_columns); if (!delim_types.empty() && join_type == JoinType::MARK) { // correlated MARK join if (delim_types.size() + 1 == conditions.size()) { @@ -280,7 +246,7 @@ unique_ptr PhysicalHashJoin::InitializeHashTable(ClientContext &c delim_payload_types.push_back(aggr->return_type); info.correlated_aggregates.push_back(std::move(aggr)); - auto count_fun = CountFunctionBase::GetFunction(); + auto count_fun = CountFun::GetFunction(); vector> children; // this is a dummy but we need it to make the hash table understand whats going on children.push_back(make_uniq_base(count_fun.return_type, 0U)); @@ -312,36 +278,42 @@ unique_ptr PhysicalHashJoin::GetLocalSinkState(ExecutionContext void JoinFilterPushdownInfo::Sink(DataChunk &chunk, JoinFilterLocalState &lstate) const { // if we are pushing any filters into a probe-side, compute the min/max over the columns that we are pushing - for (idx_t pushdown_idx = 0; pushdown_idx < join_condition.size(); pushdown_idx++) { - auto join_condition_idx = join_condition[pushdown_idx]; + for (idx_t pushdown_idx = 0; pushdown_idx < filters.size(); pushdown_idx++) { + auto &pushdown = filters[pushdown_idx]; for (idx_t i = 0; i < 2; i++) { idx_t aggr_idx = pushdown_idx * 2 + i; - lstate.local_aggregate_state->Sink(chunk, join_condition_idx, aggr_idx); + lstate.local_aggregate_state->Sink(chunk, pushdown.join_condition, aggr_idx); } } } SinkResultType PhysicalHashJoin::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const { - auto &gstate = input.global_state.Cast(); auto &lstate = input.local_state.Cast(); // resolve the join keys for the right chunk lstate.join_keys.Reset(); lstate.join_key_executor.Execute(chunk, lstate.join_keys); - if (filter_pushdown && !gstate.skip_filter_pushdown) { + if (filter_pushdown) { filter_pushdown->Sink(lstate.join_keys, *lstate.local_filter_state); } - if (payload_columns.col_types.empty()) { // there are only keys: place an empty chunk in the payload + // build the HT + auto &ht = *lstate.hash_table; + if (payload_types.empty()) { + // there are only keys: place an empty chunk in the payload lstate.payload_chunk.SetCardinality(chunk.size()); - } else { // there are payload columns - lstate.payload_chunk.ReferenceColumns(chunk, payload_columns.col_idxs); + ht.Build(lstate.append_state, lstate.join_keys, lstate.payload_chunk); + } else { + // there are payload columns + lstate.payload_chunk.Reset(); + lstate.payload_chunk.SetCardinality(chunk); + for (idx_t i = 0; i < payload_column_idxs.size(); i++) { + lstate.payload_chunk.data[i].Reference(chunk.data[payload_column_idxs[i]]); + } + ht.Build(lstate.append_state, lstate.join_keys, lstate.payload_chunk); } - // build the HT - lstate.hash_table->Build(lstate.append_state, lstate.join_keys, lstate.payload_chunk); - return SinkResultType::NEED_MORE_INPUT; } @@ -364,7 +336,7 @@ SinkCombineResultType PhysicalHashJoin::Combine(ExecutionContext &context, Opera auto &client_profiler = QueryProfiler::Get(context.client); context.thread.profiler.Flush(*this); client_profiler.Flush(context.thread.profiler); - if (filter_pushdown && !gstate.skip_filter_pushdown) { + if (filter_pushdown) { filter_pushdown->Combine(*gstate.global_filter_state, *lstate.local_filter_state); } @@ -403,16 +375,9 @@ static idx_t GetPartitioningSpaceRequirement(ClientContext &context, const vecto void PhysicalHashJoin::PrepareFinalize(ClientContext &context, GlobalSinkState &global_state) const { auto &gstate = global_state.Cast(); - const auto &ht = *gstate.hash_table; - + auto &ht = *gstate.hash_table; gstate.total_size = ht.GetTotalSize(gstate.local_hash_tables, gstate.max_partition_size, gstate.max_partition_count); - gstate.probe_side_requirement = - GetPartitioningSpaceRequirement(context, children[0]->types, ht.GetRadixBits(), gstate.num_threads); - const auto max_partition_ht_size = - gstate.max_partition_size + JoinHashTable::PointerTableSize(gstate.max_partition_count); - gstate.temporary_memory_state->SetMinimumReservation(max_partition_ht_size + gstate.probe_side_requirement); - bool all_constant; gstate.temporary_memory_state->SetMaterializationPenalty(GetTupleWidth(children[0]->types, all_constant)); gstate.temporary_memory_state->SetRemainingSize(gstate.total_size); @@ -455,26 +420,24 @@ class HashJoinFinalizeEvent : public BasePipelineEvent { auto &ht = *sink.hash_table; const auto chunk_count = ht.GetDataCollection().ChunkCount(); const auto num_threads = NumericCast(sink.num_threads); - - // If the data is very skewed (many of the exact same key), our finalize will become slow, - // due to completely slamming the same atomic using compare-and-swaps. - // We can detect this because we partition the data, and go for a single-threaded finalize instead. - const auto max_partition_ht_size = - sink.max_partition_size + JoinHashTable::PointerTableSize(sink.max_partition_count); - const auto skew = static_cast(max_partition_ht_size) / static_cast(sink.total_size); - - if (num_threads == 1 || (ht.Count() < PARALLEL_CONSTRUCT_THRESHOLD && skew > SKEW_SINGLE_THREADED_THRESHOLD && - !context.config.verify_parallelism)) { + if (num_threads == 1 || (ht.Count() < PARALLEL_CONSTRUCT_THRESHOLD && !context.config.verify_parallelism)) { // Single-threaded finalize finalize_tasks.push_back( make_uniq(shared_from_this(), context, sink, 0U, chunk_count, false, sink.op)); } else { // Parallel finalize - const idx_t chunks_per_task = context.config.verify_parallelism ? 1 : CHUNKS_PER_TASK; - for (idx_t chunk_idx = 0; chunk_idx < chunk_count; chunk_idx += chunks_per_task) { - auto chunk_idx_to = MinValue(chunk_idx + chunks_per_task, chunk_count); - finalize_tasks.push_back(make_uniq(shared_from_this(), context, sink, chunk_idx, - chunk_idx_to, true, sink.op)); + auto chunks_per_thread = MaxValue((chunk_count + num_threads - 1) / num_threads, 1); + + idx_t chunk_idx = 0; + for (idx_t thread_idx = 0; thread_idx < num_threads; thread_idx++) { + auto chunk_idx_from = chunk_idx; + auto chunk_idx_to = MinValue(chunk_idx_from + chunks_per_thread, chunk_count); + finalize_tasks.push_back(make_uniq(shared_from_this(), context, sink, + chunk_idx_from, chunk_idx_to, true, sink.op)); + chunk_idx = chunk_idx_to; + if (chunk_idx == chunk_count) { + break; + } } } SetTasks(std::move(finalize_tasks)); @@ -485,9 +448,7 @@ class HashJoinFinalizeEvent : public BasePipelineEvent { sink.hash_table->finalized = true; } - static constexpr idx_t PARALLEL_CONSTRUCT_THRESHOLD = 1048576; - static constexpr idx_t CHUNKS_PER_TASK = 64; - static constexpr double SKEW_SINGLE_THREADED_THRESHOLD = 0.33; + static constexpr const idx_t PARALLEL_CONSTRUCT_THRESHOLD = 1048576; }; void HashJoinGlobalSinkState::ScheduleFinalize(Pipeline &pipeline, Event &event) { @@ -586,122 +547,60 @@ class HashJoinRepartitionEvent : public BasePipelineEvent { vector partition_counts(num_partitions, 0); sink.total_size = sink.hash_table->GetTotalSize(partition_sizes, partition_counts, sink.max_partition_size, sink.max_partition_count); - sink.probe_side_requirement = + const auto probe_side_requirement = GetPartitioningSpaceRequirement(sink.context, op.types, sink.hash_table->GetRadixBits(), sink.num_threads); sink.temporary_memory_state->SetMinimumReservation(sink.max_partition_size + JoinHashTable::PointerTableSize(sink.max_partition_count) + - sink.probe_side_requirement); + probe_side_requirement); sink.temporary_memory_state->UpdateReservation(executor.context); - D_ASSERT(sink.temporary_memory_state->GetReservation() >= sink.probe_side_requirement); - sink.hash_table->PrepareExternalFinalize(sink.temporary_memory_state->GetReservation() - - sink.probe_side_requirement); + sink.hash_table->PrepareExternalFinalize(sink.temporary_memory_state->GetReservation()); sink.ScheduleFinalize(*pipeline, *this); } }; -void JoinFilterPushdownInfo::PushInFilter(const JoinFilterPushdownFilter &info, JoinHashTable &ht, - const PhysicalOperator &op, idx_t filter_idx, idx_t filter_col_idx) const { - // generate a "OR" filter (i.e. x=1 OR x=535 OR x=997) - // first scan the entire vector at the probe side - // FIXME: this code is duplicated from PerfectHashJoinExecutor::FullScanHashTable - auto build_idx = join_condition[filter_idx]; - auto &data_collection = ht.GetDataCollection(); - - Vector tuples_addresses(LogicalType::POINTER, ht.Count()); // allocate space for all the tuples - - JoinHTScanState join_ht_state(data_collection, 0, data_collection.ChunkCount(), - TupleDataPinProperties::KEEP_EVERYTHING_PINNED); - - // Go through all the blocks and fill the keys addresses - idx_t key_count = ht.FillWithHTOffsets(join_ht_state, tuples_addresses); - - // Scan the build keys in the hash table - Vector build_vector(ht.layout.GetTypes()[build_idx], key_count); - data_collection.Gather(tuples_addresses, *FlatVector::IncrementalSelectionVector(), key_count, build_idx, - build_vector, *FlatVector::IncrementalSelectionVector(), nullptr); - - // generate the OR-clause - note that we only need to consider unique values here (so we use a seT) - value_set_t unique_ht_values; - for (idx_t k = 0; k < key_count; k++) { - unique_ht_values.insert(build_vector.GetValue(k)); - } - vector in_list(unique_ht_values.begin(), unique_ht_values.end()); - - // generating the OR filter only makes sense if the range is - // not dense and that the range does not contain NULL - // i.e. if we have the values [0, 1, 2, 3, 4] - the min/max is fully equivalent to the OR filter - if (FilterCombiner::ContainsNull(in_list) || FilterCombiner::IsDenseRange(in_list)) { - return; - } - - // generate the OR filter - auto in_filter = make_uniq(std::move(in_list)); - in_filter->origin_is_hash_join = true; - - // we push the OR filter as an OptionalFilter so that we can use it for zonemap pruning only - // the IN-list is expensive to execute otherwise - auto filter = make_uniq(std::move(in_filter)); - info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(filter)); - return; -} - -unique_ptr JoinFilterPushdownInfo::Finalize(ClientContext &context, JoinHashTable &ht, - JoinFilterGlobalState &gstate, - const PhysicalOperator &op) const { +void JoinFilterPushdownInfo::PushFilters(JoinFilterGlobalState &gstate, const PhysicalOperator &op) const { // finalize the min/max aggregates vector min_max_types; for (auto &aggr_expr : min_max_aggregates) { min_max_types.push_back(aggr_expr->return_type); } - auto final_min_max = make_uniq(); - final_min_max->Initialize(Allocator::DefaultAllocator(), min_max_types); - - gstate.global_aggregate_state->Finalize(*final_min_max); + DataChunk final_min_max; + final_min_max.Initialize(Allocator::DefaultAllocator(), min_max_types); - if (probe_info.empty()) { - return final_min_max; // There are not table souces in which we can push down filters - } + gstate.global_aggregate_state->Finalize(final_min_max); - auto dynamic_or_filter_threshold = ClientConfig::GetSetting(context); // create a filter for each of the aggregates - for (idx_t filter_idx = 0; filter_idx < join_condition.size(); filter_idx++) { - for (auto &info : probe_info) { - auto filter_col_idx = info.columns[filter_idx].probe_column_index.column_index; - auto min_idx = filter_idx * 2; - auto max_idx = min_idx + 1; - - auto min_val = final_min_max->data[min_idx].GetValue(0); - auto max_val = final_min_max->data[max_idx].GetValue(0); - if (min_val.IsNull() || max_val.IsNull()) { - // min/max is NULL - // this can happen in case all values in the RHS column are NULL, but they are still pushed into the - // hash table e.g. because they are part of a RIGHT join - continue; - } - // if the HT is small we can generate a complete "OR" filter - if (ht.Count() > 1 && ht.Count() <= dynamic_or_filter_threshold) { - PushInFilter(info, ht, op, filter_idx, filter_col_idx); - } - - if (Value::NotDistinctFrom(min_val, max_val)) { - // min = max - generate an equality filter - auto constant_filter = make_uniq(ExpressionType::COMPARE_EQUAL, std::move(min_val)); - info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(constant_filter)); - } else { - // min != max - generate a range filter - auto greater_equals = - make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, std::move(min_val)); - info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(greater_equals)); - auto less_equals = - make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, std::move(max_val)); - info.dynamic_filters->PushFilter(op, filter_col_idx, std::move(less_equals)); - } + for (idx_t filter_idx = 0; filter_idx < filters.size(); filter_idx++) { + auto &filter = filters[filter_idx]; + auto filter_col_idx = filter.probe_column_index.column_index; + auto min_idx = filter_idx * 2; + auto max_idx = min_idx + 1; + + auto min_val = final_min_max.data[min_idx].GetValue(0); + auto max_val = final_min_max.data[max_idx].GetValue(0); + if (min_val.IsNull() || max_val.IsNull()) { + // min/max is NULL + // this can happen in case all values in the RHS column are NULL, but they are still pushed into the hash + // table e.g. because they are part of a RIGHT join + continue; } + if (Value::NotDistinctFrom(min_val, max_val)) { + // min = max - generate an equality filter + auto constant_filter = make_uniq(ExpressionType::COMPARE_EQUAL, std::move(min_val)); + dynamic_filters->PushFilter(op, filter_col_idx, std::move(constant_filter)); + } else { + // min != max - generate a range filter + auto greater_equals = + make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, std::move(min_val)); + dynamic_filters->PushFilter(op, filter_col_idx, std::move(greater_equals)); + auto less_equals = make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, std::move(max_val)); + dynamic_filters->PushFilter(op, filter_col_idx, std::move(less_equals)); + } + // not null filter + dynamic_filters->PushFilter(op, filter_col_idx, make_uniq()); } - - return final_min_max; } SinkFinalizeType PhysicalHashJoin::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, @@ -717,24 +616,22 @@ SinkFinalizeType PhysicalHashJoin::Finalize(Pipeline &pipeline, Event &event, Cl const auto max_partition_ht_size = sink.max_partition_size + JoinHashTable::PointerTableSize(sink.max_partition_count); - const auto very_very_skewed = // No point in repartitioning if it's this skewed - static_cast(max_partition_ht_size) >= 0.8 * static_cast(sink.total_size); - if (!very_very_skewed && - (max_partition_ht_size + sink.probe_side_requirement) > sink.temporary_memory_state->GetReservation()) { + if (max_partition_ht_size > sink.temporary_memory_state->GetReservation()) { // We have to repartition ht.SetRepartitionRadixBits(sink.temporary_memory_state->GetReservation(), sink.max_partition_size, sink.max_partition_count); auto new_event = make_shared_ptr(pipeline, *this, sink, sink.local_hash_tables); event.InsertEvent(std::move(new_event)); } else { - // No repartitioning! + // No repartitioning! We do need some space for partitioning the probe-side, though + const auto probe_side_requirement = + GetPartitioningSpaceRequirement(context, children[0]->types, ht.GetRadixBits(), sink.num_threads); + sink.temporary_memory_state->SetMinimumReservation(max_partition_ht_size + probe_side_requirement); for (auto &local_ht : sink.local_hash_tables) { ht.Merge(*local_ht); } sink.local_hash_tables.clear(); - D_ASSERT(sink.temporary_memory_state->GetReservation() >= sink.probe_side_requirement); - sink.hash_table->PrepareExternalFinalize(sink.temporary_memory_state->GetReservation() - - sink.probe_side_requirement); + sink.hash_table->PrepareExternalFinalize(sink.temporary_memory_state->GetReservation()); sink.ScheduleFinalize(pipeline, event); } sink.finalized = true; @@ -748,19 +645,12 @@ SinkFinalizeType PhysicalHashJoin::Finalize(Pipeline &pipeline, Event &event, Cl sink.local_hash_tables.clear(); ht.Unpartition(); - Value min; - Value max; - if (filter_pushdown && !sink.skip_filter_pushdown && ht.Count() > 0) { - auto final_min_max = filter_pushdown->Finalize(context, ht, *sink.global_filter_state, *this); - min = final_min_max->data[0].GetValue(0); - max = final_min_max->data[1].GetValue(0); - } else if (TypeIsIntegral(conditions[0].right->return_type.InternalType())) { - min = Value::MinimumValue(conditions[0].right->return_type); - max = Value::MaximumValue(conditions[0].right->return_type); + if (filter_pushdown && ht.Count() > 0) { + filter_pushdown->PushFilters(*sink.global_filter_state, *this); } // check for possible perfect hash table - auto use_perfect_hash = sink.perfect_join_executor->CanDoPerfectHashJoin(*this, min, max); + auto use_perfect_hash = sink.perfect_join_executor->CanDoPerfectHashJoin(); if (use_perfect_hash) { D_ASSERT(ht.equality_types.size() == 1); auto key_type = ht.equality_types[0]; @@ -787,9 +677,8 @@ class HashJoinOperatorState : public CachingOperatorState { : probe_executor(context), scan_structure(*sink.hash_table, join_key_state) { } - DataChunk lhs_join_keys; + DataChunk join_keys; TupleDataChunkState join_key_state; - DataChunk lhs_output; ExpressionExecutor probe_executor; JoinHashTable::ScanStructure scan_structure; @@ -810,13 +699,10 @@ unique_ptr PhysicalHashJoin::GetOperatorState(ExecutionContext &c auto &allocator = BufferAllocator::Get(context.client); auto &sink = sink_state->Cast(); auto state = make_uniq(context.client, sink); - state->lhs_join_keys.Initialize(allocator, condition_types); - if (!lhs_output_columns.col_types.empty()) { - state->lhs_output.Initialize(allocator, lhs_output_columns.col_types); - } if (sink.perfect_join_executor) { state->perfect_hash_join_state = sink.perfect_join_executor->GetOperatorState(context); } else { + state->join_keys.Initialize(allocator, condition_types); for (auto &cond : conditions) { state->probe_executor.AddExpression(*cond.left); } @@ -841,16 +727,13 @@ OperatorResultType PhysicalHashJoin::ExecuteInternal(ExecutionContext &context, if (EmptyResultIfRHSIsEmpty()) { return OperatorResultType::FINISHED; } - state.lhs_output.ReferenceColumns(input, lhs_output_columns.col_idxs); - ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, state.lhs_output, chunk); + ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, input, chunk); return OperatorResultType::NEED_MORE_INPUT; } if (sink.perfect_join_executor) { D_ASSERT(!sink.external); - state.lhs_output.ReferenceColumns(input, lhs_output_columns.col_idxs); - return sink.perfect_join_executor->ProbePerfectHashTable(context, input, state.lhs_output, chunk, - *state.perfect_hash_join_state); + return sink.perfect_join_executor->ProbePerfectHashTable(context, input, chunk, *state.perfect_hash_join_state); } if (sink.external && !state.initialized) { @@ -864,21 +747,19 @@ OperatorResultType PhysicalHashJoin::ExecuteInternal(ExecutionContext &context, if (state.scan_structure.is_null) { // probe the HT, start by resolving the join keys for the left chunk - state.lhs_join_keys.Reset(); - state.probe_executor.Execute(input, state.lhs_join_keys); + state.join_keys.Reset(); + state.probe_executor.Execute(input, state.join_keys); // perform the actual probe if (sink.external) { - sink.hash_table->ProbeAndSpill(state.scan_structure, state.lhs_join_keys, state.join_key_state, + sink.hash_table->ProbeAndSpill(state.scan_structure, state.join_keys, state.join_key_state, state.probe_state, input, *sink.probe_spill, state.spill_state, state.spill_chunk); } else { - sink.hash_table->Probe(state.scan_structure, state.lhs_join_keys, state.join_key_state, state.probe_state); + sink.hash_table->Probe(state.scan_structure, state.join_keys, state.join_key_state, state.probe_state); } } - - state.lhs_output.ReferenceColumns(input, lhs_output_columns.col_idxs); - state.scan_structure.Next(state.lhs_join_keys, state.lhs_output, chunk); + state.scan_structure.Next(state.join_keys, input, chunk); if (state.scan_structure.PointersExhausted() && chunk.size() == 0) { state.scan_structure.is_null = true; @@ -979,12 +860,14 @@ class HashJoinLocalSourceState : public LocalSourceState { //! Local scan state for probe spill ColumnDataConsumerScanState probe_local_scan; //! Chunks for holding the scanned probe collection - DataChunk lhs_probe_chunk; - DataChunk lhs_join_keys; - DataChunk lhs_output; + DataChunk probe_chunk; + DataChunk join_keys; + DataChunk payload; TupleDataChunkState join_key_state; - ExpressionExecutor lhs_join_key_executor; + //! Column indices to easily reference the join keys/payload columns in probe_chunk + vector join_key_indices; + vector payload_indices; //! Scan structure for the external probe JoinHashTable::ScanStructure scan_structure; JoinHashTable::ProbeState probe_state; @@ -1065,13 +948,10 @@ void HashJoinGlobalSourceState::PrepareBuild(HashJoinGlobalSinkState &sink) { auto &ht = *sink.hash_table; // Update remaining size - sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation(sink.context, ht.GetRemainingSize() + - sink.probe_side_requirement); + sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation(sink.context, ht.GetRemainingSize()); // Try to put the next partitions in the block collection of the HT - D_ASSERT(!sink.external || sink.temporary_memory_state->GetReservation() >= sink.probe_side_requirement); - if (!sink.external || - !ht.PrepareExternalFinalize(sink.temporary_memory_state->GetReservation() - sink.probe_side_requirement)) { + if (!sink.external || !ht.PrepareExternalFinalize(sink.temporary_memory_state->GetReservation())) { global_stage = HashJoinSourceStage::DONE; sink.temporary_memory_state->SetZero(); return; @@ -1087,20 +967,7 @@ void HashJoinGlobalSourceState::PrepareBuild(HashJoinGlobalSinkState &sink) { build_chunk_count = data_collection.ChunkCount(); build_chunk_done = 0; - if (sink.context.config.verify_parallelism) { - build_chunks_per_thread = 1; - } else { - const auto max_partition_ht_size = - sink.max_partition_size + JoinHashTable::PointerTableSize(sink.max_partition_count); - const auto skew = static_cast(max_partition_ht_size) / static_cast(sink.total_size); - - if (skew > HashJoinFinalizeEvent::SKEW_SINGLE_THREADED_THRESHOLD) { - build_chunks_per_thread = build_chunk_count; // This forces single-threaded building - } else { - build_chunks_per_thread = // Same task size as in HashJoinFinalizeEvent - MaxValue(MinValue(build_chunk_count, HashJoinFinalizeEvent::CHUNKS_PER_TASK), 1); - } - } + build_chunks_per_thread = MaxValue((build_chunk_count + sink.num_threads - 1) / sink.num_threads, 1); ht.InitializePointerTable(); @@ -1177,18 +1044,23 @@ bool HashJoinGlobalSourceState::AssignTask(HashJoinGlobalSinkState &sink, HashJo HashJoinLocalSourceState::HashJoinLocalSourceState(const PhysicalHashJoin &op, const HashJoinGlobalSinkState &sink, Allocator &allocator) - : local_stage(HashJoinSourceStage::INIT), addresses(LogicalType::POINTER), lhs_join_key_executor(sink.context), + : local_stage(HashJoinSourceStage::INIT), addresses(LogicalType::POINTER), scan_structure(*sink.hash_table, join_key_state) { auto &chunk_state = probe_local_scan.current_chunk_state; chunk_state.properties = ColumnDataScanProperties::ALLOW_ZERO_COPY; - lhs_probe_chunk.Initialize(allocator, sink.probe_types); - lhs_join_keys.Initialize(allocator, op.condition_types); - lhs_output.Initialize(allocator, op.lhs_output_columns.col_types); + probe_chunk.Initialize(allocator, sink.probe_types); + join_keys.Initialize(allocator, op.condition_types); + payload.Initialize(allocator, op.children[0]->types); TupleDataCollection::InitializeChunkState(join_key_state, op.condition_types); - for (auto &cond : op.conditions) { - lhs_join_key_executor.AddExpression(*cond.left); + // Store the indices of the columns to reference them easily + idx_t col_idx = 0; + for (; col_idx < op.condition_types.size(); col_idx++) { + join_key_indices.push_back(col_idx); + } + for (; col_idx < sink.probe_types.size() - 1; col_idx++) { + payload_indices.push_back(col_idx); } } @@ -1239,7 +1111,7 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash if (!scan_structure.is_null) { // Still have elements remaining (i.e. we got >STANDARD_VECTOR_SIZE elements in the previous probe) - scan_structure.Next(lhs_join_keys, lhs_output, chunk); + scan_structure.Next(join_keys, payload, chunk); if (chunk.size() != 0 || !scan_structure.PointersExhausted()) { return; } @@ -1256,23 +1128,22 @@ void HashJoinLocalSourceState::ExternalProbe(HashJoinGlobalSinkState &sink, Hash } // Scan input chunk for next probe - sink.probe_spill->consumer->ScanChunk(probe_local_scan, lhs_probe_chunk); + sink.probe_spill->consumer->ScanChunk(probe_local_scan, probe_chunk); // Get the probe chunk columns/hashes - lhs_join_keys.Reset(); - lhs_join_key_executor.Execute(lhs_probe_chunk, lhs_join_keys); - lhs_output.ReferenceColumns(lhs_probe_chunk, sink.op.lhs_output_columns.col_idxs); + join_keys.ReferenceColumns(probe_chunk, join_key_indices); + payload.ReferenceColumns(probe_chunk, payload_indices); + auto precomputed_hashes = &probe_chunk.data.back(); if (sink.hash_table->Count() == 0 && !gstate.op.EmptyResultIfRHSIsEmpty()) { - gstate.op.ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, lhs_output, chunk); + gstate.op.ConstructEmptyJoinResult(sink.hash_table->join_type, sink.hash_table->has_null, payload, chunk); empty_ht_probe_in_progress = true; return; } // Perform the probe - auto precomputed_hashes = &lhs_probe_chunk.data.back(); - sink.hash_table->Probe(scan_structure, lhs_join_keys, join_key_state, probe_state, precomputed_hashes); - scan_structure.Next(lhs_join_keys, lhs_output, chunk); + sink.hash_table->Probe(scan_structure, join_keys, join_key_state, probe_state, precomputed_hashes); + scan_structure.Next(join_keys, payload, chunk); } void HashJoinLocalSourceState::ExternalScanHT(HashJoinGlobalSinkState &sink, HashJoinGlobalSourceState &gstate, @@ -1331,41 +1202,35 @@ SourceResultType PhysicalHashJoin::GetData(ExecutionContext &context, DataChunk return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } -ProgressData PhysicalHashJoin::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { +double PhysicalHashJoin::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { auto &sink = sink_state->Cast(); auto &gstate = gstate_p.Cast(); - ProgressData res; - if (!sink.external) { if (PropagatesBuildSide(join_type)) { - res.done = static_cast(gstate.full_outer_chunk_done); - res.total = static_cast(gstate.full_outer_chunk_count); - return res; + return static_cast(gstate.full_outer_chunk_done) / + static_cast(gstate.full_outer_chunk_count) * 100.0; } - res.done = 0.0; - res.total = 1.0; - return res; + return 100.0; } - const auto &ht = *sink.hash_table; - const auto num_partitions = static_cast(RadixPartitioning::NumberOfPartitions(ht.GetRadixBits())); + auto num_partitions = static_cast(RadixPartitioning::NumberOfPartitions(sink.hash_table->GetRadixBits())); + auto partition_start = static_cast(sink.hash_table->GetPartitionStart()); + auto partition_end = static_cast(sink.hash_table->GetPartitionEnd()); - res.done = static_cast(ht.FinishedPartitionCount()); - res.total = num_partitions; + // This many partitions are fully done + auto progress = partition_start / num_partitions; - const auto probe_chunk_done = static_cast(gstate.probe_chunk_done); - const auto probe_chunk_count = static_cast(gstate.probe_chunk_count); + auto probe_chunk_done = static_cast(gstate.probe_chunk_done); + auto probe_chunk_count = static_cast(gstate.probe_chunk_count); if (probe_chunk_count != 0) { - // Progress of the current round of probing + // Progress of the current round of probing, weighed by the number of partitions auto probe_progress = probe_chunk_done / probe_chunk_count; - // Weighed by the number of partitions - probe_progress *= static_cast(ht.CurrentPartitionCount()); - // Add it to the progress - res.done += probe_progress; + // Add it to the progress, weighed by the number of partitions in the current round + progress += (partition_end - partition_start) / num_partitions * probe_progress; } - return res; + return progress * 100.0; } InsertionOrderPreservingMap PhysicalHashJoin::ParamsToString() const { @@ -1384,6 +1249,11 @@ InsertionOrderPreservingMap PhysicalHashJoin::ParamsToString() const { } result["Conditions"] = condition_info; + if (perfect_join_statistics.is_build_small) { + // perfect hash join + result["Build Min"] = perfect_join_statistics.build_min.ToString(); + result["Build Max"] = perfect_join_statistics.build_max.ToString(); + } SetEstimatedCardinality(result, estimated_cardinality); return result; } diff --git a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp index c5d5810fa..143b1f207 100644 --- a/src/duckdb/src/execution/operator/join/physical_iejoin.cpp +++ b/src/duckdb/src/execution/operator/join/physical_iejoin.cpp @@ -1,19 +1,18 @@ #include "duckdb/execution/operator/join/physical_iejoin.hpp" -#include "duckdb/common/atomic.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/row_operations/row_operations.hpp" #include "duckdb/common/sort/sort.hpp" #include "duckdb/common/sort/sorted_block.hpp" -#include "duckdb/common/thread.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/parallel/event.hpp" #include "duckdb/parallel/meta_pipeline.hpp" #include "duckdb/parallel/thread_context.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" +#include "duckdb/common/atomic.hpp" +#include "duckdb/common/thread.hpp" namespace duckdb { @@ -389,42 +388,18 @@ IEJoinUnion::IEJoinUnion(ClientContext &context, const PhysicalIEJoin &op, Sorte auto ref = make_uniq(order1.expression->return_type, 0U); vector orders; orders.emplace_back(order1.type, order1.null_order, std::move(ref)); - // The goal is to make i (from the left table) < j (from the right table), - // if value[i] and value[j] match the condition 1. - // Add a column from_left to solve the problem when there exist multiple equal values in l1. - // If the operator is loose inequality, make t1.from_left (== true) sort BEFORE t2.from_left (== false). - // Otherwise, make t1.from_left sort (== true) sort AFTER t2.from_left (== false). - // For example, if t1.time <= t2.time - // | value | 1 | 1 | 1 | 1 | - // | --------- | ----- | ----- | ----- | ----- | - // | from_left | T(l2) | T(l2) | F(r1) | F(r2) | - // if t1.time < t2.time - // | value | 1 | 1 | 1 | 1 | - // | --------- | ----- | ----- | ----- | ----- | - // | from_left | F(r2) | F(r1) | T(l2) | T(l1) | - // Using this OrderType, if i < j then value[i] (from left table) and value[j] (from right table) match - // the condition (t1.time <= t2.time or t1.time < t2.time), then from_left will force them into the correct order. - auto from_left = make_uniq(Value::BOOLEAN(true)); - orders.emplace_back(SBIterator::ComparisonValue(cmp1) == 0 ? OrderType::DESCENDING : OrderType::ASCENDING, - OrderByNullType::ORDER_DEFAULT, std::move(from_left)); l1 = make_uniq(context, orders, payload_layout, op); // LHS has positive rids ExpressionExecutor l_executor(context); l_executor.AddExpression(*order1.expression); - // add const column true - auto left_const = make_uniq(Value::BOOLEAN(true)); - l_executor.AddExpression(*left_const); l_executor.AddExpression(*order2.expression); AppendKey(t1, l_executor, *l1, 1, 1, b1); // RHS has negative rids ExpressionExecutor r_executor(context); r_executor.AddExpression(*op.rhs_orders[0].expression); - // add const column flase - auto right_const = make_uniq(Value::BOOLEAN(false)); - r_executor.AddExpression(*right_const); r_executor.AddExpression(*op.rhs_orders[1].expression); AppendKey(t2, r_executor, *l1, -1, -1, b2); @@ -472,12 +447,12 @@ IEJoinUnion::IEJoinUnion(ClientContext &context, const PhysicalIEJoin &op, Sorte // 7. initialize bit-array B (|B| = n), and set all bits to 0 n = l2->count.load(); bit_array.resize(ValidityMask::EntryCount(n), 0); - bit_mask.Initialize(bit_array.data(), n); + bit_mask.Initialize(bit_array.data()); // Bloom filter bloom_count = (n + (BLOOM_CHUNK_BITS - 1)) / BLOOM_CHUNK_BITS; bloom_array.resize(ValidityMask::EntryCount(bloom_count), 0); - bloom_filter.Initialize(bloom_array.data(), bloom_count); + bloom_filter.Initialize(bloom_array.data()); // 11. for(i←1 to n) do const auto &cmp2 = op.conditions[1].comparison; @@ -488,6 +463,53 @@ IEJoinUnion::IEJoinUnion(ClientContext &context, const PhysicalIEJoin &op, Sorte (void)NextRow(); } +idx_t IEJoinUnion::SearchL1(idx_t pos) { + // Perform an exponential search in the appropriate direction + op1->SetIndex(pos); + + idx_t step = 1; + auto hi = pos; + auto lo = pos; + if (!op1->cmp) { + // Scan left for loose inequality + lo -= MinValue(step, lo); + step *= 2; + off1->SetIndex(lo); + while (lo > 0 && op1->Compare(*off1)) { + hi = lo; + lo -= MinValue(step, lo); + step *= 2; + off1->SetIndex(lo); + } + } else { + // Scan right for strict inequality + hi += MinValue(step, n - hi); + step *= 2; + off1->SetIndex(hi); + while (hi < n && !op1->Compare(*off1)) { + lo = hi; + hi += MinValue(step, n - hi); + step *= 2; + off1->SetIndex(hi); + } + } + + // Binary search the target area + while (lo < hi) { + const auto mid = lo + (hi - lo) / 2; + off1->SetIndex(mid); + if (op1->Compare(*off1)) { + hi = mid; + } else { + lo = mid + 1; + } + } + + off1->SetIndex(lo); + + return lo; +} + bool IEJoinUnion::NextRow() { for (; i < n; ++i) { // 12. pos ← P[i] @@ -517,7 +539,7 @@ bool IEJoinUnion::NextRow() { // Find the leftmost off1 where L1[pos] op1 L1[off1..n] // These are the rows that satisfy the op1 condition // and that is where we should start scanning B from - j = pos; + j = SearchL1(pos); return true; } @@ -889,7 +911,7 @@ class IEJoinGlobalSourceState : public GlobalSourceState { GetNextPair(client, lstate); } - ProgressData GetProgress() const { + double GetProgress() const { auto &left_table = *gsink.tables[0]; auto &right_table = *gsink.tables[1]; @@ -903,14 +925,7 @@ class IEJoinGlobalSourceState : public GlobalSourceState { const auto r = MinValue(next_right.load(), right_outers.load()); const auto returned = completed.load() + l + r; - ProgressData res; - if (count) { - res.done = double(returned); - res.total = double(count); - } else { - res.SetInvalid(); - } - return res; + return count ? (double(returned) / double(count)) : -1; } const PhysicalIEJoin &op; @@ -944,7 +959,7 @@ unique_ptr PhysicalIEJoin::GetLocalSourceState(ExecutionContex return make_uniq(context.client, *this); } -ProgressData PhysicalIEJoin::GetProgress(ClientContext &context, GlobalSourceState &gsource_p) const { +double PhysicalIEJoin::GetProgress(ClientContext &context, GlobalSourceState &gsource_p) const { auto &gsource = gsource_p.Cast(); return gsource.GetProgress(); } diff --git a/src/duckdb/src/execution/operator/join/physical_range_join.cpp b/src/duckdb/src/execution/operator/join/physical_range_join.cpp index f7701f845..6c7deb1e8 100644 --- a/src/duckdb/src/execution/operator/join/physical_range_join.cpp +++ b/src/duckdb/src/execution/operator/join/physical_range_join.cpp @@ -62,6 +62,7 @@ PhysicalRangeJoin::GlobalSortedTable::GlobalSortedTable(ClientContext &context, RowLayout &payload_layout, const PhysicalOperator &op_p) : op(op_p), global_sort_state(BufferManager::GetBufferManager(context), orders, payload_layout), has_null(0), count(0), memory_per_thread(0) { + D_ASSERT(orders.size() == 1); // Set external (can be forced with the PRAGMA) auto &config = ClientConfig::GetConfig(context); diff --git a/src/duckdb/src/execution/operator/order/physical_order.cpp b/src/duckdb/src/execution/operator/order/physical_order.cpp index 71294e9b7..e0bb0c940 100644 --- a/src/duckdb/src/execution/operator/order/physical_order.cpp +++ b/src/duckdb/src/execution/operator/order/physical_order.cpp @@ -264,14 +264,10 @@ SourceResultType PhysicalOrder::GetData(ExecutionContext &context, DataChunk &ch return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } -OperatorPartitionData PhysicalOrder::GetPartitionData(ExecutionContext &context, DataChunk &chunk, - GlobalSourceState &gstate_p, LocalSourceState &lstate_p, - const OperatorPartitionInfo &partition_info) const { - if (partition_info.RequiresPartitionColumns()) { - throw InternalException("PhysicalOrder::GetPartitionData: partition columns not supported"); - } +idx_t PhysicalOrder::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, + LocalSourceState &lstate_p) const { auto &lstate = lstate_p.Cast(); - return OperatorPartitionData(lstate.batch_index); + return lstate.batch_index; } InsertionOrderPreservingMap PhysicalOrder::ParamsToString() const { diff --git a/src/duckdb/src/execution/operator/order/physical_top_n.cpp b/src/duckdb/src/execution/operator/order/physical_top_n.cpp index 669c25a5e..aa686878a 100644 --- a/src/duckdb/src/execution/operator/order/physical_top_n.cpp +++ b/src/duckdb/src/execution/operator/order/physical_top_n.cpp @@ -1,20 +1,19 @@ #include "duckdb/execution/operator/order/physical_top_n.hpp" #include "duckdb/common/assert.hpp" +#include "duckdb/common/sort/sort.hpp" +#include "duckdb/common/types/row/row_layout.hpp" +#include "duckdb/common/value_operations/value_operations.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/create_sort_key.hpp" #include "duckdb/storage/data_table.hpp" -#include "duckdb/planner/filter/dynamic_filter.hpp" namespace duckdb { PhysicalTopN::PhysicalTopN(vector types, vector orders, idx_t limit, idx_t offset, - shared_ptr dynamic_filter_p, idx_t estimated_cardinality) + idx_t estimated_cardinality) : PhysicalOperator(PhysicalOperatorType::TOP_N, std::move(types), estimated_cardinality), orders(std::move(orders)), - limit(limit), offset(offset), dynamic_filter(std::move(dynamic_filter_p)) { -} - -PhysicalTopN::~PhysicalTopN() { + limit(limit), offset(offset) { } //===--------------------------------------------------------------------===// @@ -22,55 +21,33 @@ PhysicalTopN::~PhysicalTopN() { //===--------------------------------------------------------------------===// class TopNHeap; -struct TopNEntry { - string_t sort_key; - idx_t index; - - bool operator<(const TopNEntry &other) const { - return sort_key < other.sort_key; - } -}; - struct TopNScanState { - TopNScanState() : pos(0), sel(STANDARD_VECTOR_SIZE) { - } - + unique_ptr scanner; idx_t pos; - vector scan_order; - SelectionVector sel; + bool exclude_offset; }; -struct TopNBoundaryValue { - explicit TopNBoundaryValue(const PhysicalTopN &op) - : op(op), boundary_vector(op.orders[0].expression->return_type), - boundary_modifiers(op.orders[0].type, op.orders[0].null_order) { - } +class TopNSortState { +public: + explicit TopNSortState(TopNHeap &heap); - const PhysicalTopN &op; - mutex lock; - string boundary_value; - bool is_set = false; - Vector boundary_vector; - OrderModifiers boundary_modifiers; - - string GetBoundaryValue() { - lock_guard l(lock); - return boundary_value; - } + TopNHeap &heap; + unique_ptr local_state; + unique_ptr global_state; + idx_t count; + bool is_sorted; - void UpdateValue(string_t boundary_val) { - unique_lock l(lock); - if (!is_set || boundary_val < string_t(boundary_value)) { - boundary_value = boundary_val.GetString(); - is_set = true; - if (op.dynamic_filter) { - CreateSortKeyHelpers::DecodeSortKey(boundary_val, boundary_vector, 0, boundary_modifiers); - auto new_dynamic_value = boundary_vector.GetValue(0); - l.unlock(); - op.dynamic_filter->SetValue(std::move(new_dynamic_value)); - } - } - } +public: + void Initialize(); + void Append(DataChunk &sort_chunk, DataChunk &payload); + + void Sink(DataChunk &input); + void Finalize(); + + void Move(TopNSortState &other); + + void InitializeScan(TopNScanState &state, bool exclude_offset); + void Scan(TopNScanState &state, DataChunk &chunk); }; class TopNHeap { @@ -84,77 +61,162 @@ class TopNHeap { Allocator &allocator; BufferManager &buffer_manager; - unsafe_vector heap; const vector &payload_types; const vector &orders; - vector modifiers; idx_t limit; idx_t offset; - idx_t heap_size; + TopNSortState sort_state; ExpressionExecutor executor; DataChunk sort_chunk; - DataChunk heap_data; - DataChunk payload_chunk; - DataChunk sort_keys; - StringHeap sort_key_heap; - - SelectionVector matching_sel; - DataChunk compare_chunk; - //! Cached global boundary value as a set of constant vectors + DataChunk payload_chunk; + //! A set of boundary values that determine either the minimum or the maximum value we have to consider for our + //! top-n DataChunk boundary_values; - //! Cached global boundary value in sort-key format - string boundary_val; + //! Whether or not the boundary_values has been set. The boundary_values are only set after a reduce step + bool has_boundary_values; + SelectionVector final_sel; SelectionVector true_sel; SelectionVector false_sel; SelectionVector new_remaining_sel; public: - void Sink(DataChunk &input, optional_ptr boundary_value = nullptr); + void Sink(DataChunk &input); void Combine(TopNHeap &other); void Reduce(); void Finalize(); + void ExtractBoundaryValues(DataChunk ¤t_chunk, DataChunk &prev_chunk); + void InitializeScan(TopNScanState &state, bool exclude_offset); void Scan(TopNScanState &state, DataChunk &chunk); - bool CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload, TopNBoundaryValue &boundary_val); - void AddSmallHeap(DataChunk &input, Vector &sort_keys_vec); - void AddLargeHeap(DataChunk &input, Vector &sort_keys_vec); + bool CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload); +}; -public: - idx_t ReduceThreshold() const { - return MaxValue(STANDARD_VECTOR_SIZE * 5ULL, 2ULL * heap_size); +//===--------------------------------------------------------------------===// +// TopNSortState +//===--------------------------------------------------------------------===// +TopNSortState::TopNSortState(TopNHeap &heap) : heap(heap), count(0), is_sorted(false) { +} + +void TopNSortState::Initialize() { + RowLayout layout; + layout.Initialize(heap.payload_types); + auto &buffer_manager = heap.buffer_manager; + global_state = make_uniq(buffer_manager, heap.orders, layout); + local_state = make_uniq(); + local_state->Initialize(*global_state, buffer_manager); +} + +void TopNSortState::Append(DataChunk &sort_chunk, DataChunk &payload) { + D_ASSERT(!is_sorted); + if (heap.has_boundary_values) { + if (!heap.CheckBoundaryValues(sort_chunk, payload)) { + return; + } } - idx_t InitialHeapAllocSize() const { - return MinValue(STANDARD_VECTOR_SIZE * 100ULL, ReduceThreshold()) + STANDARD_VECTOR_SIZE; + local_state->SinkChunk(sort_chunk, payload); + count += payload.size(); +} + +void TopNSortState::Sink(DataChunk &input) { + // compute the ordering values for the new chunk + heap.sort_chunk.Reset(); + heap.executor.Execute(input, heap.sort_chunk); + + // append the new chunk to what we have already + Append(heap.sort_chunk, input); +} + +void TopNSortState::Move(TopNSortState &other) { + local_state = std::move(other.local_state); + global_state = std::move(other.global_state); + count = other.count; + is_sorted = other.is_sorted; +} + +void TopNSortState::Finalize() { + D_ASSERT(!is_sorted); + global_state->AddLocalState(*local_state); + + global_state->PrepareMergePhase(); + while (global_state->sorted_blocks.size() > 1) { + MergeSorter merge_sorter(*global_state, heap.buffer_manager); + merge_sorter.PerformInMergeRound(); + global_state->CompleteMergeRound(); } + is_sorted = true; +} -private: - inline bool EntryShouldBeAdded(const string_t &sort_key) { - if (heap.size() < heap_size) { - // heap is full - check the latest entry - return true; - } - if (sort_key < heap.front().sort_key) { - // sort key is smaller than current max value - return true; - } - // heap is full and there is no room for the entry - return false; +void TopNSortState::InitializeScan(TopNScanState &state, bool exclude_offset) { + D_ASSERT(is_sorted); + if (global_state->sorted_blocks.empty()) { + state.scanner = nullptr; + } else { + D_ASSERT(global_state->sorted_blocks.size() == 1); + state.scanner = make_uniq(*global_state->sorted_blocks[0]->payload_data, *global_state); } + state.pos = 0; + state.exclude_offset = exclude_offset && heap.offset > 0; +} - inline void AddEntryToHeap(const TopNEntry &entry) { - if (heap.size() >= heap_size) { - std::pop_heap(heap.begin(), heap.end()); - heap.pop_back(); +void TopNSortState::Scan(TopNScanState &state, DataChunk &chunk) { + if (!state.scanner) { + return; + } + auto offset = heap.offset; + auto limit = heap.limit; + D_ASSERT(is_sorted); + while (chunk.size() == 0) { + state.scanner->Scan(chunk); + if (chunk.size() == 0) { + break; + } + idx_t start = state.pos; + idx_t end = state.pos + chunk.size(); + state.pos = end; + + idx_t chunk_start = 0; + idx_t chunk_end = chunk.size(); + if (state.exclude_offset) { + // we need to exclude all tuples before the OFFSET + // check if we should include anything + if (end <= offset) { + // end is smaller than offset: include nothing! + chunk.Reset(); + continue; + } else if (start < offset) { + // we need to slice + chunk_start = offset - start; + } + } + // check if we need to truncate at the offset + limit mark + if (start >= offset + limit) { + // we are finished + chunk_end = 0; + } else if (end > offset + limit) { + // the end extends past the offset + limit + // truncate the current chunk + chunk_end = offset + limit - start; + } + D_ASSERT(chunk_end - chunk_start <= STANDARD_VECTOR_SIZE); + if (chunk_end == chunk_start) { + chunk.Reset(); + break; + } else if (chunk_start > 0) { + SelectionVector sel(STANDARD_VECTOR_SIZE); + for (idx_t i = chunk_start; i < chunk_end; i++) { + sel.set_index(i - chunk_start, i); + } + chunk.Slice(sel, chunk_end - chunk_start); + } else if (chunk_end != chunk.size()) { + chunk.SetCardinality(chunk_end); } - heap.push_back(entry); - std::push_heap(heap.begin(), heap.end()); } -}; +} //===--------------------------------------------------------------------===// // TopNHeap @@ -162,25 +224,21 @@ class TopNHeap { TopNHeap::TopNHeap(ClientContext &context, Allocator &allocator, const vector &payload_types_p, const vector &orders_p, idx_t limit, idx_t offset) : allocator(allocator), buffer_manager(BufferManager::GetBufferManager(context)), payload_types(payload_types_p), - orders(orders_p), limit(limit), offset(offset), heap_size(limit + offset), executor(context), - matching_sel(STANDARD_VECTOR_SIZE), final_sel(STANDARD_VECTOR_SIZE), true_sel(STANDARD_VECTOR_SIZE), - false_sel(STANDARD_VECTOR_SIZE), new_remaining_sel(STANDARD_VECTOR_SIZE) { + orders(orders_p), limit(limit), offset(offset), sort_state(*this), executor(context), has_boundary_values(false), + final_sel(STANDARD_VECTOR_SIZE), true_sel(STANDARD_VECTOR_SIZE), false_sel(STANDARD_VECTOR_SIZE), + new_remaining_sel(STANDARD_VECTOR_SIZE) { // initialize the executor and the sort_chunk vector sort_types; for (auto &order : orders) { auto &expr = order.expression; sort_types.push_back(expr->return_type); executor.AddExpression(*expr); - modifiers.emplace_back(order.type, order.null_order); } - heap.reserve(InitialHeapAllocSize()); - vector sort_keys_type {LogicalType::BLOB}; - sort_keys.Initialize(allocator, sort_keys_type); - heap_data.Initialize(allocator, payload_types, InitialHeapAllocSize()); payload_chunk.Initialize(allocator, payload_types); sort_chunk.Initialize(allocator, sort_types); compare_chunk.Initialize(allocator, sort_types); boundary_values.Initialize(allocator, sort_types); + sort_state.Initialize(); } TopNHeap::TopNHeap(ClientContext &context, const vector &payload_types, @@ -193,93 +251,84 @@ TopNHeap::TopNHeap(ExecutionContext &context, const vector &payload : TopNHeap(context.client, Allocator::Get(context.client), payload_types, orders, limit, offset) { } -void TopNHeap::AddSmallHeap(DataChunk &input, Vector &sort_keys_vec) { - // insert the sort keys into the priority queue - constexpr idx_t BASE_INDEX = NumericLimits::Maximum(); +void TopNHeap::Sink(DataChunk &input) { + sort_state.Sink(input); +} - bool any_added = false; - auto sort_key_values = FlatVector::GetData(sort_keys_vec); - for (idx_t r = 0; r < input.size(); r++) { - auto &sort_key = sort_key_values[r]; - if (!EntryShouldBeAdded(sort_key)) { - continue; - } - // replace the previous top entry with the new entry - TopNEntry entry; - entry.sort_key = sort_key; - entry.index = BASE_INDEX + r; - AddEntryToHeap(entry); - any_added = true; - } - if (!any_added) { - // early-out: no matches - return; - } +void TopNHeap::Combine(TopNHeap &other) { + other.Finalize(); - // for all matching entries we need to copy over the corresponding payload values - idx_t match_count = 0; - for (auto &entry : heap) { - if (entry.index < BASE_INDEX) { - continue; - } - // this entry was added in this chunk - // if not inlined - copy over the string to the string heap - if (!entry.sort_key.IsInlined()) { - entry.sort_key = sort_key_heap.AddBlob(entry.sort_key); + TopNScanState state; + other.InitializeScan(state, false); + while (true) { + payload_chunk.Reset(); + other.Scan(state, payload_chunk); + if (payload_chunk.size() == 0) { + break; } - // to finalize the addition of this entry we need to move over the payload data - matching_sel.set_index(match_count, entry.index - BASE_INDEX); - entry.index = heap_data.size() + match_count; - match_count++; + Sink(payload_chunk); } + Reduce(); +} - // copy over the input rows to the payload chunk - heap_data.Append(input, true, &matching_sel, match_count); +void TopNHeap::Finalize() { + sort_state.Finalize(); } -void TopNHeap::AddLargeHeap(DataChunk &input, Vector &sort_keys_vec) { - auto sort_key_values = FlatVector::GetData(sort_keys_vec); - idx_t base_index = heap_data.size(); - idx_t match_count = 0; - for (idx_t r = 0; r < input.size(); r++) { - auto &sort_key = sort_key_values[r]; - if (!EntryShouldBeAdded(sort_key)) { - continue; - } - // replace the previous top entry with the new entry - TopNEntry entry; - entry.sort_key = sort_key.IsInlined() ? sort_key : sort_key_heap.AddBlob(sort_key); - entry.index = base_index + match_count; - AddEntryToHeap(entry); - matching_sel.set_index(match_count++, r); - } - if (match_count == 0) { - // early-out: no matches +void TopNHeap::Reduce() { + idx_t min_sort_threshold = MaxValue(STANDARD_VECTOR_SIZE * 5ULL, 2ULL * (limit + offset)); + if (sort_state.count < min_sort_threshold) { + // only reduce when we pass two times the limit + offset, or 5 vectors (whichever comes first) return; } + sort_state.Finalize(); + TopNSortState new_state(*this); + new_state.Initialize(); - // copy over the input rows to the payload chunk - heap_data.Append(input, true, &matching_sel, match_count); + TopNScanState state; + sort_state.InitializeScan(state, false); + + DataChunk new_chunk; + new_chunk.Initialize(allocator, payload_types); + + DataChunk *current_chunk = &new_chunk; + DataChunk *prev_chunk = &payload_chunk; + has_boundary_values = false; + while (true) { + current_chunk->Reset(); + Scan(state, *current_chunk); + if (current_chunk->size() == 0) { + ExtractBoundaryValues(*current_chunk, *prev_chunk); + break; + } + new_state.Sink(*current_chunk); + std::swap(current_chunk, prev_chunk); + } + + sort_state.Move(new_state); } -bool TopNHeap::CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload, TopNBoundaryValue &global_boundary) { - // get the global boundary value - auto current_boundary_val = global_boundary.GetBoundaryValue(); - if (current_boundary_val.empty()) { - // no boundary value (yet) - don't do anything - return true; +void TopNHeap::ExtractBoundaryValues(DataChunk ¤t_chunk, DataChunk &prev_chunk) { + // extract the last entry of the prev_chunk and set as minimum value + D_ASSERT(prev_chunk.size() > 0); + for (idx_t col_idx = 0; col_idx < current_chunk.ColumnCount(); col_idx++) { + ConstantVector::Reference(current_chunk.data[col_idx], prev_chunk.data[col_idx], prev_chunk.size() - 1, + prev_chunk.size()); } - if (current_boundary_val != boundary_val) { - // new boundary value - decode - boundary_val = std::move(current_boundary_val); - boundary_values.Reset(); - CreateSortKeyHelpers::DecodeSortKey(string_t(boundary_val), boundary_values, 0, modifiers); - for (auto &col : boundary_values.data) { - col.SetVectorType(VectorType::CONSTANT_VECTOR); - } + current_chunk.SetCardinality(1); + sort_chunk.Reset(); + executor.Execute(¤t_chunk, sort_chunk); + + boundary_values.Reset(); + boundary_values.Append(sort_chunk); + boundary_values.SetCardinality(1); + for (idx_t i = 0; i < boundary_values.ColumnCount(); i++) { + boundary_values.data[i].SetVectorType(VectorType::CONSTANT_VECTOR); } - boundary_values.SetCardinality(sort_chunk.size()); + has_boundary_values = true; +} +bool TopNHeap::CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload) { // we have boundary values // from these boundary values, determine which values we should insert (if any) idx_t final_count = 0; @@ -341,139 +390,23 @@ bool TopNHeap::CheckBoundaryValues(DataChunk &sort_chunk, DataChunk &payload, To return true; } -void TopNHeap::Sink(DataChunk &input, optional_ptr global_boundary) { - static constexpr idx_t SMALL_HEAP_THRESHOLD = 100; - - // compute the ordering values for the new chunk - sort_chunk.Reset(); - executor.Execute(input, sort_chunk); - - if (global_boundary) { - // if we have a global boundary value check which rows pass before doing anything - if (!CheckBoundaryValues(sort_chunk, input, *global_boundary)) { - // nothing in this chunk can be in the final result - return; - } - } - - // construct the sort key from the sort chunk - sort_keys.Reset(); - auto &sort_keys_vec = sort_keys.data[0]; - CreateSortKeyHelpers::CreateSortKey(sort_chunk, modifiers, sort_keys_vec); - - if (heap_size <= SMALL_HEAP_THRESHOLD) { - AddSmallHeap(input, sort_keys_vec); - } else { - AddLargeHeap(input, sort_keys_vec); - } - - // if we modified the heap we might be able to update the global boundary - // note that the global boundary only applies to FULL heaps - if (heap.size() >= heap_size && global_boundary) { - global_boundary->UpdateValue(heap.front().sort_key); - } -} - -void TopNHeap::Combine(TopNHeap &other) { - other.Finalize(); - - idx_t match_count = 0; - // merge the heap of other into this - for (idx_t i = 0; i < other.heap.size(); i++) { - // heap is full - check the latest entry - auto &other_entry = other.heap[i]; - auto &sort_key = other_entry.sort_key; - if (!EntryShouldBeAdded(sort_key)) { - continue; - } - // add this entry - TopNEntry new_entry; - new_entry.sort_key = sort_key.IsInlined() ? sort_key : sort_key_heap.AddBlob(sort_key); - new_entry.index = heap_data.size() + match_count; - AddEntryToHeap(new_entry); - - matching_sel.set_index(match_count++, other_entry.index); - if (match_count >= STANDARD_VECTOR_SIZE) { - // flush - heap_data.Append(other.heap_data, true, &matching_sel, match_count); - match_count = 0; - } - } - if (match_count > 0) { - // flush - heap_data.Append(other.heap_data, true, &matching_sel, match_count); - match_count = 0; - } - Reduce(); -} - -void TopNHeap::Finalize() { -} - -void TopNHeap::Reduce() { - if (heap_data.size() < ReduceThreshold()) { - // only reduce when we pass the reduce threshold - return; - } - // we have too many values in the heap - reduce them - StringHeap new_sort_heap; - DataChunk new_heap_data; - new_heap_data.Initialize(allocator, payload_types, heap.size()); - - SelectionVector new_payload_sel(heap.size()); - for (idx_t i = 0; i < heap.size(); i++) { - auto &entry = heap[i]; - // the entry is not inlined - move the sort key to the new sort heap - if (!entry.sort_key.IsInlined()) { - entry.sort_key = new_sort_heap.AddBlob(entry.sort_key); - } - // move this heap entry to position X in the payload chunk - new_payload_sel.set_index(i, entry.index); - entry.index = i; - } - - // copy over the data from the current payload chunk to the new payload chunk - new_heap_data.Slice(heap_data, new_payload_sel, heap.size()); - new_heap_data.Flatten(); - - sort_key_heap.Destroy(); - sort_key_heap.Move(new_sort_heap); - heap_data.Reference(new_heap_data); -} - void TopNHeap::InitializeScan(TopNScanState &state, bool exclude_offset) { - auto heap_copy = heap; - // traverse the rest of the heap - state.scan_order.resize(heap_copy.size()); - while (!heap_copy.empty()) { - std::pop_heap(heap_copy.begin(), heap_copy.end()); - state.scan_order[heap_copy.size() - 1] = UnsafeNumericCast(heap_copy.back().index); - heap_copy.pop_back(); - } - state.pos = exclude_offset ? offset : 0; + sort_state.InitializeScan(state, exclude_offset); } void TopNHeap::Scan(TopNScanState &state, DataChunk &chunk) { - if (state.pos >= state.scan_order.size()) { - return; - } - SelectionVector sel(state.scan_order.data() + state.pos); - idx_t count = MinValue(STANDARD_VECTOR_SIZE, state.scan_order.size() - state.pos); - state.pos += STANDARD_VECTOR_SIZE; - - chunk.Reset(); - chunk.Slice(heap_data, sel, count); + sort_state.Scan(state, chunk); } class TopNGlobalState : public GlobalSinkState { public: - TopNGlobalState(ClientContext &context, const PhysicalTopN &op) - : heap(context, op.types, op.orders, op.limit, op.offset), boundary_value(op) { + TopNGlobalState(ClientContext &context, const vector &payload_types, + const vector &orders, idx_t limit, idx_t offset) + : heap(context, payload_types, orders, limit, offset) { } mutex lock; TopNHeap heap; - TopNBoundaryValue boundary_value; }; class TopNLocalState : public LocalSinkState { @@ -491,10 +424,7 @@ unique_ptr PhysicalTopN::GetLocalSinkState(ExecutionContext &con } unique_ptr PhysicalTopN::GetGlobalSinkState(ClientContext &context) const { - if (dynamic_filter) { - dynamic_filter->Reset(); - } - return make_uniq(context, *this); + return make_uniq(context, types, orders, limit, offset); } //===--------------------------------------------------------------------===// @@ -502,9 +432,8 @@ unique_ptr PhysicalTopN::GetGlobalSinkState(ClientContext &cont //===--------------------------------------------------------------------===// SinkResultType PhysicalTopN::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const { // append to the local sink state - auto &gstate = input.global_state.Cast(); auto &sink = input.local_state.Cast(); - sink.heap.Sink(chunk, &gstate.boundary_value); + sink.heap.Sink(chunk); sink.heap.Reduce(); return SinkResultType::NEED_MORE_INPUT; } diff --git a/src/duckdb/src/execution/operator/persistent/csv_rejects_table.cpp b/src/duckdb/src/execution/operator/persistent/csv_rejects_table.cpp index 0674181f2..11e8c1b0e 100644 --- a/src/duckdb/src/execution/operator/persistent/csv_rejects_table.cpp +++ b/src/duckdb/src/execution/operator/persistent/csv_rejects_table.cpp @@ -63,17 +63,14 @@ void CSVRejectsTable::InitializeTable(ClientContext &context, const ReadCSVData // Create CSV_ERROR_TYPE ENUM string enum_name = "CSV_ERROR_TYPE"; - constexpr uint8_t number_of_accepted_errors = 7; - Vector order_errors(LogicalType::VARCHAR, number_of_accepted_errors); + Vector order_errors(LogicalType::VARCHAR, 6); order_errors.SetValue(0, "CAST"); order_errors.SetValue(1, "MISSING COLUMNS"); order_errors.SetValue(2, "TOO MANY COLUMNS"); order_errors.SetValue(3, "UNQUOTED VALUE"); order_errors.SetValue(4, "LINE SIZE OVER MAXIMUM"); order_errors.SetValue(5, "INVALID UNICODE"); - order_errors.SetValue(6, "INVALID STATE"); - - LogicalType enum_type = LogicalType::ENUM(enum_name, order_errors, number_of_accepted_errors); + LogicalType enum_type = LogicalType::ENUM(enum_name, order_errors, 6); auto type_info = make_uniq(enum_name, enum_type); type_info->temporary = true; type_info->on_conflict = OnCreateConflict::IGNORE_ON_CONFLICT; diff --git a/src/duckdb/src/execution/operator/persistent/physical_batch_copy_to_file.cpp b/src/duckdb/src/execution/operator/persistent/physical_batch_copy_to_file.cpp index 4effccaff..d1fcd7b70 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_batch_copy_to_file.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_batch_copy_to_file.cpp @@ -143,7 +143,7 @@ class FixedBatchCopyLocalState : public LocalSinkState { FixedBatchCopyState current_task = FixedBatchCopyState::SINKING_DATA; void InitializeCollection(ClientContext &context, const PhysicalOperator &op) { - collection = make_uniq(BufferAllocator::Get(context), op.children[0]->types); + collection = make_uniq(context, op.children[0]->types, ColumnDataAllocatorType::HYBRID); collection->InitializeAppend(append_state); local_memory_usage = 0; } @@ -434,7 +434,7 @@ void PhysicalBatchCopyToFile::RepartitionBatches(ClientContext &context, GlobalS // the collection is too large for a batch - we need to repartition // create an empty collection auto new_collection = - make_uniq(BufferAllocator::Get(context), children[0]->types); + make_uniq(context, children[0]->types, ColumnDataAllocatorType::HYBRID); append_batch = make_uniq(0U, std::move(new_collection)); } if (append_batch) { @@ -458,7 +458,8 @@ void PhysicalBatchCopyToFile::RepartitionBatches(ClientContext &context, GlobalS // the collection is full - move it to the result and create a new one task_manager.AddTask(make_uniq(gstate.scheduled_batch_index++, std::move(append_batch))); - auto new_collection = make_uniq(BufferAllocator::Get(context), children[0]->types); + auto new_collection = + make_uniq(context, children[0]->types, ColumnDataAllocatorType::HYBRID); append_batch = make_uniq(0U, std::move(new_collection)); append_batch->collection->InitializeAppend(append_state); } diff --git a/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp b/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp index 2e546c477..8bad7cbbb 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_batch_insert.cpp @@ -34,8 +34,6 @@ PhysicalBatchInsert::PhysicalBatchInsert(LogicalOperator &op, SchemaCatalogEntry //===--------------------------------------------------------------------===// // CollectionMerger //===--------------------------------------------------------------------===// -enum class RowGroupBatchType : uint8_t { FLUSHED, NOT_FLUSHED }; - class CollectionMerger { public: explicit CollectionMerger(ClientContext &context) : context(context) { @@ -43,17 +41,10 @@ class CollectionMerger { ClientContext &context; vector> current_collections; - RowGroupBatchType batch_type = RowGroupBatchType::NOT_FLUSHED; public: - void AddCollection(unique_ptr collection, RowGroupBatchType type) { + void AddCollection(unique_ptr collection) { current_collections.push_back(std::move(collection)); - if (type == RowGroupBatchType::FLUSHED) { - batch_type = RowGroupBatchType::FLUSHED; - if (current_collections.size() > 1) { - throw InternalException("Cannot merge flushed collections"); - } - } } bool Empty() { @@ -74,9 +65,9 @@ class CollectionMerger { DataChunk scan_chunk; scan_chunk.Initialize(context, types); - vector column_ids; + vector column_ids; for (idx_t i = 0; i < types.size(); i++) { - column_ids.emplace_back(i); + column_ids.push_back(i); } for (auto &collection : current_collections) { if (!collection) { @@ -100,14 +91,13 @@ class CollectionMerger { } new_collection->FinalizeAppend(TransactionData(0, 0), append_state); writer.WriteLastRowGroup(*new_collection); - } else if (batch_type == RowGroupBatchType::NOT_FLUSHED) { - writer.WriteLastRowGroup(*new_collection); } current_collections.clear(); return new_collection; } }; +enum class RowGroupBatchType : uint8_t { FLUSHED, NOT_FLUSHED }; struct RowGroupBatchEntry { RowGroupBatchEntry(idx_t batch_idx, unique_ptr collection_p, RowGroupBatchType type) : batch_idx(batch_idx), total_rows(collection_p->GetTotalRows()), unflushed_memory(0), @@ -141,21 +131,19 @@ class BatchInsertGlobalState : public GlobalSinkState { explicit BatchInsertGlobalState(ClientContext &context, DuckTableEntry &table, idx_t minimum_memory_per_thread) : memory_manager(context, minimum_memory_per_thread), table(table), insert_count(0), optimistically_written(false), minimum_memory_per_thread(minimum_memory_per_thread) { - row_group_size = table.GetStorage().GetRowGroupSize(); } BatchMemoryManager memory_manager; BatchTaskManager task_manager; mutex lock; DuckTableEntry &table; - idx_t row_group_size; idx_t insert_count; vector collections; idx_t next_start = 0; atomic optimistically_written; idx_t minimum_memory_per_thread; - bool ReadyToMerge(idx_t count) const; + static bool ReadyToMerge(idx_t count); void ScheduleMergeTasks(idx_t min_batch_index); unique_ptr MergeCollections(ClientContext &context, vector merge_collections, @@ -190,8 +178,8 @@ class BatchInsertLocalState : public LocalSinkState { void CreateNewCollection(DuckTableEntry &table, const vector &insert_types) { auto table_info = table.GetStorage().GetDataTableInfo(); - auto &io_manager = TableIOManager::Get(table.GetStorage()); - current_collection = make_uniq(std::move(table_info), io_manager, insert_types, + auto &block_manager = TableIOManager::Get(table.GetStorage()).GetBlockManagerForRowData(); + current_collection = make_uniq(std::move(table_info), block_manager, insert_types, NumericCast(MAX_ROW_ID)); current_collection->InitializeEmpty(); current_collection->InitializeAppend(current_append_state); @@ -239,21 +227,21 @@ struct BatchMergeTask { idx_t total_count; }; -bool BatchInsertGlobalState::ReadyToMerge(idx_t count) const { +bool BatchInsertGlobalState::ReadyToMerge(idx_t count) { // we try to merge so the count fits nicely into row groups - if (count >= row_group_size / 10 * 9 && count <= row_group_size) { + if (count >= Storage::ROW_GROUP_SIZE / 10 * 9 && count <= Storage::ROW_GROUP_SIZE) { // 90%-100% of row group size return true; } - if (count >= row_group_size / 10 * 18 && count <= row_group_size * 2) { + if (count >= Storage::ROW_GROUP_SIZE / 10 * 18 && count <= Storage::ROW_GROUP_SIZE * 2) { // 180%-200% of row group size return true; } - if (count >= row_group_size / 10 * 27 && count <= row_group_size * 3) { + if (count >= Storage::ROW_GROUP_SIZE / 10 * 27 && count <= Storage::ROW_GROUP_SIZE * 3) { // 270%-300% of row group size return true; } - if (count >= row_group_size / 10 * 36) { + if (count >= Storage::ROW_GROUP_SIZE / 10 * 36) { // >360% of row group size return true; } @@ -342,7 +330,7 @@ unique_ptr BatchInsertGlobalState::MergeCollections(ClientCo CollectionMerger merger(context); idx_t written_data = 0; for (auto &entry : merge_collections) { - merger.AddCollection(std::move(entry.collection), RowGroupBatchType::NOT_FLUSHED); + merger.AddCollection(std::move(entry.collection)); written_data += entry.unflushed_memory; } optimistically_written = true; @@ -358,7 +346,7 @@ void BatchInsertGlobalState::AddCollection(ClientContext &context, idx_t batch_i batch_index, min_batch_index); } auto new_count = current_collection->GetTotalRows(); - auto batch_type = new_count < row_group_size ? RowGroupBatchType::NOT_FLUSHED : RowGroupBatchType::FLUSHED; + auto batch_type = new_count < Storage::ROW_GROUP_SIZE ? RowGroupBatchType::NOT_FLUSHED : RowGroupBatchType::FLUSHED; if (batch_type == RowGroupBatchType::FLUSHED && writer) { writer->WriteLastRowGroup(*current_collection); } @@ -517,8 +505,7 @@ SinkResultType PhysicalBatchInsert::Sink(ExecutionContext &context, DataChunk &c if (!lstate.constraint_state) { lstate.constraint_state = table.GetStorage().InitializeConstraintState(table, bound_constraints); } - auto &storage = table.GetStorage(); - storage.VerifyAppendConstraints(*lstate.constraint_state, context.client, lstate.insert_chunk, nullptr, nullptr); + table.GetStorage().VerifyAppendConstraints(*lstate.constraint_state, context.client, lstate.insert_chunk); auto new_row_group = lstate.current_collection->Append(lstate.insert_chunk, lstate.current_append_state); if (new_row_group) { @@ -569,7 +556,7 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, auto &gstate = input.global_state.Cast(); auto &memory_manager = gstate.memory_manager; - if (gstate.optimistically_written || gstate.insert_count >= gstate.row_group_size) { + if (gstate.optimistically_written || gstate.insert_count >= LocalStorage::MERGE_THRESHOLD) { // we have written data to disk optimistically or are inserting a large amount of data // perform a final pass over all of the row groups and merge them together vector> mergers; @@ -582,7 +569,7 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, if (!current_merger) { current_merger = make_uniq(context); } - current_merger->AddCollection(std::move(entry.collection), entry.type); + current_merger->AddCollection(std::move(entry.collection)); memory_manager.ReduceUnflushedMemory(entry.unflushed_memory); } else { // this collection has been flushed: it does not need to be merged @@ -593,7 +580,7 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, current_merger.reset(); } auto larger_merger = make_uniq(context); - larger_merger->AddCollection(std::move(entry.collection), entry.type); + larger_merger->AddCollection(std::move(entry.collection)); mergers.push_back(std::move(larger_merger)); } } @@ -629,7 +616,7 @@ SinkFinalizeType PhysicalBatchInsert::Finalize(Pipeline &pipeline, Event &event, memory_manager.ReduceUnflushedMemory(entry.unflushed_memory); entry.collection->Scan(transaction, [&](DataChunk &insert_chunk) { - storage.LocalAppend(append_state, context, insert_chunk, false); + storage.LocalAppend(append_state, table, context, insert_chunk); return true; }); } diff --git a/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp b/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp index 6ad354ea2..353c091c8 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_copy_database.cpp @@ -42,7 +42,6 @@ SourceResultType PhysicalCopyDatabase::GetData(ExecutionContext &context, DataCh catalog.CreateType(context.client, create_info->Cast()); break; case CatalogType::MACRO_ENTRY: - case CatalogType::TABLE_MACRO_ENTRY: catalog.CreateFunction(context.client, create_info->Cast()); break; case CatalogType::TABLE_ENTRY: { diff --git a/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp b/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp index fa85d670b..fece3ef01 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_copy_to_file.cpp @@ -510,12 +510,6 @@ SinkFinalizeType PhysicalCopyToFile::Finalize(Pipeline &pipeline, Event &event, } if (per_thread_output) { // already happened in combine - if (NumericCast(gstate.rows_copied.load()) == 0 && sink_state != nullptr) { - // no rows from source, write schema to file - auto global_lock = gstate.lock.GetExclusiveLock(); - gstate.global_state = CreateFileState(context, *sink_state, *global_lock); - function.copy_to_finalize(context, *bind_data, *gstate.global_state); - } return SinkFinalizeType::READY; } if (function.copy_to_finalize) { diff --git a/src/duckdb/src/execution/operator/persistent/physical_delete.cpp b/src/duckdb/src/execution/operator/persistent/physical_delete.cpp index e92e2ec66..ec832aa29 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_delete.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_delete.cpp @@ -1,14 +1,13 @@ #include "duckdb/execution/operator/persistent/physical_delete.hpp" -#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/common/atomic.hpp" #include "duckdb/common/types/column/column_data_collection.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/execution/index/bound_index.hpp" #include "duckdb/storage/data_table.hpp" -#include "duckdb/storage/table/delete_state.hpp" #include "duckdb/storage/table/scan_state.hpp" #include "duckdb/transaction/duck_transaction.hpp" +#include "duckdb/storage/table/delete_state.hpp" +#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" namespace duckdb { @@ -24,23 +23,13 @@ PhysicalDelete::PhysicalDelete(vector types, TableCatalogEntry &tab //===--------------------------------------------------------------------===// class DeleteGlobalState : public GlobalSinkState { public: - explicit DeleteGlobalState(ClientContext &context, const vector &return_types, - TableCatalogEntry &table, const vector> &bound_constraints) - : deleted_count(0), return_collection(context, return_types), has_unique_indexes(false) { - - // We need to append deletes to the local delete-ART. - auto &storage = table.GetStorage(); - if (storage.HasUniqueIndexes()) { - storage.InitializeLocalStorage(delete_index_append_state, table, context, bound_constraints); - has_unique_indexes = true; - } + explicit DeleteGlobalState(ClientContext &context, const vector &return_types) + : deleted_count(0), return_collection(context, return_types) { } mutex delete_lock; idx_t deleted_count; ColumnDataCollection return_collection; - LocalAppendState delete_index_append_state; - bool has_unique_indexes; }; class DeleteLocalState : public LocalSinkState { @@ -48,68 +37,39 @@ class DeleteLocalState : public LocalSinkState { DeleteLocalState(ClientContext &context, TableCatalogEntry &table, const vector> &bound_constraints) { delete_chunk.Initialize(Allocator::Get(context), table.GetTypes()); - auto &storage = table.GetStorage(); - delete_state = storage.InitializeDelete(table, context, bound_constraints); + delete_state = table.GetStorage().InitializeDelete(table, context, bound_constraints); } - -public: DataChunk delete_chunk; unique_ptr delete_state; }; SinkResultType PhysicalDelete::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const { - auto &g_state = input.global_state.Cast(); - auto &l_state = input.local_state.Cast(); + auto &gstate = input.global_state.Cast(); + auto &ustate = input.local_state.Cast(); + // get rows and auto &transaction = DuckTransaction::Get(context.client, table.db); - auto &row_ids = chunk.data[row_id_index]; + auto &row_identifiers = chunk.data[row_id_index]; - vector column_ids; + vector column_ids; for (idx_t i = 0; i < table.ColumnCount(); i++) { column_ids.emplace_back(i); }; - auto fetch_state = ColumnFetchState(); + auto cfs = ColumnFetchState(); - lock_guard delete_guard(g_state.delete_lock); - if (!return_chunk && !g_state.has_unique_indexes) { - g_state.deleted_count += table.Delete(*l_state.delete_state, context.client, row_ids, chunk.size()); - return SinkResultType::NEED_MORE_INPUT; - } - - // Fetch the to-be-deleted chunk. - l_state.delete_chunk.Reset(); - row_ids.Flatten(chunk.size()); - table.Fetch(transaction, l_state.delete_chunk, column_ids, row_ids, chunk.size(), fetch_state); - - // Append the deleted row IDs to the delete indexes. - // If we only delete local row IDs, then the delete_chunk is empty. - if (g_state.has_unique_indexes && l_state.delete_chunk.size() != 0) { - auto &local_storage = LocalStorage::Get(context.client, table.db); - auto storage = local_storage.GetStorage(table); - storage->delete_indexes.Scan([&](Index &index) { - if (!index.IsBound() || !index.IsUnique()) { - return false; - } - auto &bound_index = index.Cast(); - auto error = bound_index.Append(l_state.delete_chunk, row_ids); - if (error.HasError()) { - throw InternalException("failed to update delete ART in physical delete: ", error.Message()); - } - return false; - }); - } - - // Append the return_chunk to the return collection. + lock_guard delete_guard(gstate.delete_lock); if (return_chunk) { - g_state.return_collection.Append(l_state.delete_chunk); + ustate.delete_chunk.Reset(); + row_identifiers.Flatten(chunk.size()); + table.Fetch(transaction, ustate.delete_chunk, column_ids, row_identifiers, chunk.size(), cfs); + gstate.return_collection.Append(ustate.delete_chunk); } - - g_state.deleted_count += table.Delete(*l_state.delete_state, context.client, row_ids, chunk.size()); + gstate.deleted_count += table.Delete(*ustate.delete_state, context.client, row_identifiers, chunk.size()); return SinkResultType::NEED_MORE_INPUT; } unique_ptr PhysicalDelete::GetGlobalSinkState(ClientContext &context) const { - return make_uniq(context, GetTypes(), tableref, bound_constraints); + return make_uniq(context, GetTypes()); } unique_ptr PhysicalDelete::GetLocalSinkState(ExecutionContext &context) const { @@ -147,6 +107,7 @@ SourceResultType PhysicalDelete::GetData(ExecutionContext &context, DataChunk &c } g.return_collection.Scan(state.scan_state, chunk); + return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } diff --git a/src/duckdb/src/execution/operator/persistent/physical_export.cpp b/src/duckdb/src/execution/operator/persistent/physical_export.cpp index 66afb4c97..733b01f76 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_export.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_export.cpp @@ -9,18 +9,16 @@ #include "duckdb/parallel/pipeline.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/transaction/transaction.hpp" -#include "duckdb/catalog/duck_catalog.hpp" -#include "duckdb/catalog/dependency_manager.hpp" #include #include namespace duckdb { -void ReorderTableEntries(catalog_entry_vector_t &tables); - using std::stringstream; +void ReorderTableEntries(catalog_entry_vector_t &tables); + PhysicalExport::PhysicalExport(vector types, CopyFunction function, unique_ptr info, idx_t estimated_cardinality, unique_ptr exported_tables) : PhysicalOperator(PhysicalOperatorType::EXPORT, std::move(types), estimated_cardinality), @@ -229,18 +227,36 @@ SourceResultType PhysicalExport::GetData(ExecutionContext &context, DataChunk &c auto &ccontext = context.client; auto &fs = FileSystem::GetFileSystem(ccontext); - auto &catalog = Catalog::GetCatalog(ccontext, info->catalog); + // gather all catalog types to export + ExportEntries entries; - catalog_entry_vector_t catalog_entries; - catalog_entries = GetNaiveExportOrder(context.client, catalog); - auto dependency_manager = catalog.GetDependencyManager(); - if (dependency_manager) { - dependency_manager->ReorderEntries(catalog_entries, ccontext); + auto schema_list = Catalog::GetSchemas(ccontext, info->catalog); + ExtractEntries(context.client, schema_list, entries); + + // consider the order of tables because of foreign key constraint + entries.tables.clear(); + for (idx_t i = 0; i < exported_tables->data.size(); i++) { + entries.tables.push_back(exported_tables->data[i].entry); } + // order macro's by timestamp so nested macro's are imported nicely + sort(entries.macros.begin(), entries.macros.end(), + [](const reference &lhs, const reference &rhs) { + return lhs.get().oid < rhs.get().oid; + }); + // write the schema.sql file + // export order is SCHEMA -> SEQUENCE -> TABLE -> VIEW -> INDEX + stringstream ss; - WriteCatalogEntries(ss, catalog_entries); + WriteCatalogEntries(ss, entries.schemas); + WriteCatalogEntries(ss, entries.custom_types); + WriteCatalogEntries(ss, entries.sequences); + WriteCatalogEntries(ss, entries.tables); + WriteCatalogEntries(ss, entries.views); + WriteCatalogEntries(ss, entries.indexes); + WriteCatalogEntries(ss, entries.macros); + WriteStringStreamToFile(fs, ss, fs.JoinPath(info->file_path, "schema.sql")); // write the load.sql file diff --git a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp index dac3491fe..626f28b82 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_insert.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_insert.cpp @@ -18,7 +18,6 @@ #include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/storage/table/append_state.hpp" #include "duckdb/storage/table/update_state.hpp" -#include "duckdb/function/create_sort_key.hpp" namespace duckdb { @@ -28,14 +27,14 @@ PhysicalInsert::PhysicalInsert( vector> set_expressions, vector set_columns, vector set_types, idx_t estimated_cardinality, bool return_chunk, bool parallel, OnConflictAction action_type, unique_ptr on_conflict_condition_p, unique_ptr do_update_condition_p, - unordered_set conflict_target_p, vector columns_to_fetch_p, bool update_is_del_and_insert) + unordered_set conflict_target_p, vector columns_to_fetch_p) : PhysicalOperator(PhysicalOperatorType::INSERT, std::move(types_p), estimated_cardinality), column_index_map(std::move(column_index_map)), insert_table(&table), insert_types(table.GetTypes()), bound_defaults(std::move(bound_defaults)), bound_constraints(std::move(bound_constraints_p)), return_chunk(return_chunk), parallel(parallel), action_type(action_type), set_expressions(std::move(set_expressions)), set_columns(std::move(set_columns)), set_types(std::move(set_types)), on_conflict_condition(std::move(on_conflict_condition_p)), do_update_condition(std::move(do_update_condition_p)), - conflict_target(std::move(conflict_target_p)), update_is_del_and_insert(update_is_del_and_insert) { + conflict_target(std::move(conflict_target_p)), columns_to_fetch(std::move(columns_to_fetch_p)) { if (action_type == OnConflictAction::THROW) { return; @@ -45,12 +44,11 @@ PhysicalInsert::PhysicalInsert( // One or more columns are referenced from the existing table, // we use the 'insert_types' to figure out which types these columns have - types_to_fetch = vector(columns_to_fetch_p.size(), LogicalType::SQLNULL); - for (idx_t i = 0; i < columns_to_fetch_p.size(); i++) { - auto &id = columns_to_fetch_p[i]; + types_to_fetch = vector(columns_to_fetch.size(), LogicalType::SQLNULL); + for (idx_t i = 0; i < columns_to_fetch.size(); i++) { + auto &id = columns_to_fetch[i]; D_ASSERT(id < insert_types.size()); types_to_fetch[i] = insert_types[id]; - columns_to_fetch.emplace_back(id); } } @@ -58,7 +56,7 @@ PhysicalInsert::PhysicalInsert(LogicalOperator &op, SchemaCatalogEntry &schema, idx_t estimated_cardinality, bool parallel) : PhysicalOperator(PhysicalOperatorType::CREATE_TABLE_AS, op.types, estimated_cardinality), insert_table(nullptr), return_chunk(false), schema(&schema), info(std::move(info_p)), parallel(parallel), - action_type(OnConflictAction::THROW), update_is_del_and_insert(false) { + action_type(OnConflictAction::THROW) { GetInsertInfo(*info, insert_types, bound_defaults); } @@ -74,37 +72,49 @@ void PhysicalInsert::GetInsertInfo(const BoundCreateTableInfo &info, vector &return_types, - DuckTableEntry &table) - : table(table), insert_count(0), initialized(false), return_collection(context, return_types) { -} - -InsertLocalState::InsertLocalState(ClientContext &context, const vector &types, - const vector> &bound_defaults, - const vector> &bound_constraints) - : default_executor(context, bound_defaults), bound_constraints(bound_constraints) { - - auto &allocator = Allocator::Get(context); - insert_chunk.Initialize(allocator, types); - update_chunk.Initialize(allocator, types); - append_chunk.Initialize(allocator, types); -} - -ConstraintState &InsertLocalState::GetConstraintState(DataTable &table, TableCatalogEntry &table_ref) { - if (!constraint_state) { - constraint_state = table.InitializeConstraintState(table_ref, bound_constraints); +class InsertGlobalState : public GlobalSinkState { +public: + explicit InsertGlobalState(ClientContext &context, const vector &return_types, DuckTableEntry &table) + : table(table), insert_count(0), initialized(false), return_collection(context, return_types) { } - return *constraint_state; -} -TableDeleteState &InsertLocalState::GetDeleteState(DataTable &table, TableCatalogEntry &table_ref, - ClientContext &context) { - if (!delete_state) { - delete_state = table.InitializeDelete(table_ref, context, bound_constraints); + mutex lock; + DuckTableEntry &table; + idx_t insert_count; + bool initialized; + LocalAppendState append_state; + ColumnDataCollection return_collection; +}; + +class InsertLocalState : public LocalSinkState { +public: + InsertLocalState(ClientContext &context, const vector &types, + const vector> &bound_defaults, + const vector> &bound_constraints) + : default_executor(context, bound_defaults), bound_constraints(bound_constraints) { + insert_chunk.Initialize(Allocator::Get(context), types); + } + + DataChunk insert_chunk; + ExpressionExecutor default_executor; + TableAppendState local_append_state; + unique_ptr local_collection; + optional_ptr writer; + // Rows that have been updated by a DO UPDATE conflict + unordered_set updated_global_rows; + // Rows in the transaction-local storage that have been updated by a DO UPDATE conflict + unordered_set updated_local_rows; + idx_t update_count = 0; + unique_ptr constraint_state; + const vector> &bound_constraints; + + ConstraintState &GetConstraintState(DataTable &table, TableCatalogEntry &tableref) { + if (!constraint_state) { + constraint_state = table.InitializeConstraintState(tableref, bound_constraints); + } + return *constraint_state; } - return *delete_state; -} +}; unique_ptr PhysicalInsert::GetGlobalSinkState(ClientContext &context) const { optional_ptr table; @@ -263,62 +273,42 @@ static void CreateUpdateChunk(ExecutionContext &context, DataChunk &chunk, Table } template -static idx_t PerformOnConflictAction(InsertLocalState &lstate, ExecutionContext &context, DataChunk &chunk, - TableCatalogEntry &table, Vector &row_ids, const PhysicalInsert &op) { - // Early-out, if we do nothing on conflicting rows. +static idx_t PerformOnConflictAction(ExecutionContext &context, DataChunk &chunk, TableCatalogEntry &table, + Vector &row_ids, const PhysicalInsert &op) { + if (op.action_type == OnConflictAction::NOTHING) { return 0; } - auto &set_columns = op.set_columns; + DataChunk update_chunk; CreateUpdateChunk(context, chunk, table, row_ids, update_chunk, op); - auto &data_table = table.GetStorage(); - - // Perform the UPDATE on the (global) storage. - if (!op.update_is_del_and_insert) { - if (GLOBAL) { - auto update_state = data_table.InitializeUpdate(table, context.client, op.bound_constraints); - data_table.Update(*update_state, context.client, row_ids, set_columns, update_chunk); - return update_chunk.size(); - } - auto &local_storage = LocalStorage::Get(context.client, data_table.db); - local_storage.Update(data_table, row_ids, set_columns, update_chunk); - return update_chunk.size(); - } - - // Arrange the columns in the standard table order. - DataChunk &append_chunk = lstate.append_chunk; - append_chunk.SetCardinality(update_chunk); - for (idx_t i = 0; i < append_chunk.ColumnCount(); i++) { - append_chunk.data[i].Reference(chunk.data[i]); - } - for (idx_t i = 0; i < set_columns.size(); i++) { - append_chunk.data[set_columns[i].index].Reference(update_chunk.data[i]); - } + auto &data_table = table.GetStorage(); + // Perform the update, using the results of the SET expressions if (GLOBAL) { - auto &delete_state = lstate.GetDeleteState(data_table, table, context.client); - data_table.Delete(delete_state, context.client, row_ids, update_chunk.size()); + auto update_state = data_table.InitializeUpdate(table, context.client, op.bound_constraints); + data_table.Update(*update_state, context.client, row_ids, set_columns, update_chunk); } else { auto &local_storage = LocalStorage::Get(context.client, data_table.db); - local_storage.Delete(data_table, row_ids, update_chunk.size()); + // Perform the update, using the results of the SET expressions + local_storage.Update(data_table, row_ids, set_columns, update_chunk); } - - data_table.LocalAppend(table, context.client, append_chunk, op.bound_constraints, row_ids, append_chunk); return update_chunk.size(); } // TODO: should we use a hash table to keep track of this instead? +template static void RegisterUpdatedRows(InsertLocalState &lstate, const Vector &row_ids, idx_t count) { // Insert all rows, if any of the rows has already been updated before, we throw an error auto data = FlatVector::GetData(row_ids); - auto &updated_rows = lstate.updated_rows; + // The rowids in the transaction-local ART aren't final yet so we have to separately keep track of the two sets of + // rowids + unordered_set &updated_rows = GLOBAL ? lstate.updated_global_rows : lstate.updated_local_rows; for (idx_t i = 0; i < count; i++) { auto result = updated_rows.insert(data[i]); if (result.second == false) { - // This is following postgres behavior: throw InvalidInputException( "ON CONFLICT DO UPDATE can not update the same row twice in the same command. Ensure that no rows " "proposed for insertion within the same command have duplicate constrained values"); @@ -326,148 +316,31 @@ static void RegisterUpdatedRows(InsertLocalState &lstate, const Vector &row_ids, } } -static void CheckDistinctnessInternal(ValidityMask &valid, vector> &sort_keys, idx_t count, - map> &result) { - for (idx_t i = 0; i < count; i++) { - bool has_conflicts = false; - for (idx_t j = i + 1; j < count; j++) { - if (!valid.RowIsValid(j)) { - // Already a conflict - continue; - } - bool matches = true; - for (auto &sort_key : sort_keys) { - auto &this_row = FlatVector::GetData(sort_key.get())[i]; - auto &other_row = FlatVector::GetData(sort_key.get())[j]; - if (this_row != other_row) { - matches = false; - break; - } - } - if (matches) { - auto &row_ids = result[i]; - has_conflicts = true; - row_ids.push_back(j); - valid.SetInvalid(j); - } - } - if (has_conflicts) { - valid.SetInvalid(i); - } - } -} - -void PrepareSortKeys(DataChunk &input, unordered_map> &sort_keys, - const unordered_set &column_ids) { - OrderModifiers order_modifiers(OrderType::ASCENDING, OrderByNullType::NULLS_LAST); - for (auto &it : column_ids) { - auto &sort_key = sort_keys[it]; - if (sort_key != nullptr) { - continue; - } - auto &column = input.data[it]; - sort_key = make_uniq(LogicalType::BLOB); - CreateSortKeyHelpers::CreateSortKey(column, input.size(), order_modifiers, *sort_key); - } -} - -static map> CheckDistinctness(DataChunk &input, ConflictInfo &info, - unordered_set &matched_indexes) { - map> conflicts; - unordered_map> sort_keys; - //! Register which rows have already caused a conflict - ValidityMask valid(input.size()); - - auto &column_ids = info.column_ids; - if (column_ids.empty()) { - for (auto index : matched_indexes) { - auto &index_column_ids = index->GetColumnIdSet(); - PrepareSortKeys(input, sort_keys, index_column_ids); - vector> columns; - for (auto &idx : index_column_ids) { - columns.push_back(*sort_keys[idx]); - } - CheckDistinctnessInternal(valid, columns, input.size(), conflicts); - } - } else { - PrepareSortKeys(input, sort_keys, column_ids); - vector> columns; - for (auto &idx : column_ids) { - columns.push_back(*sort_keys[idx]); - } - CheckDistinctnessInternal(valid, columns, input.size(), conflicts); - } - return conflicts; -} - -template -static void VerifyOnConflictCondition(ExecutionContext &context, DataChunk &combined_chunk, - const unique_ptr &on_conflict_condition, - ConstraintState &constraint_state, DataChunk &tuples, DataTable &data_table, - LocalStorage &local_storage) { - if (!on_conflict_condition) { - return; - } - DataChunk conflict_condition_result; - CheckOnConflictCondition(context, combined_chunk, on_conflict_condition, conflict_condition_result); - bool conditions_met = AllConflictsMeetCondition(conflict_condition_result); - if (conditions_met) { - return; - } - - // We need to throw. Filter all tuples that passed, and verify again with those that violate the constraint. - ManagedSelection sel(combined_chunk.size()); - auto data = FlatVector::GetData(conflict_condition_result.data[0]); - for (idx_t i = 0; i < combined_chunk.size(); i++) { - if (!data[i]) { - // This tuple did not meet the condition. - sel.Append(i); - } - } - combined_chunk.Slice(sel.Selection(), sel.Count()); - - // Verify and throw. - if (GLOBAL) { - data_table.VerifyAppendConstraints(constraint_state, context.client, combined_chunk, nullptr, nullptr); - throw InternalException("VerifyAppendConstraints was expected to throw but didn't"); - } - - auto &indexes = local_storage.GetIndexes(data_table); - auto storage = local_storage.GetStorage(data_table); - DataTable::VerifyUniqueIndexes(indexes, storage, tuples, nullptr); - throw InternalException("VerifyUniqueIndexes was expected to throw but didn't"); -} - template static idx_t HandleInsertConflicts(TableCatalogEntry &table, ExecutionContext &context, InsertLocalState &lstate, - DataChunk &tuples, const PhysicalInsert &op) { + DataTable &data_table, const PhysicalInsert &op) { auto &types_to_fetch = op.types_to_fetch; auto &on_conflict_condition = op.on_conflict_condition; auto &conflict_target = op.conflict_target; auto &columns_to_fetch = op.columns_to_fetch; - auto &data_table = table.GetStorage(); auto &local_storage = LocalStorage::Get(context.client, data_table.db); + // We either want to do nothing, or perform an update when conflicts arise ConflictInfo conflict_info(conflict_target); - ConflictManager conflict_manager(VerifyExistenceType::APPEND, tuples.size(), &conflict_info); + ConflictManager conflict_manager(VerifyExistenceType::APPEND, lstate.insert_chunk.size(), &conflict_info); if (GLOBAL) { auto &constraint_state = lstate.GetConstraintState(data_table, table); - auto storage = local_storage.GetStorage(data_table); - data_table.VerifyAppendConstraints(constraint_state, context.client, tuples, storage, &conflict_manager); + data_table.VerifyAppendConstraints(constraint_state, context.client, lstate.insert_chunk, &conflict_manager); } else { - auto &indexes = local_storage.GetIndexes(data_table); - auto storage = local_storage.GetStorage(data_table); - DataTable::VerifyUniqueIndexes(indexes, storage, tuples, &conflict_manager); + DataTable::VerifyUniqueIndexes(local_storage.GetIndexes(data_table), context.client, lstate.insert_chunk, + &conflict_manager); } - conflict_manager.Finalize(); if (conflict_manager.ConflictCount() == 0) { // No conflicts found, 0 updates performed return 0; } - idx_t affected_tuples = 0; - auto &conflicts = conflict_manager.Conflicts(); auto &row_ids = conflict_manager.RowIds(); @@ -476,8 +349,8 @@ static idx_t HandleInsertConflicts(TableCatalogEntry &table, ExecutionContext &c DataChunk combined_chunk; // contains conflict_chunk + scan_chunk (wide) // Filter out everything but the conflicting rows - conflict_chunk.Initialize(context.client, tuples.GetTypes()); - conflict_chunk.Reference(tuples); + conflict_chunk.Initialize(context.client, lstate.insert_chunk.GetTypes()); + conflict_chunk.Reference(lstate.insert_chunk); conflict_chunk.Slice(conflicts.Selection(), conflicts.Count()); conflict_chunk.SetCardinality(conflicts.Count()); @@ -501,115 +374,60 @@ static idx_t HandleInsertConflicts(TableCatalogEntry &table, ExecutionContext &c // Splice the Input chunk and the fetched chunk together CombineExistingAndInsertTuples(combined_chunk, scan_chunk, conflict_chunk, context.client, op); - auto &constraint_state = lstate.GetConstraintState(data_table, table); - VerifyOnConflictCondition(context, combined_chunk, on_conflict_condition, constraint_state, tuples, - data_table, local_storage); - - if (&tuples == &lstate.update_chunk) { - // Allow updating duplicate rows for the 'update_chunk' - RegisterUpdatedRows(lstate, row_ids, combined_chunk.size()); + if (on_conflict_condition) { + DataChunk conflict_condition_result; + CheckOnConflictCondition(context, combined_chunk, on_conflict_condition, conflict_condition_result); + bool conditions_met = AllConflictsMeetCondition(conflict_condition_result); + if (!conditions_met) { + // Filter out the tuples that did pass the filter, then run the verify again + ManagedSelection sel(combined_chunk.size()); + auto data = FlatVector::GetData(conflict_condition_result.data[0]); + for (idx_t i = 0; i < combined_chunk.size(); i++) { + if (!data[i]) { + // Only populate the selection vector with the tuples that did not meet the condition + sel.Append(i); + } + } + combined_chunk.Slice(sel.Selection(), sel.Count()); + row_ids.Slice(sel.Selection(), sel.Count()); + if (GLOBAL) { + auto &constraint_state = lstate.GetConstraintState(data_table, table); + data_table.VerifyAppendConstraints(constraint_state, context.client, combined_chunk, nullptr); + } else { + DataTable::VerifyUniqueIndexes(local_storage.GetIndexes(data_table), context.client, + lstate.insert_chunk, nullptr); + } + throw InternalException("The previous operation was expected to throw but didn't"); + } } - affected_tuples += PerformOnConflictAction(lstate, context, combined_chunk, table, row_ids, op); + RegisterUpdatedRows(lstate, row_ids, combined_chunk.size()); + + idx_t updated_tuples = PerformOnConflictAction(context, combined_chunk, table, row_ids, op); // Remove the conflicting tuples from the insert chunk - SelectionVector sel_vec(tuples.size()); - idx_t new_size = SelectionVector::Inverted(conflicts.Selection(), sel_vec, conflicts.Count(), tuples.size()); - tuples.Slice(sel_vec, new_size); - tuples.SetCardinality(new_size); - return affected_tuples; + SelectionVector sel_vec(lstate.insert_chunk.size()); + idx_t new_size = + SelectionVector::Inverted(conflicts.Selection(), sel_vec, conflicts.Count(), lstate.insert_chunk.size()); + lstate.insert_chunk.Slice(sel_vec, new_size); + lstate.insert_chunk.SetCardinality(new_size); + return updated_tuples; } -idx_t PhysicalInsert::OnConflictHandling(TableCatalogEntry &table, ExecutionContext &context, InsertGlobalState &gstate, +idx_t PhysicalInsert::OnConflictHandling(TableCatalogEntry &table, ExecutionContext &context, InsertLocalState &lstate) const { auto &data_table = table.GetStorage(); - auto &local_storage = LocalStorage::Get(context.client, data_table.db); - if (action_type == OnConflictAction::THROW) { auto &constraint_state = lstate.GetConstraintState(data_table, table); - auto storage = local_storage.GetStorage(data_table); - data_table.VerifyAppendConstraints(constraint_state, context.client, lstate.insert_chunk, storage, nullptr); + data_table.VerifyAppendConstraints(constraint_state, context.client, lstate.insert_chunk, nullptr); return 0; } - - ConflictInfo conflict_info(conflict_target); - - auto &global_indexes = data_table.GetDataTableInfo()->GetIndexes(); - auto &local_indexes = local_storage.GetIndexes(data_table); - - unordered_set matched_indexes; - if (conflict_info.column_ids.empty()) { - // We care about every index that applies to the table if no ON CONFLICT (...) target is given - global_indexes.Scan([&](Index &index) { - if (!index.IsUnique()) { - return false; - } - if (conflict_info.ConflictTargetMatches(index)) { - D_ASSERT(index.IsBound()); - auto &bound_index = index.Cast(); - matched_indexes.insert(&bound_index); - } - return false; - }); - local_indexes.Scan([&](Index &index) { - if (!index.IsUnique()) { - return false; - } - if (conflict_info.ConflictTargetMatches(index)) { - D_ASSERT(index.IsBound()); - auto &bound_index = index.Cast(); - matched_indexes.insert(&bound_index); - } - return false; - }); - } - - auto inner_conflicts = CheckDistinctness(lstate.insert_chunk, conflict_info, matched_indexes); - idx_t count = lstate.insert_chunk.size(); - if (!inner_conflicts.empty()) { - // We have at least one inner conflict, filter it out - ManagedSelection sel_vec(count); - ValidityMask not_a_conflict(count); - set last_occurrences_of_conflict; - for (idx_t i = 0; i < count; i++) { - auto it = inner_conflicts.find(i); - if (it != inner_conflicts.end()) { - auto &conflicts = it->second; - auto conflict_it = conflicts.begin(); - for (; conflict_it != conflicts.end();) { - auto &idx = *conflict_it; - not_a_conflict.SetInvalid(idx); - conflict_it++; - if (conflict_it == conflicts.end()) { - last_occurrences_of_conflict.insert(idx); - } - } - } - if (not_a_conflict.RowIsValid(i)) { - sel_vec.Append(i); - } - } - if (action_type == OnConflictAction::UPDATE) { - ManagedSelection last_occurrences(last_occurrences_of_conflict.size()); - for (auto &idx : last_occurrences_of_conflict) { - last_occurrences.Append(idx); - } - - lstate.update_chunk.Reference(lstate.insert_chunk); - lstate.update_chunk.Slice(last_occurrences.Selection(), last_occurrences.Count()); - lstate.update_chunk.SetCardinality(last_occurrences.Count()); - } - - lstate.insert_chunk.Slice(sel_vec.Selection(), sel_vec.Count()); - lstate.insert_chunk.SetCardinality(sel_vec.Count()); - } - // Check whether any conflicts arise, and if they all meet the conflict_target + condition // If that's not the case - We throw the first error idx_t updated_tuples = 0; - updated_tuples += HandleInsertConflicts(table, context, lstate, lstate.insert_chunk, *this); + updated_tuples += HandleInsertConflicts(table, context, lstate, data_table, *this); // Also check the transaction-local storage+ART so we can detect conflicts within this transaction - updated_tuples += HandleInsertConflicts(table, context, lstate, lstate.insert_chunk, *this); + updated_tuples += HandleInsertConflicts(table, context, lstate, data_table, *this); return updated_tuples; } @@ -634,7 +452,7 @@ SinkResultType PhysicalInsert::Sink(ExecutionContext &context, DataChunk &chunk, // so it should not be added to the RETURNING chunk gstate.return_collection.Append(lstate.insert_chunk); } - idx_t updated_tuples = OnConflictHandling(table, context, gstate, lstate); + idx_t updated_tuples = OnConflictHandling(table, context, lstate); if (action_type == OnConflictAction::NOTHING && return_chunk) { // Because we didn't add to the RETURNING chunk yet // we add the tuples that did not get filtered out now @@ -642,31 +460,28 @@ SinkResultType PhysicalInsert::Sink(ExecutionContext &context, DataChunk &chunk, } gstate.insert_count += lstate.insert_chunk.size(); gstate.insert_count += updated_tuples; - storage.LocalAppend(gstate.append_state, context.client, lstate.insert_chunk, true); - if (action_type == OnConflictAction::UPDATE && lstate.update_chunk.size() != 0) { - // Flush the append so we can target the data we just appended with the update + storage.LocalAppend(gstate.append_state, table, context.client, lstate.insert_chunk, true); + + // We finalize the local append to write the segment node count. + if (action_type != OnConflictAction::THROW) { storage.FinalizeLocalAppend(gstate.append_state); gstate.initialized = false; - (void)HandleInsertConflicts(table, context, lstate, lstate.update_chunk, *this); - (void)HandleInsertConflicts(table, context, lstate, lstate.update_chunk, *this); - // All of the tuples should have been turned into an update, leaving the chunk empty afterwards - D_ASSERT(lstate.update_chunk.size() == 0); } + } else { D_ASSERT(!return_chunk); // parallel append if (!lstate.local_collection) { lock_guard l(gstate.lock); auto table_info = storage.GetDataTableInfo(); - auto &io_manager = TableIOManager::Get(table.GetStorage()); - lstate.local_collection = make_uniq(std::move(table_info), io_manager, insert_types, + auto &block_manager = TableIOManager::Get(storage).GetBlockManagerForRowData(); + lstate.local_collection = make_uniq(std::move(table_info), block_manager, insert_types, NumericCast(MAX_ROW_ID)); lstate.local_collection->InitializeEmpty(); lstate.local_collection->InitializeAppend(lstate.local_append_state); lstate.writer = &gstate.table.GetStorage().CreateOptimisticWriter(context.client); } - OnConflictHandling(table, context, gstate, lstate); - D_ASSERT(action_type != OnConflictAction::UPDATE); + OnConflictHandling(table, context, lstate); auto new_row_group = lstate.local_collection->Append(lstate.insert_chunk, lstate.local_append_state); if (new_row_group) { @@ -688,10 +503,6 @@ SinkCombineResultType PhysicalInsert::Combine(ExecutionContext &context, Operato return SinkCombineResultType::FINISHED; } - auto &table = gstate.table; - auto &storage = table.GetStorage(); - const idx_t row_group_size = storage.GetRowGroupSize(); - // parallel append: finalize the append TransactionData tdata(0, 0); lstate.local_collection->FinalizeAppend(tdata, lstate.local_append_state); @@ -700,19 +511,19 @@ SinkCombineResultType PhysicalInsert::Combine(ExecutionContext &context, Operato lock_guard lock(gstate.lock); gstate.insert_count += append_count; - if (append_count < row_group_size) { + if (append_count < Storage::ROW_GROUP_SIZE) { // we have few rows - append to the local storage directly + auto &table = gstate.table; + auto &storage = table.GetStorage(); storage.InitializeLocalAppend(gstate.append_state, table, context.client, bound_constraints); auto &transaction = DuckTransaction::Get(context.client, table.catalog); lstate.local_collection->Scan(transaction, [&](DataChunk &insert_chunk) { - storage.LocalAppend(gstate.append_state, context.client, insert_chunk, false); + storage.LocalAppend(gstate.append_state, table, context.client, insert_chunk); return true; }); storage.FinalizeLocalAppend(gstate.append_state); } else { // we have written rows to disk optimistically - merge directly into the transaction-local storage - lstate.writer->WriteLastRowGroup(*lstate.local_collection); - lstate.writer->FinalFlush(); gstate.table.GetStorage().LocalMerge(context.client, *lstate.local_collection); gstate.table.GetStorage().FinalizeOptimisticWriter(context.client, *lstate.writer); } diff --git a/src/duckdb/src/execution/operator/persistent/physical_update.cpp b/src/duckdb/src/execution/operator/persistent/physical_update.cpp index 88d30c5e6..f314eb120 100644 --- a/src/duckdb/src/execution/operator/persistent/physical_update.cpp +++ b/src/duckdb/src/execution/operator/persistent/physical_update.cpp @@ -9,9 +9,7 @@ #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/storage/table/delete_state.hpp" -#include "duckdb/storage/table/scan_state.hpp" #include "duckdb/storage/table/update_state.hpp" -#include "duckdb/transaction/duck_transaction.hpp" namespace duckdb { @@ -23,26 +21,7 @@ PhysicalUpdate::PhysicalUpdate(vector types, TableCatalogEntry &tab : PhysicalOperator(PhysicalOperatorType::UPDATE, std::move(types), estimated_cardinality), tableref(tableref), table(table), columns(std::move(columns)), expressions(std::move(expressions)), bound_defaults(std::move(bound_defaults)), bound_constraints(std::move(bound_constraints)), - return_chunk(return_chunk), index_update(false) { - - auto &indexes = table.GetDataTableInfo().get()->GetIndexes(); - auto index_columns = indexes.GetRequiredColumns(); - - unordered_set update_columns; - for (const auto col : this->columns) { - update_columns.insert(col.index); - } - - for (const auto &col : table.Columns()) { - if (index_columns.find(col.Logical().index) == index_columns.end()) { - continue; - } - if (update_columns.find(col.Physical().index) == update_columns.end()) { - continue; - } - index_update = true; - break; - } + return_chunk(return_chunk) { } //===--------------------------------------------------------------------===// @@ -56,7 +35,7 @@ class UpdateGlobalState : public GlobalSinkState { mutex lock; idx_t updated_count; - unordered_set updated_rows; + unordered_set updated_columns; ColumnDataCollection return_collection; }; @@ -66,8 +45,7 @@ class UpdateLocalState : public LocalSinkState { const vector &table_types, const vector> &bound_defaults, const vector> &bound_constraints) : default_executor(context, bound_defaults), bound_constraints(bound_constraints) { - - // Initialize the update chunk. + // initialize the update chunk auto &allocator = Allocator::Get(context); vector update_types; update_types.reserve(expressions.size()); @@ -75,15 +53,12 @@ class UpdateLocalState : public LocalSinkState { update_types.push_back(expr->return_type); } update_chunk.Initialize(allocator, update_types); - - // Initialize the mock and delete chunk. + // initialize the mock chunk mock_chunk.Initialize(allocator, table_types); - delete_chunk.Initialize(allocator, table_types); } DataChunk update_chunk; DataChunk mock_chunk; - DataChunk delete_chunk; ExpressionExecutor default_executor; unique_ptr delete_state; unique_ptr update_state; @@ -105,104 +80,79 @@ class UpdateLocalState : public LocalSinkState { }; SinkResultType PhysicalUpdate::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const { - auto &g_state = input.global_state.Cast(); - auto &l_state = input.local_state.Cast(); + auto &gstate = input.global_state.Cast(); + auto &lstate = input.local_state.Cast(); + + DataChunk &update_chunk = lstate.update_chunk; + DataChunk &mock_chunk = lstate.mock_chunk; chunk.Flatten(); - l_state.default_executor.SetChunk(chunk); + lstate.default_executor.SetChunk(chunk); - DataChunk &update_chunk = l_state.update_chunk; + // update data in the base table + // the row ids are given to us as the last column of the child chunk + auto &row_ids = chunk.data[chunk.ColumnCount() - 1]; update_chunk.Reset(); update_chunk.SetCardinality(chunk); for (idx_t i = 0; i < expressions.size(); i++) { - // Default expression, set to the default value of the column. - if (expressions[i]->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { - l_state.default_executor.ExecuteExpression(columns[i].index, update_chunk.data[i]); - continue; + if (expressions[i]->type == ExpressionType::VALUE_DEFAULT) { + // default expression, set to the default value of the column + lstate.default_executor.ExecuteExpression(columns[i].index, update_chunk.data[i]); + } else { + D_ASSERT(expressions[i]->type == ExpressionType::BOUND_REF); + // index into child chunk + auto &binding = expressions[i]->Cast(); + update_chunk.data[i].Reference(chunk.data[binding.index]); } - - D_ASSERT(expressions[i]->GetExpressionType() == ExpressionType::BOUND_REF); - auto &binding = expressions[i]->Cast(); - update_chunk.data[i].Reference(chunk.data[binding.index]); } - lock_guard glock(g_state.lock); - auto &row_ids = chunk.data[chunk.ColumnCount() - 1]; - DataChunk &mock_chunk = l_state.mock_chunk; - - // Regular in-place update. - if (!update_is_del_and_insert) { + lock_guard glock(gstate.lock); + if (update_is_del_and_insert) { + // index update or update on complex type, perform a delete and an append instead + + // figure out which rows have not yet been deleted in this update + // this is required since we might see the same row_id multiple times + // in the case of an UPDATE query that e.g. has joins + auto row_id_data = FlatVector::GetData(row_ids); + SelectionVector sel(STANDARD_VECTOR_SIZE); + idx_t update_count = 0; + for (idx_t i = 0; i < update_chunk.size(); i++) { + auto row_id = row_id_data[i]; + if (gstate.updated_columns.find(row_id) == gstate.updated_columns.end()) { + gstate.updated_columns.insert(row_id); + sel.set_index(update_count++, i); + } + } + if (update_count != update_chunk.size()) { + // we need to slice here + update_chunk.Slice(sel, update_count); + } + auto &delete_state = lstate.GetDeleteState(table, tableref, context.client); + table.Delete(delete_state, context.client, row_ids, update_chunk.size()); + // for the append we need to arrange the columns in a specific manner (namely the "standard table order") + mock_chunk.SetCardinality(update_chunk); + for (idx_t i = 0; i < columns.size(); i++) { + mock_chunk.data[columns[i].index].Reference(update_chunk.data[i]); + } + table.LocalAppend(tableref, context.client, mock_chunk, bound_constraints); + } else { if (return_chunk) { mock_chunk.SetCardinality(update_chunk); for (idx_t i = 0; i < columns.size(); i++) { mock_chunk.data[columns[i].index].Reference(update_chunk.data[i]); } } - auto &update_state = l_state.GetUpdateState(table, tableref, context.client); + auto &update_state = lstate.GetUpdateState(table, tableref, context.client); table.Update(update_state, context.client, row_ids, columns, update_chunk); - - if (return_chunk) { - g_state.return_collection.Append(mock_chunk); - } - g_state.updated_count += chunk.size(); - return SinkResultType::NEED_MORE_INPUT; } - // We update an index or a complex type, so we need to split the UPDATE into DELETE + INSERT. - - // Keep track of the rows that have not yet been deleted in this UPDATE. - // This is required since we might see the same row_id multiple times, e.g., - // during an UPDATE containing joins. - SelectionVector sel(update_chunk.size()); - idx_t update_count = 0; - auto row_id_data = FlatVector::GetData(row_ids); - - for (idx_t i = 0; i < update_chunk.size(); i++) { - auto row_id = row_id_data[i]; - if (g_state.updated_rows.find(row_id) == g_state.updated_rows.end()) { - g_state.updated_rows.insert(row_id); - sel.set_index(update_count++, i); - } - } - - // The update chunk now contains exactly those rows that we are deleting. - Vector del_row_ids(row_ids); - if (update_count != update_chunk.size()) { - update_chunk.Slice(sel, update_count); - del_row_ids.Slice(row_ids, sel, update_count); - } - - auto &delete_chunk = index_update ? l_state.delete_chunk : l_state.mock_chunk; - delete_chunk.Reset(); - delete_chunk.SetCardinality(update_count); - - if (index_update) { - auto &transaction = DuckTransaction::Get(context.client, table.db); - vector column_ids; - for (idx_t i = 0; i < table.ColumnCount(); i++) { - column_ids.emplace_back(i); - }; - // We need to fetch the previous index keys to add them to the delete index. - auto fetch_state = ColumnFetchState(); - table.Fetch(transaction, delete_chunk, column_ids, row_ids, update_count, fetch_state); - } - - auto &delete_state = l_state.GetDeleteState(table, tableref, context.client); - table.Delete(delete_state, context.client, del_row_ids, update_count); - - // Arrange the columns in the standard table order. - mock_chunk.SetCardinality(update_count); - for (idx_t i = 0; i < columns.size(); i++) { - mock_chunk.data[columns[i].index].Reference(update_chunk.data[i]); - } - - table.LocalAppend(tableref, context.client, mock_chunk, bound_constraints, del_row_ids, delete_chunk); if (return_chunk) { - g_state.return_collection.Append(mock_chunk); + gstate.return_collection.Append(mock_chunk); } - g_state.updated_count += chunk.size(); + gstate.updated_count += chunk.size(); + return SinkResultType::NEED_MORE_INPUT; } diff --git a/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp b/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp index fa150693e..9fa89e51d 100644 --- a/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp +++ b/src/duckdb/src/execution/operator/projection/physical_tableinout_function.cpp @@ -23,7 +23,7 @@ class TableInOutGlobalState : public GlobalOperatorState { PhysicalTableInOutFunction::PhysicalTableInOutFunction(vector types, TableFunction function_p, unique_ptr bind_data_p, - vector column_ids_p, idx_t estimated_cardinality, + vector column_ids_p, idx_t estimated_cardinality, vector project_input_p) : PhysicalOperator(PhysicalOperatorType::INOUT_FUNCTION, std::move(types), estimated_cardinality), function(std::move(function_p)), bind_data(std::move(bind_data_p)), column_ids(std::move(column_ids_p)), @@ -111,11 +111,7 @@ OperatorResultType PhysicalTableInOutFunction::Execute(ExecutionContext &context InsertionOrderPreservingMap PhysicalTableInOutFunction::ParamsToString() const { InsertionOrderPreservingMap result; if (function.to_string) { - TableFunctionToStringInput input(function, bind_data.get()); - auto to_string_result = function.to_string(input); - for (const auto &it : to_string_result) { - result[it.first] = it.second; - } + result["__text__"] = function.to_string(bind_data.get()); } else { result["Name"] = function.name; } diff --git a/src/duckdb/src/execution/operator/projection/physical_unnest.cpp b/src/duckdb/src/execution/operator/projection/physical_unnest.cpp index 4f32fd291..b964d91f2 100644 --- a/src/duckdb/src/execution/operator/projection/physical_unnest.cpp +++ b/src/duckdb/src/execution/operator/projection/physical_unnest.cpp @@ -19,7 +19,7 @@ class UnnestOperatorState : public OperatorState { // and set the return type in the list_data chunk, which will contain the evaluated expression results vector list_data_types; for (auto &exp : select_list) { - D_ASSERT(exp->GetExpressionType() == ExpressionType::BOUND_UNNEST); + D_ASSERT(exp->type == ExpressionType::BOUND_UNNEST); auto &bue = exp->Cast(); list_data_types.push_back(bue.child->return_type); executor.AddExpression(*bue.child.get()); diff --git a/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp b/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp index c1e2707b2..e2a67505a 100644 --- a/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_positional_scan.cpp @@ -119,7 +119,7 @@ class PositionalTableScanner { return source.ColumnCount(); } - ProgressData GetProgress(ClientContext &context) { + double GetProgress(ClientContext &context) { return table.GetProgress(context, global_state); } @@ -179,16 +179,15 @@ SourceResultType PhysicalPositionalScan::GetData(ExecutionContext &context, Data return SourceResultType::HAVE_MORE_OUTPUT; } -ProgressData PhysicalPositionalScan::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { +double PhysicalPositionalScan::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { auto &gstate = gstate_p.Cast(); - ProgressData res; - - for (size_t t = 0; t < child_tables.size(); ++t) { - res.Add(child_tables[t]->GetProgress(context, *gstate.global_states[t])); + double result = child_tables[0]->GetProgress(context, *gstate.global_states[0]); + for (size_t t = 1; t < child_tables.size(); ++t) { + result = MinValue(result, child_tables[t]->GetProgress(context, *gstate.global_states[t])); } - return res; + return result; } bool PhysicalPositionalScan::Equals(const PhysicalOperator &other_p) const { @@ -209,12 +208,4 @@ bool PhysicalPositionalScan::Equals(const PhysicalOperator &other_p) const { return true; } -vector> PhysicalPositionalScan::GetChildren() const { - auto result = PhysicalOperator::GetChildren(); - for (auto &entry : child_tables) { - result.push_back(*entry); - } - return result; -} - } // namespace duckdb diff --git a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp index 0ea996d34..27ba3982a 100644 --- a/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp +++ b/src/duckdb/src/execution/operator/scan/physical_table_scan.cpp @@ -11,7 +11,7 @@ namespace duckdb { PhysicalTableScan::PhysicalTableScan(vector types, TableFunction function_p, unique_ptr bind_data_p, vector returned_types_p, - vector column_ids_p, vector projection_ids_p, + vector column_ids_p, vector projection_ids_p, vector names_p, unique_ptr table_filters_p, idx_t estimated_cardinality, ExtraOperatorInfo extra_info, vector parameters_p) @@ -27,12 +27,8 @@ class TableScanGlobalSourceState : public GlobalSourceState { if (op.dynamic_filters && op.dynamic_filters->HasFilters()) { table_filters = op.dynamic_filters->GetFinalTableFilters(op, op.table_filters.get()); } - if (op.function.init_global) { - auto filters = table_filters ? *table_filters : GetTableFilters(op); - TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, filters, - op.extra_info.sample_options); - + TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, GetTableFilters(op)); global_state = op.function.init_global(context, input); if (global_state) { max_threads = global_state->MaxThreads(); @@ -75,7 +71,7 @@ class TableScanLocalSourceState : public LocalSourceState { const PhysicalTableScan &op) { if (op.function.init_local) { TableFunctionInitInput input(op.bind_data.get(), op.column_ids, op.projection_ids, - gstate.GetTableFilters(op), op.extra_info.sample_options); + gstate.GetTableFilters(op)); local_state = op.function.init_local(context, input, gstate.global_state.get()); } } @@ -95,111 +91,82 @@ unique_ptr PhysicalTableScan::GetGlobalSourceState(ClientCont SourceResultType PhysicalTableScan::GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const { D_ASSERT(!column_ids.empty()); - auto &g_state = input.global_state.Cast(); - auto &l_state = input.local_state.Cast(); - - TableFunctionInput data(bind_data.get(), l_state.local_state.get(), g_state.global_state.get()); + auto &gstate = input.global_state.Cast(); + auto &state = input.local_state.Cast(); + TableFunctionInput data(bind_data.get(), state.local_state.get(), gstate.global_state.get()); if (function.function) { function.function(context.client, data, chunk); - return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; + } else { + if (gstate.in_out_final) { + function.in_out_function_final(context, data, chunk); + } + function.in_out_function(context, data, gstate.input_chunk, chunk); + if (chunk.size() == 0 && function.in_out_function_final) { + function.in_out_function_final(context, data, chunk); + gstate.in_out_final = true; + } } - if (g_state.in_out_final) { - function.in_out_function_final(context, data, chunk); - } - function.in_out_function(context, data, g_state.input_chunk, chunk); - if (chunk.size() == 0 && function.in_out_function_final) { - function.in_out_function_final(context, data, chunk); - g_state.in_out_final = true; - } return chunk.size() == 0 ? SourceResultType::FINISHED : SourceResultType::HAVE_MORE_OUTPUT; } -ProgressData PhysicalTableScan::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { +double PhysicalTableScan::GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const { auto &gstate = gstate_p.Cast(); - ProgressData res; if (function.table_scan_progress) { - double table_progress = function.table_scan_progress(context, bind_data.get(), gstate.global_state.get()); - if (table_progress < 0.0) { - res.SetInvalid(); - } else { - res.done = table_progress; - res.total = 100.0; - // Assume cardinality is always 1e3 - res.Normalize(1e3); - } - } else { - // if table_scan_progress is not implemented we don't support this function yet in the progress bar - res.SetInvalid(); + return function.table_scan_progress(context, bind_data.get(), gstate.global_state.get()); } - return res; + // if table_scan_progress is not implemented we don't support this function yet in the progress bar + return -1; } -bool PhysicalTableScan::SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { - if (!function.get_partition_data) { - return false; - } - // FIXME: actually check if partition info is supported - return true; -} - -OperatorPartitionData PhysicalTableScan::GetPartitionData(ExecutionContext &context, DataChunk &chunk, - GlobalSourceState &gstate_p, LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const { - D_ASSERT(SupportsPartitioning(partition_info)); - D_ASSERT(function.get_partition_data); +idx_t PhysicalTableScan::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate_p, + LocalSourceState &lstate) const { + D_ASSERT(SupportsBatchIndex()); + D_ASSERT(function.get_batch_index); auto &gstate = gstate_p.Cast(); auto &state = lstate.Cast(); - TableFunctionGetPartitionInput input(bind_data.get(), state.local_state.get(), gstate.global_state.get(), - partition_info); - return function.get_partition_data(context.client, input); + return function.get_batch_index(context.client, bind_data.get(), state.local_state.get(), + gstate.global_state.get()); } string PhysicalTableScan::GetName() const { return StringUtil::Upper(function.name + " " + function.extra_info); } -void AddProjectionNames(const ColumnIndex &index, const string &name, const LogicalType &type, string &result) { - if (!index.HasChildren()) { - // base case - no children projected out - if (!result.empty()) { - result += "\n"; - } - result += name; - return; - } - auto &child_types = StructType::GetChildTypes(type); - for (auto &child_index : index.GetChildIndexes()) { - auto &ele = child_types[child_index.GetPrimaryIndex()]; - AddProjectionNames(child_index, name + "." + ele.first, ele.second, result); - } -} - InsertionOrderPreservingMap PhysicalTableScan::ParamsToString() const { InsertionOrderPreservingMap result; if (function.to_string) { - TableFunctionToStringInput input(function, bind_data.get()); - auto to_string_result = function.to_string(input); - for (const auto &it : to_string_result) { - result[it.first] = it.second; - } + result["__text__"] = function.to_string(bind_data.get()); } else { result["Function"] = StringUtil::Upper(function.name); } if (function.projection_pushdown) { - string projections; - idx_t projected_column_count = function.filter_prune ? projection_ids.size() : column_ids.size(); - for (idx_t i = 0; i < projected_column_count; i++) { - auto base_index = function.filter_prune ? projection_ids[i] : i; - auto &column_index = column_ids[base_index]; - auto column_id = column_index.GetPrimaryIndex(); - if (column_id >= names.size()) { - continue; + if (function.filter_prune) { + string projections; + for (idx_t i = 0; i < projection_ids.size(); i++) { + const auto &column_id = column_ids[projection_ids[i]]; + if (column_id < names.size()) { + if (i > 0) { + projections += "\n"; + } + projections += names[column_id]; + } + } + result["Projections"] = projections; + } else { + string projections; + for (idx_t i = 0; i < column_ids.size(); i++) { + const auto &column_id = column_ids[i]; + if (column_id < names.size()) { + if (i > 0) { + projections += "\n"; + } + projections += names[column_id]; + } } - AddProjectionNames(column_index, names[column_id], returned_types[column_id], projections); + result["Projections"] = projections; } - result["Projections"] = projections; } if (function.filter_pushdown && table_filters) { string filters_info; @@ -212,20 +179,11 @@ InsertionOrderPreservingMap PhysicalTableScan::ParamsToString() const { filters_info += "\n"; } first_item = false; - - const auto col_id = column_ids[column_index].GetPrimaryIndex(); - if (col_id == COLUMN_IDENTIFIER_ROW_ID) { - filters_info += filter->ToString("rowid"); - } else { - filters_info += filter->ToString(names[col_id]); - } + filters_info += filter->ToString(names[column_ids[column_index]]); } } result["Filters"] = filters_info; } - if (extra_info.sample_options) { - result["Sample Method"] = "System: " + extra_info.sample_options->sample_size.ToString() + "%"; - } if (!extra_info.file_filters.empty()) { result["File Filters"] = extra_info.file_filters; if (extra_info.filtered_files.IsValid() && extra_info.total_files.IsValid()) { diff --git a/src/duckdb/src/execution/operator/schema/physical_alter.cpp b/src/duckdb/src/execution/operator/schema/physical_alter.cpp index 0d463e5ad..0e73fc29d 100644 --- a/src/duckdb/src/execution/operator/schema/physical_alter.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_alter.cpp @@ -11,6 +11,7 @@ namespace duckdb { SourceResultType PhysicalAlter::GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const { auto &catalog = Catalog::GetCatalog(context.client, info->catalog); catalog.Alter(context.client, *info); + return SourceResultType::FINISHED; } diff --git a/src/duckdb/src/execution/operator/schema/physical_attach.cpp b/src/duckdb/src/execution/operator/schema/physical_attach.cpp index 523f0d57e..69af179f3 100644 --- a/src/duckdb/src/execution/operator/schema/physical_attach.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_attach.cpp @@ -36,6 +36,7 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c // constant-time lookup in the catalog for the db name auto existing_db = db_manager.GetDatabase(context.client, name); if (existing_db) { + if ((existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_WRITE) || (!existing_db->IsReadOnly() && options.access_mode == AccessMode::READ_ONLY)) { @@ -45,9 +46,7 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c throw BinderException("Database \"%s\" is already attached in %s mode, cannot re-attach in %s mode", name, existing_mode_str, attached_mode); } - if (!options.default_table.name.empty()) { - existing_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name); - } + return SourceResultType::FINISHED; } } @@ -71,11 +70,8 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c auto attached_db = db_manager.AttachDatabase(context.client, *info, options); //! Initialize the database. - const auto storage_options = info->GetStorageOptions(); - attached_db->Initialize(storage_options); - if (!options.default_table.name.empty()) { - attached_db->GetCatalog().SetDefaultTable(options.default_table.schema, options.default_table.name); - } + const auto block_alloc_size = info->GetBlockAllocSize(); + attached_db->Initialize(block_alloc_size); return SourceResultType::FINISHED; } diff --git a/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp b/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp index e34e49de4..7eceeecb4 100644 --- a/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp +++ b/src/duckdb/src/execution/operator/schema/physical_create_art_index.cpp @@ -16,13 +16,12 @@ namespace duckdb { PhysicalCreateARTIndex::PhysicalCreateARTIndex(LogicalOperator &op, TableCatalogEntry &table_p, const vector &column_ids, unique_ptr info, vector> unbound_expressions, - idx_t estimated_cardinality, const bool sorted, - unique_ptr alter_table_info) + idx_t estimated_cardinality, const bool sorted) : PhysicalOperator(PhysicalOperatorType::CREATE_INDEX, op.types, estimated_cardinality), table(table_p.Cast()), info(std::move(info)), unbound_expressions(std::move(unbound_expressions)), - sorted(sorted), alter_table_info(std::move(alter_table_info)) { + sorted(sorted) { - // Convert the logical column ids to physical column ids. + // Convert the virtual column ids to physical column ids. for (auto &column_id : column_ids) { storage_ids.push_back(table.GetColumns().LogicalToPhysical(LogicalIndex(column_id)).index); } @@ -83,14 +82,11 @@ SinkResultType PhysicalCreateARTIndex::SinkUnsorted(OperatorSinkInput &input) co auto &l_state = input.local_state.Cast(); auto row_count = l_state.key_chunk.size(); - auto &art = l_state.local_index->Cast(); // Insert each key and its corresponding row ID. + auto &art = l_state.local_index->Cast(); for (idx_t i = 0; i < row_count; i++) { - auto status = art.tree.GetGateStatus(); - auto conflict_type = art.Insert(art.tree, l_state.keys[i], 0, l_state.row_ids[i], status, nullptr); - D_ASSERT(conflict_type != ARTConflictType::TRANSACTION); - if (conflict_type == ARTConflictType::CONSTRAINT) { + if (!art.Insert(art.tree, l_state.keys[i], 0, l_state.row_ids[i], art.tree.GetGateStatus())) { throw ConstraintException("Data contains duplicates on indexed column(s)"); } } @@ -127,18 +123,6 @@ SinkResultType PhysicalCreateARTIndex::Sink(ExecutionContext &context, DataChunk auto &l_state = input.local_state.Cast(); l_state.arena_allocator.Reset(); l_state.key_chunk.ReferenceColumns(chunk, l_state.key_column_ids); - - // Check for NULLs, if we are creating a PRIMARY KEY. - // FIXME: Later, we want to ensure that we skip the NULL check for any non-PK alter. - if (alter_table_info) { - auto row_count = l_state.key_chunk.size(); - for (idx_t i = 0; i < l_state.key_chunk.ColumnCount(); i++) { - if (VectorOperations::HasNull(l_state.key_chunk.data[i], row_count)) { - throw ConstraintException("NOT NULL constraint failed: %s", info->index_name); - } - } - } - ART::GenerateKeyVectors(l_state.arena_allocator, l_state.key_chunk, chunk.data[chunk.ColumnCount() - 1], l_state.keys, l_state.row_ids); @@ -154,7 +138,7 @@ SinkCombineResultType PhysicalCreateARTIndex::Combine(ExecutionContext &context, auto &g_state = input.global_state.Cast(); auto &l_state = input.local_state.Cast(); - // Merge the local index into the global index. + // merge the local index into the global index if (!g_state.global_index->MergeIndexes(*l_state.local_index)) { throw ConstraintException("Data contains duplicates on indexed column(s)"); } @@ -165,54 +149,38 @@ SinkCombineResultType PhysicalCreateARTIndex::Combine(ExecutionContext &context, SinkFinalizeType PhysicalCreateARTIndex::Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const { - // Here, we set the resulting global index as the newly created index of the table. + // here, we set the resulting global index as the newly created index of the table auto &state = input.global_state.Cast(); - // Vacuum excess memory and verify. + // vacuum excess memory and verify state.global_index->Vacuum(); D_ASSERT(!state.global_index->VerifyAndToString(true).empty()); state.global_index->VerifyAllocations(); auto &storage = table.GetStorage(); if (!storage.IsRoot()) { - throw TransactionException("cannot add an index to a table that has been altered"); + throw TransactionException("Transaction conflict: cannot add an index to a table that has been altered!"); } auto &schema = table.schema; info->column_ids = storage_ids; - // FIXME: We should check for catalog exceptions prior to index creation, and later double-check. - if (!alter_table_info) { - // Ensure that the index does not yet exist in the catalog. - auto entry = schema.GetEntry(schema.GetCatalogTransaction(context), CatalogType::INDEX_ENTRY, info->index_name); - if (entry) { - if (info->on_conflict != OnCreateConflict::IGNORE_ON_CONFLICT) { - throw CatalogException("Index with name \"%s\" already exists!", info->index_name); - } - // IF NOT EXISTS on existing index. We are done. - return SinkFinalizeType::READY; + // Ensure that the index does not yet exist. + // FIXME: We should early-out prior to creating the index. + if (schema.GetEntry(schema.GetCatalogTransaction(context), CatalogType::INDEX_ENTRY, info->index_name)) { + if (info->on_conflict != OnCreateConflict::IGNORE_ON_CONFLICT) { + throw CatalogException("Index with name \"%s\" already exists!", info->index_name); } - - auto index_entry = schema.CreateIndex(schema.GetCatalogTransaction(context), *info, table).get(); - D_ASSERT(index_entry); - auto &index = index_entry->Cast(); - index.initial_index_size = state.global_index->GetInMemorySize(); - - } else { - // Ensure that there are no other indexes with that name on this table. - auto &indexes = storage.GetDataTableInfo()->GetIndexes(); - indexes.Scan([&](Index &index) { - if (index.GetIndexName() == info->index_name) { - throw CatalogException("an index with that name already exists for this table: %s", info->index_name); - } - return false; - }); - - auto &catalog = Catalog::GetCatalog(context, info->catalog); - catalog.Alter(context, *alter_table_info); + // IF NOT EXISTS on existing index. We are done. + return SinkFinalizeType::READY; } - // Add the index to the storage. + auto index_entry = schema.CreateIndex(schema.GetCatalogTransaction(context), *info, table).get(); + D_ASSERT(index_entry); + auto &index = index_entry->Cast(); + index.initial_index_size = state.global_index->GetInMemorySize(); + + // add index to storage storage.AddIndex(std::move(state.global_index)); return SinkFinalizeType::READY; } diff --git a/src/duckdb/src/execution/operator/set/physical_union.cpp b/src/duckdb/src/execution/operator/set/physical_union.cpp index 1194b9539..4954dc879 100644 --- a/src/duckdb/src/execution/operator/set/physical_union.cpp +++ b/src/duckdb/src/execution/operator/set/physical_union.cpp @@ -32,11 +32,7 @@ void PhysicalUnion::BuildPipelines(Pipeline ¤t, MetaPipeline &meta_pipelin order_matters = true; } if (sink) { - if (sink->SinkOrderDependent()) { - order_matters = true; - } - auto partition_info = sink->RequiredPartitionInfo(); - if (partition_info.batch_index) { + if (sink->SinkOrderDependent() || sink->RequiresBatchIndex()) { order_matters = true; } if (!sink->ParallelSink()) { diff --git a/src/duckdb/src/execution/physical_operator.cpp b/src/duckdb/src/execution/physical_operator.cpp index c5119620b..3fe08ddfa 100644 --- a/src/duckdb/src/execution/physical_operator.cpp +++ b/src/duckdb/src/execution/physical_operator.cpp @@ -50,7 +50,7 @@ idx_t PhysicalOperator::EstimatedThreadCount() const { idx_t result = 0; if (children.empty()) { // Terminal operator, e.g., base table, these decide the degree of parallelism of pipelines - result = MaxValue(estimated_cardinality / (DEFAULT_ROW_GROUP_SIZE * 2), 1); + result = MaxValue(estimated_cardinality / (Storage::ROW_GROUP_SIZE * 2), 1); } else if (type == PhysicalOperatorType::UNION) { // We can run union pipelines in parallel, so we sum up the thread count of the children for (auto &child : children) { @@ -116,16 +116,13 @@ SourceResultType PhysicalOperator::GetData(ExecutionContext &context, DataChunk throw InternalException("Calling GetData on a node that is not a source!"); } -OperatorPartitionData PhysicalOperator::GetPartitionData(ExecutionContext &context, DataChunk &chunk, - GlobalSourceState &gstate, LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const { - throw InternalException("Calling GetPartitionData on a node that does not support it"); +idx_t PhysicalOperator::GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate) const { + throw InternalException("Calling GetBatchIndex on a node that does not support it"); } -ProgressData PhysicalOperator::GetProgress(ClientContext &context, GlobalSourceState &gstate) const { - ProgressData res; - res.SetInvalid(); - return res; +double PhysicalOperator::GetProgress(ClientContext &context, GlobalSourceState &gstate) const { + return -1; } // LCOV_EXCL_STOP @@ -178,13 +175,10 @@ bool PhysicalOperator::OperatorCachingAllowed(ExecutionContext &context) { return false; } else if (!context.pipeline->GetSink()) { return false; + } else if (context.pipeline->GetSink()->RequiresBatchIndex()) { + return false; } else if (context.pipeline->IsOrderDependent()) { return false; - } else { - auto partition_info = context.pipeline->GetSink()->RequiredPartitionInfo(); - if (partition_info.AnyRequired()) { - return false; - } } return true; @@ -246,7 +240,7 @@ vector> PhysicalOperator::GetSources() const { bool PhysicalOperator::AllSourcesSupportBatchIndex() const { auto sources = GetSources(); for (auto &source : sources) { - if (!source.get().SupportsPartitioning(OperatorPartitionInfo::BatchIndex())) { + if (!source.get().SupportsBatchIndex()) { return false; } } diff --git a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp index c61781a33..c069fd9c7 100644 --- a/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp @@ -3,9 +3,7 @@ #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" #include "duckdb/execution/operator/aggregate/physical_perfecthash_aggregate.hpp" #include "duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp" -#include "duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" -#include "duckdb/execution/operator/scan/physical_table_scan.hpp" #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/client_context.hpp" @@ -30,88 +28,6 @@ hugeint_t GetRangeHugeint(const BaseStatistics &nstats) { return Hugeint::Convert(NumericStats::GetMax(nstats)) - Hugeint::Convert(NumericStats::GetMin(nstats)); } -static bool CanUsePartitionedAggregate(ClientContext &context, LogicalAggregate &op, PhysicalOperator &child, - vector &partition_columns) { - if (op.grouping_sets.size() > 1 || !op.grouping_functions.empty()) { - return false; - } - for (auto &expression : op.expressions) { - auto &aggregate = expression->Cast(); - if (aggregate.IsDistinct()) { - // distinct aggregates are not supported in partitioned hash aggregates - return false; - } - } - // check if the source is partitioned by the aggregate columns - // figure out the columns we are grouping by - for (auto &group_expr : op.groups) { - // only support bound reference here - if (group_expr->GetExpressionType() != ExpressionType::BOUND_REF) { - return false; - } - auto &ref = group_expr->Cast(); - partition_columns.push_back(ref.index); - } - // traverse the children of the aggregate to find the source operator - reference child_ref(child); - while (child_ref.get().type != PhysicalOperatorType::TABLE_SCAN) { - auto &child_op = child_ref.get(); - switch (child_op.type) { - case PhysicalOperatorType::PROJECTION: { - // recompute partition columns - auto &projection = child_op.Cast(); - vector new_columns; - for (auto &partition_col : partition_columns) { - // we only support bound reference here - auto &expr = projection.select_list[partition_col]; - if (expr->GetExpressionType() != ExpressionType::BOUND_REF) { - return false; - } - auto &ref = expr->Cast(); - new_columns.push_back(ref.index); - } - // continue into child node with new columns - partition_columns = std::move(new_columns); - child_ref = *child_op.children[0]; - break; - } - case PhysicalOperatorType::FILTER: - // continue into child operators - child_ref = *child_op.children[0]; - break; - default: - // unsupported operator for partition pass-through - return false; - } - } - auto &table_scan = child_ref.get().Cast(); - if (!table_scan.function.get_partition_info) { - // this source does not expose partition information - skip - return false; - } - // get the base columns by projecting over the projection_ids/column_ids - if (!table_scan.projection_ids.empty()) { - for (auto &partition_col : partition_columns) { - partition_col = table_scan.projection_ids[partition_col]; - } - } - vector base_columns; - for (const auto &partition_idx : partition_columns) { - auto col_idx = partition_idx; - col_idx = table_scan.column_ids[col_idx].GetPrimaryIndex(); - base_columns.push_back(col_idx); - } - // check if the source operator is partitioned by the grouping columns - TableFunctionPartitionInput input(table_scan.bind_data.get(), base_columns); - auto partition_info = table_scan.function.get_partition_info(context, input); - if (partition_info != TablePartitionInfo::SINGLE_VALUE_PARTITIONS) { - // we only support single-value partitions currently - return false; - } - // we have single value partitions! - return true; -} - static bool CanUsePerfectHashAggregate(ClientContext &context, LogicalAggregate &op, vector &bits_per_group) { if (op.grouping_sets.size() > 1 || !op.grouping_functions.empty()) { return false; @@ -241,19 +157,19 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalAggregate plan = ExtractAggregateExpressions(std::move(plan), op.expressions, op.groups); - bool can_use_simple_aggregation = true; - for (auto &expression : op.expressions) { - auto &aggregate = expression->Cast(); - if (!aggregate.function.simple_update) { - // unsupported aggregate for simple aggregation: use hash aggregation - can_use_simple_aggregation = false; - break; - } - } if (op.groups.empty() && op.grouping_sets.size() <= 1) { // no groups, check if we can use a simple aggregation // special case: aggregate entire columns together - if (can_use_simple_aggregation) { + bool use_simple_aggregation = true; + for (auto &expression : op.expressions) { + auto &aggregate = expression->Cast(); + if (!aggregate.function.simple_update) { + // unsupported aggregate for simple aggregation: use hash aggregation + use_simple_aggregation = false; + break; + } + } + if (use_simple_aggregation) { groupby = make_uniq_base(op.types, std::move(op.expressions), op.estimated_cardinality); } else { @@ -262,14 +178,9 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalAggregate } } else { // groups! create a GROUP BY aggregator - // use a partitioned or perfect hash aggregate if possible - vector partition_columns; + // use a perfect hash aggregate if possible vector required_bits; - if (can_use_simple_aggregation && CanUsePartitionedAggregate(context, op, *plan, partition_columns)) { - groupby = make_uniq_base( - context, op.types, std::move(op.expressions), std::move(op.groups), std::move(partition_columns), - op.estimated_cardinality); - } else if (CanUsePerfectHashAggregate(context, op, required_bits)) { + if (CanUsePerfectHashAggregate(context, op, required_bits)) { groupby = make_uniq_base( context, op.types, std::move(op.expressions), std::move(op.groups), std::move(op.group_stats), std::move(required_bits), op.estimated_cardinality); diff --git a/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp b/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp index e8d310519..5a2345bc7 100644 --- a/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp @@ -1,6 +1,4 @@ -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/execution/operator/join/perfect_hash_join_executor.hpp" -#include "duckdb/execution/operator/join/physical_blockwise_nl_join.hpp" #include "duckdb/execution/operator/join/physical_cross_product.hpp" #include "duckdb/execution/operator/join/physical_hash_join.hpp" #include "duckdb/execution/operator/join/physical_iejoin.hpp" @@ -10,21 +8,150 @@ #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/function/table/table_scan.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/transaction/duck_transaction.hpp" +#include "duckdb/common/operator/subtract.hpp" +#include "duckdb/execution/operator/join/physical_blockwise_nl_join.hpp" +#include "duckdb/planner/expression/bound_reference_expression.hpp" +#include "duckdb/planner/expression_iterator.hpp" +#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" namespace duckdb { +bool ExtractNumericValue(Value val, int64_t &result) { + if (!val.type().IsIntegral()) { + switch (val.type().InternalType()) { + case PhysicalType::INT16: + result = val.GetValueUnsafe(); + break; + case PhysicalType::INT32: + result = val.GetValueUnsafe(); + break; + case PhysicalType::INT64: + result = val.GetValueUnsafe(); + break; + default: + return false; + } + } else { + if (!val.DefaultTryCastAs(LogicalType::BIGINT)) { + return false; + } + result = val.GetValue(); + } + return true; +} + +void CheckForPerfectJoinOpt(LogicalComparisonJoin &op, PerfectHashJoinStats &join_state) { + // we only do this optimization for inner joins + if (op.join_type != JoinType::INNER) { + return; + } + // with one condition + if (op.conditions.size() != 1) { + return; + } + // with propagated statistics + if (op.join_stats.empty()) { + return; + } + for (auto &type : op.children[1]->types) { + switch (type.InternalType()) { + case PhysicalType::STRUCT: + case PhysicalType::LIST: + case PhysicalType::ARRAY: + return; + default: + break; + } + } + // with equality condition and null values not equal + for (auto &&condition : op.conditions) { + if (condition.comparison != ExpressionType::COMPARE_EQUAL) { + return; + } + } + // with integral internal types + for (auto &&join_stat : op.join_stats) { + if (!TypeIsInteger(join_stat->GetType().InternalType()) || + join_stat->GetType().InternalType() == PhysicalType::INT128 || + join_stat->GetType().InternalType() == PhysicalType::UINT128) { + // perfect join not possible for non-integral types or hugeint + return; + } + } + + // and when the build range is smaller than the threshold + auto &stats_build = *op.join_stats[1].get(); // rhs stats + if (!NumericStats::HasMinMax(stats_build)) { + return; + } + int64_t min_value, max_value; + if (!ExtractNumericValue(NumericStats::Min(stats_build), min_value) || + !ExtractNumericValue(NumericStats::Max(stats_build), max_value)) { + return; + } + if (max_value < min_value) { + // empty table + return; + } + int64_t build_range; + if (!TrySubtractOperator::Operation(max_value, min_value, build_range)) { + return; + } + + // Fill join_stats for invisible join + auto &stats_probe = *op.join_stats[0].get(); // lhs stats + if (!NumericStats::HasMinMax(stats_probe)) { + return; + } + + // The max size our build must have to run the perfect HJ + const idx_t MAX_BUILD_SIZE = 1000000; + join_state.probe_min = NumericStats::Min(stats_probe); + join_state.probe_max = NumericStats::Max(stats_probe); + join_state.build_min = NumericStats::Min(stats_build); + join_state.build_max = NumericStats::Max(stats_build); + join_state.estimated_cardinality = op.estimated_cardinality; + join_state.build_range = NumericCast(build_range); + if (join_state.build_range > MAX_BUILD_SIZE) { + return; + } + join_state.is_build_small = true; + return; +} + static void RewriteJoinCondition(Expression &expr, idx_t offset) { - if (expr.GetExpressionType() == ExpressionType::BOUND_REF) { + if (expr.type == ExpressionType::BOUND_REF) { auto &ref = expr.Cast(); ref.index += offset; } ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { RewriteJoinCondition(child, offset); }); } +bool PhysicalPlanGenerator::HasEquality(vector &conds, idx_t &range_count) { + for (size_t c = 0; c < conds.size(); ++c) { + auto &cond = conds[c]; + switch (cond.comparison) { + case ExpressionType::COMPARE_EQUAL: + case ExpressionType::COMPARE_NOT_DISTINCT_FROM: + return true; + case ExpressionType::COMPARE_LESSTHAN: + case ExpressionType::COMPARE_GREATERTHAN: + case ExpressionType::COMPARE_LESSTHANOREQUALTO: + case ExpressionType::COMPARE_GREATERTHANOREQUALTO: + ++range_count; + break; + case ExpressionType::COMPARE_NOTEQUAL: + case ExpressionType::COMPARE_DISTINCT_FROM: + break; + default: + throw NotImplementedException("Unimplemented comparison join"); + } + } + return false; +} + unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalComparisonJoin &op) { // now visit the children D_ASSERT(op.children.size() == 2); @@ -42,7 +169,7 @@ unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalCo } idx_t has_range = 0; - bool has_equality = op.HasEquality(has_range); + bool has_equality = HasEquality(op.conditions, has_range); bool can_merge = has_range > 0; bool can_iejoin = has_range >= 2 && recursive_cte_tables.empty(); switch (op.join_type) { @@ -65,12 +192,14 @@ unique_ptr PhysicalPlanGenerator::PlanComparisonJoin(LogicalCo unique_ptr plan; if (has_equality && !prefer_range_joins) { // Equality join with small number of keys : possible perfect join optimization - plan = make_uniq( - op, std::move(left), std::move(right), std::move(op.conditions), op.join_type, op.left_projection_map, - op.right_projection_map, std::move(op.mark_types), op.estimated_cardinality, std::move(op.filter_pushdown)); - plan->Cast().join_stats = std::move(op.join_stats); + PerfectHashJoinStats perfect_join_stats; + CheckForPerfectJoinOpt(op, perfect_join_stats); + plan = + make_uniq(op, std::move(left), std::move(right), std::move(op.conditions), op.join_type, + op.left_projection_map, op.right_projection_map, std::move(op.mark_types), + op.estimated_cardinality, perfect_join_stats, std::move(op.filter_pushdown)); + } else { - D_ASSERT(op.left_projection_map.empty()); if (left->estimated_cardinality <= client_config.nested_loop_join_threshold || right->estimated_cardinality <= client_config.nested_loop_join_threshold) { can_iejoin = false; diff --git a/src/duckdb/src/execution/physical_plan/plan_create_index.cpp b/src/duckdb/src/execution/physical_plan/plan_create_index.cpp index e2017c233..a7e28444b 100644 --- a/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_create_index.cpp @@ -1,17 +1,20 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" +#include "duckdb/execution/operator/filter/physical_filter.hpp" +#include "duckdb/execution/operator/schema/physical_create_art_index.hpp" #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/planner/expression/bound_operator_expression.hpp" -#include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/operator/logical_create_index.hpp" -#include "duckdb/planner/operator/logical_get.hpp" + +#include "duckdb/main/database.hpp" +#include "duckdb/execution/index/index_type.hpp" +#include "duckdb/execution/index/bound_index.hpp" namespace duckdb { unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateIndex &op) { - // Ensure that all expressions contain valid scalar functions. - // E.g., get_current_timestamp(), random(), and sequence values cannot be index keys. + + // validate that all expressions contain valid scalar functions + // e.g. get_current_timestamp(), random(), and sequence values are not allowed as index keys + // because they make deletions and lookups unfeasible for (idx_t i = 0; i < op.unbound_expressions.size(); i++) { auto &expr = op.unbound_expressions[i]; if (!expr->IsConsistent()) { @@ -19,7 +22,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateInde } } - // If we get here and the index type is not valid index type, we throw an exception. + // Do we have a valid index type? const auto index_type = context.db->config.GetIndexTypes().FindByName(op.info->index_type); if (!index_type) { throw BinderException("Unknown index type: " + op.info->index_type); @@ -28,13 +31,12 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalCreateInde throw InternalException("Index type '%s' is missing a create_plan function", op.info->index_type); } - // Add a dependency for the entire table on which we create the index. + // table scan operator for index key columns and row IDs dependencies.AddDependency(op.table); + D_ASSERT(op.info->scan_types.size() - 1 <= op.info->names.size()); D_ASSERT(op.info->scan_types.size() - 1 <= op.info->column_ids.size()); - // Generate a physical plan for the parallel index creation. - // TABLE SCAN - PROJECTION - (optional) NOT NULL FILTER - (optional) ORDER BY - CREATE INDEX D_ASSERT(op.children.size() == 1); auto table_scan = CreatePlan(*op.children[0]); diff --git a/src/duckdb/src/execution/physical_plan/plan_cte.cpp b/src/duckdb/src/execution/physical_plan/plan_cte.cpp index 9c6596279..190cb9319 100644 --- a/src/duckdb/src/execution/physical_plan/plan_cte.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_cte.cpp @@ -24,7 +24,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalMaterializ auto right = CreatePlan(*op.children[1]); unique_ptr cte; - cte = make_uniq(op.ctename, op.table_index, right->types, std::move(left), std::move(right), + cte = make_uniq(op.ctename, op.table_index, op.children[1]->types, std::move(left), std::move(right), op.estimated_cardinality); cte->working_table = working_table; cte->cte_scans = materialized_ctes[op.table_index]; diff --git a/src/duckdb/src/execution/physical_plan/plan_delete.cpp b/src/duckdb/src/execution/physical_plan/plan_delete.cpp index d6afee808..7550da083 100644 --- a/src/duckdb/src/execution/physical_plan/plan_delete.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_delete.cpp @@ -21,7 +21,7 @@ unique_ptr DuckCatalog::PlanDelete(ClientContext &context, Log unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalDelete &op) { D_ASSERT(op.children.size() == 1); D_ASSERT(op.expressions.size() == 1); - D_ASSERT(op.expressions[0]->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(op.expressions[0]->type == ExpressionType::BOUND_REF); auto plan = CreatePlan(*op.children[0]); diff --git a/src/duckdb/src/execution/physical_plan/plan_delim_join.cpp b/src/duckdb/src/execution/physical_plan/plan_delim_join.cpp index 9755f8330..e545586c6 100644 --- a/src/duckdb/src/execution/physical_plan/plan_delim_join.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_delim_join.cpp @@ -42,7 +42,7 @@ unique_ptr PhysicalPlanGenerator::PlanDelimJoin(LogicalCompari vector delim_types; vector> distinct_groups, distinct_expressions; for (auto &delim_expr : op.duplicate_eliminated_columns) { - D_ASSERT(delim_expr->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(delim_expr->type == ExpressionType::BOUND_REF); auto &bound_ref = delim_expr->Cast(); delim_types.push_back(bound_ref.return_type); distinct_groups.push_back(make_uniq(bound_ref.return_type, bound_ref.index)); diff --git a/src/duckdb/src/execution/physical_plan/plan_distinct.cpp b/src/duckdb/src/execution/physical_plan/plan_distinct.cpp index 60fdb6584..355169c33 100644 --- a/src/duckdb/src/execution/physical_plan/plan_distinct.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_distinct.cpp @@ -1,7 +1,7 @@ #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" #include "duckdb/execution/operator/projection/physical_projection.hpp" #include "duckdb/execution/physical_plan_generator.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" +#include "duckdb/function/aggregate/distributive_functions.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/operator/logical_distinct.hpp" @@ -25,7 +25,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalDistinct & // creates one group per distinct_target for (idx_t i = 0; i < distinct_targets.size(); i++) { auto &target = distinct_targets[i]; - if (target->GetExpressionType() == ExpressionType::BOUND_REF) { + if (target->type == ExpressionType::BOUND_REF) { auto &bound_ref = target->Cast(); group_by_references[bound_ref.index] = i; } @@ -59,9 +59,8 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalDistinct & first_children.push_back(std::move(bound)); FunctionBinder function_binder(context); - auto first_aggregate = - function_binder.BindAggregateFunction(FirstFunctionGetter::GetFunction(logical_type), - std::move(first_children), nullptr, AggregateType::NON_DISTINCT); + auto first_aggregate = function_binder.BindAggregateFunction( + FirstFun::GetFunction(logical_type), std::move(first_children), nullptr, AggregateType::NON_DISTINCT); first_aggregate->order_bys = op.order_by ? op.order_by->Copy() : nullptr; if (ClientConfig::GetConfig(context).enable_optimizer) { @@ -69,7 +68,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalDistinct & auto new_expr = OrderedAggregateOptimizer::Apply(context, *first_aggregate, groups, changes_made); if (new_expr) { D_ASSERT(new_expr->return_type == first_aggregate->return_type); - D_ASSERT(new_expr->GetExpressionType() == ExpressionType::BOUND_AGGREGATE); + D_ASSERT(new_expr->type == ExpressionType::BOUND_AGGREGATE); first_aggregate = unique_ptr_cast(std::move(new_expr)); } } diff --git a/src/duckdb/src/execution/physical_plan/plan_export.cpp b/src/duckdb/src/execution/physical_plan/plan_export.cpp index ff04115e3..0f4237d9c 100644 --- a/src/duckdb/src/execution/physical_plan/plan_export.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_export.cpp @@ -6,6 +6,10 @@ namespace duckdb { unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalExport &op) { + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("Export is disabled through configuration"); + } auto export_node = make_uniq(op.types, op.function, std::move(op.copy_info), op.estimated_cardinality, std::move(op.exported_tables)); // plan the underlying copy statements, if any diff --git a/src/duckdb/src/execution/physical_plan/plan_filter.cpp b/src/duckdb/src/execution/physical_plan/plan_filter.cpp index 50c1253d0..ea87121a3 100644 --- a/src/duckdb/src/execution/physical_plan/plan_filter.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_filter.cpp @@ -20,7 +20,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalFilter &op filter->children.push_back(std::move(plan)); plan = std::move(filter); } - if (op.HasProjectionMap()) { + if (!op.projection_map.empty()) { // there is a projection map, generate a physical projection vector> select_list; for (idx_t i = 0; i < op.projection_map.size(); i++) { diff --git a/src/duckdb/src/execution/physical_plan/plan_get.cpp b/src/duckdb/src/execution/physical_plan/plan_get.cpp index 3b5d940eb..2f4c65d32 100644 --- a/src/duckdb/src/execution/physical_plan/plan_get.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_get.cpp @@ -14,22 +14,22 @@ namespace duckdb { -unique_ptr CreateTableFilterSet(TableFilterSet &table_filters, const vector &column_ids) { +unique_ptr CreateTableFilterSet(TableFilterSet &table_filters, const vector &column_ids) { // create the table filter map auto table_filter_set = make_uniq(); for (auto &table_filter : table_filters.filters) { // find the relative column index from the absolute column index into the table - optional_idx column_index; + idx_t column_index = DConstants::INVALID_INDEX; for (idx_t i = 0; i < column_ids.size(); i++) { - if (table_filter.first == column_ids[i].GetPrimaryIndex()) { + if (table_filter.first == column_ids[i]) { column_index = i; break; } } - if (!column_index.IsValid()) { + if (column_index == DConstants::INVALID_INDEX) { throw InternalException("Could not find column index for table filter"); } - table_filter_set->filters[column_index.GetIndex()] = std::move(table_filter.second); + table_filter_set->filters[column_index] = std::move(table_filter.second); } return table_filter_set; } @@ -95,7 +95,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalGet &op) { unique_ptr unsupported_filter; unordered_set to_remove; for (auto &entry : table_filters->filters) { - auto column_id = column_ids[entry.first].GetPrimaryIndex(); + auto column_id = column_ids[entry.first]; auto &type = op.returned_types[column_id]; if (!op.function.supports_pushdown_type(type)) { idx_t column_id_filter = entry.first; @@ -123,8 +123,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalGet &op) { if (!select_list.empty()) { vector filter_types; for (auto &c : projection_ids) { - auto column_id = column_ids[c].GetPrimaryIndex(); - filter_types.push_back(op.returned_types[column_id]); + filter_types.push_back(op.returned_types[column_ids[c]]); } filter = make_uniq(filter_types, std::move(select_list), op.estimated_cardinality); } @@ -140,7 +139,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalGet &op) { if (column_ids.size() == op.returned_types.size()) { bool projection_necessary = false; for (idx_t i = 0; i < column_ids.size(); i++) { - if (column_ids[i].GetPrimaryIndex() != i) { + if (column_ids[i] != i) { projection_necessary = true; break; } @@ -159,15 +158,13 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalGet &op) { vector types; vector> expressions; for (auto &column_id : column_ids) { - if (column_id.IsRowIdColumn()) { - types.emplace_back(op.GetRowIdType()); - // Now how to make that a constant expression. - expressions.push_back(make_uniq(Value(op.GetRowIdType()))); + if (column_id == COLUMN_IDENTIFIER_ROW_ID) { + types.emplace_back(LogicalType::ROW_TYPE); + expressions.push_back(make_uniq(Value::BIGINT(0))); } else { - auto col_id = column_id.GetPrimaryIndex(); - auto type = op.returned_types[col_id]; + auto type = op.returned_types[column_id]; types.push_back(type); - expressions.push_back(make_uniq(type, col_id)); + expressions.push_back(make_uniq(type, column_id)); } } unique_ptr projection = diff --git a/src/duckdb/src/execution/physical_plan/plan_insert.cpp b/src/duckdb/src/execution/physical_plan/plan_insert.cpp index 2342a1ef0..0ce031d07 100644 --- a/src/duckdb/src/execution/physical_plan/plan_insert.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_insert.cpp @@ -101,7 +101,7 @@ unique_ptr DuckCatalog::PlanInsert(ClientContext &context, Log std::move(op.expressions), std::move(op.set_columns), std::move(op.set_types), op.estimated_cardinality, op.return_chunk, parallel_streaming_insert && num_threads > 1, op.action_type, std::move(op.on_conflict_condition), std::move(op.do_update_condition), std::move(op.on_conflict_filter), - std::move(op.columns_to_fetch), op.update_is_del_and_insert); + std::move(op.columns_to_fetch)); } D_ASSERT(plan); insert->children.push_back(std::move(plan)); diff --git a/src/duckdb/src/execution/physical_plan/plan_order.cpp b/src/duckdb/src/execution/physical_plan/plan_order.cpp index 449e7ee81..a7161ad30 100644 --- a/src/duckdb/src/execution/physical_plan/plan_order.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_order.cpp @@ -9,16 +9,16 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalOrder &op) auto plan = CreatePlan(*op.children[0]); if (!op.orders.empty()) { - vector projection_map; - if (op.HasProjectionMap()) { - projection_map = std::move(op.projection_map); - } else { + vector projections; + if (op.projections.empty()) { for (idx_t i = 0; i < plan->types.size(); i++) { - projection_map.push_back(i); + projections.push_back(i); } + } else { + projections = std::move(op.projections); } - auto order = make_uniq(op.types, std::move(op.orders), std::move(projection_map), - op.estimated_cardinality); + auto order = + make_uniq(op.types, std::move(op.orders), std::move(projections), op.estimated_cardinality); order->children.push_back(std::move(plan)); plan = std::move(order); } diff --git a/src/duckdb/src/execution/physical_plan/plan_prepare.cpp b/src/duckdb/src/execution/physical_plan/plan_prepare.cpp index 191377b1f..0a61e9391 100644 --- a/src/duckdb/src/execution/physical_plan/plan_prepare.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_prepare.cpp @@ -8,8 +8,8 @@ namespace duckdb { unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalPrepare &op) { D_ASSERT(op.children.size() <= 1); - // generate physical plan only when all parameters are bound (otherwise the physical plan won't be used anyway) - if (op.prepared->properties.bound_all_parameters && !op.children.empty()) { + // generate physical plan + if (!op.children.empty()) { auto plan = CreatePlan(*op.children[0]); op.prepared->types = plan->types; op.prepared->plan = std::move(plan); diff --git a/src/duckdb/src/execution/physical_plan/plan_projection.cpp b/src/duckdb/src/execution/physical_plan/plan_projection.cpp index f5f262f55..76fb36df7 100644 --- a/src/duckdb/src/execution/physical_plan/plan_projection.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_projection.cpp @@ -21,7 +21,7 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalProjection // e.g. PROJECTION(#0, #1, #2, #3, ...) bool omit_projection = true; for (idx_t i = 0; i < op.types.size(); i++) { - if (op.expressions[i]->GetExpressionType() == ExpressionType::BOUND_REF) { + if (op.expressions[i]->type == ExpressionType::BOUND_REF) { auto &bound_ref = op.expressions[i]->Cast(); if (bound_ref.index == i) { continue; diff --git a/src/duckdb/src/execution/physical_plan/plan_sample.cpp b/src/duckdb/src/execution/physical_plan/plan_sample.cpp index be5578477..e13ef8eb1 100644 --- a/src/duckdb/src/execution/physical_plan/plan_sample.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_sample.cpp @@ -3,7 +3,6 @@ #include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/planner/operator/logical_sample.hpp" #include "duckdb/common/enum_util.hpp" -#include "duckdb/common/random_engine.hpp" namespace duckdb { @@ -13,10 +12,6 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalSample &op auto plan = CreatePlan(*op.children[0]); unique_ptr sample; - if (!op.sample_options->seed.IsValid()) { - auto &random_engine = RandomEngine::Get(context); - op.sample_options->SetSeed(random_engine.NextRandomInteger()); - } switch (op.sample_options->method) { case SampleMethod::RESERVOIR_SAMPLE: sample = make_uniq(op.types, std::move(op.sample_options), op.estimated_cardinality); @@ -28,9 +23,9 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalSample &op "reservoir sampling or use a sample_size", EnumUtil::ToString(op.sample_options->method)); } - sample = make_uniq( - op.types, op.sample_options->method, op.sample_options->sample_size.GetValue(), - static_cast(op.sample_options->seed.GetIndex()), op.estimated_cardinality); + sample = make_uniq(op.types, op.sample_options->method, + op.sample_options->sample_size.GetValue(), + op.sample_options->seed, op.estimated_cardinality); break; default: throw InternalException("Unimplemented sample method"); diff --git a/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp b/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp index dada24fcf..ef0f17554 100644 --- a/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_set_operation.cpp @@ -81,10 +81,11 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalSetOperati // EXCEPT is ANTI join // INTERSECT is SEMI join + PerfectHashJoinStats join_stats; // used in inner joins only JoinType join_type = op.type == LogicalOperatorType::LOGICAL_EXCEPT ? JoinType::ANTI : JoinType::SEMI; result = make_uniq(op, std::move(left), std::move(right), std::move(conditions), join_type, - op.estimated_cardinality); + op.estimated_cardinality, join_stats); // For EXCEPT ALL / INTERSECT ALL we need to remove the row number column again if (op.setop_all) { diff --git a/src/duckdb/src/execution/physical_plan/plan_simple.cpp b/src/duckdb/src/execution/physical_plan/plan_simple.cpp index 7c03ff4f0..a13b607c4 100644 --- a/src/duckdb/src/execution/physical_plan/plan_simple.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_simple.cpp @@ -1,10 +1,11 @@ #include "duckdb/execution/operator/helper/physical_load.hpp" #include "duckdb/execution/operator/helper/physical_transaction.hpp" -#include "duckdb/execution/operator/helper/physical_update_extensions.hpp" #include "duckdb/execution/operator/helper/physical_vacuum.hpp" +#include "duckdb/execution/operator/helper/physical_update_extensions.hpp" #include "duckdb/execution/operator/schema/physical_alter.hpp" #include "duckdb/execution/operator/schema/physical_attach.hpp" #include "duckdb/execution/operator/schema/physical_create_schema.hpp" +#include "duckdb/execution/operator/schema/physical_create_sequence.hpp" #include "duckdb/execution/operator/schema/physical_create_view.hpp" #include "duckdb/execution/operator/schema/physical_detach.hpp" #include "duckdb/execution/operator/schema/physical_drop.hpp" diff --git a/src/duckdb/src/execution/physical_plan/plan_top_n.cpp b/src/duckdb/src/execution/physical_plan/plan_top_n.cpp index 700021876..9748904c5 100644 --- a/src/duckdb/src/execution/physical_plan/plan_top_n.cpp +++ b/src/duckdb/src/execution/physical_plan/plan_top_n.cpp @@ -9,9 +9,8 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(LogicalTopN &op) auto plan = CreatePlan(*op.children[0]); - auto top_n = - make_uniq(op.types, std::move(op.orders), NumericCast(op.limit), - NumericCast(op.offset), std::move(op.dynamic_filter), op.estimated_cardinality); + auto top_n = make_uniq(op.types, std::move(op.orders), NumericCast(op.limit), + NumericCast(op.offset), op.estimated_cardinality); top_n->children.push_back(std::move(plan)); return std::move(top_n); } diff --git a/src/duckdb/src/execution/physical_plan_generator.cpp b/src/duckdb/src/execution/physical_plan_generator.cpp index 1ac6f61b2..9dead0909 100644 --- a/src/duckdb/src/execution/physical_plan_generator.cpp +++ b/src/duckdb/src/execution/physical_plan_generator.cpp @@ -13,6 +13,24 @@ namespace duckdb { +class DependencyExtractor : public LogicalOperatorVisitor { +public: + explicit DependencyExtractor(LogicalDependencyList &dependencies) : dependencies(dependencies) { + } + +protected: + unique_ptr VisitReplace(BoundFunctionExpression &expr, unique_ptr *expr_ptr) override { + // extract dependencies from the bound function expression + if (expr.function.dependency) { + expr.function.dependency(expr, dependencies); + } + return nullptr; + } + +private: + LogicalDependencyList &dependencies; +}; + PhysicalPlanGenerator::PhysicalPlanGenerator(ClientContext &context) : context(context) { } @@ -33,6 +51,10 @@ unique_ptr PhysicalPlanGenerator::CreatePlan(unique_ptrResolveOperatorTypes(); profiler.EndPhase(); + // extract dependencies from the logical plan + DependencyExtractor extractor(dependencies); + extractor.VisitOperator(*op); + // then create the main physical plan profiler.StartPhase(MetricsType::PHYSICAL_PLANNER_CREATE_PLAN); auto plan = CreatePlan(*op); diff --git a/src/duckdb/src/execution/radix_partitioned_hashtable.cpp b/src/duckdb/src/execution/radix_partitioned_hashtable.cpp index cf6038fa4..cfd968100 100644 --- a/src/duckdb/src/execution/radix_partitioned_hashtable.cpp +++ b/src/duckdb/src/execution/radix_partitioned_hashtable.cpp @@ -8,6 +8,8 @@ #include "duckdb/execution/executor.hpp" #include "duckdb/execution/ht_entry.hpp" #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/parallel/event.hpp" #include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/storage/temporary_memory_manager.hpp" @@ -48,7 +50,7 @@ void RadixPartitionedHashTable::SetGroupingValues() { for (idx_t i = 0; i < grouping.size(); i++) { if (grouping_set.find(grouping[i]) == grouping_set.end()) { // We don't group on this value! - grouping_value += 1LL << (grouping.size() - (i + 1)); + grouping_value += (int64_t)1 << (grouping.size() - (i + 1)); } } grouping_values.push_back(Value::BIGINT(grouping_value)); @@ -92,60 +94,51 @@ class RadixHTGlobalSinkState; struct RadixHTConfig { public: - explicit RadixHTConfig(RadixHTGlobalSinkState &sink); + explicit RadixHTConfig(ClientContext &context, RadixHTGlobalSinkState &sink); - void SetRadixBits(const idx_t &radix_bits_p); + void SetRadixBits(idx_t radix_bits_p); bool SetRadixBitsToExternal(); idx_t GetRadixBits() const; private: - void SetRadixBitsInternal(idx_t radix_bits_p, bool external); - idx_t InitialSinkRadixBits() const; - idx_t MaximumSinkRadixBits() const; - idx_t SinkCapacity() const; - -private: - //! The global sink state - RadixHTGlobalSinkState &sink; - -public: - //! Number of threads (from TaskScheduler) - const idx_t number_of_threads; - //! Width of tuples - const idx_t row_width; - //! Capacity of HTs during the Sink - const idx_t sink_capacity; + void SetRadixBitsInternal(const idx_t radix_bits_p, bool external); + static idx_t InitialSinkRadixBits(ClientContext &context); + static idx_t MaximumSinkRadixBits(ClientContext &context); + static idx_t ExternalRadixBits(const idx_t &maximum_sink_radix_bits_p); + static idx_t SinkCapacity(ClientContext &context); private: //! Assume (1 << 15) = 32KB L1 cache per core, divided by two because hyperthreading - static constexpr idx_t L1_CACHE_SIZE = 32768 / 2; + static constexpr const idx_t L1_CACHE_SIZE = 32768 / 2; //! Assume (1 << 20) = 1MB L2 cache per core, divided by two because hyperthreading - static constexpr idx_t L2_CACHE_SIZE = 1048576 / 2; + static constexpr const idx_t L2_CACHE_SIZE = 1048576 / 2; //! Assume (1 << 20) + (1 << 19) = 1.5MB L3 cache per core (shared), divided by two because hyperthreading - static constexpr idx_t L3_CACHE_SIZE = 1572864 / 2; + static constexpr const idx_t L3_CACHE_SIZE = 1572864 / 2; //! Sink radix bits to initialize with - static constexpr idx_t MAXIMUM_INITIAL_SINK_RADIX_BITS = 4; + static constexpr const idx_t MAXIMUM_INITIAL_SINK_RADIX_BITS = 3; //! Maximum Sink radix bits (independent of threads) - static constexpr idx_t MAXIMUM_FINAL_SINK_RADIX_BITS = 8; + static constexpr const idx_t MAXIMUM_FINAL_SINK_RADIX_BITS = 7; + //! By how many radix bits to increment if we go external + static constexpr const idx_t EXTERNAL_RADIX_BITS_INCREMENT = 3; + //! The global sink state + RadixHTGlobalSinkState &sink; //! Current thread-global sink radix bits atomic sink_radix_bits; //! Maximum Sink radix bits (set based on number of threads) const idx_t maximum_sink_radix_bits; - - //! Thresholds at which we reduce the sink radix bits - //! This needed to reduce cache misses when we have very wide rows - static constexpr idx_t ROW_WIDTH_THRESHOLD_ONE = 32; - static constexpr idx_t ROW_WIDTH_THRESHOLD_TWO = 64; + //! Radix bits if we go external + const idx_t external_radix_bits; public: - //! If we have this many or less threads, we grow the HT, otherwise we abandon - static constexpr idx_t GROW_STRATEGY_THREAD_THRESHOLD = 2; + //! Capacity of HTs during the Sink + const idx_t sink_capacity; + //! If we fill this many blocks per partition, we trigger a repartition - static constexpr double BLOCK_FILL_FACTOR = 1.8; + static constexpr const double BLOCK_FILL_FACTOR = 1.8; //! By how many bits to repartition if a repartition is triggered - static constexpr idx_t REPARTITION_RADIX_BITS = 2; + static constexpr const idx_t REPARTITION_RADIX_BITS = 2; }; class RadixHTGlobalSinkState : public GlobalSinkState { @@ -160,7 +153,11 @@ class RadixHTGlobalSinkState : public GlobalSinkState { ClientContext &context; //! Temporary memory state for managing this hash table's memory usage unique_ptr temporary_memory_state; - idx_t minimum_reservation; + + //! The radix HT + const RadixPartitionedHashTable &radix_ht; + //! Config for partitioning + RadixHTConfig config; //! Whether we've called Finalize bool finalized; @@ -173,16 +170,10 @@ class RadixHTGlobalSinkState : public GlobalSinkState { //! If any thread has called combine atomic any_combined; - //! The radix HT - const RadixPartitionedHashTable &radix_ht; - //! Config for partitioning - RadixHTConfig config; - //! Uncombined partitioned data that will be put into the AggregatePartitions unique_ptr uncombined_data; //! Allocators used during the Sink/Finalize vector> stored_allocators; - idx_t stored_allocators_size; //! Partitions that are finalized during GetData vector> partitions; @@ -199,11 +190,10 @@ class RadixHTGlobalSinkState : public GlobalSinkState { RadixHTGlobalSinkState::RadixHTGlobalSinkState(ClientContext &context_p, const RadixPartitionedHashTable &radix_ht_p) : context(context_p), temporary_memory_state(TemporaryMemoryManager::Get(context).Register(context)), - finalized(false), external(false), active_threads(0), + radix_ht(radix_ht_p), config(context, *this), finalized(false), external(false), active_threads(0), number_of_threads(NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads())), - any_combined(false), radix_ht(radix_ht_p), config(*this), stored_allocators_size(0), finalize_done(0), - scan_pin_properties(TupleDataPinProperties::DESTROY_AFTER_DONE), count_before_combining(0), - max_partition_size(0) { + any_combined(false), finalize_done(0), scan_pin_properties(TupleDataPinProperties::DESTROY_AFTER_DONE), + count_before_combining(0), max_partition_size(0) { // Compute minimum reservation auto block_alloc_size = BufferManager::GetBufferManager(context).GetBlockAllocSize(); @@ -220,7 +210,7 @@ RadixHTGlobalSinkState::RadixHTGlobalSinkState(ClientContext &context_p, const R // This really is the minimum reservation that we can do auto num_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); - minimum_reservation = num_threads * ht_size; + auto minimum_reservation = num_threads * ht_size; temporary_memory_state->SetMinimumReservation(minimum_reservation); temporary_memory_state->SetRemainingSizeAndUpdateReservation(context, minimum_reservation); @@ -261,18 +251,18 @@ void RadixHTGlobalSinkState::Destroy() { } // LCOV_EXCL_STOP -RadixHTConfig::RadixHTConfig(RadixHTGlobalSinkState &sink_p) - : sink(sink_p), number_of_threads(sink.number_of_threads), row_width(sink.radix_ht.GetLayout().GetRowWidth()), - sink_capacity(SinkCapacity()), sink_radix_bits(InitialSinkRadixBits()), - maximum_sink_radix_bits(MaximumSinkRadixBits()) { +RadixHTConfig::RadixHTConfig(ClientContext &context, RadixHTGlobalSinkState &sink_p) + : sink(sink_p), sink_radix_bits(InitialSinkRadixBits(context)), + maximum_sink_radix_bits(MaximumSinkRadixBits(context)), + external_radix_bits(ExternalRadixBits(maximum_sink_radix_bits)), sink_capacity(SinkCapacity(context)) { } -void RadixHTConfig::SetRadixBits(const idx_t &radix_bits_p) { +void RadixHTConfig::SetRadixBits(idx_t radix_bits_p) { SetRadixBitsInternal(MinValue(radix_bits_p, maximum_sink_radix_bits), false); } bool RadixHTConfig::SetRadixBitsToExternal() { - SetRadixBitsInternal(MAXIMUM_FINAL_SINK_RADIX_BITS, true); + SetRadixBitsInternal(external_radix_bits, true); return sink.external; } @@ -294,36 +284,35 @@ void RadixHTConfig::SetRadixBitsInternal(const idx_t radix_bits_p, bool external sink.external = true; } sink_radix_bits = radix_bits_p; + return; } -idx_t RadixHTConfig::InitialSinkRadixBits() const { - return MinValue(RadixPartitioning::RadixBitsOfPowerOfTwo(NextPowerOfTwo(number_of_threads)), - MAXIMUM_INITIAL_SINK_RADIX_BITS); +idx_t RadixHTConfig::InitialSinkRadixBits(ClientContext &context) { + const auto active_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); + return MinValue(RadixPartitioning::RadixBits(NextPowerOfTwo(active_threads)), MAXIMUM_INITIAL_SINK_RADIX_BITS); } -idx_t RadixHTConfig::MaximumSinkRadixBits() const { - if (number_of_threads <= GROW_STRATEGY_THREAD_THRESHOLD) { - return InitialSinkRadixBits(); // Don't repartition unless we go external - } - // If rows are very wide we have to reduce the number of partitions, otherwise cache misses get out of hand - if (row_width >= ROW_WIDTH_THRESHOLD_TWO) { - return MAXIMUM_FINAL_SINK_RADIX_BITS - 2; - } - if (row_width >= ROW_WIDTH_THRESHOLD_ONE) { - return MAXIMUM_FINAL_SINK_RADIX_BITS - 1; - } - return MAXIMUM_FINAL_SINK_RADIX_BITS; +idx_t RadixHTConfig::MaximumSinkRadixBits(ClientContext &context) { + const auto active_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); + return MinValue(RadixPartitioning::RadixBits(NextPowerOfTwo(active_threads)), MAXIMUM_FINAL_SINK_RADIX_BITS); } -idx_t RadixHTConfig::SinkCapacity() const { +idx_t RadixHTConfig::ExternalRadixBits(const idx_t &maximum_sink_radix_bits_p) { + return MinValue(maximum_sink_radix_bits_p + EXTERNAL_RADIX_BITS_INCREMENT, MAXIMUM_FINAL_SINK_RADIX_BITS); +} + +idx_t RadixHTConfig::SinkCapacity(ClientContext &context) { + // Get active and maximum number of threads + const auto active_threads = NumericCast(TaskScheduler::GetScheduler(context).NumberOfThreads()); + // Compute cache size per active thread (assuming cache is shared) - const auto total_shared_cache_size = number_of_threads * L3_CACHE_SIZE; - const auto cache_per_active_thread = L1_CACHE_SIZE + L2_CACHE_SIZE + total_shared_cache_size / number_of_threads; + const auto total_shared_cache_size = active_threads * L3_CACHE_SIZE; + const auto cache_per_active_thread = L1_CACHE_SIZE + L2_CACHE_SIZE + total_shared_cache_size / active_threads; // Divide cache per active thread by entry size, round up to next power of two, to get capacity - const auto size_per_entry = LossyNumericCast(sizeof(ht_entry_t) * GroupedAggregateHashTable::LOAD_FACTOR) + - MinValue(row_width, ROW_WIDTH_THRESHOLD_TWO); - const auto capacity = NextPowerOfTwo(cache_per_active_thread / size_per_entry); + const auto size_per_entry = sizeof(ht_entry_t) * GroupedAggregateHashTable::LOAD_FACTOR; + const auto capacity = + NextPowerOfTwo(LossyNumericCast(static_cast(cache_per_active_thread) / size_per_entry)); // Capacity must be at least the minimum capacity return MaxValue(capacity, GroupedAggregateHashTable::InitialCapacity()); @@ -365,7 +354,7 @@ void RadixPartitionedHashTable::PopulateGroupChunk(DataChunk &group_chunk, DataC for (auto &group_idx : grouping_set) { // Retrieve the expression containing the index in the input chunk auto &group = op.groups[group_idx]; - D_ASSERT(group->GetExpressionType() == ExpressionType::BOUND_REF); + D_ASSERT(group->type == ExpressionType::BOUND_REF); auto &bound_ref_expr = group->Cast(); // Reference from input_chunk[group.index] -> group_chunk[chunk_index] group_chunk.data[chunk_index++].Reference(input_chunk.data[bound_ref_expr.index]); @@ -374,15 +363,14 @@ void RadixPartitionedHashTable::PopulateGroupChunk(DataChunk &group_chunk, DataC group_chunk.Verify(); } -void MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, RadixHTLocalSinkState &lstate) { +bool MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, RadixHTLocalSinkState &lstate) { auto &config = gstate.config; auto &ht = *lstate.ht; + auto &partitioned_data = ht.GetPartitionedData(); // Check if we're approaching the memory limit auto &temporary_memory_state = *gstate.temporary_memory_state; - const auto aggregate_allocator_size = ht.GetAggregateAllocator()->AllocationSize(); - const auto total_size = - aggregate_allocator_size + ht.GetPartitionedData().SizeInBytes() + ht.Capacity() * sizeof(ht_entry_t); + const auto total_size = partitioned_data->SizeInBytes() + ht.Capacity() * sizeof(ht_entry_t); idx_t thread_limit = temporary_memory_state.GetReservation() / gstate.number_of_threads; if (total_size > thread_limit) { // We're over the thread memory limit @@ -391,9 +379,7 @@ void MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra auto guard = gstate.Lock(); thread_limit = temporary_memory_state.GetReservation() / gstate.number_of_threads; if (total_size > thread_limit) { - // Out-of-core would be triggered below, update minimum reservation and try to increase the reservation - temporary_memory_state.SetMinimumReservation(aggregate_allocator_size * gstate.number_of_threads + - gstate.minimum_reservation); + // Out-of-core would be triggered below, try to increase the reservation auto remaining_size = MaxValue(gstate.number_of_threads * total_size, temporary_memory_state.GetRemainingSize()); temporary_memory_state.SetRemainingSizeAndUpdateReservation(context, 2 * remaining_size); @@ -410,23 +396,27 @@ void MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra BufferManager::GetBufferManager(context), gstate.radix_ht.GetLayout(), config.GetRadixBits(), gstate.radix_ht.GetLayout().ColumnCount() - 1); } + + ht.UnpinData(); + partitioned_data->Repartition(*lstate.abandoned_data); ht.SetRadixBits(gstate.config.GetRadixBits()); - ht.AcquirePartitionedData()->Repartition(*lstate.abandoned_data); + ht.InitializePartitionedData(); + return true; } } - // We can go external when there are few threads, but we shouldn't repartition here - if (gstate.number_of_threads <= RadixHTConfig::GROW_STRATEGY_THREAD_THRESHOLD) { - return; + // We can go external when there is only one active thread, but we shouldn't repartition here + if (gstate.number_of_threads < 2) { + return false; } - const auto partition_count = ht.GetPartitionedData().PartitionCount(); - const auto current_radix_bits = RadixPartitioning::RadixBitsOfPowerOfTwo(partition_count); + const auto partition_count = partitioned_data->PartitionCount(); + const auto current_radix_bits = RadixPartitioning::RadixBits(partition_count); D_ASSERT(current_radix_bits <= config.GetRadixBits()); const auto block_size = BufferManager::GetBufferManager(context).GetBlockSize(); const auto row_size_per_partition = - ht.GetPartitionedData().Count() * ht.GetPartitionedData().GetLayout().GetRowWidth() / partition_count; + partitioned_data->Count() * partitioned_data->GetLayout().GetRowWidth() / partition_count; if (row_size_per_partition > LossyNumericCast(config.BLOCK_FILL_FACTOR * static_cast(block_size))) { // We crossed our block filling threshold, try to increment radix bits config.SetRadixBits(current_radix_bits + config.REPARTITION_RADIX_BITS); @@ -434,12 +424,16 @@ void MaybeRepartition(ClientContext &context, RadixHTGlobalSinkState &gstate, Ra const auto global_radix_bits = config.GetRadixBits(); if (current_radix_bits == global_radix_bits) { - return; // We're already on the right number of radix bits + return false; // We're already on the right number of radix bits } // We're out-of-sync with the global radix bits, repartition + ht.UnpinData(); + auto old_partitioned_data = std::move(partitioned_data); ht.SetRadixBits(global_radix_bits); - ht.Repartition(); + ht.InitializePartitionedData(); + old_partitioned_data->Repartition(*ht.GetPartitionedData()); + return true; } void RadixPartitionedHashTable::Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input, @@ -457,41 +451,25 @@ void RadixPartitionedHashTable::Sink(ExecutionContext &context, DataChunk &chunk auto &ht = *lstate.ht; ht.AddChunk(group_chunk, payload_input, filter); - if (ht.Count() + STANDARD_VECTOR_SIZE < GroupedAggregateHashTable::ResizeThreshold(gstate.config.sink_capacity)) { + if (ht.Count() + STANDARD_VECTOR_SIZE < ht.ResizeThreshold()) { return; // We can fit another chunk } - if (gstate.number_of_threads > RadixHTConfig::GROW_STRATEGY_THREAD_THRESHOLD || gstate.external) { + if (gstate.number_of_threads > 2) { // 'Reset' the HT without taking its data, we can just keep appending to the same collection // This only works because we never resize the HT + ht.ClearPointerTable(); + ht.ResetCount(); // We don't do this when running with 1 or 2 threads, it only makes sense when there's many threads - ht.Abandon(); - - // Once we've inserted more than SKIP_LOOKUP_THRESHOLD tuples, - // and more than UNIQUE_PERCENTAGE_THRESHOLD were unique, - // we set the HT to skip doing lookups, which makes it blindly append data to the HT. - // This speeds up adding data, at the cost of no longer de-duplicating. - // The data will be de-duplicated later anyway - static constexpr idx_t SKIP_LOOKUP_THRESHOLD = 262144; - static constexpr double UNIQUE_PERCENTAGE_THRESHOLD = 0.95; - const auto unique_percentage = - static_cast(ht.GetPartitionedData().Count()) / static_cast(ht.GetSinkCount()); - if (ht.GetSinkCount() > SKIP_LOOKUP_THRESHOLD && unique_percentage > UNIQUE_PERCENTAGE_THRESHOLD) { - ht.SkipLookups(); - } } // Check if we need to repartition - const auto radix_bits_before = ht.GetRadixBits(); - MaybeRepartition(context.client, gstate, lstate); - const auto repartitioned = radix_bits_before != ht.GetRadixBits(); + auto repartitioned = MaybeRepartition(context.client, gstate, lstate); if (repartitioned && ht.Count() != 0) { // We repartitioned, but we didn't clear the pointer table / reset the count because we're on 1 or 2 threads - ht.Abandon(); - if (gstate.external) { - ht.Resize(gstate.config.sink_capacity); - } + ht.ClearPointerTable(); + ht.ResetCount(); } // TODO: combine early and often @@ -510,15 +488,16 @@ void RadixPartitionedHashTable::Combine(ExecutionContext &context, GlobalSinkSta MaybeRepartition(context.client, gstate, lstate); auto &ht = *lstate.ht; - auto lstate_data = ht.AcquirePartitionedData(); + ht.UnpinData(); + if (lstate.abandoned_data) { D_ASSERT(gstate.external); - D_ASSERT(lstate.abandoned_data->PartitionCount() == lstate.ht->GetPartitionedData().PartitionCount()); + D_ASSERT(lstate.abandoned_data->PartitionCount() == lstate.ht->GetPartitionedData()->PartitionCount()); D_ASSERT(lstate.abandoned_data->PartitionCount() == RadixPartitioning::NumberOfPartitions(gstate.config.GetRadixBits())); - lstate.abandoned_data->Combine(*lstate_data); + lstate.abandoned_data->Combine(*lstate.ht->GetPartitionedData()); } else { - lstate.abandoned_data = std::move(lstate_data); + lstate.abandoned_data = std::move(ht.GetPartitionedData()); } auto guard = gstate.Lock(); @@ -528,7 +507,6 @@ void RadixPartitionedHashTable::Combine(ExecutionContext &context, GlobalSinkSta gstate.uncombined_data = std::move(lstate.abandoned_data); } gstate.stored_allocators.emplace_back(ht.GetAggregateAllocator()); - gstate.stored_allocators_size += gstate.stored_allocators.back()->AllocationSize(); } void RadixPartitionedHashTable::Finalize(ClientContext &context, GlobalSinkState &gstate_p) const { @@ -563,7 +541,7 @@ void RadixPartitionedHashTable::Finalize(ClientContext &context, GlobalSinkState } // Minimum of combining one partition at a time - gstate.temporary_memory_state->SetMinimumReservation(gstate.stored_allocators_size + gstate.max_partition_size); + gstate.temporary_memory_state->SetMinimumReservation(gstate.max_partition_size); // Set size to 0 until the scan actually starts gstate.temporary_memory_state->SetZero(); gstate.finalized = true; @@ -580,15 +558,12 @@ idx_t RadixPartitionedHashTable::MaxThreads(GlobalSinkState &sink_p) const { const auto max_threads = MinValue( NumericCast(TaskScheduler::GetScheduler(sink.context).NumberOfThreads()), sink.partitions.size()); - sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation( - sink.context, sink.stored_allocators_size + max_threads * sink.max_partition_size); + sink.temporary_memory_state->SetRemainingSizeAndUpdateReservation(sink.context, + max_threads * sink.max_partition_size); - // we cannot spill aggregate state memory - const auto usable_memory = sink.temporary_memory_state->GetReservation() > sink.stored_allocators_size - ? sink.temporary_memory_state->GetReservation() - sink.max_partition_size - : 0; // This many partitions will fit given our reservation (at least 1)) - const auto partitions_fit = MaxValue(usable_memory / sink.max_partition_size, 1); + const auto partitions_fit = + MaxValue(sink.temporary_memory_state->GetReservation() / sink.max_partition_size, 1); // Mininum of the two return MinValue(partitions_fit, max_threads); @@ -709,8 +684,8 @@ SourceResultType RadixHTGlobalSourceState::AssignTask(RadixHTGlobalSinkState &si } RadixHTLocalSourceState::RadixHTLocalSourceState(ExecutionContext &context, const RadixPartitionedHashTable &radix_ht) - : task(RadixHTSourceTaskType::NO_TASK), task_idx(DConstants::INVALID_INDEX), scan_status(RadixHTScanStatus::DONE), - layout(radix_ht.GetLayout().Copy()), aggregate_allocator(BufferAllocator::Get(context.client)) { + : task(RadixHTSourceTaskType::NO_TASK), scan_status(RadixHTScanStatus::DONE), layout(radix_ht.GetLayout().Copy()), + aggregate_allocator(BufferAllocator::Get(context.client)) { auto &allocator = BufferAllocator::Get(context.client); auto scan_chunk_types = radix_ht.group_types; for (auto &aggr_type : radix_ht.op.aggregate_return_types) { @@ -756,17 +731,21 @@ void RadixHTLocalSourceState::Finalize(RadixHTGlobalSinkState &sink, RadixHTGlob ht = sink.radix_ht.CreateHT(gstate.context, MinValue(capacity, capacity_limit), 0); } else { - ht->Abandon(); + // We may want to resize here to the size of this partition, but for now we just assume uniform partition sizes + ht->InitializePartitionedData(); + ht->ClearPointerTable(); + ht->ResetCount(); } // Now combine the uncombined data using this thread's HT ht->Combine(*partition.data, &partition.progress); + ht->UnpinData(); partition.progress = 1; // Move the combined data back to the partition partition.data = make_uniq(BufferManager::GetBufferManager(gstate.context), sink.radix_ht.GetLayout()); - partition.data->Combine(*ht->AcquirePartitionedData()->GetPartitions()[0]); + partition.data->Combine(*ht->GetPartitionedData()->GetPartitions()[0]); // Update thread-global state auto guard = sink.Lock(); @@ -924,24 +903,25 @@ SourceResultType RadixPartitionedHashTable::GetData(ExecutionContext &context, D } } -ProgressData RadixPartitionedHashTable::GetProgress(ClientContext &, GlobalSinkState &sink_p, - GlobalSourceState &gstate_p) const { +double RadixPartitionedHashTable::GetProgress(ClientContext &, GlobalSinkState &sink_p, + GlobalSourceState &gstate_p) const { auto &sink = sink_p.Cast(); auto &gstate = gstate_p.Cast(); // Get partition combine progress, weigh it 2x - ProgressData progress; + double total_progress = 0; for (auto &partition : sink.partitions) { - progress.done += 2.0 * partition->progress; + total_progress += 2.0 * partition->progress; } // Get scan progress, weigh it 1x - progress.done += 1.0 * double(gstate.task_done); + total_progress += 1.0 * double(gstate.task_done); // Divide by 3x for the weights, and the number of partitions to get a value between 0 and 1 again - progress.total += 3.0 * double(sink.partitions.size()); + total_progress /= 3.0 * double(sink.partitions.size()); - return progress; + // Multiply by 100 to get a percentage + return 100.0 * total_progress; } } // namespace duckdb diff --git a/src/duckdb/src/execution/reservoir_sample.cpp b/src/duckdb/src/execution/reservoir_sample.cpp new file mode 100644 index 000000000..284e03fae --- /dev/null +++ b/src/duckdb/src/execution/reservoir_sample.cpp @@ -0,0 +1,324 @@ +#include "duckdb/execution/reservoir_sample.hpp" +#include "duckdb/common/types/data_chunk.hpp" +#include "duckdb/common/pair.hpp" + +namespace duckdb { + +void ReservoirChunk::Serialize(Serializer &serializer) const { + chunk.Serialize(serializer); +} + +unique_ptr ReservoirChunk::Deserialize(Deserializer &deserializer) { + auto result = make_uniq(); + result->chunk.Deserialize(deserializer); + return result; +} + +ReservoirSample::ReservoirSample(Allocator &allocator, idx_t sample_count, int64_t seed) + : BlockingSample(seed), allocator(allocator), sample_count(sample_count), reservoir_initialized(false) { +} + +ReservoirSample::ReservoirSample(idx_t sample_count, int64_t seed) + : ReservoirSample(Allocator::DefaultAllocator(), sample_count, seed) { +} + +void ReservoirSample::AddToReservoir(DataChunk &input) { + if (sample_count == 0) { + // sample count is 0, means no samples were requested + return; + } + old_base_reservoir_sample.num_entries_seen_total += input.size(); + // Input: A population V of n weighted items + // Output: A reservoir R with a size m + // 1: The first m items of V are inserted into R + // first we need to check if the reservoir already has "m" elements + if (!reservoir_data_chunk || reservoir_data_chunk->size() < sample_count) { + if (FillReservoir(input) == 0) { + // entire chunk was consumed by reservoir + return; + } + } + D_ASSERT(reservoir_data_chunk); + D_ASSERT(reservoir_data_chunk->size() == sample_count); + // Initialize the weights if they have not been already + if (old_base_reservoir_sample.reservoir_weights.empty()) { + old_base_reservoir_sample.InitializeReservoir(reservoir_data_chunk->size(), sample_count); + } + // find the position of next_index_to_sample relative to number of seen entries (num_entries_to_skip_b4_next_sample) + idx_t remaining = input.size(); + idx_t base_offset = 0; + while (true) { + idx_t offset = old_base_reservoir_sample.next_index_to_sample - + old_base_reservoir_sample.num_entries_to_skip_b4_next_sample; + if (offset >= remaining) { + // not in this chunk! increment current count and go to the next chunk + old_base_reservoir_sample.num_entries_to_skip_b4_next_sample += remaining; + return; + } + // in this chunk! replace the element + ReplaceElement(input, base_offset + offset); + // shift the chunk forward + remaining -= offset; + base_offset += offset; + } +} + +unique_ptr ReservoirSample::GetChunk() { + if (!reservoir_data_chunk || reservoir_data_chunk->size() == 0) { + return nullptr; + } + auto collected_sample_count = reservoir_data_chunk->size(); + if (collected_sample_count > STANDARD_VECTOR_SIZE) { + // get from the back to avoid creating two selection vectors + // one to return the first STANDARD_VECTOR_SIZE + // another to replace the reservoir_data_chunk with the first STANDARD VECTOR SIZE missing + auto ret = make_uniq(); + auto samples_remaining = collected_sample_count - STANDARD_VECTOR_SIZE; + auto reservoir_types = reservoir_data_chunk->GetTypes(); + SelectionVector sel(STANDARD_VECTOR_SIZE); + for (idx_t i = samples_remaining; i < collected_sample_count; i++) { + sel.set_index(i - samples_remaining, i); + } + ret->Initialize(allocator, reservoir_types); + ret->Slice(*reservoir_data_chunk, sel, STANDARD_VECTOR_SIZE); + ret->SetCardinality(STANDARD_VECTOR_SIZE); + // reduce capacity and cardinality of the sample data chunk + reservoir_data_chunk->SetCardinality(samples_remaining); + return ret; + } + return std::move(reservoir_data_chunk); +} + +void ReservoirSample::ReplaceElement(DataChunk &input, idx_t index_in_chunk, double with_weight) { + // replace the entry in the reservoir + // 8. The item in R with the minimum key is replaced by item vi + D_ASSERT(input.ColumnCount() == reservoir_data_chunk->ColumnCount()); + for (idx_t col_idx = 0; col_idx < input.ColumnCount(); col_idx++) { + reservoir_data_chunk->SetValue(col_idx, old_base_reservoir_sample.min_weighted_entry_index, + input.GetValue(col_idx, index_in_chunk)); + } + old_base_reservoir_sample.ReplaceElement(with_weight); +} + +void ReservoirSample::InitializeReservoir(DataChunk &input) { + reservoir_data_chunk = make_uniq(); + reservoir_data_chunk->Initialize(allocator, input.GetTypes(), sample_count); + for (idx_t col_idx = 0; col_idx < reservoir_data_chunk->ColumnCount(); col_idx++) { + FlatVector::Validity(reservoir_data_chunk->data[col_idx]).Initialize(sample_count); + } + reservoir_initialized = true; +} + +idx_t ReservoirSample::FillReservoir(DataChunk &input) { + idx_t chunk_count = input.size(); + input.Flatten(); + auto num_added_samples = reservoir_data_chunk ? reservoir_data_chunk->size() : 0; + D_ASSERT(num_added_samples <= sample_count); + + // required count is what we still need to add to the reservoir + idx_t required_count; + if (num_added_samples + chunk_count >= sample_count) { + // have to limit the count of the chunk + required_count = sample_count - num_added_samples; + } else { + // we copy the entire chunk + required_count = chunk_count; + } + input.SetCardinality(required_count); + + // initialize the reservoir + if (!reservoir_initialized) { + InitializeReservoir(input); + } + reservoir_data_chunk->Append(input, false, nullptr, required_count); + old_base_reservoir_sample.InitializeReservoir(required_count, sample_count); + + // check if there are still elements remaining in the Input data chunk that should be + // randomly sampled and potentially added. This happens if we are on a boundary + // for example, input.size() is 1024, but our sample size is 10 + if (required_count == chunk_count) { + // we are done here + return 0; + } + // we still need to process a part of the chunk + // create a selection vector of the remaining elements + SelectionVector sel(STANDARD_VECTOR_SIZE); + for (idx_t i = required_count; i < chunk_count; i++) { + sel.set_index(i - required_count, i); + } + // slice the input vector and continue + input.Slice(sel, chunk_count - required_count); + return input.size(); +} + +void ReservoirSample::Finalize() { + return; +} + +ReservoirSamplePercentage::ReservoirSamplePercentage(Allocator &allocator, double percentage, int64_t seed) + : BlockingSample(seed), allocator(allocator), sample_percentage(percentage / 100.0), current_count(0), + is_finalized(false) { + reservoir_sample_size = idx_t(sample_percentage * RESERVOIR_THRESHOLD); + current_sample = make_uniq(allocator, reservoir_sample_size, random.NextRandomInteger()); +} + +ReservoirSamplePercentage::ReservoirSamplePercentage(double percentage, int64_t seed) + : ReservoirSamplePercentage(Allocator::DefaultAllocator(), percentage, seed) { +} + +void ReservoirSamplePercentage::AddToReservoir(DataChunk &input) { + old_base_reservoir_sample.num_entries_seen_total += input.size(); + if (current_count + input.size() > RESERVOIR_THRESHOLD) { + // we don't have enough space in our current reservoir + // first check what we still need to append to the current sample + idx_t append_to_current_sample_count = RESERVOIR_THRESHOLD - current_count; + idx_t append_to_next_sample = input.size() - append_to_current_sample_count; + if (append_to_current_sample_count > 0) { + // we have elements remaining, first add them to the current sample + if (append_to_next_sample > 0) { + // we need to also add to the next sample + DataChunk new_chunk; + new_chunk.InitializeEmpty(input.GetTypes()); + new_chunk.Slice(input, *FlatVector::IncrementalSelectionVector(), append_to_current_sample_count); + new_chunk.Flatten(); + current_sample->AddToReservoir(new_chunk); + } else { + input.Flatten(); + input.SetCardinality(append_to_current_sample_count); + current_sample->AddToReservoir(input); + } + } + if (append_to_next_sample > 0) { + // slice the input for the remainder + SelectionVector sel(append_to_next_sample); + for (idx_t i = append_to_current_sample_count; i < append_to_next_sample + append_to_current_sample_count; + i++) { + sel.set_index(i - append_to_current_sample_count, i); + } + input.Slice(sel, append_to_next_sample); + } + // now our first sample is filled: append it to the set of finished samples + finished_samples.push_back(std::move(current_sample)); + + // allocate a new sample, and potentially add the remainder of the current input to that sample + current_sample = make_uniq(allocator, reservoir_sample_size, random.NextRandomInteger()); + if (append_to_next_sample > 0) { + current_sample->AddToReservoir(input); + } + current_count = append_to_next_sample; + } else { + // we can just append to the current sample + current_count += input.size(); + current_sample->AddToReservoir(input); + } +} + +unique_ptr ReservoirSamplePercentage::GetChunk() { + if (!is_finalized) { + Finalize(); + } + while (!finished_samples.empty()) { + auto &front = finished_samples.front(); + auto chunk = front->GetChunk(); + if (chunk && chunk->size() > 0) { + return chunk; + } + // move to the next sample + finished_samples.erase(finished_samples.begin()); + } + return nullptr; +} + +void ReservoirSamplePercentage::Finalize() { + // need to finalize the current sample, if any + // we are finializing, so we are starting to return chunks. Our last chunk has + // sample_percentage * RESERVOIR_THRESHOLD entries that hold samples. + // if our current count is less than the sample_percentage * RESERVOIR_THRESHOLD + // then we have sampled too much for the current_sample and we need to redo the sample + // otherwise we can just push the current sample back + // Imagine sampling 70% of 100 rows (so 70 rows). We allocate sample_percentage * RESERVOIR_THRESHOLD + // ----------------------------------------- + auto sampled_more_than_required = + static_cast(current_count) > sample_percentage * RESERVOIR_THRESHOLD || finished_samples.empty(); + if (current_count > 0 && sampled_more_than_required) { + // create a new sample + auto new_sample_size = idx_t(round(sample_percentage * static_cast(current_count))); + auto new_sample = make_uniq(allocator, new_sample_size, random.NextRandomInteger()); + while (true) { + auto chunk = current_sample->GetChunk(); + if (!chunk || chunk->size() == 0) { + break; + } + new_sample->AddToReservoir(*chunk); + } + finished_samples.push_back(std::move(new_sample)); + } else { + finished_samples.push_back(std::move(current_sample)); + } + // when finalizing, current_sample is null. All samples are now in finished samples. + current_sample = nullptr; + is_finalized = true; +} + +BaseReservoirSampling::BaseReservoirSampling(int64_t seed) : random(seed) { + next_index_to_sample = 0; + min_weight_threshold = 0; + min_weighted_entry_index = 0; + num_entries_to_skip_b4_next_sample = 0; + num_entries_seen_total = 0; +} + +BaseReservoirSampling::BaseReservoirSampling() : BaseReservoirSampling(-1) { +} + +void BaseReservoirSampling::InitializeReservoir(idx_t cur_size, idx_t sample_size) { + //! 1: The first m items of V are inserted into R + //! first we need to check if the reservoir already has "m" elements + if (cur_size == sample_size) { + //! 2. For each item vi ∈ R: Calculate a key ki = random(0, 1) + //! we then define the threshold to enter the reservoir T_w as the minimum key of R + //! we use a priority queue to extract the minimum key in O(1) time + for (idx_t i = 0; i < sample_size; i++) { + double k_i = random.NextRandom(); + reservoir_weights.emplace(-k_i, i); + } + SetNextEntry(); + } +} + +void BaseReservoirSampling::SetNextEntry() { + //! 4. Let r = random(0, 1) and Xw = log(r) / log(T_w) + auto &min_key = reservoir_weights.top(); + double t_w = -min_key.first; + double r = random.NextRandom(); + double x_w = log(r) / log(t_w); + //! 5. From the current item vc skip items until item vi , such that: + //! 6. wc +wc+1 +···+wi−1 < Xw <= wc +wc+1 +···+wi−1 +wi + //! since all our weights are 1 (uniform sampling), we can just determine the amount of elements to skip + min_weight_threshold = t_w; + min_weighted_entry_index = min_key.second; + next_index_to_sample = MaxValue(1, idx_t(round(x_w))); + num_entries_to_skip_b4_next_sample = 0; +} + +void BaseReservoirSampling::ReplaceElement(double with_weight) { + //! replace the entry in the reservoir + //! pop the minimum entry + reservoir_weights.pop(); + //! now update the reservoir + //! 8. Let tw = Tw i , r2 = random(tw,1) and vi’s key: ki = (r2)1/wi + //! 9. The new threshold Tw is the new minimum key of R + //! we generate a random number between (min_weight_threshold, 1) + double r2 = random.NextRandom(min_weight_threshold, 1); + + //! if we are merging two reservoir samples use the weight passed + if (with_weight >= 0) { + r2 = with_weight; + } + //! now we insert the new weight into the reservoir + reservoir_weights.emplace(-r2, min_weighted_entry_index); + //! we update the min entry with the new min entry in the reservoir + SetNextEntry(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/execution/sample/base_reservoir_sample.cpp b/src/duckdb/src/execution/sample/base_reservoir_sample.cpp deleted file mode 100644 index 0f0fcdf7a..000000000 --- a/src/duckdb/src/execution/sample/base_reservoir_sample.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "duckdb/execution/reservoir_sample.hpp" -#include - -namespace duckdb { - -double BaseReservoirSampling::GetMinWeightFromTuplesSeen(idx_t rows_seen_total) { - // this function was obtained using https://mycurvefit.com. Inputting multiple x, y values into - // The - switch (rows_seen_total) { - case 0: - return 0; - case 1: - return 0.000161; - case 2: - return 0.530136; - case 3: - return 0.693454; - default: { - return (0.99 - 0.355 * std::exp(-0.07 * static_cast(rows_seen_total))); - } - } -} - -BaseReservoirSampling::BaseReservoirSampling(int64_t seed) : random(seed) { - next_index_to_sample = 0; - min_weight_threshold = 0; - min_weighted_entry_index = 0; - num_entries_to_skip_b4_next_sample = 0; - num_entries_seen_total = 0; -} - -BaseReservoirSampling::BaseReservoirSampling() : BaseReservoirSampling(1) { -} - -unique_ptr BaseReservoirSampling::Copy() { - auto ret = make_uniq(1); - ret->reservoir_weights = reservoir_weights; - ret->next_index_to_sample = next_index_to_sample; - ret->min_weight_threshold = min_weight_threshold; - ret->min_weighted_entry_index = min_weighted_entry_index; - ret->num_entries_to_skip_b4_next_sample = num_entries_to_skip_b4_next_sample; - ret->num_entries_seen_total = num_entries_seen_total; - return ret; -} - -void BaseReservoirSampling::InitializeReservoirWeights(idx_t cur_size, idx_t sample_size) { - //! 1: The first m items of V are inserted into R - //! first we need to check if the reservoir already has "m" elements - //! 2. For each item vi ∈ R: Calculate a key ki = random(0, 1) - //! we then define the threshold to enter the reservoir T_w as the minimum key of R - //! we use a priority queue to extract the minimum key in O(1) time - if (cur_size == sample_size) { - //! 2. For each item vi ∈ R: Calculate a key ki = random(0, 1) - //! we then define the threshold to enter the reservoir T_w as the minimum key of R - //! we use a priority queue to extract the minimum key in O(1) time - for (idx_t i = 0; i < sample_size; i++) { - double k_i = random.NextRandom(); - reservoir_weights.emplace(-k_i, i); - } - SetNextEntry(); - } -} - -void BaseReservoirSampling::SetNextEntry() { - D_ASSERT(!reservoir_weights.empty()); - //! 4. Let r = random(0, 1) and Xw = log(r) / log(T_w) - auto &min_key = reservoir_weights.top(); - double t_w = -min_key.first; - double r = random.NextRandom32(); - double x_w = log(r) / log(t_w); - //! 5. From the current item vc skip items until item vi , such that: - //! 6. wc +wc+1 +···+wi−1 < Xw <= wc +wc+1 +···+wi−1 +wi - //! since all our weights are 1 (uniform sampling), we can just determine the amount of elements to skip - min_weight_threshold = t_w; - min_weighted_entry_index = min_key.second; - next_index_to_sample = MaxValue(1, idx_t(round(x_w))); - num_entries_to_skip_b4_next_sample = 0; -} - -void BaseReservoirSampling::ReplaceElementWithIndex(idx_t entry_index, double with_weight, bool pop) { - - if (pop) { - reservoir_weights.pop(); - } - double r2 = with_weight; - //! now we insert the new weight into the reservoir - reservoir_weights.emplace(-r2, entry_index); - //! we update the min entry with the new min entry in the reservoir - SetNextEntry(); -} - -void BaseReservoirSampling::ReplaceElement(double with_weight) { - //! replace the entry in the reservoir - //! pop the minimum entry - reservoir_weights.pop(); - //! now update the reservoir - //! 8. Let tw = Tw i , r2 = random(tw,1) and vi’s key: ki = (r2)1/wi - //! 9. The new threshold Tw is the new minimum key of R - //! we generate a random number between (min_weight_threshold, 1) - double r2 = random.NextRandom(min_weight_threshold, 1); - - //! if we are merging two reservoir samples use the weight passed - if (with_weight >= 0) { - r2 = with_weight; - } - //! now we insert the new weight into the reservoir - reservoir_weights.emplace(-r2, min_weighted_entry_index); - //! we update the min entry with the new min entry in the reservoir - SetNextEntry(); -} - -void BaseReservoirSampling::UpdateMinWeightThreshold() { - if (!reservoir_weights.empty()) { - min_weight_threshold = -reservoir_weights.top().first; - min_weighted_entry_index = reservoir_weights.top().second; - return; - } - min_weight_threshold = 1; -} - -void BaseReservoirSampling::FillWeights(SelectionVector &sel, idx_t &sel_size) { - if (!reservoir_weights.empty()) { - return; - } - D_ASSERT(reservoir_weights.empty()); - auto num_entries_seen_normalized = num_entries_seen_total / FIXED_SAMPLE_SIZE; - auto min_weight = GetMinWeightFromTuplesSeen(num_entries_seen_normalized); - for (idx_t i = 0; i < sel_size; i++) { - auto weight = random.NextRandom(min_weight, 1); - reservoir_weights.emplace(-weight, i); - } - D_ASSERT(reservoir_weights.size() <= sel_size); - SetNextEntry(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/sample/reservoir_sample.cpp b/src/duckdb/src/execution/sample/reservoir_sample.cpp deleted file mode 100644 index ba777b609..000000000 --- a/src/duckdb/src/execution/sample/reservoir_sample.cpp +++ /dev/null @@ -1,930 +0,0 @@ -#include "duckdb/execution/reservoir_sample.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include - -namespace duckdb { - -std::pair BlockingSample::PopFromWeightQueue() { - D_ASSERT(base_reservoir_sample && !base_reservoir_sample->reservoir_weights.empty()); - auto ret = base_reservoir_sample->reservoir_weights.top(); - base_reservoir_sample->reservoir_weights.pop(); - - base_reservoir_sample->UpdateMinWeightThreshold(); - D_ASSERT(base_reservoir_sample->min_weight_threshold > 0); - return ret; -} - -double BlockingSample::GetMinWeightThreshold() { - return base_reservoir_sample->min_weight_threshold; -} - -idx_t BlockingSample::GetPriorityQueueSize() { - return base_reservoir_sample->reservoir_weights.size(); -} - -void BlockingSample::Destroy() { - destroyed = true; -} - -void ReservoirChunk::Serialize(Serializer &serializer) const { - chunk.Serialize(serializer); -} - -unique_ptr ReservoirChunk::Deserialize(Deserializer &deserializer) { - auto result = make_uniq(); - result->chunk.Deserialize(deserializer); - return result; -} - -unique_ptr ReservoirChunk::Copy() const { - auto copy = make_uniq(); - copy->chunk.Initialize(Allocator::DefaultAllocator(), chunk.GetTypes()); - - chunk.Copy(copy->chunk); - return copy; -} - -ReservoirSample::ReservoirSample(idx_t sample_count, unique_ptr reservoir_chunk) - : ReservoirSample(Allocator::DefaultAllocator(), sample_count, 1) { - if (reservoir_chunk) { - this->reservoir_chunk = std::move(reservoir_chunk); - sel_size = this->reservoir_chunk->chunk.size(); - sel = SelectionVector(0, sel_size); - ExpandSerializedSample(); - } - stats_sample = true; -} - -ReservoirSample::ReservoirSample(Allocator &allocator, idx_t sample_count, int64_t seed) - : BlockingSample(seed), sample_count(sample_count), allocator(allocator) { - base_reservoir_sample = make_uniq(seed); - type = SampleType::RESERVOIR_SAMPLE; - reservoir_chunk = nullptr; - stats_sample = false; - sel = SelectionVector(sample_count); - sel_size = 0; -} - -idx_t ReservoirSample::GetSampleCount() { - return sample_count; -} - -idx_t ReservoirSample::NumSamplesCollected() const { - if (!reservoir_chunk) { - return 0; - } - return reservoir_chunk->chunk.size(); -} - -SamplingState ReservoirSample::GetSamplingState() const { - if (base_reservoir_sample->reservoir_weights.empty()) { - return SamplingState::RANDOM; - } - return SamplingState::RESERVOIR; -} - -idx_t ReservoirSample::GetActiveSampleCount() const { - switch (GetSamplingState()) { - case SamplingState::RANDOM: - return sel_size; - case SamplingState::RESERVOIR: - return base_reservoir_sample->reservoir_weights.size(); - default: - throw InternalException("Sampling State is INVALID"); - } -} - -idx_t ReservoirSample::GetTuplesSeen() const { - return base_reservoir_sample->num_entries_seen_total; -} - -DataChunk &ReservoirSample::Chunk() { - D_ASSERT(reservoir_chunk); - return reservoir_chunk->chunk; -} - -unique_ptr ReservoirSample::GetChunk() { - if (destroyed || !reservoir_chunk || Chunk().size() == 0) { - return nullptr; - } - // cannot destory internal samples. - auto ret = make_uniq(); - - SelectionVector ret_sel(STANDARD_VECTOR_SIZE); - idx_t collected_samples = GetActiveSampleCount(); - - if (collected_samples == 0) { - return nullptr; - } - - idx_t samples_remaining; - idx_t return_chunk_size; - if (collected_samples > STANDARD_VECTOR_SIZE) { - samples_remaining = collected_samples - STANDARD_VECTOR_SIZE; - return_chunk_size = STANDARD_VECTOR_SIZE; - } else { - samples_remaining = 0; - return_chunk_size = collected_samples; - } - - for (idx_t i = samples_remaining; i < collected_samples; i++) { - // pop samples and reduce size of selection vector. - if (GetSamplingState() == SamplingState::RESERVOIR) { - auto top = PopFromWeightQueue(); - ret_sel.set_index(i - samples_remaining, sel.get_index(top.second)); - } else { - ret_sel.set_index(i - samples_remaining, sel.get_index(i)); - } - sel_size -= 1; - } - - auto reservoir_types = Chunk().GetTypes(); - - ret->Initialize(allocator, reservoir_types, STANDARD_VECTOR_SIZE); - ret->Slice(Chunk(), ret_sel, return_chunk_size); - ret->SetCardinality(return_chunk_size); - return ret; -} - -unique_ptr ReservoirSample::CreateNewSampleChunk(vector &types, idx_t size) const { - auto new_sample_chunk = make_uniq(); - new_sample_chunk->chunk.Initialize(Allocator::DefaultAllocator(), types, size); - - // set the NULL columns correctly - for (idx_t col_idx = 0; col_idx < types.size(); col_idx++) { - if (!ValidSampleType(types[col_idx]) && stats_sample) { - new_sample_chunk->chunk.data[col_idx].SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(new_sample_chunk->chunk.data[col_idx], true); - } - } - return new_sample_chunk; -} - -void ReservoirSample::Vacuum() { - Verify(); - if (NumSamplesCollected() <= FIXED_SAMPLE_SIZE || !reservoir_chunk || destroyed) { - // sample is destroyed or too small to shrink - return; - } - - auto ret = Copy(); - auto ret_reservoir = duckdb::unique_ptr_cast(std::move(ret)); - reservoir_chunk = std::move(ret_reservoir->reservoir_chunk); - sel = std::move(ret_reservoir->sel); - sel_size = ret_reservoir->sel_size; - - Verify(); - // We should only have one sample chunk now. - D_ASSERT(Chunk().size() > 0 && Chunk().size() <= sample_count); -} - -unique_ptr ReservoirSample::Copy() const { - - auto ret = make_uniq(sample_count); - ret->stats_sample = stats_sample; - - ret->base_reservoir_sample = base_reservoir_sample->Copy(); - ret->destroyed = destroyed; - - if (!reservoir_chunk || destroyed) { - return unique_ptr_cast(std::move(ret)); - } - - D_ASSERT(reservoir_chunk); - - // create a new sample chunk to store new samples - auto types = reservoir_chunk->chunk.GetTypes(); - // how many values should be copied - idx_t values_to_copy = MinValue(GetActiveSampleCount(), sample_count); - - auto new_sample_chunk = CreateNewSampleChunk(types, GetReservoirChunkCapacity()); - - SelectionVector sel_copy(sel); - - ret->reservoir_chunk = std::move(new_sample_chunk); - ret->UpdateSampleAppend(ret->reservoir_chunk->chunk, reservoir_chunk->chunk, sel_copy, values_to_copy); - ret->sel = SelectionVector(values_to_copy); - for (idx_t i = 0; i < values_to_copy; i++) { - ret->sel.set_index(i, i); - } - ret->sel_size = sel_size; - D_ASSERT(ret->reservoir_chunk->chunk.size() <= sample_count); - ret->Verify(); - return unique_ptr_cast(std::move(ret)); -} - -void ReservoirSample::ConvertToReservoirSample() { - D_ASSERT(sel_size <= sample_count); - base_reservoir_sample->FillWeights(sel, sel_size); -} - -vector ReservoirSample::GetRandomizedVector(uint32_t range, uint32_t size) const { - vector ret; - ret.reserve(range); - for (uint32_t i = 0; i < range; i++) { - ret.push_back(i); - } - if (size == FIXED_SAMPLE_SIZE) { - std::shuffle(ret.begin(), ret.end(), base_reservoir_sample->random); - return ret; - } - for (uint32_t i = 0; i < size; i++) { - uint32_t random_shuffle = base_reservoir_sample->random.NextRandomInteger32(i, range); - if (random_shuffle == i) { - // leave the value where it is - continue; - } - uint32_t tmp = ret[random_shuffle]; - // basically replacing the tuple that was at index actual_sample_indexes[random_shuffle] - ret[random_shuffle] = ret[i]; - ret[i] = tmp; - } - return ret; -} - -void ReservoirSample::SimpleMerge(ReservoirSample &other) { - D_ASSERT(GetPriorityQueueSize() == 0); - D_ASSERT(other.GetPriorityQueueSize() == 0); - D_ASSERT(GetSamplingState() == SamplingState::RANDOM); - D_ASSERT(other.GetSamplingState() == SamplingState::RANDOM); - - if (other.GetActiveSampleCount() == 0 && other.GetTuplesSeen() == 0) { - return; - } - - if (GetActiveSampleCount() == 0 && GetTuplesSeen() == 0) { - sel = SelectionVector(other.sel); - sel_size = other.sel_size; - base_reservoir_sample->num_entries_seen_total = other.GetTuplesSeen(); - return; - } - - idx_t total_seen = GetTuplesSeen() + other.GetTuplesSeen(); - - auto weight_tuples_this = static_cast(GetTuplesSeen()) / static_cast(total_seen); - auto weight_tuples_other = static_cast(other.GetTuplesSeen()) / static_cast(total_seen); - - // If weights don't add up to 1, most likely a simple merge occured and no new samples were added. - // if that is the case, add the missing weight to the lower weighted sample to adjust. - // this is to avoid cases where if you have a 20k row table and add another 20k rows row by row - // then eventually the missing weights will add up, and get you a more even distribution - if (weight_tuples_this + weight_tuples_other < 1) { - weight_tuples_other += 1 - (weight_tuples_other + weight_tuples_this); - } - - idx_t keep_from_this = 0; - idx_t keep_from_other = 0; - D_ASSERT(stats_sample); - D_ASSERT(sample_count == FIXED_SAMPLE_SIZE); - D_ASSERT(sample_count == other.sample_count); - auto sample_count_double = static_cast(sample_count); - - if (weight_tuples_this > weight_tuples_other) { - keep_from_this = MinValue(static_cast(round(sample_count_double * weight_tuples_this)), - GetActiveSampleCount()); - keep_from_other = MinValue(sample_count - keep_from_this, other.GetActiveSampleCount()); - } else { - keep_from_other = MinValue(static_cast(round(sample_count_double * weight_tuples_other)), - other.GetActiveSampleCount()); - keep_from_this = MinValue(sample_count - keep_from_other, GetActiveSampleCount()); - } - - D_ASSERT(keep_from_this <= GetActiveSampleCount()); - D_ASSERT(keep_from_other <= other.GetActiveSampleCount()); - D_ASSERT(keep_from_other + keep_from_this <= FIXED_SAMPLE_SIZE); - idx_t size_after_merge = MinValue(keep_from_other + keep_from_this, FIXED_SAMPLE_SIZE); - - // Check if appending the other samples to this will go over the sample chunk size - if (reservoir_chunk->chunk.size() + keep_from_other > GetReservoirChunkCapacity()) { - Vacuum(); - } - - D_ASSERT(size_after_merge <= other.GetActiveSampleCount() + GetActiveSampleCount()); - SelectionVector chunk_sel(keep_from_other); - auto offset = reservoir_chunk->chunk.size(); - for (idx_t i = keep_from_this; i < size_after_merge; i++) { - if (i >= GetActiveSampleCount()) { - sel.set_index(GetActiveSampleCount(), offset); - sel_size += 1; - } else { - sel.set_index(i, offset); - } - chunk_sel.set_index(i - keep_from_this, other.sel.get_index(i - keep_from_this)); - offset += 1; - } - - D_ASSERT(GetActiveSampleCount() == size_after_merge); - - // Copy the rows that make it to the sample from other and put them into this. - UpdateSampleAppend(reservoir_chunk->chunk, other.reservoir_chunk->chunk, chunk_sel, keep_from_other); - base_reservoir_sample->num_entries_seen_total += other.GetTuplesSeen(); - - // if THIS has too many samples now, we conver it to a slower sample. - if (GetTuplesSeen() >= FIXED_SAMPLE_SIZE * FAST_TO_SLOW_THRESHOLD) { - ConvertToReservoirSample(); - } - Verify(); -} - -void ReservoirSample::WeightedMerge(ReservoirSample &other_sample) { - D_ASSERT(GetSamplingState() == SamplingState::RESERVOIR); - D_ASSERT(other_sample.GetSamplingState() == SamplingState::RESERVOIR); - - // Find out how many samples we want to keep. - idx_t total_samples = GetActiveSampleCount() + other_sample.GetActiveSampleCount(); - idx_t total_samples_seen = - base_reservoir_sample->num_entries_seen_total + other_sample.base_reservoir_sample->num_entries_seen_total; - idx_t num_samples_to_keep = MinValue(total_samples, MinValue(sample_count, total_samples_seen)); - - D_ASSERT(GetActiveSampleCount() <= num_samples_to_keep); - D_ASSERT(total_samples <= FIXED_SAMPLE_SIZE * 2); - - // pop from base base_reservoir weights until there are num_samples_to_keep left. - vector this_indexes_to_replace; - for (idx_t i = num_samples_to_keep; i < total_samples; i++) { - auto min_weight_this = base_reservoir_sample->min_weight_threshold; - auto min_weight_other = other_sample.base_reservoir_sample->min_weight_threshold; - // min weight threshol is always positive - if (min_weight_this > min_weight_other) { - // pop from other - other_sample.base_reservoir_sample->reservoir_weights.pop(); - other_sample.base_reservoir_sample->UpdateMinWeightThreshold(); - } else { - auto top_this = PopFromWeightQueue(); - this_indexes_to_replace.push_back(top_this.second); - base_reservoir_sample->UpdateMinWeightThreshold(); - } - } - - D_ASSERT(other_sample.GetPriorityQueueSize() + GetPriorityQueueSize() <= FIXED_SAMPLE_SIZE); - D_ASSERT(other_sample.GetPriorityQueueSize() + GetPriorityQueueSize() == num_samples_to_keep); - D_ASSERT(other_sample.reservoir_chunk->chunk.GetTypes() == reservoir_chunk->chunk.GetTypes()); - - // Prepare a selection vector to copy data from the other sample chunk to this sample chunk - SelectionVector sel_other(other_sample.GetPriorityQueueSize()); - D_ASSERT(GetPriorityQueueSize() <= num_samples_to_keep); - D_ASSERT(other_sample.GetPriorityQueueSize() >= this_indexes_to_replace.size()); - idx_t chunk_offset = 0; - - // Now push weights from other.base_reservoir_sample to this - // Depending on how many sample values "this" has, we either need to add to the selection vector - // Or replace values in "this'" selection vector - idx_t i = 0; - while (other_sample.GetPriorityQueueSize() > 0) { - auto other_top = other_sample.PopFromWeightQueue(); - idx_t index_for_new_pair = chunk_offset + reservoir_chunk->chunk.size(); - - // update the sel used to copy values from other to this - sel_other.set_index(chunk_offset, other_top.second); - if (i < this_indexes_to_replace.size()) { - auto replacement_index = this_indexes_to_replace[i]; - sel.set_index(replacement_index, index_for_new_pair); - other_top.second = replacement_index; - } else { - sel.set_index(sel_size, index_for_new_pair); - other_top.second = sel_size; - sel_size += 1; - } - - // make sure that the sample indexes are (this.sample_chunk.size() + chunk_offfset) - base_reservoir_sample->reservoir_weights.push(other_top); - chunk_offset += 1; - i += 1; - } - - D_ASSERT(GetPriorityQueueSize() == num_samples_to_keep); - - base_reservoir_sample->UpdateMinWeightThreshold(); - D_ASSERT(base_reservoir_sample->min_weight_threshold > 0); - base_reservoir_sample->num_entries_seen_total = GetTuplesSeen() + other_sample.GetTuplesSeen(); - - UpdateSampleAppend(reservoir_chunk->chunk, other_sample.reservoir_chunk->chunk, sel_other, chunk_offset); - if (reservoir_chunk->chunk.size() > FIXED_SAMPLE_SIZE * (FIXED_SAMPLE_SIZE_MULTIPLIER - 3)) { - Vacuum(); - } - - Verify(); -} - -void ReservoirSample::Merge(unique_ptr other) { - if (destroyed || other->destroyed) { - Destroy(); - return; - } - - D_ASSERT(other->type == SampleType::RESERVOIR_SAMPLE); - auto &other_sample = other->Cast(); - - // if the other sample has not collected anything yet return - if (!other_sample.reservoir_chunk || other_sample.reservoir_chunk->chunk.size() == 0) { - return; - } - - // this has not collected samples, take over the other - if (!reservoir_chunk || reservoir_chunk->chunk.size() == 0) { - base_reservoir_sample = std::move(other->base_reservoir_sample); - reservoir_chunk = std::move(other_sample.reservoir_chunk); - sel = SelectionVector(other_sample.sel); - sel_size = other_sample.sel_size; - Verify(); - return; - } - //! Both samples are still in "fast sampling" method - if (GetSamplingState() == SamplingState::RANDOM && other_sample.GetSamplingState() == SamplingState::RANDOM) { - SimpleMerge(other_sample); - return; - } - - // One or none of the samples are in "Fast Sampling" method. - // When this is the case, switch both to slow sampling - ConvertToReservoirSample(); - other_sample.ConvertToReservoirSample(); - WeightedMerge(other_sample); -} - -void ReservoirSample::ShuffleSel(SelectionVector &sel, idx_t range, idx_t size) const { - auto randomized = GetRandomizedVector(static_cast(range), static_cast(size)); - SelectionVector original_sel(range); - for (idx_t i = 0; i < range; i++) { - original_sel.set_index(i, sel.get_index(i)); - } - for (idx_t i = 0; i < size; i++) { - sel.set_index(i, original_sel.get_index(randomized[i])); - } -} - -void ReservoirSample::NormalizeWeights() { - vector> tmp_weights; - while (!base_reservoir_sample->reservoir_weights.empty()) { - auto top = base_reservoir_sample->reservoir_weights.top(); - tmp_weights.push_back(std::move(top)); - base_reservoir_sample->reservoir_weights.pop(); - } - std::sort(tmp_weights.begin(), tmp_weights.end(), - [&](std::pair a, std::pair b) { return a.second < b.second; }); - for (idx_t i = 0; i < tmp_weights.size(); i++) { - base_reservoir_sample->reservoir_weights.emplace(tmp_weights.at(i).first, i); - } - base_reservoir_sample->SetNextEntry(); -} - -void ReservoirSample::EvictOverBudgetSamples() { - Verify(); - if (!reservoir_chunk || destroyed) { - return; - } - - // since this is for serialization, we really need to make sure keep a - // minimum of 1% of the rows or 2048 rows - idx_t num_samples_to_keep = - MinValue(FIXED_SAMPLE_SIZE, static_cast(SAVE_PERCENTAGE * static_cast(GetTuplesSeen()))); - - if (num_samples_to_keep <= 0) { - reservoir_chunk->chunk.SetCardinality(0); - return; - } - - if (num_samples_to_keep == sample_count) { - return; - } - - // if we over sampled, make sure we only keep the highest percentage samples - std::unordered_set selections_to_delete; - - while (num_samples_to_keep < GetPriorityQueueSize()) { - auto top = PopFromWeightQueue(); - D_ASSERT(top.second < sel_size); - selections_to_delete.emplace(top.second); - } - - // set up reservoir chunk for the reservoir sample - D_ASSERT(reservoir_chunk->chunk.size() <= sample_count); - // create a new sample chunk to store new samples - auto types = reservoir_chunk->chunk.GetTypes(); - D_ASSERT(num_samples_to_keep <= sample_count); - D_ASSERT(stats_sample); - D_ASSERT(sample_count == FIXED_SAMPLE_SIZE); - auto new_reservoir_chunk = CreateNewSampleChunk(types, sample_count); - - // The current selection vector can potentially have 2048 valid mappings. - // If we need to save a sample with less rows than that, we need to do the following - // 1. Create a new selection vector that doesn't point to the rows we are evicting - SelectionVector new_sel(num_samples_to_keep); - idx_t offset = 0; - for (idx_t i = 0; i < num_samples_to_keep + selections_to_delete.size(); i++) { - if (selections_to_delete.find(i) == selections_to_delete.end()) { - D_ASSERT(i - offset < num_samples_to_keep); - new_sel.set_index(i - offset, sel.get_index(i)); - } else { - offset += 1; - } - } - // 2. Update row_ids in our weights so that they don't store rows ids to - // indexes in the selection vector that have been evicted. - if (!selections_to_delete.empty()) { - NormalizeWeights(); - } - - D_ASSERT(reservoir_chunk->chunk.GetTypes() == new_reservoir_chunk->chunk.GetTypes()); - - UpdateSampleAppend(new_reservoir_chunk->chunk, reservoir_chunk->chunk, new_sel, num_samples_to_keep); - // set the cardinality - new_reservoir_chunk->chunk.SetCardinality(num_samples_to_keep); - reservoir_chunk = std::move(new_reservoir_chunk); - sel_size = num_samples_to_keep; - base_reservoir_sample->UpdateMinWeightThreshold(); -} - -void ReservoirSample::ExpandSerializedSample() { - if (!reservoir_chunk) { - return; - } - - auto types = reservoir_chunk->chunk.GetTypes(); - auto new_res_chunk = CreateNewSampleChunk(types, GetReservoirChunkCapacity()); - auto copy_count = reservoir_chunk->chunk.size(); - SelectionVector tmp_sel = SelectionVector(0, copy_count); - UpdateSampleAppend(new_res_chunk->chunk, reservoir_chunk->chunk, tmp_sel, copy_count); - new_res_chunk->chunk.SetCardinality(copy_count); - std::swap(reservoir_chunk, new_res_chunk); -} - -idx_t ReservoirSample::GetReservoirChunkCapacity() const { - return sample_count + (FIXED_SAMPLE_SIZE_MULTIPLIER * FIXED_SAMPLE_SIZE); -} - -idx_t ReservoirSample::FillReservoir(DataChunk &chunk) { - - idx_t ingested_count = 0; - if (!reservoir_chunk) { - if (chunk.size() > FIXED_SAMPLE_SIZE) { - throw InternalException("Creating sample with DataChunk that is larger than the fixed sample size"); - } - auto types = chunk.GetTypes(); - // create a new sample chunk to store new samples - reservoir_chunk = CreateNewSampleChunk(types, GetReservoirChunkCapacity()); - } - - idx_t actual_sample_index_start = GetActiveSampleCount(); - D_ASSERT(reservoir_chunk->chunk.ColumnCount() == chunk.ColumnCount()); - - if (reservoir_chunk->chunk.size() < sample_count) { - ingested_count = MinValue(sample_count - reservoir_chunk->chunk.size(), chunk.size()); - auto random_other_sel = - GetRandomizedVector(static_cast(ingested_count), static_cast(ingested_count)); - SelectionVector sel_for_input_chunk(ingested_count); - for (idx_t i = 0; i < ingested_count; i++) { - sel.set_index(actual_sample_index_start + i, actual_sample_index_start + i); - sel_for_input_chunk.set_index(i, random_other_sel[i]); - } - UpdateSampleAppend(reservoir_chunk->chunk, chunk, sel_for_input_chunk, ingested_count); - sel_size += ingested_count; - } - D_ASSERT(GetActiveSampleCount() <= sample_count); - D_ASSERT(GetActiveSampleCount() >= ingested_count); - // always return how many tuples were ingested - return ingested_count; -} - -void ReservoirSample::Destroy() { - destroyed = true; -} - -SelectionVectorHelper ReservoirSample::GetReplacementIndexes(idx_t sample_chunk_offset, - idx_t theoretical_chunk_length) { - if (GetSamplingState() == SamplingState::RANDOM) { - return GetReplacementIndexesFast(sample_chunk_offset, theoretical_chunk_length); - } - return GetReplacementIndexesSlow(sample_chunk_offset, theoretical_chunk_length); -} - -SelectionVectorHelper ReservoirSample::GetReplacementIndexesFast(idx_t sample_chunk_offset, idx_t chunk_length) { - - // how much weight to the other tuples have compared to the ones in this chunk? - auto weight_tuples_other = static_cast(chunk_length) / static_cast(GetTuplesSeen() + chunk_length); - auto num_to_pop = static_cast(round(weight_tuples_other * static_cast(sample_count))); - D_ASSERT(num_to_pop <= sample_count); - D_ASSERT(num_to_pop <= sel_size); - SelectionVectorHelper ret; - - if (num_to_pop == 0) { - ret.sel = SelectionVector(num_to_pop); - ret.size = 0; - return ret; - } - std::unordered_map replacement_indexes; - SelectionVector chunk_sel(num_to_pop); - - auto random_indexes_chunk = GetRandomizedVector(static_cast(chunk_length), num_to_pop); - auto random_sel_indexes = GetRandomizedVector(static_cast(sel_size), num_to_pop); - for (idx_t i = 0; i < num_to_pop; i++) { - // update the selection vector for the reservoir sample - chunk_sel.set_index(i, random_indexes_chunk[i]); - // sel is not guaratneed to be random, so we update the indexes according to our - // random sel indexes. - sel.set_index(random_sel_indexes[i], sample_chunk_offset + i); - } - - D_ASSERT(sel_size == sample_count); - - ret.sel = SelectionVector(chunk_sel); - ret.size = num_to_pop; - return ret; -} - -SelectionVectorHelper ReservoirSample::GetReplacementIndexesSlow(const idx_t sample_chunk_offset, - const idx_t chunk_length) { - idx_t remaining = chunk_length; - std::unordered_map ret_map; - idx_t sample_chunk_index = 0; - - idx_t base_offset = 0; - - while (true) { - idx_t offset = - base_reservoir_sample->next_index_to_sample - base_reservoir_sample->num_entries_to_skip_b4_next_sample; - if (offset >= remaining) { - // not in this chunk! increment current count and go to the next chunk - base_reservoir_sample->num_entries_to_skip_b4_next_sample += remaining; - break; - } - // in this chunk! replace the element - // ret[index_in_new_chunk] = index_in_sample_chunk (the sample chunk offset will be applied later) - // D_ASSERT(sample_chunk_index == ret.size()); - ret_map[base_offset + offset] = sample_chunk_index; - double r2 = base_reservoir_sample->random.NextRandom32(base_reservoir_sample->min_weight_threshold, 1); - // replace element in our max_heap - // first get the top most pair - const auto top = PopFromWeightQueue(); - const auto index = top.second; - const auto index_in_sample_chunk = sample_chunk_offset + sample_chunk_index; - sel.set_index(index, index_in_sample_chunk); - base_reservoir_sample->ReplaceElementWithIndex(index, r2, false); - - sample_chunk_index += 1; - // shift the chunk forward - remaining -= offset; - base_offset += offset; - } - - // create selection vector to return - SelectionVector ret_sel(ret_map.size()); - D_ASSERT(sel_size == sample_count); - for (auto &kv : ret_map) { - ret_sel.set_index(kv.second, kv.first); - } - SelectionVectorHelper ret; - ret.sel = SelectionVector(ret_sel); - ret.size = static_cast(ret_map.size()); - return ret; -} - -void ReservoirSample::Finalize() { -} - -bool ReservoirSample::ValidSampleType(const LogicalType &type) { - return type.IsNumeric(); -} - -void ReservoirSample::UpdateSampleAppend(DataChunk &this_, DataChunk &other, SelectionVector &other_sel, - idx_t append_count) const { - idx_t new_size = this_.size() + append_count; - if (other.size() == 0) { - return; - } - D_ASSERT(this_.GetTypes() == other.GetTypes()); - - // UpdateSampleAppend(this_, other, other_sel, append_count); - D_ASSERT(this_.GetTypes() == other.GetTypes()); - auto types = reservoir_chunk->chunk.GetTypes(); - - for (idx_t i = 0; i < reservoir_chunk->chunk.ColumnCount(); i++) { - auto col_type = types[i]; - if (ValidSampleType(col_type) || !stats_sample) { - D_ASSERT(this_.data[i].GetVectorType() == VectorType::FLAT_VECTOR); - VectorOperations::Copy(other.data[i], this_.data[i], other_sel, append_count, 0, this_.size()); - } - } - this_.SetCardinality(new_size); -} - -void ReservoirSample::AddToReservoir(DataChunk &chunk) { - if (destroyed || chunk.size() == 0) { - return; - } - - idx_t tuples_consumed = FillReservoir(chunk); - base_reservoir_sample->num_entries_seen_total += tuples_consumed; - D_ASSERT(sample_count == 0 || reservoir_chunk->chunk.size() >= 1); - - if (tuples_consumed == chunk.size()) { - return; - } - - // the chunk filled the first FIXED_SAMPLE_SIZE chunk but still has tuples remaining - // slice the chunk and call AddToReservoir again. - if (tuples_consumed != chunk.size() && tuples_consumed != 0) { - // Fill reservoir consumed some of the chunk to reach FIXED_SAMPLE_SIZE - // now we need to - // So we slice it and call AddToReservoir - auto slice = make_uniq(); - auto samples_remaining = chunk.size() - tuples_consumed; - auto types = chunk.GetTypes(); - SelectionVector input_sel(samples_remaining); - for (idx_t i = 0; i < samples_remaining; i++) { - input_sel.set_index(i, tuples_consumed + i); - } - slice->Initialize(Allocator::DefaultAllocator(), types, samples_remaining); - slice->Slice(chunk, input_sel, samples_remaining); - slice->SetCardinality(samples_remaining); - AddToReservoir(*slice); - return; - } - - // at this point we should have collected at least sample count samples - D_ASSERT(GetActiveSampleCount() >= sample_count); - - auto chunk_sel = GetReplacementIndexes(reservoir_chunk->chunk.size(), chunk.size()); - - if (chunk_sel.size == 0) { - // not adding any samples - return; - } - idx_t size = chunk_sel.size; - D_ASSERT(size <= chunk.size()); - - UpdateSampleAppend(reservoir_chunk->chunk, chunk, chunk_sel.sel, size); - - base_reservoir_sample->num_entries_seen_total += chunk.size(); - D_ASSERT(base_reservoir_sample->reservoir_weights.size() == 0 || - base_reservoir_sample->reservoir_weights.size() == sample_count); - - Verify(); - - // if we are over the threshold, we ned to swith to slow sampling. - if (GetSamplingState() == SamplingState::RANDOM && GetTuplesSeen() >= FIXED_SAMPLE_SIZE * FAST_TO_SLOW_THRESHOLD) { - ConvertToReservoirSample(); - } - if (reservoir_chunk->chunk.size() >= (GetReservoirChunkCapacity() - (static_cast(FIXED_SAMPLE_SIZE) * 3))) { - Vacuum(); - } -} - -void ReservoirSample::Verify() { -#ifdef DEBUG - if (destroyed) { - return; - } - if (GetPriorityQueueSize() == 0) { - D_ASSERT(GetActiveSampleCount() <= sample_count); - D_ASSERT(GetTuplesSeen() >= GetActiveSampleCount()); - return; - } - if (NumSamplesCollected() > sample_count) { - D_ASSERT(GetPriorityQueueSize() == sample_count); - } else if (NumSamplesCollected() <= sample_count && GetPriorityQueueSize() > 0) { - // it's possible to collect more samples than your priority queue size. - // see sample_converts_to_reservoir_sample.test - D_ASSERT(NumSamplesCollected() >= GetPriorityQueueSize()); - } - auto base_reservoir_copy = base_reservoir_sample->Copy(); - std::unordered_map index_count; - while (!base_reservoir_copy->reservoir_weights.empty()) { - auto &pair = base_reservoir_copy->reservoir_weights.top(); - if (index_count.find(pair.second) == index_count.end()) { - index_count[pair.second] = 1; - base_reservoir_copy->reservoir_weights.pop(); - } else { - index_count[pair.second] += 1; - base_reservoir_copy->reservoir_weights.pop(); - throw InternalException("Duplicate selection index in reservoir weights"); - } - } - // TODO: Verify the Sel as well. No duplicate indices. - - if (reservoir_chunk) { - reservoir_chunk->chunk.Verify(); - } -#endif -} - -ReservoirSamplePercentage::ReservoirSamplePercentage(double percentage, int64_t seed, idx_t reservoir_sample_size) - : BlockingSample(seed), allocator(Allocator::DefaultAllocator()), sample_percentage(percentage / 100.0), - reservoir_sample_size(reservoir_sample_size), current_count(0), is_finalized(false) { - current_sample = make_uniq(allocator, reservoir_sample_size, base_reservoir_sample->random()); - type = SampleType::RESERVOIR_PERCENTAGE_SAMPLE; -} - -ReservoirSamplePercentage::ReservoirSamplePercentage(Allocator &allocator, double percentage, int64_t seed) - : BlockingSample(seed), allocator(allocator), sample_percentage(percentage / 100.0), current_count(0), - is_finalized(false) { - reservoir_sample_size = (idx_t)(sample_percentage * RESERVOIR_THRESHOLD); - current_sample = make_uniq(allocator, reservoir_sample_size, base_reservoir_sample->random()); - type = SampleType::RESERVOIR_PERCENTAGE_SAMPLE; -} - -ReservoirSamplePercentage::ReservoirSamplePercentage(double percentage, int64_t seed) - : ReservoirSamplePercentage(Allocator::DefaultAllocator(), percentage, seed) { -} - -void ReservoirSamplePercentage::AddToReservoir(DataChunk &input) { - base_reservoir_sample->num_entries_seen_total += input.size(); - if (current_count + input.size() > RESERVOIR_THRESHOLD) { - // we don't have enough space in our current reservoir - // first check what we still need to append to the current sample - idx_t append_to_current_sample_count = RESERVOIR_THRESHOLD - current_count; - idx_t append_to_next_sample = input.size() - append_to_current_sample_count; - if (append_to_current_sample_count > 0) { - // we have elements remaining, first add them to the current sample - if (append_to_next_sample > 0) { - // we need to also add to the next sample - DataChunk new_chunk; - new_chunk.InitializeEmpty(input.GetTypes()); - new_chunk.Slice(input, *FlatVector::IncrementalSelectionVector(), append_to_current_sample_count); - new_chunk.Flatten(); - current_sample->AddToReservoir(new_chunk); - } else { - input.Flatten(); - input.SetCardinality(append_to_current_sample_count); - current_sample->AddToReservoir(input); - } - } - if (append_to_next_sample > 0) { - // slice the input for the remainder - SelectionVector sel(append_to_next_sample); - for (idx_t i = append_to_current_sample_count; i < append_to_next_sample + append_to_current_sample_count; - i++) { - sel.set_index(i - append_to_current_sample_count, i); - } - input.Slice(sel, append_to_next_sample); - } - // now our first sample is filled: append it to the set of finished samples - finished_samples.push_back(std::move(current_sample)); - - // allocate a new sample, and potentially add the remainder of the current input to that sample - current_sample = make_uniq(allocator, reservoir_sample_size, base_reservoir_sample->random()); - if (append_to_next_sample > 0) { - current_sample->AddToReservoir(input); - } - current_count = append_to_next_sample; - } else { - // we can just append to the current sample - current_count += input.size(); - current_sample->AddToReservoir(input); - } -} - -unique_ptr ReservoirSamplePercentage::GetChunk() { - // reservoir sample percentage should never stay - if (!is_finalized) { - Finalize(); - } - while (!finished_samples.empty()) { - auto &front = finished_samples.front(); - auto chunk = front->GetChunk(); - if (chunk && chunk->size() > 0) { - return chunk; - } - // move to the next sample - finished_samples.erase(finished_samples.begin()); - } - return nullptr; -} - -unique_ptr ReservoirSamplePercentage::Copy() const { - throw InternalException("Cannot call Copy on ReservoirSample Percentage"); -} - -void ReservoirSamplePercentage::Finalize() { - // need to finalize the current sample, if any - // we are finializing, so we are starting to return chunks. Our last chunk has - // sample_percentage * RESERVOIR_THRESHOLD entries that hold samples. - // if our current count is less than the sample_percentage * RESERVOIR_THRESHOLD - // then we have sampled too much for the current_sample and we need to redo the sample - // otherwise we can just push the current sample back - // Imagine sampling 70% of 100 rows (so 70 rows). We allocate sample_percentage * RESERVOIR_THRESHOLD - // ----------------------------------------- - auto sampled_more_than_required = - static_cast(current_count) > sample_percentage * RESERVOIR_THRESHOLD || finished_samples.empty(); - if (current_count > 0 && sampled_more_than_required) { - // create a new sample - auto new_sample_size = static_cast(round(sample_percentage * static_cast(current_count))); - auto new_sample = make_uniq(allocator, new_sample_size, base_reservoir_sample->random()); - while (true) { - auto chunk = current_sample->GetChunk(); - if (!chunk || chunk->size() == 0) { - break; - } - new_sample->AddToReservoir(*chunk); - } - finished_samples.push_back(std::move(new_sample)); - } else { - finished_samples.push_back(std::move(current_sample)); - } - // when finalizing, current_sample is null. All samples are now in finished samples. - current_sample = nullptr; - is_finalized = true; -} - -} // namespace duckdb diff --git a/src/duckdb/src/execution/window_executor.cpp b/src/duckdb/src/execution/window_executor.cpp new file mode 100644 index 000000000..937741058 --- /dev/null +++ b/src/duckdb/src/execution/window_executor.cpp @@ -0,0 +1,1830 @@ +#include "duckdb/execution/window_executor.hpp" + +#include "duckdb/common/operator/add.hpp" +#include "duckdb/common/operator/subtract.hpp" + +#include "duckdb/common/array.hpp" + +namespace duckdb { + +//===--------------------------------------------------------------------===// +// WindowDataChunk +//===--------------------------------------------------------------------===// +bool WindowDataChunk::IsSimple(const Vector &v) { + switch (v.GetType().InternalType()) { + case PhysicalType::BOOL: + case PhysicalType::UINT8: + case PhysicalType::INT8: + case PhysicalType::UINT16: + case PhysicalType::INT16: + case PhysicalType::UINT32: + case PhysicalType::INT32: + case PhysicalType::UINT64: + case PhysicalType::INT64: + case PhysicalType::FLOAT: + case PhysicalType::DOUBLE: + case PhysicalType::INTERVAL: + case PhysicalType::UINT128: + case PhysicalType::INT128: + return true; + case PhysicalType::LIST: + case PhysicalType::STRUCT: + case PhysicalType::ARRAY: + case PhysicalType::VARCHAR: + case PhysicalType::BIT: + return false; + default: + break; + } + + throw InternalException("Unsupported type for WindowDataChunk"); +} + +WindowDataChunk::WindowDataChunk(DataChunk &chunk) : chunk(chunk) { +} + +void WindowDataChunk::Initialize(Allocator &allocator, const vector &types, idx_t capacity) { + vector new_locks(types.size()); + locks.swap(new_locks); + chunk.Initialize(allocator, types, capacity); + chunk.SetCardinality(capacity); + + is_simple.clear(); + for (const auto &v : chunk.data) { + is_simple.push_back(IsSimple(v)); + } +} + +void WindowDataChunk::Copy(DataChunk &input, idx_t begin) { + const auto source_count = input.size(); + const idx_t end = begin + source_count; + const idx_t count = chunk.size(); + D_ASSERT(end <= count); + // Can we overwrite the validity mask in parallel? + bool aligned = IsMaskAligned(begin, end, count); + for (column_t i = 0; i < chunk.data.size(); ++i) { + auto &src = input.data[i]; + auto &dst = chunk.data[i]; + UnifiedVectorFormat sdata; + src.ToUnifiedFormat(count, sdata); + if (is_simple[i] && aligned && sdata.validity.AllValid()) { + VectorOperations::Copy(src, dst, source_count, 0, begin); + } else { + lock_guard column_guard(locks[i]); + VectorOperations::Copy(src, dst, source_count, 0, begin); + } + } +} + +static idx_t FindNextStart(const ValidityMask &mask, idx_t l, const idx_t r, idx_t &n) { + if (mask.AllValid()) { + auto start = MinValue(l + n - 1, r); + n -= MinValue(n, r - l); + return start; + } + + while (l < r) { + // If l is aligned with the start of a block, and the block is blank, then skip forward one block. + idx_t entry_idx; + idx_t shift; + mask.GetEntryIndex(l, entry_idx, shift); + + const auto block = mask.GetValidityEntry(entry_idx); + if (mask.NoneValid(block) && !shift) { + l += ValidityMask::BITS_PER_VALUE; + continue; + } + + // Loop over the block + for (; shift < ValidityMask::BITS_PER_VALUE && l < r; ++shift, ++l) { + if (mask.RowIsValid(block, shift) && --n == 0) { + return MinValue(l, r); + } + } + } + + // Didn't find a start so return the end of the range + return r; +} + +static idx_t FindPrevStart(const ValidityMask &mask, const idx_t l, idx_t r, idx_t &n) { + if (mask.AllValid()) { + auto start = (r <= l + n) ? l : r - n; + n -= r - start; + return start; + } + + while (l < r) { + // If r is aligned with the start of a block, and the previous block is blank, + // then skip backwards one block. + idx_t entry_idx; + idx_t shift; + mask.GetEntryIndex(r - 1, entry_idx, shift); + + const auto block = mask.GetValidityEntry(entry_idx); + if (mask.NoneValid(block) && (shift + 1 == ValidityMask::BITS_PER_VALUE)) { + // r is nonzero (> l) and word aligned, so this will not underflow. + r -= ValidityMask::BITS_PER_VALUE; + continue; + } + + // Loop backwards over the block + // shift is probing r-1 >= l >= 0 + for (++shift; shift-- > 0 && l < r; --r) { + // l < r ensures n == 1 if result is supposed to be NULL because of EXCLUDE + if (mask.RowIsValid(block, shift) && --n == 0) { + return MaxValue(l, r - 1); + } + } + } + + // Didn't find a start so return the start of the range + return l; +} + +template +static T GetCell(const DataChunk &chunk, idx_t column, idx_t index) { + D_ASSERT(chunk.ColumnCount() > column); + auto &source = chunk.data[column]; + const auto data = FlatVector::GetData(source); + return data[index]; +} + +static bool CellIsNull(const DataChunk &chunk, idx_t column, idx_t index) { + D_ASSERT(chunk.ColumnCount() > column); + auto &source = chunk.data[column]; + return FlatVector::IsNull(source, index); +} + +static void CopyCell(const DataChunk &chunk, idx_t column, idx_t index, Vector &target, idx_t target_offset) { + D_ASSERT(chunk.ColumnCount() > column); + auto &source = chunk.data[column]; + VectorOperations::Copy(source, target, index + 1, index, target_offset); +} + +//===--------------------------------------------------------------------===// +// WindowInputColumn +//===--------------------------------------------------------------------===// +WindowInputColumn::WindowInputColumn(optional_ptr expr_p, ClientContext &context, idx_t count) + : expr(expr_p), scalar(expr ? expr->IsScalar() : true), count(count), wtarget(target) { + + if (expr) { + vector types; + types.emplace_back(expr->return_type); + wtarget.Initialize(Allocator::Get(context), types, count); + ptype = expr->return_type.InternalType(); + } +} + +void WindowInputColumn::Copy(DataChunk &input_chunk, idx_t input_idx) { + if (expr && (!input_idx || !scalar)) { + wtarget.Copy(input_chunk, input_idx); + } +} + +//===--------------------------------------------------------------------===// +// WindowColumnIterator +//===--------------------------------------------------------------------===// +template +struct WindowColumnIterator { + using iterator = WindowColumnIterator; + using iterator_category = std::random_access_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using reference = T; + using pointer = idx_t; + + explicit WindowColumnIterator(const WindowInputColumn &coll_p, pointer pos_p = 0) : coll(&coll_p), pos(pos_p) { + } + + // Forward iterator + inline reference operator*() const { + return coll->GetCell(pos); + } + inline explicit operator pointer() const { + return pos; + } + + inline iterator &operator++() { + ++pos; + return *this; + } + inline iterator operator++(int) { + auto result = *this; + ++(*this); + return result; + } + + // Bidirectional iterator + inline iterator &operator--() { + --pos; + return *this; + } + inline iterator operator--(int) { + auto result = *this; + --(*this); + return result; + } + + // Random Access + inline iterator &operator+=(difference_type n) { + pos += UnsafeNumericCast(n); + return *this; + } + inline iterator &operator-=(difference_type n) { + pos -= UnsafeNumericCast(n); + return *this; + } + + inline reference operator[](difference_type m) const { + return coll->GetCell(pos + m); + } + + friend inline iterator &operator+(const iterator &a, difference_type n) { + return iterator(a.coll, a.pos + n); + } + + friend inline iterator operator-(const iterator &a, difference_type n) { + return iterator(a.coll, a.pos - n); + } + + friend inline iterator operator+(difference_type n, const iterator &a) { + return a + n; + } + friend inline difference_type operator-(const iterator &a, const iterator &b) { + return difference_type(a.pos - b.pos); + } + + friend inline bool operator==(const iterator &a, const iterator &b) { + return a.pos == b.pos; + } + friend inline bool operator!=(const iterator &a, const iterator &b) { + return a.pos != b.pos; + } + friend inline bool operator<(const iterator &a, const iterator &b) { + return a.pos < b.pos; + } + friend inline bool operator<=(const iterator &a, const iterator &b) { + return a.pos <= b.pos; + } + friend inline bool operator>(const iterator &a, const iterator &b) { + return a.pos > b.pos; + } + friend inline bool operator>=(const iterator &a, const iterator &b) { + return a.pos >= b.pos; + } + +private: + optional_ptr coll; + pointer pos; +}; + +template +struct OperationCompare : public std::function { + inline bool operator()(const T &lhs, const T &val) const { + return OP::template Operation(lhs, val); + } +}; + +template +static idx_t FindTypedRangeBound(const WindowInputColumn &over, const idx_t order_begin, const idx_t order_end, + const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, + const FrameBounds &prev) { + D_ASSERT(!boundary.CellIsNull(chunk_idx)); + const auto val = boundary.GetCell(chunk_idx); + + OperationCompare comp; + + // Check that the value we are searching for is in range. + if (range == WindowBoundary::EXPR_PRECEDING_RANGE) { + // Preceding but value past the current value + const auto cur_val = over.GetCell(order_end - 1); + if (comp(cur_val, val)) { + throw OutOfRangeException("Invalid RANGE PRECEDING value"); + } + } else { + // Following but value before the current value + D_ASSERT(range == WindowBoundary::EXPR_FOLLOWING_RANGE); + const auto cur_val = over.GetCell(order_begin); + if (comp(val, cur_val)) { + throw OutOfRangeException("Invalid RANGE FOLLOWING value"); + } + } + + // Try to reuse the previous bounds to restrict the search. + // This is only valid if the previous bounds were non-empty + // Only inject the comparisons if the previous bounds are a strict subset. + WindowColumnIterator begin(over, order_begin); + WindowColumnIterator end(over, order_end); + if (prev.start < prev.end) { + if (order_begin < prev.start && prev.start < order_end) { + const auto first = over.GetCell(prev.start); + if (!comp(val, first)) { + // prev.first <= val, so we can start further forward + begin += UnsafeNumericCast(prev.start - order_begin); + } + } + if (order_begin < prev.end && prev.end < order_end) { + const auto second = over.GetCell(prev.end - 1); + if (!comp(second, val)) { + // val <= prev.second, so we can end further back + // (prev.second is the largest peer) + end -= UnsafeNumericCast(order_end - prev.end - 1); + } + } + } + + if (FROM) { + return idx_t(std::lower_bound(begin, end, val, comp)); + } else { + return idx_t(std::upper_bound(begin, end, val, comp)); + } +} + +template +static idx_t FindRangeBound(const WindowInputColumn &over, const idx_t order_begin, const idx_t order_end, + const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, + const FrameBounds &prev) { + D_ASSERT(boundary.chunk.ColumnCount() == 1); + D_ASSERT(boundary.chunk.data[0].GetType().InternalType() == over.ptype); + + switch (over.ptype) { + case PhysicalType::INT8: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::INT16: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::INT32: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::INT64: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::UINT8: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::UINT16: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::UINT32: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::UINT64: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::INT128: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::UINT128: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, + prev); + case PhysicalType::FLOAT: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::DOUBLE: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case PhysicalType::INTERVAL: + return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, + prev); + default: + throw InternalException("Unsupported column type for RANGE"); + } +} + +template +static idx_t FindOrderedRangeBound(const WindowInputColumn &over, const OrderType range_sense, const idx_t order_begin, + const idx_t order_end, const WindowBoundary range, WindowInputExpression &boundary, + const idx_t chunk_idx, const FrameBounds &prev) { + switch (range_sense) { + case OrderType::ASCENDING: + return FindRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + case OrderType::DESCENDING: + return FindRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); + default: + throw InternalException("Unsupported ORDER BY sense for RANGE"); + } +} + +struct WindowBoundariesState { + static inline bool IsScalar(const unique_ptr &expr) { + return !expr || expr->IsScalar(); + } + + static inline bool BoundaryNeedsPeer(const WindowBoundary &boundary) { + switch (boundary) { + case WindowBoundary::CURRENT_ROW_RANGE: + case WindowBoundary::EXPR_PRECEDING_RANGE: + case WindowBoundary::EXPR_FOLLOWING_RANGE: + return true; + default: + return false; + } + } + + static inline bool ExpressionNeedsPeer(const ExpressionType &type) { + switch (type) { + case ExpressionType::WINDOW_RANK: + case ExpressionType::WINDOW_RANK_DENSE: + case ExpressionType::WINDOW_PERCENT_RANK: + case ExpressionType::WINDOW_CUME_DIST: + return true; + default: + return false; + } + } + + WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size); + + void Update(const idx_t row_idx, const WindowInputColumn &range_collection, const idx_t chunk_idx, + WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, + const ValidityMask &partition_mask, const ValidityMask &order_mask); + + void Bounds(DataChunk &bounds, idx_t row_idx, const WindowInputColumn &range, const idx_t count, + WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, + const ValidityMask &partition_mask, const ValidityMask &order_mask); + + // Cached lookups + const ExpressionType type; + const idx_t input_size; + const WindowBoundary start_boundary; + const WindowBoundary end_boundary; + const size_t partition_count; + const size_t order_count; + const OrderType range_sense; + const bool has_preceding_range; + const bool has_following_range; + const bool needs_peer; + + idx_t next_pos = 0; + idx_t partition_start = 0; + idx_t partition_end = 0; + idx_t peer_start = 0; + idx_t peer_end = 0; + idx_t valid_start = 0; + idx_t valid_end = 0; + idx_t window_start = NumericLimits::Maximum(); + idx_t window_end = NumericLimits::Maximum(); + FrameBounds prev; +}; + +//===--------------------------------------------------------------------===// +// WindowBoundariesState +//===--------------------------------------------------------------------===// +void WindowBoundariesState::Update(const idx_t row_idx, const WindowInputColumn &range_collection, + const idx_t chunk_idx, WindowInputExpression &boundary_start, + WindowInputExpression &boundary_end, const ValidityMask &partition_mask, + const ValidityMask &order_mask) { + + if (partition_count + order_count > 0) { + + // determine partition and peer group boundaries to ultimately figure out window size + const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); + const auto is_peer = !order_mask.RowIsValidUnsafe(row_idx); + const auto is_jump = (next_pos != row_idx); + + // when the partition changes, recompute the boundaries + if (!is_same_partition || is_jump) { + if (is_jump) { + idx_t n = 1; + partition_start = FindPrevStart(partition_mask, 0, row_idx + 1, n); + n = 1; + peer_start = FindPrevStart(order_mask, 0, row_idx + 1, n); + } else { + partition_start = row_idx; + peer_start = row_idx; + } + + // find end of partition + partition_end = input_size; + if (partition_count) { + idx_t n = 1; + partition_end = FindNextStart(partition_mask, partition_start + 1, input_size, n); + } + + // Find valid ordering values for the new partition + // so we can exclude NULLs from RANGE expression computations + valid_start = partition_start; + valid_end = partition_end; + + if ((valid_start < valid_end) && has_preceding_range) { + // Exclude any leading NULLs + if (range_collection.CellIsNull(valid_start)) { + idx_t n = 1; + valid_start = FindNextStart(order_mask, valid_start + 1, valid_end, n); + } + } + + if ((valid_start < valid_end) && has_following_range) { + // Exclude any trailing NULLs + if (range_collection.CellIsNull(valid_end - 1)) { + idx_t n = 1; + valid_end = FindPrevStart(order_mask, valid_start, valid_end, n); + } + + // Reset range hints + prev.start = valid_start; + prev.end = valid_end; + } + } else if (!is_peer) { + peer_start = row_idx; + } + + if (needs_peer) { + peer_end = partition_end; + if (order_count) { + idx_t n = 1; + peer_end = FindNextStart(order_mask, peer_start + 1, partition_end, n); + } + } + + } else { + // OVER() + partition_end = input_size; + peer_end = partition_end; + } + next_pos = row_idx + 1; + + // determine window boundaries depending on the type of expression + switch (start_boundary) { + case WindowBoundary::UNBOUNDED_PRECEDING: + window_start = partition_start; + break; + case WindowBoundary::CURRENT_ROW_ROWS: + window_start = row_idx; + break; + case WindowBoundary::CURRENT_ROW_RANGE: + window_start = peer_start; + break; + case WindowBoundary::EXPR_PRECEDING_ROWS: { + int64_t computed_start; + if (!TrySubtractOperator::Operation(static_cast(row_idx), boundary_start.GetCell(chunk_idx), + computed_start)) { + window_start = partition_start; + } else { + window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + break; + } + case WindowBoundary::EXPR_FOLLOWING_ROWS: { + int64_t computed_start; + if (!TryAddOperator::Operation(static_cast(row_idx), boundary_start.GetCell(chunk_idx), + computed_start)) { + window_start = partition_start; + } else { + window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + break; + } + case WindowBoundary::EXPR_PRECEDING_RANGE: { + if (boundary_start.CellIsNull(chunk_idx)) { + window_start = peer_start; + } else { + prev.start = FindOrderedRangeBound(range_collection, range_sense, valid_start, row_idx + 1, + start_boundary, boundary_start, chunk_idx, prev); + window_start = prev.start; + } + break; + } + case WindowBoundary::EXPR_FOLLOWING_RANGE: { + if (boundary_start.CellIsNull(chunk_idx)) { + window_start = peer_start; + } else { + prev.start = FindOrderedRangeBound(range_collection, range_sense, row_idx, valid_end, start_boundary, + boundary_start, chunk_idx, prev); + window_start = prev.start; + } + break; + } + default: + throw InternalException("Unsupported window start boundary"); + } + + switch (end_boundary) { + case WindowBoundary::CURRENT_ROW_ROWS: + window_end = row_idx + 1; + break; + case WindowBoundary::CURRENT_ROW_RANGE: + window_end = peer_end; + break; + case WindowBoundary::UNBOUNDED_FOLLOWING: + window_end = partition_end; + break; + case WindowBoundary::EXPR_PRECEDING_ROWS: { + int64_t computed_start; + if (!TrySubtractOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), + computed_start)) { + window_end = partition_end; + } else { + window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + break; + } + case WindowBoundary::EXPR_FOLLOWING_ROWS: { + int64_t computed_start; + if (!TryAddOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), + computed_start)) { + window_end = partition_end; + } else { + window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); + } + break; + } + case WindowBoundary::EXPR_PRECEDING_RANGE: { + if (boundary_end.CellIsNull(chunk_idx)) { + window_end = peer_end; + } else { + prev.end = FindOrderedRangeBound(range_collection, range_sense, valid_start, row_idx + 1, + end_boundary, boundary_end, chunk_idx, prev); + window_end = prev.end; + } + break; + } + case WindowBoundary::EXPR_FOLLOWING_RANGE: { + if (boundary_end.CellIsNull(chunk_idx)) { + window_end = peer_end; + } else { + prev.end = FindOrderedRangeBound(range_collection, range_sense, row_idx, valid_end, end_boundary, + boundary_end, chunk_idx, prev); + window_end = prev.end; + } + break; + } + default: + throw InternalException("Unsupported window end boundary"); + } + + // clamp windows to partitions if they should exceed + if (window_start < partition_start) { + window_start = partition_start; + } + if (window_start > partition_end) { + window_start = partition_end; + } + if (window_end < partition_start) { + window_end = partition_start; + } + if (window_end > partition_end) { + window_end = partition_end; + } +} + +static bool HasPrecedingRange(const BoundWindowExpression &wexpr) { + return (wexpr.start == WindowBoundary::EXPR_PRECEDING_RANGE || wexpr.end == WindowBoundary::EXPR_PRECEDING_RANGE); +} + +static bool HasFollowingRange(const BoundWindowExpression &wexpr) { + return (wexpr.start == WindowBoundary::EXPR_FOLLOWING_RANGE || wexpr.end == WindowBoundary::EXPR_FOLLOWING_RANGE); +} + +WindowBoundariesState::WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size) + : type(wexpr.type), input_size(input_size), start_boundary(wexpr.start), end_boundary(wexpr.end), + partition_count(wexpr.partitions.size()), order_count(wexpr.orders.size()), + range_sense(wexpr.orders.empty() ? OrderType::INVALID : wexpr.orders[0].type), + has_preceding_range(HasPrecedingRange(wexpr)), has_following_range(HasFollowingRange(wexpr)), + // if we have EXCLUDE GROUP / TIES, we also need peer boundaries + needs_peer(BoundaryNeedsPeer(wexpr.end) || ExpressionNeedsPeer(wexpr.type) || + wexpr.exclude_clause >= WindowExcludeMode::GROUP) { +} + +void WindowBoundariesState::Bounds(DataChunk &bounds, idx_t row_idx, const WindowInputColumn &range, const idx_t count, + WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, + const ValidityMask &partition_mask, const ValidityMask &order_mask) { + bounds.Reset(); + D_ASSERT(bounds.ColumnCount() == 6); + auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); + auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); + auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); + auto window_begin_data = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); + auto window_end_data = FlatVector::GetData(bounds.data[WINDOW_END]); + for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { + Update(row_idx, range, chunk_idx, boundary_start, boundary_end, partition_mask, order_mask); + *partition_begin_data++ = partition_start; + *partition_end_data++ = partition_end; + if (needs_peer) { + *peer_begin_data++ = peer_start; + *peer_end_data++ = peer_end; + } + *window_begin_data++ = UnsafeNumericCast(window_start); + *window_end_data++ = UnsafeNumericCast(window_end); + } + bounds.SetCardinality(count); +} + +//===--------------------------------------------------------------------===// +// WindowExecutorBoundsState +//===--------------------------------------------------------------------===// +class WindowExecutorBoundsState : public WindowExecutorLocalState { +public: + explicit WindowExecutorBoundsState(const WindowExecutorGlobalState &gstate); + ~WindowExecutorBoundsState() override { + } + + virtual void UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range); + + // Frame management + const ValidityMask &partition_mask; + const ValidityMask &order_mask; + DataChunk bounds; + WindowBoundariesState state; + + // evaluate boundaries if present. Parser has checked boundary types. + WindowInputExpression boundary_start; + WindowInputExpression boundary_end; +}; + +WindowExecutorBoundsState::WindowExecutorBoundsState(const WindowExecutorGlobalState &gstate) + : WindowExecutorLocalState(gstate), partition_mask(gstate.partition_mask), order_mask(gstate.order_mask), + state(gstate.executor.wexpr, gstate.payload_count), + boundary_start(gstate.executor.wexpr.start_expr.get(), gstate.executor.context), + boundary_end(gstate.executor.wexpr.end_expr.get(), gstate.executor.context) { + vector bounds_types(6, LogicalType(LogicalTypeId::UBIGINT)); + bounds.Initialize(Allocator::Get(gstate.executor.context), bounds_types); +} + +void WindowExecutorBoundsState::UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) { + // Evaluate the row-level arguments + boundary_start.Execute(input_chunk); + boundary_end.Execute(input_chunk); + + const auto count = input_chunk.size(); + bounds.Reset(); + state.Bounds(bounds, row_idx, range, count, boundary_start, boundary_end, partition_mask, order_mask); +} + +//===--------------------------------------------------------------------===// +// ExclusionFilter +//===--------------------------------------------------------------------===// + +//! Handles window exclusion by piggybacking on the filtering logic. +//! (needed for first_value, last_value, nth_value) +class ExclusionFilter { +public: + ExclusionFilter(const WindowExcludeMode exclude_mode_p, idx_t total_count, const ValidityMask &src) + : mode(exclude_mode_p), mask_src(src) { + mask.Initialize(total_count); + + // copy the data from mask_src + FetchFromSource(0, total_count); + } + + //! Copy the entries from mask_src to mask, in the index range [begin, end) + void FetchFromSource(idx_t begin, idx_t end); + //! Apply the current exclusion to the validity mask + //! (offset is the current row's index within the chunk) + void ApplyExclusion(DataChunk &bounds, idx_t row_idx, idx_t offset); + //! Reset the validity mask to match mask_src + //! (offset is the current row's index within the chunk) + void ResetMask(idx_t row_idx, idx_t offset); + + //! The current peer group's begin + idx_t curr_peer_begin; + //! The current peer group's end + idx_t curr_peer_end; + //! The window exclusion mode + WindowExcludeMode mode; + //! The validity mask representing the exclusion + ValidityMask mask; + //! The validity mask upon which mask is based + const ValidityMask &mask_src; + //! A validity mask consisting of only one entries (needed if no ignore_nulls mask is supplied) + ValidityMask all_ones_mask; +}; + +void ExclusionFilter::FetchFromSource(idx_t begin, idx_t end) { + idx_t begin_entry_idx; + idx_t end_entry_idx; + idx_t idx_in_entry; + mask.GetEntryIndex(begin, begin_entry_idx, idx_in_entry); + mask.GetEntryIndex(end - 1, end_entry_idx, idx_in_entry); + auto dst = mask.GetData() + begin_entry_idx; + for (idx_t entry_idx = begin_entry_idx; entry_idx <= end_entry_idx; ++entry_idx) { + *dst++ = mask_src.GetValidityEntry(entry_idx); + } +} + +void ExclusionFilter::ApplyExclusion(DataChunk &bounds, idx_t row_idx, idx_t offset) { + // flip the bits in mask according to the window exclusion mode + switch (mode) { + case WindowExcludeMode::CURRENT_ROW: + mask.SetInvalid(row_idx); + break; + case WindowExcludeMode::TIES: + case WindowExcludeMode::GROUP: { + if (curr_peer_end == row_idx || offset == 0) { + // new peer group or input chunk: set entire peer group to invalid + auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); + curr_peer_begin = peer_begin[offset]; + curr_peer_end = peer_end[offset]; + for (idx_t i = curr_peer_begin; i < curr_peer_end; i++) { + mask.SetInvalid(i); + } + } + if (mode == WindowExcludeMode::TIES) { + mask.Set(row_idx, mask_src.RowIsValid(row_idx)); + } + break; + } + default: + break; + } +} + +void ExclusionFilter::ResetMask(idx_t row_idx, idx_t offset) { + // flip the bits that were modified in ApplyExclusion back + switch (mode) { + case WindowExcludeMode::CURRENT_ROW: + mask.Set(row_idx, mask_src.RowIsValid(row_idx)); + break; + case WindowExcludeMode::TIES: + mask.SetInvalid(row_idx); + DUCKDB_EXPLICIT_FALLTHROUGH; + case WindowExcludeMode::GROUP: + if (curr_peer_end == row_idx + 1) { + // if we've reached the peer group's end, restore the entire peer group + FetchFromSource(curr_peer_begin, curr_peer_end); + } + break; + default: + break; + } +} + +//===--------------------------------------------------------------------===// +// WindowExecutor +//===--------------------------------------------------------------------===// +static void PrepareInputExpressions(const vector> &exprs, ExpressionExecutor &executor, + DataChunk &chunk) { + if (exprs.empty()) { + return; + } + + vector types; + for (idx_t expr_idx = 0; expr_idx < exprs.size(); ++expr_idx) { + types.push_back(exprs[expr_idx]->return_type); + executor.AddExpression(*exprs[expr_idx]); + } + + if (!types.empty()) { + auto &allocator = executor.GetAllocator(); + chunk.Initialize(allocator, types); + } +} + +WindowExecutor::WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context) : wexpr(wexpr), context(context) { +} + +WindowExecutorGlobalState::WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask) + : executor(executor), payload_count(payload_count), partition_mask(partition_mask), order_mask(order_mask), + range((HasPrecedingRange(executor.wexpr) || HasFollowingRange(executor.wexpr)) + ? executor.wexpr.orders[0].expression.get() + : nullptr, + executor.context, payload_count) { + for (const auto &child : executor.wexpr.children) { + arg_types.emplace_back(child->return_type); + } +} + +WindowExecutorLocalState::WindowExecutorLocalState(const WindowExecutorGlobalState &gstate) + : payload_executor(gstate.executor.context), range_executor(gstate.executor.context) { + // TODO: child may be a scalar, don't need to materialize the whole collection then + + // evaluate inner expressions of window functions, could be more complex + PrepareInputExpressions(gstate.executor.wexpr.children, payload_executor, payload_chunk); + + if (gstate.range.expr) { + vector types; + types.emplace_back(gstate.range.expr->return_type); + range_executor.AddExpression(*gstate.range.expr); + + auto &allocator = range_executor.GetAllocator(); + range_chunk.Initialize(allocator, types); + } +} + +void WindowExecutorLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &input_chunk, idx_t input_idx) { + if (gstate.range.expr && (!input_idx || !gstate.range.scalar)) { + range_executor.Execute(input_chunk, range_chunk); + gstate.range.Copy(range_chunk, input_idx); + } +} + +unique_ptr WindowExecutor::GetGlobalState(const idx_t payload_count, + const ValidityMask &partition_mask, + const ValidityMask &order_mask) const { + return make_uniq(*this, payload_count, partition_mask, order_mask); +} + +unique_ptr WindowExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + return make_uniq(gstate); +} + +void WindowExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, + WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { + lstate.Sink(gstate, input_chunk, input_idx); +} + +//===--------------------------------------------------------------------===// +// WindowAggregateExecutor +//===--------------------------------------------------------------------===// +class WindowAggregateExecutorGlobalState : public WindowExecutorGlobalState { +public: + bool IsConstantAggregate(); + bool IsCustomAggregate(); + bool IsDistinctAggregate(); + + WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask); + + // aggregate computation algorithm + unique_ptr aggregator; + // aggregate global state + unique_ptr gsink; +}; + +bool WindowAggregateExecutorGlobalState::IsConstantAggregate() { + const auto &wexpr = executor.wexpr; + + if (!wexpr.aggregate) { + return false; + } + // window exclusion cannot be handled by constant aggregates + if (wexpr.exclude_clause != WindowExcludeMode::NO_OTHER) { + return false; + } + + // COUNT(*) is already handled efficiently by segment trees. + if (wexpr.children.empty()) { + return false; + } + + /* + The default framing option is RANGE UNBOUNDED PRECEDING, which + is the same as RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT + ROW; it sets the frame to be all rows from the partition start + up through the current row's last peer (a row that the window's + ORDER BY clause considers equivalent to the current row; all + rows are peers if there is no ORDER BY). In general, UNBOUNDED + PRECEDING means that the frame starts with the first row of the + partition, and similarly UNBOUNDED FOLLOWING means that the + frame ends with the last row of the partition, regardless of + RANGE, ROWS or GROUPS mode. In ROWS mode, CURRENT ROW means that + the frame starts or ends with the current row; but in RANGE or + GROUPS mode it means that the frame starts or ends with the + current row's first or last peer in the ORDER BY ordering. The + offset PRECEDING and offset FOLLOWING options vary in meaning + depending on the frame mode. + */ + switch (wexpr.start) { + case WindowBoundary::UNBOUNDED_PRECEDING: + break; + case WindowBoundary::CURRENT_ROW_RANGE: + if (!wexpr.orders.empty()) { + return false; + } + break; + default: + return false; + } + + switch (wexpr.end) { + case WindowBoundary::UNBOUNDED_FOLLOWING: + break; + case WindowBoundary::CURRENT_ROW_RANGE: + if (!wexpr.orders.empty()) { + return false; + } + break; + default: + return false; + } + + return true; +} + +bool WindowAggregateExecutorGlobalState::IsDistinctAggregate() { + const auto &wexpr = executor.wexpr; + + if (!wexpr.aggregate) { + return false; + } + + return wexpr.distinct; +} + +bool WindowAggregateExecutorGlobalState::IsCustomAggregate() { + const auto &wexpr = executor.wexpr; + const auto &mode = reinterpret_cast(executor).mode; + + if (!wexpr.aggregate) { + return false; + } + + if (!AggregateObject(wexpr).function.window) { + return false; + } + + return (mode < WindowAggregationMode::COMBINE); +} + +void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &result, WindowExecutorLocalState &lstate, + WindowExecutorGlobalState &gstate) const { + auto &lbstate = lstate.Cast(); + lbstate.UpdateBounds(row_idx, input_chunk, gstate.range); + + const auto count = input_chunk.size(); + EvaluateInternal(gstate, lstate, result, count, row_idx); + + result.Verify(count); +} + +WindowAggregateExecutor::WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, + WindowAggregationMode mode) + : WindowExecutor(wexpr, context), mode(mode) { +} + +WindowAggregateExecutorGlobalState::WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, + const idx_t group_count, + const ValidityMask &partition_mask, + const ValidityMask &order_mask) + : WindowExecutorGlobalState(executor, group_count, partition_mask, order_mask) { + auto &wexpr = executor.wexpr; + auto &context = executor.context; + auto return_type = wexpr.return_type; + const auto &mode = reinterpret_cast(executor).mode; + + // Force naive for SEPARATE mode or for (currently!) unsupported functionality + const auto force_naive = + !ClientConfig::GetConfig(context).enable_optimizer || mode == WindowAggregationMode::SEPARATE; + AggregateObject aggr(wexpr); + if (force_naive || (wexpr.distinct && wexpr.exclude_clause != WindowExcludeMode::NO_OTHER)) { + aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + } else if (IsDistinctAggregate()) { + // build a merge sort tree + // see https://dl.acm.org/doi/pdf/10.1145/3514221.3526184 + aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause, context); + } else if (IsConstantAggregate()) { + aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + } else if (IsCustomAggregate()) { + aggregator = make_uniq(aggr, arg_types, return_type, wexpr.exclude_clause); + } else { + // build a segment tree for frame-adhering aggregates + // see http://www.vldb.org/pvldb/vol8/p1058-leis.pdf + aggregator = make_uniq(aggr, arg_types, return_type, mode, wexpr.exclude_clause); + } + + gsink = aggregator->GetGlobalState(group_count, partition_mask); +} + +unique_ptr WindowAggregateExecutor::GetGlobalState(const idx_t payload_count, + const ValidityMask &partition_mask, + const ValidityMask &order_mask) const { + return make_uniq(*this, payload_count, partition_mask, order_mask); +} + +class WindowAggregateExecutorLocalState : public WindowExecutorBoundsState { +public: + WindowAggregateExecutorLocalState(const WindowExecutorGlobalState &gstate, const WindowAggregator &aggregator) + : WindowExecutorBoundsState(gstate), filter_executor(gstate.executor.context) { + + auto &gastate = gstate.Cast(); + aggregator_state = aggregator.GetLocalState(*gastate.gsink); + + // evaluate the FILTER clause and stuff it into a large mask for compactness and reuse + auto &wexpr = gstate.executor.wexpr; + if (wexpr.filter_expr) { + filter_executor.AddExpression(*wexpr.filter_expr); + filter_sel.Initialize(STANDARD_VECTOR_SIZE); + } + } + +public: + // state of aggregator + unique_ptr aggregator_state; + //! Executor for any filter clause + ExpressionExecutor filter_executor; + //! Result of filtering + SelectionVector filter_sel; +}; + +unique_ptr +WindowAggregateExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + auto &gastate = gstate.Cast(); + auto res = make_uniq(gstate, *gastate.aggregator); + return std::move(res); +} + +void WindowAggregateExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, + WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { + auto &gastate = gstate.Cast(); + auto &lastate = lstate.Cast(); + auto &filter_sel = lastate.filter_sel; + auto &filter_executor = lastate.filter_executor; + auto &payload_executor = lastate.payload_executor; + auto &payload_chunk = lastate.payload_chunk; + auto &aggregator = gastate.aggregator; + + idx_t filtered = 0; + SelectionVector *filtering = nullptr; + if (wexpr.filter_expr) { + filtering = &filter_sel; + filtered = filter_executor.SelectExpression(input_chunk, filter_sel); + } + + if (!wexpr.children.empty()) { + payload_chunk.Reset(); + payload_executor.Execute(input_chunk, payload_chunk); + payload_chunk.Verify(); + } else if (aggregator) { + // Zero-argument aggregate (e.g., COUNT(*) + payload_chunk.SetCardinality(input_chunk); + } + + D_ASSERT(aggregator); + auto &gestate = *gastate.gsink; + auto &lestate = *lastate.aggregator_state; + aggregator->Sink(gestate, lestate, payload_chunk, input_idx, filtering, filtered); + + WindowExecutor::Sink(input_chunk, input_idx, total_count, gstate, lstate); +} + +static void ApplyWindowStats(const WindowBoundary &boundary, FrameDelta &delta, BaseStatistics *base, bool is_start) { + // Avoid overflow by clamping to the frame bounds + auto base_stats = delta; + + switch (boundary) { + case WindowBoundary::UNBOUNDED_PRECEDING: + if (is_start) { + delta.end = 0; + return; + } + break; + case WindowBoundary::UNBOUNDED_FOLLOWING: + if (!is_start) { + delta.begin = 0; + return; + } + break; + case WindowBoundary::CURRENT_ROW_ROWS: + delta.begin = delta.end = 0; + return; + case WindowBoundary::EXPR_PRECEDING_ROWS: + if (base && base->GetStatsType() == StatisticsType::NUMERIC_STATS && NumericStats::HasMinMax(*base)) { + // Preceding so negative offset from current row + base_stats.begin = NumericStats::GetMin(*base); + base_stats.end = NumericStats::GetMax(*base); + if (delta.begin < base_stats.end && base_stats.end < delta.end) { + delta.begin = -base_stats.end; + } + if (delta.begin < base_stats.begin && base_stats.begin < delta.end) { + delta.end = -base_stats.begin + 1; + } + } + return; + case WindowBoundary::EXPR_FOLLOWING_ROWS: + if (base && base->GetStatsType() == StatisticsType::NUMERIC_STATS && NumericStats::HasMinMax(*base)) { + base_stats.begin = NumericStats::GetMin(*base); + base_stats.end = NumericStats::GetMax(*base); + if (base_stats.end < delta.end) { + delta.end = base_stats.end + 1; + } + } + return; + + case WindowBoundary::CURRENT_ROW_RANGE: + case WindowBoundary::EXPR_PRECEDING_RANGE: + case WindowBoundary::EXPR_FOLLOWING_RANGE: + return; + default: + break; + } + + if (is_start) { + throw InternalException("Unsupported window start boundary"); + } else { + throw InternalException("Unsupported window end boundary"); + } +} + +void WindowAggregateExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { + auto &gastate = gstate.Cast(); + auto &aggregator = gastate.aggregator; + auto &gsink = gastate.gsink; + D_ASSERT(aggregator); + + // Estimate the frame statistics + // Default to the entire partition if we don't know anything + FrameStats stats; + const auto count = NumericCast(gastate.payload_count); + + // First entry is the frame start + stats[0] = FrameDelta(-count, count); + auto base = wexpr.expr_stats.empty() ? nullptr : wexpr.expr_stats[0].get(); + ApplyWindowStats(wexpr.start, stats[0], base, true); + + // Second entry is the frame end + stats[1] = FrameDelta(-count, count); + base = wexpr.expr_stats.empty() ? nullptr : wexpr.expr_stats[1].get(); + ApplyWindowStats(wexpr.end, stats[1], base, false); + + auto &lastate = lstate.Cast(); + aggregator->Finalize(*gsink, *lastate.aggregator_state, stats); +} + +void WindowAggregateExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gastate = gstate.Cast(); + auto &lastate = lstate.Cast(); + auto &aggregator = gastate.aggregator; + auto &gsink = gastate.gsink; + D_ASSERT(aggregator); + + auto &agg_state = *lastate.aggregator_state; + + aggregator->Evaluate(*gsink, agg_state, lastate.bounds, result, count, row_idx); +} + +//===--------------------------------------------------------------------===// +// WindowRowNumberExecutor +//===--------------------------------------------------------------------===// +WindowRowNumberExecutor::WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +void WindowRowNumberExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &lbstate = lstate.Cast(); + auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); + auto rdata = FlatVector::GetData(result); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + rdata[i] = NumericCast(row_idx - partition_begin[i] + 1); + } +} + +//===--------------------------------------------------------------------===// +// WindowPeerState +//===--------------------------------------------------------------------===// +class WindowPeerState : public WindowExecutorBoundsState { +public: + explicit WindowPeerState(const WindowExecutorGlobalState &gstate) : WindowExecutorBoundsState(gstate) { + } + +public: + uint64_t dense_rank = 1; + uint64_t rank_equal = 0; + uint64_t rank = 1; + + void NextRank(idx_t partition_begin, idx_t peer_begin, idx_t row_idx); +}; + +void WindowPeerState::NextRank(idx_t partition_begin, idx_t peer_begin, idx_t row_idx) { + if (partition_begin == row_idx) { + dense_rank = 1; + rank = 1; + rank_equal = 0; + } else if (peer_begin == row_idx) { + dense_rank++; + rank += rank_equal; + rank_equal = 0; + } + rank_equal++; +} + +WindowRankExecutor::WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +unique_ptr WindowRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + return make_uniq(gstate); +} + +void WindowRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &lpeer = lstate.Cast(); + auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); + auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); + auto rdata = FlatVector::GetData(result); + + // Reset to "previous" row + lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; + lpeer.rank_equal = (row_idx - peer_begin[0]); + + for (idx_t i = 0; i < count; ++i, ++row_idx) { + lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); + rdata[i] = NumericCast(lpeer.rank); + } +} + +WindowDenseRankExecutor::WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +unique_ptr +WindowDenseRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + return make_uniq(gstate); +} + +void WindowDenseRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &lpeer = lstate.Cast(); + + auto &order_mask = gstate.order_mask; + auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); + auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); + auto rdata = FlatVector::GetData(result); + + // Reset to "previous" row + lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; + lpeer.rank_equal = (row_idx - peer_begin[0]); + + // The previous dense rank is the number of order mask bits in [partition_begin, row_idx) + lpeer.dense_rank = 0; + + auto order_begin = partition_begin[0]; + idx_t begin_idx; + idx_t begin_offset; + order_mask.GetEntryIndex(order_begin, begin_idx, begin_offset); + + auto order_end = row_idx; + idx_t end_idx; + idx_t end_offset; + order_mask.GetEntryIndex(order_end, end_idx, end_offset); + + // If they are in the same entry, just loop + if (begin_idx == end_idx) { + const auto entry = order_mask.GetValidityEntry(begin_idx); + for (; begin_offset < end_offset; ++begin_offset) { + lpeer.dense_rank += order_mask.RowIsValid(entry, begin_offset); + } + } else { + // Count the ragged bits at the start of the partition + if (begin_offset) { + const auto entry = order_mask.GetValidityEntry(begin_idx); + for (; begin_offset < order_mask.BITS_PER_VALUE; ++begin_offset) { + lpeer.dense_rank += order_mask.RowIsValid(entry, begin_offset); + ++order_begin; + } + ++begin_idx; + } + + // Count the the aligned bits. + ValidityMask tail_mask(order_mask.GetData() + begin_idx); + lpeer.dense_rank += tail_mask.CountValid(order_end - order_begin); + } + + for (idx_t i = 0; i < count; ++i, ++row_idx) { + lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); + rdata[i] = NumericCast(lpeer.dense_rank); + } +} + +WindowPercentRankExecutor::WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +unique_ptr +WindowPercentRankExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + return make_uniq(gstate); +} + +void WindowPercentRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &lpeer = lstate.Cast(); + auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); + auto partition_end = FlatVector::GetData(lpeer.bounds.data[PARTITION_END]); + auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); + auto rdata = FlatVector::GetData(result); + + // Reset to "previous" row + lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; + lpeer.rank_equal = (row_idx - peer_begin[0]); + + for (idx_t i = 0; i < count; ++i, ++row_idx) { + lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); + auto denom = static_cast(NumericCast(partition_end[i] - partition_begin[i] - 1)); + double percent_rank = denom > 0 ? ((double)lpeer.rank - 1) / denom : 0; + rdata[i] = percent_rank; + } +} + +//===--------------------------------------------------------------------===// +// WindowCumeDistExecutor +//===--------------------------------------------------------------------===// +WindowCumeDistExecutor::WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +void WindowCumeDistExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &lbstate = lstate.Cast(); + auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); + auto partition_end = FlatVector::GetData(lbstate.bounds.data[PARTITION_END]); + auto peer_end = FlatVector::GetData(lbstate.bounds.data[PEER_END]); + auto rdata = FlatVector::GetData(result); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + auto denom = static_cast(NumericCast(partition_end[i] - partition_begin[i])); + double cume_dist = denom > 0 ? ((double)(peer_end[i] - partition_begin[i])) / denom : 0; + rdata[i] = cume_dist; + } +} + +//===--------------------------------------------------------------------===// +// WindowValueGlobalState +//===--------------------------------------------------------------------===// + +class WindowValueGlobalState : public WindowExecutorGlobalState { +public: + WindowValueGlobalState(const WindowExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask) + : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask), + payload_collection(payload_data), ignore_nulls(&no_nulls) + + { + if (!arg_types.empty()) { + payload_collection.Initialize(Allocator::Get(executor.context), arg_types, payload_count); + } + + auto &wexpr = executor.wexpr; + if (wexpr.ignore_nulls) { + switch (wexpr.type) { + case ExpressionType::WINDOW_LEAD: + case ExpressionType::WINDOW_LAG: + case ExpressionType::WINDOW_FIRST_VALUE: + case ExpressionType::WINDOW_LAST_VALUE: + case ExpressionType::WINDOW_NTH_VALUE: + ignore_nulls = &FlatVector::Validity(payload_collection.chunk.data[0]); + break; + default: + break; + } + } + } + + // The partition values + DataChunk payload_data; + // The partition values + WindowDataChunk payload_collection; + // Mask to use for exclusion if we are not ignoring NULLs + ValidityMask no_nulls; + // IGNORE NULLS + optional_ptr ignore_nulls; +}; + +//===--------------------------------------------------------------------===// +// WindowValueLocalState +//===--------------------------------------------------------------------===// + +//! A class representing the state of the first_value, last_value and nth_value functions +class WindowValueLocalState : public WindowExecutorBoundsState { +public: + explicit WindowValueLocalState(const WindowValueGlobalState &gvstate) + : WindowExecutorBoundsState(gvstate), gvstate(gvstate) { + } + + //! Lazily initialize for value Execute + void Initialize(); + + //! The corresponding global value state + const WindowValueGlobalState &gvstate; + //! Lazy initialization flag + bool initialized = false; + //! The exclusion filter handler + unique_ptr exclusion_filter; + //! The validity mask that combines both the NULLs and exclusion information + optional_ptr ignore_nulls_exclude; +}; + +void WindowValueLocalState::Initialize() { + if (initialized) { + return; + } + auto ignore_nulls = gvstate.ignore_nulls; + if (gvstate.executor.wexpr.exclude_clause == WindowExcludeMode::NO_OTHER) { + exclusion_filter = nullptr; + ignore_nulls_exclude = ignore_nulls; + } else { + // create the exclusion filter based on ignore_nulls + exclusion_filter = + make_uniq(gvstate.executor.wexpr.exclude_clause, gvstate.payload_count, *ignore_nulls); + ignore_nulls_exclude = &exclusion_filter->mask; + } + + initialized = true; +} + +//===--------------------------------------------------------------------===// +// WindowValueExecutor +//===--------------------------------------------------------------------===// +WindowValueExecutor::WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowExecutor(wexpr, context) { +} + +WindowNtileExecutor::WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowValueExecutor(wexpr, context) { +} + +unique_ptr WindowValueExecutor::GetGlobalState(const idx_t payload_count, + const ValidityMask &partition_mask, + const ValidityMask &order_mask) const { + return make_uniq(*this, payload_count, partition_mask, order_mask); +} + +void WindowValueExecutor::Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, + WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { + auto &gvstate = gstate.Cast(); + auto &lvstate = lstate.Cast(); + auto &payload_chunk = lvstate.payload_chunk; + auto &payload_executor = lvstate.payload_executor; + auto &payload_collection = gvstate.payload_collection; + + if (!wexpr.children.empty()) { + payload_chunk.Reset(); + payload_executor.Execute(input_chunk, payload_chunk); + payload_chunk.Verify(); + payload_collection.Copy(payload_chunk, input_idx); + } + + WindowExecutor::Sink(input_chunk, input_idx, total_count, gstate, lstate); +} + +unique_ptr WindowValueExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + const auto &gvstate = gstate.Cast(); + return make_uniq(gvstate); +} + +void WindowNtileExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gvstate = gstate.Cast(); + auto &payload_collection = gvstate.payload_collection.chunk; + D_ASSERT(payload_collection.ColumnCount() == 1); + auto &lbstate = lstate.Cast(); + auto partition_begin = FlatVector::GetData(lbstate.bounds.data[PARTITION_BEGIN]); + auto partition_end = FlatVector::GetData(lbstate.bounds.data[PARTITION_END]); + auto rdata = FlatVector::GetData(result); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + if (CellIsNull(payload_collection, 0, row_idx)) { + FlatVector::SetNull(result, i, true); + } else { + auto n_param = GetCell(payload_collection, 0, row_idx); + if (n_param < 1) { + throw InvalidInputException("Argument for ntile must be greater than zero"); + } + // With thanks from SQLite's ntileValueFunc() + auto n_total = NumericCast(partition_end[i] - partition_begin[i]); + if (n_param > n_total) { + // more groups allowed than we have values + // map every entry to a unique group + n_param = n_total; + } + int64_t n_size = (n_total / n_param); + // find the row idx within the group + D_ASSERT(row_idx >= partition_begin[i]); + auto adjusted_row_idx = NumericCast(row_idx - partition_begin[i]); + // now compute the ntile + int64_t n_large = n_total - n_param * n_size; + int64_t i_small = n_large * (n_size + 1); + int64_t result_ntile; + + D_ASSERT((n_large * (n_size + 1) + (n_param - n_large) * n_size) == n_total); + + if (adjusted_row_idx < i_small) { + result_ntile = 1 + adjusted_row_idx / (n_size + 1); + } else { + result_ntile = 1 + n_large + (adjusted_row_idx - i_small) / n_size; + } + // result has to be between [1, NTILE] + D_ASSERT(result_ntile >= 1 && result_ntile <= n_param); + rdata[i] = result_ntile; + } + } +} + +//===--------------------------------------------------------------------===// +// WindowLeadLagLocalState +//===--------------------------------------------------------------------===// +class WindowLeadLagLocalState : public WindowValueLocalState { +public: + explicit WindowLeadLagLocalState(const WindowValueGlobalState &gstate) + : WindowValueLocalState(gstate), + leadlag_offset(gstate.executor.wexpr.offset_expr.get(), gstate.executor.context), + leadlag_default(gstate.executor.wexpr.default_expr.get(), gstate.executor.context) { + } + + void UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) override; + +public: + // LEAD/LAG Evaluation + WindowInputExpression leadlag_offset; + WindowInputExpression leadlag_default; +}; + +void WindowLeadLagLocalState::UpdateBounds(idx_t row_idx, DataChunk &input_chunk, const WindowInputColumn &range) { + // Evaluate the row-level arguments + leadlag_offset.Execute(input_chunk); + leadlag_default.Execute(input_chunk); + + WindowExecutorBoundsState::UpdateBounds(row_idx, input_chunk, range); +} + +WindowLeadLagExecutor::WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowValueExecutor(wexpr, context) { +} + +unique_ptr +WindowLeadLagExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { + const auto &gvstate = gstate.Cast(); + return make_uniq(gvstate); +} + +void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gvstate = gstate.Cast(); + auto &payload_collection = gvstate.payload_collection.chunk; + auto &ignore_nulls = gvstate.ignore_nulls; + auto &llstate = lstate.Cast(); + + bool can_shift = ignore_nulls->AllValid(); + if (wexpr.offset_expr) { + can_shift = can_shift && wexpr.offset_expr->IsFoldable(); + } + if (wexpr.default_expr) { + can_shift = can_shift && wexpr.default_expr->IsFoldable(); + } + + auto partition_begin = FlatVector::GetData(llstate.bounds.data[PARTITION_BEGIN]); + auto partition_end = FlatVector::GetData(llstate.bounds.data[PARTITION_END]); + const auto row_end = row_idx + count; + for (idx_t i = 0; i < count;) { + int64_t offset = 1; + if (wexpr.offset_expr) { + offset = llstate.leadlag_offset.GetCell(i); + } + int64_t val_idx = (int64_t)row_idx; + if (wexpr.type == ExpressionType::WINDOW_LEAD) { + val_idx = AddOperatorOverflowCheck::Operation(val_idx, offset); + } else { + val_idx = SubtractOperatorOverflowCheck::Operation(val_idx, offset); + } + + idx_t delta = 0; + if (val_idx < (int64_t)row_idx) { + // Count backwards + delta = idx_t(row_idx - idx_t(val_idx)); + val_idx = int64_t(FindPrevStart(*ignore_nulls, partition_begin[i], row_idx, delta)); + } else if (val_idx > (int64_t)row_idx) { + delta = idx_t(idx_t(val_idx) - row_idx); + val_idx = int64_t(FindNextStart(*ignore_nulls, row_idx + 1, partition_end[i], delta)); + } + // else offset is zero, so don't move. + + if (can_shift) { + const auto target_limit = MinValue(partition_end[i], row_end) - row_idx; + if (!delta) { + // Copy source[index:index+width] => result[i:] + const auto index = NumericCast(val_idx); + const auto source_limit = partition_end[i] - index; + const auto width = MinValue(source_limit, target_limit); + auto &source = payload_collection.data[0]; + VectorOperations::Copy(source, result, index + width, index, i); + i += width; + row_idx += width; + } else if (wexpr.default_expr) { + const auto width = MinValue(delta, target_limit); + llstate.leadlag_default.CopyCell(result, i, width); + i += width; + row_idx += width; + } else { + for (idx_t nulls = MinValue(delta, target_limit); nulls--; ++i, ++row_idx) { + FlatVector::SetNull(result, i, true); + } + } + } else { + if (!delta) { + CopyCell(payload_collection, 0, NumericCast(val_idx), result, i); + } else if (wexpr.default_expr) { + llstate.leadlag_default.CopyCell(result, i); + } else { + FlatVector::SetNull(result, i, true); + } + ++i; + ++row_idx; + } + } +} + +WindowFirstValueExecutor::WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowValueExecutor(wexpr, context) { +} + +void WindowFirstValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gvstate = gstate.Cast(); + auto &payload_collection = gvstate.payload_collection.chunk; + auto &lvstate = lstate.Cast(); + lvstate.Initialize(); + auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ApplyExclusion(lvstate.bounds, row_idx, i); + } + + if (window_begin[i] >= window_end[i]) { + FlatVector::SetNull(result, i, true); + continue; + } + // Same as NTH_VALUE(..., 1) + idx_t n = 1; + const auto first_idx = FindNextStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); + if (!n) { + CopyCell(payload_collection, 0, first_idx, result, i); + } else { + FlatVector::SetNull(result, i, true); + } + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ResetMask(row_idx, i); + } + } +} + +WindowLastValueExecutor::WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowValueExecutor(wexpr, context) { +} + +void WindowLastValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gvstate = gstate.Cast(); + auto &payload_collection = gvstate.payload_collection.chunk; + auto &lvstate = lstate.Cast(); + lvstate.Initialize(); + auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ApplyExclusion(lvstate.bounds, row_idx, i); + } + + if (window_begin[i] >= window_end[i]) { + FlatVector::SetNull(result, i, true); + continue; + } + idx_t n = 1; + const auto last_idx = FindPrevStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); + if (!n) { + CopyCell(payload_collection, 0, last_idx, result, i); + } else { + FlatVector::SetNull(result, i, true); + } + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ResetMask(row_idx, i); + } + } +} + +WindowNthValueExecutor::WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context) + : WindowValueExecutor(wexpr, context) { +} + +void WindowNthValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, + Vector &result, idx_t count, idx_t row_idx) const { + auto &gvstate = gstate.Cast(); + auto &payload_collection = gvstate.payload_collection.chunk; + D_ASSERT(payload_collection.ColumnCount() == 2); + + auto &lvstate = lstate.Cast(); + lvstate.Initialize(); + auto window_begin = FlatVector::GetData(lvstate.bounds.data[WINDOW_BEGIN]); + auto window_end = FlatVector::GetData(lvstate.bounds.data[WINDOW_END]); + for (idx_t i = 0; i < count; ++i, ++row_idx) { + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ApplyExclusion(lvstate.bounds, row_idx, i); + } + + if (window_begin[i] >= window_end[i]) { + FlatVector::SetNull(result, i, true); + continue; + } + // Returns value evaluated at the row that is the n'th row of the window frame (counting from 1); + // returns NULL if there is no such row. + if (CellIsNull(payload_collection, 1, row_idx)) { + FlatVector::SetNull(result, i, true); + } else { + auto n_param = GetCell(payload_collection, 1, row_idx); + if (n_param < 1) { + FlatVector::SetNull(result, i, true); + } else { + auto n = idx_t(n_param); + const auto nth_index = FindNextStart(*lvstate.ignore_nulls_exclude, window_begin[i], window_end[i], n); + if (!n) { + CopyCell(payload_collection, 0, nth_index, result, i); + } else { + FlatVector::SetNull(result, i, true); + } + } + } + + if (lvstate.exclusion_filter) { + lvstate.exclusion_filter->ResetMask(row_idx, i); + } + } +} + +} // namespace duckdb diff --git a/src/duckdb/src/execution/window_segment_tree.cpp b/src/duckdb/src/execution/window_segment_tree.cpp new file mode 100644 index 000000000..be71e85c7 --- /dev/null +++ b/src/duckdb/src/execution/window_segment_tree.cpp @@ -0,0 +1,2073 @@ +#include "duckdb/execution/window_segment_tree.hpp" + +#include "duckdb/common/algorithm.hpp" +#include "duckdb/common/helper.hpp" +#include "duckdb/common/sort/partition_state.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/execution/merge_sort_tree.hpp" +#include "duckdb/planner/expression/bound_constant_expression.hpp" +#include "duckdb/execution/window_executor.hpp" + +#include +#include +#include + +namespace duckdb { + +//===--------------------------------------------------------------------===// +// WindowAggregator +//===--------------------------------------------------------------------===// +WindowAggregatorState::WindowAggregatorState() : allocator(Allocator::DefaultAllocator()) { +} + +class WindowAggregatorGlobalState : public WindowAggregatorState { +public: + WindowAggregatorGlobalState(const WindowAggregator &aggregator_p, idx_t group_count) + : aggregator(aggregator_p), winputs(inputs), locals(0), finalized(0) { + + if (!aggregator.arg_types.empty()) { + winputs.Initialize(Allocator::DefaultAllocator(), aggregator.arg_types, group_count); + } + if (aggregator.aggr.filter) { + // Start with all invalid and set the ones that pass + filter_mask.Initialize(group_count, false); + } + } + + //! The aggregator data + const WindowAggregator &aggregator; + + //! Partition data chunk + DataChunk inputs; + WindowDataChunk winputs; + + //! The filtered rows in inputs. + ValidityArray filter_mask; + + //! Lock for single threading + mutable mutex lock; + + //! Count of local tasks + mutable std::atomic locals; + + //! Number of finalised states + std::atomic finalized; +}; + +WindowAggregator::WindowAggregator(AggregateObject aggr_p, const vector &arg_types_p, + const LogicalType &result_type_p, const WindowExcludeMode exclude_mode_p) + : aggr(std::move(aggr_p)), arg_types(arg_types_p), result_type(result_type_p), + state_size(aggr.function.state_size(aggr.function)), exclude_mode(exclude_mode_p) { +} + +WindowAggregator::~WindowAggregator() { +} + +unique_ptr WindowAggregator::GetGlobalState(idx_t group_count, const ValidityMask &) const { + return make_uniq(*this, group_count); +} + +void WindowAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, + idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { + auto &gasink = gsink.Cast(); + auto &winputs = gasink.winputs; + auto &filter_mask = gasink.filter_mask; + if (winputs.chunk.ColumnCount()) { + winputs.Copy(arg_chunk, input_idx); + } + if (filter_sel) { + for (idx_t f = 0; f < filtered; ++f) { + filter_mask.SetValid(input_idx + filter_sel->get_index(f)); + } + } +} + +void WindowAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) { +} + +//===--------------------------------------------------------------------===// +// WindowConstantAggregator +//===--------------------------------------------------------------------===// +struct WindowAggregateStates { + explicit WindowAggregateStates(const AggregateObject &aggr); + ~WindowAggregateStates() { + Destroy(); + } + + //! The number of states + idx_t GetCount() const { + return states.size() / state_size; + } + data_ptr_t *GetData() { + return FlatVector::GetData(*statef); + } + data_ptr_t GetStatePtr(idx_t idx) { + return states.data() + idx * state_size; + } + const_data_ptr_t GetStatePtr(idx_t idx) const { + return states.data() + idx * state_size; + } + //! Initialise all the states + void Initialize(idx_t count); + //! Combine the states into the target + void Combine(WindowAggregateStates &target, + AggregateCombineType combine_type = AggregateCombineType::PRESERVE_INPUT); + //! Finalize the states into an output vector + void Finalize(Vector &result); + //! Destroy the states + void Destroy(); + + //! A description of the aggregator + const AggregateObject aggr; + //! The size of each state + const idx_t state_size; + //! The allocator to use + ArenaAllocator allocator; + //! Data pointer that contains the state data + vector states; + //! Reused result state container for the window functions + unique_ptr statef; +}; + +WindowAggregateStates::WindowAggregateStates(const AggregateObject &aggr) + : aggr(aggr), state_size(aggr.function.state_size(aggr.function)), allocator(Allocator::DefaultAllocator()) { +} + +void WindowAggregateStates::Initialize(idx_t count) { + states.resize(count * state_size); + auto state_ptr = states.data(); + + statef = make_uniq(LogicalType::POINTER, count); + auto state_f_data = FlatVector::GetData(*statef); + + for (idx_t i = 0; i < count; ++i, state_ptr += state_size) { + state_f_data[i] = state_ptr; + aggr.function.initialize(aggr.function, state_ptr); + } + + // Prevent conversion of results to constants + statef->SetVectorType(VectorType::FLAT_VECTOR); +} + +void WindowAggregateStates::Combine(WindowAggregateStates &target, AggregateCombineType combine_type) { + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator, AggregateCombineType::ALLOW_DESTRUCTIVE); + aggr.function.combine(*statef, *target.statef, aggr_input_data, GetCount()); +} + +void WindowAggregateStates::Finalize(Vector &result) { + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.finalize(*statef, aggr_input_data, result, GetCount(), 0); +} + +void WindowAggregateStates::Destroy() { + if (states.empty()) { + return; + } + + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + if (aggr.function.destructor) { + aggr.function.destructor(*statef, aggr_input_data, GetCount()); + } + + states.clear(); +} + +class WindowConstantAggregatorGlobalState : public WindowAggregatorGlobalState { +public: + WindowConstantAggregatorGlobalState(const WindowConstantAggregator &aggregator, idx_t count, + const ValidityMask &partition_mask); + + void Finalize(const FrameStats &stats); + + //! Partition starts + vector partition_offsets; + //! Reused result state container for the window functions + WindowAggregateStates statef; + //! Aggregate results + unique_ptr results; +}; + +class WindowConstantAggregatorLocalState : public WindowAggregatorState { +public: + explicit WindowConstantAggregatorLocalState(const WindowConstantAggregatorGlobalState &gstate); + ~WindowConstantAggregatorLocalState() override { + } + + void Sink(DataChunk &payload_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + void Combine(WindowConstantAggregatorGlobalState &gstate); + +public: + //! The global state we are sharing + const WindowConstantAggregatorGlobalState &gstate; + //! Reusable chunk for sinking + DataChunk inputs; + //! A vector of pointers to "state", used for intermediate window segment aggregation + Vector statep; + //! Reused result state container for the window functions + WindowAggregateStates statef; + //! The current result partition being read + idx_t partition; + //! Shared SV for evaluation + SelectionVector matches; +}; + +WindowConstantAggregatorGlobalState::WindowConstantAggregatorGlobalState(const WindowConstantAggregator &aggregator, + idx_t group_count, + const ValidityMask &partition_mask) + : WindowAggregatorGlobalState(aggregator, STANDARD_VECTOR_SIZE), statef(aggregator.aggr) { + + // Locate the partition boundaries + if (partition_mask.AllValid()) { + partition_offsets.emplace_back(0); + } else { + idx_t entry_idx; + idx_t shift; + for (idx_t start = 0; start < group_count;) { + partition_mask.GetEntryIndex(start, entry_idx, shift); + + // If start is aligned with the start of a block, + // and the block is blank, then skip forward one block. + const auto block = partition_mask.GetValidityEntry(entry_idx); + if (partition_mask.NoneValid(block) && !shift) { + start += ValidityMask::BITS_PER_VALUE; + continue; + } + + // Loop over the block + for (; shift < ValidityMask::BITS_PER_VALUE && start < group_count; ++shift, ++start) { + if (partition_mask.RowIsValid(block, shift)) { + partition_offsets.emplace_back(start); + } + } + } + } + + // Initialise the vector for caching the results + results = make_uniq(aggregator.result_type, partition_offsets.size()); + + // Initialise the final states + statef.Initialize(partition_offsets.size()); + + // Add final guard + partition_offsets.emplace_back(group_count); +} + +WindowConstantAggregatorLocalState::WindowConstantAggregatorLocalState( + const WindowConstantAggregatorGlobalState &gstate) + : gstate(gstate), statep(Value::POINTER(0)), statef(gstate.statef.aggr), partition(0) { + matches.Initialize(); + + // Start the aggregates + auto &partition_offsets = gstate.partition_offsets; + auto &aggregator = gstate.aggregator; + statef.Initialize(partition_offsets.size() - 1); + + // Set up shared buffer + inputs.Initialize(Allocator::DefaultAllocator(), aggregator.arg_types); + + gstate.locals++; +} + +WindowConstantAggregator::WindowConstantAggregator(AggregateObject aggr, const vector &arg_types, + const LogicalType &result_type, + const WindowExcludeMode exclude_mode_p) + : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p) { +} + +unique_ptr WindowConstantAggregator::GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const { + return make_uniq(*this, group_count, partition_mask); +} + +void WindowConstantAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, + idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { + auto &lastate = lstate.Cast(); + + lastate.Sink(arg_chunk, input_idx, filter_sel, filtered); +} + +void WindowConstantAggregatorLocalState::Sink(DataChunk &payload_chunk, idx_t row, + optional_ptr filter_sel, idx_t filtered) { + auto &partition_offsets = gstate.partition_offsets; + auto &aggregator = gstate.aggregator; + const auto &aggr = aggregator.aggr; + const auto chunk_begin = row; + const auto chunk_end = chunk_begin + payload_chunk.size(); + idx_t partition = + idx_t(std::upper_bound(partition_offsets.begin(), partition_offsets.end(), row) - partition_offsets.begin()) - + 1; + + auto state_f_data = statef.GetData(); + auto state_p_data = FlatVector::GetData(statep); + + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + idx_t begin = 0; + idx_t filter_idx = 0; + auto partition_end = partition_offsets[partition + 1]; + while (row < chunk_end) { + if (row == partition_end) { + ++partition; + partition_end = partition_offsets[partition + 1]; + } + partition_end = MinValue(partition_end, chunk_end); + auto end = partition_end - chunk_begin; + + inputs.Reset(); + if (filter_sel) { + // Slice to any filtered rows in [begin, end) + SelectionVector sel; + + // Find the first value in [begin, end) + for (; filter_idx < filtered; ++filter_idx) { + auto idx = filter_sel->get_index(filter_idx); + if (idx >= begin) { + break; + } + } + + // Find the first value in [end, filtered) + sel.Initialize(filter_sel->data() + filter_idx); + idx_t nsel = 0; + for (; filter_idx < filtered; ++filter_idx, ++nsel) { + auto idx = filter_sel->get_index(filter_idx); + if (idx >= end) { + break; + } + } + + if (nsel != inputs.size()) { + inputs.Slice(payload_chunk, sel, nsel); + } + } else { + // Slice to [begin, end) + if (begin) { + for (idx_t c = 0; c < payload_chunk.ColumnCount(); ++c) { + inputs.data[c].Slice(payload_chunk.data[c], begin, end); + } + } else { + inputs.Reference(payload_chunk); + } + inputs.SetCardinality(end - begin); + } + + // Aggregate the filtered rows into a single state + const auto count = inputs.size(); + auto state = state_f_data[partition]; + if (aggr.function.simple_update) { + aggr.function.simple_update(inputs.data.data(), aggr_input_data, inputs.ColumnCount(), state, count); + } else { + state_p_data[0] = state_f_data[partition]; + aggr.function.update(inputs.data.data(), aggr_input_data, inputs.ColumnCount(), statep, count); + } + + // Skip filtered rows too! + row += end - begin; + begin = end; + } +} + +void WindowConstantAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, + const FrameStats &stats) { + auto &gastate = gstate.Cast(); + auto &lastate = lstate.Cast(); + + // Single-threaded combine + lock_guard finalize_guard(gastate.lock); + lastate.statef.Combine(gastate.statef); + lastate.statef.Destroy(); + + // Last one out turns off the lights! + if (++gastate.finalized == gastate.locals) { + gastate.statef.Finalize(*gastate.results); + gastate.statef.Destroy(); + } +} + +unique_ptr WindowConstantAggregator::GetLocalState(const WindowAggregatorState &gstate) const { + return make_uniq(gstate.Cast()); +} + +void WindowConstantAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { + auto &gasink = gsink.Cast(); + const auto &partition_offsets = gasink.partition_offsets; + const auto &results = *gasink.results; + + auto begins = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); + // Chunk up the constants and copy them one at a time + auto &lcstate = lstate.Cast(); + idx_t matched = 0; + idx_t target_offset = 0; + for (idx_t i = 0; i < count; ++i) { + const auto begin = begins[i]; + // Find the partition containing [begin, end) + while (partition_offsets[lcstate.partition + 1] <= begin) { + // Flush the previous partition's data + if (matched) { + VectorOperations::Copy(results, result, lcstate.matches, matched, 0, target_offset); + target_offset += matched; + matched = 0; + } + ++lcstate.partition; + } + + lcstate.matches.set_index(matched++, lcstate.partition); + } + + // Flush the last partition + if (matched) { + // Optimize constant result + if (target_offset == 0 && matched == count) { + VectorOperations::Copy(results, result, lcstate.matches, 1, 0, target_offset); + result.SetVectorType(VectorType::CONSTANT_VECTOR); + } else { + VectorOperations::Copy(results, result, lcstate.matches, matched, 0, target_offset); + } + } +} + +//===--------------------------------------------------------------------===// +// WindowCustomAggregator +//===--------------------------------------------------------------------===// +WindowCustomAggregator::WindowCustomAggregator(AggregateObject aggr, const vector &arg_types, + const LogicalType &result_type, const WindowExcludeMode exclude_mode) + : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode) { +} + +WindowCustomAggregator::~WindowCustomAggregator() { +} + +class WindowCustomAggregatorState : public WindowAggregatorState { +public: + WindowCustomAggregatorState(const AggregateObject &aggr, const WindowExcludeMode exclude_mode); + ~WindowCustomAggregatorState() override; + +public: + //! The aggregate function + const AggregateObject &aggr; + //! Data pointer that contains a single state, shared by all the custom evaluators + vector state; + //! Reused result state container for the window functions + Vector statef; + //! The frame boundaries, used for the window functions + SubFrames frames; +}; + +static void InitSubFrames(SubFrames &frames, const WindowExcludeMode exclude_mode) { + idx_t nframes = 0; + switch (exclude_mode) { + case WindowExcludeMode::NO_OTHER: + nframes = 1; + break; + case WindowExcludeMode::TIES: + nframes = 3; + break; + case WindowExcludeMode::CURRENT_ROW: + case WindowExcludeMode::GROUP: + nframes = 2; + break; + } + frames.resize(nframes, {0, 0}); +} + +class WindowCustomAggregatorGlobalState : public WindowAggregatorGlobalState { +public: + explicit WindowCustomAggregatorGlobalState(const WindowCustomAggregator &aggregator, idx_t group_count) + : WindowAggregatorGlobalState(aggregator, group_count) { + + gcstate = make_uniq(aggregator.aggr, aggregator.exclude_mode); + } + + //! Traditional packed filter mask for API + ValidityMask filter_packed; + //! Data pointer that contains a single local state, used for global custom window execution state + unique_ptr gcstate; + //! Partition description for custom window APIs + unique_ptr partition_input; +}; + +WindowCustomAggregatorState::WindowCustomAggregatorState(const AggregateObject &aggr, + const WindowExcludeMode exclude_mode) + : aggr(aggr), state(aggr.function.state_size(aggr.function)), + statef(Value::POINTER(CastPointerToValue(state.data()))), frames(3, {0, 0}) { + // if we have a frame-by-frame method, share the single state + aggr.function.initialize(aggr.function, state.data()); + + InitSubFrames(frames, exclude_mode); +} + +WindowCustomAggregatorState::~WindowCustomAggregatorState() { + if (aggr.function.destructor) { + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.destructor(statef, aggr_input_data, 1); + } +} + +unique_ptr WindowCustomAggregator::GetGlobalState(idx_t group_count, + const ValidityMask &) const { + return make_uniq(*this, group_count); +} + +void WindowCustomAggregator::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const FrameStats &stats) { + // Single threaded Finalize for now + auto &gcsink = gsink.Cast(); + lock_guard gestate_guard(gcsink.lock); + if (gcsink.finalized) { + return; + } + + WindowAggregator::Finalize(gsink, lstate, stats); + + auto &inputs = gcsink.inputs; + auto &filter_mask = gcsink.filter_mask; + auto &filter_packed = gcsink.filter_packed; + filter_mask.Pack(filter_packed, filter_mask.target_count); + + gcsink.partition_input = + make_uniq(inputs.data.data(), inputs.ColumnCount(), inputs.size(), filter_packed, stats); + + if (aggr.function.window_init) { + auto &gcstate = *gcsink.gcstate; + + AggregateInputData aggr_input_data(aggr.GetFunctionData(), gcstate.allocator); + aggr.function.window_init(aggr_input_data, *gcsink.partition_input, gcstate.state.data()); + } + + ++gcsink.finalized; +} + +unique_ptr WindowCustomAggregator::GetLocalState(const WindowAggregatorState &gstate) const { + return make_uniq(aggr, exclude_mode); +} + +template +static void EvaluateSubFrames(const DataChunk &bounds, const WindowExcludeMode exclude_mode, idx_t count, idx_t row_idx, + SubFrames &frames, OP operation) { + auto begins = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); + auto ends = FlatVector::GetData(bounds.data[WINDOW_END]); + auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); + + for (idx_t i = 0, cur_row = row_idx; i < count; ++i, ++cur_row) { + idx_t nframes = 0; + if (exclude_mode == WindowExcludeMode::NO_OTHER) { + auto begin = begins[i]; + auto end = ends[i]; + frames[nframes++] = FrameBounds(begin, end); + } else { + // The frame_exclusion option allows rows around the current row to be excluded from the frame, + // even if they would be included according to the frame start and frame end options. + // EXCLUDE CURRENT ROW excludes the current row from the frame. + // EXCLUDE GROUP excludes the current row and its ordering peers from the frame. + // EXCLUDE TIES excludes any peers of the current row from the frame, but not the current row itself. + // EXCLUDE NO OTHERS simply specifies explicitly the default behavior + // of not excluding the current row or its peers. + // https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS + // + // For the sake of the client, we make some guarantees about the subframes: + // * They are in order left-to-right + // * They do not intersect + // * start <= end + // * The number is always the same + // + // Since we always have peer_begin <= cur_row < cur_row + 1 <= peer_end + // this is not too hard to arrange, but it may be that some subframes are contiguous, + // and some are empty. + + // WindowExcludePart::LEFT + auto begin = begins[i]; + auto end = (exclude_mode == WindowExcludeMode::CURRENT_ROW) ? cur_row : peer_begin[i]; + end = MaxValue(begin, end); + frames[nframes++] = FrameBounds(begin, end); + + // with EXCLUDE TIES, in addition to the frame part right of the peer group's end, + // we also need to consider the current row + if (exclude_mode == WindowExcludeMode::TIES) { + frames[nframes++] = FrameBounds(cur_row, cur_row + 1); + } + + // WindowExcludePart::RIGHT + end = ends[i]; + begin = (exclude_mode == WindowExcludeMode::CURRENT_ROW) ? (cur_row + 1) : peer_end[i]; + begin = MinValue(begin, end); + frames[nframes++] = FrameBounds(begin, end); + } + + operation(i); + } +} + +void WindowCustomAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { + auto &lcstate = lstate.Cast(); + auto &frames = lcstate.frames; + const_data_ptr_t gstate_p = nullptr; + auto &gcsink = gsink.Cast(); + if (gcsink.gcstate) { + gstate_p = gcsink.gcstate->state.data(); + } + + EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t i) { + // Extract the range + AggregateInputData aggr_input_data(aggr.GetFunctionData(), lstate.allocator); + aggr.function.window(aggr_input_data, *gcsink.partition_input, gstate_p, lcstate.state.data(), frames, result, + i); + }); +} + +//===--------------------------------------------------------------------===// +// WindowNaiveAggregator +//===--------------------------------------------------------------------===// +WindowNaiveAggregator::WindowNaiveAggregator(AggregateObject aggr, const vector &arg_types, + const LogicalType &result_type, const WindowExcludeMode exclude_mode) + : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode) { +} + +WindowNaiveAggregator::~WindowNaiveAggregator() { +} + +class WindowNaiveState : public WindowAggregatorState { +public: + struct HashRow { + HashRow(WindowNaiveState &state, const DataChunk &inputs) : state(state), inputs(inputs) { + } + + size_t operator()(const idx_t &i) const { + return state.Hash(inputs, i); + } + + WindowNaiveState &state; + const DataChunk &inputs; + }; + + struct EqualRow { + EqualRow(WindowNaiveState &state, const DataChunk &inputs) : state(state), inputs(inputs) { + } + + bool operator()(const idx_t &lhs, const idx_t &rhs) const { + return state.KeyEqual(inputs, lhs, rhs); + } + + WindowNaiveState &state; + const DataChunk &inputs; + }; + + using RowSet = std::unordered_set; + + explicit WindowNaiveState(const WindowNaiveAggregator &gsink); + + void Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, + idx_t row_idx); + +protected: + //! Flush the accumulated intermediate states into the result states + void FlushStates(const WindowAggregatorGlobalState &gsink); + + //! Hashes a value for the hash table + size_t Hash(const DataChunk &inputs, idx_t rid); + //! Compares two values for the hash table + bool KeyEqual(const DataChunk &inputs, const idx_t &lhs, const idx_t &rhs); + + //! The global state + const WindowNaiveAggregator &aggregator; + //! Data pointer that contains a vector of states, used for row aggregation + vector state; + //! Reused result state container for the aggregate + Vector statef; + //! A vector of pointers to "state", used for buffering intermediate aggregates + Vector statep; + //! Input data chunk, used for leaf segment aggregation + DataChunk leaves; + //! The rows beging updated. + SelectionVector update_sel; + //! Count of buffered values + idx_t flush_count; + //! The frame boundaries, used for EXCLUDE + SubFrames frames; + //! The optional hash table used for DISTINCT + Vector hashes; +}; + +WindowNaiveState::WindowNaiveState(const WindowNaiveAggregator &aggregator_p) + : aggregator(aggregator_p), state(aggregator.state_size * STANDARD_VECTOR_SIZE), statef(LogicalType::POINTER), + statep((LogicalType::POINTER)), flush_count(0), hashes(LogicalType::HASH) { + InitSubFrames(frames, aggregator.exclude_mode); + + update_sel.Initialize(); + + // Build the finalise vector that just points to the result states + data_ptr_t state_ptr = state.data(); + D_ASSERT(statef.GetVectorType() == VectorType::FLAT_VECTOR); + statef.SetVectorType(VectorType::CONSTANT_VECTOR); + statef.Flatten(STANDARD_VECTOR_SIZE); + auto fdata = FlatVector::GetData(statef); + for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; ++i) { + fdata[i] = state_ptr; + state_ptr += aggregator.state_size; + } +} + +void WindowNaiveState::FlushStates(const WindowAggregatorGlobalState &gsink) { + if (!flush_count) { + return; + } + + auto &inputs = gsink.inputs; + leaves.Slice(inputs, update_sel, flush_count); + + auto &aggr = aggregator.aggr; + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), statep, flush_count); + + flush_count = 0; +} + +size_t WindowNaiveState::Hash(const DataChunk &inputs, idx_t rid) { + auto s = UnsafeNumericCast(rid); + SelectionVector sel(&s); + leaves.Slice(inputs, sel, 1); + leaves.Hash(hashes); + + return *FlatVector::GetData(hashes); +} + +bool WindowNaiveState::KeyEqual(const DataChunk &inputs, const idx_t &lhs, const idx_t &rhs) { + auto l = UnsafeNumericCast(lhs); + SelectionVector lsel(&l); + + auto r = UnsafeNumericCast(rhs); + SelectionVector rsel(&r); + + sel_t f = 0; + SelectionVector fsel(&f); + + for (auto &input : inputs.data) { + Vector left(input, lsel, 1); + Vector right(input, rsel, 1); + if (!VectorOperations::NotDistinctFrom(left, right, nullptr, 1, nullptr, &fsel)) { + return false; + } + } + + return true; +} + +void WindowNaiveState::Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, + idx_t count, idx_t row_idx) { + auto &aggr = aggregator.aggr; + auto &filter_mask = gsink.filter_mask; + auto &inputs = gsink.inputs; + + if (leaves.ColumnCount() == 0 && inputs.ColumnCount() > 0) { + leaves.Initialize(Allocator::DefaultAllocator(), inputs.GetTypes()); + } + + auto fdata = FlatVector::GetData(statef); + auto pdata = FlatVector::GetData(statep); + + HashRow hash_row(*this, inputs); + EqualRow equal_row(*this, inputs); + RowSet row_set(STANDARD_VECTOR_SIZE, hash_row, equal_row); + + EvaluateSubFrames(bounds, aggregator.exclude_mode, count, row_idx, frames, [&](idx_t rid) { + auto agg_state = fdata[rid]; + aggr.function.initialize(aggr.function, agg_state); + + // Just update the aggregate with the unfiltered input rows + row_set.clear(); + for (const auto &frame : frames) { + for (auto f = frame.start; f < frame.end; ++f) { + if (!filter_mask.RowIsValid(f)) { + continue; + } + + // Filter out duplicates + if (aggr.IsDistinct() && !row_set.insert(f).second) { + continue; + } + + pdata[flush_count] = agg_state; + update_sel[flush_count++] = UnsafeNumericCast(f); + if (flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(gsink); + } + } + } + }); + + // Flush the final states + FlushStates(gsink); + + // Finalise the result aggregates and write to the result + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.finalize(statef, aggr_input_data, result, count, 0); + + // Destruct the result aggregates + if (aggr.function.destructor) { + aggr.function.destructor(statef, aggr_input_data, count); + } +} + +unique_ptr WindowNaiveAggregator::GetLocalState(const WindowAggregatorState &gstate) const { + return make_uniq(*this); +} + +void WindowNaiveAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { + const auto &gnstate = gsink.Cast(); + auto &lnstate = lstate.Cast(); + lnstate.Evaluate(gnstate, bounds, result, count, row_idx); +} + +//===--------------------------------------------------------------------===// +// WindowSegmentTree +//===--------------------------------------------------------------------===// +class WindowSegmentTreeGlobalState : public WindowAggregatorGlobalState { +public: + using AtomicCounters = vector>; + + WindowSegmentTreeGlobalState(const WindowSegmentTree &aggregator, idx_t group_count); + + ArenaAllocator &CreateTreeAllocator() { + lock_guard tree_lock(lock); + tree_allocators.emplace_back(make_uniq(Allocator::DefaultAllocator())); + return *tree_allocators.back(); + } + + //! The owning aggregator + const WindowSegmentTree &tree; + //! The actual window segment tree: an array of aggregate states that represent all the intermediate nodes + WindowAggregateStates levels_flat_native; + //! For each level, the starting location in the levels_flat_native array + vector levels_flat_start; + //! The level being built (read) + std::atomic build_level; + //! The number of entries started so far at each level + unique_ptr build_started; + //! The number of entries completed so far at each level + unique_ptr build_completed; + //! The tree allocators. + //! We need to hold onto them for the tree lifetime, + //! not the lifetime of the local state that constructed part of the tree + vector> tree_allocators; + + // TREE_FANOUT needs to cleanly divide STANDARD_VECTOR_SIZE + static constexpr idx_t TREE_FANOUT = 16; +}; + +WindowSegmentTree::WindowSegmentTree(AggregateObject aggr, const vector &arg_types, + const LogicalType &result_type, WindowAggregationMode mode_p, + const WindowExcludeMode exclude_mode_p) + : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p), mode(mode_p) { +} + +class WindowSegmentTreePart { +public: + //! Right side nodes need to be cached and processed in reverse order + using RightEntry = std::pair; + + enum FramePart : uint8_t { FULL = 0, LEFT = 1, RIGHT = 2 }; + + WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, const DataChunk &inputs, + const ValidityArray &filter_mask); + ~WindowSegmentTreePart(); + + unique_ptr Copy() const { + return make_uniq(allocator, aggr, inputs, filter_mask); + } + + void FlushStates(bool combining); + void ExtractFrame(idx_t begin, idx_t end, data_ptr_t current_state); + void WindowSegmentValue(const WindowSegmentTreeGlobalState &tree, idx_t l_idx, idx_t begin, idx_t end, + data_ptr_t current_state); + //! Writes result and calls destructors + void Finalize(Vector &result, idx_t count); + + void Combine(WindowSegmentTreePart &other, idx_t count); + + void Evaluate(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, Vector &result, + idx_t count, idx_t row_idx, FramePart frame_part); + +protected: + //! Initialises the accumulation state vector (statef) + void Initialize(idx_t count); + //! Accumulate upper tree levels + void EvaluateUpperLevels(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, + idx_t count, idx_t row_idx, FramePart frame_part); + void EvaluateLeaves(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, idx_t count, + idx_t row_idx, FramePart frame_part, FramePart leaf_part); + +public: + //! Allocator for aggregates + ArenaAllocator &allocator; + //! The aggregate function + const AggregateObject &aggr; + //! Order insensitive aggregate (we can optimise internal combines) + const bool order_insensitive; + //! The partition arguments + const DataChunk &inputs; + //! The filtered rows in inputs + const ValidityArray &filter_mask; + //! The size of a single aggregate state + const idx_t state_size; + //! Data pointer that contains a vector of states, used for intermediate window segment aggregation + vector state; + //! Input data chunk, used for leaf segment aggregation + DataChunk leaves; + //! The filtered rows in inputs. + SelectionVector filter_sel; + //! A vector of pointers to "state", used for intermediate window segment aggregation + Vector statep; + //! Reused state pointers for combining segment tree levels + Vector statel; + //! Reused result state container for the window functions + Vector statef; + //! Count of buffered values + idx_t flush_count; + //! Cache of right side tree ranges for ordered aggregates + vector right_stack; +}; + +class WindowSegmentTreeState : public WindowAggregatorState { +public: + WindowSegmentTreeState() { + } + + void Finalize(WindowSegmentTreeGlobalState &gstate); + void Evaluate(const WindowSegmentTreeGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, + idx_t row_idx); + //! The left (default) segment tree part + unique_ptr part; + //! The right segment tree part (for EXCLUDE) + unique_ptr right_part; +}; + +void WindowSegmentTree::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, const FrameStats &stats) { + + auto &gasink = gsink.Cast(); + auto &inputs = gasink.inputs; + + WindowAggregator::Finalize(gsink, lstate, stats); + + if (inputs.ColumnCount() > 0) { + if (aggr.function.combine && UseCombineAPI()) { + lstate.Cast().Finalize(gasink); + } + } + + ++gasink.finalized; +} + +WindowSegmentTreePart::WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, + const DataChunk &inputs, const ValidityArray &filter_mask) + : allocator(allocator), aggr(aggr), + order_insensitive(aggr.function.order_dependent == AggregateOrderDependent::NOT_ORDER_DEPENDENT), inputs(inputs), + filter_mask(filter_mask), state_size(aggr.function.state_size(aggr.function)), + state(state_size * STANDARD_VECTOR_SIZE), statep(LogicalType::POINTER), statel(LogicalType::POINTER), + statef(LogicalType::POINTER), flush_count(0) { + if (inputs.ColumnCount() > 0) { + leaves.Initialize(Allocator::DefaultAllocator(), inputs.GetTypes()); + filter_sel.Initialize(); + } + + // Build the finalise vector that just points to the result states + data_ptr_t state_ptr = state.data(); + D_ASSERT(statef.GetVectorType() == VectorType::FLAT_VECTOR); + statef.SetVectorType(VectorType::CONSTANT_VECTOR); + statef.Flatten(STANDARD_VECTOR_SIZE); + auto fdata = FlatVector::GetData(statef); + for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; ++i) { + fdata[i] = state_ptr; + state_ptr += state_size; + } +} + +WindowSegmentTreePart::~WindowSegmentTreePart() { +} + +unique_ptr WindowSegmentTree::GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const { + return make_uniq(*this, group_count); +} + +unique_ptr WindowSegmentTree::GetLocalState(const WindowAggregatorState &gstate) const { + return make_uniq(); +} + +void WindowSegmentTreePart::FlushStates(bool combining) { + if (!flush_count) { + return; + } + + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + if (combining) { + statel.Verify(flush_count); + aggr.function.combine(statel, statep, aggr_input_data, flush_count); + } else { + leaves.Slice(inputs, filter_sel, flush_count); + aggr.function.update(&leaves.data[0], aggr_input_data, leaves.ColumnCount(), statep, flush_count); + } + + flush_count = 0; +} + +void WindowSegmentTreePart::Combine(WindowSegmentTreePart &other, idx_t count) { + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.combine(other.statef, statef, aggr_input_data, count); +} + +void WindowSegmentTreePart::ExtractFrame(idx_t begin, idx_t end, data_ptr_t state_ptr) { + const auto count = end - begin; + + // If we are not filtering, + // just update the shared dictionary selection to the range + // Otherwise set it to the input rows that pass the filter + auto states = FlatVector::GetData(statep); + if (filter_mask.AllValid()) { + for (idx_t i = 0; i < count; ++i) { + states[flush_count] = state_ptr; + filter_sel.set_index(flush_count++, begin + i); + if (flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(false); + } + } + } else { + for (idx_t i = begin; i < end; ++i) { + if (filter_mask.RowIsValid(i)) { + states[flush_count] = state_ptr; + filter_sel.set_index(flush_count++, i); + if (flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(false); + } + } + } + } +} + +void WindowSegmentTreePart::WindowSegmentValue(const WindowSegmentTreeGlobalState &tree, idx_t l_idx, idx_t begin, + idx_t end, data_ptr_t state_ptr) { + D_ASSERT(begin <= end); + if (begin == end || inputs.ColumnCount() == 0) { + return; + } + + const auto count = end - begin; + if (l_idx == 0) { + ExtractFrame(begin, end, state_ptr); + } else { + // find out where the states begin + auto begin_ptr = tree.levels_flat_native.GetStatePtr(begin + tree.levels_flat_start[l_idx - 1]); + // set up a vector of pointers that point towards the set of states + auto ldata = FlatVector::GetData(statel); + auto pdata = FlatVector::GetData(statep); + for (idx_t i = 0; i < count; i++) { + pdata[flush_count] = state_ptr; + ldata[flush_count++] = begin_ptr; + begin_ptr += state_size; + if (flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(true); + } + } + } +} +void WindowSegmentTreePart::Finalize(Vector &result, idx_t count) { + // Finalise the result aggregates and write to result if write_result is set + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + aggr.function.finalize(statef, aggr_input_data, result, count, 0); + + // Destruct the result aggregates + if (aggr.function.destructor) { + aggr.function.destructor(statef, aggr_input_data, count); + } +} + +WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(const WindowSegmentTree &aggregator, idx_t group_count) + : WindowAggregatorGlobalState(aggregator, group_count), tree(aggregator), levels_flat_native(aggregator.aggr) { + + D_ASSERT(inputs.ColumnCount() > 0); + + // compute space required to store internal nodes of segment tree + levels_flat_start.push_back(0); + + idx_t levels_flat_offset = 0; + idx_t level_current = 0; + // level 0 is data itself + idx_t level_size; + // iterate over the levels of the segment tree + while ((level_size = + (level_current == 0 ? inputs.size() : levels_flat_offset - levels_flat_start[level_current - 1])) > 1) { + for (idx_t pos = 0; pos < level_size; pos += TREE_FANOUT) { + levels_flat_offset++; + } + + levels_flat_start.push_back(levels_flat_offset); + level_current++; + } + + // Corner case: single element in the window + if (levels_flat_offset == 0) { + ++levels_flat_offset; + } + + levels_flat_native.Initialize(levels_flat_offset); + + // Start by building from the bottom level + build_level = 0; + + build_started = make_uniq(levels_flat_start.size()); + for (auto &counter : *build_started) { + counter = 0; + } + + build_completed = make_uniq(levels_flat_start.size()); + for (auto &counter : *build_completed) { + counter = 0; + } +} + +void WindowSegmentTreeState::Finalize(WindowSegmentTreeGlobalState &gstate) { + // Single part for constructing the tree + auto &inputs = gstate.inputs; + auto &tree = gstate.tree; + auto &filter_mask = gstate.filter_mask; + WindowSegmentTreePart gtstate(gstate.CreateTreeAllocator(), tree.aggr, inputs, filter_mask); + + auto &levels_flat_native = gstate.levels_flat_native; + const auto &levels_flat_start = gstate.levels_flat_start; + // iterate over the levels of the segment tree + for (;;) { + const idx_t level_current = gstate.build_level.load(); + if (level_current >= levels_flat_start.size()) { + break; + } + + // level 0 is data itself + const auto level_size = + (level_current == 0 ? inputs.size() + : levels_flat_start[level_current] - levels_flat_start[level_current - 1]); + if (level_size <= 1) { + break; + } + const idx_t build_count = (level_size + gstate.TREE_FANOUT - 1) / gstate.TREE_FANOUT; + + // Build the next fan-in + const idx_t build_idx = (*gstate.build_started).at(level_current)++; + if (build_idx >= build_count) { + // Nothing left at this level, so wait until other threads are done. + // Since we are only building TREE_FANOUT values at a time, this will be quick. + while (level_current == gstate.build_level.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + continue; + } + + // compute the aggregate for this entry in the segment tree + const idx_t pos = build_idx * gstate.TREE_FANOUT; + const idx_t levels_flat_offset = levels_flat_start[level_current] + build_idx; + auto state_ptr = levels_flat_native.GetStatePtr(levels_flat_offset); + gtstate.WindowSegmentValue(gstate, level_current, pos, MinValue(level_size, pos + gstate.TREE_FANOUT), + state_ptr); + gtstate.FlushStates(level_current > 0); + + // If that was the last one, mark the level as complete. + const idx_t build_complete = ++(*gstate.build_completed).at(level_current); + if (build_complete == build_count) { + gstate.build_level++; + continue; + } + } +} + +void WindowSegmentTree::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { + const auto >state = gsink.Cast(); + auto <state = lstate.Cast(); + ltstate.Evaluate(gtstate, bounds, result, count, row_idx); +} + +void WindowSegmentTreeState::Evaluate(const WindowSegmentTreeGlobalState >state, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) { + auto window_begin = FlatVector::GetData(bounds.data[WINDOW_BEGIN]); + auto window_end = FlatVector::GetData(bounds.data[WINDOW_END]); + auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); + auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); + + if (!part) { + part = + make_uniq(allocator, gtstate.aggregator.aggr, gtstate.inputs, gtstate.filter_mask); + } + + if (gtstate.aggregator.exclude_mode != WindowExcludeMode::NO_OTHER) { + // 1. evaluate the tree left of the excluded part + part->Evaluate(gtstate, window_begin, peer_begin, result, count, row_idx, WindowSegmentTreePart::LEFT); + + // 2. set up a second state for the right of the excluded part + if (!right_part) { + right_part = part->Copy(); + } + + // 3. evaluate the tree right of the excluded part + right_part->Evaluate(gtstate, peer_end, window_end, result, count, row_idx, WindowSegmentTreePart::RIGHT); + + // 4. combine the buffer state into the Segment Tree State + part->Combine(*right_part, count); + } else { + part->Evaluate(gtstate, window_begin, window_end, result, count, row_idx, WindowSegmentTreePart::FULL); + } + + part->Finalize(result, count); +} + +void WindowSegmentTreePart::Evaluate(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, + Vector &result, idx_t count, idx_t row_idx, FramePart frame_part) { + Initialize(count); + + if (order_insensitive) { + // First pass: aggregate the segment tree nodes with sharing + EvaluateUpperLevels(tree, begins, ends, count, row_idx, frame_part); + + // Second pass: aggregate the ragged leaves + EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::FULL); + } else { + // Evaluate leaves in order + EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::LEFT); + EvaluateUpperLevels(tree, begins, ends, count, row_idx, frame_part); + EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::RIGHT); + } +} + +void WindowSegmentTreePart::Initialize(idx_t count) { + auto fdata = FlatVector::GetData(statef); + for (idx_t rid = 0; rid < count; ++rid) { + auto state_ptr = fdata[rid]; + aggr.function.initialize(aggr.function, state_ptr); + } +} + +void WindowSegmentTreePart::EvaluateUpperLevels(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, + const idx_t *ends, idx_t count, idx_t row_idx, FramePart frame_part) { + auto fdata = FlatVector::GetData(statef); + + const auto exclude_mode = tree.tree.exclude_mode; + const bool begin_on_curr_row = frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::CURRENT_ROW; + const bool end_on_curr_row = frame_part == FramePart::LEFT && exclude_mode == WindowExcludeMode::CURRENT_ROW; + + const auto max_level = tree.levels_flat_start.size() + 1; + right_stack.resize(max_level, {0, 0}); + + // Share adjacent identical states + // We do this first because we want to share only tree aggregations + idx_t prev_begin = 1; + idx_t prev_end = 0; + auto ldata = FlatVector::GetData(statel); + auto pdata = FlatVector::GetData(statep); + data_ptr_t prev_state = nullptr; + for (idx_t rid = 0, cur_row = row_idx; rid < count; ++rid, ++cur_row) { + auto state_ptr = fdata[rid]; + + auto begin = begin_on_curr_row ? cur_row + 1 : begins[rid]; + auto end = end_on_curr_row ? cur_row : ends[rid]; + if (begin >= end) { + continue; + } + + // Skip level 0 + idx_t l_idx = 0; + idx_t right_max = 0; + for (; l_idx < max_level; l_idx++) { + idx_t parent_begin = begin / tree.TREE_FANOUT; + idx_t parent_end = end / tree.TREE_FANOUT; + if (prev_state && l_idx == 1 && begin == prev_begin && end == prev_end) { + // Just combine the previous top level result + ldata[flush_count] = prev_state; + pdata[flush_count] = state_ptr; + if (++flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(true); + } + break; + } + + if (order_insensitive && l_idx == 1) { + prev_state = state_ptr; + prev_begin = begin; + prev_end = end; + } + + if (parent_begin == parent_end) { + if (l_idx) { + WindowSegmentValue(tree, l_idx, begin, end, state_ptr); + } + break; + } + idx_t group_begin = parent_begin * tree.TREE_FANOUT; + if (begin != group_begin) { + if (l_idx) { + WindowSegmentValue(tree, l_idx, begin, group_begin + tree.TREE_FANOUT, state_ptr); + } + parent_begin++; + } + idx_t group_end = parent_end * tree.TREE_FANOUT; + if (end != group_end) { + if (l_idx) { + if (order_insensitive) { + WindowSegmentValue(tree, l_idx, group_end, end, state_ptr); + } else { + right_stack[l_idx] = {group_end, end}; + right_max = l_idx; + } + } + } + begin = parent_begin; + end = parent_end; + } + + // Flush the right side values from left to right for order_sensitive aggregates + // As we go up the tree, the right side ranges move left, + // so we just cache them in a fixed size, preallocated array. + // Then we can just reverse scan the array and append the cached ranges. + for (l_idx = right_max; l_idx > 0; --l_idx) { + auto &right_entry = right_stack[l_idx]; + const auto group_end = right_entry.first; + const auto end = right_entry.second; + if (end) { + WindowSegmentValue(tree, l_idx, group_end, end, state_ptr); + right_entry = {0, 0}; + } + } + } + FlushStates(true); +} + +void WindowSegmentTreePart::EvaluateLeaves(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, + const idx_t *ends, idx_t count, idx_t row_idx, FramePart frame_part, + FramePart leaf_part) { + + auto fdata = FlatVector::GetData(statef); + + // For order-sensitive aggregates, we have to process the ragged leaves in two pieces. + // The left side have to be added before the main tree followed by the ragged right sides. + // The current row is the leftmost value of the right hand side. + const bool compute_left = leaf_part != FramePart::RIGHT; + const bool compute_right = leaf_part != FramePart::LEFT; + const auto exclude_mode = tree.tree.exclude_mode; + const bool begin_on_curr_row = frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::CURRENT_ROW; + const bool end_on_curr_row = frame_part == FramePart::LEFT && exclude_mode == WindowExcludeMode::CURRENT_ROW; + // with EXCLUDE TIES, in addition to the frame part right of the peer group's end, we also need to consider the + // current row + const bool add_curr_row = compute_left && frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::TIES; + + for (idx_t rid = 0, cur_row = row_idx; rid < count; ++rid, ++cur_row) { + auto state_ptr = fdata[rid]; + + const auto begin = begin_on_curr_row ? cur_row + 1 : begins[rid]; + const auto end = end_on_curr_row ? cur_row : ends[rid]; + if (add_curr_row) { + WindowSegmentValue(tree, 0, cur_row, cur_row + 1, state_ptr); + } + if (begin >= end) { + continue; + } + + idx_t parent_begin = begin / tree.TREE_FANOUT; + idx_t parent_end = end / tree.TREE_FANOUT; + if (parent_begin == parent_end) { + if (compute_left) { + WindowSegmentValue(tree, 0, begin, end, state_ptr); + } + continue; + } + + idx_t group_begin = parent_begin * tree.TREE_FANOUT; + if (begin != group_begin && compute_left) { + WindowSegmentValue(tree, 0, begin, group_begin + tree.TREE_FANOUT, state_ptr); + } + idx_t group_end = parent_end * tree.TREE_FANOUT; + if (end != group_end && compute_right) { + WindowSegmentValue(tree, 0, group_end, end, state_ptr); + } + } + FlushStates(false); +} + +//===--------------------------------------------------------------------===// +// WindowDistinctAggregator +//===--------------------------------------------------------------------===// +WindowDistinctAggregator::WindowDistinctAggregator(AggregateObject aggr, const vector &arg_types, + const LogicalType &result_type, + const WindowExcludeMode exclude_mode_p, ClientContext &context) + : WindowAggregator(std::move(aggr), arg_types, result_type, exclude_mode_p), context(context) { +} + +class WindowDistinctAggregatorLocalState; + +class WindowDistinctAggregatorGlobalState; + +class WindowDistinctSortTree : public MergeSortTree { +public: + // prev_idx, input_idx + using ZippedTuple = std::tuple; + using ZippedElements = vector; + + explicit WindowDistinctSortTree(WindowDistinctAggregatorGlobalState &gdastate, idx_t count) : gdastate(gdastate) { + // Set up for parallel build + build_level = 0; + build_complete = 0; + build_run = 0; + build_run_length = 1; + build_num_runs = count; + } + + void Build(WindowDistinctAggregatorLocalState &ldastate); + +protected: + bool TryNextRun(idx_t &level_idx, idx_t &run_idx); + void BuildRun(idx_t level_nr, idx_t i, WindowDistinctAggregatorLocalState &ldastate); + + WindowDistinctAggregatorGlobalState &gdastate; +}; + +class WindowDistinctAggregatorGlobalState : public WindowAggregatorGlobalState { +public: + using GlobalSortStatePtr = unique_ptr; + using ZippedTuple = WindowDistinctSortTree::ZippedTuple; + using ZippedElements = WindowDistinctSortTree::ZippedElements; + + WindowDistinctAggregatorGlobalState(const WindowDistinctAggregator &aggregator, idx_t group_count); + + //! Compute the block starts + void MeasurePayloadBlocks(); + //! Patch up the previous index block boundaries + void PatchPrevIdcs(); + bool TryPrepareNextStage(WindowDistinctAggregatorLocalState &lstate); + + // Single threaded sorting for now + ClientContext &context; + idx_t memory_per_thread; + + //! Finalize guard + mutex lock; + //! Finalize stage + atomic stage; + //! Tasks launched + idx_t total_tasks = 0; + //! Tasks launched + idx_t tasks_assigned = 0; + //! Tasks landed + mutable atomic tasks_completed; + + //! The sorted payload data types (partition index) + vector payload_types; + //! The aggregate arguments + partition index + vector sort_types; + + //! Sorting operations + GlobalSortStatePtr global_sort; + //! The block starts (the scanner doesn't know this) plus the total count + vector block_starts; + + //! The block boundary seconds + mutable ZippedElements seconds; + //! The MST with the distinct back pointers + mutable MergeSortTree zipped_tree; + //! The merge sort tree for the aggregate. + WindowDistinctSortTree merge_sort_tree; + + //! The actual window segment tree: an array of aggregate states that represent all the intermediate nodes + WindowAggregateStates levels_flat_native; + //! For each level, the starting location in the levels_flat_native array + vector levels_flat_start; +}; + +WindowDistinctAggregatorGlobalState::WindowDistinctAggregatorGlobalState(const WindowDistinctAggregator &aggregator, + idx_t group_count) + : WindowAggregatorGlobalState(aggregator, group_count), context(aggregator.context), + stage(PartitionSortStage::INIT), tasks_completed(0), merge_sort_tree(*this, group_count), + levels_flat_native(aggregator.aggr) { + payload_types.emplace_back(LogicalType::UBIGINT); + + // 1: functionComputePrevIdcs(𝑖𝑛) + // 2: sorted ← [] + // We sort the aggregate arguments and use the partition index as a tie-breaker. + // TODO: Use a hash table? + sort_types = aggregator.arg_types; + for (const auto &type : payload_types) { + sort_types.emplace_back(type); + } + + vector orders; + for (const auto &type : sort_types) { + auto expr = make_uniq(Value(type)); + orders.emplace_back(BoundOrderByNode(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(expr))); + } + + RowLayout payload_layout; + payload_layout.Initialize(payload_types); + + global_sort = make_uniq(BufferManager::GetBufferManager(context), orders, payload_layout); + + memory_per_thread = PhysicalOperator::GetMaxThreadMemory(context); + + // 6: prevIdcs ← [] + // 7: prevIdcs[0] ← “-” + auto &prev_idcs = zipped_tree.Allocate(group_count); + + // To handle FILTER clauses we make the missing elements + // point to themselves so they won't be counted. + for (idx_t i = 0; i < group_count; ++i) { + prev_idcs[i] = ZippedTuple(i + 1, i); + } + + // compute space required to store aggregation states of merge sort tree + // this is one aggregate state per entry per level + idx_t internal_nodes = 0; + levels_flat_start.push_back(internal_nodes); + for (idx_t level_nr = 0; level_nr < zipped_tree.tree.size(); ++level_nr) { + internal_nodes += zipped_tree.tree[level_nr].first.size(); + levels_flat_start.push_back(internal_nodes); + } + levels_flat_native.Initialize(internal_nodes); + + merge_sort_tree.tree.reserve(zipped_tree.tree.size()); + for (idx_t level_nr = 0; level_nr < zipped_tree.tree.size(); ++level_nr) { + auto &zipped_level = zipped_tree.tree[level_nr].first; + WindowDistinctSortTree::Elements level; + WindowDistinctSortTree::Offsets cascades; + level.resize(zipped_level.size()); + merge_sort_tree.tree.emplace_back(std::move(level), std::move(cascades)); + } +} + +class WindowDistinctAggregatorLocalState : public WindowAggregatorState { +public: + explicit WindowDistinctAggregatorLocalState(const WindowDistinctAggregatorGlobalState &aggregator); + + void Sink(DataChunk &arg_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + void Sorted(); + void ExecuteTask(); + void Evaluate(const WindowDistinctAggregatorGlobalState &gdstate, const DataChunk &bounds, Vector &result, + idx_t count, idx_t row_idx); + + //! Thread-local sorting data + LocalSortState local_sort; + //! Finalize stage + PartitionSortStage stage = PartitionSortStage::INIT; + //! Finalize scan block index + idx_t block_idx; + //! Thread-local tree aggregation + Vector update_v; + Vector source_v; + Vector target_v; + DataChunk leaves; + SelectionVector sel; + +protected: + //! Flush the accumulated intermediate states into the result states + void FlushStates(); + + //! The aggregator we are working with + const WindowDistinctAggregatorGlobalState &gastate; + DataChunk sort_chunk; + DataChunk payload_chunk; + //! Reused result state container for the window functions + WindowAggregateStates statef; + //! A vector of pointers to "state", used for buffering intermediate aggregates + Vector statep; + //! Reused state pointers for combining tree elements + Vector statel; + //! Count of buffered values + idx_t flush_count; + //! The frame boundaries, used for the window functions + SubFrames frames; +}; + +WindowDistinctAggregatorLocalState::WindowDistinctAggregatorLocalState( + const WindowDistinctAggregatorGlobalState &gastate) + : update_v(LogicalType::POINTER), source_v(LogicalType::POINTER), target_v(LogicalType::POINTER), gastate(gastate), + statef(gastate.aggregator.aggr), statep(LogicalType::POINTER), statel(LogicalType::POINTER), flush_count(0) { + InitSubFrames(frames, gastate.aggregator.exclude_mode); + payload_chunk.Initialize(Allocator::DefaultAllocator(), gastate.payload_types); + + auto &global_sort = gastate.global_sort; + local_sort.Initialize(*global_sort, global_sort->buffer_manager); + + sort_chunk.Initialize(Allocator::DefaultAllocator(), gastate.sort_types); + sort_chunk.data.back().Reference(payload_chunk.data[0]); + + //! Input data chunk, used for leaf segment aggregation + leaves.Initialize(Allocator::DefaultAllocator(), gastate.inputs.GetTypes()); + sel.Initialize(); + + gastate.locals++; +} + +unique_ptr WindowDistinctAggregator::GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const { + return make_uniq(*this, group_count); +} + +void WindowDistinctAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, + idx_t input_idx, optional_ptr filter_sel, idx_t filtered) { + WindowAggregator::Sink(gsink, lstate, arg_chunk, input_idx, filter_sel, filtered); + + auto &ldstate = lstate.Cast(); + ldstate.Sink(arg_chunk, input_idx, filter_sel, filtered); +} + +void WindowDistinctAggregatorLocalState::Sink(DataChunk &arg_chunk, idx_t input_idx, + optional_ptr filter_sel, idx_t filtered) { + // 3: for i ← 0 to in.size do + // 4: sorted[i] ← (in[i], i) + const auto count = arg_chunk.size(); + payload_chunk.Reset(); + auto &sorted_vec = payload_chunk.data[0]; + auto sorted = FlatVector::GetData(sorted_vec); + std::iota(sorted, sorted + count, input_idx); + + for (column_t c = 0; c < arg_chunk.ColumnCount(); ++c) { + sort_chunk.data[c].Reference(arg_chunk.data[c]); + } + sort_chunk.data.back().Reference(sorted_vec); + sort_chunk.SetCardinality(arg_chunk); + payload_chunk.SetCardinality(sort_chunk); + + // Apply FILTER clause, if any + if (filter_sel) { + sort_chunk.Slice(*filter_sel, filtered); + payload_chunk.Slice(*filter_sel, filtered); + } + + local_sort.SinkChunk(sort_chunk, payload_chunk); + + if (local_sort.SizeInBytes() > gastate.memory_per_thread) { + local_sort.Sort(*gastate.global_sort, true); + } +} + +void WindowDistinctAggregatorLocalState::ExecuteTask() { + auto &global_sort = *gastate.global_sort; + switch (stage) { + case PartitionSortStage::INIT: + // AddLocalState is thread-safe + global_sort.AddLocalState(local_sort); + break; + case PartitionSortStage::MERGE: { + MergeSorter merge_sorter(global_sort, global_sort.buffer_manager); + merge_sorter.PerformInMergeRound(); + break; + } + case PartitionSortStage::SORTED: + Sorted(); + break; + default: + break; + } + + ++gastate.tasks_completed; +} + +void WindowDistinctAggregatorGlobalState::MeasurePayloadBlocks() { + const auto &blocks = global_sort->sorted_blocks[0]->payload_data->data_blocks; + idx_t count = 0; + for (const auto &block : blocks) { + block_starts.emplace_back(count); + count += block->count; + } + block_starts.emplace_back(count); +} + +bool WindowDistinctAggregatorGlobalState::TryPrepareNextStage(WindowDistinctAggregatorLocalState &lstate) { + lock_guard stage_guard(lock); + + switch (stage.load()) { + case PartitionSortStage::INIT: + // Wait for all the local sorts to be processed + if (tasks_completed < locals) { + return false; + } + global_sort->PrepareMergePhase(); + if (!(global_sort->sorted_blocks.size() / 2)) { + if (global_sort->sorted_blocks.empty()) { + lstate.stage = stage = PartitionSortStage::FINISHED; + return true; + } + MeasurePayloadBlocks(); + seconds.resize(block_starts.size() - 1); + total_tasks = seconds.size(); + tasks_completed = 0; + tasks_assigned = 0; + lstate.stage = stage = PartitionSortStage::SORTED; + lstate.block_idx = tasks_assigned++; + return true; + } + global_sort->InitializeMergeRound(); + lstate.stage = stage = PartitionSortStage::MERGE; + total_tasks = locals; + tasks_assigned = 1; + tasks_completed = 0; + return true; + case PartitionSortStage::MERGE: + if (tasks_assigned < total_tasks) { + lstate.stage = PartitionSortStage::MERGE; + ++tasks_assigned; + return true; + } else if (tasks_completed < tasks_assigned) { + return false; + } + global_sort->CompleteMergeRound(true); + if (!(global_sort->sorted_blocks.size() / 2)) { + MeasurePayloadBlocks(); + seconds.resize(block_starts.size() - 1); + total_tasks = seconds.size(); + tasks_completed = 0; + tasks_assigned = 0; + lstate.stage = stage = PartitionSortStage::SORTED; + lstate.block_idx = tasks_assigned++; + return true; + } + global_sort->InitializeMergeRound(); + lstate.stage = PartitionSortStage::MERGE; + total_tasks = locals; + tasks_assigned = 1; + tasks_completed = 0; + return true; + case PartitionSortStage::SORTED: + if (tasks_assigned < total_tasks) { + lstate.stage = PartitionSortStage::SORTED; + lstate.block_idx = tasks_assigned++; + return true; + } else if (tasks_completed < tasks_assigned) { + lstate.stage = PartitionSortStage::FINISHED; + // Sleep while other tasks finish + return false; + } + // Last task patches the boundaries + PatchPrevIdcs(); + break; + default: + break; + } + + lstate.stage = stage = PartitionSortStage::FINISHED; + + return true; +} + +void WindowDistinctAggregator::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const FrameStats &stats) { + auto &gdsink = gsink.Cast(); + auto &ldstate = lstate.Cast(); + + // 5: Sort sorted lexicographically increasing + ldstate.ExecuteTask(); + + // Merge in parallel + while (gdsink.stage.load() != PartitionSortStage::FINISHED) { + if (gdsink.TryPrepareNextStage(ldstate)) { + ldstate.ExecuteTask(); + } else { + std::this_thread::yield(); + } + } + + // These are a parallel implementations, + // so every thread can call them. + gdsink.zipped_tree.Build(); + gdsink.merge_sort_tree.Build(ldstate); + + ++gdsink.finalized; +} + +void WindowDistinctAggregatorLocalState::Sorted() { + using ZippedTuple = WindowDistinctAggregatorGlobalState::ZippedTuple; + auto &global_sort = gastate.global_sort; + auto &prev_idcs = gastate.zipped_tree.LowestLevel(); + auto &aggregator = gastate.aggregator; + auto &scan_chunk = payload_chunk; + + auto scanner = make_uniq(*global_sort, block_idx); + const auto in_size = gastate.block_starts.at(block_idx + 1); + scanner->Scan(scan_chunk); + idx_t scan_idx = 0; + + auto *input_idx = FlatVector::GetData(scan_chunk.data[0]); + idx_t i = 0; + + SBIterator curr(*global_sort, ExpressionType::COMPARE_LESSTHAN); + SBIterator prev(*global_sort, ExpressionType::COMPARE_LESSTHAN); + auto prefix_layout = global_sort->sort_layout.GetPrefixComparisonLayout(aggregator.arg_types.size()); + + const auto block_begin = gastate.block_starts.at(block_idx); + if (!block_begin) { + // First block, so set up initial sentinel + i = input_idx[scan_idx++]; + prev_idcs[i] = ZippedTuple(0, i); + std::get<0>(gastate.seconds[block_idx]) = i; + } else { + // Move to the to end of the previous block + // so we can record the comparison result for the first row + curr.SetIndex(block_begin - 1); + prev.SetIndex(block_begin - 1); + scan_idx = 0; + std::get<0>(gastate.seconds[block_idx]) = input_idx[scan_idx]; + } + + // 8: for i ← 1 to in.size do + for (++curr; curr.GetIndex() < in_size; ++curr, ++prev) { + // Scan second one chunk at a time + // Note the scan is one behind the iterators + if (scan_idx >= scan_chunk.size()) { + scan_chunk.Reset(); + scanner->Scan(scan_chunk); + scan_idx = 0; + input_idx = FlatVector::GetData(scan_chunk.data[0]); + } + auto second = i; + i = input_idx[scan_idx++]; + + int lt = 0; + if (prefix_layout.all_constant) { + lt = FastMemcmp(prev.entry_ptr, curr.entry_ptr, prefix_layout.comparison_size); + } else { + lt = Comparators::CompareTuple(prev.scan, curr.scan, prev.entry_ptr, curr.entry_ptr, prefix_layout, + prev.external); + } + + // 9: if sorted[i].first == sorted[i-1].first then + // 10: prevIdcs[i] ← sorted[i-1].second + // 11: else + // 12: prevIdcs[i] ← “-” + if (!lt) { + prev_idcs[i] = ZippedTuple(second + 1, i); + } else { + prev_idcs[i] = ZippedTuple(0, i); + } + } + + // Save the last value of i for patching up the block boundaries + std::get<1>(gastate.seconds[block_idx]) = i; +} + +void WindowDistinctAggregatorGlobalState::PatchPrevIdcs() { + // 13: return prevIdcs + + // Patch up the indices at block boundaries + // (We don't need to patch block 0.) + auto &prev_idcs = zipped_tree.LowestLevel(); + for (idx_t block_idx = 1; block_idx < seconds.size(); ++block_idx) { + // We only need to patch if the first index in the block + // was a back link to the previous block (10:) + auto i = std::get<0>(seconds.at(block_idx)); + if (std::get<0>(prev_idcs[i])) { + auto second = std::get<1>(seconds.at(block_idx - 1)); + prev_idcs[i] = ZippedTuple(second + 1, i); + } + } +} + +bool WindowDistinctSortTree::TryNextRun(idx_t &level_idx, idx_t &run_idx) { + const auto fanout = FANOUT; + + lock_guard stage_guard(build_lock); + + // Verify we are not done + if (build_level >= tree.size()) { + return false; + } + + // Finished with this level? + if (build_complete >= build_num_runs) { + auto &zipped_tree = gdastate.zipped_tree; + std::swap(tree[build_level].second, zipped_tree.tree[build_level].second); + + ++build_level; + if (build_level >= tree.size()) { + zipped_tree.tree.clear(); + return false; + } + + const auto count = LowestLevel().size(); + build_run_length *= fanout; + build_num_runs = (count + build_run_length - 1) / build_run_length; + build_run = 0; + build_complete = 0; + } + + // If all runs are in flight, + // yield until the next level is ready + if (build_run >= build_num_runs) { + return false; + } + + level_idx = build_level; + run_idx = build_run++; + + return true; +} + +void WindowDistinctSortTree::Build(WindowDistinctAggregatorLocalState &ldastate) { + // Fan in parent levels until we are at the top + // Note that we don't build the top layer as that would just be all the data. + while (build_level.load() < tree.size()) { + idx_t level_idx; + idx_t run_idx; + if (TryNextRun(level_idx, run_idx)) { + BuildRun(level_idx, run_idx, ldastate); + } else { + std::this_thread::yield(); + } + } +} + +void WindowDistinctSortTree::BuildRun(idx_t level_nr, idx_t run_idx, WindowDistinctAggregatorLocalState &ldastate) { + auto &aggr = gdastate.aggregator.aggr; + auto &allocator = gdastate.allocator; + auto &inputs = gdastate.inputs; + auto &levels_flat_native = gdastate.levels_flat_native; + + //! Input data chunk, used for leaf segment aggregation + auto &leaves = ldastate.leaves; + auto &sel = ldastate.sel; + + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + + //! The states to update + auto &update_v = ldastate.update_v; + auto updates = FlatVector::GetData(update_v); + + auto &source_v = ldastate.source_v; + auto sources = FlatVector::GetData(source_v); + auto &target_v = ldastate.target_v; + auto targets = FlatVector::GetData(target_v); + + auto &zipped_tree = gdastate.zipped_tree; + auto &zipped_level = zipped_tree.tree[level_nr].first; + auto &level = tree[level_nr].first; + + // Reset the combine state + idx_t nupdate = 0; + idx_t ncombine = 0; + data_ptr_t prev_state = nullptr; + idx_t i = run_idx * build_run_length; + auto next_limit = MinValue(zipped_level.size(), i + build_run_length); + idx_t levels_flat_offset = level_nr * zipped_level.size() + i; + for (auto j = i; j < next_limit; ++j) { + // Initialise the next aggregate + auto curr_state = levels_flat_native.GetStatePtr(levels_flat_offset++); + + // Update this state (if it matches) + const auto prev_idx = std::get<0>(zipped_level[j]); + level[j] = prev_idx; + if (prev_idx < i + 1) { + updates[nupdate] = curr_state; + // input_idx + sel[nupdate] = UnsafeNumericCast(std::get<1>(zipped_level[j])); + ++nupdate; + } + + // Merge the previous state (if any) + if (prev_state) { + sources[ncombine] = prev_state; + targets[ncombine] = curr_state; + ++ncombine; + } + prev_state = curr_state; + + // Flush the states if one is maxed out. + if (MaxValue(ncombine, nupdate) >= STANDARD_VECTOR_SIZE) { + // Push the updates first so they propagate + leaves.Reference(inputs); + leaves.Slice(sel, nupdate); + aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); + nupdate = 0; + + // Combine the states sequentially + aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); + ncombine = 0; + } + } + + // Flush any remaining states + if (ncombine || nupdate) { + // Push the updates + leaves.Reference(inputs); + leaves.Slice(sel, nupdate); + aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); + nupdate = 0; + + // Combine the states sequentially + aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); + ncombine = 0; + } + + ++build_complete; +} + +void WindowDistinctAggregatorLocalState::FlushStates() { + if (!flush_count) { + return; + } + + const auto &aggr = gastate.aggregator.aggr; + AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); + statel.Verify(flush_count); + aggr.function.combine(statel, statep, aggr_input_data, flush_count); + + flush_count = 0; +} + +void WindowDistinctAggregatorLocalState::Evaluate(const WindowDistinctAggregatorGlobalState &gdstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) { + auto ldata = FlatVector::GetData(statel); + auto pdata = FlatVector::GetData(statep); + + const auto &merge_sort_tree = gdstate.merge_sort_tree; + const auto &levels_flat_native = gdstate.levels_flat_native; + const auto exclude_mode = gdstate.aggregator.exclude_mode; + + // Build the finalise vector that just points to the result states + statef.Initialize(count); + + EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t rid) { + auto agg_state = statef.GetStatePtr(rid); + + // TODO: Extend AggregateLowerBound to handle subframes, just like SelectNth. + const auto lower = frames[0].start; + const auto upper = frames[0].end; + merge_sort_tree.AggregateLowerBound(lower, upper, lower + 1, + [&](idx_t level, const idx_t run_begin, const idx_t run_pos) { + if (run_pos != run_begin) { + // Find the source aggregate + // Buffer a merge of the indicated state into the current state + const auto agg_idx = gdstate.levels_flat_start[level] + run_pos - 1; + const auto running_agg = levels_flat_native.GetStatePtr(agg_idx); + pdata[flush_count] = agg_state; + ldata[flush_count++] = running_agg; + if (flush_count >= STANDARD_VECTOR_SIZE) { + FlushStates(); + } + } + }); + }); + + // Flush the final states + FlushStates(); + + // Finalise the result aggregates and write to the result + statef.Finalize(result); + statef.Destroy(); +} + +unique_ptr WindowDistinctAggregator::GetLocalState(const WindowAggregatorState &gstate) const { + return make_uniq(gstate.Cast()); +} + +void WindowDistinctAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, + const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { + + const auto &gdstate = gsink.Cast(); + auto &ldstate = lstate.Cast(); + ldstate.Evaluate(gdstate, bounds, result, count, row_idx); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/distributive/count.cpp b/src/duckdb/src/function/aggregate/distributive/count.cpp index 30824b7a2..8b5c3be2b 100644 --- a/src/duckdb/src/function/aggregate/distributive/count.cpp +++ b/src/duckdb/src/function/aggregate/distributive/count.cpp @@ -1,7 +1,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" namespace duckdb { @@ -37,7 +36,7 @@ struct CountStarFunction : public BaseCountFunction { template static void Window(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, const_data_ptr_t, data_ptr_t l_state, const SubFrames &frames, Vector &result, idx_t rid) { - D_ASSERT(partition.column_ids.empty()); + D_ASSERT(partition.input_count == 0); auto data = FlatVector::GetData(result); RESULT_TYPE total = 0; @@ -211,7 +210,7 @@ struct CountFunction : public BaseCountFunction { } }; -AggregateFunction CountFunctionBase::GetFunction() { +AggregateFunction CountFun::GetFunction() { AggregateFunction fun({LogicalType(LogicalTypeId::ANY)}, LogicalType::BIGINT, AggregateFunction::StateSize, AggregateFunction::StateInitialize, CountFunction::CountScatter, AggregateFunction::StateCombine, @@ -242,14 +241,21 @@ unique_ptr CountPropagateStats(ClientContext &context, BoundAggr return nullptr; } -AggregateFunctionSet CountFun::GetFunctions() { - AggregateFunction count_function = CountFunctionBase::GetFunction(); +void CountFun::RegisterFunction(BuiltinFunctions &set) { + AggregateFunction count_function = CountFun::GetFunction(); count_function.statistics = CountPropagateStats; AggregateFunctionSet count("count"); count.AddFunction(count_function); // the count function can also be called without arguments + count_function = CountStarFun::GetFunction(); + count.AddFunction(count_function); + set.AddFunction(count); +} + +void CountStarFun::RegisterFunction(BuiltinFunctions &set) { + AggregateFunctionSet count("count_star"); count.AddFunction(CountStarFun::GetFunction()); - return count; + set.AddFunction(count); } } // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp b/src/duckdb/src/function/aggregate/distributive/first.cpp similarity index 86% rename from src/duckdb/src/function/aggregate/distributive/first_last_any.cpp rename to src/duckdb/src/function/aggregate/distributive/first.cpp index 4e7455efa..8fed21904 100644 --- a/src/duckdb/src/function/aggregate/distributive/first_last_any.cpp +++ b/src/duckdb/src/function/aggregate/distributive/first.cpp @@ -1,8 +1,7 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" -#include "duckdb/function/create_sort_key.hpp" #include "duckdb/planner/expression.hpp" namespace duckdb { @@ -69,7 +68,7 @@ struct FirstFunction : public FirstFunctionBase { template struct FirstFunctionStringBase : public FirstFunctionBase { - template + template static void SetValue(STATE &state, AggregateInputData &input_data, string_t value, bool is_null) { if (LAST && state.is_set) { Destroy(state, input_data); @@ -82,9 +81,7 @@ struct FirstFunctionStringBase : public FirstFunctionBase { } else { state.is_set = true; state.is_null = false; - if ((COMBINE && !LAST) || value.IsInlined()) { - // We use the aggregate allocator for 'first', so the allocation is already done when combining - // Of course, if the value is inlined, we also don't need to allocate + if (value.IsInlined()) { state.value = value; } else { // non-inlined string, need to allocate space for it @@ -100,7 +97,7 @@ struct FirstFunctionStringBase : public FirstFunctionBase { template static void Combine(const STATE &source, STATE &target, AggregateInputData &input_data) { if (source.is_set && (LAST || !target.is_set)) { - SetValue(target, input_data, source.value, source.is_null); + SetValue(target, input_data, source.value, source.is_null); } } @@ -216,23 +213,9 @@ struct FirstVectorFunction : FirstFunctionStringBase { } }; -template -static void FirstFunctionSimpleUpdate(Vector inputs[], AggregateInputData &aggregate_input_data, idx_t input_count, - data_ptr_t state, idx_t count) { - auto agg_state = reinterpret_cast *>(state); - if (LAST || !agg_state->is_set) { - // For FIRST, this skips looping over the input once the aggregate state has been set - // FIXME: for LAST we could loop from the back of the Vector instead - AggregateFunction::UnaryUpdate, T, FirstFunction>(inputs, aggregate_input_data, - input_count, state, count); - } -} - template static AggregateFunction GetFirstAggregateTemplated(LogicalType type) { - auto result = AggregateFunction::UnaryAggregate, T, T, FirstFunction>(type, type); - result.simple_update = FirstFunctionSimpleUpdate; - return result; + return AggregateFunction::UnaryAggregate, T, T, FirstFunction>(type, type); } template @@ -308,7 +291,7 @@ static AggregateFunction GetFirstFunction(const LogicalType &type) { } } -AggregateFunction FirstFunctionGetter::GetFunction(const LogicalType &type) { +AggregateFunction FirstFun::GetFunction(const LogicalType &type) { auto fun = GetFirstFunction(type); fun.name = "first"; return fun; @@ -321,7 +304,6 @@ unique_ptr BindDecimalFirst(ClientContext &context, AggregateFunct auto name = std::move(function.name); function = GetFirstFunction(decimal_type); function.name = std::move(name); - function.distinct_dependent = AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT; function.return_type = decimal_type; return nullptr; } @@ -341,7 +323,6 @@ unique_ptr BindFirst(ClientContext &context, AggregateFunction &fu auto name = std::move(function.name); function = GetFirstOperator(input_type); function.name = std::move(name); - function.distinct_dependent = AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT; if (function.bind) { return function.bind(context, function, arguments); } else { @@ -357,22 +338,22 @@ static void AddFirstOperator(AggregateFunctionSet &set) { nullptr, BindFirst)); } -AggregateFunctionSet FirstFun::GetFunctions() { +void FirstFun::RegisterFunction(BuiltinFunctions &set) { AggregateFunctionSet first("first"); - AddFirstOperator(first); - return first; -} - -AggregateFunctionSet LastFun::GetFunctions() { AggregateFunctionSet last("last"); - AddFirstOperator(last); - return last; -} - -AggregateFunctionSet AnyValueFun::GetFunctions() { AggregateFunctionSet any_value("any_value"); + + AddFirstOperator(first); + AddFirstOperator(last); AddFirstOperator(any_value); - return any_value; + + set.AddFunction(first); + first.name = "arbitrary"; + set.AddFunction(first); + + set.AddFunction(last); + + set.AddFunction(any_value); } } // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/distributive_functions.cpp b/src/duckdb/src/function/aggregate/distributive_functions.cpp new file mode 100644 index 000000000..5971861c7 --- /dev/null +++ b/src/duckdb/src/function/aggregate/distributive_functions.cpp @@ -0,0 +1,15 @@ +#include "duckdb/function/aggregate/distributive_functions.hpp" +#include "duckdb/common/exception.hpp" +#include "duckdb/common/types/null_value.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" +#include "duckdb/function/aggregate_function.hpp" + +namespace duckdb { + +void BuiltinFunctions::RegisterDistributiveAggregates() { + Register(); + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp index aa49db798..4e86f930b 100644 --- a/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +++ b/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp @@ -4,7 +4,6 @@ #include "duckdb/common/types/list_segment.hpp" #include "duckdb/function/aggregate_function.hpp" #include "duckdb/function/function_binder.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" #include "duckdb/storage/buffer_manager.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" @@ -14,46 +13,35 @@ namespace duckdb { struct SortedAggregateBindData : public FunctionData { - using Expressions = vector>; - using BindInfoPtr = unique_ptr; - using OrderBys = vector; - - SortedAggregateBindData(ClientContext &context, Expressions &children, AggregateFunction &aggregate, - BindInfoPtr &bind_info, OrderBys &order_bys) - : buffer_manager(BufferManager::GetBufferManager(context)), function(aggregate), - bind_info(std::move(bind_info)), threshold(ClientConfig::GetConfig(context).ordered_aggregate_threshold), + SortedAggregateBindData(ClientContext &context, BoundAggregateExpression &expr) + : buffer_manager(BufferManager::GetBufferManager(context)), function(expr.function), + bind_info(std::move(expr.bind_info)), threshold(ClientConfig::GetConfig(context).ordered_aggregate_threshold), external(ClientConfig::GetConfig(context).force_external) { + auto &children = expr.children; arg_types.reserve(children.size()); arg_funcs.reserve(children.size()); for (const auto &child : children) { arg_types.emplace_back(child->return_type); ListSegmentFunctions funcs; GetSegmentDataFunctions(funcs, arg_types.back()); - arg_funcs.emplace_back(std::move(funcs)); + arg_funcs.emplace_back(funcs); } - sort_types.reserve(order_bys.size()); - sort_funcs.reserve(order_bys.size()); - for (auto &order : order_bys) { + auto &order_bys = *expr.order_bys; + sort_types.reserve(order_bys.orders.size()); + sort_funcs.reserve(order_bys.orders.size()); + for (auto &order : order_bys.orders) { orders.emplace_back(order.Copy()); sort_types.emplace_back(order.expression->return_type); ListSegmentFunctions funcs; GetSegmentDataFunctions(funcs, sort_types.back()); - sort_funcs.emplace_back(std::move(funcs)); + sort_funcs.emplace_back(funcs); } - sorted_on_args = (children.size() == order_bys.size()); + sorted_on_args = (children.size() == order_bys.orders.size()); for (size_t i = 0; sorted_on_args && i < children.size(); ++i) { - sorted_on_args = children[i]->Equals(*order_bys[i].expression); + sorted_on_args = children[i]->Equals(*order_bys.orders[i].expression); } } - SortedAggregateBindData(ClientContext &context, BoundAggregateExpression &expr) - : SortedAggregateBindData(context, expr.children, expr.function, expr.bind_info, expr.order_bys->orders) { - } - - SortedAggregateBindData(ClientContext &context, BoundWindowExpression &expr) - : SortedAggregateBindData(context, expr.children, *expr.aggregate, expr.bind_info, expr.arg_orders) { - } - SortedAggregateBindData(const SortedAggregateBindData &other) : buffer_manager(other.buffer_manager), function(other.function), arg_types(other.arg_types), arg_funcs(other.arg_funcs), sort_types(other.sort_types), sort_funcs(other.sort_funcs), @@ -756,8 +744,7 @@ void FunctionBinder::BindSortedAggregate(ClientContext &context, BoundAggregateE // Replace the aggregate with the wrapper AggregateFunction ordered_aggregate( bound_function.name, arguments, bound_function.return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + AggregateFunction::StateInitialize, SortedAggregateFunction::ScatterUpdate, AggregateFunction::StateCombine, SortedAggregateFunction::Finalize, bound_function.null_handling, SortedAggregateFunction::SimpleUpdate, nullptr, @@ -769,50 +756,4 @@ void FunctionBinder::BindSortedAggregate(ClientContext &context, BoundAggregateE expr.order_bys.reset(); } -void FunctionBinder::BindSortedAggregate(ClientContext &context, BoundWindowExpression &expr) { - if (expr.arg_orders.empty() || expr.children.empty()) { - // not a sorted aggregate: return - return; - } - // Remove unnecessary ORDER BY clauses and return if nothing remains - if (context.config.enable_optimizer) { - if (BoundOrderModifier::Simplify(expr.arg_orders, expr.partitions)) { - expr.arg_orders.clear(); - return; - } - } - auto &aggregate = *expr.aggregate; - auto &children = expr.children; - auto &arg_orders = expr.arg_orders; - auto sorted_bind = make_uniq(context, expr); - - if (!sorted_bind->sorted_on_args) { - // The arguments are the children plus the sort columns. - for (auto &order : arg_orders) { - children.emplace_back(std::move(order.expression)); - } - } - - vector arguments; - arguments.reserve(children.size()); - for (const auto &child : children) { - arguments.emplace_back(child->return_type); - } - - // Replace the aggregate with the wrapper - AggregateFunction ordered_aggregate( - aggregate.name, arguments, aggregate.return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - SortedAggregateFunction::ScatterUpdate, - AggregateFunction::StateCombine, - SortedAggregateFunction::Finalize, aggregate.null_handling, SortedAggregateFunction::SimpleUpdate, nullptr, - AggregateFunction::StateDestroy, nullptr, - SortedAggregateFunction::Window); - - aggregate = std::move(ordered_aggregate); - expr.bind_info = std::move(sorted_bind); - expr.arg_orders.clear(); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/built_in_functions.cpp b/src/duckdb/src/function/built_in_functions.cpp index 00e7eac64..23372fcdb 100644 --- a/src/duckdb/src/function/built_in_functions.cpp +++ b/src/duckdb/src/function/built_in_functions.cpp @@ -1,16 +1,12 @@ #include "duckdb/function/built_in_functions.hpp" - -#include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" -#include "duckdb/main/extension_entries.hpp" #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" #include "duckdb/parser/parsed_data/create_collation_info.hpp" #include "duckdb/parser/parsed_data/create_copy_function_info.hpp" #include "duckdb/parser/parsed_data/create_pragma_function_info.hpp" #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" #include "duckdb/parser/parsed_data/create_table_function_info.hpp" -#include "duckdb/main/extension_helper.hpp" -#include "duckdb/main/config.hpp" +#include "duckdb/catalog/catalog.hpp" +#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp" namespace duckdb { @@ -89,83 +85,4 @@ void BuiltinFunctions::AddFunction(CopyFunction function) { catalog.CreateCopyFunction(transaction, info); } -struct ExtensionFunctionInfo : public ScalarFunctionInfo { - explicit ExtensionFunctionInfo(string extension_p) : extension(std::move(extension_p)) { - } - - string extension; -}; - -unique_ptr BindExtensionFunction(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - // if this is triggered we are trying to call a method that is present in an extension - // but the extension is not loaded - // try to autoload the extension - // first figure out which extension we need to auto-load - auto &function_info = bound_function.function_info->Cast(); - auto &extension_name = function_info.extension; - auto &db = *context.db; - - if (!ExtensionHelper::CanAutoloadExtension(extension_name)) { - throw BinderException("Trying to call function \"%s\" which is present in extension \"%s\" - but the extension " - "is not loaded and could not be auto-loaded", - bound_function.name, extension_name); - } - // auto-load the extension - ExtensionHelper::AutoLoadExtension(db, extension_name); - - // now find the function in the catalog - auto &catalog = Catalog::GetSystemCatalog(db); - auto &function_entry = catalog.GetEntry(context, DEFAULT_SCHEMA, bound_function.name); - // override the function with the extension function - bound_function = function_entry.functions.GetFunctionByArguments(context, bound_function.arguments); - // call the original bind (if any) - if (!bound_function.bind) { - return nullptr; - } - return bound_function.bind(context, bound_function, arguments); -} - -void BuiltinFunctions::AddExtensionFunction(ScalarFunctionSet set) { - CreateScalarFunctionInfo info(std::move(set)); - info.internal = true; - catalog.CreateFunction(transaction, info); -} - -void BuiltinFunctions::RegisterExtensionOverloads() { -#ifdef GENERATE_EXTENSION_ENTRIES - // do not insert auto loading placeholders when generating extension entries - return; -#endif - ScalarFunctionSet current_set; - for (auto &entry : EXTENSION_FUNCTION_OVERLOADS) { - vector arguments; - auto splits = StringUtil::Split(entry.signature, ">"); - auto return_type = DBConfig::ParseLogicalType(splits[1]); - auto argument_splits = StringUtil::Split(splits[0], ","); - for (auto ¶m : argument_splits) { - arguments.push_back(DBConfig::ParseLogicalType(param)); - } - if (entry.type != CatalogType::SCALAR_FUNCTION_ENTRY) { - throw InternalException( - "Extension function overloads only supported for scalar functions currently - %s has a different type", - entry.name); - } - - ScalarFunction function(entry.name, std::move(arguments), std::move(return_type), nullptr, - BindExtensionFunction); - function.function_info = make_shared_ptr(entry.extension); - if (current_set.name != entry.name) { - if (!current_set.name.empty()) { - // create set of functions - AddExtensionFunction(current_set); - } - current_set = ScalarFunctionSet(entry.name); - } - // add this function to the set of function overloads - current_set.AddFunction(std::move(function)); - } - AddExtensionFunction(std::move(current_set)); -} - } // namespace duckdb diff --git a/src/duckdb/src/function/cast/decimal_cast.cpp b/src/duckdb/src/function/cast/decimal_cast.cpp index 21f80bf04..7f9f2b493 100644 --- a/src/duckdb/src/function/cast/decimal_cast.cpp +++ b/src/duckdb/src/function/cast/decimal_cast.cpp @@ -155,7 +155,7 @@ struct DecimalScaleDownCheckOperator { data->result.GetType().ToString()); return HandleVectorCastError::Operation(std::move(error), mask, idx, data->vector_cast_data); } - return DecimalScaleDownOperator::Operation(input, mask, idx, dataptr); + return Cast::Operation(input / data->factor); } }; diff --git a/src/duckdb/src/function/cast/string_cast.cpp b/src/duckdb/src/function/cast/string_cast.cpp index f3a19c427..9f8b5ee29 100644 --- a/src/duckdb/src/function/cast/string_cast.cpp +++ b/src/duckdb/src/function/cast/string_cast.cpp @@ -342,8 +342,8 @@ bool VectorStringToMap::StringToNestedTypeCastLoop(const string_t *source_data, vector_cast_data.all_converted = false; } + auto &key_validity = FlatVector::Validity(result_key_child); if (!vector_cast_data.all_converted) { - auto &key_validity = FlatVector::Validity(result_key_child); for (idx_t row_idx = 0; row_idx < count; row_idx++) { if (!result_mask.RowIsValid(row_idx)) { continue; diff --git a/src/duckdb/src/function/cast/struct_cast.cpp b/src/duckdb/src/function/cast/struct_cast.cpp index 051581c54..94f494c1c 100644 --- a/src/duckdb/src/function/cast/struct_cast.cpp +++ b/src/duckdb/src/function/cast/struct_cast.cpp @@ -1,4 +1,3 @@ -#include "duckdb/common/exception/binder_exception.hpp" #include "duckdb/function/cast/default_casts.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/function/cast/bound_cast_data.hpp" @@ -8,67 +7,51 @@ namespace duckdb { unique_ptr StructBoundCastData::BindStructToStructCast(BindCastInput &input, const LogicalType &source, const LogicalType &target) { vector child_cast_info; - auto &source_children = StructType::GetChildTypes(source); - auto &target_children = StructType::GetChildTypes(target); + auto &source_child_types = StructType::GetChildTypes(source); + auto &result_child_types = StructType::GetChildTypes(target); auto target_is_unnamed = StructType::IsUnnamed(target); auto source_is_unnamed = StructType::IsUnnamed(source); - auto is_unnamed = target_is_unnamed || source_is_unnamed; - if (is_unnamed && source_children.size() != target_children.size()) { + if (source_child_types.size() != result_child_types.size()) { throw TypeMismatchException(input.query_location, source, target, "Cannot cast STRUCTs of different size"); } - - case_insensitive_map_t target_children_map; - if (!is_unnamed) { - for (idx_t i = 0; i < target_children.size(); i++) { - auto &name = target_children[i].first; - if (target_children_map.find(name) != target_children_map.end()) { - throw NotImplementedException("Error while casting - duplicate name \"%s\" in struct", name); + bool named_struct_cast = !source_is_unnamed && !target_is_unnamed; + case_insensitive_map_t target_members; + if (named_struct_cast) { + for (idx_t i = 0; i < result_child_types.size(); i++) { + auto &target_name = result_child_types[i].first; + if (target_members.find(target_name) != target_members.end()) { + throw NotImplementedException("Error while casting - duplicate name \"%s\" in struct", target_name); } - target_children_map[name] = i; + target_members[target_name] = i; } } - - vector source_indexes; - vector target_indexes; - vector target_null_indexes; - bool has_any_match = is_unnamed; - - for (idx_t i = 0; i < source_children.size(); i++) { - auto &source_child = source_children[i]; - auto target_idx = i; - - // Map to the correct index for names structs. - if (!is_unnamed) { - auto target_child = target_children_map.find(source_child.first); - if (target_child == target_children_map.end()) { - // Skip any children that have no target. - continue; + vector child_member_map; + child_member_map.reserve(source_child_types.size()); + for (idx_t source_idx = 0; source_idx < source_child_types.size(); source_idx++) { + auto &source_child = source_child_types[source_idx]; + idx_t target_idx; + if (named_struct_cast) { + // named struct cast - find corresponding member in target + auto entry = target_members.find(source_child.first); + if (entry == target_members.end()) { + throw TypeMismatchException(input.query_location, source, target, + "Cannot cast STRUCTs - element \"" + source_child.first + + "\" in source struct was not found in target struct"); } - target_idx = target_child->second; - target_children_map.erase(target_child); - has_any_match = true; + target_idx = entry->second; + target_members.erase(entry); + } else { + // unnamed struct cast - positionally cast elements + target_idx = source_idx; } - - source_indexes.push_back(i); - target_indexes.push_back(target_idx); - auto child_cast = input.GetCastFunction(source_child.second, target_children[target_idx].second); + child_member_map.push_back(target_idx); + auto child_cast = input.GetCastFunction(source_child.second, result_child_types[target_idx].second); child_cast_info.push_back(std::move(child_cast)); } - - if (!has_any_match) { - throw BinderException("STRUCT to STRUCT cast must have at least one matching member"); - } - - // The remaining target children have no match in the source struct. - // Thus, they become NULL. - for (const auto &target_child : target_children_map) { - target_null_indexes.push_back(target_child.second); - } - - return make_uniq(std::move(child_cast_info), target, std::move(source_indexes), - std::move(target_indexes), std::move(target_null_indexes)); + D_ASSERT(child_member_map.size() == source_child_types.size()); + return make_uniq(std::move(child_cast_info), target, std::move(child_member_map)); } unique_ptr StructBoundCastData::InitStructCastLocalState(CastLocalStateParameters ¶meters) { @@ -88,47 +71,32 @@ unique_ptr StructBoundCastData::InitStructCastLocalState(Cas static bool StructToStructCast(Vector &source, Vector &result, idx_t count, CastParameters ¶meters) { auto &cast_data = parameters.cast_data->Cast(); - auto &l_state = parameters.local_state->Cast(); - - auto &source_vectors = StructVector::GetEntries(source); - auto &target_children = StructVector::GetEntries(result); + auto &lstate = parameters.local_state->Cast(); + auto &source_child_types = StructType::GetChildTypes(source.GetType()); + auto &source_children = StructVector::GetEntries(source); + D_ASSERT(source_children.size() == StructType::GetChildTypes(result.GetType()).size()); + auto &result_children = StructVector::GetEntries(result); bool all_converted = true; - for (idx_t i = 0; i < cast_data.source_indexes.size(); i++) { - auto source_idx = cast_data.source_indexes[i]; - auto target_idx = cast_data.target_indexes[i]; - - auto &source_vector = *source_vectors[source_idx]; - auto &target_vector = *target_children[target_idx]; - - auto &child_cast_info = cast_data.child_cast_info[i]; - CastParameters child_parameters(parameters, child_cast_info.cast_data, l_state.local_states[i]); - auto success = child_cast_info.function(source_vector, target_vector, count, child_parameters); - if (!success) { + for (idx_t c_idx = 0; c_idx < source_child_types.size(); c_idx++) { + auto source_idx = c_idx; + auto target_idx = cast_data.child_member_map[source_idx]; + auto &source_child_vector = *source_children[source_idx]; + auto &result_child_vector = *result_children[target_idx]; + CastParameters child_parameters(parameters, cast_data.child_cast_info[c_idx].cast_data, + lstate.local_states[c_idx]); + if (!cast_data.child_cast_info[c_idx].function(source_child_vector, result_child_vector, count, + child_parameters)) { all_converted = false; } } - - if (!cast_data.target_null_indexes.empty()) { - for (idx_t i = 0; i < cast_data.target_null_indexes.size(); i++) { - auto target_idx = cast_data.target_null_indexes[i]; - auto &target_vector = *target_children[target_idx]; - - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - } - } - if (source.GetVectorType() == VectorType::CONSTANT_VECTOR) { result.SetVectorType(VectorType::CONSTANT_VECTOR); ConstantVector::SetNull(result, ConstantVector::IsNull(source)); - return all_converted; + } else { + source.Flatten(count); + FlatVector::Validity(result) = FlatVector::Validity(source); } - - source.Flatten(count); - auto &result_validity = FlatVector::Validity(result); - result_validity = FlatVector::Validity(source); - result.Verify(count); return all_converted; } diff --git a/src/duckdb/src/function/cast/union/from_struct.cpp b/src/duckdb/src/function/cast/union/from_struct.cpp index c6fcd2a03..ca3aecfca 100644 --- a/src/duckdb/src/function/cast/union/from_struct.cpp +++ b/src/duckdb/src/function/cast/union/from_struct.cpp @@ -58,8 +58,6 @@ bool StructToUnionCast::Cast(Vector &source, Vector &result, idx_t count, CastPa cast_data.child_cast_info[i].function(source_child_vector, result_child_vector, count, child_parameters); (void)converted; D_ASSERT(converted); - // we flatten the child because we use FlatVector::SetNull below and we may get non-flat from source/cast - result_child_vector.Flatten(count); } if (source.GetVectorType() == VectorType::CONSTANT_VECTOR) { @@ -70,15 +68,15 @@ bool StructToUnionCast::Cast(Vector &source, Vector &result, idx_t count, CastPa auto &tag_vec = *target_children[0]; ConstantVector::SetNull(result, ConstantVector::IsNull(tag_vec)); } else { + source.Flatten(count); + FlatVector::Validity(result) = FlatVector::Validity(source); + // if the tag is NULL, the union should be NULL auto &tag_vec = *target_children[0]; - UnifiedVectorFormat source_data, tag_data; - source.ToUnifiedFormat(count, source_data); + UnifiedVectorFormat tag_data; tag_vec.ToUnifiedFormat(count, tag_data); - for (idx_t i = 0; i < count; i++) { - if (!source_data.validity.RowIsValid(source_data.sel->get_index(i)) || - !tag_data.validity.RowIsValid(tag_data.sel->get_index(i))) { + if (!tag_data.validity.RowIsValid(tag_data.sel->get_index(i))) { FlatVector::SetNull(result, i, true); } } diff --git a/src/duckdb/src/function/compression_config.cpp b/src/duckdb/src/function/compression_config.cpp index deece1a85..a5e686f36 100644 --- a/src/duckdb/src/function/compression_config.cpp +++ b/src/duckdb/src/function/compression_config.cpp @@ -26,10 +26,6 @@ static const DefaultCompressionMethod internal_compression_methods[] = { {CompressionType::COMPRESSION_ALP, AlpCompressionFun::GetFunction, AlpCompressionFun::TypeIsSupported}, {CompressionType::COMPRESSION_ALPRD, AlpRDCompressionFun::GetFunction, AlpRDCompressionFun::TypeIsSupported}, {CompressionType::COMPRESSION_FSST, FSSTFun::GetFunction, FSSTFun::TypeIsSupported}, - {CompressionType::COMPRESSION_ZSTD, ZSTDFun::GetFunction, ZSTDFun::TypeIsSupported}, - {CompressionType::COMPRESSION_ROARING, RoaringCompressionFun::GetFunction, RoaringCompressionFun::TypeIsSupported}, - {CompressionType::COMPRESSION_EMPTY, EmptyValidityCompressionFun::GetFunction, - EmptyValidityCompressionFun::TypeIsSupported}, {CompressionType::COMPRESSION_AUTO, nullptr, nullptr}}; static optional_ptr FindCompressionFunction(CompressionFunctionSet &set, CompressionType type, @@ -83,8 +79,6 @@ vector> DBConfig::GetCompressionFunctions(const P TryLoadCompression(*this, result, CompressionType::COMPRESSION_ALP, physical_type); TryLoadCompression(*this, result, CompressionType::COMPRESSION_ALPRD, physical_type); TryLoadCompression(*this, result, CompressionType::COMPRESSION_FSST, physical_type); - TryLoadCompression(*this, result, CompressionType::COMPRESSION_ZSTD, physical_type); - TryLoadCompression(*this, result, CompressionType::COMPRESSION_ROARING, physical_type); return result; } diff --git a/src/duckdb/src/function/encoding_function.cpp b/src/duckdb/src/function/encoding_function.cpp deleted file mode 100644 index 644652c46..000000000 --- a/src/duckdb/src/function/encoding_function.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "duckdb/function/encoding_function.hpp" -#include "duckdb/main/config.hpp" - -namespace duckdb { - -struct DefaultEncodeMethod { - string name; - encode_t encode_function; - idx_t ratio; - idx_t bytes_per_iteration; -}; - -void DecodeUTF16ToUTF8(const char *source_buffer, idx_t &source_buffer_current_position, const idx_t source_buffer_size, - char *target_buffer, idx_t &target_buffer_current_position, const idx_t target_buffer_size, - char *remaining_bytes_buffer, idx_t &remaining_bytes_size) { - - for (; source_buffer_current_position < source_buffer_size; source_buffer_current_position += 2) { - if (target_buffer_current_position == target_buffer_size) { - // We are done - return; - } - const uint16_t ch = - static_cast(static_cast(source_buffer[source_buffer_current_position]) | - (static_cast(source_buffer[source_buffer_current_position + 1]) << 8)); - if (ch >= 0xD800 && ch <= 0xDFFF) { - throw InvalidInputException("File is not utf-16 encoded"); - } - if (ch <= 0x007F) { - // 1-byte UTF-8 for ASCII characters - target_buffer[target_buffer_current_position++] = static_cast(ch & 0x7F); - } else if (ch <= 0x07FF) { - // 2-byte UTF-8 - target_buffer[target_buffer_current_position++] = static_cast(0xC0 | (ch >> 6)); - if (target_buffer_current_position == target_buffer_size) { - // We are done, but we have to store one byte for the next chunk! - source_buffer_current_position += 2; - remaining_bytes_buffer[0] = static_cast(0x80 | (ch & 0x3F)); - remaining_bytes_size = 1; - return; - } - target_buffer[target_buffer_current_position++] = static_cast(0x80 | (ch & 0x3F)); - } else { - // 3-byte UTF-8 - target_buffer[target_buffer_current_position++] = static_cast(0xE0 | (ch >> 12)); - if (target_buffer_current_position == target_buffer_size) { - // We are done, but we have to store two bytes for the next chunk! - source_buffer_current_position += 2; - remaining_bytes_buffer[0] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - remaining_bytes_buffer[1] = static_cast(0x80 | (ch & 0x3F)); - remaining_bytes_size = 2; - return; - } - target_buffer[target_buffer_current_position++] = static_cast(0x80 | ((ch >> 6) & 0x3F)); - if (target_buffer_current_position == target_buffer_size) { - // We are done, but we have to store one byte for the next chunk! - source_buffer_current_position += 2; - remaining_bytes_buffer[0] = static_cast(0x80 | (ch & 0x3F)); - remaining_bytes_size = 1; - return; - } - target_buffer[target_buffer_current_position++] = static_cast(0x80 | (ch & 0x3F)); - } - } -} - -void DecodeLatin1ToUTF8(const char *source_buffer, idx_t &source_buffer_current_position, - const idx_t source_buffer_size, char *target_buffer, idx_t &target_buffer_current_position, - const idx_t target_buffer_size, char *remaining_bytes_buffer, idx_t &remaining_bytes_size) { - for (; source_buffer_current_position < source_buffer_size; source_buffer_current_position++) { - if (target_buffer_current_position == target_buffer_size) { - // We are done - return; - } - const unsigned char ch = static_cast(source_buffer[source_buffer_current_position]); - if (ch > 0x7F && ch <= 0x9F) { - throw InvalidInputException("File is not latin-1 encoded"); - } - if (ch <= 0x7F) { - // ASCII: 1 byte in UTF-8 - target_buffer[target_buffer_current_position++] = static_cast(ch); - } else { - // Non-ASCII: 2 bytes in UTF-8 - target_buffer[target_buffer_current_position++] = static_cast(0xc2 + (ch > 0xbf)); - if (target_buffer_current_position == target_buffer_size) { - // We are done, but we have to store one byte for the next chunk! - source_buffer_current_position++; - remaining_bytes_buffer[0] = static_cast((ch & 0x3f) + 0x80); - remaining_bytes_size = 1; - return; - } - target_buffer[target_buffer_current_position++] = static_cast((ch & 0x3f) + 0x80); - } - } -} - -void DecodeUTF8(const char *source_buffer, idx_t &source_buffer_current_position, const idx_t source_buffer_size, - char *target_buffer, idx_t &target_buffer_current_position, const idx_t target_buffer_size, - char *remaining_bytes_buffer, idx_t &remaining_bytes_size) { - throw InternalException("Decode UTF8 is not a valid function, and should be verified one level up."); -} - -void EncodingFunctionSet::Initialize(DBConfig &config) { - config.RegisterEncodeFunction({"utf-8", DecodeUTF8, 1, 1}); - config.RegisterEncodeFunction({"latin-1", DecodeLatin1ToUTF8, 2, 1}); - config.RegisterEncodeFunction({"utf-16", DecodeUTF16ToUTF8, 2, 2}); -} - -void DBConfig::RegisterEncodeFunction(const EncodingFunction &function) const { - lock_guard l(encoding_functions->lock); - const auto decode_type = function.GetType(); - if (encoding_functions->functions.find(decode_type) != encoding_functions->functions.end()) { - throw InvalidInputException("Decoding function with name %s already registered", decode_type); - } - encoding_functions->functions[decode_type] = function; -} - -optional_ptr DBConfig::GetEncodeFunction(const string &name) const { - lock_guard l(encoding_functions->lock); - // Check if the function is already loaded into the global compression functions. - if (encoding_functions->functions.find(name) != encoding_functions->functions.end()) { - return &encoding_functions->functions[name]; - } - return nullptr; -} - -vector> DBConfig::GetLoadedEncodedFunctions() const { - lock_guard l(encoding_functions->lock); - vector> result; - for (auto &function : encoding_functions->functions) { - result.push_back(function.second); - } - return result; -} -} // namespace duckdb diff --git a/src/duckdb/src/function/function.cpp b/src/duckdb/src/function/function.cpp index 3307d3c54..9427f445b 100644 --- a/src/duckdb/src/function/function.cpp +++ b/src/duckdb/src/function/function.cpp @@ -2,13 +2,11 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/hash.hpp" -#include "duckdb/function/built_in_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/function/scalar_function.hpp" #include "duckdb/parser/parsed_data/pragma_info.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/main/extension_entries.hpp" namespace duckdb { @@ -74,10 +72,9 @@ bool SimpleNamedParameterFunction::HasNamedParameters() const { BaseScalarFunction::BaseScalarFunction(string name_p, vector arguments_p, LogicalType return_type_p, FunctionStability stability, LogicalType varargs_p, - FunctionNullHandling null_handling, FunctionErrors errors) + FunctionNullHandling null_handling) : SimpleFunction(std::move(name_p), std::move(arguments_p), std::move(varargs_p)), - return_type(std::move(return_type_p)), stability(stability), null_handling(null_handling), errors(errors), - collation_handling(FunctionCollationHandling::PROPAGATE_COLLATIONS) { + return_type(std::move(return_type_p)), stability(stability), null_handling(null_handling) { } BaseScalarFunction::~BaseScalarFunction() { @@ -95,14 +92,22 @@ void BuiltinFunctions::Initialize() { RegisterTableFunctions(); RegisterArrowFunctions(); + RegisterDistributiveAggregates(); + + RegisterCompressedMaterializationFunctions(); + + RegisterGenericFunctions(); + RegisterOperators(); + RegisterSequenceFunctions(); + RegisterStringFunctions(); + RegisterNestedFunctions(); + RegisterPragmaFunctions(); // initialize collations AddCollation("nocase", LowerFun::GetFunction(), true); - AddCollation("noaccent", StripAccentsFun::GetFunction(), true); + AddCollation("noaccent", StripAccentsFun::GetFunction()); AddCollation("nfc", NFCNormalizeFun::GetFunction()); - - RegisterExtensionOverloads(); } hash_t BaseScalarFunction::Hash() const { diff --git a/src/duckdb/src/function/function_binder.cpp b/src/duckdb/src/function/function_binder.cpp index 671441825..6bc8dcfaa 100644 --- a/src/duckdb/src/function/function_binder.cpp +++ b/src/duckdb/src/function/function_binder.cpp @@ -6,19 +6,17 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/aggregate_function.hpp" #include "duckdb/function/cast_rules.hpp" -#include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/parser/parsed_data/create_secret_info.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" namespace duckdb { -FunctionBinder::FunctionBinder(ClientContext &context_p) : binder(nullptr), context(context_p) { -} -FunctionBinder::FunctionBinder(Binder &binder_p) : binder(&binder_p), context(binder_p.context) { +FunctionBinder::FunctionBinder(ClientContext &context) : context(context) { } optional_idx FunctionBinder::BindVarArgsFunctionCost(const SimpleFunction &func, const vector &arguments) { @@ -320,13 +318,24 @@ unique_ptr FunctionBinder::BindScalarFunction(ScalarFunctionCatalogE // found a matching function! auto bound_function = func.functions.GetFunctionByOffset(best_function.GetIndex()); - // If any of the parameters are NULL, the function will just be replaced with a NULL constant. - // We try to give the NULL constant the correct type, but we have to do this without binding the function, - // because functions with DEFAULT_NULL_HANDLING should not have to deal with NULL inputs in their bind code. - // Some functions may have an invalid default return type, as they must be bound to infer the return type. - // In those cases, we default to SQLNULL. - const auto return_type_if_null = - bound_function.return_type.IsComplete() ? bound_function.return_type : LogicalType::SQLNULL; + // If any of the parameters are NULL, the function will just be replaced with a NULL constant + // But this NULL constant needs to have to correct type, because we use LogicalType::SQLNULL for binding macro's + // However, some functions may have an invalid return type, so we default to SQLNULL for those + LogicalType return_type_if_null; + switch (bound_function.return_type.id()) { + case LogicalTypeId::ANY: + case LogicalTypeId::DECIMAL: + case LogicalTypeId::STRUCT: + case LogicalTypeId::LIST: + case LogicalTypeId::MAP: + case LogicalTypeId::UNION: + case LogicalTypeId::ARRAY: + return_type_if_null = LogicalType::SQLNULL; + break; + default: + return_type_if_null = bound_function.return_type; + } + if (bound_function.null_handling == FunctionNullHandling::DEFAULT_NULL_HANDLING) { for (auto &child : children) { if (child->return_type == LogicalTypeId::SQLNULL) { @@ -347,110 +356,22 @@ unique_ptr FunctionBinder::BindScalarFunction(ScalarFunctionCatalogE return BindScalarFunction(bound_function, std::move(children), is_operator, binder); } -bool RequiresCollationPropagation(const LogicalType &type) { - return type.id() == LogicalTypeId::VARCHAR && !type.HasAlias(); -} - -string ExtractCollation(const vector> &children) { - string collation; - for (auto &arg : children) { - if (!RequiresCollationPropagation(arg->return_type)) { - // not a varchar column - continue; - } - auto child_collation = StringType::GetCollation(arg->return_type); - if (collation.empty()) { - collation = child_collation; - } else if (!child_collation.empty() && collation != child_collation) { - throw BinderException("Cannot combine types with different collation!"); - } - } - return collation; -} - -void PropagateCollations(ClientContext &, ScalarFunction &bound_function, vector> &children) { - if (!RequiresCollationPropagation(bound_function.return_type)) { - // we only need to propagate if the function returns a varchar - return; - } - auto collation = ExtractCollation(children); - if (collation.empty()) { - // no collation to propagate - return; - } - // propagate the collation to the return type - auto collation_type = LogicalType::VARCHAR_COLLATION(std::move(collation)); - bound_function.return_type = std::move(collation_type); -} - -void PushCollations(ClientContext &context, ScalarFunction &bound_function, vector> &children, - CollationType type) { - auto collation = ExtractCollation(children); - if (collation.empty()) { - // no collation to push - return; - } - // push collation into the return type if required - auto collation_type = LogicalType::VARCHAR_COLLATION(std::move(collation)); - if (RequiresCollationPropagation(bound_function.return_type)) { - bound_function.return_type = collation_type; - } - // push collations to the children - for (auto &arg : children) { - if (RequiresCollationPropagation(arg->return_type)) { - // if this is a varchar type - propagate the collation - arg->return_type = collation_type; - } - // now push the actual collation handling - ExpressionBinder::PushCollation(context, arg, arg->return_type, type); - } -} - -void HandleCollations(ClientContext &context, ScalarFunction &bound_function, - vector> &children) { - switch (bound_function.collation_handling) { - case FunctionCollationHandling::IGNORE_COLLATIONS: - // explicitly ignoring collation handling - break; - case FunctionCollationHandling::PROPAGATE_COLLATIONS: - PropagateCollations(context, bound_function, children); - break; - case FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS: - // first propagate, then push collations to the children - PushCollations(context, bound_function, children, CollationType::COMBINABLE_COLLATIONS); - break; - default: - throw InternalException("Unrecognized collation handling"); - } -} - unique_ptr FunctionBinder::BindScalarFunction(ScalarFunction bound_function, vector> children, bool is_operator, optional_ptr binder) { unique_ptr bind_info; - if (bound_function.bind) { bind_info = bound_function.bind(context, bound_function, children); - } else if (bound_function.bind_extended) { - if (!binder) { - throw InternalException("Function '%s' has a 'bind_extended' but the FunctionBinder was created without " - "a reference to a Binder", - bound_function.name); - } - ScalarFunctionBindInput bind_input(*binder); - bind_info = bound_function.bind_extended(bind_input, bound_function, children); } - if (bound_function.get_modified_databases && binder) { auto &properties = binder->GetStatementProperties(); FunctionModifiedDatabasesInput input(bind_info, properties); bound_function.get_modified_databases(context, input); } - HandleCollations(context, bound_function, children); - // check if we need to add casts to the children CastToFunctionArguments(bound_function, children); + // now create the function auto return_type = bound_function.return_type; unique_ptr result; auto result_func = make_uniq(std::move(return_type), std::move(bound_function), diff --git a/src/duckdb/src/function/function_list.cpp b/src/duckdb/src/function/function_list.cpp deleted file mode 100644 index 70d869703..000000000 --- a/src/duckdb/src/function/function_list.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "duckdb/function/function_list.hpp" - -#include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/scalar/compressed_materialization_functions.hpp" -#include "duckdb/function/scalar/date_functions.hpp" -#include "duckdb/function/scalar/generic_functions.hpp" -#include "duckdb/function/scalar/list_functions.hpp" -#include "duckdb/function/scalar/map_functions.hpp" -#include "duckdb/function/scalar/operator_functions.hpp" -#include "duckdb/function/scalar/sequence_functions.hpp" -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/function/scalar/struct_functions.hpp" -#include "duckdb/function/scalar/system_functions.hpp" -#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" - -namespace duckdb { - -// Scalar Function -#define DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, _PARAM::GetFunction, nullptr, nullptr, nullptr } -#define DUCKDB_SCALAR_FUNCTION(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_SCALAR_FUNCTION_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) -// Scalar Function Set -#define DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, _PARAM::GetFunctions, nullptr, nullptr } -#define DUCKDB_SCALAR_FUNCTION_SET(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_SCALAR_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_SCALAR_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) -// Aggregate Function -#define DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, _PARAM::GetFunction, nullptr } -#define DUCKDB_AGGREGATE_FUNCTION(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_AGGREGATE_FUNCTION_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_BASE(_PARAM::ALIAS, _PARAM::Name) -// Aggregate Function Set -#define DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _NAME) \ - { _NAME, _PARAM::Parameters, _PARAM::Description, _PARAM::Example, nullptr, nullptr, nullptr, _PARAM::GetFunctions } -#define DUCKDB_AGGREGATE_FUNCTION_SET(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM, _PARAM::Name) -#define DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(_PARAM) DUCKDB_AGGREGATE_FUNCTION_SET_BASE(_PARAM::ALIAS, _PARAM::Name) -#define FINAL_FUNCTION \ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } - -// this list is generated by scripts/generate_functions.py -static const StaticFunctionDefinition function[] = { - DUCKDB_SCALAR_FUNCTION(NotLikeFun), - DUCKDB_SCALAR_FUNCTION(NotILikeFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorModuloFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorMultiplyFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorAddFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorSubtractFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorFloatDivideFun), - DUCKDB_SCALAR_FUNCTION_SET(OperatorIntegerDivideFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUbigintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUintegerFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUsmallintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalCompressIntegralUtinyintFun), - DUCKDB_SCALAR_FUNCTION(InternalCompressStringHugeintFun), - DUCKDB_SCALAR_FUNCTION(InternalCompressStringUbigintFun), - DUCKDB_SCALAR_FUNCTION(InternalCompressStringUintegerFun), - DUCKDB_SCALAR_FUNCTION(InternalCompressStringUsmallintFun), - DUCKDB_SCALAR_FUNCTION(InternalCompressStringUtinyintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralBigintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralHugeintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralIntegerFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralSmallintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUbigintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUhugeintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUintegerFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressIntegralUsmallintFun), - DUCKDB_SCALAR_FUNCTION_SET(InternalDecompressStringFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(AddFun), - DUCKDB_AGGREGATE_FUNCTION_SET(AnyValueFun), - DUCKDB_AGGREGATE_FUNCTION_SET_ALIAS(ArbitraryFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayCatFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayConcatFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayContainsFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayExtractFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayHasFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayIndexofFun), - DUCKDB_SCALAR_FUNCTION_SET(ArrayLengthFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayPositionFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayResizeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArraySelectFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayWhereFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayZipFun), - DUCKDB_SCALAR_FUNCTION_SET(BitLengthFun), - DUCKDB_SCALAR_FUNCTION(CombineFun), - DUCKDB_SCALAR_FUNCTION(ConcatFun), - DUCKDB_SCALAR_FUNCTION(ConcatWsFun), - DUCKDB_SCALAR_FUNCTION(ConstantOrNullFun), - DUCKDB_SCALAR_FUNCTION_SET(ContainsFun), - DUCKDB_AGGREGATE_FUNCTION_SET(CountFun), - DUCKDB_AGGREGATE_FUNCTION(CountStarFun), - DUCKDB_SCALAR_FUNCTION(CreateSortKeyFun), - DUCKDB_SCALAR_FUNCTION(CurrvalFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(DivideFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(EndsWithFun), - DUCKDB_SCALAR_FUNCTION(ErrorFun), - DUCKDB_SCALAR_FUNCTION(FinalizeFun), - DUCKDB_AGGREGATE_FUNCTION_SET(FirstFun), - DUCKDB_SCALAR_FUNCTION(GetVariableFun), - DUCKDB_SCALAR_FUNCTION(IlikeEscapeFun), - DUCKDB_AGGREGATE_FUNCTION_SET(LastFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(LcaseFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(LenFun), - DUCKDB_SCALAR_FUNCTION_SET(LengthFun), - DUCKDB_SCALAR_FUNCTION_SET(LengthGraphemeFun), - DUCKDB_SCALAR_FUNCTION(LikeEscapeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListCatFun), - DUCKDB_SCALAR_FUNCTION(ListConcatFun), - DUCKDB_SCALAR_FUNCTION(ListContainsFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ListElementFun), - DUCKDB_SCALAR_FUNCTION_SET(ListExtractFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListHasFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(ListIndexofFun), - DUCKDB_SCALAR_FUNCTION(ListPositionFun), - DUCKDB_SCALAR_FUNCTION_SET(ListResizeFun), - DUCKDB_SCALAR_FUNCTION(ListSelectFun), - DUCKDB_SCALAR_FUNCTION(ListWhereFun), - DUCKDB_SCALAR_FUNCTION(ListZipFun), - DUCKDB_SCALAR_FUNCTION(LowerFun), - DUCKDB_SCALAR_FUNCTION(MapContainsFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MaxFun), - DUCKDB_SCALAR_FUNCTION_SET(MD5Fun), - DUCKDB_SCALAR_FUNCTION_SET(MD5NumberFun), - DUCKDB_AGGREGATE_FUNCTION_SET(MinFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ModFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(MultiplyFun), - DUCKDB_SCALAR_FUNCTION(NextvalFun), - DUCKDB_SCALAR_FUNCTION(NFCNormalizeFun), - DUCKDB_SCALAR_FUNCTION(NotIlikeEscapeFun), - DUCKDB_SCALAR_FUNCTION(NotLikeEscapeFun), - DUCKDB_SCALAR_FUNCTION_SET(OctetLengthFun), - DUCKDB_SCALAR_FUNCTION(PrefixFun), - DUCKDB_SCALAR_FUNCTION(RegexpEscapeFun), - DUCKDB_SCALAR_FUNCTION_SET(RegexpExtractFun), - DUCKDB_SCALAR_FUNCTION_SET(RegexpExtractAllFun), - DUCKDB_SCALAR_FUNCTION_SET(RegexpFun), - DUCKDB_SCALAR_FUNCTION_SET(RegexpMatchesFun), - DUCKDB_SCALAR_FUNCTION_SET(RegexpReplaceFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(RegexpSplitToArrayFun), - DUCKDB_SCALAR_FUNCTION(RowFun), - DUCKDB_SCALAR_FUNCTION_SET(SHA1Fun), - DUCKDB_SCALAR_FUNCTION_SET(SHA256Fun), - DUCKDB_SCALAR_FUNCTION_ALIAS(SplitFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StrSplitFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(StrSplitRegexFun), - DUCKDB_SCALAR_FUNCTION_SET(StrfTimeFun), - DUCKDB_SCALAR_FUNCTION(StringSplitFun), - DUCKDB_SCALAR_FUNCTION_SET(StringSplitRegexFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(StringToArrayFun), - DUCKDB_SCALAR_FUNCTION(StripAccentsFun), - DUCKDB_SCALAR_FUNCTION(StrlenFun), - DUCKDB_SCALAR_FUNCTION_SET(StrpTimeFun), - DUCKDB_SCALAR_FUNCTION(StructConcatFun), - DUCKDB_SCALAR_FUNCTION_SET(StructExtractFun), - DUCKDB_SCALAR_FUNCTION_SET(StructExtractAtFun), - DUCKDB_SCALAR_FUNCTION(StructPackFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(SubstrFun), - DUCKDB_SCALAR_FUNCTION_SET(SubstringFun), - DUCKDB_SCALAR_FUNCTION_SET(SubstringGraphemeFun), - DUCKDB_SCALAR_FUNCTION_SET_ALIAS(SubtractFun), - DUCKDB_SCALAR_FUNCTION(SuffixFun), - DUCKDB_SCALAR_FUNCTION_SET(TryStrpTimeFun), - DUCKDB_SCALAR_FUNCTION_ALIAS(UcaseFun), - DUCKDB_SCALAR_FUNCTION(UpperFun), - DUCKDB_SCALAR_FUNCTION(ConcatOperatorFun), - DUCKDB_SCALAR_FUNCTION(LikeFun), - DUCKDB_SCALAR_FUNCTION(ILikeFun), - DUCKDB_SCALAR_FUNCTION(GlobPatternFun), - FINAL_FUNCTION -}; - -const StaticFunctionDefinition *FunctionList::GetInternalFunctionList() { - return function; -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/macro_function.cpp b/src/duckdb/src/function/macro_function.cpp index d70150c88..cb9313b04 100644 --- a/src/duckdb/src/function/macro_function.cpp +++ b/src/duckdb/src/function/macro_function.cpp @@ -43,12 +43,12 @@ MacroBindResult MacroFunction::BindMacroFunction(const vector> &defaults) { // separate positional and default arguments for (auto &arg : function_expr.children) { - if (!arg->GetAlias().empty()) { + if (!arg->alias.empty()) { // default argument - if (defaults.count(arg->GetAlias())) { - return MacroBindResult(StringUtil::Format("Duplicate default parameters %s!", arg->GetAlias())); + if (defaults.count(arg->alias)) { + return MacroBindResult(StringUtil::Format("Duplicate default parameters %s!", arg->alias)); } - defaults[arg->GetAlias()] = std::move(arg); + defaults[arg->alias] = std::move(arg); } else if (!defaults.empty()) { return MacroBindResult("Positional parameters cannot come after parameters with a default value!"); } else { diff --git a/src/duckdb/src/function/pragma/pragma_functions.cpp b/src/duckdb/src/function/pragma/pragma_functions.cpp index 635828066..3e82bfb7c 100644 --- a/src/duckdb/src/function/pragma/pragma_functions.cpp +++ b/src/duckdb/src/function/pragma/pragma_functions.cpp @@ -99,9 +99,11 @@ static void PragmaDisableForceParallelism(ClientContext &context, const Function } static void PragmaEnableObjectCache(ClientContext &context, const FunctionParameters ¶meters) { + DBConfig::GetConfig(context).options.object_cache_enable = true; } static void PragmaDisableObjectCache(ClientContext &context, const FunctionParameters ¶meters) { + DBConfig::GetConfig(context).options.object_cache_enable = false; } static void PragmaEnableCheckpointOnShutdown(ClientContext &context, const FunctionParameters ¶meters) { diff --git a/src/duckdb/src/function/pragma/pragma_queries.cpp b/src/duckdb/src/function/pragma/pragma_queries.cpp index 66dd6ace7..39db1f12a 100644 --- a/src/duckdb/src/function/pragma/pragma_queries.cpp +++ b/src/duckdb/src/function/pragma/pragma_queries.cpp @@ -138,6 +138,10 @@ string PragmaPlatform(ClientContext &context, const FunctionParameters ¶mete } string PragmaImportDatabase(ClientContext &context, const FunctionParameters ¶meters) { + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("Import is disabled through configuration"); + } auto &fs = FileSystem::GetFileSystem(context); string final_query; diff --git a/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp b/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp index 78410a59f..e431ae406 100644 --- a/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp +++ b/src/duckdb/src/function/scalar/compressed_materialization/compress_integral.cpp @@ -3,7 +3,6 @@ #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/function/function_set.hpp" #include "duckdb/function/scalar/compressed_materialization_functions.hpp" -#include "duckdb/function/scalar/compressed_materialization_utils.hpp" namespace duckdb { @@ -41,12 +40,9 @@ static void IntegralCompressFunction(DataChunk &args, ExpressionState &state, Ve D_ASSERT(args.ColumnCount() == 2); D_ASSERT(args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR); const auto min_val = ConstantVector::GetData(args.data[1])[0]; - UnaryExecutor::Execute( - args.data[0], result, args.size(), - [&](const INPUT_TYPE &input) { - return TemplatedIntegralCompress::Operation(input, min_val); - }, - FunctionErrors::CANNOT_ERROR); + UnaryExecutor::Execute(args.data[0], result, args.size(), [&](const INPUT_TYPE &input) { + return TemplatedIntegralCompress::Operation(input, min_val); + }); } template @@ -127,12 +123,9 @@ static void IntegralDecompressFunction(DataChunk &args, ExpressionState &state, D_ASSERT(args.data[1].GetVectorType() == VectorType::CONSTANT_VECTOR); D_ASSERT(args.data[1].GetType() == result.GetType()); const auto min_val = ConstantVector::GetData(args.data[1])[0]; - UnaryExecutor::Execute( - args.data[0], result, args.size(), - [&](const INPUT_TYPE &input) { - return TemplatedIntegralDecompress::Operation(input, min_val); - }, - FunctionErrors::CANNOT_ERROR); + UnaryExecutor::Execute(args.data[0], result, args.size(), [&](const INPUT_TYPE &input) { + return TemplatedIntegralDecompress::Operation(input, min_val); + }); } template @@ -197,7 +190,8 @@ unique_ptr CMIntegralDeserialize(Deserializer &deserializer, Scala ScalarFunction CMIntegralCompressFun::GetFunction(const LogicalType &input_type, const LogicalType &result_type) { ScalarFunction result(IntegralCompressFunctionName(result_type), {input_type, input_type}, result_type, - GetIntegralCompressFunctionInputSwitch(input_type, result_type), CMUtils::Bind); + GetIntegralCompressFunctionInputSwitch(input_type, result_type), + CompressedMaterializationFunctions::Bind); result.serialize = CMIntegralSerialize; result.deserialize = CMIntegralDeserialize; return result; @@ -213,9 +207,16 @@ static ScalarFunctionSet GetIntegralCompressFunctionSet(const LogicalType &resul return set; } +void CMIntegralCompressFun::RegisterFunction(BuiltinFunctions &set) { + for (const auto &result_type : CompressedMaterializationFunctions::IntegralTypes()) { + set.AddFunction(GetIntegralCompressFunctionSet(result_type)); + } +} + ScalarFunction CMIntegralDecompressFun::GetFunction(const LogicalType &input_type, const LogicalType &result_type) { ScalarFunction result(IntegralDecompressFunctionName(result_type), {input_type, result_type}, result_type, - GetIntegralDecompressFunctionInputSwitch(input_type, result_type), CMUtils::Bind); + GetIntegralDecompressFunctionInputSwitch(input_type, result_type), + CompressedMaterializationFunctions::Bind); result.serialize = CMIntegralSerialize; result.deserialize = CMIntegralDeserialize; return result; @@ -223,7 +224,7 @@ ScalarFunction CMIntegralDecompressFun::GetFunction(const LogicalType &input_typ static ScalarFunctionSet GetIntegralDecompressFunctionSet(const LogicalType &result_type) { ScalarFunctionSet set(IntegralDecompressFunctionName(result_type)); - for (const auto &input_type : CMUtils::IntegralTypes()) { + for (const auto &input_type : CompressedMaterializationFunctions::IntegralTypes()) { if (GetTypeIdSize(result_type.InternalType()) > GetTypeIdSize(input_type.InternalType())) { set.AddFunction(CMIntegralDecompressFun::GetFunction(input_type, result_type)); } @@ -231,52 +232,12 @@ static ScalarFunctionSet GetIntegralDecompressFunctionSet(const LogicalType &res return set; } -ScalarFunctionSet InternalCompressIntegralUtinyintFun::GetFunctions() { - return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UTINYINT)); -} - -ScalarFunctionSet InternalCompressIntegralUsmallintFun::GetFunctions() { - return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::USMALLINT)); -} - -ScalarFunctionSet InternalCompressIntegralUintegerFun::GetFunctions() { - return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UINTEGER)); -} - -ScalarFunctionSet InternalCompressIntegralUbigintFun::GetFunctions() { - return GetIntegralCompressFunctionSet(LogicalType(LogicalTypeId::UBIGINT)); -} - -ScalarFunctionSet InternalDecompressIntegralSmallintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::SMALLINT)); -} - -ScalarFunctionSet InternalDecompressIntegralIntegerFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::INTEGER)); -} - -ScalarFunctionSet InternalDecompressIntegralBigintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::BIGINT)); -} - -ScalarFunctionSet InternalDecompressIntegralHugeintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::HUGEINT)); -} - -ScalarFunctionSet InternalDecompressIntegralUsmallintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::USMALLINT)); -} - -ScalarFunctionSet InternalDecompressIntegralUintegerFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UINTEGER)); -} - -ScalarFunctionSet InternalDecompressIntegralUbigintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UBIGINT)); -} - -ScalarFunctionSet InternalDecompressIntegralUhugeintFun::GetFunctions() { - return GetIntegralDecompressFunctionSet(LogicalType(LogicalTypeId::UHUGEINT)); +void CMIntegralDecompressFun::RegisterFunction(BuiltinFunctions &set) { + for (const auto &result_type : LogicalType::Integral()) { + if (GetTypeIdSize(result_type.InternalType()) > 1) { + set.AddFunction(GetIntegralDecompressFunctionSet(result_type)); + } + } } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp b/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp index d1d0734d1..907b8c455 100644 --- a/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp +++ b/src/duckdb/src/function/scalar/compressed_materialization/compress_string.cpp @@ -1,6 +1,5 @@ #include "duckdb/common/bswap.hpp" #include "duckdb/function/scalar/compressed_materialization_functions.hpp" -#include "duckdb/function/scalar/compressed_materialization_utils.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" @@ -69,8 +68,7 @@ inline uint8_t StringCompress(const string_t &input) { template static void StringCompressFunction(DataChunk &args, ExpressionState &state, Vector &result) { - UnaryExecutor::Execute(args.data[0], result, args.size(), StringCompress, - FunctionErrors::CANNOT_ERROR); + UnaryExecutor::Execute(args.data[0], result, args.size(), StringCompress); } template @@ -163,10 +161,9 @@ template static void StringDecompressFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &allocator = ExecuteFunctionState::GetFunctionState(state)->Cast().allocator; allocator.Reset(); - UnaryExecutor::Execute( - args.data[0], result, args.size(), - [&](const INPUT_TYPE &input) { return StringDecompress(input, allocator); }, - FunctionErrors::CANNOT_ERROR); + UnaryExecutor::Execute(args.data[0], result, args.size(), [&](const INPUT_TYPE &input) { + return StringDecompress(input, allocator); + }); } template @@ -206,12 +203,18 @@ unique_ptr CMStringCompressDeserialize(Deserializer &deserializer, ScalarFunction CMStringCompressFun::GetFunction(const LogicalType &result_type) { ScalarFunction result(StringCompressFunctionName(result_type), {LogicalType::VARCHAR}, result_type, - GetStringCompressFunctionSwitch(result_type), CMUtils::Bind); + GetStringCompressFunctionSwitch(result_type), CompressedMaterializationFunctions::Bind); result.serialize = CMStringCompressSerialize; result.deserialize = CMStringCompressDeserialize; return result; } +void CMStringCompressFun::RegisterFunction(BuiltinFunctions &set) { + for (const auto &result_type : CompressedMaterializationFunctions::StringTypes()) { + set.AddFunction(CMStringCompressFun::GetFunction(result_type)); + } +} + static void CMStringDecompressSerialize(Serializer &serializer, const optional_ptr bind_data, const ScalarFunction &function) { serializer.WriteProperty(100, "arguments", function.arguments); @@ -226,8 +229,8 @@ unique_ptr CMStringDecompressDeserialize(Deserializer &deserialize ScalarFunction CMStringDecompressFun::GetFunction(const LogicalType &input_type) { ScalarFunction result(StringDecompressFunctionName(), {input_type}, LogicalType::VARCHAR, - GetStringDecompressFunctionSwitch(input_type), CMUtils::Bind, nullptr, nullptr, - StringDecompressLocalState::Init); + GetStringDecompressFunctionSwitch(input_type), CompressedMaterializationFunctions::Bind, + nullptr, nullptr, StringDecompressLocalState::Init); result.serialize = CMStringDecompressSerialize; result.deserialize = CMStringDecompressDeserialize; return result; @@ -235,34 +238,14 @@ ScalarFunction CMStringDecompressFun::GetFunction(const LogicalType &input_type) static ScalarFunctionSet GetStringDecompressFunctionSet() { ScalarFunctionSet set(StringDecompressFunctionName()); - for (const auto &input_type : CMUtils::StringTypes()) { + for (const auto &input_type : CompressedMaterializationFunctions::StringTypes()) { set.AddFunction(CMStringDecompressFun::GetFunction(input_type)); } return set; } -ScalarFunction InternalCompressStringUtinyintFun::GetFunction() { - return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UTINYINT)); -} - -ScalarFunction InternalCompressStringUsmallintFun::GetFunction() { - return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::USMALLINT)); -} - -ScalarFunction InternalCompressStringUintegerFun::GetFunction() { - return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UINTEGER)); -} - -ScalarFunction InternalCompressStringUbigintFun::GetFunction() { - return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::UBIGINT)); -} - -ScalarFunction InternalCompressStringHugeintFun::GetFunction() { - return CMStringCompressFun::GetFunction(LogicalType(LogicalTypeId::HUGEINT)); -} - -ScalarFunctionSet InternalDecompressStringFun::GetFunctions() { - return GetStringDecompressFunctionSet(); +void CMStringDecompressFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(GetStringDecompressFunctionSet()); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp b/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp new file mode 100644 index 000000000..456d1bb8a --- /dev/null +++ b/src/duckdb/src/function/scalar/compressed_materialization_functions.cpp @@ -0,0 +1,29 @@ +#include "duckdb/function/scalar/compressed_materialization_functions.hpp" + +namespace duckdb { + +const vector CompressedMaterializationFunctions::IntegralTypes() { + return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT}; +} + +const vector CompressedMaterializationFunctions::StringTypes() { + return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT, + LogicalType::HUGEINT}; +} + +// LCOV_EXCL_START +unique_ptr CompressedMaterializationFunctions::Bind(ClientContext &context, + ScalarFunction &bound_function, + vector> &arguments) { + throw BinderException("Compressed materialization functions are for internal use only!"); +} +// LCOV_EXCL_STOP + +void BuiltinFunctions::RegisterCompressedMaterializationFunctions() { + Register(); + Register(); + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp b/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp deleted file mode 100644 index 2d09a7e7f..000000000 --- a/src/duckdb/src/function/scalar/compressed_materialization_utils.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "duckdb/function/scalar/compressed_materialization_utils.hpp" - -namespace duckdb { - -const vector CMUtils::IntegralTypes() { - return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT}; -} - -const vector CMUtils::StringTypes() { - return {LogicalType::UTINYINT, LogicalType::USMALLINT, LogicalType::UINTEGER, LogicalType::UBIGINT, - LogicalType::HUGEINT}; -} - -// LCOV_EXCL_START -unique_ptr CMUtils::Bind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - throw BinderException("Compressed materialization functions are for internal use only!"); -} -// LCOV_EXCL_STOP - -} // namespace duckdb diff --git a/src/duckdb/extension/core_functions/scalar/generic/binning.cpp b/src/duckdb/src/function/scalar/generic/binning.cpp similarity index 99% rename from src/duckdb/extension/core_functions/scalar/generic/binning.cpp rename to src/duckdb/src/function/scalar/generic/binning.cpp index 83f7c0700..aaa9d19db 100644 --- a/src/duckdb/extension/core_functions/scalar/generic/binning.cpp +++ b/src/duckdb/src/function/scalar/generic/binning.cpp @@ -1,12 +1,12 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/hugeint.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/common/types/date.hpp" #include "duckdb/common/types/time.hpp" #include "duckdb/common/types/timestamp.hpp" #include "duckdb/common/vector_operations/generic_executor.hpp" -#include "core_functions/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" +#include "duckdb/common/operator/subtract.hpp" +#include "duckdb/common/serializer/deserializer.hpp" namespace duckdb { @@ -500,7 +500,6 @@ ScalarFunctionSet EquiWidthBinsFun::GetFunctions() { for (auto &function : functions.functions) { function.serialize = EquiWidthBinSerialize; function.deserialize = EquiWidthBinDeserialize; - BaseScalarFunction::SetReturnsError(function); } return functions; } diff --git a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp index 32b9f855c..05b0ebce6 100644 --- a/src/duckdb/src/function/scalar/generic/constant_or_null.cpp +++ b/src/duckdb/src/function/scalar/generic/constant_or_null.cpp @@ -1,4 +1,3 @@ -#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/execution/expression_executor.hpp" @@ -66,6 +65,10 @@ static void ConstantOrNullFunction(DataChunk &args, ExpressionState &state, Vect } } +ScalarFunction ConstantOrNull::GetFunction(const LogicalType &return_type) { + return ScalarFunction("constant_or_null", {return_type, LogicalType::ANY}, return_type, ConstantOrNullFunction); +} + unique_ptr ConstantOrNull::Bind(Value value) { return make_uniq(std::move(value)); } @@ -94,12 +97,11 @@ unique_ptr ConstantOrNullBind(ClientContext &context, ScalarFuncti return make_uniq(std::move(value)); } -ScalarFunction ConstantOrNullFun::GetFunction() { - auto fun = ScalarFunction("constant_or_null", {LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, - ConstantOrNullFunction); +void ConstantOrNull::RegisterFunction(BuiltinFunctions &set) { + auto fun = ConstantOrNull::GetFunction(LogicalType::ANY); fun.bind = ConstantOrNullBind; fun.varargs = LogicalType::ANY; - return fun; + set.AddFunction(fun); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/generic/getvariable.cpp b/src/duckdb/src/function/scalar/generic/getvariable.cpp index 14d32954d..b46ab60db 100644 --- a/src/duckdb/src/function/scalar/generic/getvariable.cpp +++ b/src/duckdb/src/function/scalar/generic/getvariable.cpp @@ -49,10 +49,10 @@ unique_ptr BindGetVariableExpression(FunctionBindExpressionInput &in return make_uniq(bind_data.value); } -ScalarFunction GetVariableFun::GetFunction() { +void GetVariableFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction getvar("getvariable", {LogicalType::VARCHAR}, LogicalType::ANY, nullptr, GetVariableBind, nullptr); getvar.bind_expression = BindGetVariableExpression; - return getvar; + set.AddFunction(getvar); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/generic_functions.cpp b/src/duckdb/src/function/scalar/generic_functions.cpp new file mode 100644 index 000000000..27330ab1f --- /dev/null +++ b/src/duckdb/src/function/scalar/generic_functions.cpp @@ -0,0 +1,11 @@ +#include "duckdb/function/scalar/generic_functions.hpp" + +namespace duckdb { + +void BuiltinFunctions::RegisterGenericFunctions() { + Register(); + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/contains_or_position.cpp b/src/duckdb/src/function/scalar/list/contains_or_position.cpp index 309d78c39..c10e467b2 100644 --- a/src/duckdb/src/function/scalar/list/contains_or_position.cpp +++ b/src/duckdb/src/function/scalar/list/contains_or_position.cpp @@ -1,4 +1,3 @@ -#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression_binder.hpp" @@ -67,4 +66,11 @@ ScalarFunction ListPositionFun::GetFunction() { ListSearchFunction, ListSearchBind); } +void ListContainsFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"list_contains", "array_contains", "list_has", "array_has"}, GetFunction()); +} + +void ListPositionFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"list_position", "list_indexof", "array_position", "array_indexof"}, GetFunction()); +} } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_extract.cpp b/src/duckdb/src/function/scalar/list/list_extract.cpp index 058ce5f42..37176f23a 100644 --- a/src/duckdb/src/function/scalar/list/list_extract.cpp +++ b/src/duckdb/src/function/scalar/list/list_extract.cpp @@ -4,8 +4,7 @@ #include "duckdb/common/uhugeint.hpp" #include "duckdb/common/vector_operations/binary_executor.hpp" #include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" -#include "duckdb/function/scalar/list_functions.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/parser/expression/bound_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -106,8 +105,9 @@ static void ExecuteListExtract(Vector &result, Vector &list, Vector &offsets, co static void ExecuteStringExtract(Vector &result, Vector &input_vector, Vector &subscript_vector, const idx_t count) { BinaryExecutor::Execute( - input_vector, subscript_vector, result, count, - [&](string_t input_string, int64_t subscript) { return SubstringUnicode(result, input_string, subscript, 1); }); + input_vector, subscript_vector, result, count, [&](string_t input_string, int64_t subscript) { + return SubstringFun::SubstringUnicode(result, input_string, subscript, 1); + }); } static void ListExtractFunction(DataChunk &args, ExpressionState &state, Vector &result) { @@ -156,35 +156,29 @@ static unique_ptr ListExtractStats(ClientContext &context, Funct return child_copy.ToUnique(); } -ScalarFunctionSet ListExtractFun::GetFunctions() { - ScalarFunctionSet list_extract_set("list_extract"); - - // the arguments and return types are actually set in the binder function - ScalarFunction lfun({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::ANY, - ListExtractFunction, ListExtractBind, nullptr, ListExtractStats); - - ScalarFunction sfun({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, ListExtractFunction); - BaseScalarFunction::SetReturnsError(lfun); - BaseScalarFunction::SetReturnsError(sfun); - list_extract_set.AddFunction(lfun); - list_extract_set.AddFunction(sfun); - return list_extract_set; -} - -ScalarFunctionSet ArrayExtractFun::GetFunctions() { - ScalarFunctionSet array_extract_set("array_extract"); - +void ListExtractFun::RegisterFunction(BuiltinFunctions &set) { // the arguments and return types are actually set in the binder function ScalarFunction lfun({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::ANY, ListExtractFunction, ListExtractBind, nullptr, ListExtractStats); ScalarFunction sfun({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, ListExtractFunction); - array_extract_set.AddFunction(lfun); - array_extract_set.AddFunction(sfun); - array_extract_set.AddFunction(GetKeyExtractFunction()); - array_extract_set.AddFunction(GetIndexExtractFunction()); - return array_extract_set; + ScalarFunctionSet list_extract("list_extract"); + list_extract.AddFunction(lfun); + list_extract.AddFunction(sfun); + set.AddFunction(list_extract); + + ScalarFunctionSet list_element("list_element"); + list_element.AddFunction(lfun); + list_element.AddFunction(sfun); + set.AddFunction(list_element); + + ScalarFunctionSet array_extract("array_extract"); + array_extract.AddFunction(lfun); + array_extract.AddFunction(sfun); + array_extract.AddFunction(StructExtractFun::KeyExtractFunction()); + array_extract.AddFunction(StructExtractFun::IndexExtractFunction()); + set.AddFunction(array_extract); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_resize.cpp b/src/duckdb/src/function/scalar/list/list_resize.cpp index 019dfcc72..86d21fd58 100644 --- a/src/duckdb/src/function/scalar/list/list_resize.cpp +++ b/src/duckdb/src/function/scalar/list/list_resize.cpp @@ -1,6 +1,5 @@ #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar_function.hpp" #include "duckdb/function/built_in_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" @@ -155,19 +154,24 @@ static unique_ptr ListResizeBind(ClientContext &context, ScalarFun return make_uniq(bound_function.return_type); } -ScalarFunctionSet ListResizeFun::GetFunctions() { +void ListResizeFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction simple_fun({LogicalType::LIST(LogicalTypeId::ANY), LogicalTypeId::ANY}, LogicalType::LIST(LogicalTypeId::ANY), ListResizeFunction, ListResizeBind); simple_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(simple_fun); + ScalarFunction default_value_fun({LogicalType::LIST(LogicalTypeId::ANY), LogicalTypeId::ANY, LogicalTypeId::ANY}, LogicalType::LIST(LogicalTypeId::ANY), ListResizeFunction, ListResizeBind); default_value_fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - BaseScalarFunction::SetReturnsError(default_value_fun); - ScalarFunctionSet list_resize_set("list_resize"); - list_resize_set.AddFunction(simple_fun); - list_resize_set.AddFunction(default_value_fun); - return list_resize_set; + + ScalarFunctionSet list_resize("list_resize"); + list_resize.AddFunction(simple_fun); + list_resize.AddFunction(default_value_fun); + set.AddFunction(list_resize); + + ScalarFunctionSet array_resize("array_resize"); + array_resize.AddFunction(simple_fun); + array_resize.AddFunction(default_value_fun); + set.AddFunction(array_resize); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_select.cpp b/src/duckdb/src/function/scalar/list/list_select.cpp index 55c6a9f1d..07413977b 100644 --- a/src/duckdb/src/function/scalar/list/list_select.cpp +++ b/src/duckdb/src/function/scalar/list/list_select.cpp @@ -4,7 +4,6 @@ #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/function/scalar/list_functions.hpp" namespace duckdb { @@ -180,4 +179,8 @@ ScalarFunction ListSelectFun::GetFunction() { return fun; } +void ListSelectFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"list_select", "array_select"}, ListSelectFun::GetFunction()); + set.AddFunction({"list_where", "array_where"}, ListWhereFun::GetFunction()); +} } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/list/list_zip.cpp b/src/duckdb/src/function/scalar/list/list_zip.cpp index ef39a989d..6e24689cf 100644 --- a/src/duckdb/src/function/scalar/list/list_zip.cpp +++ b/src/duckdb/src/function/scalar/list/list_zip.cpp @@ -1,5 +1,4 @@ #include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/function/scalar/list_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression_binder.hpp" @@ -112,7 +111,7 @@ static void ListZipFunction(DataChunk &args, ExpressionState &state, Vector &res offset += len; } for (idx_t child_idx = 0; child_idx < args_size; child_idx++) { - if (args.data[child_idx].GetType() != LogicalType::SQLNULL) { + if (!(args.data[child_idx].GetType() == LogicalType::SQLNULL)) { struct_entries[child_idx]->Slice(ListVector::GetEntry(args.data[child_idx]), selections[child_idx], result_size); } @@ -132,9 +131,7 @@ static unique_ptr ListZipBind(ClientContext &context, ScalarFuncti throw BinderException("Provide at least one argument to " + bound_function.name); } if (arguments[size - 1]->return_type.id() == LogicalTypeId::BOOLEAN) { - if (--size == 0) { - throw BinderException("Provide at least one list argument to " + bound_function.name); - } + size--; } case_insensitive_set_t struct_names; @@ -163,8 +160,11 @@ ScalarFunction ListZipFun::GetFunction() { auto fun = ScalarFunction({}, LogicalType::LIST(LogicalTypeId::STRUCT), ListZipFunction, ListZipBind); fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; // Special handling needed? return fun; } +void ListZipFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"list_zip", "array_zip"}, GetFunction()); +} } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/nested_functions.cpp b/src/duckdb/src/function/scalar/nested_functions.cpp index 2d5359c4e..8685ad4aa 100644 --- a/src/duckdb/src/function/scalar/nested_functions.cpp +++ b/src/duckdb/src/function/scalar/nested_functions.cpp @@ -37,4 +37,15 @@ void MapUtil::ReinterpretMap(Vector &result, Vector &input, idx_t count) { result.SetVectorType(input.GetVectorType()); } +void BuiltinFunctions::RegisterNestedFunctions() { + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/operators.cpp b/src/duckdb/src/function/scalar/operators.cpp new file mode 100644 index 000000000..2862b13c2 --- /dev/null +++ b/src/duckdb/src/function/scalar/operators.cpp @@ -0,0 +1,14 @@ +#include "duckdb/function/scalar/operators.hpp" +#include "duckdb/common/exception.hpp" + +namespace duckdb { + +void BuiltinFunctions::RegisterOperators() { + Register(); + Register(); + Register(); + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/operator/add.cpp b/src/duckdb/src/function/scalar/operators/add.cpp similarity index 99% rename from src/duckdb/src/function/scalar/operator/add.cpp rename to src/duckdb/src/function/scalar/operators/add.cpp index fa2f1a9e7..f3b86d527 100644 --- a/src/duckdb/src/function/scalar/operator/add.cpp +++ b/src/duckdb/src/function/scalar/operators/add.cpp @@ -90,8 +90,7 @@ template <> timestamp_t AddOperator::Operation(date_t left, interval_t right) { if (left == date_t::infinity()) { return timestamp_t::infinity(); - } - if (left == date_t::ninfinity()) { + } else if (left == date_t::ninfinity()) { return timestamp_t::ninfinity(); } return Interval::Add(Timestamp::FromDatetime(left, dtime_t(0)), right); diff --git a/src/duckdb/src/function/scalar/operator/arithmetic.cpp b/src/duckdb/src/function/scalar/operators/arithmetic.cpp similarity index 75% rename from src/duckdb/src/function/scalar/operator/arithmetic.cpp rename to src/duckdb/src/function/scalar/operators/arithmetic.cpp index a3c11ed63..037897830 100644 --- a/src/duckdb/src/function/scalar/operator/arithmetic.cpp +++ b/src/duckdb/src/function/scalar/operators/arithmetic.cpp @@ -12,7 +12,6 @@ #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/function/scalar/operators.hpp" -#include "duckdb/function/scalar/operator_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -299,7 +298,7 @@ unique_ptr NopDecimalBind(ClientContext &context, ScalarFunction & return nullptr; } -ScalarFunction AddFunction::GetFunction(const LogicalType &type) { +ScalarFunction AddFun::GetFunction(const LogicalType &type) { D_ASSERT(type.IsNumeric()); if (type.id() == LogicalTypeId::DECIMAL) { return ScalarFunction("+", {type}, type, ScalarFunction::NopFunction, NopDecimalBind); @@ -308,173 +307,138 @@ ScalarFunction AddFunction::GetFunction(const LogicalType &type) { } } -ScalarFunction AddFunction::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { +ScalarFunction AddFun::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { if (left_type.IsNumeric() && left_type.id() == right_type.id()) { if (left_type.id() == LogicalTypeId::DECIMAL) { auto function = ScalarFunction("+", {left_type, right_type}, left_type, nullptr, BindDecimalAddSubtract); - BaseScalarFunction::SetReturnsError(function); function.serialize = SerializeDecimalArithmetic; function.deserialize = DeserializeDecimalArithmetic; return function; } else if (left_type.IsIntegral()) { - ScalarFunction function("+", {left_type, right_type}, left_type, - GetScalarIntegerFunction(left_type.InternalType()), - nullptr, nullptr, - PropagateNumericStats); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, left_type, + GetScalarIntegerFunction(left_type.InternalType()), nullptr, + nullptr, PropagateNumericStats); } else { - ScalarFunction function("+", {left_type, right_type}, left_type, - GetScalarBinaryFunction(left_type.InternalType())); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, left_type, + GetScalarBinaryFunction(left_type.InternalType())); } } switch (left_type.id()) { case LogicalTypeId::DATE: if (right_type.id() == LogicalTypeId::INTEGER) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::DATE, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::DATE, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::TIME) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::TIME_TZ) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP_TZ, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP_TZ, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::INTEGER: if (right_type.id() == LogicalTypeId::DATE) { - ScalarFunction function("+", {left_type, right_type}, right_type, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, right_type, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::INTERVAL: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::INTERVAL, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::INTERVAL, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::DATE) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - BaseScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::TIME) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIME, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIME, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::TIME_TZ) { - ScalarFunction function( - "+", {left_type, right_type}, LogicalType::TIME_TZ, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIME_TZ, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::TIMESTAMP) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIME: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIME, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIME, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::DATE) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIME_TZ: if (right_type.id() == LogicalTypeId::DATE) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP_TZ, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP_TZ, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function( - "+", {left_type, right_type}, LogicalType::TIME_TZ, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIME_TZ, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIMESTAMP: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("+", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("+", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } break; default: break; } // LCOV_EXCL_START - throw NotImplementedException("AddFunction for types %s, %s", EnumUtil::ToString(left_type.id()), + throw NotImplementedException("AddFun for types %s, %s", EnumUtil::ToString(left_type.id()), EnumUtil::ToString(right_type.id())); // LCOV_EXCL_STOP } -ScalarFunctionSet OperatorAddFun::GetFunctions() { - ScalarFunctionSet add("+"); +void AddFun::RegisterFunction(BuiltinFunctions &set) { + ScalarFunctionSet functions("+"); for (auto &type : LogicalType::Numeric()) { // unary add function is a nop, but only exists for numeric types - add.AddFunction(AddFunction::GetFunction(type)); + functions.AddFunction(GetFunction(type)); // binary add function adds two numbers together - add.AddFunction(AddFunction::GetFunction(type, type)); + functions.AddFunction(GetFunction(type, type)); } // we can add integers to dates - add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::INTEGER)); - add.AddFunction(AddFunction::GetFunction(LogicalType::INTEGER, LogicalType::DATE)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTEGER)); + functions.AddFunction(GetFunction(LogicalType::INTEGER, LogicalType::DATE)); // we can add intervals together - add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); // we can add intervals to dates/times/timestamps - add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); - add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::DATE)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::DATE)); - add.AddFunction(AddFunction::GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); - add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIME)); + functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIME)); - add.AddFunction(AddFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); - add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP)); + functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIMESTAMP)); - add.AddFunction(AddFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); - add.AddFunction(AddFunction::GetFunction(LogicalType::INTERVAL, LogicalType::TIME_TZ)); + functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::TIME_TZ)); // we can add times to dates - add.AddFunction(AddFunction::GetFunction(LogicalType::TIME, LogicalType::DATE)); - add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::TIME)); + functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::DATE)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::TIME)); // we can add times with time zones (offsets) to dates - add.AddFunction(AddFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::DATE)); - add.AddFunction(AddFunction::GetFunction(LogicalType::DATE, LogicalType::TIME_TZ)); + functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::DATE)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::TIME_TZ)); // we can add lists together - add.AddFunction(ListConcatFun::GetFunction()); + functions.AddFunction(ListConcatFun::GetFunction()); + + set.AddFunction(functions); - return add; + functions.name = "add"; + set.AddFunction(functions); } //===--------------------------------------------------------------------===// @@ -614,107 +578,81 @@ static unique_ptr NegateBindStatistics(ClientContext &context, F return stats.ToUnique(); } -ScalarFunction SubtractFunction::GetFunction(const LogicalType &type) { +ScalarFunction SubtractFun::GetFunction(const LogicalType &type) { if (type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction func("-", {type}, type, ScalarFunction::UnaryFunction); - ScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction("-", {type}, type, ScalarFunction::UnaryFunction); } else if (type.id() == LogicalTypeId::DECIMAL) { - ScalarFunction func("-", {type}, type, nullptr, DecimalNegateBind, nullptr, NegateBindStatistics); - return func; + return ScalarFunction("-", {type}, type, nullptr, DecimalNegateBind, nullptr, NegateBindStatistics); } else { D_ASSERT(type.IsNumeric()); - ScalarFunction func("-", {type}, type, ScalarFunction::GetScalarUnaryFunction(type), nullptr, - nullptr, NegateBindStatistics); - ScalarFunction::SetReturnsError(func); - return func; + return ScalarFunction("-", {type}, type, ScalarFunction::GetScalarUnaryFunction(type), nullptr, + nullptr, NegateBindStatistics); } } -ScalarFunction SubtractFunction::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { +ScalarFunction SubtractFun::GetFunction(const LogicalType &left_type, const LogicalType &right_type) { if (left_type.IsNumeric() && left_type.id() == right_type.id()) { if (left_type.id() == LogicalTypeId::DECIMAL) { - ScalarFunction function("-", {left_type, right_type}, left_type, nullptr, - BindDecimalAddSubtract); - ScalarFunction::SetReturnsError(function); + auto function = + ScalarFunction("-", {left_type, right_type}, left_type, nullptr, + BindDecimalAddSubtract); function.serialize = SerializeDecimalArithmetic; function.deserialize = DeserializeDecimalArithmetic; return function; } else if (left_type.IsIntegral()) { - ScalarFunction function( + return ScalarFunction( "-", {left_type, right_type}, left_type, GetScalarIntegerFunction(left_type.InternalType()), nullptr, nullptr, PropagateNumericStats); - ScalarFunction::SetReturnsError(function); - return function; } else { - ScalarFunction function("-", {left_type, right_type}, left_type, - GetScalarBinaryFunction(left_type.InternalType())); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, left_type, + GetScalarBinaryFunction(left_type.InternalType())); } } switch (left_type.id()) { case LogicalTypeId::DATE: if (right_type.id() == LogicalTypeId::DATE) { - ScalarFunction function("-", {left_type, right_type}, LogicalType::BIGINT, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, LogicalType::BIGINT, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::INTEGER) { - ScalarFunction function("-", {left_type, right_type}, LogicalType::DATE, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, LogicalType::DATE, + ScalarFunction::BinaryFunction); } else if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("-", {left_type, right_type}, LogicalType::TIMESTAMP, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, LogicalType::TIMESTAMP, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIMESTAMP: if (right_type.id() == LogicalTypeId::TIMESTAMP) { - ScalarFunction function( + return ScalarFunction( "-", {left_type, right_type}, LogicalType::INTERVAL, ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; } else if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function( + return ScalarFunction( "-", {left_type, right_type}, LogicalType::TIMESTAMP, ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; } break; case LogicalTypeId::INTERVAL: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function( - "-", {left_type, right_type}, LogicalType::INTERVAL, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, LogicalType::INTERVAL, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIME: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function("-", {left_type, right_type}, LogicalType::TIME, - ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; + return ScalarFunction("-", {left_type, right_type}, LogicalType::TIME, + ScalarFunction::BinaryFunction); } break; case LogicalTypeId::TIME_TZ: if (right_type.id() == LogicalTypeId::INTERVAL) { - ScalarFunction function( + return ScalarFunction( "-", {left_type, right_type}, LogicalType::TIME_TZ, ScalarFunction::BinaryFunction); - ScalarFunction::SetReturnsError(function); - return function; } break; default: @@ -726,31 +664,33 @@ ScalarFunction SubtractFunction::GetFunction(const LogicalType &left_type, const // LCOV_EXCL_STOP } -ScalarFunctionSet OperatorSubtractFun::GetFunctions() { - ScalarFunctionSet subtract("-"); +void SubtractFun::RegisterFunction(BuiltinFunctions &set) { + ScalarFunctionSet functions("-"); for (auto &type : LogicalType::Numeric()) { // unary subtract function, negates the input (i.e. multiplies by -1) - subtract.AddFunction(SubtractFunction::GetFunction(type)); + functions.AddFunction(GetFunction(type)); // binary subtract function "a - b", subtracts b from a - subtract.AddFunction(SubtractFunction::GetFunction(type, type)); + functions.AddFunction(GetFunction(type, type)); } // we can subtract dates from each other - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::DATE)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::DATE)); // we can subtract integers from dates - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::INTEGER)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTEGER)); // we can subtract timestamps from each other - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::TIMESTAMP)); + functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::TIMESTAMP)); // we can subtract intervals from each other - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL, LogicalType::INTERVAL)); // we can subtract intervals from dates/times/timestamps, but not the other way around - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::DATE, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::TIME, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::TIMESTAMP, LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::TIME_TZ, LogicalType::INTERVAL)); // we can negate intervals - subtract.AddFunction(SubtractFunction::GetFunction(LogicalType::INTERVAL)); + functions.AddFunction(GetFunction(LogicalType::INTERVAL)); + set.AddFunction(functions); - return subtract; + functions.name = "subtract"; + set.AddFunction(functions); } //===--------------------------------------------------------------------===// @@ -863,35 +803,34 @@ unique_ptr BindDecimalMultiply(ClientContext &context, ScalarFunct return std::move(bind_data); } -ScalarFunctionSet OperatorMultiplyFun::GetFunctions() { - ScalarFunctionSet multiply("*"); +void MultiplyFun::RegisterFunction(BuiltinFunctions &set) { + ScalarFunctionSet functions("*"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::DECIMAL) { ScalarFunction function({type, type}, type, nullptr, BindDecimalMultiply); function.serialize = SerializeDecimalArithmetic; function.deserialize = DeserializeDecimalArithmetic; - multiply.AddFunction(function); + functions.AddFunction(function); } else if (TypeIsIntegral(type.InternalType())) { - multiply.AddFunction(ScalarFunction( + functions.AddFunction(ScalarFunction( {type, type}, type, GetScalarIntegerFunction(type.InternalType()), nullptr, nullptr, PropagateNumericStats)); } else { - multiply.AddFunction( + functions.AddFunction( ScalarFunction({type, type}, type, GetScalarBinaryFunction(type.InternalType()))); } } - multiply.AddFunction( + functions.AddFunction( ScalarFunction({LogicalType::INTERVAL, LogicalType::BIGINT}, LogicalType::INTERVAL, ScalarFunction::BinaryFunction)); - multiply.AddFunction( + functions.AddFunction( ScalarFunction({LogicalType::BIGINT, LogicalType::INTERVAL}, LogicalType::INTERVAL, ScalarFunction::BinaryFunction)); - for (auto &func : multiply.functions) { - ScalarFunction::SetReturnsError(func); - } + set.AddFunction(functions); - return multiply; + functions.name = "multiply"; + set.AddFunction(functions); } //===--------------------------------------------------------------------===// @@ -1026,7 +965,7 @@ unique_ptr BindBinaryFloatingPoint(ClientContext &context, ScalarF return nullptr; } -ScalarFunctionSet OperatorFloatDivideFun::GetFunctions() { +void DivideFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunctionSet fp_divide("/"); fp_divide.AddFunction(ScalarFunction({LogicalType::FLOAT, LogicalType::FLOAT}, LogicalType::FLOAT, nullptr, BindBinaryFloatingPoint)); @@ -1035,13 +974,8 @@ ScalarFunctionSet OperatorFloatDivideFun::GetFunctions() { fp_divide.AddFunction( ScalarFunction({LogicalType::INTERVAL, LogicalType::BIGINT}, LogicalType::INTERVAL, BinaryScalarFunctionIgnoreZero)); - for (auto &func : fp_divide.functions) { - ScalarFunction::SetReturnsError(func); - } - return fp_divide; -} + set.AddFunction(fp_divide); -ScalarFunctionSet OperatorIntegerDivideFun::GetFunctions() { ScalarFunctionSet full_divide("//"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::DECIMAL) { @@ -1051,10 +985,10 @@ ScalarFunctionSet OperatorIntegerDivideFun::GetFunctions() { ScalarFunction({type, type}, type, GetBinaryFunctionIgnoreZero(type.InternalType()))); } } - for (auto &func : full_divide.functions) { - ScalarFunction::SetReturnsError(func); - } - return full_divide; + set.AddFunction(full_divide); + + full_divide.name = "divide"; + set.AddFunction(full_divide); } //===--------------------------------------------------------------------===// @@ -1097,23 +1031,21 @@ hugeint_t ModuloOperator::Operation(hugeint_t left, hugeint_t right) { return left % right; } -ScalarFunctionSet OperatorModuloFun::GetFunctions() { - ScalarFunctionSet modulo("%"); +void ModFun::RegisterFunction(BuiltinFunctions &set) { + ScalarFunctionSet functions("%"); for (auto &type : LogicalType::Numeric()) { if (type.id() == LogicalTypeId::FLOAT || type.id() == LogicalTypeId::DOUBLE) { - modulo.AddFunction(ScalarFunction({type, type}, type, nullptr, BindBinaryFloatingPoint)); + functions.AddFunction(ScalarFunction({type, type}, type, nullptr, BindBinaryFloatingPoint)); } else if (type.id() == LogicalTypeId::DECIMAL) { - modulo.AddFunction(ScalarFunction({type, type}, type, nullptr, BindDecimalModulo)); + functions.AddFunction(ScalarFunction({type, type}, type, nullptr, BindDecimalModulo)); } else { - modulo.AddFunction( + functions.AddFunction( ScalarFunction({type, type}, type, GetBinaryFunctionIgnoreZero(type.InternalType()))); } } - for (auto &func : modulo.functions) { - ScalarFunction::SetReturnsError(func); - } - - return modulo; + set.AddFunction(functions); + functions.name = "mod"; + set.AddFunction(functions); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/operator/multiply.cpp b/src/duckdb/src/function/scalar/operators/multiply.cpp similarity index 100% rename from src/duckdb/src/function/scalar/operator/multiply.cpp rename to src/duckdb/src/function/scalar/operators/multiply.cpp diff --git a/src/duckdb/src/function/scalar/operator/subtract.cpp b/src/duckdb/src/function/scalar/operators/subtract.cpp similarity index 100% rename from src/duckdb/src/function/scalar/operator/subtract.cpp rename to src/duckdb/src/function/scalar/operators/subtract.cpp diff --git a/src/duckdb/src/function/scalar/sequence/nextval.cpp b/src/duckdb/src/function/scalar/sequence/nextval.cpp index 6738383dc..f25fac67d 100644 --- a/src/duckdb/src/function/scalar/sequence/nextval.cpp +++ b/src/duckdb/src/function/scalar/sequence/nextval.cpp @@ -1,5 +1,4 @@ #include "duckdb/function/scalar/sequence_functions.hpp" -#include "duckdb/function/scalar/sequence_utils.hpp" #include "duckdb/catalog/catalog.hpp" #include "duckdb/catalog/dependency_list.hpp" @@ -29,23 +28,15 @@ struct NextSequenceValueOperator { } }; -SequenceCatalogEntry &BindSequence(Binder &binder, string &catalog, string &schema, const string &name) { +SequenceCatalogEntry &BindSequence(ClientContext &context, string &catalog, string &schema, const string &name) { // fetch the sequence from the catalog - Binder::BindSchemaOrCatalog(binder.context, catalog, schema); - return binder.EntryRetriever() - .GetEntry(CatalogType::SEQUENCE_ENTRY, catalog, schema, name) - ->Cast(); -} - -SequenceCatalogEntry &BindSequenceFromContext(ClientContext &context, string &catalog, string &schema, - const string &name) { Binder::BindSchemaOrCatalog(context, catalog, schema); return Catalog::GetEntry(context, catalog, schema, name); } -SequenceCatalogEntry &BindSequence(Binder &binder, const string &name) { +SequenceCatalogEntry &BindSequence(ClientContext &context, const string &name) { auto qname = QualifiedName::Parse(name); - return BindSequence(binder, qname.catalog, qname.schema, qname.name); + return BindSequence(context, qname.catalog, qname.schema, qname.name); } struct NextValLocalState : public FunctionLocalState { @@ -89,26 +80,30 @@ static void NextValFunction(DataChunk &args, ExpressionState &state, Vector &res } } -static unique_ptr NextValBind(ScalarFunctionBindInput &bind_input, ScalarFunction &, +static unique_ptr NextValBind(ClientContext &context, ScalarFunction &, vector> &arguments) { - if (arguments[0]->HasParameter() || arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } if (!arguments[0]->IsFoldable()) { throw NotImplementedException( "currval/nextval requires a constant sequence - non-constant sequences are no longer supported"); } - auto &binder = bind_input.binder; // parameter to nextval function is a foldable constant // evaluate the constant and perform the catalog lookup already - auto seqname = ExpressionExecutor::EvaluateScalar(binder.context, *arguments[0]); + auto seqname = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); if (seqname.IsNull()) { return nullptr; } - auto &seq = BindSequence(binder, seqname.ToString()); + auto &seq = BindSequence(context, seqname.ToString()); return make_uniq(seq); } +static void NextValDependency(BoundFunctionExpression &expr, LogicalDependencyList &dependencies) { + if (!expr.bind_info) { + return; + } + auto &info = expr.bind_info->Cast(); + dependencies.AddDependency(info.sequence); +} + void Serialize(Serializer &serializer, const optional_ptr bind_data, const ScalarFunction &) { auto &next_val_bind_data = bind_data->Cast(); serializer.WritePropertyWithDefault(100, "sequence_create_info", next_val_bind_data.create_info); @@ -122,7 +117,7 @@ unique_ptr Deserialize(Deserializer &deserializer, ScalarFunction } auto &seq_info = create_info->Cast(); auto &context = deserializer.Get(); - auto &sequence = BindSequenceFromContext(context, seq_info.catalog, seq_info.schema, seq_info.name); + auto &sequence = BindSequence(context, seq_info.catalog, seq_info.schema, seq_info.name); return make_uniq(sequence); } @@ -134,29 +129,25 @@ void NextValModifiedDatabases(ClientContext &context, FunctionModifiedDatabasesI input.properties.RegisterDBModify(seq.sequence.ParentCatalog(), context); } -ScalarFunction NextvalFun::GetFunction() { +void NextvalFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction next_val("nextval", {LogicalType::VARCHAR}, LogicalType::BIGINT, - NextValFunction, nullptr, nullptr); - next_val.bind_extended = NextValBind; + NextValFunction, NextValBind, NextValDependency); next_val.stability = FunctionStability::VOLATILE; next_val.serialize = Serialize; next_val.deserialize = Deserialize; next_val.get_modified_databases = NextValModifiedDatabases; next_val.init_local_state = NextValLocalFunction; - BaseScalarFunction::SetReturnsError(next_val); - return next_val; + set.AddFunction(next_val); } -ScalarFunction CurrvalFun::GetFunction() { +void CurrvalFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunction curr_val("currval", {LogicalType::VARCHAR}, LogicalType::BIGINT, - NextValFunction, nullptr, nullptr); - curr_val.bind_extended = NextValBind; + NextValFunction, NextValBind, NextValDependency); curr_val.stability = FunctionStability::VOLATILE; curr_val.serialize = Serialize; curr_val.deserialize = Deserialize; curr_val.init_local_state = NextValLocalFunction; - BaseScalarFunction::SetReturnsError(curr_val); - return curr_val; + set.AddFunction(curr_val); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/sequence_functions.cpp b/src/duckdb/src/function/scalar/sequence_functions.cpp new file mode 100644 index 000000000..30b0c0659 --- /dev/null +++ b/src/duckdb/src/function/scalar/sequence_functions.cpp @@ -0,0 +1,10 @@ +#include "duckdb/function/scalar/sequence_functions.hpp" + +namespace duckdb { + +void BuiltinFunctions::RegisterSequenceFunctions() { + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/caseconvert.cpp b/src/duckdb/src/function/scalar/string/caseconvert.cpp index d0d850f5a..b6240d062 100644 --- a/src/duckdb/src/function/scalar/string/caseconvert.cpp +++ b/src/duckdb/src/function/scalar/string/caseconvert.cpp @@ -1,8 +1,6 @@ #include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/common/string_util.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/common/vector_operations/unary_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -13,14 +11,41 @@ namespace duckdb { +const uint8_t UpperFun::ASCII_TO_UPPER_MAP[] = { + 0, 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, 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, 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}; +const uint8_t LowerFun::ASCII_TO_LOWER_MAP[] = { + 0, 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, 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, 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}; + template static string_t ASCIICaseConvert(Vector &result, const char *input_data, idx_t input_length) { idx_t output_length = input_length; auto result_str = StringVector::EmptyString(result, output_length); auto result_data = result_str.GetDataWriteable(); for (idx_t i = 0; i < input_length; i++) { - result_data[i] = UnsafeNumericCast(IS_UPPER ? StringUtil::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] - : StringUtil::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); + result_data[i] = UnsafeNumericCast(IS_UPPER ? UpperFun::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] + : LowerFun::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); } result_str.Finalize(); return result_str; @@ -65,19 +90,19 @@ static void CaseConvert(const char *input_data, idx_t input_length, char *result i += UnsafeNumericCast(sz); } else { // ascii - *result_data = UnsafeNumericCast(IS_UPPER ? StringUtil::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] - : StringUtil::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); + *result_data = UnsafeNumericCast(IS_UPPER ? UpperFun::ASCII_TO_UPPER_MAP[uint8_t(input_data[i])] + : LowerFun::ASCII_TO_LOWER_MAP[uint8_t(input_data[i])]); result_data++; i++; } } } -idx_t LowerLength(const char *input_data, idx_t input_length) { +idx_t LowerFun::LowerLength(const char *input_data, idx_t input_length) { return GetResultLength(input_data, input_length); } -void LowerCase(const char *input_data, idx_t input_length, char *result_data) { +void LowerFun::LowerCase(const char *input_data, idx_t input_length, char *result_data) { CaseConvert(input_data, input_length, result_data); } @@ -141,9 +166,14 @@ ScalarFunction LowerFun::GetFunction() { nullptr, CaseConvertPropagateStats); } -ScalarFunction UpperFun::GetFunction() { - return ScalarFunction("upper", {LogicalType::VARCHAR}, LogicalType::VARCHAR, CaseConvertFunction, nullptr, - nullptr, CaseConvertPropagateStats); +void LowerFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"lower", "lcase"}, LowerFun::GetFunction()); +} + +void UpperFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"upper", "ucase"}, + ScalarFunction({LogicalType::VARCHAR}, LogicalType::VARCHAR, CaseConvertFunction, nullptr, + nullptr, CaseConvertPropagateStats)); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/concat.cpp b/src/duckdb/src/function/scalar/string/concat.cpp index a6a495a95..0f1d35099 100644 --- a/src/duckdb/src/function/scalar/string/concat.cpp +++ b/src/duckdb/src/function/scalar/string/concat.cpp @@ -4,7 +4,6 @@ #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/function/scalar/string_functions.hpp" - #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -155,14 +154,14 @@ struct ListConcatInputData { const list_entry_t *input_entries = nullptr; }; -static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector &result, bool is_operator) { +static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto count = args.size(); auto result_entries = FlatVector::GetData(result); vector input_data; for (auto &input : args.data) { - if (!is_operator && input.GetType().id() == LogicalTypeId::SQLNULL) { - // LIST_CONCAT ignores NULL values + if (input.GetType().id() == LogicalTypeId::SQLNULL) { + // ignore NULL values continue; } @@ -178,7 +177,6 @@ static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector & input_data.push_back(std::move(data)); } - auto &result_validity = FlatVector::Validity(result); idx_t offset = 0; for (idx_t i = 0; i < count; i++) { auto &result_entry = result_entries[i]; @@ -187,10 +185,6 @@ static void ListConcatFunction(DataChunk &args, ExpressionState &state, Vector & for (auto &data : input_data) { auto list_index = data.vdata.sel->get_index(i); if (!data.vdata.validity.RowIsValid(list_index)) { - // LIST_CONCAT ignores NULL values, but || does not - if (is_operator) { - result_validity.SetInvalid(i); - } continue; } const auto &list_entry = data.input_entries[list_index]; @@ -211,7 +205,7 @@ static void ConcatFunction(DataChunk &args, ExpressionState &state, Vector &resu auto &func_expr = state.expr.Cast(); auto &info = func_expr.bind_info->Cast(); if (info.return_type.id() == LogicalTypeId::LIST) { - return ListConcatFunction(args, state, result, info.is_operator); + return ListConcatFunction(args, state, result); } else if (info.is_operator) { return ConcatOperator(args, state, result); } @@ -342,26 +336,30 @@ ScalarFunction ListConcatFun::GetFunction() { return fun; } -// the concat operator and concat function have different behavior regarding NULLs -// this is strange but seems consistent with postgresql and mysql -// (sqlite does not support the concat function, only the concat operator) +void ListConcatFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"list_concat", "list_cat", "array_concat", "array_cat"}, GetFunction()); +} + +void ConcatFun::RegisterFunction(BuiltinFunctions &set) { + // the concat operator and concat function have different behavior regarding NULLs + // this is strange but seems consistent with postgresql and mysql + // (sqlite does not support the concat function, only the concat operator) + + // the concat operator behaves as one would expect: any NULL value present results in a NULL + // i.e. NULL || 'hello' = NULL + // the concat function, however, treats NULL values as an empty string + // i.e. concat(NULL, 'hello') = 'hello' -// the concat operator behaves as one would expect: any NULL value present results in a NULL -// i.e. NULL || 'hello' = NULL -// the concat function, however, treats NULL values as an empty string -// i.e. concat(NULL, 'hello') = 'hello' -ScalarFunction ConcatFun::GetFunction() { ScalarFunction concat = ScalarFunction("concat", {LogicalType::ANY}, LogicalType::ANY, ConcatFunction, BindConcatFunction); concat.varargs = LogicalType::ANY; concat.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return concat; -} + set.AddFunction(concat); -ScalarFunction ConcatOperatorFun::GetFunction() { ScalarFunction concat_op = ScalarFunction("||", {LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, ConcatFunction, BindConcatOperator); - return concat_op; + concat.null_handling = FunctionNullHandling::SPECIAL_HANDLING; + set.AddFunction(concat_op); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/concat_ws.cpp b/src/duckdb/src/function/scalar/string/concat_ws.cpp index ebc1e8b3a..7689738c4 100644 --- a/src/duckdb/src/function/scalar/string/concat_ws.cpp +++ b/src/duckdb/src/function/scalar/string/concat_ws.cpp @@ -130,7 +130,7 @@ static unique_ptr BindConcatWSFunction(ClientContext &context, Sca return nullptr; } -ScalarFunction ConcatWsFun::GetFunction() { +void ConcatWSFun::RegisterFunction(BuiltinFunctions &set) { // concat_ws functions similarly to the concat function, except the result is NULL if the separator is NULL // if the separator is not NULL, however, NULL values are counted as empty string // there is one separate rule: there are no separators added between NULL values, @@ -143,7 +143,7 @@ ScalarFunction ConcatWsFun::GetFunction() { LogicalType::VARCHAR, ConcatWSFunction, BindConcatWSFunction); concat_ws.varargs = LogicalType::ANY; concat_ws.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return ScalarFunction(concat_ws); + set.AddFunction(concat_ws); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/contains.cpp b/src/duckdb/src/function/scalar/string/contains.cpp index b34d62c78..f1c3f8dca 100644 --- a/src/duckdb/src/function/scalar/string/contains.cpp +++ b/src/duckdb/src/function/scalar/string/contains.cpp @@ -1,11 +1,10 @@ +#include "duckdb/function/scalar/string_functions.hpp" + #include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/scalar/list_functions.hpp" -#include "duckdb/function/scalar/map_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" - +#include "duckdb/function/scalar/nested_functions.hpp" +#include "duckdb/core_functions/scalar/map_functions.hpp" namespace duckdb { template @@ -100,7 +99,8 @@ idx_t ContainsGeneric(const unsigned char *haystack, idx_t haystack_size, const } } -idx_t FindStrInStr(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, idx_t needle_size) { +idx_t ContainsFun::Find(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, + idx_t needle_size) { D_ASSERT(needle_size > 0); // start off by performing a memchr to find the first character of the auto location = memchr(haystack, needle[0], haystack_size); @@ -133,7 +133,7 @@ idx_t FindStrInStr(const unsigned char *haystack, idx_t haystack_size, const uns } } -idx_t FindStrInStr(const string_t &haystack_s, const string_t &needle_s) { +idx_t ContainsFun::Find(const string_t &haystack_s, const string_t &needle_s) { auto haystack = const_uchar_ptr_cast(haystack_s.GetData()); auto haystack_size = haystack_s.GetSize(); auto needle = const_uchar_ptr_cast(needle_s.GetData()); @@ -142,23 +142,16 @@ idx_t FindStrInStr(const string_t &haystack_s, const string_t &needle_s) { // empty needle: always true return 0; } - return FindStrInStr(haystack, haystack_size, needle, needle_size); + return ContainsFun::Find(haystack, haystack_size, needle, needle_size); } struct ContainsOperator { template static inline TR Operation(TA left, TB right) { - return FindStrInStr(left, right) != DConstants::INVALID_INDEX; + return ContainsFun::Find(left, right) != DConstants::INVALID_INDEX; } }; -ScalarFunction GetStringContains() { - ScalarFunction string_fun("contains", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction); - string_fun.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return string_fun; -} - ScalarFunctionSet ContainsFun::GetFunctions() { auto string_fun = GetStringContains(); auto list_fun = ListContainsFun::GetFunction(); @@ -170,4 +163,14 @@ ScalarFunctionSet ContainsFun::GetFunctions() { return set; } +ScalarFunction ContainsFun::GetStringContains() { + ScalarFunction string_fun("contains", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction); + return string_fun; +} + +void ContainsFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(GetFunctions()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/length.cpp b/src/duckdb/src/function/scalar/string/length.cpp index 538646419..5ad1438cf 100644 --- a/src/duckdb/src/function/scalar/string/length.cpp +++ b/src/duckdb/src/function/scalar/string/length.cpp @@ -1,9 +1,10 @@ -#include "duckdb/common/exception.hpp" +#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/types/bit.hpp" + +#include "duckdb/common/exception.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/scalar/string_common.hpp" -#include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" + #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "utf8proc.hpp" @@ -13,14 +14,14 @@ namespace duckdb { struct StringLengthOperator { template static inline TR Operation(TA input) { - return Length(input); + return LengthFun::Length(input); } }; struct GraphemeCountOperator { template static inline TR Operation(TA input) { - return GraphemeCount(input); + return LengthFun::GraphemeCount(input); } }; @@ -110,14 +111,12 @@ static void ArrayLengthFunction(DataChunk &args, ExpressionState &state, Vector static unique_ptr ArrayOrListLengthBind(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { - if (arguments[0]->HasParameter() || arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { + if (arguments[0]->HasParameter()) { throw ParameterNotResolvedException(); } - - const auto &arg_type = arguments[0]->return_type.id(); - if (arg_type == LogicalTypeId::ARRAY) { + if (arguments[0]->return_type.id() == LogicalTypeId::ARRAY) { bound_function.function = ArrayLengthFunction; - } else if (arg_type == LogicalTypeId::LIST) { + } else if (arguments[0]->return_type.id() == LogicalTypeId::LIST) { bound_function.function = ListLengthFunction; } else { // Unreachable @@ -185,7 +184,7 @@ static void ArrayLengthBinaryFunction(DataChunk &args, ExpressionState &state, V static unique_ptr ArrayOrListLengthBinaryBind(ClientContext &context, ScalarFunction &bound_function, vector> &arguments) { - if (arguments[0]->HasParameter() || arguments[0]->return_type.id() == LogicalTypeId::UNKNOWN) { + if (arguments[0]->HasParameter()) { throw ParameterNotResolvedException(); } auto type = arguments[0]->return_type; @@ -217,60 +216,47 @@ static unique_ptr ArrayOrListLengthBinaryBind(ClientContext &conte } } -ScalarFunctionSet LengthFun::GetFunctions() { +void LengthFun::RegisterFunction(BuiltinFunctions &set) { + ScalarFunction array_length_unary = + ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind); ScalarFunctionSet length("length"); length.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction, nullptr, nullptr, LengthPropagateStats)); length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - length.AddFunction( - ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind)); - return (length); -} + length.AddFunction(array_length_unary); + set.AddFunction(length); + length.name = "len"; + set.AddFunction(length); -ScalarFunctionSet LengthGraphemeFun::GetFunctions() { ScalarFunctionSet length_grapheme("length_grapheme"); length_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction, nullptr, nullptr, LengthPropagateStats)); - return (length_grapheme); -} + set.AddFunction(length_grapheme); -ScalarFunctionSet ArrayLengthFun::GetFunctions() { ScalarFunctionSet array_length("array_length"); - array_length.AddFunction( - ScalarFunction({LogicalType::LIST(LogicalType::ANY)}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBind)); + array_length.AddFunction(array_length_unary); array_length.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::ANY), LogicalType::BIGINT}, LogicalType::BIGINT, nullptr, ArrayOrListLengthBinaryBind)); - for (auto &func : array_length.functions) { - BaseScalarFunction::SetReturnsError(func); - } - return (array_length); -} + set.AddFunction(array_length); -ScalarFunction StrlenFun::GetFunction() { - return ScalarFunction("strlen", {LogicalType::VARCHAR}, LogicalType::BIGINT, - ScalarFunction::UnaryFunction); -} - -ScalarFunctionSet BitLengthFun::GetFunctions() { + set.AddFunction(ScalarFunction("strlen", {LogicalType::VARCHAR}, LogicalType::BIGINT, + ScalarFunction::UnaryFunction)); ScalarFunctionSet bit_length("bit_length"); bit_length.AddFunction(ScalarFunction({LogicalType::VARCHAR}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); bit_length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - return (bit_length); -} - -ScalarFunctionSet OctetLengthFun::GetFunctions() { + set.AddFunction(bit_length); // length for BLOB type ScalarFunctionSet octet_length("octet_length"); octet_length.AddFunction(ScalarFunction({LogicalType::BLOB}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); octet_length.AddFunction(ScalarFunction({LogicalType::BIT}, LogicalType::BIGINT, ScalarFunction::UnaryFunction)); - return (octet_length); + set.AddFunction(octet_length); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/like.cpp b/src/duckdb/src/function/scalar/string/like.cpp index 5e279cf28..b82711787 100644 --- a/src/duckdb/src/function/scalar/string/like.cpp +++ b/src/duckdb/src/function/scalar/string/like.cpp @@ -1,7 +1,5 @@ #include "duckdb/common/exception.hpp" -#include "duckdb/common/string_util.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -12,7 +10,7 @@ namespace duckdb { struct StandardCharacterReader { static void NextCharacter(const char *sdata, idx_t slen, idx_t &sidx) { sidx++; - while (sidx < slen && !IsCharacter(sdata[sidx])) { + while (sidx < slen && !LengthFun::IsCharacter(sdata[sidx])) { sidx++; } } @@ -28,7 +26,7 @@ struct ASCIILCaseReader { } static char Operation(const char *data, idx_t pos) { - return (char)StringUtil::ASCII_TO_LOWER_MAP[(uint8_t)data[pos]]; + return (char)LowerFun::ASCII_TO_LOWER_MAP[(uint8_t)data[pos]]; } }; @@ -118,8 +116,8 @@ struct LikeMatcher : public FunctionData { for (; segment_idx < end_idx; segment_idx++) { auto &segment = segments[segment_idx]; // find the pattern of the current segment - idx_t next_offset = - FindStrInStr(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), segment.pattern.size()); + idx_t next_offset = ContainsFun::Find(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), + segment.pattern.size()); if (next_offset == DConstants::INVALID_INDEX) { // could not find this pattern in the string: no match return false; @@ -143,8 +141,8 @@ struct LikeMatcher : public FunctionData { } else { auto &segment = segments.back(); // find the pattern of the current segment - idx_t next_offset = - FindStrInStr(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), segment.pattern.size()); + idx_t next_offset = ContainsFun::Find(str_data, str_len, const_uchar_ptr_cast(segment.pattern.c_str()), + segment.pattern.size()); return next_offset != DConstants::INVALID_INDEX; } } @@ -207,11 +205,6 @@ static unique_ptr LikeBindFunction(ClientContext &context, ScalarF vector> &arguments) { // pattern is the second argument. If its constant, we can already prepare the pattern and store it for later. D_ASSERT(arguments.size() == 2 || arguments.size() == 3); - for (auto &arg : arguments) { - if (arg->return_type.id() == LogicalTypeId::VARCHAR && !StringType::GetCollation(arg->return_type).empty()) { - return nullptr; - } - } if (arguments[1]->IsFoldable()) { Value pattern_str = ExpressionExecutor::EvaluateScalar(context, *arguments[1]); return LikeMatcher::CreateLikeMatcher(pattern_str.ToString()); @@ -235,7 +228,7 @@ bool LikeOperatorFunction(string_t &s, string_t &pat, char escape) { return LikeOperatorFunction(s.GetData(), s.GetSize(), pat.GetData(), pat.GetSize(), escape); } -bool Glob(const char *string, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark) { +bool LikeFun::Glob(const char *string, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark) { idx_t sidx = 0; idx_t pidx = 0; main_loop : { @@ -257,7 +250,7 @@ main_loop : { } // recursively match the remainder of the pattern for (; sidx < slen; sidx++) { - if (Glob(string + sidx, slen - sidx, pattern + pidx, plen - pidx)) { + if (LikeFun::Glob(string + sidx, slen - sidx, pattern + pidx, plen - pidx)) { return true; } } @@ -409,13 +402,13 @@ bool ILikeOperatorFunction(string_t &str, string_t &pattern, char escape = '\0') auto pat_size = pattern.GetSize(); // lowercase both the str and the pattern - idx_t str_llength = LowerLength(str_data, str_size); + idx_t str_llength = LowerFun::LowerLength(str_data, str_size); auto str_ldata = make_unsafe_uniq_array_uninitialized(str_llength); - LowerCase(str_data, str_size, str_ldata.get()); + LowerFun::LowerCase(str_data, str_size, str_ldata.get()); - idx_t pat_llength = LowerLength(pat_data, pat_size); + idx_t pat_llength = LowerFun::LowerLength(pat_data, pat_size); auto pat_ldata = make_unsafe_uniq_array_uninitialized(pat_llength); - LowerCase(pat_data, pat_size, pat_ldata.get()); + LowerFun::LowerCase(pat_data, pat_size, pat_ldata.get()); string_t str_lcase(str_ldata.get(), UnsafeNumericCast(str_llength)); string_t pat_lcase(pat_ldata.get(), UnsafeNumericCast(pat_llength)); return LikeOperatorFunction(str_lcase, pat_lcase, escape); @@ -475,7 +468,7 @@ struct NotILikeOperatorASCII { struct GlobOperator { template static inline TR Operation(TA str, TB pattern) { - return Glob(str.GetData(), str.GetSize(), pattern.GetData(), pattern.GetSize()); + return LikeFun::Glob(str.GetData(), str.GetSize(), pattern.GetData(), pattern.GetSize()); } }; @@ -517,71 +510,45 @@ static void RegularLikeFunction(DataChunk &input, ExpressionState &state, Vector input.size()); } } - -ScalarFunction NotLikeFun::GetFunction() { - ScalarFunction not_like("!~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - RegularLikeFunction, LikeBindFunction); - not_like.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return not_like; -} - -ScalarFunction GlobPatternFun::GetFunction() { - ScalarFunction glob("~~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction); - glob.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return glob; -} - -ScalarFunction ILikeFun::GetFunction() { - ScalarFunction ilike("~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction, nullptr, nullptr, - ILikePropagateStats); - ilike.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return ilike; -} - -ScalarFunction NotILikeFun::GetFunction() { - ScalarFunction not_ilike("!~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - ScalarFunction::BinaryFunction, nullptr, - nullptr, ILikePropagateStats); - not_ilike.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return not_ilike; +void LikeFun::RegisterFunction(BuiltinFunctions &set) { + // like + set.AddFunction(GetLikeFunction()); + // not like + set.AddFunction(ScalarFunction("!~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + RegularLikeFunction, LikeBindFunction)); + // glob + set.AddFunction(ScalarFunction("~~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction)); + // ilike + set.AddFunction(ScalarFunction("~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction, nullptr, + nullptr, ILikePropagateStats)); + // not ilike + set.AddFunction(ScalarFunction("!~~*", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + ScalarFunction::BinaryFunction, nullptr, + nullptr, ILikePropagateStats)); } -ScalarFunction LikeFun::GetFunction() { - ScalarFunction like("~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, - RegularLikeFunction, LikeBindFunction); - like.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return like; +ScalarFunction LikeFun::GetLikeFunction() { + return ScalarFunction("~~", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, + RegularLikeFunction, LikeBindFunction); } -ScalarFunction NotLikeEscapeFun::GetFunction() { - ScalarFunction not_like_escape("not_like_escape", - {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction); - not_like_escape.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return not_like_escape; +void LikeEscapeFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(GetLikeEscapeFun()); + set.AddFunction({"not_like_escape"}, + ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction)); + + set.AddFunction({"ilike_escape"}, ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction)); + set.AddFunction({"not_ilike_escape"}, + ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction)); } -ScalarFunction IlikeEscapeFun::GetFunction() { - ScalarFunction ilike_escape("ilike_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction); - ilike_escape.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return ilike_escape; +ScalarFunction LikeEscapeFun::GetLikeEscapeFun() { + return ScalarFunction("like_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, + LogicalType::BOOLEAN, LikeEscapeFunction); } - -ScalarFunction NotIlikeEscapeFun::GetFunction() { - ScalarFunction not_ilike_escape("not_ilike_escape", - {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction); - not_ilike_escape.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return not_ilike_escape; -} -ScalarFunction LikeEscapeFun::GetFunction() { - ScalarFunction like_escape("like_escape", {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, - LogicalType::BOOLEAN, LikeEscapeFunction); - like_escape.collation_handling = FunctionCollationHandling::PUSH_COMBINABLE_COLLATIONS; - return like_escape; -} - } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/nfc_normalize.cpp b/src/duckdb/src/function/scalar/string/nfc_normalize.cpp index 92a061494..289843356 100644 --- a/src/duckdb/src/function/scalar/string/nfc_normalize.cpp +++ b/src/duckdb/src/function/scalar/string/nfc_normalize.cpp @@ -1,5 +1,5 @@ -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" + #include "utf8proc_wrapper.hpp" namespace duckdb { @@ -9,7 +9,7 @@ struct NFCNormalizeOperator { static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { auto input_data = input.GetData(); auto input_length = input.GetSize(); - if (IsAscii(input_data, input_length)) { + if (StripAccentsFun::IsAscii(input_data, input_length)) { return input; } auto normalized_str = Utf8Proc::Normalize(input_data, input_length); @@ -31,4 +31,8 @@ ScalarFunction NFCNormalizeFun::GetFunction() { return ScalarFunction("nfc_normalize", {LogicalType::VARCHAR}, LogicalType::VARCHAR, NFCNormalizeFunction); } +void NFCNormalizeFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(NFCNormalizeFun::GetFunction()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/prefix.cpp b/src/duckdb/src/function/scalar/string/prefix.cpp index 2b46610fa..d15c1e02e 100644 --- a/src/duckdb/src/function/scalar/string/prefix.cpp +++ b/src/duckdb/src/function/scalar/string/prefix.cpp @@ -65,4 +65,8 @@ ScalarFunction PrefixFun::GetFunction() { ScalarFunction::BinaryFunction); } +void PrefixFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(GetFunction()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/regexp.cpp b/src/duckdb/src/function/scalar/string/regexp.cpp index 2383e3b57..265e84be7 100644 --- a/src/duckdb/src/function/scalar/string/regexp.cpp +++ b/src/duckdb/src/function/scalar/string/regexp.cpp @@ -382,7 +382,7 @@ static unique_ptr RegexExtractBind(ClientContext &context, ScalarF std::move(group_string)); } -ScalarFunctionSet RegexpFun::GetFunctions() { +void RegexpFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunctionSet regexp_full_match("regexp_full_match"); regexp_full_match.AddFunction( ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, @@ -392,10 +392,7 @@ ScalarFunctionSet RegexpFun::GetFunctions() { ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, RegexpMatchesBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - return (regexp_full_match); -} -ScalarFunctionSet RegexpMatchesFun::GetFunctions() { ScalarFunctionSet regexp_partial_match("regexp_matches"); regexp_partial_match.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, @@ -405,13 +402,7 @@ ScalarFunctionSet RegexpMatchesFun::GetFunctions() { {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::BOOLEAN, RegexpMatchesFunction, RegexpMatchesBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - for (auto &func : regexp_partial_match.functions) { - BaseScalarFunction::SetReturnsError(func); - } - return (regexp_partial_match); -} -ScalarFunctionSet RegexpReplaceFun::GetFunctions() { ScalarFunctionSet regexp_replace("regexp_replace"); regexp_replace.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexReplaceFunction, RegexReplaceBind, nullptr, @@ -419,10 +410,7 @@ ScalarFunctionSet RegexpReplaceFun::GetFunctions() { regexp_replace.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexReplaceFunction, RegexReplaceBind, nullptr, nullptr, RegexInitLocalState)); - return (regexp_replace); -} -ScalarFunctionSet RegexpExtractFun::GetFunctions() { ScalarFunctionSet regexp_extract("regexp_extract"); regexp_extract.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexExtractFunction, RegexExtractBind, nullptr, nullptr, @@ -446,10 +434,7 @@ ScalarFunctionSet RegexpExtractFun::GetFunctions() { {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::LIST(LogicalType::VARCHAR), LogicalType::VARCHAR}, LogicalType::VARCHAR, RegexExtractStructFunction, RegexExtractBind, nullptr, nullptr, RegexInitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - return (regexp_extract); -} -ScalarFunctionSet RegexpExtractAllFun::GetFunctions() { ScalarFunctionSet regexp_extract_all("regexp_extract_all"); regexp_extract_all.AddFunction(ScalarFunction( {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::LIST(LogicalType::VARCHAR), @@ -464,7 +449,12 @@ ScalarFunctionSet RegexpExtractAllFun::GetFunctions() { LogicalType::LIST(LogicalType::VARCHAR), RegexpExtractAll::Execute, RegexpExtractAll::Bind, nullptr, nullptr, RegexpExtractAll::InitLocalState, LogicalType::INVALID, FunctionStability::CONSISTENT, FunctionNullHandling::SPECIAL_HANDLING)); - return (regexp_extract_all); + + set.AddFunction(regexp_full_match); + set.AddFunction(regexp_partial_match); + set.AddFunction(regexp_replace); + set.AddFunction(regexp_extract); + set.AddFunction(regexp_extract_all); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp b/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp index 144dcff03..0e6cfa7dd 100644 --- a/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp +++ b/src/duckdb/src/function/scalar/string/regexp/regexp_extract_all.cpp @@ -1,5 +1,4 @@ #include "duckdb/function/scalar/regexp.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/function/scalar/string_functions.hpp" @@ -37,7 +36,7 @@ bool ExtractAll(duckdb_re2::StringPiece &input, duckdb_re2::RE2 &pattern, idx_t // to avoid an infinite loop // FIXME: support unicode characters consumed++; - while (*startpos + consumed < input.length() && !IsCharacter(input[*startpos + consumed])) { + while (*startpos + consumed < input.length() && !LengthFun::IsCharacter(input[*startpos + consumed])) { consumed++; } } diff --git a/src/duckdb/src/function/scalar/string/strip_accents.cpp b/src/duckdb/src/function/scalar/string/strip_accents.cpp index 2ab7ca497..1883c60f0 100644 --- a/src/duckdb/src/function/scalar/string/strip_accents.cpp +++ b/src/duckdb/src/function/scalar/string/strip_accents.cpp @@ -1,11 +1,10 @@ -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "utf8proc.hpp" namespace duckdb { -bool IsAscii(const char *input, idx_t n) { +bool StripAccentsFun::IsAscii(const char *input, idx_t n) { for (idx_t i = 0; i < n; i++) { if (input[i] & 0x80) { // non-ascii character @@ -18,7 +17,7 @@ bool IsAscii(const char *input, idx_t n) { struct StripAccentsOperator { template static RESULT_TYPE Operation(INPUT_TYPE input, Vector &result) { - if (IsAscii(input.GetData(), input.GetSize())) { + if (StripAccentsFun::IsAscii(input.GetData(), input.GetSize())) { return input; } @@ -42,4 +41,8 @@ ScalarFunction StripAccentsFun::GetFunction() { return ScalarFunction("strip_accents", {LogicalType::VARCHAR}, LogicalType::VARCHAR, StripAccentsFunction); } +void StripAccentsFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(StripAccentsFun::GetFunction()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/substring.cpp b/src/duckdb/src/function/scalar/string/substring.cpp index 58c93624a..f7ff13f34 100644 --- a/src/duckdb/src/function/scalar/string/substring.cpp +++ b/src/duckdb/src/function/scalar/string/substring.cpp @@ -1,4 +1,3 @@ -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/function/scalar/string_functions.hpp" #include "duckdb/common/algorithm.hpp" @@ -95,7 +94,7 @@ string_t SubstringASCII(Vector &result, string_t input, int64_t offset, int64_t return SubstringSlice(result, input_data, start, UnsafeNumericCast(end - start)); } -string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length) { +string_t SubstringFun::SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length) { auto input_data = input.GetData(); auto input_size = input.GetSize(); @@ -130,7 +129,7 @@ string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_ } int64_t current_character = 0; for (idx_t i = input_size; i > 0; i--) { - if (IsCharacter(input_data[i - 1])) { + if (LengthFun::IsCharacter(input_data[i - 1])) { current_character++; if (current_character == start) { start_pos = i; @@ -140,10 +139,10 @@ string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_ } } } - while (!IsCharacter(input_data[start_pos])) { + while (!LengthFun::IsCharacter(input_data[start_pos])) { start_pos++; } - while (end_pos < input_size && !IsCharacter(input_data[end_pos])) { + while (end_pos < input_size && !LengthFun::IsCharacter(input_data[end_pos])) { end_pos++; } @@ -171,7 +170,7 @@ string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_ int64_t current_character = 0; for (idx_t i = 0; i < input_size; i++) { - if (IsCharacter(input_data[i])) { + if (LengthFun::IsCharacter(input_data[i])) { if (current_character == start) { start_pos = i; } else if (current_character == end) { @@ -191,7 +190,7 @@ string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_ UnsafeNumericCast(end_pos - start_pos)); } -string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length) { +string_t SubstringFun::SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length) { auto input_data = input.GetData(); auto input_size = input.GetSize(); @@ -252,13 +251,13 @@ string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64 struct SubstringUnicodeOp { static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringUnicode(result, input, offset, length); + return SubstringFun::SubstringUnicode(result, input, offset, length); } }; struct SubstringGraphemeOp { static string_t Substring(Vector &result, string_t input, int64_t offset, int64_t length) { - return SubstringGrapheme(result, input, offset, length); + return SubstringFun::SubstringGrapheme(result, input, offset, length); } }; @@ -312,7 +311,7 @@ static unique_ptr SubstringPropagateStats(ClientContext &context return nullptr; } -ScalarFunctionSet SubstringFun::GetFunctions() { +void SubstringFun::RegisterFunction(BuiltinFunctions &set) { ScalarFunctionSet substr("substring"); substr.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, @@ -320,10 +319,10 @@ ScalarFunctionSet SubstringFun::GetFunctions() { substr.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, SubstringPropagateStats)); - return (substr); -} + set.AddFunction(substr); + substr.name = "substr"; + set.AddFunction(substr); -ScalarFunctionSet SubstringGraphemeFun::GetFunctions() { ScalarFunctionSet substr_grapheme("substring_grapheme"); substr_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, @@ -331,7 +330,7 @@ ScalarFunctionSet SubstringGraphemeFun::GetFunctions() { substr_grapheme.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, SubstringFunction, nullptr, nullptr, SubstringPropagateStats)); - return (substr_grapheme); + set.AddFunction(substr_grapheme); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string/suffix.cpp b/src/duckdb/src/function/scalar/string/suffix.cpp index 21175f61d..df1484571 100644 --- a/src/duckdb/src/function/scalar/string/suffix.cpp +++ b/src/duckdb/src/function/scalar/string/suffix.cpp @@ -40,4 +40,8 @@ ScalarFunction SuffixFun::GetFunction() { ScalarFunction::BinaryFunction); } +void SuffixFun::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction({"suffix", "ends_with"}, GetFunction()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/string_functions.cpp b/src/duckdb/src/function/scalar/string_functions.cpp new file mode 100644 index 000000000..e3ccbe0af --- /dev/null +++ b/src/duckdb/src/function/scalar/string_functions.cpp @@ -0,0 +1,22 @@ +#include "duckdb/function/scalar/string_functions.hpp" + +namespace duckdb { + +void BuiltinFunctions::RegisterStringFunctions() { + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); +} + +} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/struct/struct_concat.cpp b/src/duckdb/src/function/scalar/struct/struct_concat.cpp deleted file mode 100644 index f5ed780e8..000000000 --- a/src/duckdb/src/function/scalar/struct/struct_concat.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "duckdb/function/scalar/nested_functions.hpp" -#include "duckdb/function/scalar/struct_functions.hpp" -#include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/storage/statistics/struct_stats.hpp" - -namespace duckdb { - -static void StructConcatFunction(DataChunk &args, ExpressionState &state, Vector &result) { - auto &result_cols = StructVector::GetEntries(result); - idx_t offset = 0; - - if (!args.AllConstant()) { - // Unless all arguments are constant, we flatten the input to make sure it's homogeneous - args.Flatten(); - } - - for (auto &arg : args.data) { - const auto &child_cols = StructVector::GetEntries(arg); - for (auto &child_col : child_cols) { - result_cols[offset++]->Reference(*child_col); - } - } - D_ASSERT(offset == result_cols.size()); - - if (args.AllConstant()) { - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } - - result.Verify(args.size()); -} - -static unique_ptr StructConcatBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - - // collect names and deconflict, construct return type - if (arguments.empty()) { - throw InvalidInputException("struct_concat: At least one argument is required"); - } - - child_list_t combined_children; - case_insensitive_set_t name_set; - - bool has_unnamed = false; - - for (idx_t arg_idx = 0; arg_idx < arguments.size(); arg_idx++) { - const auto &arg = arguments[arg_idx]; - - if (arg->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } - - if (arg->return_type.id() != LogicalTypeId::STRUCT) { - throw InvalidInputException("struct_concat: Argument at position \"%d\" is not a STRUCT", arg_idx + 1); - } - - const auto &child_types = StructType::GetChildTypes(arg->return_type); - for (const auto &child : child_types) { - if (!child.first.empty()) { - auto it = name_set.find(child.first); - if (it != name_set.end()) { - if (*it == child.first) { - throw InvalidInputException("struct_concat: Arguments contain duplicate STRUCT entry \"%s\"", - child.first); - } - throw InvalidInputException( - "struct_concat: Arguments contain case-insensitive duplicate STRUCT entry \"%s\" and \"%s\"", - child.first, *it); - } - name_set.insert(child.first); - } else { - has_unnamed = true; - } - combined_children.push_back(child); - } - } - - if (has_unnamed && !name_set.empty()) { - throw InvalidInputException("struct_concat: Cannot mix named and unnamed STRUCTs"); - } - - bound_function.return_type = LogicalType::STRUCT(combined_children); - return nullptr; -} - -unique_ptr StructConcatStats(ClientContext &context, FunctionStatisticsInput &input) { - const auto &expr = input.expr; - - auto &arg_stats = input.child_stats; - auto &arg_exprs = input.expr.children; - - auto struct_stats = StructStats::CreateUnknown(expr.return_type); - idx_t struct_index = 0; - - for (idx_t arg_idx = 0; arg_idx < arg_exprs.size(); arg_idx++) { - auto &arg_stat = arg_stats[arg_idx]; - auto &arg_type = arg_exprs[arg_idx]->return_type; - for (idx_t child_idx = 0; child_idx < StructType::GetChildCount(arg_type); child_idx++) { - auto &child_stat = StructStats::GetChildStats(arg_stat, child_idx); - StructStats::SetChildStats(struct_stats, struct_index++, child_stat); - } - } - return struct_stats.ToUnique(); -} - -ScalarFunction StructConcatFun::GetFunction() { - ScalarFunction fun("struct_concat", {}, LogicalTypeId::STRUCT, StructConcatFunction, StructConcatBind, nullptr, - StructConcatStats); - fun.varargs = LogicalType::ANY; - fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING; - return fun; -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/scalar/struct/struct_extract.cpp b/src/duckdb/src/function/scalar/struct/struct_extract.cpp index 20cc74157..b4ef1c8d6 100644 --- a/src/duckdb/src/function/scalar/struct/struct_extract.cpp +++ b/src/duckdb/src/function/scalar/struct/struct_extract.cpp @@ -1,14 +1,28 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/struct_functions.hpp" #include "duckdb/function/scalar/nested_functions.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/storage/statistics/struct_stats.hpp" -#include "duckdb/function/scalar/struct_utils.hpp" namespace duckdb { +struct StructExtractBindData : public FunctionData { + explicit StructExtractBindData(idx_t index) : index(index) { + } + + idx_t index; + +public: + unique_ptr Copy() const override { + return make_uniq(index); + } + bool Equals(const FunctionData &other_p) const override { + auto &other = other_p.Cast(); + return index == other.index; + } +}; + static void StructExtractFunction(DataChunk &args, ExpressionState &state, Vector &result) { auto &func_expr = state.expr.Cast(); auto &info = func_expr.bind_info->Cast(); @@ -84,12 +98,11 @@ static unique_ptr StructExtractBind(ClientContext &context, Scalar } bound_function.return_type = std::move(return_type); - return GetBindData(key_index); + return StructExtractFun::GetBindData(key_index); } -static unique_ptr StructExtractBindInternal(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments, - bool struct_extract) { +static unique_ptr StructExtractBindIndex(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments) { D_ASSERT(bound_function.arguments.size() == 2); auto &child_type = arguments[0]->return_type; if (child_type.id() == LogicalTypeId::UNKNOWN) { @@ -100,7 +113,7 @@ static unique_ptr StructExtractBindInternal(ClientContext &context if (struct_children.empty()) { throw InternalException("Can't extract something from an empty struct"); } - if (struct_extract && !StructType::IsUnnamed(child_type)) { + if (!StructType::IsUnnamed(child_type)) { throw BinderException( "struct_extract with an integer key can only be used on unnamed structs, use a string key instead"); } @@ -121,17 +134,7 @@ static unique_ptr StructExtractBindInternal(ClientContext &context index, struct_children.size()); } bound_function.return_type = struct_children[NumericCast(index - 1)].second; - return GetBindData(NumericCast(index - 1)); -} - -static unique_ptr StructExtractBindIndex(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return StructExtractBindInternal(context, bound_function, arguments, true); -} - -static unique_ptr StructExtractAtBind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments) { - return StructExtractBindInternal(context, bound_function, arguments, false); + return StructExtractFun::GetBindData(NumericCast(index - 1)); } static unique_ptr PropagateStructExtractStats(ClientContext &context, FunctionStatisticsInput &input) { @@ -143,37 +146,30 @@ static unique_ptr PropagateStructExtractStats(ClientContext &con return struct_child_stats[info.index].ToUnique(); } -unique_ptr GetBindData(idx_t index) { +unique_ptr StructExtractFun::GetBindData(idx_t index) { return make_uniq(index); } -ScalarFunction GetKeyExtractFunction() { +ScalarFunction StructExtractFun::KeyExtractFunction() { return ScalarFunction("struct_extract", {LogicalTypeId::STRUCT, LogicalType::VARCHAR}, LogicalType::ANY, StructExtractFunction, StructExtractBind, nullptr, PropagateStructExtractStats); } -ScalarFunction GetIndexExtractFunction() { +ScalarFunction StructExtractFun::IndexExtractFunction() { return ScalarFunction("struct_extract", {LogicalTypeId::STRUCT, LogicalType::BIGINT}, LogicalType::ANY, StructExtractFunction, StructExtractBindIndex); } -ScalarFunction GetExtractAtFunction() { - return ScalarFunction("struct_extract_at", {LogicalTypeId::STRUCT, LogicalType::BIGINT}, LogicalType::ANY, - StructExtractFunction, StructExtractAtBind); -} - ScalarFunctionSet StructExtractFun::GetFunctions() { - // the arguments and return types are actually set in the binder function - ScalarFunctionSet struct_extract_set("struct_extract"); - struct_extract_set.AddFunction(GetKeyExtractFunction()); - struct_extract_set.AddFunction(GetIndexExtractFunction()); - return struct_extract_set; + ScalarFunctionSet functions("struct_extract"); + functions.AddFunction(KeyExtractFunction()); + functions.AddFunction(IndexExtractFunction()); + return functions; } -ScalarFunctionSet StructExtractAtFun::GetFunctions() { - ScalarFunctionSet struct_extractat_set("struct_extract_at"); - struct_extractat_set.AddFunction(GetExtractAtFunction()); - return struct_extractat_set; +void StructExtractFun::RegisterFunction(BuiltinFunctions &set) { + // the arguments and return types are actually set in the binder function + set.AddFunction(GetFunctions()); } } // namespace duckdb diff --git a/src/duckdb/src/function/scalar/system/aggregate_export.cpp b/src/duckdb/src/function/scalar/system/aggregate_export.cpp index 64fee3e8c..92fea109a 100644 --- a/src/duckdb/src/function/scalar/system/aggregate_export.cpp +++ b/src/duckdb/src/function/scalar/system/aggregate_export.cpp @@ -1,7 +1,5 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/function/function_binder.hpp" -#include "duckdb/function/scalar/generic_common.hpp" -#include "duckdb/function/scalar/system_functions.hpp" #include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/database.hpp" @@ -267,7 +265,7 @@ static void ExportAggregateFinalize(Vector &state, AggregateInputData &aggr_inpu } ExportAggregateFunctionBindData::ExportAggregateFunctionBindData(unique_ptr aggregate_p) { - D_ASSERT(aggregate_p->GetExpressionType() == ExpressionType::BOUND_AGGREGATE); + D_ASSERT(aggregate_p->type == ExpressionType::BOUND_AGGREGATE); aggregate = unique_ptr_cast(std::move(aggregate_p)); } @@ -341,7 +339,7 @@ ExportAggregateFunction::Bind(unique_ptr child_aggrega child_aggregate->aggr_type); } -ScalarFunction FinalizeFun::GetFunction() { +ScalarFunction ExportAggregateFunction::GetFinalize() { auto result = ScalarFunction("finalize", {LogicalTypeId::AGGREGATE_STATE}, LogicalTypeId::INVALID, AggregateStateFinalize, BindAggregateState, nullptr, nullptr, InitFinalizeState); result.null_handling = FunctionNullHandling::SPECIAL_HANDLING; @@ -350,7 +348,7 @@ ScalarFunction FinalizeFun::GetFunction() { return result; } -ScalarFunction CombineFun::GetFunction() { +ScalarFunction ExportAggregateFunction::GetCombine() { auto result = ScalarFunction("combine", {LogicalTypeId::AGGREGATE_STATE, LogicalTypeId::ANY}, LogicalTypeId::AGGREGATE_STATE, AggregateStateCombine, BindAggregateState, nullptr, nullptr, InitCombineState); @@ -360,4 +358,9 @@ ScalarFunction CombineFun::GetFunction() { return result; } +void ExportAggregateFunction::RegisterFunction(BuiltinFunctions &set) { + set.AddFunction(ExportAggregateFunction::GetCombine()); + set.AddFunction(ExportAggregateFunction::GetFinalize()); +} + } // namespace duckdb diff --git a/src/duckdb/src/function/scalar_function.cpp b/src/duckdb/src/function/scalar_function.cpp index a627643fd..75d74cf50 100644 --- a/src/duckdb/src/function/scalar_function.cpp +++ b/src/duckdb/src/function/scalar_function.cpp @@ -10,28 +10,28 @@ ScalarFunctionInfo::~ScalarFunctionInfo() { ScalarFunction::ScalarFunction(string name, vector arguments, LogicalType return_type, scalar_function_t function, bind_scalar_function_t bind, - bind_scalar_function_extended_t bind_extended, function_statistics_t statistics, + dependency_function_t dependency, function_statistics_t statistics, init_local_state_t init_local_state, LogicalType varargs, FunctionStability side_effects, FunctionNullHandling null_handling, bind_lambda_function_t bind_lambda) : BaseScalarFunction(std::move(name), std::move(arguments), std::move(return_type), side_effects, std::move(varargs), null_handling), - function(std::move(function)), bind(bind), bind_extended(bind_extended), init_local_state(init_local_state), + function(std::move(function)), bind(bind), init_local_state(init_local_state), dependency(dependency), statistics(statistics), bind_lambda(bind_lambda), bind_expression(nullptr), get_modified_databases(nullptr), serialize(nullptr), deserialize(nullptr) { } ScalarFunction::ScalarFunction(vector arguments, LogicalType return_type, scalar_function_t function, - bind_scalar_function_t bind, bind_scalar_function_extended_t bind_extended, + bind_scalar_function_t bind, dependency_function_t dependency, function_statistics_t statistics, init_local_state_t init_local_state, LogicalType varargs, FunctionStability side_effects, FunctionNullHandling null_handling, bind_lambda_function_t bind_lambda) - : ScalarFunction(string(), std::move(arguments), std::move(return_type), std::move(function), bind, bind_extended, + : ScalarFunction(string(), std::move(arguments), std::move(return_type), std::move(function), bind, dependency, statistics, init_local_state, std::move(varargs), side_effects, null_handling, bind_lambda) { } bool ScalarFunction::operator==(const ScalarFunction &rhs) const { return name == rhs.name && arguments == rhs.arguments && return_type == rhs.return_type && varargs == rhs.varargs && - bind == rhs.bind && bind_extended == rhs.bind_extended && statistics == rhs.statistics && + bind == rhs.bind && dependency == rhs.dependency && statistics == rhs.statistics && bind_lambda == rhs.bind_lambda; } diff --git a/src/duckdb/src/function/table/arrow.cpp b/src/duckdb/src/function/table/arrow.cpp index 5d719e8f7..634d6d71c 100644 --- a/src/duckdb/src/function/table/arrow.cpp +++ b/src/duckdb/src/function/table/arrow.cpp @@ -59,38 +59,38 @@ static unique_ptr GetArrowExtensionType(const ArrowSchemaMetadata &ex } } // Check for DuckDB canonical extensions - else if (extension_type.IsNonCanonicalType("hugeint")) { + else if (arrow_extension == "duckdb.hugeint") { if (format != "w:16") { std::ostringstream error; - error << "DuckDB hugeint must be a fixed-size binary of 16 bytes (i.e., \'w:16\'). It is incorrectly " + error << "duckdb.hugeint must be a fixed-size binary of 16 bytes (i.e., \'w:16\'). It is incorrectly " "defined as:" << format; return make_uniq(error.str()); } return make_uniq(LogicalType::HUGEINT); - } else if (extension_type.IsNonCanonicalType("uhugeint")) { + } else if (arrow_extension == "duckdb.uhugeint") { if (format != "w:16") { std::ostringstream error; - error << "DuckDB uhugeint must be a fixed-size binary of 16 bytes (i.e., \'w:16\'). It is incorrectly " + error << "duckdb.uhugeint must be a fixed-size binary of 16 bytes (i.e., \'w:16\'). It is incorrectly " "defined as:" << format; return make_uniq(error.str()); } return make_uniq(LogicalType::UHUGEINT); - } else if (extension_type.IsNonCanonicalType("time_tz")) { + } else if (arrow_extension == "duckdb.time_tz") { if (format != "w:8") { std::ostringstream error; - error << "DuckDB time_tz must be a fixed-size binary of 8 bytes (i.e., \'w:8\'). It is incorrectly defined " + error << "duckdb.time_tz must be a fixed-size binary of 8 bytes (i.e., \'w:8\'). It is incorrectly defined " "as:" << format; return make_uniq(error.str()); } return make_uniq(LogicalType::TIME_TZ, make_uniq(ArrowDateTimeType::MICROSECONDS)); - } else if (extension_type.IsNonCanonicalType("bit")) { + } else if (arrow_extension == "duckdb.bit") { if (format != "z" && format != "Z") { std::ostringstream error; - error << "DuckDB bit must be a blob (i.e., \'z\' or \'Z\'). It is incorrectly defined as:" << format; + error << "duckdb.bit must be a blob (i.e., \'z\' or \'Z\'). It is incorrectly defined as:" << format; return make_uniq(error.str()); } else if (format == "z") { auto type_info = make_uniq(ArrowVariableSizeType::NORMAL); @@ -99,10 +99,10 @@ static unique_ptr GetArrowExtensionType(const ArrowSchemaMetadata &ex auto type_info = make_uniq(ArrowVariableSizeType::SUPER_SIZE); return make_uniq(LogicalType::BIT, std::move(type_info)); - } else if (extension_type.IsNonCanonicalType("varint")) { + } else if (arrow_extension == "duckdb.varint") { if (format != "z" && format != "Z") { std::ostringstream error; - error << "DuckDB bit must be a blob (i.e., \'z\'). It is incorrectly defined as:" << format; + error << "duckdb.bit must be a blob (i.e., \'z\'). It is incorrectly defined as:" << format; return make_uniq(error.str()); } unique_ptr type_info; @@ -370,15 +370,6 @@ void ArrowTableFunction::PopulateArrowTableType(ArrowTableType &arrow_table, Arr } } -unique_ptr ArrowTableFunction::ArrowScanBindDumb(ClientContext &context, TableFunctionBindInput &input, - vector &return_types, - vector &names) { - auto bind_data = ArrowScanBind(context, input, return_types, names); - auto &arrow_bind_data = bind_data->Cast(); - arrow_bind_data.projection_pushdown_enabled = false; - return bind_data; -} - unique_ptr ArrowTableFunction::ArrowScanBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { if (input.inputs[0].IsNull() || input.inputs[1].IsNull() || input.inputs[2].IsNull()) { @@ -484,10 +475,7 @@ ArrowTableFunction::ArrowScanInitLocalInternal(ClientContext &context, TableFunc auto result = make_uniq(std::move(current_chunk)); result->column_ids = input.column_ids; result->filters = input.filters.get(); - auto &bind_data = input.bind_data->Cast(); - if (!bind_data.projection_pushdown_enabled) { - result->column_ids.clear(); - } else if (!input.projection_ids.empty()) { + if (!input.projection_ids.empty()) { auto &asgs = global_state_p->Cast(); result->all_columns.Initialize(context, asgs.scanned_types); } @@ -538,13 +526,11 @@ unique_ptr ArrowTableFunction::ArrowScanCardinality(ClientContex return make_uniq(); } -OperatorPartitionData ArrowTableFunction::ArrowGetPartitionData(ClientContext &context, - TableFunctionGetPartitionInput &input) { - if (input.partition_info.RequiresPartitionColumns()) { - throw InternalException("ArrowTableFunction::GetPartitionData: partition columns not supported"); - } - auto &state = input.local_state->Cast(); - return OperatorPartitionData(state.batch_index); +idx_t ArrowTableFunction::ArrowGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, + GlobalTableFunctionState *global_state) { + auto &state = local_state->Cast(); + return state.batch_index; } bool ArrowTableFunction::ArrowPushdownType(const LogicalType &type) { @@ -598,7 +584,7 @@ void ArrowTableFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction arrow("arrow_scan", {LogicalType::POINTER, LogicalType::POINTER, LogicalType::POINTER}, ArrowScanFunction, ArrowScanBind, ArrowScanInitGlobal, ArrowScanInitLocal); arrow.cardinality = ArrowScanCardinality; - arrow.get_partition_data = ArrowGetPartitionData; + arrow.get_batch_index = ArrowGetBatchIndex; arrow.projection_pushdown = true; arrow.filter_pushdown = true; arrow.filter_prune = true; @@ -606,9 +592,9 @@ void ArrowTableFunction::RegisterFunction(BuiltinFunctions &set) { set.AddFunction(arrow); TableFunction arrow_dumb("arrow_scan_dumb", {LogicalType::POINTER, LogicalType::POINTER, LogicalType::POINTER}, - ArrowScanFunction, ArrowScanBindDumb, ArrowScanInitGlobal, ArrowScanInitLocal); + ArrowScanFunction, ArrowScanBind, ArrowScanInitGlobal, ArrowScanInitLocal); arrow_dumb.cardinality = ArrowScanCardinality; - arrow_dumb.get_partition_data = ArrowGetPartitionData; + arrow_dumb.get_batch_index = ArrowGetBatchIndex; arrow_dumb.projection_pushdown = false; arrow_dumb.filter_pushdown = false; arrow_dumb.filter_prune = false; diff --git a/src/duckdb/src/function/table/arrow_conversion.cpp b/src/duckdb/src/function/table/arrow_conversion.cpp index e09f81aac..81b4344e8 100644 --- a/src/duckdb/src/function/table/arrow_conversion.cpp +++ b/src/duckdb/src/function/table/arrow_conversion.cpp @@ -27,7 +27,6 @@ ArrowArrayPhysicalType GetArrowArrayPhysicalType(const ArrowType &type) { } // namespace -#if STANDARD_VECTOR_SIZE > 64 static void ShiftRight(unsigned char *ar, int size, int shift) { int carry = 0; while (shift--) { @@ -38,7 +37,6 @@ static void ShiftRight(unsigned char *ar, int size, int shift) { } } } -#endif idx_t GetEffectiveOffset(const ArrowArray &array, int64_t parent_offset, const ArrowScanLocalState &state, int64_t nested_offset = -1) { @@ -100,7 +98,7 @@ static void GetValidityMask(ValidityMask &mask, ArrowArray &array, const ArrowSc //! We are setting a validity mask of the data part of dictionary vector //! For some reason, Nulls are allowed to be indexes, hence we need to set the last element here to be null //! We might have to resize the mask - mask.Resize(size + 1); + mask.Resize(size, size + 1); mask.SetInvalid(size); } } @@ -725,9 +723,6 @@ static void ColumnArrowToDuckDBRunEndEncoded(Vector &vector, const ArrowArray &a D_ASSERT(vector.GetType() == values_type.GetDuckType()); auto &scan_state = array_state.state; - if (vector.GetBuffer()) { - vector.GetBuffer()->SetAuxiliaryData(make_uniq(array_state.owned_data)); - } D_ASSERT(run_ends_array.length == values_array.length); auto compressed_size = NumericCast(run_ends_array.length); @@ -769,9 +764,6 @@ static void ColumnArrowToDuckDB(Vector &vector, ArrowArray &array, ArrowArraySca auto &scan_state = array_state.state; D_ASSERT(!array.dictionary); - if (vector.GetBuffer()) { - vector.GetBuffer()->SetAuxiliaryData(make_uniq(array_state.owned_data)); - } switch (vector.GetType().id()) { case LogicalTypeId::SQLNULL: vector.Reference(Value()); @@ -1290,9 +1282,6 @@ static bool CanContainNull(const ArrowArray &array, const ValidityMask *parent_m static void ColumnArrowToDuckDBDictionary(Vector &vector, ArrowArray &array, ArrowArrayScanState &array_state, idx_t size, const ArrowType &arrow_type, int64_t nested_offset, const ValidityMask *parent_mask, uint64_t parent_offset) { - if (vector.GetBuffer()) { - vector.GetBuffer()->SetAuxiliaryData(make_uniq(array_state.owned_data)); - } D_ASSERT(arrow_type.HasDictionary()); auto &scan_state = array_state.state; const bool has_nulls = CanContainNull(array, parent_mask); @@ -1349,31 +1338,17 @@ static void ColumnArrowToDuckDBDictionary(Vector &vector, ArrowArray &array, Arr } void ArrowTableFunction::ArrowToDuckDB(ArrowScanLocalState &scan_state, const arrow_column_map_t &arrow_convert_data, - DataChunk &output, idx_t start, bool arrow_scan_is_projected, - idx_t rowid_column_index) { + DataChunk &output, idx_t start, bool arrow_scan_is_projected) { for (idx_t idx = 0; idx < output.ColumnCount(); idx++) { - auto col_idx = scan_state.column_ids.empty() ? idx : scan_state.column_ids[idx]; + auto col_idx = scan_state.column_ids[idx]; // If projection was not pushed down into the arrow scanner, but projection pushdown is enabled on the // table function, we need to use original column ids here. auto arrow_array_idx = arrow_scan_is_projected ? idx : col_idx; - if (rowid_column_index != COLUMN_IDENTIFIER_ROW_ID) { - if (col_idx == COLUMN_IDENTIFIER_ROW_ID) { - arrow_array_idx = rowid_column_index; - } else if (col_idx >= rowid_column_index) { - // Since the rowid column is skipped when the table is bound (its not a named column), - // we need to shift references forward in the Arrow array by one to match the alignment - // that DuckDB believes the Arrow array is in. - col_idx += 1; - arrow_array_idx += 1; - } - } else { - // If there isn't any defined row_id_index, and we're asked for it, skip the column. - // This is the incumbent behavior. - if (col_idx == COLUMN_IDENTIFIER_ROW_ID) { - continue; - } + if (col_idx == COLUMN_IDENTIFIER_ROW_ID) { + // This column is skipped by the projection pushdown + continue; } auto &parent_array = scan_state.chunk->arrow_array; @@ -1393,6 +1368,7 @@ void ArrowTableFunction::ArrowToDuckDB(ArrowScanLocalState &scan_state, const ar if (!array_state.owned_data) { array_state.owned_data = scan_state.chunk; } + output.data[idx].GetBuffer()->SetAuxiliaryData(make_uniq(array_state.owned_data)); auto array_physical_type = GetArrowArrayPhysicalType(arrow_type); diff --git a/src/duckdb/src/function/table/copy_csv.cpp b/src/duckdb/src/function/table/copy_csv.cpp index 42e3f0610..26d04f89d 100644 --- a/src/duckdb/src/function/table/copy_csv.cpp +++ b/src/duckdb/src/function/table/copy_csv.cpp @@ -40,15 +40,6 @@ void SubstringDetection(char str_1, string &str_2, const string &name_str_1, con } } -void StringDetection(const string &str_1, const string &str_2, const string &name_str_1, const string &name_str_2) { - if (str_1.empty() || str_2.empty()) { - return; - } - if (str_2.find(str_1) != string::npos) { - throw BinderException("%s must not appear in the %s specification and vice versa", name_str_1, name_str_2); - } -} - //===--------------------------------------------------------------------===// // Bind //===--------------------------------------------------------------------===// @@ -59,15 +50,17 @@ void WriteQuoteOrEscape(WriteStream &writer, char quote_or_escape) { } void BaseCSVData::Finalize() { - auto delimiter_string = options.dialect_options.state_machine_options.delimiter.GetValue(); - - // quote and delimiter must not be substrings of each other - SubstringDetection(options.dialect_options.state_machine_options.quote.GetValue(), delimiter_string, "QUOTE", - "DELIMITER"); - + // verify that the options are correct in the final pass + if (options.dialect_options.state_machine_options.escape == '\0') { + options.dialect_options.state_machine_options.escape = options.dialect_options.state_machine_options.quote; + } // escape and delimiter must not be substrings of each other - SubstringDetection(options.dialect_options.state_machine_options.escape.GetValue(), delimiter_string, "ESCAPE", - "DELIMITER"); + AreOptionsEqual(options.dialect_options.state_machine_options.delimiter.GetValue(), + options.dialect_options.state_machine_options.escape.GetValue(), "DELIMITER", "ESCAPE"); + + // delimiter and quote must not be substrings of each other + AreOptionsEqual(options.dialect_options.state_machine_options.quote.GetValue(), + options.dialect_options.state_machine_options.delimiter.GetValue(), "DELIMITER", "QUOTE"); // escape and quote must not be substrings of each other (but can be the same) if (options.dialect_options.state_machine_options.quote != options.dialect_options.state_machine_options.escape) { @@ -75,33 +68,26 @@ void BaseCSVData::Finalize() { options.dialect_options.state_machine_options.escape.GetValue(), "QUOTE", "ESCAPE"); } - // comment and quote must not be substrings of each other + // delimiter and quote must not be substrings of each other AreOptionsEqual(options.dialect_options.state_machine_options.comment.GetValue(), options.dialect_options.state_machine_options.quote.GetValue(), "COMMENT", "QUOTE"); - // delimiter and comment must not be substrings of each other - SubstringDetection(options.dialect_options.state_machine_options.comment.GetValue(), delimiter_string, "COMMENT", - "DELIMITER"); + // delimiter and quote must not be substrings of each other + AreOptionsEqual(options.dialect_options.state_machine_options.comment.GetValue(), + options.dialect_options.state_machine_options.delimiter.GetValue(), "COMMENT", "DELIMITER"); // null string and delimiter must not be substrings of each other for (auto &null_str : options.null_str) { if (!null_str.empty()) { - StringDetection(options.dialect_options.state_machine_options.delimiter.GetValue(), null_str, "DELIMITER", - "NULL"); + SubstringDetection(options.dialect_options.state_machine_options.delimiter.GetValue(), null_str, + "DELIMITER", "NULL"); - // quote and nullstr must not be substrings of each other + // quote/escape and nullstr must not be substrings of each other SubstringDetection(options.dialect_options.state_machine_options.quote.GetValue(), null_str, "QUOTE", "NULL"); - // Validate the nullstr against the escape character - const char escape = options.dialect_options.state_machine_options.escape.GetValue(); - // Allow nullstr to be escape character + some non-special character, e.g., "\N" (MySQL default). - // In this case, only unquoted occurrences of the nullstr will be recognized as null values. - if (options.dialect_options.state_machine_options.rfc_4180 == false && null_str.size() == 2 && - null_str[0] == escape && null_str[1] != '\0') { - continue; - } - SubstringDetection(escape, null_str, "ESCAPE", "NULL"); + SubstringDetection(options.dialect_options.state_machine_options.escape.GetValue(), null_str, "ESCAPE", + "NULL"); } } @@ -217,7 +203,7 @@ static unique_ptr WriteCSVBind(ClientContext &context, CopyFunctio bind_data->requires_quotes['\n'] = true; bind_data->requires_quotes['\r'] = true; bind_data->requires_quotes[NumericCast( - bind_data->options.dialect_options.state_machine_options.delimiter.GetValue()[0])] = true; + bind_data->options.dialect_options.state_machine_options.delimiter.GetValue())] = true; bind_data->requires_quotes[NumericCast( bind_data->options.dialect_options.state_machine_options.quote.GetValue())] = true; @@ -325,8 +311,7 @@ static void WriteQuotedString(WriteStream &writer, WriteCSVData &csv_data, const // force quote is disabled: check if we need to add quotes anyway force_quote = RequiresQuotes(csv_data, str, len); } - // If a quote is set to none (i.e., null-terminator) we skip the quotation - if (force_quote && options.dialect_options.state_machine_options.quote.GetValue() != '\0') { + if (force_quote) { // quoting is enabled: we might need to escape things in the string bool requires_escape = false; // simple CSV @@ -455,7 +440,7 @@ static unique_ptr WriteCSVInitializeGlobal(ClientContext &co // write the header line to the file for (idx_t i = 0; i < csv_data.options.name_list.size(); i++) { if (i != 0) { - WriteQuoteOrEscape(stream, options.dialect_options.state_machine_options.delimiter.GetValue()[0]); + WriteQuoteOrEscape(stream, options.dialect_options.state_machine_options.delimiter.GetValue()); } WriteQuotedString(stream, csv_data, csv_data.options.name_list[i].c_str(), csv_data.options.name_list[i].size(), false); @@ -492,7 +477,7 @@ static void WriteCSVChunkInternal(ClientContext &context, FunctionData &bind_dat D_ASSERT(options.null_str.size() == 1); for (idx_t col_idx = 0; col_idx < cast_chunk.ColumnCount(); col_idx++) { if (col_idx != 0) { - WriteQuoteOrEscape(writer, options.dialect_options.state_machine_options.delimiter.GetValue()[0]); + WriteQuoteOrEscape(writer, options.dialect_options.state_machine_options.delimiter.GetValue()); } if (FlatVector::IsNull(cast_chunk.data[col_idx], row_idx)) { // write null value diff --git a/src/duckdb/src/function/table/glob.cpp b/src/duckdb/src/function/table/glob.cpp index 736c2778e..d31462450 100644 --- a/src/duckdb/src/function/table/glob.cpp +++ b/src/duckdb/src/function/table/glob.cpp @@ -8,7 +8,7 @@ namespace duckdb { struct GlobFunctionBindData : public TableFunctionData { - shared_ptr file_list; + unique_ptr file_list; }; static unique_ptr GlobFunctionBind(ClientContext &context, TableFunctionBindInput &input, diff --git a/src/duckdb/src/function/table/query_function.cpp b/src/duckdb/src/function/table/query_function.cpp index c44b1919c..d000c03ac 100644 --- a/src/duckdb/src/function/table/query_function.cpp +++ b/src/duckdb/src/function/table/query_function.cpp @@ -16,39 +16,33 @@ static unique_ptr ParseSubquery(const string &query, const ParserOp return duckdb::make_uniq(std::move(select_stmt)); } -static string UnionTablesQuery(TableFunctionBindInput &input) { +static void UnionTablesQuery(TableFunctionBindInput &input, string &query) { for (auto &input_val : input.inputs) { if (input_val.IsNull()) { throw BinderException("Cannot use NULL as function argument"); } } - string result; string by_name = (input.inputs.size() == 2 && (input.inputs[1].type().id() == LogicalTypeId::BOOLEAN && input.inputs[1].GetValue())) ? "BY NAME " : ""; // 'by_name' variable defaults to false if (input.inputs[0].type().id() == LogicalTypeId::VARCHAR) { - auto from_path = input.inputs[0].ToString(); - auto qualified_name = QualifiedName::Parse(from_path); - result += "FROM " + qualified_name.ToString(); + query += "FROM " + KeywordHelper::WriteOptionallyQuoted(input.inputs[0].ToString()); } else if (input.inputs[0].type() == LogicalType::LIST(LogicalType::VARCHAR)) { string union_all_clause = " UNION ALL " + by_name + "FROM "; const auto &children = ListValue::GetChildren(input.inputs[0]); - if (children.empty()) { throw InvalidInputException("Input list is empty"); } - auto qualified_name = QualifiedName::Parse(children[0].ToString()); - result += "FROM " + qualified_name.ToString(); + + query += "FROM " + KeywordHelper::WriteOptionallyQuoted(children[0].ToString()); for (size_t i = 1; i < children.size(); ++i) { auto child = children[i].ToString(); - auto qualified_name = QualifiedName::Parse(child); - result += union_all_clause + qualified_name.ToString(); + query += union_all_clause + KeywordHelper::WriteOptionallyQuoted(child); } } else { throw InvalidInputException("Expected a table or a list with tables as input"); } - return result; } static unique_ptr QueryBindReplace(ClientContext &context, TableFunctionBindInput &input) { @@ -58,7 +52,8 @@ static unique_ptr QueryBindReplace(ClientContext &context, TableFuncti } static unique_ptr TableBindReplace(ClientContext &context, TableFunctionBindInput &input) { - auto query = UnionTablesQuery(input); + string query; + UnionTablesQuery(input, query); auto subquery_ref = ParseSubquery(query, context.GetParserOptions(), "Expected a table or a list with tables as input"); return std::move(subquery_ref); diff --git a/src/duckdb/src/function/table/read_csv.cpp b/src/duckdb/src/function/table/read_csv.cpp index f01934e7b..0c6dcf127 100644 --- a/src/duckdb/src/function/table/read_csv.cpp +++ b/src/duckdb/src/function/table/read_csv.cpp @@ -26,16 +26,14 @@ #include "duckdb/execution/operator/csv_scanner/string_value_scanner.hpp" #include -#include "duckdb/execution/operator/csv_scanner/csv_schema.hpp" namespace duckdb { -unique_ptr ReadCSV::OpenCSV(const string &file_path, const CSVReaderOptions &options, +unique_ptr ReadCSV::OpenCSV(const string &file_path, FileCompressionType compression, ClientContext &context) { auto &fs = FileSystem::GetFileSystem(context); auto &allocator = BufferAllocator::Get(context); - auto &db_config = DBConfig::GetConfig(context); - return CSVFileHandle::OpenFile(db_config, fs, allocator, file_path, options); + return CSVFileHandle::OpenFile(fs, allocator, file_path, compression); } ReadCSVData::ReadCSVData() { @@ -45,113 +43,44 @@ void ReadCSVData::FinalizeRead(ClientContext &context) { BaseCSVData::Finalize(); } -//! Function to do schema discovery over one CSV file or a list/glob of CSV files -void SchemaDiscovery(ClientContext &context, ReadCSVData &result, CSVReaderOptions &options, - vector &return_types, vector &names, MultiFileList &multi_file_list) { - vector schemas; - const auto option_og = options; - - const auto file_paths = multi_file_list.GetAllFiles(); - - // Here what we want to do is to sniff a given number of lines, if we have many files, we might go through them - // to reach the number of lines. - const idx_t required_number_of_lines = options.sniff_size * options.sample_size_chunks; - - idx_t total_number_of_rows = 0; - idx_t current_file = 0; - options.file_path = file_paths[current_file]; - - result.buffer_manager = make_shared_ptr(context, options, options.file_path, 0, false); - { - CSVSniffer sniffer(options, result.buffer_manager, CSVStateMachineCache::Get(context)); - auto sniffer_result = sniffer.SniffCSV(); - idx_t rows_read = sniffer.LinesSniffed() - - (options.dialect_options.skip_rows.GetValue() + options.dialect_options.header.GetValue()); - - schemas.emplace_back(sniffer_result.names, sniffer_result.return_types, file_paths[0], rows_read, - result.buffer_manager->GetBuffer(0)->actual_size == 0); - total_number_of_rows += sniffer.LinesSniffed(); - } - - // We do a copy of the options to not pollute the options of the first file. - constexpr idx_t max_files_to_sniff = 10; - idx_t files_to_sniff = file_paths.size() > max_files_to_sniff ? max_files_to_sniff : file_paths.size(); - while (total_number_of_rows < required_number_of_lines && current_file + 1 < files_to_sniff) { - auto option_copy = option_og; - current_file++; - option_copy.file_path = file_paths[current_file]; - auto buffer_manager = - make_shared_ptr(context, option_copy, option_copy.file_path, current_file, false); - // TODO: We could cache the sniffer to be reused during scanning. Currently that's an exercise left to the - // reader - CSVSniffer sniffer(option_copy, buffer_manager, CSVStateMachineCache::Get(context)); - auto sniffer_result = sniffer.SniffCSV(); - idx_t rows_read = sniffer.LinesSniffed() - (option_copy.dialect_options.skip_rows.GetValue() + - option_copy.dialect_options.header.GetValue()); - if (buffer_manager->GetBuffer(0)->actual_size == 0) { - schemas.emplace_back(true); - } else { - schemas.emplace_back(sniffer_result.names, sniffer_result.return_types, option_copy.file_path, rows_read); - } - total_number_of_rows += sniffer.LinesSniffed(); - } - - // We might now have multiple schemas, we need to go through them to define the one true schema - CSVSchema best_schema; - for (auto &schema : schemas) { - if (best_schema.Empty()) { - // A schema is bettah than no schema - best_schema = schema; - } else if (best_schema.GetRowsRead() == 0) { - // If the best-schema has no data-rows, that's easy, we just take the new schema - best_schema = schema; - } else if (schema.GetRowsRead() != 0) { - // We might have conflicting-schemas, we must merge them - best_schema.MergeSchemas(schema, options.null_padding); - } - } - - if (names.empty()) { - names = best_schema.GetNames(); - return_types = best_schema.GetTypes(); - } - result.csv_types = return_types; - result.csv_names = names; -} - static unique_ptr ReadCSVBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { auto result = make_uniq(); auto &options = result->options; - const auto multi_file_reader = MultiFileReader::Create(input.table_function); - const auto multi_file_list = multi_file_reader->CreateFileList(context, input.inputs[0]); - if (multi_file_list->GetTotalFileCount() > 1) { - options.multi_file_reader = true; - } + auto multi_file_reader = MultiFileReader::Create(input.table_function); + auto multi_file_list = multi_file_reader->CreateFileList(context, input.inputs[0]); + options.FromNamedParameters(input.named_parameters, context); options.file_options.AutoDetectHivePartitioning(*multi_file_list, context); options.Verify(); - if (!options.file_options.union_by_name) { - if (options.auto_detect) { - SchemaDiscovery(context, *result, options, return_types, names, *multi_file_list); + if (!options.auto_detect) { + if (!options.columns_set) { + throw BinderException("read_csv requires columns to be specified through the 'columns' option. Use " + "read_csv_auto or set read_csv(..., " + "AUTO_DETECT=TRUE) to automatically guess columns."); } else { - // If we are not running the sniffer, the columns must be set! - if (!options.columns_set) { - throw BinderException("read_csv requires columns to be specified through the 'columns' option. Use " - "read_csv_auto or set read_csv(..., " - "AUTO_DETECT=TRUE) to automatically guess columns."); - } names = options.name_list; return_types = options.sql_type_list; } - D_ASSERT(return_types.size() == names.size()); - result->options.dialect_options.num_cols = names.size(); + } + if (options.auto_detect && !options.file_options.union_by_name) { + options.file_path = multi_file_list->GetFirstFile(); + result->buffer_manager = make_shared_ptr(context, options, options.file_path, 0); + CSVSniffer sniffer(options, result->buffer_manager, CSVStateMachineCache::Get(context)); + auto sniffer_result = sniffer.SniffCSV(); + if (names.empty()) { + names = sniffer_result.names; + return_types = sniffer_result.return_types; + } + result->csv_types = return_types; + result->csv_names = names; + } - multi_file_reader->BindOptions(options.file_options, *multi_file_list, return_types, names, - result->reader_bind); - } else { + D_ASSERT(return_types.size() == names.size()); + result->options.dialect_options.num_cols = names.size(); + if (options.file_options.union_by_name) { result->reader_bind = multi_file_reader->BindUnionReader(context, return_types, names, *multi_file_list, *result, options); if (result->union_readers.size() > 1) { @@ -160,7 +89,7 @@ static unique_ptr ReadCSVBind(ClientContext &context, TableFunctio } } if (!options.sql_types_per_column.empty()) { - const auto exception = CSVError::ColumnTypesError(options.sql_types_per_column, names); + auto exception = CSVError::ColumnTypesError(options.sql_types_per_column, names); if (!exception.error_message.empty()) { throw BinderException(exception.error_message); } @@ -171,14 +100,18 @@ static unique_ptr ReadCSVBind(ClientContext &context, TableFunctio } } } + result->csv_types = return_types; + result->csv_names = names; + } else { + result->csv_types = return_types; + result->csv_names = names; + multi_file_reader->BindOptions(options.file_options, *multi_file_list, return_types, names, + result->reader_bind); } - - result->csv_types = return_types; - result->csv_names = names; result->return_types = return_types; result->return_names = names; if (!options.force_not_null_names.empty()) { - // Let's first check all column names match + // Lets first check all column names match duckdb::unordered_set column_names; for (auto &name : names) { column_names.insert(name); @@ -201,6 +134,7 @@ static unique_ptr ReadCSVBind(ClientContext &context, TableFunctio // TODO: make the CSV reader use MultiFileList throughout, instead of converting to vector result->files = multi_file_list->GetAllFiles(); + result->Finalize(); return std::move(result); } @@ -235,7 +169,7 @@ static unique_ptr ReadCSVInitGlobal(ClientContext &con return nullptr; } return make_uniq(context, bind_data.buffer_manager, bind_data.options, - context.db->NumberOfThreads(), bind_data.files, input.column_indexes, bind_data); + context.db->NumberOfThreads(), bind_data.files, input.column_ids, bind_data); } unique_ptr ReadCSVInitLocal(ExecutionContext &context, TableFunctionInitInput &input, @@ -288,12 +222,10 @@ static void ReadCSVFunction(ClientContext &context, TableFunctionInput &data_p, } while (true); } -static OperatorPartitionData CSVReaderGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input) { - if (input.partition_info.RequiresPartitionColumns()) { - throw InternalException("CSVReader::GetPartitionData: partition columns not supported"); - } - auto &data = input.local_state->Cast(); - return OperatorPartitionData(data.csv_reader->scanner_idx); +static idx_t CSVReaderGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state) { + auto &data = local_state->Cast(); + return data.csv_reader->scanner_idx; } void ReadCSVTableFunction::ReadCSVAddNamedParameters(TableFunction &table_function) { @@ -333,8 +265,6 @@ void ReadCSVTableFunction::ReadCSVAddNamedParameters(TableFunction &table_functi table_function.named_parameters["names"] = LogicalType::LIST(LogicalType::VARCHAR); table_function.named_parameters["column_names"] = LogicalType::LIST(LogicalType::VARCHAR); table_function.named_parameters["comment"] = LogicalType::VARCHAR; - table_function.named_parameters["encoding"] = LogicalType::VARCHAR; - table_function.named_parameters["rfc_4180"] = LogicalType::BOOLEAN; MultiFileReader::AddParameters(table_function); } @@ -366,11 +296,13 @@ void CSVComplexFilterPushdown(ClientContext &context, LogicalGet &get, FunctionD unique_ptr CSVReaderCardinality(ClientContext &context, const FunctionData *bind_data_p) { auto &bind_data = bind_data_p->Cast(); - // determined through the scientific method as the average amount of rows in a CSV file - idx_t per_file_cardinality = 42; + idx_t per_file_cardinality = 0; if (bind_data.buffer_manager && bind_data.buffer_manager->file_handle) { auto estimated_row_width = (bind_data.csv_types.size() * 5); per_file_cardinality = bind_data.buffer_manager->file_handle->FileSize() / estimated_row_width; + } else { + // determined through the scientific method as the average amount of rows in a CSV file + per_file_cardinality = 42; } return make_uniq(bind_data.files.size() * per_file_cardinality); } @@ -405,7 +337,7 @@ TableFunction ReadCSVTableFunction::GetFunction() { read_csv.pushdown_complex_filter = CSVComplexFilterPushdown; read_csv.serialize = CSVReaderSerialize; read_csv.deserialize = CSVReaderDeserialize; - read_csv.get_partition_data = CSVReaderGetPartitionData; + read_csv.get_batch_index = CSVReaderGetBatchIndex; read_csv.cardinality = CSVReaderCardinality; read_csv.projection_pushdown = true; read_csv.type_pushdown = PushdownTypeToCSVScanner; diff --git a/src/duckdb/src/function/table/read_file.cpp b/src/duckdb/src/function/table/read_file.cpp index 158e89fd0..e9039b0bf 100644 --- a/src/duckdb/src/function/table/read_file.cpp +++ b/src/duckdb/src/function/table/read_file.cpp @@ -64,7 +64,7 @@ static unique_ptr ReadFileBind(ClientContext &context, TableFuncti names.push_back("content"); return_types.push_back(LogicalType::BIGINT); names.push_back("size"); - return_types.push_back(LogicalType::TIMESTAMP_TZ); + return_types.push_back(LogicalType::TIMESTAMP); names.push_back("last_modified"); return std::move(result); @@ -150,30 +150,11 @@ static void ReadFileExecute(ClientContext &context, TableFunctionInput &input, D FlatVector::GetData(file_name_vector)[out_idx] = file_name_string; } break; case ReadFileBindData::FILE_CONTENT_COLUMN: { - auto file_size_raw = file_handle->GetFileSize(); - AssertMaxFileSize(file_name, file_size_raw); - auto file_size = UnsafeNumericCast(file_size_raw); + auto file_size = file_handle->GetFileSize(); + AssertMaxFileSize(file_name, file_size); auto &file_content_vector = output.data[col_idx]; - auto content_string = StringVector::EmptyString(file_content_vector, file_size_raw); - - auto remaining_bytes = UnsafeNumericCast(file_size); - - // Read in batches of 100mb - constexpr auto MAX_READ_SIZE = 100LL * 1024 * 1024; - while (remaining_bytes > 0) { - const auto bytes_to_read = MinValue(remaining_bytes, MAX_READ_SIZE); - const auto content_string_ptr = - content_string.GetDataWriteable() + (file_size - remaining_bytes); - const auto actually_read = - file_handle->Read(content_string_ptr, UnsafeNumericCast(bytes_to_read)); - if (actually_read == 0) { - // Uh oh, random EOF? - throw IOException("Failed to read file '%s' at offset %lu, unexpected EOF", file_name, - file_size - remaining_bytes); - } - remaining_bytes -= actually_read; - } - + auto content_string = StringVector::EmptyString(file_content_vector, file_size); + file_handle->Read(content_string.GetDataWriteable(), file_size); content_string.Finalize(); OP::VERIFY(file_name, content_string); @@ -191,8 +172,7 @@ static void ReadFileExecute(ClientContext &context, TableFunctionInput &input, D // correctly) try { auto timestamp_seconds = Timestamp::FromEpochSeconds(fs.GetLastModifiedTime(*file_handle)); - FlatVector::GetData(last_modified_vector)[out_idx] = - timestamp_tz_t(timestamp_seconds); + FlatVector::GetData(last_modified_vector)[out_idx] = timestamp_seconds; } catch (std::exception &ex) { ErrorData error(ex); if (error.Type() == ExceptionType::CONVERSION) { diff --git a/src/duckdb/src/function/table/sniff_csv.cpp b/src/duckdb/src/function/table/sniff_csv.cpp index 5c72aabb9..9c845bbfd 100644 --- a/src/duckdb/src/function/table/sniff_csv.cpp +++ b/src/duckdb/src/function/table/sniff_csv.cpp @@ -21,8 +21,6 @@ struct CSVSniffFunctionData : public TableFunctionData { vector return_types_csv; // Column Names of CSV (If given by the user) vector names_csv; - // If we want to force the match of the sniffer types - bool force_match = true; }; struct CSVSniffGlobalState : public GlobalTableFunctionState { @@ -38,31 +36,21 @@ static unique_ptr CSVSniffInitGlobal(ClientContext &co static unique_ptr CSVSniffBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names) { auto result = make_uniq(); - if (input.inputs[0].IsNull()) { - throw BinderException("sniff_csv cannot take NULL as a file path parameter"); + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("sniff_csv is disabled through configuration"); } result->path = input.inputs[0].ToString(); auto it = input.named_parameters.find("auto_detect"); if (it != input.named_parameters.end()) { - if (it->second.IsNull()) { - throw BinderException("\"%s\" expects a non-null boolean value (e.g. TRUE or 1)", it->first); - } if (!it->second.GetValue()) { throw InvalidInputException("sniff_csv function does not accept auto_detect variable set to false"); } // otherwise remove it input.named_parameters.erase("auto_detect"); } - - // If we want to force the match of the sniffer - it = input.named_parameters.find("force_match"); - if (it != input.named_parameters.end()) { - result->force_match = it->second.GetValue(); - input.named_parameters.erase("force_match"); - } result->options.FromNamedParameters(input.named_parameters, context); result->options.Verify(); - // We want to return the whole CSV Configuration // 1. Delimiter return_types.emplace_back(LogicalType::VARCHAR); @@ -117,13 +105,6 @@ string FormatOptions(char opt) { return result; } -string FormatOptions(string opt) { - if (opt.size() == 1) { - return FormatOptions(opt[0]); - } - return opt; -} - static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { auto &global_state = data_p.global_state->Cast(); // Are we done? @@ -151,7 +132,7 @@ static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, sniffer_options.sql_type_list = data.return_types_csv; } CSVSniffer sniffer(sniffer_options, buffer_manager, CSVStateMachineCache::Get(context)); - auto sniffer_result = sniffer.SniffCSV(data.force_match); + auto sniffer_result = sniffer.SniffCSV(true); string str_opt; string separator = ", "; // Set output @@ -175,7 +156,7 @@ static void CSVSniffFunction(ClientContext &context, TableFunctionInput &data_p, // 6. Skip Rows output.SetValue(5, 0, Value::UINTEGER(NumericCast(sniffer_options.dialect_options.skip_rows.GetValue()))); // 7. Has Header - auto has_header = Value::BOOLEAN(sniffer_options.dialect_options.header.GetValue()); + auto has_header = Value::BOOLEAN(sniffer_options.dialect_options.header.GetValue()).ToString(); output.SetValue(6, 0, has_header); // 8. List> {'col1': 'INTEGER', 'col2': 'VARCHAR'} vector values; @@ -313,7 +294,6 @@ void CSVSnifferFunction::RegisterFunction(BuiltinFunctions &set) { TableFunction csv_sniffer("sniff_csv", {LogicalType::VARCHAR}, CSVSniffFunction, CSVSniffBind, CSVSniffInitGlobal); // Accept same options as the actual csv reader ReadCSVTableFunction::ReadCSVAddNamedParameters(csv_sniffer); - csv_sniffer.named_parameters["force_match"] = LogicalType::BOOLEAN; set.AddFunction(csv_sniffer); } } // namespace duckdb diff --git a/src/duckdb/src/function/table/system/duckdb_columns.cpp b/src/duckdb/src/function/table/system/duckdb_columns.cpp index d30ea5300..1632a9e5c 100644 --- a/src/duckdb/src/function/table/system/duckdb_columns.cpp +++ b/src/duckdb/src/function/table/system/duckdb_columns.cpp @@ -115,7 +115,7 @@ class TableColumnHelper : public ColumnHelper { explicit TableColumnHelper(TableCatalogEntry &entry) : entry(entry) { for (auto &constraint : entry.GetConstraints()) { if (constraint->type == ConstraintType::NOT_NULL) { - auto ¬_null = constraint->Cast(); + auto ¬_null = *reinterpret_cast(constraint.get()); not_null_cols.insert(not_null.index.index); } } diff --git a/src/duckdb/src/function/table/system/duckdb_constraints.cpp b/src/duckdb/src/function/table/system/duckdb_constraints.cpp index 5f436f2c8..8637feaf3 100644 --- a/src/duckdb/src/function/table/system/duckdb_constraints.cpp +++ b/src/duckdb/src/function/table/system/duckdb_constraints.cpp @@ -307,6 +307,7 @@ void DuckDBConstraintsFunction(ClientContext &context, TableFunctionInput &data_ for (auto &name : info.referenced_columns) { referenced_column_name_list.push_back(Value(std::move(name))); } + // constraint_column_indexes, LIST output.SetValue(col++, count, Value::LIST(LogicalType::BIGINT, std::move(column_index_list))); @@ -324,7 +325,6 @@ void DuckDBConstraintsFunction(ClientContext &context, TableFunctionInput &data_ output.SetValue(col++, count, Value::LIST(LogicalType::VARCHAR, std::move(referenced_column_name_list))); count++; } - if (data.constraint_offset >= constraints.size()) { data.constraint_offset = 0; data.offset++; diff --git a/src/duckdb/src/function/table/system/duckdb_dependencies.cpp b/src/duckdb/src/function/table/system/duckdb_dependencies.cpp index 720bee4d8..6f7370194 100644 --- a/src/duckdb/src/function/table/system/duckdb_dependencies.cpp +++ b/src/duckdb/src/function/table/system/duckdb_dependencies.cpp @@ -57,12 +57,13 @@ unique_ptr DuckDBDependenciesInit(ClientContext &conte // scan all the schemas and collect them auto &catalog = Catalog::GetCatalog(context, INVALID_CATALOG); - auto dependency_manager = catalog.GetDependencyManager(); - if (dependency_manager) { - dependency_manager->Scan( - context, [&](CatalogEntry &obj, CatalogEntry &dependent, const DependencyDependentFlags &flags) { - result->entries.emplace_back(obj, dependent, flags); - }); + if (catalog.IsDuckCatalog()) { + auto &duck_catalog = catalog.Cast(); + auto &dependency_manager = duck_catalog.GetDependencyManager(); + dependency_manager.Scan(context, + [&](CatalogEntry &obj, CatalogEntry &dependent, const DependencyDependentFlags &flags) { + result->entries.emplace_back(obj, dependent, flags); + }); } return std::move(result); diff --git a/src/duckdb/src/function/table/system/duckdb_extensions.cpp b/src/duckdb/src/function/table/system/duckdb_extensions.cpp index 64d26dea9..c61fa7431 100644 --- a/src/duckdb/src/function/table/system/duckdb_extensions.cpp +++ b/src/duckdb/src/function/table/system/duckdb_extensions.cpp @@ -97,7 +97,7 @@ unique_ptr DuckDBExtensionsInit(ClientContext &context // Secondly we scan all installed extensions and their install info #ifndef WASM_LOADABLE_EXTENSIONS - auto ext_directory = ExtensionHelper::GetExtensionDirectoryPath(context); + auto ext_directory = ExtensionHelper::ExtensionDirectory(context); fs.ListFiles(ext_directory, [&](const string &path, bool is_directory) { if (!StringUtil::EndsWith(path, ".duckdb_extension")) { return; diff --git a/src/duckdb/src/function/table/system/duckdb_functions.cpp b/src/duckdb/src/function/table/system/duckdb_functions.cpp index 4ed87e524..80ac7bcb3 100644 --- a/src/duckdb/src/function/table/system/duckdb_functions.cpp +++ b/src/duckdb/src/function/table/system/duckdb_functions.cpp @@ -8,12 +8,11 @@ #include "duckdb/catalog/catalog_entry/table_macro_catalog_entry.hpp" #include "duckdb/function/table_macro_function.hpp" #include "duckdb/function/scalar_macro_function.hpp" + #include "duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/common/algorithm.hpp" -#include "duckdb/common/optional_idx.hpp" -#include "duckdb/common/types.hpp" #include "duckdb/main/client_data.hpp" namespace duckdb { @@ -77,8 +76,8 @@ static unique_ptr DuckDBFunctionsBind(ClientContext &context, Tabl names.emplace_back("function_oid"); return_types.emplace_back(LogicalType::BIGINT); - names.emplace_back("examples"); - return_types.emplace_back(LogicalType::LIST(LogicalType::VARCHAR)); + names.emplace_back("example"); + return_types.emplace_back(LogicalType::VARCHAR); names.emplace_back("stability"); return_types.emplace_back(LogicalType::VARCHAR); @@ -155,11 +154,6 @@ struct ScalarFunctionExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(ScalarFunctionCatalogEntry &entry, idx_t offset) { - auto fun = entry.functions.GetFunctionByOffset(offset); - return fun.arguments; - } - static Value GetVarArgs(ScalarFunctionCatalogEntry &entry, idx_t offset) { auto fun = entry.functions.GetFunctionByOffset(offset); return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); @@ -208,11 +202,6 @@ struct AggregateFunctionExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(AggregateFunctionCatalogEntry &entry, idx_t offset) { - auto fun = entry.functions.GetFunctionByOffset(offset); - return fun.arguments; - } - static Value GetVarArgs(AggregateFunctionCatalogEntry &entry, idx_t offset) { auto fun = entry.functions.GetFunctionByOffset(offset); return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); @@ -248,7 +237,7 @@ struct MacroExtractor { vector results; auto ¯o_entry = *entry.macros[offset]; for (auto ¶m : macro_entry.parameters) { - D_ASSERT(param->GetExpressionType() == ExpressionType::COLUMN_REF); + D_ASSERT(param->type == ExpressionType::COLUMN_REF); auto &colref = param->Cast(); results.emplace_back(colref.GetColumnName()); } @@ -270,18 +259,6 @@ struct MacroExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(ScalarMacroCatalogEntry &entry, idx_t offset) { - vector results; - auto ¯o_entry = *entry.macros[offset]; - for (idx_t i = 0; i < macro_entry.parameters.size(); i++) { - results.emplace_back(LogicalType::UNKNOWN); - } - for (idx_t i = 0; i < macro_entry.default_parameters.size(); i++) { - results.emplace_back(LogicalType::UNKNOWN); - } - return results; - } - static Value GetVarArgs(ScalarMacroCatalogEntry &entry, idx_t offset) { return Value(); } @@ -319,7 +296,7 @@ struct TableMacroExtractor { vector results; auto ¯o_entry = *entry.macros[offset]; for (auto ¶m : macro_entry.parameters) { - D_ASSERT(param->GetExpressionType() == ExpressionType::COLUMN_REF); + D_ASSERT(param->type == ExpressionType::COLUMN_REF); auto &colref = param->Cast(); results.emplace_back(colref.GetColumnName()); } @@ -341,18 +318,6 @@ struct TableMacroExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(TableMacroCatalogEntry &entry, idx_t offset) { - vector results; - auto ¯o_entry = *entry.macros[offset]; - for (idx_t i = 0; i < macro_entry.parameters.size(); i++) { - results.emplace_back(LogicalType::UNKNOWN); - } - for (idx_t i = 0; i < macro_entry.default_parameters.size(); i++) { - results.emplace_back(LogicalType::UNKNOWN); - } - return results; - } - static Value GetVarArgs(TableMacroCatalogEntry &entry, idx_t offset) { return Value(); } @@ -413,11 +378,6 @@ struct TableFunctionExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(TableFunctionCatalogEntry &entry, idx_t offset) { - auto fun = entry.functions.GetFunctionByOffset(offset); - return fun.arguments; - } - static Value GetVarArgs(TableFunctionCatalogEntry &entry, idx_t offset) { auto fun = entry.functions.GetFunctionByOffset(offset); return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); @@ -475,11 +435,6 @@ struct PragmaFunctionExtractor { return Value::LIST(LogicalType::VARCHAR, std::move(results)); } - static vector GetParameterLogicalTypes(PragmaFunctionCatalogEntry &entry, idx_t offset) { - auto fun = entry.functions.GetFunctionByOffset(offset); - return fun.arguments; - } - static Value GetVarArgs(PragmaFunctionCatalogEntry &entry, idx_t offset) { auto fun = entry.functions.GetFunctionByOffset(offset); return !fun.HasVarArgs() ? Value() : Value(fun.varargs.ToString()); @@ -498,92 +453,9 @@ struct PragmaFunctionExtractor { } }; -static vector ToValueVector(vector &string_vector) { - vector result; - for (string &str : string_vector) { - result.emplace_back(Value(str)); - } - return result; -} - -template -static Value GetParameterNames(FunctionEntry &entry, idx_t function_idx, FunctionDescription &function_description, - Value ¶meter_types) { - vector parameter_names; - if (!function_description.parameter_names.empty()) { - for (idx_t param_idx = 0; param_idx < ListValue::GetChildren(parameter_types).size(); param_idx++) { - if (param_idx < function_description.parameter_names.size()) { - parameter_names.emplace_back(function_description.parameter_names[param_idx]); - } else { - parameter_names.emplace_back("col" + to_string(param_idx)); - } - } - } else { - // fallback - auto &function = entry.Cast(); - parameter_names = OP::GetParameters(function, function_idx); - } - return Value::LIST(LogicalType::VARCHAR, parameter_names); -} - -// returns values: -// 0: exact type match; N: match using N values; Invalid(): no match -static optional_idx CalcDescriptionSpecificity(FunctionDescription &description, - const vector ¶meter_types) { - if (description.parameter_types.size() != parameter_types.size()) { - return optional_idx::Invalid(); - } - idx_t any_count = 0; - for (idx_t i = 0; i < description.parameter_types.size(); i++) { - if (description.parameter_types[i].id() == LogicalTypeId::ANY) { - any_count++; - } else if (description.parameter_types[i] != parameter_types[i]) { - return optional_idx::Invalid(); - } - } - return any_count; -} - -// Find FunctionDescription object with matching number of arguments and types -static optional_idx GetFunctionDescriptionIndex(vector &function_descriptions, - vector &function_parameter_types) { - if (function_descriptions.size() == 1) { - // one description, use it even if nr of parameters don't match - idx_t nr_function_parameters = function_parameter_types.size(); - for (idx_t i = 0; i < function_descriptions[0].parameter_types.size(); i++) { - if (i < nr_function_parameters && function_descriptions[0].parameter_types[i] != LogicalTypeId::ANY && - function_descriptions[0].parameter_types[i] != function_parameter_types[i]) { - return optional_idx::Invalid(); - } - } - return optional_idx(0); - } - - // multiple descriptions, search most specific description - optional_idx best_description_idx; - // specificity_score: 0: exact type match; N: match using N values; Invalid(): no match - optional_idx best_specificity_score; - optional_idx specificity_score; - for (idx_t descr_idx = 0; descr_idx < function_descriptions.size(); descr_idx++) { - specificity_score = CalcDescriptionSpecificity(function_descriptions[descr_idx], function_parameter_types); - if (specificity_score.IsValid() && - (!best_specificity_score.IsValid() || specificity_score.GetIndex() < best_specificity_score.GetIndex())) { - best_specificity_score = specificity_score; - best_description_idx = descr_idx; - } - } - return best_description_idx; -} - template bool ExtractFunctionData(FunctionEntry &entry, idx_t function_idx, DataChunk &output, idx_t output_offset) { auto &function = entry.Cast(); - vector parameter_types_vector = OP::GetParameterLogicalTypes(function, function_idx); - Value parameter_types_value = OP::GetParameterTypes(function, function_idx); - optional_idx description_idx = GetFunctionDescriptionIndex(entry.descriptions, parameter_types_vector); - FunctionDescription function_description = - description_idx.IsValid() ? entry.descriptions[description_idx.GetIndex()] : FunctionDescription(); - idx_t col = 0; // database_name, LogicalType::VARCHAR @@ -602,8 +474,7 @@ bool ExtractFunctionData(FunctionEntry &entry, idx_t function_idx, DataChunk &ou output.SetValue(col++, output_offset, Value(OP::GetFunctionType())); // function_description, LogicalType::VARCHAR - output.SetValue(col++, output_offset, - (function_description.description.empty()) ? Value() : Value(function_description.description)); + output.SetValue(col++, output_offset, entry.description.empty() ? Value() : entry.description); // comment, LogicalType::VARCHAR output.SetValue(col++, output_offset, entry.comment); @@ -615,11 +486,15 @@ bool ExtractFunctionData(FunctionEntry &entry, idx_t function_idx, DataChunk &ou output.SetValue(col++, output_offset, OP::GetReturnType(function, function_idx)); // parameters, LogicalType::LIST(LogicalType::VARCHAR) - output.SetValue(col++, output_offset, - GetParameterNames(function, function_idx, function_description, parameter_types_value)); + auto parameters = OP::GetParameters(function, function_idx); + for (idx_t param_idx = 0; param_idx < function.parameter_names.size() && param_idx < parameters.size(); + param_idx++) { + parameters[param_idx] = Value(function.parameter_names[param_idx]); + } + output.SetValue(col++, output_offset, Value::LIST(LogicalType::VARCHAR, std::move(parameters))); // parameter_types, LogicalType::LIST(LogicalType::VARCHAR) - output.SetValue(col++, output_offset, parameter_types_value); + output.SetValue(col++, output_offset, OP::GetParameterTypes(function, function_idx)); // varargs, LogicalType::VARCHAR output.SetValue(col++, output_offset, OP::GetVarArgs(function, function_idx)); @@ -636,9 +511,8 @@ bool ExtractFunctionData(FunctionEntry &entry, idx_t function_idx, DataChunk &ou // function_oid, LogicalType::BIGINT output.SetValue(col++, output_offset, Value::BIGINT(NumericCast(function.oid))); - // examples, LogicalType::LIST(LogicalType::VARCHAR) - output.SetValue(col++, output_offset, - Value::LIST(LogicalType::VARCHAR, ToValueVector(function_description.examples))); + // example, LogicalType::VARCHAR + output.SetValue(col++, output_offset, entry.example.empty() ? Value() : entry.example); // stability, LogicalType::VARCHAR output.SetValue(col++, output_offset, OP::ResultType(function, function_idx)); @@ -672,6 +546,7 @@ void DuckDBFunctionsFunction(ClientContext &context, TableFunctionInput &data_p, finished = ExtractFunctionData(entry, data.offset_in_entry, output, count); break; + case CatalogType::MACRO_ENTRY: finished = ExtractFunctionData(entry, data.offset_in_entry, output, count); diff --git a/src/duckdb/src/function/table/system/duckdb_memory.cpp b/src/duckdb/src/function/table/system/duckdb_memory.cpp index a1eb044b7..e67fa5106 100644 --- a/src/duckdb/src/function/table/system/duckdb_memory.cpp +++ b/src/duckdb/src/function/table/system/duckdb_memory.cpp @@ -27,6 +27,7 @@ static unique_ptr DuckDBMemoryBind(ClientContext &context, TableFu unique_ptr DuckDBMemoryInit(ClientContext &context, TableFunctionInitInput &input) { auto result = make_uniq(); + result->entries = BufferManager::GetBufferManager(context).GetMemoryUsageInfo(); return std::move(result); } diff --git a/src/duckdb/src/function/table/system/duckdb_settings.cpp b/src/duckdb/src/function/table/system/duckdb_settings.cpp index b7c3a56b8..eec5bbfe1 100644 --- a/src/duckdb/src/function/table/system/duckdb_settings.cpp +++ b/src/duckdb/src/function/table/system/duckdb_settings.cpp @@ -54,7 +54,7 @@ unique_ptr DuckDBSettingsInit(ClientContext &context, value.name = option->name; value.value = option->get_setting(context).ToString(); value.description = option->description; - value.input_type = option->parameter_type; + value.input_type = EnumUtil::ToString(option->parameter_type); value.scope = EnumUtil::ToString(scope); result->settings.push_back(std::move(value)); diff --git a/src/duckdb/src/function/table/system/duckdb_tables.cpp b/src/duckdb/src/function/table/system/duckdb_tables.cpp index 5e007bbff..7f1386ab3 100644 --- a/src/duckdb/src/function/table/system/duckdb_tables.cpp +++ b/src/duckdb/src/function/table/system/duckdb_tables.cpp @@ -86,6 +86,18 @@ unique_ptr DuckDBTablesInit(ClientContext &context, Ta return std::move(result); } +static bool TableHasPrimaryKey(TableCatalogEntry &table) { + for (auto &constraint : table.GetConstraints()) { + if (constraint->type == ConstraintType::UNIQUE) { + auto &unique = constraint->Cast(); + if (unique.IsPrimaryKey()) { + return true; + } + } + } + return false; +} + static idx_t CheckConstraintCount(TableCatalogEntry &table) { idx_t check_count = 0; for (auto &constraint : table.GetConstraints()) { @@ -136,7 +148,7 @@ void DuckDBTablesFunction(ClientContext &context, TableFunctionInput &data_p, Da // temporary, LogicalType::BOOLEAN output.SetValue(col++, count, Value::BOOLEAN(table.temporary)); // has_primary_key, LogicalType::BOOLEAN - output.SetValue(col++, count, Value::BOOLEAN(table.HasPrimaryKey())); + output.SetValue(col++, count, Value::BOOLEAN(TableHasPrimaryKey(table))); // estimated_size, LogicalType::BIGINT Value card_val = !storage_info.cardinality.IsValid() diff --git a/src/duckdb/src/function/table/system/duckdb_types.cpp b/src/duckdb/src/function/table/system/duckdb_types.cpp index dd98408b9..3872852d0 100644 --- a/src/duckdb/src/function/table/system/duckdb_types.cpp +++ b/src/duckdb/src/function/table/system/duckdb_types.cpp @@ -184,7 +184,7 @@ void DuckDBTypesFunction(ClientContext &context, TableFunctionInput &data_p, Dat labels.emplace_back(data[i]); } - output.SetValue(col++, count, Value::LIST(LogicalType::VARCHAR, labels)); + output.SetValue(col++, count, Value::LIST(labels)); } else { output.SetValue(col++, count, Value()); } diff --git a/src/duckdb/src/function/table/system/pragma_storage_info.cpp b/src/duckdb/src/function/table/system/pragma_storage_info.cpp index 5500c1c5d..0c33ebf01 100644 --- a/src/duckdb/src/function/table/system/pragma_storage_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_storage_info.cpp @@ -79,9 +79,6 @@ static unique_ptr PragmaStorageInfoBind(ClientContext &context, Ta names.emplace_back("segment_info"); return_types.emplace_back(LogicalType::VARCHAR); - names.emplace_back("additional_block_ids"); - return_types.emplace_back(LogicalType::LIST(LogicalTypeId::BIGINT)); - auto qname = QualifiedName::Parse(input.inputs[0].GetValue()); // look up the table name in the catalog @@ -96,14 +93,6 @@ unique_ptr PragmaStorageInfoInit(ClientContext &contex return make_uniq(); } -static Value ValueFromBlockIdList(const vector &block_ids) { - vector blocks; - for (auto &block_id : block_ids) { - blocks.push_back(Value::BIGINT(block_id)); - } - return Value::LIST(LogicalTypeId::BIGINT, blocks); -} - static void PragmaStorageInfoFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { auto &bind_data = data_p.bind_data->Cast(); auto &data = data_p.global_state->Cast(); @@ -149,12 +138,6 @@ static void PragmaStorageInfoFunction(ClientContext &context, TableFunctionInput } // segment_info output.SetValue(col_idx++, count, Value(entry.segment_info)); - // additional_block_ids - if (entry.persistent) { - output.SetValue(col_idx++, count, ValueFromBlockIdList(entry.additional_blocks)); - } else { - output.SetValue(col_idx++, count, Value()); - } count++; } output.SetCardinality(count); diff --git a/src/duckdb/src/function/table/system/pragma_table_info.cpp b/src/duckdb/src/function/table/system/pragma_table_info.cpp index 56205d900..3e47ff398 100644 --- a/src/duckdb/src/function/table/system/pragma_table_info.cpp +++ b/src/duckdb/src/function/table/system/pragma_table_info.cpp @@ -215,12 +215,6 @@ static ColumnConstraintInfo CheckConstraints(TableCatalogEntry &table, const Col return result; } -void PragmaTableInfo::GetColumnInfo(TableCatalogEntry &table, const ColumnDefinition &column, DataChunk &output, - idx_t index) { - auto constraint_info = CheckConstraints(table, column); - PragmaShowHelper::GetTableColumns(column, constraint_info, output, index); -} - static void PragmaTableInfoTable(PragmaTableOperatorData &data, TableCatalogEntry &table, DataChunk &output, bool is_table_info) { if (data.offset >= table.GetColumns().LogicalColumnCount()) { diff --git a/src/duckdb/src/function/table/system/pragma_table_sample.cpp b/src/duckdb/src/function/table/system/pragma_table_sample.cpp deleted file mode 100644 index 7f4122b92..000000000 --- a/src/duckdb/src/function/table/system/pragma_table_sample.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "duckdb/function/table/system_functions.hpp" - -#include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" -#include "duckdb/parser/qualified_name.hpp" -#include "duckdb/parser/constraints/not_null_constraint.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" -#include "duckdb/planner/expression/bound_parameter_expression.hpp" -#include "duckdb/planner/binder.hpp" - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/limits.hpp" - -#include - -namespace duckdb { - -struct DuckDBTableSampleFunctionData : public TableFunctionData { - explicit DuckDBTableSampleFunctionData(CatalogEntry &entry_p) : entry(entry_p) { - } - CatalogEntry &entry; -}; - -struct DuckDBTableSampleOperatorData : public GlobalTableFunctionState { - DuckDBTableSampleOperatorData() : sample_offset(0) { - sample = nullptr; - } - idx_t sample_offset; - unique_ptr sample; -}; - -static unique_ptr DuckDBTableSampleBind(ClientContext &context, TableFunctionBindInput &input, - vector &return_types, vector &names) { - - // look up the table name in the catalog - auto qname = QualifiedName::Parse(input.inputs[0].GetValue()); - Binder::BindSchemaOrCatalog(context, qname.catalog, qname.schema); - - auto &entry = Catalog::GetEntry(context, CatalogType::TABLE_ENTRY, qname.catalog, qname.schema, qname.name); - if (entry.type != CatalogType::TABLE_ENTRY) { - throw NotImplementedException("Invalid Catalog type passed to table_sample()"); - } - auto &table_entry = entry.Cast(); - auto types = table_entry.GetTypes(); - for (auto &type : types) { - return_types.push_back(type); - } - for (idx_t i = 0; i < types.size(); i++) { - auto logical_index = LogicalIndex(i); - auto &col = table_entry.GetColumn(logical_index); - names.push_back(col.GetName()); - } - - return make_uniq(entry); -} - -unique_ptr DuckDBTableSampleInit(ClientContext &context, TableFunctionInitInput &input) { - return make_uniq(); -} - -static void DuckDBTableSampleTable(ClientContext &context, DuckDBTableSampleOperatorData &data, - TableCatalogEntry &table, DataChunk &output) { - // if table has statistics. - // copy the sample of statistics into the output chunk - if (!data.sample) { - data.sample = table.GetSample(); - } - if (data.sample) { - auto sample_chunk = data.sample->GetChunk(); - if (sample_chunk) { - sample_chunk->Copy(output, 0); - data.sample_offset += sample_chunk->size(); - } - } -} - -static void DuckDBTableSampleFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { - auto &bind_data = data_p.bind_data->Cast(); - auto &state = data_p.global_state->Cast(); - switch (bind_data.entry.type) { - case CatalogType::TABLE_ENTRY: - DuckDBTableSampleTable(context, state, bind_data.entry.Cast(), output); - break; - default: - throw NotImplementedException("Unimplemented catalog type for pragma_table_sample"); - } -} - -void DuckDBTableSample::RegisterFunction(BuiltinFunctions &set) { - set.AddFunction(TableFunction("duckdb_table_sample", {LogicalType::VARCHAR}, DuckDBTableSampleFunction, - DuckDBTableSampleBind, DuckDBTableSampleInit)); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/table/system/test_all_types.cpp b/src/duckdb/src/function/table/system/test_all_types.cpp index 0fbcd884b..2b1e08033 100644 --- a/src/duckdb/src/function/table/system/test_all_types.cpp +++ b/src/duckdb/src/function/table/system/test_all_types.cpp @@ -1,8 +1,7 @@ -#include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/pair.hpp" -#include "duckdb/common/types/bit.hpp" #include "duckdb/common/types/date.hpp" #include "duckdb/common/types/timestamp.hpp" +#include "duckdb/common/types/bit.hpp" #include "duckdb/function/table/system_functions.hpp" #include @@ -100,55 +99,49 @@ vector TestAllTypesFun::GetTestTypes(bool use_large_enum) { // arrays auto int_list_type = LogicalType::LIST(LogicalType::INTEGER); - auto empty_int_list = Value::LIST(LogicalType::INTEGER, vector()); - auto int_list = - Value::LIST(LogicalType::INTEGER, {Value::INTEGER(42), Value::INTEGER(999), Value(LogicalType::INTEGER), - Value(LogicalType::INTEGER), Value::INTEGER(-42)}); + auto empty_int_list = Value::EMPTYLIST(LogicalType::INTEGER); + auto int_list = Value::LIST({Value::INTEGER(42), Value::INTEGER(999), Value(LogicalType::INTEGER), + Value(LogicalType::INTEGER), Value::INTEGER(-42)}); result.emplace_back(int_list_type, "int_array", empty_int_list, int_list); auto double_list_type = LogicalType::LIST(LogicalType::DOUBLE); - auto empty_double_list = Value::LIST(LogicalType::DOUBLE, vector()); - auto double_list = Value::LIST(LogicalType::DOUBLE, {Value::DOUBLE(42), Value::DOUBLE(NAN), - Value::DOUBLE(std::numeric_limits::infinity()), - Value::DOUBLE(-std::numeric_limits::infinity()), - Value(LogicalType::DOUBLE), Value::DOUBLE(-42)}); + auto empty_double_list = Value::EMPTYLIST(LogicalType::DOUBLE); + auto double_list = Value::LIST( + {Value::DOUBLE(42), Value::DOUBLE(NAN), Value::DOUBLE(std::numeric_limits::infinity()), + Value::DOUBLE(-std::numeric_limits::infinity()), Value(LogicalType::DOUBLE), Value::DOUBLE(-42)}); result.emplace_back(double_list_type, "double_array", empty_double_list, double_list); auto date_list_type = LogicalType::LIST(LogicalType::DATE); - auto empty_date_list = Value::LIST(LogicalType::DATE, vector()); - auto date_list = Value::LIST(LogicalType::DATE, {Value::DATE(date_t()), Value::DATE(date_t::infinity()), - Value::DATE(date_t::ninfinity()), Value(LogicalType::DATE), - Value::DATE(Date::FromString("2022-05-12"))}); + auto empty_date_list = Value::EMPTYLIST(LogicalType::DATE); + auto date_list = + Value::LIST({Value::DATE(date_t()), Value::DATE(date_t::infinity()), Value::DATE(date_t::ninfinity()), + Value(LogicalType::DATE), Value::DATE(Date::FromString("2022-05-12"))}); result.emplace_back(date_list_type, "date_array", empty_date_list, date_list); auto timestamp_list_type = LogicalType::LIST(LogicalType::TIMESTAMP); - auto empty_timestamp_list = Value::LIST(LogicalType::TIMESTAMP, vector()); - auto timestamp_list = - Value::LIST(LogicalType::TIMESTAMP, {Value::TIMESTAMP(timestamp_t()), Value::TIMESTAMP(timestamp_t::infinity()), - Value::TIMESTAMP(timestamp_t::ninfinity()), Value(LogicalType::TIMESTAMP), - Value::TIMESTAMP(Timestamp::FromString("2022-05-12 16:23:45"))}); + auto empty_timestamp_list = Value::EMPTYLIST(LogicalType::TIMESTAMP); + auto timestamp_list = Value::LIST({Value::TIMESTAMP(timestamp_t()), Value::TIMESTAMP(timestamp_t::infinity()), + Value::TIMESTAMP(timestamp_t::ninfinity()), Value(LogicalType::TIMESTAMP), + Value::TIMESTAMP(Timestamp::FromString("2022-05-12 16:23:45"))}); result.emplace_back(timestamp_list_type, "timestamp_array", empty_timestamp_list, timestamp_list); auto timestamptz_list_type = LogicalType::LIST(LogicalType::TIMESTAMP_TZ); - auto empty_timestamptz_list = Value::LIST(LogicalType::TIMESTAMP_TZ, vector()); - auto timestamptz_list = - Value::LIST(LogicalType::TIMESTAMP_TZ, - {Value::TIMESTAMPTZ(timestamp_tz_t()), Value::TIMESTAMPTZ(timestamp_tz_t(timestamp_t::infinity())), - Value::TIMESTAMPTZ(timestamp_tz_t(timestamp_t::ninfinity())), Value(LogicalType::TIMESTAMP_TZ), - Value::TIMESTAMPTZ(timestamp_tz_t(Timestamp::FromString("2022-05-12 16:23:45-07")))}); + auto empty_timestamptz_list = Value::EMPTYLIST(LogicalType::TIMESTAMP_TZ); + auto timestamptz_list = Value::LIST({Value::TIMESTAMPTZ(timestamp_t()), Value::TIMESTAMPTZ(timestamp_t::infinity()), + Value::TIMESTAMPTZ(timestamp_t::ninfinity()), Value(LogicalType::TIMESTAMP_TZ), + Value::TIMESTAMPTZ(Timestamp::FromString("2022-05-12 16:23:45-07"))}); result.emplace_back(timestamptz_list_type, "timestamptz_array", empty_timestamptz_list, timestamptz_list); auto varchar_list_type = LogicalType::LIST(LogicalType::VARCHAR); - auto empty_varchar_list = Value::LIST(LogicalType::VARCHAR, vector()); - auto varchar_list = Value::LIST(LogicalType::VARCHAR, {Value("🦆🦆🦆🦆🦆🦆"), Value("goose"), - Value(LogicalType::VARCHAR), Value("")}); + auto empty_varchar_list = Value::EMPTYLIST(LogicalType::VARCHAR); + auto varchar_list = + Value::LIST({Value("🦆🦆🦆🦆🦆🦆"), Value("goose"), Value(LogicalType::VARCHAR), Value("")}); result.emplace_back(varchar_list_type, "varchar_array", empty_varchar_list, varchar_list); // nested arrays auto nested_list_type = LogicalType::LIST(int_list_type); - auto empty_nested_list = Value::LIST(int_list_type, vector()); - auto nested_int_list = - Value::LIST(int_list_type, {empty_int_list, int_list, Value(int_list_type), empty_int_list, int_list}); + auto empty_nested_list = Value::EMPTYLIST(int_list_type); + auto nested_int_list = Value::LIST({empty_int_list, int_list, Value(int_list_type), empty_int_list, int_list}); result.emplace_back(nested_list_type, "nested_int_array", empty_nested_list, nested_int_list); // structs @@ -190,8 +183,8 @@ vector TestAllTypesFun::GetTestTypes(bool use_large_enum) { // array of structs auto array_of_structs_type = LogicalType::LIST(struct_type); - auto min_array_of_struct_val = Value::LIST(struct_type, vector()); - auto max_array_of_struct_val = Value::LIST(struct_type, {min_struct_val, max_struct_val, Value(struct_type)}); + auto min_array_of_struct_val = Value::EMPTYLIST(struct_type); + auto max_array_of_struct_val = Value::LIST({min_struct_val, max_struct_val, Value(struct_type)}); result.emplace_back(array_of_structs_type, "array_of_structs", std::move(min_array_of_struct_val), std::move(max_array_of_struct_val)); @@ -222,42 +215,39 @@ vector TestAllTypesFun::GetTestTypes(bool use_large_enum) { // fixed int array auto fixed_int_array_type = LogicalType::ARRAY(LogicalType::INTEGER, 3); - auto fixed_int_min_array_value = Value::ARRAY(LogicalType::INTEGER, {Value(LogicalType::INTEGER), 2, 3}); - auto fixed_int_max_array_value = Value::ARRAY(LogicalType::INTEGER, {4, 5, 6}); + auto fixed_int_min_array_value = Value::ARRAY({Value(LogicalType::INTEGER), 2, 3}); + auto fixed_int_max_array_value = Value::ARRAY({4, 5, 6}); result.emplace_back(fixed_int_array_type, "fixed_int_array", fixed_int_min_array_value, fixed_int_max_array_value); // fixed varchar array auto fixed_varchar_array_type = LogicalType::ARRAY(LogicalType::VARCHAR, 3); - auto fixed_varchar_min_array_value = - Value::ARRAY(LogicalType::VARCHAR, {Value("a"), Value(LogicalType::VARCHAR), Value("c")}); - auto fixed_varchar_max_array_value = Value::ARRAY(LogicalType::VARCHAR, {Value("d"), Value("e"), Value("f")}); + auto fixed_varchar_min_array_value = Value::ARRAY({Value("a"), Value(LogicalType::VARCHAR), Value("c")}); + auto fixed_varchar_max_array_value = Value::ARRAY({Value("d"), Value("e"), Value("f")}); result.emplace_back(fixed_varchar_array_type, "fixed_varchar_array", fixed_varchar_min_array_value, fixed_varchar_max_array_value); // fixed nested int array auto fixed_nested_int_array_type = LogicalType::ARRAY(fixed_int_array_type, 3); - auto fixed_nested_int_min_array_value = Value::ARRAY( - fixed_int_array_type, {fixed_int_min_array_value, Value(fixed_int_array_type), fixed_int_min_array_value}); - auto fixed_nested_int_max_array_value = Value::ARRAY( - fixed_int_array_type, {fixed_int_max_array_value, fixed_int_min_array_value, fixed_int_max_array_value}); + auto fixed_nested_int_min_array_value = + Value::ARRAY({fixed_int_min_array_value, Value(fixed_int_array_type), fixed_int_min_array_value}); + auto fixed_nested_int_max_array_value = + Value::ARRAY({fixed_int_max_array_value, fixed_int_min_array_value, fixed_int_max_array_value}); result.emplace_back(fixed_nested_int_array_type, "fixed_nested_int_array", fixed_nested_int_min_array_value, fixed_nested_int_max_array_value); // fixed nested varchar array auto fixed_nested_varchar_array_type = LogicalType::ARRAY(fixed_varchar_array_type, 3); auto fixed_nested_varchar_min_array_value = - Value::ARRAY(fixed_varchar_array_type, - {fixed_varchar_min_array_value, Value(fixed_varchar_array_type), fixed_varchar_min_array_value}); + Value::ARRAY({fixed_varchar_min_array_value, Value(fixed_varchar_array_type), fixed_varchar_min_array_value}); auto fixed_nested_varchar_max_array_value = - Value::ARRAY(fixed_varchar_array_type, - {fixed_varchar_max_array_value, fixed_varchar_min_array_value, fixed_varchar_max_array_value}); + Value::ARRAY({fixed_varchar_max_array_value, fixed_varchar_min_array_value, fixed_varchar_max_array_value}); result.emplace_back(fixed_nested_varchar_array_type, "fixed_nested_varchar_array", fixed_nested_varchar_min_array_value, fixed_nested_varchar_max_array_value); // fixed array of structs auto fixed_struct_array_type = LogicalType::ARRAY(struct_type, 3); - auto fixed_struct_min_array_value = Value::ARRAY(struct_type, {min_struct_val, max_struct_val, min_struct_val}); - auto fixed_struct_max_array_value = Value::ARRAY(struct_type, {max_struct_val, min_struct_val, max_struct_val}); + auto fixed_struct_min_array_value = Value::ARRAY({min_struct_val, max_struct_val, min_struct_val}); + auto fixed_struct_max_array_value = Value::ARRAY({max_struct_val, min_struct_val, max_struct_val}); result.emplace_back(fixed_struct_array_type, "fixed_struct_array", fixed_struct_min_array_value, fixed_struct_max_array_value); @@ -272,18 +262,18 @@ vector TestAllTypesFun::GetTestTypes(bool use_large_enum) { struct_of_fixed_array_max_value); // fixed array of list of int - auto fixed_array_of_list_of_int_type = LogicalType::ARRAY(int_list_type, 3); - auto fixed_array_of_list_of_int_min_value = Value::ARRAY(int_list_type, {empty_int_list, int_list, empty_int_list}); - auto fixed_array_of_list_of_int_max_value = Value::ARRAY(int_list_type, {int_list, empty_int_list, int_list}); + auto fixed_array_of_list_of_int_type = LogicalType::ARRAY(LogicalType::LIST(LogicalType::INTEGER), 3); + auto fixed_array_of_list_of_int_min_value = Value::ARRAY({empty_int_list, int_list, empty_int_list}); + auto fixed_array_of_list_of_int_max_value = Value::ARRAY({int_list, empty_int_list, int_list}); result.emplace_back(fixed_array_of_list_of_int_type, "fixed_array_of_int_list", fixed_array_of_list_of_int_min_value, fixed_array_of_list_of_int_max_value); // list of fixed array of int auto list_of_fixed_array_of_int_type = LogicalType::LIST(fixed_int_array_type); - auto list_of_fixed_array_of_int_min_value = Value::LIST( - fixed_int_array_type, {fixed_int_min_array_value, fixed_int_max_array_value, fixed_int_min_array_value}); - auto list_of_fixed_array_of_int_max_value = Value::LIST( - fixed_int_array_type, {fixed_int_max_array_value, fixed_int_min_array_value, fixed_int_max_array_value}); + auto list_of_fixed_array_of_int_min_value = + Value::LIST({fixed_int_min_array_value, fixed_int_max_array_value, fixed_int_min_array_value}); + auto list_of_fixed_array_of_int_max_value = + Value::LIST({fixed_int_max_array_value, fixed_int_min_array_value, fixed_int_max_array_value}); result.emplace_back(list_of_fixed_array_of_int_type, "list_of_fixed_int_array", list_of_fixed_array_of_int_min_value, list_of_fixed_array_of_int_max_value); diff --git a/src/duckdb/src/function/table/system_functions.cpp b/src/duckdb/src/function/table/system_functions.cpp index 7560221c5..12e8bcc35 100644 --- a/src/duckdb/src/function/table/system_functions.cpp +++ b/src/duckdb/src/function/table/system_functions.cpp @@ -34,7 +34,6 @@ void BuiltinFunctions::RegisterSQLiteFunctions() { DuckDBSequencesFun::RegisterFunction(*this); DuckDBSettingsFun::RegisterFunction(*this); DuckDBTablesFun::RegisterFunction(*this); - DuckDBTableSample::RegisterFunction(*this); DuckDBTemporaryFilesFun::RegisterFunction(*this); DuckDBTypesFun::RegisterFunction(*this); DuckDBVariablesFun::RegisterFunction(*this); diff --git a/src/duckdb/src/function/table/table_scan.cpp b/src/duckdb/src/function/table/table_scan.cpp index b36abbb9b..7733bf2b4 100644 --- a/src/duckdb/src/function/table/table_scan.cpp +++ b/src/duckdb/src/function/table/table_scan.cpp @@ -17,569 +17,361 @@ #include "duckdb/storage/table/scan_state.hpp" #include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/transaction/local_storage.hpp" -#include "duckdb/storage/storage_index.hpp" #include "duckdb/main/client_data.hpp" -#include "duckdb/common/algorithm.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" -#include "duckdb/planner/filter/in_filter.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_comparison_expression.hpp" -#include "duckdb/planner/filter/conjunction_filter.hpp" namespace duckdb { +//===--------------------------------------------------------------------===// +// Table Scan +//===--------------------------------------------------------------------===// +bool TableScanParallelStateNext(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, GlobalTableFunctionState *gstate); + struct TableScanLocalState : public LocalTableFunctionState { - //! The current position in the scan. + //! The current position in the scan TableScanState scan_state; - //! The DataChunk containing all read columns. - //! This includes filter columns, which are immediately removed. - DataChunk all_columns; -}; - -struct IndexScanLocalState : public LocalTableFunctionState { - //! The batch index, which determines the offset in the row ID vector. - idx_t batch_index; - //! The DataChunk containing all read columns. - //! This includes filter columns, which are immediately removed. + //! The DataChunk containing all read columns (even filter columns that are immediately removed) DataChunk all_columns; }; -static StorageIndex TransformStorageIndex(const ColumnIndex &column_id) { - vector result; - for (auto &child_id : column_id.GetChildIndexes()) { - result.push_back(TransformStorageIndex(child_id)); +static storage_t GetStorageIndex(TableCatalogEntry &table, column_t column_id) { + if (column_id == DConstants::INVALID_INDEX) { + return column_id; } - return StorageIndex(column_id.GetPrimaryIndex(), std::move(result)); + auto &col = table.GetColumn(LogicalIndex(column_id)); + return col.StorageOid(); } -static StorageIndex GetStorageIndex(TableCatalogEntry &table, const ColumnIndex &column_id) { - if (column_id.IsRowIdColumn()) { - return StorageIndex(); - } - - // The index of the base ColumnIndex is equal to the physical column index in the table - // for any child indices because the indices are already the physical indices. - // Only the top-level can have generated columns. - auto &col = table.GetColumn(column_id.ToLogical()); - auto result = TransformStorageIndex(column_id); - result.SetIndex(col.StorageOid()); - return result; -} - -class TableScanGlobalState : public GlobalTableFunctionState { -public: +struct TableScanGlobalState : public GlobalTableFunctionState { TableScanGlobalState(ClientContext &context, const FunctionData *bind_data_p) { D_ASSERT(bind_data_p); auto &bind_data = bind_data_p->Cast(); max_threads = bind_data.table.GetStorage().MaxThreads(context); } - //! The maximum number of threads for this table scan. + ParallelTableScanState state; idx_t max_threads; - //! The projected columns of this table scan. + vector projection_ids; - //! The types of all scanned columns. vector scanned_types; -public: - virtual unique_ptr InitLocalState(ExecutionContext &context, - TableFunctionInitInput &input) = 0; - virtual void TableScanFunc(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) = 0; - virtual double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p) const = 0; - virtual OperatorPartitionData TableScanGetPartitionData(ClientContext &context, - TableFunctionGetPartitionInput &input) = 0; - idx_t MaxThreads() const override { return max_threads; } + bool CanRemoveFilterColumns() const { return !projection_ids.empty(); } }; -class DuckIndexScanState : public TableScanGlobalState { -public: - DuckIndexScanState(ClientContext &context, const FunctionData *bind_data_p) - : TableScanGlobalState(context, bind_data_p), next_batch_index(0), finished(false) { +static unique_ptr TableScanInitLocal(ExecutionContext &context, TableFunctionInitInput &input, + GlobalTableFunctionState *gstate) { + auto result = make_uniq(); + auto &bind_data = input.bind_data->Cast(); + vector column_ids = input.column_ids; + for (auto &col : column_ids) { + auto storage_idx = GetStorageIndex(bind_data.table, col); + col = storage_idx; } - - //! The batch index of the next Sink. - //! Also determines the offset of the next chunk. I.e., offset = next_batch_index * STANDARD_VECTOR_SIZE. - idx_t next_batch_index; - //! The total scanned row IDs. - unsafe_vector row_ids; - //! The column IDs of the to-be-scanned columns. - vector column_ids; - //! True, if no more row IDs must be scanned. - bool finished; - //! Synchronize changes to the global index scan state. - mutex index_scan_lock; - - ColumnFetchState fetch_state; - TableScanState table_scan_state; - -public: - unique_ptr InitLocalState(ExecutionContext &context, - TableFunctionInitInput &input) override { - auto l_state = make_uniq(); - if (input.CanRemoveFilterColumns()) { - l_state->all_columns.Initialize(context.client, scanned_types); - } - return std::move(l_state); + result->scan_state.Initialize(std::move(column_ids), input.filters.get()); + TableScanParallelStateNext(context.client, input.bind_data.get(), result.get(), gstate); + if (input.CanRemoveFilterColumns()) { + auto &tsgs = gstate->Cast(); + result->all_columns.Initialize(context.client, tsgs.scanned_types); } - void TableScanFunc(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) override { - auto &bind_data = data_p.bind_data->Cast(); - auto &tx = DuckTransaction::Get(context, bind_data.table.catalog); - auto &storage = bind_data.table.GetStorage(); - auto &l_state = data_p.local_state->Cast(); - - auto row_id_count = row_ids.size(); - idx_t scan_count = 0; - idx_t offset = 0; - - { - // Synchronize changes to the shared global state. - lock_guard l(index_scan_lock); - if (!finished) { - l_state.batch_index = next_batch_index; - next_batch_index++; - - offset = l_state.batch_index * STANDARD_VECTOR_SIZE; - auto remaining = row_id_count - offset; - scan_count = remaining < STANDARD_VECTOR_SIZE ? remaining : STANDARD_VECTOR_SIZE; - finished = remaining < STANDARD_VECTOR_SIZE ? true : false; - } - } - - if (scan_count != 0) { - auto row_id_data = (data_ptr_t)&row_ids[0 + offset]; // NOLINT - this is not pretty - Vector local_vector(LogicalType::ROW_TYPE, row_id_data); + result->scan_state.options.force_fetch_row = ClientConfig::GetConfig(context.client).force_fetch_row; - if (CanRemoveFilterColumns()) { - l_state.all_columns.Reset(); - storage.Fetch(tx, l_state.all_columns, column_ids, local_vector, scan_count, fetch_state); - output.ReferenceColumns(l_state.all_columns, projection_ids); - } else { - storage.Fetch(tx, output, column_ids, local_vector, scan_count, fetch_state); - } - } + return std::move(result); +} - if (output.size() == 0) { - auto &local_storage = LocalStorage::Get(tx); - if (CanRemoveFilterColumns()) { - l_state.all_columns.Reset(); - local_storage.Scan(table_scan_state.local_state, column_ids, l_state.all_columns); - output.ReferenceColumns(l_state.all_columns, projection_ids); +unique_ptr TableScanInitGlobal(ClientContext &context, TableFunctionInitInput &input) { + D_ASSERT(input.bind_data); + auto &bind_data = input.bind_data->Cast(); + auto result = make_uniq(context, input.bind_data.get()); + bind_data.table.GetStorage().InitializeParallelScan(context, result->state); + if (input.CanRemoveFilterColumns()) { + result->projection_ids = input.projection_ids; + const auto &columns = bind_data.table.GetColumns(); + for (const auto &col_idx : input.column_ids) { + if (col_idx == COLUMN_IDENTIFIER_ROW_ID) { + result->scanned_types.emplace_back(LogicalType::ROW_TYPE); } else { - local_storage.Scan(table_scan_state.local_state, column_ids, output); + result->scanned_types.push_back(columns.GetColumn(LogicalIndex(col_idx)).Type()); } } } + return std::move(result); +} - double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p) const override { - auto total_rows = row_ids.size(); - if (total_rows == 0) { - return 100; - } - - auto scanned_rows = next_batch_index * STANDARD_VECTOR_SIZE; - auto percentage = 100 * (static_cast(scanned_rows) / static_cast(total_rows)); - return percentage > 100 ? 100 : percentage; - } - - OperatorPartitionData TableScanGetPartitionData(ClientContext &context, - TableFunctionGetPartitionInput &input) override { - auto &l_state = input.local_state->Cast(); - return OperatorPartitionData(l_state.batch_index); - } -}; - -class DuckTableScanState : public TableScanGlobalState { -public: - DuckTableScanState(ClientContext &context, const FunctionData *bind_data_p) - : TableScanGlobalState(context, bind_data_p) { - } - - ParallelTableScanState state; - -public: - unique_ptr InitLocalState(ExecutionContext &context, - TableFunctionInitInput &input) override { - auto &bind_data = input.bind_data->Cast(); - auto l_state = make_uniq(); - - vector storage_ids; - for (auto &col : input.column_indexes) { - storage_ids.push_back(GetStorageIndex(bind_data.table, col)); - } - - l_state->scan_state.Initialize(std::move(storage_ids), input.filters.get(), input.sample_options.get()); - - auto &storage = bind_data.table.GetStorage(); - storage.NextParallelScan(context.client, state, l_state->scan_state); - if (input.CanRemoveFilterColumns()) { - l_state->all_columns.Initialize(context.client, scanned_types); - } - - l_state->scan_state.options.force_fetch_row = ClientConfig::GetConfig(context.client).force_fetch_row; - return std::move(l_state); - } - - void TableScanFunc(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) override { - auto &bind_data = data_p.bind_data->Cast(); - auto &tx = DuckTransaction::Get(context, bind_data.table.catalog); - auto &storage = bind_data.table.GetStorage(); - - auto &l_state = data_p.local_state->Cast(); - l_state.scan_state.options.force_fetch_row = ClientConfig::GetConfig(context).force_fetch_row; - - do { - if (bind_data.is_create_index) { - storage.CreateIndexScan(l_state.scan_state, output, - TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED); - } else if (CanRemoveFilterColumns()) { - l_state.all_columns.Reset(); - storage.Scan(tx, l_state.all_columns, l_state.scan_state); - output.ReferenceColumns(l_state.all_columns, projection_ids); - } else { - storage.Scan(tx, output, l_state.scan_state); - } - if (output.size() > 0) { - return; - } - - auto next = storage.NextParallelScan(context, state, l_state.scan_state); - if (!next) { - return; - } - } while (true); +static unique_ptr TableScanStatistics(ClientContext &context, const FunctionData *bind_data_p, + column_t column_id) { + auto &bind_data = bind_data_p->Cast(); + auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); + if (local_storage.Find(bind_data.table.GetStorage())) { + // we don't emit any statistics for tables that have outstanding transaction-local data + return nullptr; } + return bind_data.table.GetStatistics(context, column_id); +} - double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p) const override { - auto &bind_data = bind_data_p->Cast(); - auto &storage = bind_data.table.GetStorage(); - auto total_rows = storage.GetTotalRows(); - - // The table is empty or smaller than the standard vector size. - if (total_rows == 0) { - return 100; - } +static void TableScanFunc(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { + auto &bind_data = data_p.bind_data->Cast(); + auto &gstate = data_p.global_state->Cast(); + auto &state = data_p.local_state->Cast(); + auto &transaction = DuckTransaction::Get(context, bind_data.table.catalog); + auto &storage = bind_data.table.GetStorage(); - idx_t scanned_rows = state.scan_state.processed_rows; - scanned_rows += state.local_state.processed_rows; - auto percentage = 100 * (static_cast(scanned_rows) / static_cast(total_rows)); - if (percentage > 100) { - // If the last chunk has fewer elements than STANDARD_VECTOR_SIZE, and if our percentage is over 100, - // then we finished this table. - return 100; + state.scan_state.options.force_fetch_row = ClientConfig::GetConfig(context).force_fetch_row; + do { + if (bind_data.is_create_index) { + storage.CreateIndexScan(state.scan_state, output, + TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED); + } else if (gstate.CanRemoveFilterColumns()) { + state.all_columns.Reset(); + storage.Scan(transaction, state.all_columns, state.scan_state); + output.ReferenceColumns(state.all_columns, gstate.projection_ids); + } else { + storage.Scan(transaction, output, state.scan_state); } - return percentage; - } - - OperatorPartitionData TableScanGetPartitionData(ClientContext &context, - TableFunctionGetPartitionInput &input) override { - auto &l_state = input.local_state->Cast(); - if (l_state.scan_state.table_state.row_group) { - return OperatorPartitionData(l_state.scan_state.table_state.batch_index); + if (output.size() > 0) { + return; } - if (l_state.scan_state.local_state.row_group) { - return OperatorPartitionData(l_state.scan_state.table_state.batch_index + - l_state.scan_state.local_state.batch_index); + if (!TableScanParallelStateNext(context, data_p.bind_data.get(), data_p.local_state.get(), + data_p.global_state.get())) { + return; } - return OperatorPartitionData(0); - } -}; - -static unique_ptr TableScanInitLocal(ExecutionContext &context, TableFunctionInitInput &input, - GlobalTableFunctionState *g_state) { - auto &cast_g_state = g_state->Cast(); - return cast_g_state.InitLocalState(context, input); + } while (true); } -unique_ptr DuckTableScanInitGlobal(ClientContext &context, TableFunctionInitInput &input, - DataTable &storage, const TableScanBindData &bind_data) { - auto g_state = make_uniq(context, input.bind_data.get()); - storage.InitializeParallelScan(context, g_state->state); - if (!input.CanRemoveFilterColumns()) { - return std::move(g_state); - } +bool TableScanParallelStateNext(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state) { + auto &bind_data = bind_data_p->Cast(); + auto ¶llel_state = global_state->Cast(); + auto &state = local_state->Cast(); + auto &storage = bind_data.table.GetStorage(); - g_state->projection_ids = input.projection_ids; - const auto &columns = bind_data.table.GetColumns(); - for (const auto &col_idx : input.column_indexes) { - if (col_idx.IsRowIdColumn()) { - g_state->scanned_types.emplace_back(LogicalType::ROW_TYPE); - } else { - g_state->scanned_types.push_back(columns.GetColumn(col_idx.ToLogical()).Type()); - } - } - return std::move(g_state); + return storage.NextParallelScan(context, parallel_state.state, state.scan_state); } -unique_ptr DuckIndexScanInitGlobal(ClientContext &context, TableFunctionInitInput &input, - DataTable &storage, const TableScanBindData &bind_data, - unsafe_vector &row_ids) { - auto g_state = make_uniq(context, input.bind_data.get()); - if (!row_ids.empty()) { - std::sort(row_ids.begin(), row_ids.end()); - g_state->row_ids = std::move(row_ids); - } - g_state->finished = g_state->row_ids.empty() ? true : false; - - auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); - g_state->table_scan_state.options.force_fetch_row = ClientConfig::GetConfig(context).force_fetch_row; +double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p, + const GlobalTableFunctionState *gstate_p) { + auto &bind_data = bind_data_p->Cast(); + auto &gstate = gstate_p->Cast(); + auto &storage = bind_data.table.GetStorage(); + idx_t total_rows = storage.GetTotalRows(); + if (total_rows == 0) { + //! Table is either empty or smaller than a vector size, so it is finished + return 100; + } + idx_t scanned_rows = gstate.state.scan_state.processed_rows; + scanned_rows += gstate.state.local_state.processed_rows; + auto percentage = 100 * (static_cast(scanned_rows) / static_cast(total_rows)); + if (percentage > 100) { + //! In case the last chunk has less elements than STANDARD_VECTOR_SIZE, if our percentage is over 100 + //! It means we finished this table. + return 100; + } + return percentage; +} - if (input.CanRemoveFilterColumns()) { - g_state->projection_ids = input.projection_ids; +idx_t TableScanGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, GlobalTableFunctionState *gstate_p) { + auto &state = local_state->Cast(); + if (state.scan_state.table_state.row_group) { + return state.scan_state.table_state.batch_index; } - - const auto &columns = bind_data.table.GetColumns(); - for (const auto &col_idx : input.column_indexes) { - g_state->column_ids.push_back(GetStorageIndex(bind_data.table, col_idx)); - if (col_idx.IsRowIdColumn()) { - g_state->scanned_types.emplace_back(LogicalType::ROW_TYPE); - continue; - } - g_state->scanned_types.push_back(columns.GetColumn(col_idx.ToLogical()).Type()); + if (state.scan_state.local_state.row_group) { + return state.scan_state.table_state.batch_index + state.scan_state.local_state.batch_index; } + return 0; +} - g_state->table_scan_state.Initialize(g_state->column_ids, input.filters.get()); - local_storage.InitializeScan(storage, g_state->table_scan_state.local_state, input.filters); +BindInfo TableScanGetBindInfo(const optional_ptr bind_data_p) { + auto &bind_data = bind_data_p->Cast(); + return BindInfo(bind_data.table); +} - // Const-cast to indicate an index scan. - // We need this information in the bind data so that we can access it during ANALYZE. - auto &no_const_bind_data = bind_data.CastNoConst(); - no_const_bind_data.is_index_scan = true; +void TableScanDependency(LogicalDependencyList &entries, const FunctionData *bind_data_p) { + auto &bind_data = bind_data_p->Cast(); + entries.AddDependency(bind_data.table); +} - return std::move(g_state); +unique_ptr TableScanCardinality(ClientContext &context, const FunctionData *bind_data_p) { + auto &bind_data = bind_data_p->Cast(); + auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); + auto &storage = bind_data.table.GetStorage(); + idx_t table_rows = storage.GetTotalRows(); + idx_t estimated_cardinality = table_rows + local_storage.AddedRows(bind_data.table.GetStorage()); + return make_uniq(table_rows, estimated_cardinality); } -void ExtractInFilter(unique_ptr &filter, BoundColumnRefExpression &bound_ref, - unique_ptr>> &filter_expressions) { - // Special-handling of IN filters. - // They are part of a CONJUNCTION_AND. - if (filter->filter_type != TableFilterType::CONJUNCTION_AND) { - return; +//===--------------------------------------------------------------------===// +// Index Scan +//===--------------------------------------------------------------------===// +struct IndexScanGlobalState : public GlobalTableFunctionState { + IndexScanGlobalState(const data_ptr_t row_id_data, const idx_t count) + : row_ids(LogicalType::ROW_TYPE, row_id_data), row_ids_count(count), row_ids_offset(0) { } - auto &and_filter = filter->Cast(); - auto &children = and_filter.child_filters; - if (children.empty()) { - return; - } - if (children[0]->filter_type != TableFilterType::OPTIONAL_FILTER) { - return; - } + const Vector row_ids; + const idx_t row_ids_count; + idx_t row_ids_offset; + ColumnFetchState fetch_state; + TableScanState local_storage_state; + vector column_ids; + bool finished; +}; - auto &optional_filter = children[0]->Cast(); - auto &child = optional_filter.child_filter; - if (child->filter_type != TableFilterType::IN_FILTER) { - return; - } +static unique_ptr IndexScanInitGlobal(ClientContext &context, TableFunctionInitInput &input) { + auto &bind_data = input.bind_data->Cast(); - auto &in_filter = child->Cast(); - if (!in_filter.origin_is_hash_join) { - return; + data_ptr_t row_id_data = nullptr; + if (!bind_data.row_ids.empty()) { + row_id_data = (data_ptr_t)&bind_data.row_ids[0]; // NOLINT - this is not pretty } - // They are all on the same column, so we can split them. - for (const auto &value : in_filter.values) { - auto bound_constant = make_uniq(value); - auto filter_expr = make_uniq(ExpressionType::COMPARE_EQUAL, bound_ref.Copy(), - std::move(bound_constant)); - filter_expressions->push_back(std::move(filter_expr)); - } -} + auto result = make_uniq(row_id_data, bind_data.row_ids.size()); + auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); -unique_ptr>> ExtractFilters(const ColumnDefinition &col, unique_ptr &filter, - idx_t storage_idx) { - ColumnBinding binding(0, storage_idx); - auto bound_ref = make_uniq(col.Name(), col.Type(), binding); + result->local_storage_state.options.force_fetch_row = ClientConfig::GetConfig(context).force_fetch_row; + result->column_ids.reserve(input.column_ids.size()); + for (auto &id : input.column_ids) { + result->column_ids.push_back(GetStorageIndex(bind_data.table, id)); + } - auto filter_expressions = make_uniq>>(); - ExtractInFilter(filter, *bound_ref, filter_expressions); + result->local_storage_state.Initialize(result->column_ids, input.filters.get()); + local_storage.InitializeScan(bind_data.table.GetStorage(), result->local_storage_state.local_state, input.filters); - if (filter_expressions->empty()) { - auto filter_expr = filter->ToExpression(*bound_ref); - filter_expressions->push_back(std::move(filter_expr)); - } - return filter_expressions; + result->finished = false; + return std::move(result); } -bool TryScanIndex(ART &art, const ColumnList &column_list, TableFunctionInitInput &input, TableFilterSet &filter_set, - idx_t max_count, unsafe_vector &row_ids) { - // FIXME: No support for index scans on compound ARTs. - // See note above on multi-filter support. - if (art.unbound_expressions.size() > 1) { - return false; - } +static void IndexScanFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { + auto &bind_data = data_p.bind_data->Cast(); + auto &state = data_p.global_state->Cast(); + auto &transaction = DuckTransaction::Get(context, bind_data.table.catalog); + auto &local_storage = LocalStorage::Get(transaction); - auto index_expr = art.unbound_expressions[0]->Copy(); - auto &indexed_columns = art.GetColumnIds(); + if (!state.finished) { + auto remaining = state.row_ids_count - state.row_ids_offset; + auto scan_count = remaining < STANDARD_VECTOR_SIZE ? remaining : STANDARD_VECTOR_SIZE; - // NOTE: We do not push down multi-column filters, e.g., 42 = a + b. - if (indexed_columns.size() != 1) { - return false; - } - - // Get ART column. - auto &col = column_list.GetColumn(LogicalIndex(indexed_columns[0])); + Vector row_ids(state.row_ids, state.row_ids_offset, state.row_ids_offset + scan_count); + bind_data.table.GetStorage().Fetch(transaction, output, state.column_ids, row_ids, scan_count, + state.fetch_state); - // The indexes of the filters match input.column_indexes, which are: i -> column_index. - // Try to find a filter on the ART column. - optional_idx storage_index; - for (idx_t i = 0; i < input.column_indexes.size(); i++) { - if (input.column_indexes[i].ToLogical() == col.Logical()) { - storage_index = i; - break; + state.row_ids_offset += scan_count; + if (state.row_ids_offset == state.row_ids_count) { + state.finished = true; } } - - // No filter matches the ART column. - if (!storage_index.IsValid()) { - return false; - } - - // Try to find a matching filter for the column. - auto filter = filter_set.filters.find(storage_index.GetIndex()); - if (filter == filter_set.filters.end()) { - return false; + if (output.size() == 0) { + local_storage.Scan(state.local_storage_state.local_state, state.column_ids, output); } +} - auto filter_expressions = ExtractFilters(col, filter->second, storage_index.GetIndex()); - for (const auto &filter_expr : *filter_expressions) { - auto scan_state = art.TryInitializeScan(*index_expr, *filter_expr); - if (!scan_state) { - return false; - } - - // Check if we can use an index scan, and already retrieve the matching row ids. - if (!art.Scan(*scan_state, max_count, row_ids)) { - row_ids.clear(); - return false; +static void RewriteIndexExpression(Index &index, LogicalGet &get, Expression &expr, bool &rewrite_possible) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { + auto &bound_colref = expr.Cast(); + // bound column ref: rewrite to fit in the current set of bound column ids + bound_colref.binding.table_index = get.table_index; + auto &column_ids = index.GetColumnIds(); + auto &get_column_ids = get.GetColumnIds(); + column_t referenced_column = column_ids[bound_colref.binding.column_index]; + // search for the referenced column in the set of column_ids + for (idx_t i = 0; i < get_column_ids.size(); i++) { + if (get_column_ids[i] == referenced_column) { + bound_colref.binding.column_index = i; + return; + } } + // column id not found in bound columns in the LogicalGet: rewrite not possible + rewrite_possible = false; } - return true; + ExpressionIterator::EnumerateChildren( + expr, [&](Expression &child) { RewriteIndexExpression(index, get, child, rewrite_possible); }); } -unique_ptr TableScanInitGlobal(ClientContext &context, TableFunctionInitInput &input) { - D_ASSERT(input.bind_data); - - auto &bind_data = input.bind_data->Cast(); +void TableScanPushdownComplexFilter(ClientContext &context, LogicalGet &get, FunctionData *bind_data_p, + vector> &filters) { + auto &bind_data = bind_data_p->Cast(); auto &table = bind_data.table; auto &storage = table.GetStorage(); - // Can't index scan without filters. - if (!input.filters) { - return DuckTableScanInitGlobal(context, input, storage, bind_data); - } - auto &filter_set = *input.filters; - - // FIXME: We currently only support scanning one ART with one filter. - // If multiple filters exist, i.e., a = 11 AND b = 24, we need to - // 1. 1.1. Find + scan one ART for a = 11. - // 1.2. Find + scan one ART for b = 24. - // 1.3. Return the intersecting row IDs. - // 2. (Reorder and) scan a single ART with a compound key of (a, b). - if (filter_set.filters.size() != 1) { - return DuckTableScanInitGlobal(context, input, storage, bind_data); + auto &config = ClientConfig::GetConfig(context); + if (!config.enable_optimizer) { + // we only push index scans if the optimizer is enabled + return; } - - // The checkpoint lock ensures that we do not checkpoint while scanning this table. - auto checkpoint_lock = storage.GetSharedCheckpointLock(); - auto &info = storage.GetDataTableInfo(); - auto &indexes = info->GetIndexes(); - if (indexes.Empty()) { - return DuckTableScanInitGlobal(context, input, storage, bind_data); + if (bind_data.is_index_scan) { + return; } - - auto &db_config = DBConfig::GetConfig(context); - auto scan_percentage = db_config.GetSetting(context); - auto scan_max_count = db_config.GetSetting(context); - - auto total_rows = storage.GetTotalRows(); - auto total_rows_from_percentage = LossyNumericCast(double(total_rows) * scan_percentage); - auto max_count = MaxValue(scan_max_count, total_rows_from_percentage); - - auto &column_list = table.GetColumns(); - bool index_scan = false; - unsafe_vector row_ids; - - info->GetIndexes().BindAndScan(context, *info, [&](ART &art) { - index_scan = TryScanIndex(art, column_list, input, filter_set, max_count, row_ids); - return index_scan; - }); - - if (!index_scan) { - return DuckTableScanInitGlobal(context, input, storage, bind_data); + if (!get.table_filters.filters.empty()) { + // if there were filters before we can't convert this to an index scan + return; } - return DuckIndexScanInitGlobal(context, input, storage, bind_data, row_ids); -} - -static unique_ptr TableScanStatistics(ClientContext &context, const FunctionData *bind_data_p, - column_t column_id) { - auto &bind_data = bind_data_p->Cast(); - auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); - - // Don't emit statistics for tables with outstanding transaction-local data. - if (local_storage.Find(bind_data.table.GetStorage())) { - return nullptr; + if (!get.projection_ids.empty()) { + // if columns were pruned by RemoveUnusedColumns we can't convert this to an index scan, + // because index scan does not support filter_prune (yet) + return; } - return bind_data.table.GetStatistics(context, column_id); -} - -static void TableScanFunc(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { - auto &g_state = data_p.global_state->Cast(); - g_state.TableScanFunc(context, data_p, output); -} - -double TableScanProgress(ClientContext &context, const FunctionData *bind_data_p, - const GlobalTableFunctionState *g_state_p) { - auto &g_state = g_state_p->Cast(); - return g_state.TableScanProgress(context, bind_data_p); -} - -OperatorPartitionData TableScanGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input) { - if (input.partition_info.RequiresPartitionColumns()) { - throw InternalException("TableScan::GetPartitionData: partition columns not supported"); + if (filters.empty()) { + // no indexes or no filters: skip the pushdown + return; } - auto &g_state = input.global_state->Cast(); - return g_state.TableScanGetPartitionData(context, input); -} + auto checkpoint_lock = storage.GetSharedCheckpointLock(); + auto &info = storage.GetDataTableInfo(); -vector TableScanGetPartitionStats(ClientContext &context, GetPartitionStatsInput &input) { - auto &bind_data = input.bind_data->Cast(); - vector result; - auto &storage = bind_data.table.GetStorage(); - return storage.GetPartitionStats(context); -} + // bind and scan any ART indexes + info->GetIndexes().BindAndScan(context, *info, [&](ART &art_index) { + // first rewrite the index expression so the ColumnBindings align with the column bindings of the current table + if (art_index.unbound_expressions.size() > 1) { + // NOTE: index scans are not (yet) supported for compound index keys + return false; + } -BindInfo TableScanGetBindInfo(const optional_ptr bind_data_p) { - auto &bind_data = bind_data_p->Cast(); - return BindInfo(bind_data.table); -} + auto index_expression = art_index.unbound_expressions[0]->Copy(); + bool rewrite_possible = true; + RewriteIndexExpression(art_index, get, *index_expression, rewrite_possible); + if (!rewrite_possible) { + // could not rewrite! + return false; + } -void TableScanDependency(LogicalDependencyList &entries, const FunctionData *bind_data_p) { - auto &bind_data = bind_data_p->Cast(); - entries.AddDependency(bind_data.table); + // Try to find a matching index for any of the filter expressions. + for (auto &filter : filters) { + auto index_state = art_index.TryInitializeScan(*index_expression, *filter); + if (index_state != nullptr) { + + auto &db_config = DBConfig::GetConfig(context); + auto index_scan_percentage = db_config.options.index_scan_percentage; + auto index_scan_max_count = db_config.options.index_scan_max_count; + + auto total_rows = storage.GetTotalRows(); + auto total_rows_from_percentage = LossyNumericCast(double(total_rows) * index_scan_percentage); + auto max_count = MaxValue(index_scan_max_count, total_rows_from_percentage); + + // Check if we can use an index scan, and already retrieve the matching row ids. + if (art_index.Scan(*index_state, max_count, bind_data.row_ids)) { + bind_data.is_index_scan = true; + get.function = TableScanFunction::GetIndexScanFunction(); + return true; + } + + // Clear the row ids in case we exceeded the maximum count and stopped scanning. + bind_data.row_ids.clear(); + return true; + } + } + return false; + }); } -unique_ptr TableScanCardinality(ClientContext &context, const FunctionData *bind_data_p) { +string TableScanToString(const FunctionData *bind_data_p) { auto &bind_data = bind_data_p->Cast(); - auto &local_storage = LocalStorage::Get(context, bind_data.table.catalog); - auto &storage = bind_data.table.GetStorage(); - idx_t table_rows = storage.GetTotalRows(); - idx_t estimated_cardinality = table_rows + local_storage.AddedRows(bind_data.table.GetStorage()); - return make_uniq(table_rows, estimated_cardinality); -} - -InsertionOrderPreservingMap TableScanToString(TableFunctionToStringInput &input) { - InsertionOrderPreservingMap result; - auto &bind_data = input.bind_data->Cast(); - result["Table"] = bind_data.table.name; - result["Type"] = bind_data.is_index_scan ? "Index Scan" : "Sequence Scan"; + string result = bind_data.table.name; return result; } @@ -591,7 +383,7 @@ static void TableScanSerialize(Serializer &serializer, const optional_ptr()); + serializer.WriteProperty(105, "result_ids", bind_data.row_ids); } static unique_ptr TableScanDeserialize(Deserializer &deserializer, TableFunction &function) { @@ -606,10 +398,29 @@ static unique_ptr TableScanDeserialize(Deserializer &deserializer, auto result = make_uniq(catalog_entry.Cast()); deserializer.ReadProperty(103, "is_index_scan", result->is_index_scan); deserializer.ReadProperty(104, "is_create_index", result->is_create_index); - deserializer.ReadDeletedProperty>(105, "result_ids"); + deserializer.ReadProperty(105, "result_ids", result->row_ids); return std::move(result); } +TableFunction TableScanFunction::GetIndexScanFunction() { + TableFunction scan_function("index_scan", {}, IndexScanFunction); + scan_function.init_local = nullptr; + scan_function.init_global = IndexScanInitGlobal; + scan_function.statistics = TableScanStatistics; + scan_function.dependency = TableScanDependency; + scan_function.cardinality = TableScanCardinality; + scan_function.pushdown_complex_filter = nullptr; + scan_function.to_string = TableScanToString; + scan_function.table_scan_progress = nullptr; + scan_function.get_batch_index = nullptr; + scan_function.projection_pushdown = true; + scan_function.filter_pushdown = false; + scan_function.get_bind_info = TableScanGetBindInfo; + scan_function.serialize = TableScanSerialize; + scan_function.deserialize = TableScanDeserialize; + return scan_function; +} + TableFunction TableScanFunction::GetFunction() { TableFunction scan_function("seq_scan", {}, TableScanFunc); scan_function.init_local = TableScanInitLocal; @@ -617,16 +428,14 @@ TableFunction TableScanFunction::GetFunction() { scan_function.statistics = TableScanStatistics; scan_function.dependency = TableScanDependency; scan_function.cardinality = TableScanCardinality; - scan_function.pushdown_complex_filter = nullptr; + scan_function.pushdown_complex_filter = TableScanPushdownComplexFilter; scan_function.to_string = TableScanToString; scan_function.table_scan_progress = TableScanProgress; - scan_function.get_partition_data = TableScanGetPartitionData; - scan_function.get_partition_stats = TableScanGetPartitionStats; + scan_function.get_batch_index = TableScanGetBatchIndex; scan_function.get_bind_info = TableScanGetBindInfo; scan_function.projection_pushdown = true; scan_function.filter_pushdown = true; scan_function.filter_prune = true; - scan_function.sampling_pushdown = true; scan_function.serialize = TableScanSerialize; scan_function.deserialize = TableScanDeserialize; return scan_function; @@ -636,6 +445,8 @@ void TableScanFunction::RegisterFunction(BuiltinFunctions &set) { TableFunctionSet table_scan_set("seq_scan"); table_scan_set.AddFunction(GetFunction()); set.AddFunction(std::move(table_scan_set)); + + set.AddFunction(GetIndexScanFunction()); } void BuiltinFunctions::RegisterTableScanFunctions() { diff --git a/src/duckdb/src/function/table/version/pragma_version.cpp b/src/duckdb/src/function/table/version/pragma_version.cpp index bc8341084..04fac00bd 100644 --- a/src/duckdb/src/function/table/version/pragma_version.cpp +++ b/src/duckdb/src/function/table/version/pragma_version.cpp @@ -1,5 +1,5 @@ #ifndef DUCKDB_PATCH_VERSION -#define DUCKDB_PATCH_VERSION "4-dev4329" +#define DUCKDB_PATCH_VERSION "3" #endif #ifndef DUCKDB_MINOR_VERSION #define DUCKDB_MINOR_VERSION 1 @@ -8,10 +8,10 @@ #define DUCKDB_MAJOR_VERSION 1 #endif #ifndef DUCKDB_VERSION -#define DUCKDB_VERSION "v1.1.4-dev4329" +#define DUCKDB_VERSION "v1.1.3" #endif #ifndef DUCKDB_SOURCE_ID -#define DUCKDB_SOURCE_ID "a1c7e9b115" +#define DUCKDB_SOURCE_ID "19864453f7" #endif #include "duckdb/function/table/system_functions.hpp" #include "duckdb/main/database.hpp" diff --git a/src/duckdb/src/function/table_function.cpp b/src/duckdb/src/function/table_function.cpp index 6e9df8194..a5190aeea 100644 --- a/src/duckdb/src/function/table_function.cpp +++ b/src/duckdb/src/function/table_function.cpp @@ -8,9 +8,6 @@ GlobalTableFunctionState::~GlobalTableFunctionState() { LocalTableFunctionState::~LocalTableFunctionState() { } -PartitionStatistics::PartitionStatistics() : row_start(0), count(0), count_type(CountType::COUNT_APPROXIMATE) { -} - TableFunctionInfo::~TableFunctionInfo() { } @@ -20,10 +17,10 @@ TableFunction::TableFunction(string name, vector arguments, table_f : SimpleNamedParameterFunction(std::move(name), std::move(arguments)), bind(bind), bind_replace(nullptr), init_global(init_global), init_local(init_local), function(function), in_out_function(nullptr), in_out_function_final(nullptr), statistics(nullptr), dependency(nullptr), cardinality(nullptr), - pushdown_complex_filter(nullptr), to_string(nullptr), table_scan_progress(nullptr), get_partition_data(nullptr), + pushdown_complex_filter(nullptr), to_string(nullptr), table_scan_progress(nullptr), get_batch_index(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), supports_pushdown_type(nullptr), - get_partition_info(nullptr), get_partition_stats(nullptr), serialize(nullptr), deserialize(nullptr), - projection_pushdown(false), filter_pushdown(false), filter_prune(false), sampling_pushdown(false) { + serialize(nullptr), deserialize(nullptr), projection_pushdown(false), filter_pushdown(false), + filter_prune(false) { } TableFunction::TableFunction(const vector &arguments, table_function_t function, @@ -35,10 +32,9 @@ TableFunction::TableFunction() : SimpleNamedParameterFunction("", {}), bind(nullptr), bind_replace(nullptr), init_global(nullptr), init_local(nullptr), function(nullptr), in_out_function(nullptr), statistics(nullptr), dependency(nullptr), cardinality(nullptr), pushdown_complex_filter(nullptr), to_string(nullptr), table_scan_progress(nullptr), - get_partition_data(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), - supports_pushdown_type(nullptr), get_partition_info(nullptr), get_partition_stats(nullptr), serialize(nullptr), - deserialize(nullptr), projection_pushdown(false), filter_pushdown(false), filter_prune(false), - sampling_pushdown(false) { + get_batch_index(nullptr), get_bind_info(nullptr), type_pushdown(nullptr), get_multi_file_reader(nullptr), + supports_pushdown_type(nullptr), serialize(nullptr), deserialize(nullptr), projection_pushdown(false), + filter_pushdown(false), filter_prune(false) { } bool TableFunction::Equal(const TableFunction &rhs) const { diff --git a/src/duckdb/src/function/window/window_aggregate_function.cpp b/src/duckdb/src/function/window/window_aggregate_function.cpp deleted file mode 100644 index f08fc5dbc..000000000 --- a/src/duckdb/src/function/window/window_aggregate_function.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include "duckdb/function/window/window_aggregate_function.hpp" - -#include "duckdb/function/window/window_constant_aggregator.hpp" -#include "duckdb/function/window/window_custom_aggregator.hpp" -#include "duckdb/function/window/window_distinct_aggregator.hpp" -#include "duckdb/function/window/window_naive_aggregator.hpp" -#include "duckdb/function/window/window_segment_tree.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/planner/expression/bound_reference_expression.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowAggregateExecutor -//===--------------------------------------------------------------------===// -class WindowAggregateExecutorGlobalState : public WindowExecutorGlobalState { -public: - WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask); - - // aggregate global state - unique_ptr gsink; - - // the filter reference expression. - const Expression *filter_ref; -}; - -static BoundWindowExpression &SimplifyWindowedAggregate(BoundWindowExpression &wexpr, ClientContext &context) { - // Remove redundant/irrelevant modifiers (they can be serious performance cliffs) - if (wexpr.aggregate && ClientConfig::GetConfig(context).enable_optimizer) { - const auto &aggr = wexpr.aggregate; - auto &arg_orders = wexpr.arg_orders; - if (aggr->distinct_dependent != AggregateDistinctDependent::DISTINCT_DEPENDENT) { - wexpr.distinct = false; - } - if (aggr->order_dependent != AggregateOrderDependent::ORDER_DEPENDENT) { - arg_orders.clear(); - } else { - // If the argument order is prefix of the partition ordering, - // then we can just use the partition ordering. - if (BoundWindowExpression::GetSharedOrders(wexpr.orders, arg_orders) == arg_orders.size()) { - arg_orders.clear(); - } - } - } - - return wexpr; -} - -WindowAggregateExecutor::WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared, WindowAggregationMode mode) - : WindowExecutor(SimplifyWindowedAggregate(wexpr, context), context, shared), mode(mode) { - - // Force naive for SEPARATE mode or for (currently!) unsupported functionality - if (!ClientConfig::GetConfig(context).enable_optimizer || mode == WindowAggregationMode::SEPARATE) { - aggregator = make_uniq(*this, shared); - } else if (WindowDistinctAggregator::CanAggregate(wexpr)) { - // build a merge sort tree - // see https://dl.acm.org/doi/pdf/10.1145/3514221.3526184 - aggregator = make_uniq(wexpr, shared, context); - } else if (WindowConstantAggregator::CanAggregate(wexpr)) { - aggregator = make_uniq(wexpr, shared, context); - } else if (WindowCustomAggregator::CanAggregate(wexpr, mode)) { - aggregator = make_uniq(wexpr, shared); - } else if (WindowSegmentTree::CanAggregate(wexpr)) { - // build a segment tree for frame-adhering aggregates - // see http://www.vldb.org/pvldb/vol8/p1058-leis.pdf - aggregator = make_uniq(wexpr, shared); - } else { - // No accelerator can handle this combination, so fall back to naïve. - aggregator = make_uniq(*this, shared); - } - - // Compute the FILTER with the other eval columns. - // Anyone who needs it can then convert it to the form they need. - if (wexpr.filter_expr) { - const auto filter_idx = shared.RegisterSink(wexpr.filter_expr); - filter_ref = make_uniq(wexpr.filter_expr->return_type, filter_idx); - } -} - -WindowAggregateExecutorGlobalState::WindowAggregateExecutorGlobalState(const WindowAggregateExecutor &executor, - const idx_t group_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, group_count, partition_mask, order_mask), - filter_ref(executor.filter_ref.get()) { - gsink = executor.aggregator->GetGlobalState(executor.context, group_count, partition_mask); -} - -unique_ptr WindowAggregateExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -class WindowAggregateExecutorLocalState : public WindowExecutorBoundsState { -public: - WindowAggregateExecutorLocalState(const WindowExecutorGlobalState &gstate, const WindowAggregator &aggregator) - : WindowExecutorBoundsState(gstate), filter_executor(gstate.executor.context) { - - auto &gastate = gstate.Cast(); - aggregator_state = aggregator.GetLocalState(*gastate.gsink); - - // evaluate the FILTER clause and stuff it into a large mask for compactness and reuse - auto filter_ref = gastate.filter_ref; - if (filter_ref) { - filter_executor.AddExpression(*filter_ref); - filter_sel.Initialize(STANDARD_VECTOR_SIZE); - } - } - -public: - // state of aggregator - unique_ptr aggregator_state; - //! Executor for any filter clause - ExpressionExecutor filter_executor; - //! Result of filtering - SelectionVector filter_sel; -}; - -unique_ptr -WindowAggregateExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - return make_uniq(gstate, *aggregator); -} - -void WindowAggregateExecutor::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, - WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { - auto &gastate = gstate.Cast(); - auto &lastate = lstate.Cast(); - auto &filter_sel = lastate.filter_sel; - auto &filter_executor = lastate.filter_executor; - - idx_t filtered = 0; - SelectionVector *filtering = nullptr; - if (gastate.filter_ref) { - filtering = &filter_sel; - filtered = filter_executor.SelectExpression(sink_chunk, filter_sel); - } - - D_ASSERT(aggregator); - auto &gestate = *gastate.gsink; - auto &lestate = *lastate.aggregator_state; - aggregator->Sink(gestate, lestate, sink_chunk, coll_chunk, input_idx, filtering, filtered); - - WindowExecutor::Sink(sink_chunk, coll_chunk, input_idx, gstate, lstate); -} - -static void ApplyWindowStats(const WindowBoundary &boundary, FrameDelta &delta, BaseStatistics *base, bool is_start) { - // Avoid overflow by clamping to the frame bounds - auto base_stats = delta; - - switch (boundary) { - case WindowBoundary::UNBOUNDED_PRECEDING: - if (is_start) { - delta.end = 0; - return; - } - break; - case WindowBoundary::UNBOUNDED_FOLLOWING: - if (!is_start) { - delta.begin = 0; - return; - } - break; - case WindowBoundary::CURRENT_ROW_ROWS: - delta.begin = delta.end = 0; - return; - case WindowBoundary::EXPR_PRECEDING_ROWS: - if (base && base->GetStatsType() == StatisticsType::NUMERIC_STATS && NumericStats::HasMinMax(*base)) { - // Preceding so negative offset from current row - base_stats.begin = NumericStats::GetMin(*base); - base_stats.end = NumericStats::GetMax(*base); - if (delta.begin < base_stats.end && base_stats.end < delta.end) { - delta.begin = -base_stats.end; - } - if (delta.begin < base_stats.begin && base_stats.begin < delta.end) { - delta.end = -base_stats.begin + 1; - } - } - return; - case WindowBoundary::EXPR_FOLLOWING_ROWS: - if (base && base->GetStatsType() == StatisticsType::NUMERIC_STATS && NumericStats::HasMinMax(*base)) { - base_stats.begin = NumericStats::GetMin(*base); - base_stats.end = NumericStats::GetMax(*base); - if (base_stats.end < delta.end) { - delta.end = base_stats.end + 1; - } - } - return; - - case WindowBoundary::CURRENT_ROW_RANGE: - case WindowBoundary::EXPR_PRECEDING_RANGE: - case WindowBoundary::EXPR_FOLLOWING_RANGE: - return; - default: - break; - } - - if (is_start) { - throw InternalException("Unsupported window start boundary"); - } else { - throw InternalException("Unsupported window end boundary"); - } -} - -void WindowAggregateExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const { - WindowExecutor::Finalize(gstate, lstate, collection); - - auto &gastate = gstate.Cast(); - auto &gsink = gastate.gsink; - D_ASSERT(aggregator); - - // Estimate the frame statistics - // Default to the entire partition if we don't know anything - FrameStats stats; - const auto count = NumericCast(gastate.payload_count); - - // First entry is the frame start - stats[0] = FrameDelta(-count, count); - auto base = wexpr.expr_stats.empty() ? nullptr : wexpr.expr_stats[0].get(); - ApplyWindowStats(wexpr.start, stats[0], base, true); - - // Second entry is the frame end - stats[1] = FrameDelta(-count, count); - base = wexpr.expr_stats.empty() ? nullptr : wexpr.expr_stats[1].get(); - ApplyWindowStats(wexpr.end, stats[1], base, false); - - auto &lastate = lstate.Cast(); - aggregator->Finalize(*gsink, *lastate.aggregator_state, collection, stats); -} - -void WindowAggregateExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &gastate = gstate.Cast(); - auto &lastate = lstate.Cast(); - auto &gsink = gastate.gsink; - D_ASSERT(aggregator); - - auto &agg_state = *lastate.aggregator_state; - - aggregator->Evaluate(*gsink, agg_state, lastate.bounds, result, count, row_idx); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_aggregate_states.cpp b/src/duckdb/src/function/window/window_aggregate_states.cpp deleted file mode 100644 index 2a673ec54..000000000 --- a/src/duckdb/src/function/window/window_aggregate_states.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "duckdb/function/window/window_aggregate_states.hpp" - -namespace duckdb { - -WindowAggregateStates::WindowAggregateStates(const AggregateObject &aggr) - : aggr(aggr), state_size(aggr.function.state_size(aggr.function)), allocator(Allocator::DefaultAllocator()) { -} - -void WindowAggregateStates::Initialize(idx_t count) { - states.resize(count * state_size); - auto state_ptr = states.data(); - - statef = make_uniq(LogicalType::POINTER, count); - auto state_f_data = FlatVector::GetData(*statef); - - for (idx_t i = 0; i < count; ++i, state_ptr += state_size) { - state_f_data[i] = state_ptr; - aggr.function.initialize(aggr.function, state_ptr); - } - - // Prevent conversion of results to constants - statef->SetVectorType(VectorType::FLAT_VECTOR); -} - -void WindowAggregateStates::Combine(WindowAggregateStates &target, AggregateCombineType combine_type) { - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator, AggregateCombineType::ALLOW_DESTRUCTIVE); - aggr.function.combine(*statef, *target.statef, aggr_input_data, GetCount()); -} - -void WindowAggregateStates::Finalize(Vector &result) { - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.finalize(*statef, aggr_input_data, result, GetCount(), 0); -} - -void WindowAggregateStates::Destroy() { - if (states.empty()) { - return; - } - - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - if (aggr.function.destructor) { - aggr.function.destructor(*statef, aggr_input_data, GetCount()); - } - - states.clear(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_aggregator.cpp b/src/duckdb/src/function/window/window_aggregator.cpp deleted file mode 100644 index 197b89e38..000000000 --- a/src/duckdb/src/function/window/window_aggregator.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "duckdb/function/window/window_aggregator.hpp" - -#include "duckdb/function/window/window_collection.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowAggregator -//===--------------------------------------------------------------------===// -WindowAggregatorState::WindowAggregatorState() : allocator(Allocator::DefaultAllocator()) { -} - -WindowAggregator::WindowAggregator(const BoundWindowExpression &wexpr) - : wexpr(wexpr), aggr(wexpr), result_type(wexpr.return_type), state_size(aggr.function.state_size(aggr.function)), - exclude_mode(wexpr.exclude_clause) { - - for (auto &child : wexpr.children) { - arg_types.emplace_back(child->return_type); - } -} - -WindowAggregator::WindowAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared) - : WindowAggregator(wexpr) { - for (auto &child : wexpr.children) { - child_idx.emplace_back(shared.RegisterCollection(child, false)); - } -} - -WindowAggregator::~WindowAggregator() { -} - -unique_ptr WindowAggregator::GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &) const { - return make_uniq(context, *this, group_count); -} - -void WindowAggregatorLocalState::Sink(WindowAggregatorGlobalState &gastate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx) { -} - -void WindowAggregator::Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered) { - auto &gastate = gstate.Cast(); - auto &lastate = lstate.Cast(); - lastate.Sink(gastate, sink_chunk, coll_chunk, input_idx); - if (filter_sel) { - auto &filter_mask = gastate.filter_mask; - for (idx_t f = 0; f < filtered; ++f) { - filter_mask.SetValid(input_idx + filter_sel->get_index(f)); - } - } -} - -void WindowAggregatorLocalState::InitSubFrames(SubFrames &frames, const WindowExcludeMode exclude_mode) { - idx_t nframes = 0; - switch (exclude_mode) { - case WindowExcludeMode::NO_OTHER: - nframes = 1; - break; - case WindowExcludeMode::TIES: - nframes = 3; - break; - case WindowExcludeMode::CURRENT_ROW: - case WindowExcludeMode::GROUP: - nframes = 2; - break; - } - frames.resize(nframes, {0, 0}); -} - -void WindowAggregatorLocalState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { - // Prepare to scan - if (!cursor) { - cursor = make_uniq(*collection, gastate.aggregator.child_idx); - } -} - -void WindowAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) { - auto &gasink = gstate.Cast(); - auto &lastate = lstate.Cast(); - lastate.Finalize(gasink, collection); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_boundaries_state.cpp b/src/duckdb/src/function/window/window_boundaries_state.cpp deleted file mode 100644 index 7727e2a63..000000000 --- a/src/duckdb/src/function/window/window_boundaries_state.cpp +++ /dev/null @@ -1,854 +0,0 @@ -#include "duckdb/common/operator/add.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/function/window/window_boundaries_state.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowBoundariesState -//===--------------------------------------------------------------------===// -idx_t WindowBoundariesState::FindNextStart(const ValidityMask &mask, idx_t l, const idx_t r, idx_t &n) { - if (mask.AllValid()) { - auto start = MinValue(l + n - 1, r); - n -= MinValue(n, r - l); - return start; - } - - while (l < r) { - // If l is aligned with the start of a block, and the block is blank, then skip forward one block. - idx_t entry_idx; - idx_t shift; - mask.GetEntryIndex(l, entry_idx, shift); - - const auto block = mask.GetValidityEntry(entry_idx); - if (mask.NoneValid(block) && !shift) { - l += ValidityMask::BITS_PER_VALUE; - continue; - } - - // Loop over the block - for (; shift < ValidityMask::BITS_PER_VALUE && l < r; ++shift, ++l) { - if (mask.RowIsValid(block, shift) && --n == 0) { - return MinValue(l, r); - } - } - } - - // Didn't find a start so return the end of the range - return r; -} - -idx_t WindowBoundariesState::FindPrevStart(const ValidityMask &mask, const idx_t l, idx_t r, idx_t &n) { - if (mask.AllValid()) { - auto start = (r <= l + n) ? l : r - n; - n -= r - start; - return start; - } - - while (l < r) { - // If r is aligned with the start of a block, and the previous block is blank, - // then skip backwards one block. - idx_t entry_idx; - idx_t shift; - mask.GetEntryIndex(r - 1, entry_idx, shift); - - const auto block = mask.GetValidityEntry(entry_idx); - if (mask.NoneValid(block) && (shift + 1 == ValidityMask::BITS_PER_VALUE)) { - // r is nonzero (> l) and word aligned, so this will not underflow. - r -= ValidityMask::BITS_PER_VALUE; - continue; - } - - // Loop backwards over the block - // shift is probing r-1 >= l >= 0 - for (++shift; shift-- > 0 && l < r; --r) { - // l < r ensures n == 1 if result is supposed to be NULL because of EXCLUDE - if (mask.RowIsValid(block, shift) && --n == 0) { - return MaxValue(l, r - 1); - } - } - } - - // Didn't find a start so return the start of the range - return l; -} - -//===--------------------------------------------------------------------===// -// WindowColumnIterator -//===--------------------------------------------------------------------===// -template -struct WindowColumnIterator { - using iterator = WindowColumnIterator; - using iterator_category = std::random_access_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = T; - using reference = T; - using pointer = idx_t; - - explicit WindowColumnIterator(WindowCursor &coll, pointer pos = 0) : coll(&coll), pos(pos) { - } - - // Forward iterator - inline reference operator*() const { - return coll->GetCell(0, pos); - } - inline explicit operator pointer() const { - return pos; - } - - inline iterator &operator++() { - ++pos; - return *this; - } - inline iterator operator++(int) { - auto result = *this; - ++(*this); - return result; - } - - // Bidirectional iterator - inline iterator &operator--() { - --pos; - return *this; - } - inline iterator operator--(int) { - auto result = *this; - --(*this); - return result; - } - - // Random Access - inline iterator &operator+=(difference_type n) { - pos += UnsafeNumericCast(n); - return *this; - } - inline iterator &operator-=(difference_type n) { - pos -= UnsafeNumericCast(n); - return *this; - } - - inline reference operator[](difference_type m) const { - return coll->GetCell(0, pos + m); - } - - friend inline iterator &operator+(const iterator &a, difference_type n) { - return iterator(a.coll, a.pos + n); - } - - friend inline iterator operator-(const iterator &a, difference_type n) { - return iterator(a.coll, a.pos - n); - } - - friend inline iterator operator+(difference_type n, const iterator &a) { - return a + n; - } - friend inline difference_type operator-(const iterator &a, const iterator &b) { - return difference_type(a.pos - b.pos); - } - - friend inline bool operator==(const iterator &a, const iterator &b) { - return a.pos == b.pos; - } - friend inline bool operator!=(const iterator &a, const iterator &b) { - return a.pos != b.pos; - } - friend inline bool operator<(const iterator &a, const iterator &b) { - return a.pos < b.pos; - } - friend inline bool operator<=(const iterator &a, const iterator &b) { - return a.pos <= b.pos; - } - friend inline bool operator>(const iterator &a, const iterator &b) { - return a.pos > b.pos; - } - friend inline bool operator>=(const iterator &a, const iterator &b) { - return a.pos >= b.pos; - } - -private: - // optional_ptr does not allow us to modify this, but the constructor enforces it. - WindowCursor *coll; - pointer pos; -}; - -template -struct OperationCompare : public std::function { - inline bool operator()(const T &lhs, const T &val) const { - return OP::template Operation(lhs, val); - } -}; - -template -static idx_t FindTypedRangeBound(WindowCursor &over, const idx_t order_begin, const idx_t order_end, - const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, - const FrameBounds &prev) { - D_ASSERT(!boundary.CellIsNull(chunk_idx)); - const auto val = boundary.GetCell(chunk_idx); - - OperationCompare comp; - - // Check that the value we are searching for is in range. - if (range == WindowBoundary::EXPR_PRECEDING_RANGE) { - // Preceding but value past the current value - const auto cur_val = over.GetCell(0, order_end - 1); - if (comp(cur_val, val)) { - throw OutOfRangeException("Invalid RANGE PRECEDING value"); - } - } else { - // Following but value before the current value - D_ASSERT(range == WindowBoundary::EXPR_FOLLOWING_RANGE); - const auto cur_val = over.GetCell(0, order_begin); - if (comp(val, cur_val)) { - throw OutOfRangeException("Invalid RANGE FOLLOWING value"); - } - } - - // Try to reuse the previous bounds to restrict the search. - // This is only valid if the previous bounds were non-empty - // Only inject the comparisons if the previous bounds are a strict subset. - WindowColumnIterator begin(over, order_begin); - WindowColumnIterator end(over, order_end); - if (prev.start < prev.end) { - if (order_begin < prev.start && prev.start < order_end) { - const auto first = over.GetCell(0, prev.start); - if (!comp(val, first)) { - // prev.first <= val, so we can start further forward - begin += UnsafeNumericCast(prev.start - order_begin); - } - } - if (order_begin < prev.end && prev.end < order_end) { - const auto second = over.GetCell(0, prev.end - 1); - if (!comp(second, val)) { - // val <= prev.second, so we can end further back - // (prev.second is the largest peer) - end -= UnsafeNumericCast(order_end - prev.end - 1); - } - } - } - - if (FROM) { - return idx_t(std::lower_bound(begin, end, val, comp)); - } else { - return idx_t(std::upper_bound(begin, end, val, comp)); - } -} - -template -static idx_t FindRangeBound(WindowCursor &over, const idx_t order_begin, const idx_t order_end, - const WindowBoundary range, WindowInputExpression &boundary, const idx_t chunk_idx, - const FrameBounds &prev) { - switch (boundary.InternalType()) { - case PhysicalType::INT8: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::INT16: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::INT32: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::INT64: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::UINT8: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::UINT16: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::UINT32: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::UINT64: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::INT128: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::UINT128: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, - prev); - case PhysicalType::FLOAT: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::DOUBLE: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case PhysicalType::INTERVAL: - return FindTypedRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, - prev); - default: - throw InternalException("Unsupported column type for RANGE"); - } -} - -template -static idx_t FindOrderedRangeBound(WindowCursor &over, const OrderType range_sense, const idx_t order_begin, - const idx_t order_end, const WindowBoundary range, WindowInputExpression &boundary, - const idx_t chunk_idx, const FrameBounds &prev) { - switch (range_sense) { - case OrderType::ASCENDING: - return FindRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - case OrderType::DESCENDING: - return FindRangeBound(over, order_begin, order_end, range, boundary, chunk_idx, prev); - default: - throw InternalException("Unsupported ORDER BY sense for RANGE"); - } -} - -bool WindowBoundariesState::HasPrecedingRange(const BoundWindowExpression &wexpr) { - return (wexpr.start == WindowBoundary::EXPR_PRECEDING_RANGE || wexpr.end == WindowBoundary::EXPR_PRECEDING_RANGE); -} - -bool WindowBoundariesState::HasFollowingRange(const BoundWindowExpression &wexpr) { - return (wexpr.start == WindowBoundary::EXPR_FOLLOWING_RANGE || wexpr.end == WindowBoundary::EXPR_FOLLOWING_RANGE); -} - -WindowBoundsSet WindowBoundariesState::GetWindowBounds(const BoundWindowExpression &wexpr) { - const auto partition_count = wexpr.partitions.size(); - const auto order_count = wexpr.orders.size(); - - WindowBoundsSet result; - switch (wexpr.GetExpressionType()) { - case ExpressionType::WINDOW_ROW_NUMBER: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_NTILE: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_RANK: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - result.insert(PEER_BEGIN); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_RANK_DENSE: - result.insert(PARTITION_BEGIN); - result.insert(PEER_BEGIN); - break; - case ExpressionType::WINDOW_PERCENT_RANK: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - result.insert(PEER_BEGIN); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_CUME_DIST: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - result.insert(PEER_END); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_LEAD: - case ExpressionType::WINDOW_LAG: - if (wexpr.arg_orders.empty()) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - } else { - // Secondary orders need to know where the frame is - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - } - break; - case ExpressionType::WINDOW_FIRST_VALUE: - case ExpressionType::WINDOW_LAST_VALUE: - case ExpressionType::WINDOW_NTH_VALUE: - case ExpressionType::WINDOW_AGGREGATE: - result.insert(FRAME_BEGIN); - result.insert(FRAME_END); - break; - default: - throw InternalException("Window aggregate type %s", ExpressionTypeToString(wexpr.GetExpressionType())); - } - - // Internal dependencies - if (result.count(FRAME_BEGIN) || result.count(FRAME_END)) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - - // if we have EXCLUDE GROUP / TIES, we also need peer boundaries - if (wexpr.exclude_clause != WindowExcludeMode::NO_OTHER) { - result.insert(PEER_BEGIN); - result.insert(PEER_END); - } - - // If the frames are RANGE, then we need peer boundaries - // If they are preceding or following, we also need to know - // where the valid values begin or end. - switch (wexpr.start) { - case WindowBoundary::CURRENT_ROW_RANGE: - result.insert(PEER_BEGIN); - break; - case WindowBoundary::EXPR_PRECEDING_RANGE: - result.insert(PEER_BEGIN); - result.insert(VALID_BEGIN); - result.insert(VALID_END); - break; - case WindowBoundary::EXPR_FOLLOWING_RANGE: - result.insert(PEER_BEGIN); - result.insert(VALID_END); - break; - default: - break; - } - - switch (wexpr.end) { - case WindowBoundary::CURRENT_ROW_RANGE: - result.insert(PEER_END); - break; - case WindowBoundary::EXPR_PRECEDING_RANGE: - result.insert(PEER_END); - result.insert(VALID_BEGIN); - break; - case WindowBoundary::EXPR_FOLLOWING_RANGE: - result.insert(PEER_END); - result.insert(VALID_BEGIN); - result.insert(VALID_END); - break; - default: - break; - } - } - - if (result.count(VALID_END)) { - result.insert(PARTITION_END); - if (HasFollowingRange(wexpr)) { - result.insert(VALID_BEGIN); - } - } - if (result.count(VALID_BEGIN)) { - result.insert(PARTITION_BEGIN); - result.insert(PARTITION_END); - } - if (result.count(PEER_END)) { - result.insert(PARTITION_END); - if (order_count) { - result.insert(PEER_BEGIN); - } - } - if (result.count(PARTITION_END) && (partition_count + order_count)) { - result.insert(PARTITION_BEGIN); - } - - return result; -} - -WindowBoundariesState::WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size) - : required(GetWindowBounds(wexpr)), type(wexpr.GetExpressionType()), input_size(input_size), - start_boundary(wexpr.start), end_boundary(wexpr.end), partition_count(wexpr.partitions.size()), - order_count(wexpr.orders.size()), range_sense(wexpr.orders.empty() ? OrderType::INVALID : wexpr.orders[0].type), - has_preceding_range(HasPrecedingRange(wexpr)), has_following_range(HasFollowingRange(wexpr)) { -} - -void WindowBoundariesState::Bounds(DataChunk &bounds, idx_t row_idx, optional_ptr range, - const idx_t count, WindowInputExpression &boundary_start, - WindowInputExpression &boundary_end, const ValidityMask &partition_mask, - const ValidityMask &order_mask) { - bounds.Reset(); - D_ASSERT(bounds.ColumnCount() == 8); - - const auto is_jump = (next_pos != row_idx); - if (required.count(PARTITION_BEGIN)) { - PartitionBegin(bounds, row_idx, count, is_jump, partition_mask); - } - if (required.count(PARTITION_END)) { - PartitionEnd(bounds, row_idx, count, is_jump, partition_mask); - } - if (required.count(PEER_BEGIN)) { - PeerBegin(bounds, row_idx, count, is_jump, partition_mask, order_mask); - } - if (required.count(PEER_END)) { - PeerEnd(bounds, row_idx, count, partition_mask, order_mask); - } - if (required.count(VALID_BEGIN)) { - ValidBegin(bounds, row_idx, count, is_jump, partition_mask, order_mask, range); - } - if (required.count(VALID_END)) { - ValidEnd(bounds, row_idx, count, is_jump, partition_mask, order_mask, range); - } - if (required.count(FRAME_BEGIN)) { - FrameBegin(bounds, row_idx, count, boundary_start, range); - } - if (required.count(FRAME_END)) { - FrameEnd(bounds, row_idx, count, boundary_end, range); - } - next_pos += count; - - bounds.SetCardinality(count); -} - -void WindowBoundariesState::PartitionBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask) { - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - - // OVER() - if (partition_count + order_count == 0) { - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - partition_begin_data[chunk_idx] = 0; - } - return; - } - - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - // determine partition and peer group boundaries to ultimately figure out window size - const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - - // when the partition changes, recompute the boundaries - if (!is_same_partition || is_jump) { - if (is_jump) { - idx_t n = 1; - partition_start = FindPrevStart(partition_mask, 0, row_idx + 1, n); - is_jump = false; - } else { - partition_start = row_idx; - } - } - - partition_begin_data[chunk_idx] = partition_start; - } -} - -void WindowBoundariesState::PartitionEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask) { - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - - // OVER() - if (partition_count + order_count == 0) { - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - partition_end_data[chunk_idx] = input_size; - } - return; - } - - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - // determine partition and peer group boundaries to ultimately figure out window size - const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - - // when the partition changes, recompute the boundaries - if (!is_same_partition || is_jump) { - // find end of partition - partition_end = input_size; - if (partition_count) { - const auto partition_begin = partition_begin_data[chunk_idx]; - idx_t n = 1; - partition_end = FindNextStart(partition_mask, partition_begin + 1, input_size, n); - } - is_jump = false; - } - - partition_end_data[chunk_idx] = partition_end; - } -} - -void WindowBoundariesState::PeerBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask, const ValidityMask &order_mask) { - - auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); - - // OVER() - if (partition_count + order_count == 0) { - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - peer_begin_data[chunk_idx] = 0; - } - return; - } - - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - // determine partition and peer group boundaries to ultimately figure out window size - const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - const auto is_peer = !order_mask.RowIsValidUnsafe(row_idx); - - // when the partition changes, recompute the boundaries - if (!is_same_partition || is_jump) { - // find end of partition - if (is_jump) { - idx_t n = 1; - peer_start = FindPrevStart(order_mask, 0, row_idx + 1, n); - } else { - peer_start = row_idx; - } - is_jump = false; - } else if (!is_peer) { - peer_start = row_idx; - } - - peer_begin_data[chunk_idx] = peer_start; - } -} - -void WindowBoundariesState::PeerEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) { - // OVER() - if (!order_count) { - bounds.data[PEER_END].Reference(bounds.data[PARTITION_END]); - return; - } - - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); - auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - idx_t n = 1; - const auto peer_start = peer_begin_data[chunk_idx]; - const auto partition_end = partition_end_data[chunk_idx]; - peer_end_data[chunk_idx] = FindNextStart(order_mask, peer_start + 1, partition_end, n); - } -} - -void WindowBoundariesState::ValidBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask, const ValidityMask &order_mask, - optional_ptr range) { - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); - - // OVER() - D_ASSERT(partition_count + order_count != 0); - D_ASSERT(range); - - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - - if (!is_same_partition || is_jump) { - // Find valid ordering values for the new partition - // so we can exclude NULLs from RANGE expression computations - valid_start = partition_begin_data[chunk_idx]; - const auto valid_end = partition_end_data[chunk_idx]; - - if ((valid_start < valid_end) && has_preceding_range) { - // Exclude any leading NULLs - if (range->CellIsNull(0, valid_start)) { - idx_t n = 1; - valid_start = FindNextStart(order_mask, valid_start + 1, valid_end, n); - } - } - } - - valid_begin_data[chunk_idx] = valid_start; - } -} - -void WindowBoundariesState::ValidEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask, const ValidityMask &order_mask, - optional_ptr range) { - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); - auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); - - // OVER() - D_ASSERT(partition_count + order_count != 0); - D_ASSERT(range); - - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - const auto is_same_partition = !partition_mask.RowIsValidUnsafe(row_idx); - - if (!is_same_partition || is_jump) { - // Find valid ordering values for the new partition - // so we can exclude NULLs from RANGE expression computations - valid_end = partition_end_data[chunk_idx]; - - if ((valid_start < valid_end) && has_following_range) { - // Exclude any trailing NULLs - const auto valid_start = valid_begin_data[chunk_idx]; - if (range->CellIsNull(0, valid_end - 1)) { - idx_t n = 1; - valid_end = FindPrevStart(order_mask, valid_start, valid_end, n); - } - - // Reset range hints - prev.start = valid_start; - prev.end = valid_end; - } - } - - valid_end_data[chunk_idx] = valid_end; - } -} - -void WindowBoundariesState::FrameBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, - WindowInputExpression &boundary_begin, optional_ptr range) { - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto peer_begin_data = FlatVector::GetData(bounds.data[PEER_BEGIN]); - auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); - auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); - auto frame_begin_data = FlatVector::GetData(bounds.data[FRAME_BEGIN]); - - idx_t window_start = NumericLimits::Maximum(); - - switch (start_boundary) { - case WindowBoundary::UNBOUNDED_PRECEDING: - bounds.data[FRAME_BEGIN].Reference(bounds.data[PARTITION_BEGIN]); - // No need to clamp - return; - case WindowBoundary::CURRENT_ROW_ROWS: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - frame_begin_data[chunk_idx] = row_idx; - } - break; - case WindowBoundary::CURRENT_ROW_RANGE: - bounds.data[FRAME_BEGIN].Reference(bounds.data[PEER_BEGIN]); - frame_begin_data = peer_begin_data; - break; - case WindowBoundary::EXPR_PRECEDING_ROWS: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - int64_t computed_start; - if (!TrySubtractOperator::Operation(static_cast(row_idx), - boundary_begin.GetCell(chunk_idx), computed_start)) { - window_start = partition_begin_data[chunk_idx]; - } else { - window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); - } - frame_begin_data[chunk_idx] = window_start; - } - break; - case WindowBoundary::EXPR_FOLLOWING_ROWS: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - int64_t computed_start; - if (!TryAddOperator::Operation(static_cast(row_idx), boundary_begin.GetCell(chunk_idx), - computed_start)) { - window_start = partition_begin_data[chunk_idx]; - } else { - window_start = UnsafeNumericCast(MaxValue(computed_start, 0)); - } - frame_begin_data[chunk_idx] = window_start; - } - break; - case WindowBoundary::EXPR_PRECEDING_RANGE: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - if (boundary_begin.CellIsNull(chunk_idx)) { - window_start = peer_begin_data[chunk_idx]; - } else { - const auto valid_start = valid_begin_data[chunk_idx]; - prev.end = valid_end_data[chunk_idx]; - window_start = FindOrderedRangeBound(*range, range_sense, valid_start, row_idx + 1, - start_boundary, boundary_begin, chunk_idx, prev); - prev.start = window_start; - } - frame_begin_data[chunk_idx] = window_start; - } - break; - case WindowBoundary::EXPR_FOLLOWING_RANGE: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - if (boundary_begin.CellIsNull(chunk_idx)) { - window_start = peer_begin_data[chunk_idx]; - } else { - const auto valid_end = valid_end_data[chunk_idx]; - prev.end = valid_end; - window_start = FindOrderedRangeBound(*range, range_sense, row_idx, valid_end, start_boundary, - boundary_begin, chunk_idx, prev); - prev.start = window_start; - } - frame_begin_data[chunk_idx] = window_start; - } - break; - default: - throw InternalException("Unsupported window start boundary"); - } - - ClampFrame(count, frame_begin_data, partition_begin_data, partition_end_data); -} - -void WindowBoundariesState::FrameEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, - WindowInputExpression &boundary_end, optional_ptr range) { - auto partition_begin_data = FlatVector::GetData(bounds.data[PARTITION_BEGIN]); - auto partition_end_data = FlatVector::GetData(bounds.data[PARTITION_END]); - auto peer_end_data = FlatVector::GetData(bounds.data[PEER_END]); - auto valid_begin_data = FlatVector::GetData(bounds.data[VALID_BEGIN]); - auto valid_end_data = FlatVector::GetData(bounds.data[VALID_END]); - auto frame_end_data = FlatVector::GetData(bounds.data[FRAME_END]); - - idx_t window_end = NumericLimits::Maximum(); - - switch (end_boundary) { - case WindowBoundary::CURRENT_ROW_ROWS: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - frame_end_data[chunk_idx] = row_idx + 1; - } - break; - case WindowBoundary::CURRENT_ROW_RANGE: - bounds.data[FRAME_END].Reference(bounds.data[PEER_END]); - frame_end_data = peer_end_data; - break; - case WindowBoundary::UNBOUNDED_FOLLOWING: - bounds.data[FRAME_END].Reference(bounds.data[PARTITION_END]); - // No need to clamp - return; - case WindowBoundary::EXPR_PRECEDING_ROWS: { - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - int64_t computed_start; - if (!TrySubtractOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), - computed_start)) { - window_end = partition_end_data[chunk_idx]; - } else { - window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); - } - frame_end_data[chunk_idx] = window_end; - } - break; - } - case WindowBoundary::EXPR_FOLLOWING_ROWS: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - int64_t computed_start; - if (!TryAddOperator::Operation(int64_t(row_idx + 1), boundary_end.GetCell(chunk_idx), - computed_start)) { - window_end = partition_end_data[chunk_idx]; - } else { - window_end = UnsafeNumericCast(MaxValue(computed_start, 0)); - } - frame_end_data[chunk_idx] = window_end; - } - break; - case WindowBoundary::EXPR_PRECEDING_RANGE: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - if (boundary_end.CellIsNull(chunk_idx)) { - window_end = peer_end_data[chunk_idx]; - } else { - const auto valid_start = valid_begin_data[chunk_idx]; - prev.start = valid_start; - window_end = FindOrderedRangeBound(*range, range_sense, valid_start, row_idx + 1, end_boundary, - boundary_end, chunk_idx, prev); - prev.end = window_end; - } - frame_end_data[chunk_idx] = window_end; - } - break; - case WindowBoundary::EXPR_FOLLOWING_RANGE: - for (idx_t chunk_idx = 0; chunk_idx < count; ++chunk_idx, ++row_idx) { - if (boundary_end.CellIsNull(chunk_idx)) { - window_end = peer_end_data[chunk_idx]; - } else { - const auto valid_end = valid_end_data[chunk_idx]; - prev.start = valid_begin_data[chunk_idx]; - window_end = FindOrderedRangeBound(*range, range_sense, row_idx, valid_end, end_boundary, - boundary_end, chunk_idx, prev); - prev.end = window_end; - } - frame_end_data[chunk_idx] = window_end; - } - break; - default: - throw InternalException("Unsupported window end boundary"); - } - - ClampFrame(count, frame_end_data, partition_begin_data, partition_end_data); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_collection.cpp b/src/duckdb/src/function/window/window_collection.cpp deleted file mode 100644 index 0dee0cc84..000000000 --- a/src/duckdb/src/function/window/window_collection.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "duckdb/function/window/window_collection.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowCollection -//===--------------------------------------------------------------------===// -WindowCollection::WindowCollection(BufferManager &buffer_manager, idx_t count, const vector &types) - : all_valids(types.size()), types(types), count(count), buffer_manager(buffer_manager) { - if (!types.empty()) { - inputs = make_uniq(buffer_manager, types); - } - - validities.resize(types.size()); - - // Atomic vectors can't be constructed with a given value - for (auto &all_valid : all_valids) { - all_valid = true; - } -} - -void WindowCollection::GetCollection(idx_t row_idx, ColumnDataCollectionSpec &spec) { - if (spec.second && row_idx == spec.first + spec.second->Count()) { - return; - } - - lock_guard collection_guard(lock); - - auto collection = make_uniq(buffer_manager, types); - spec = {row_idx, collection.get()}; - Range probe {row_idx, collections.size()}; - auto i = std::upper_bound(ranges.begin(), ranges.end(), probe); - ranges.insert(i, probe); - collections.emplace_back(std::move(collection)); -} - -void WindowCollection::Combine(const ColumnSet &validity_cols) { - lock_guard collection_guard(lock); - - // If there are no columns (COUNT(*)) then this is a NOP - if (types.empty()) { - return; - } - - // Have we already combined? - if (inputs->Count()) { - D_ASSERT(collections.empty()); - D_ASSERT(ranges.empty()); - return; - } - - // If there are columns, we should have data - D_ASSERT(!collections.empty()); - D_ASSERT(!ranges.empty()); - - for (auto &range : ranges) { - inputs->Combine(*collections[range.second]); - } - collections.clear(); - ranges.clear(); - - if (validity_cols.empty()) { - return; - } - - D_ASSERT(inputs.get()); - - // Find all columns with NULLs - vector invalid_cols; - for (auto &col_idx : validity_cols) { - if (!all_valids[col_idx]) { - invalid_cols.emplace_back(col_idx); - validities[col_idx].Initialize(inputs->Count()); - } - } - - if (invalid_cols.empty()) { - return; - } - - WindowCursor cursor(*this, invalid_cols); - idx_t target_offset = 0; - while (cursor.Scan()) { - const auto count = cursor.chunk.size(); - for (idx_t i = 0; i < invalid_cols.size(); ++i) { - auto &other = FlatVector::Validity(cursor.chunk.data[i]); - const auto col_idx = invalid_cols[i]; - validities[col_idx].SliceInPlace(other, target_offset, 0, count); - } - target_offset += count; - } -} - -WindowBuilder::WindowBuilder(WindowCollection &collection) : collection(collection) { -} - -void WindowBuilder::Sink(DataChunk &chunk, idx_t input_idx) { - // Check whether we need a a new collection - if (!sink.second || input_idx < sink.first || sink.first + sink.second->Count() < input_idx) { - collection.GetCollection(input_idx, sink); - D_ASSERT(sink.second); - sink.second->InitializeAppend(appender); - } - sink.second->Append(appender, chunk); - - // Record NULLs - for (column_t col_idx = 0; col_idx < chunk.ColumnCount(); ++col_idx) { - if (!collection.all_valids[col_idx]) { - continue; - } - - // Column was valid, make sure it still is. - UnifiedVectorFormat data; - chunk.data[col_idx].ToUnifiedFormat(chunk.size(), data); - if (!data.validity.AllValid()) { - collection.all_valids[col_idx] = false; - } - } -} - -WindowCursor::WindowCursor(const WindowCollection &paged, vector column_ids) : paged(paged) { - D_ASSERT(paged.collections.empty()); - D_ASSERT(paged.ranges.empty()); - if (column_ids.empty()) { - // For things like COUNT(*) set the state up to contain the whole range - state.segment_index = 0; - state.chunk_index = 0; - state.current_row_index = 0; - state.next_row_index = paged.size(); - state.properties = ColumnDataScanProperties::ALLOW_ZERO_COPY; - chunk.SetCapacity(state.next_row_index); - chunk.SetCardinality(state.next_row_index); - return; - } else if (chunk.data.empty()) { - auto &inputs = paged.inputs; - D_ASSERT(inputs.get()); - inputs->InitializeScan(state, std::move(column_ids)); - inputs->InitializeScanChunk(state, chunk); - } -} - -WindowCursor::WindowCursor(const WindowCollection &paged, column_t col_idx) - : WindowCursor(paged, vector(1, col_idx)) { -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_constant_aggregator.cpp b/src/duckdb/src/function/window/window_constant_aggregator.cpp deleted file mode 100644 index 0e09c6f99..000000000 --- a/src/duckdb/src/function/window/window_constant_aggregator.cpp +++ /dev/null @@ -1,357 +0,0 @@ -#include "duckdb/function/window/window_constant_aggregator.hpp" - -#include "duckdb/function/function_binder.hpp" -#include "duckdb/function/window/window_aggregate_states.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowConstantAggregatorGlobalState -//===--------------------------------------------------------------------===// - -class WindowConstantAggregatorGlobalState : public WindowAggregatorGlobalState { -public: - WindowConstantAggregatorGlobalState(ClientContext &context, const WindowConstantAggregator &aggregator, idx_t count, - const ValidityMask &partition_mask); - - void Finalize(const FrameStats &stats); - - //! Partition starts - vector partition_offsets; - //! Reused result state container for the window functions - WindowAggregateStates statef; - //! Aggregate results - unique_ptr results; -}; - -WindowConstantAggregatorGlobalState::WindowConstantAggregatorGlobalState(ClientContext &context, - const WindowConstantAggregator &aggregator, - idx_t group_count, - const ValidityMask &partition_mask) - : WindowAggregatorGlobalState(context, aggregator, STANDARD_VECTOR_SIZE), statef(aggr) { - - // Locate the partition boundaries - if (partition_mask.AllValid()) { - partition_offsets.emplace_back(0); - } else { - idx_t entry_idx; - idx_t shift; - for (idx_t start = 0; start < group_count;) { - partition_mask.GetEntryIndex(start, entry_idx, shift); - - // If start is aligned with the start of a block, - // and the block is blank, then skip forward one block. - const auto block = partition_mask.GetValidityEntry(entry_idx); - if (partition_mask.NoneValid(block) && !shift) { - start += ValidityMask::BITS_PER_VALUE; - continue; - } - - // Loop over the block - for (; shift < ValidityMask::BITS_PER_VALUE && start < group_count; ++shift, ++start) { - if (partition_mask.RowIsValid(block, shift)) { - partition_offsets.emplace_back(start); - } - } - } - } - - // Initialise the vector for caching the results - results = make_uniq(aggregator.result_type, partition_offsets.size()); - - // Initialise the final states - statef.Initialize(partition_offsets.size()); - - // Add final guard - partition_offsets.emplace_back(group_count); -} - -//===--------------------------------------------------------------------===// -// WindowConstantAggregatorLocalState -//===--------------------------------------------------------------------===// -class WindowConstantAggregatorLocalState : public WindowAggregatorLocalState { -public: - explicit WindowConstantAggregatorLocalState(const WindowConstantAggregatorGlobalState &gstate); - ~WindowConstantAggregatorLocalState() override { - } - - void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered); - void Combine(WindowConstantAggregatorGlobalState &gstate); - -public: - //! The global state we are sharing - const WindowConstantAggregatorGlobalState &gstate; - //! Reusable chunk for sinking - DataChunk inputs; - //! Chunk for referencing the input columns - DataChunk payload_chunk; - //! A vector of pointers to "state", used for intermediate window segment aggregation - Vector statep; - //! Reused result state container for the window functions - WindowAggregateStates statef; - //! The current result partition being read - idx_t partition; - //! Shared SV for evaluation - SelectionVector matches; -}; - -WindowConstantAggregatorLocalState::WindowConstantAggregatorLocalState( - const WindowConstantAggregatorGlobalState &gstate) - : gstate(gstate), statep(Value::POINTER(0)), statef(gstate.statef.aggr), partition(0) { - matches.Initialize(); - - // Start the aggregates - auto &partition_offsets = gstate.partition_offsets; - auto &aggregator = gstate.aggregator; - statef.Initialize(partition_offsets.size() - 1); - - // Set up shared buffer - inputs.Initialize(Allocator::DefaultAllocator(), aggregator.arg_types); - payload_chunk.InitializeEmpty(inputs.GetTypes()); - - gstate.locals++; -} - -//===--------------------------------------------------------------------===// -// WindowConstantAggregator -//===--------------------------------------------------------------------===// -bool WindowConstantAggregator::CanAggregate(const BoundWindowExpression &wexpr) { - if (!wexpr.aggregate) { - return false; - } - // window exclusion cannot be handled by constant aggregates - if (wexpr.exclude_clause != WindowExcludeMode::NO_OTHER) { - return false; - } - - // DISTINCT aggregation cannot be handled by constant aggregation - if (wexpr.distinct) { - return false; - } - - // COUNT(*) is already handled efficiently by segment trees. - if (wexpr.children.empty()) { - return false; - } - - /* - The default framing option is RANGE UNBOUNDED PRECEDING, which - is the same as RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT - ROW; it sets the frame to be all rows from the partition start - up through the current row's last peer (a row that the window's - ORDER BY clause considers equivalent to the current row; all - rows are peers if there is no ORDER BY). In general, UNBOUNDED - PRECEDING means that the frame starts with the first row of the - partition, and similarly UNBOUNDED FOLLOWING means that the - frame ends with the last row of the partition, regardless of - RANGE, ROWS or GROUPS mode. In ROWS mode, CURRENT ROW means that - the frame starts or ends with the current row; but in RANGE or - GROUPS mode it means that the frame starts or ends with the - current row's first or last peer in the ORDER BY ordering. The - offset PRECEDING and offset FOLLOWING options vary in meaning - depending on the frame mode. - */ - switch (wexpr.start) { - case WindowBoundary::UNBOUNDED_PRECEDING: - break; - case WindowBoundary::CURRENT_ROW_RANGE: - if (!wexpr.orders.empty()) { - return false; - } - break; - default: - return false; - } - - switch (wexpr.end) { - case WindowBoundary::UNBOUNDED_FOLLOWING: - break; - case WindowBoundary::CURRENT_ROW_RANGE: - if (!wexpr.orders.empty()) { - return false; - } - break; - default: - return false; - } - - return true; -} - -BoundWindowExpression &WindowConstantAggregator::RebindAggregate(ClientContext &context, BoundWindowExpression &wexpr) { - FunctionBinder::BindSortedAggregate(context, wexpr); - - return wexpr; -} - -WindowConstantAggregator::WindowConstantAggregator(BoundWindowExpression &wexpr, WindowSharedExpressions &shared, - ClientContext &context) - : WindowAggregator(RebindAggregate(context, wexpr)) { - - // We only need these values for Sink - for (auto &child : wexpr.children) { - child_idx.emplace_back(shared.RegisterSink(child)); - } -} - -unique_ptr WindowConstantAggregator::GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const { - return make_uniq(context, *this, group_count, partition_mask); -} - -void WindowConstantAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered) { - auto &lastate = lstate.Cast(); - - lastate.Sink(sink_chunk, coll_chunk, input_idx, filter_sel, filtered); -} - -void WindowConstantAggregatorLocalState::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t row, - optional_ptr filter_sel, idx_t filtered) { - auto &partition_offsets = gstate.partition_offsets; - const auto &aggr = gstate.aggr; - const auto chunk_begin = row; - const auto chunk_end = chunk_begin + sink_chunk.size(); - idx_t partition = - idx_t(std::upper_bound(partition_offsets.begin(), partition_offsets.end(), row) - partition_offsets.begin()) - - 1; - - auto state_f_data = statef.GetData(); - auto state_p_data = FlatVector::GetData(statep); - - auto &child_idx = gstate.aggregator.child_idx; - for (column_t c = 0; c < child_idx.size(); ++c) { - payload_chunk.data[c].Reference(sink_chunk.data[child_idx[c]]); - } - - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - idx_t begin = 0; - idx_t filter_idx = 0; - auto partition_end = partition_offsets[partition + 1]; - while (row < chunk_end) { - if (row == partition_end) { - ++partition; - partition_end = partition_offsets[partition + 1]; - } - partition_end = MinValue(partition_end, chunk_end); - auto end = partition_end - chunk_begin; - - inputs.Reset(); - if (filter_sel) { - // Slice to any filtered rows in [begin, end) - SelectionVector sel; - - // Find the first value in [begin, end) - for (; filter_idx < filtered; ++filter_idx) { - auto idx = filter_sel->get_index(filter_idx); - if (idx >= begin) { - break; - } - } - - // Find the first value in [end, filtered) - sel.Initialize(filter_sel->data() + filter_idx); - idx_t nsel = 0; - for (; filter_idx < filtered; ++filter_idx, ++nsel) { - auto idx = filter_sel->get_index(filter_idx); - if (idx >= end) { - break; - } - } - - if (nsel != inputs.size()) { - inputs.Slice(payload_chunk, sel, nsel); - } - } else { - // Slice to [begin, end) - if (begin) { - for (idx_t c = 0; c < payload_chunk.ColumnCount(); ++c) { - inputs.data[c].Slice(payload_chunk.data[c], begin, end); - } - } else { - inputs.Reference(payload_chunk); - } - inputs.SetCardinality(end - begin); - } - - // Aggregate the filtered rows into a single state - const auto count = inputs.size(); - auto state = state_f_data[partition]; - if (aggr.function.simple_update) { - aggr.function.simple_update(inputs.data.data(), aggr_input_data, inputs.ColumnCount(), state, count); - } else { - state_p_data[0] = state_f_data[partition]; - aggr.function.update(inputs.data.data(), aggr_input_data, inputs.ColumnCount(), statep, count); - } - - // Skip filtered rows too! - row += end - begin; - begin = end; - } -} - -void WindowConstantAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, - CollectionPtr collection, const FrameStats &stats) { - auto &gastate = gstate.Cast(); - auto &lastate = lstate.Cast(); - - // Single-threaded combine - lock_guard finalize_guard(gastate.lock); - lastate.statef.Combine(gastate.statef); - lastate.statef.Destroy(); - - // Last one out turns off the lights! - if (++gastate.finalized == gastate.locals) { - gastate.statef.Finalize(*gastate.results); - gastate.statef.Destroy(); - } -} - -unique_ptr WindowConstantAggregator::GetLocalState(const WindowAggregatorState &gstate) const { - return make_uniq(gstate.Cast()); -} - -void WindowConstantAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { - auto &gasink = gsink.Cast(); - const auto &partition_offsets = gasink.partition_offsets; - const auto &results = *gasink.results; - - auto begins = FlatVector::GetData(bounds.data[FRAME_BEGIN]); - // Chunk up the constants and copy them one at a time - auto &lcstate = lstate.Cast(); - idx_t matched = 0; - idx_t target_offset = 0; - for (idx_t i = 0; i < count; ++i) { - const auto begin = begins[i]; - // Find the partition containing [begin, end) - while (partition_offsets[lcstate.partition + 1] <= begin) { - // Flush the previous partition's data - if (matched) { - VectorOperations::Copy(results, result, lcstate.matches, matched, 0, target_offset); - target_offset += matched; - matched = 0; - } - ++lcstate.partition; - } - - lcstate.matches.set_index(matched++, lcstate.partition); - } - - // Flush the last partition - if (matched) { - // Optimize constant result - if (target_offset == 0 && matched == count) { - VectorOperations::Copy(results, result, lcstate.matches, 1, 0, target_offset); - result.SetVectorType(VectorType::CONSTANT_VECTOR); - } else { - VectorOperations::Copy(results, result, lcstate.matches, matched, 0, target_offset); - } - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_custom_aggregator.cpp b/src/duckdb/src/function/window/window_custom_aggregator.cpp deleted file mode 100644 index 8416e3031..000000000 --- a/src/duckdb/src/function/window/window_custom_aggregator.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "duckdb/function/window/window_custom_aggregator.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowCustomAggregator -//===--------------------------------------------------------------------===// -bool WindowCustomAggregator::CanAggregate(const BoundWindowExpression &wexpr, WindowAggregationMode mode) { - if (!wexpr.aggregate) { - return false; - } - - if (!wexpr.aggregate->window) { - return false; - } - - // ORDER BY arguments are not currently supported - if (!wexpr.arg_orders.empty()) { - return false; - } - - return (mode < WindowAggregationMode::COMBINE); -} - -WindowCustomAggregator::WindowCustomAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared) - : WindowAggregator(wexpr, shared) { -} - -WindowCustomAggregator::~WindowCustomAggregator() { -} - -class WindowCustomAggregatorState : public WindowAggregatorLocalState { -public: - WindowCustomAggregatorState(const AggregateObject &aggr, const WindowExcludeMode exclude_mode); - ~WindowCustomAggregatorState() override; - -public: - //! The aggregate function - const AggregateObject aggr; - //! Data pointer that contains a single state, shared by all the custom evaluators - vector state; - //! Reused result state container for the window functions - Vector statef; - //! The frame boundaries, used for the window functions - SubFrames frames; -}; - -class WindowCustomAggregatorGlobalState : public WindowAggregatorGlobalState { -public: - explicit WindowCustomAggregatorGlobalState(ClientContext &context, const WindowCustomAggregator &aggregator, - idx_t group_count) - : WindowAggregatorGlobalState(context, aggregator, group_count), context(context) { - - gcstate = make_uniq(aggr, aggregator.exclude_mode); - } - - //! Buffer manager for paging custom accelerator data - ClientContext &context; - //! Traditional packed filter mask for API - ValidityMask filter_packed; - //! Data pointer that contains a single local state, used for global custom window execution state - unique_ptr gcstate; - //! Partition description for custom window APIs - unique_ptr partition_input; -}; - -WindowCustomAggregatorState::WindowCustomAggregatorState(const AggregateObject &aggr, - const WindowExcludeMode exclude_mode) - : aggr(aggr), state(aggr.function.state_size(aggr.function)), - statef(Value::POINTER(CastPointerToValue(state.data()))), frames(3, {0, 0}) { - // if we have a frame-by-frame method, share the single state - aggr.function.initialize(aggr.function, state.data()); - - InitSubFrames(frames, exclude_mode); -} - -WindowCustomAggregatorState::~WindowCustomAggregatorState() { - if (aggr.function.destructor) { - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.destructor(statef, aggr_input_data, 1); - } -} - -unique_ptr WindowCustomAggregator::GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &) const { - return make_uniq(context, *this, group_count); -} - -void WindowCustomAggregator::Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, - CollectionPtr collection, const FrameStats &stats) { - // Single threaded Finalize for now - auto &gcsink = gstate.Cast(); - lock_guard gestate_guard(gcsink.lock); - if (gcsink.finalized) { - return; - } - - WindowAggregator::Finalize(gstate, lstate, collection, stats); - - auto inputs = collection->inputs.get(); - const auto count = collection->size(); - vector all_valids; - for (auto col_idx : child_idx) { - all_valids.push_back(collection->all_valids[col_idx]); - } - auto &filter_mask = gcsink.filter_mask; - auto &filter_packed = gcsink.filter_packed; - filter_mask.Pack(filter_packed, filter_mask.Capacity()); - - gcsink.partition_input = - make_uniq(gcsink.context, inputs, count, child_idx, all_valids, filter_packed, stats); - - if (aggr.function.window_init) { - auto &gcstate = *gcsink.gcstate; - - AggregateInputData aggr_input_data(aggr.GetFunctionData(), gcstate.allocator); - aggr.function.window_init(aggr_input_data, *gcsink.partition_input, gcstate.state.data()); - } - - ++gcsink.finalized; -} - -unique_ptr WindowCustomAggregator::GetLocalState(const WindowAggregatorState &gstate) const { - return make_uniq(aggr, exclude_mode); -} - -void WindowCustomAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { - auto &lcstate = lstate.Cast(); - auto &frames = lcstate.frames; - const_data_ptr_t gstate_p = nullptr; - auto &gcsink = gsink.Cast(); - if (gcsink.gcstate) { - gstate_p = gcsink.gcstate->state.data(); - } - - EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t i) { - // Extract the range - AggregateInputData aggr_input_data(aggr.GetFunctionData(), lstate.allocator); - aggr.function.window(aggr_input_data, *gcsink.partition_input, gstate_p, lcstate.state.data(), frames, result, - i); - }); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_distinct_aggregator.cpp b/src/duckdb/src/function/window/window_distinct_aggregator.cpp deleted file mode 100644 index 1dc940f95..000000000 --- a/src/duckdb/src/function/window/window_distinct_aggregator.cpp +++ /dev/null @@ -1,758 +0,0 @@ -#include "duckdb/function/window/window_distinct_aggregator.hpp" - -#include "duckdb/common/sort/partition_state.hpp" -#include "duckdb/common/sort/sort.hpp" -#include "duckdb/execution/merge_sort_tree.hpp" -#include "duckdb/function/window/window_aggregate_states.hpp" -#include "duckdb/planner/bound_result_modifier.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -#include -#include - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowDistinctAggregator -//===--------------------------------------------------------------------===// -bool WindowDistinctAggregator::CanAggregate(const BoundWindowExpression &wexpr) { - if (!wexpr.aggregate) { - return false; - } - - return wexpr.distinct && wexpr.exclude_clause == WindowExcludeMode::NO_OTHER && wexpr.arg_orders.empty(); -} - -WindowDistinctAggregator::WindowDistinctAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared, - ClientContext &context) - : WindowAggregator(wexpr, shared), context(context) { -} - -class WindowDistinctAggregatorLocalState; - -class WindowDistinctAggregatorGlobalState; - -class WindowDistinctSortTree : public MergeSortTree { -public: - // prev_idx, input_idx - using ZippedTuple = std::tuple; - using ZippedElements = vector; - - explicit WindowDistinctSortTree(WindowDistinctAggregatorGlobalState &gdastate, idx_t count) : gdastate(gdastate) { - // Set up for parallel build - build_level = 0; - build_complete = 0; - build_run = 0; - build_run_length = 1; - build_num_runs = count; - } - - void Build(WindowDistinctAggregatorLocalState &ldastate); - -protected: - bool TryNextRun(idx_t &level_idx, idx_t &run_idx); - void BuildRun(idx_t level_nr, idx_t i, WindowDistinctAggregatorLocalState &ldastate); - - WindowDistinctAggregatorGlobalState &gdastate; -}; - -class WindowDistinctAggregatorGlobalState : public WindowAggregatorGlobalState { -public: - using GlobalSortStatePtr = unique_ptr; - using LocalSortStatePtr = unique_ptr; - using ZippedTuple = WindowDistinctSortTree::ZippedTuple; - using ZippedElements = WindowDistinctSortTree::ZippedElements; - - WindowDistinctAggregatorGlobalState(ClientContext &context, const WindowDistinctAggregator &aggregator, - idx_t group_count); - - //! Compute the block starts - void MeasurePayloadBlocks(); - //! Create a new local sort - optional_ptr InitializeLocalSort() const; - - //! Patch up the previous index block boundaries - void PatchPrevIdcs(); - bool TryPrepareNextStage(WindowDistinctAggregatorLocalState &lstate); - - // Single threaded sorting for now - ClientContext &context; - idx_t memory_per_thread; - - //! Finalize guard - mutable mutex lock; - //! Finalize stage - atomic stage; - //! Tasks launched - idx_t total_tasks = 0; - //! Tasks launched - mutable idx_t tasks_assigned; - //! Tasks landed - mutable atomic tasks_completed; - - //! The sorted payload data types (partition index) - vector payload_types; - //! The aggregate arguments + partition index - vector sort_types; - - //! Sorting operations - GlobalSortStatePtr global_sort; - //! Local sort set - mutable vector local_sorts; - //! The block starts (the scanner doesn't know this) plus the total count - vector block_starts; - - //! The block boundary seconds - mutable ZippedElements seconds; - //! The MST with the distinct back pointers - mutable MergeSortTree zipped_tree; - //! The merge sort tree for the aggregate. - WindowDistinctSortTree merge_sort_tree; - - //! The actual window segment tree: an array of aggregate states that represent all the intermediate nodes - WindowAggregateStates levels_flat_native; - //! For each level, the starting location in the levels_flat_native array - vector levels_flat_start; -}; - -WindowDistinctAggregatorGlobalState::WindowDistinctAggregatorGlobalState(ClientContext &context, - const WindowDistinctAggregator &aggregator, - idx_t group_count) - : WindowAggregatorGlobalState(context, aggregator, group_count), context(aggregator.context), - stage(PartitionSortStage::INIT), tasks_assigned(0), tasks_completed(0), merge_sort_tree(*this, group_count), - levels_flat_native(aggr) { - payload_types.emplace_back(LogicalType::UBIGINT); - - // 1: functionComputePrevIdcs(𝑖𝑛) - // 2: sorted ← [] - // We sort the aggregate arguments and use the partition index as a tie-breaker. - // TODO: Use a hash table? - sort_types = aggregator.arg_types; - for (const auto &type : payload_types) { - sort_types.emplace_back(type); - } - - vector orders; - for (const auto &type : sort_types) { - auto expr = make_uniq(Value(type)); - orders.emplace_back(BoundOrderByNode(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, std::move(expr))); - } - - RowLayout payload_layout; - payload_layout.Initialize(payload_types); - - global_sort = make_uniq(BufferManager::GetBufferManager(context), orders, payload_layout); - - memory_per_thread = PhysicalOperator::GetMaxThreadMemory(context); - - // 6: prevIdcs ← [] - // 7: prevIdcs[0] ← “-” - auto &prev_idcs = zipped_tree.Allocate(group_count); - - // To handle FILTER clauses we make the missing elements - // point to themselves so they won't be counted. - for (idx_t i = 0; i < group_count; ++i) { - prev_idcs[i] = ZippedTuple(i + 1, i); - } - - // compute space required to store aggregation states of merge sort tree - // this is one aggregate state per entry per level - idx_t internal_nodes = 0; - levels_flat_start.push_back(internal_nodes); - for (idx_t level_nr = 0; level_nr < zipped_tree.tree.size(); ++level_nr) { - internal_nodes += zipped_tree.tree[level_nr].first.size(); - levels_flat_start.push_back(internal_nodes); - } - levels_flat_native.Initialize(internal_nodes); - - merge_sort_tree.tree.reserve(zipped_tree.tree.size()); - for (idx_t level_nr = 0; level_nr < zipped_tree.tree.size(); ++level_nr) { - auto &zipped_level = zipped_tree.tree[level_nr].first; - WindowDistinctSortTree::Elements level; - WindowDistinctSortTree::Offsets cascades; - level.resize(zipped_level.size()); - merge_sort_tree.tree.emplace_back(std::move(level), std::move(cascades)); - } -} - -optional_ptr WindowDistinctAggregatorGlobalState::InitializeLocalSort() const { - lock_guard local_sort_guard(lock); - auto local_sort = make_uniq(); - local_sort->Initialize(*global_sort, global_sort->buffer_manager); - ++tasks_assigned; - local_sorts.emplace_back(std::move(local_sort)); - - return local_sorts.back().get(); -} - -class WindowDistinctAggregatorLocalState : public WindowAggregatorLocalState { -public: - explicit WindowDistinctAggregatorLocalState(const WindowDistinctAggregatorGlobalState &aggregator); - - void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered); - void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; - void Sorted(); - void ExecuteTask(); - void Evaluate(const WindowDistinctAggregatorGlobalState &gdstate, const DataChunk &bounds, Vector &result, - idx_t count, idx_t row_idx); - - //! Thread-local sorting data - optional_ptr local_sort; - //! Finalize stage - PartitionSortStage stage = PartitionSortStage::INIT; - //! Finalize scan block index - idx_t block_idx; - //! Thread-local tree aggregation - Vector update_v; - Vector source_v; - Vector target_v; - DataChunk leaves; - SelectionVector sel; - -protected: - //! Flush the accumulated intermediate states into the result states - void FlushStates(); - - //! The aggregator we are working with - const WindowDistinctAggregatorGlobalState &gastate; - DataChunk sort_chunk; - DataChunk payload_chunk; - //! Reused result state container for the window functions - WindowAggregateStates statef; - //! A vector of pointers to "state", used for buffering intermediate aggregates - Vector statep; - //! Reused state pointers for combining tree elements - Vector statel; - //! Count of buffered values - idx_t flush_count; - //! The frame boundaries, used for the window functions - SubFrames frames; -}; - -WindowDistinctAggregatorLocalState::WindowDistinctAggregatorLocalState( - const WindowDistinctAggregatorGlobalState &gastate) - : update_v(LogicalType::POINTER), source_v(LogicalType::POINTER), target_v(LogicalType::POINTER), gastate(gastate), - statef(gastate.aggr), statep(LogicalType::POINTER), statel(LogicalType::POINTER), flush_count(0) { - InitSubFrames(frames, gastate.aggregator.exclude_mode); - payload_chunk.Initialize(Allocator::DefaultAllocator(), gastate.payload_types); - - sort_chunk.Initialize(Allocator::DefaultAllocator(), gastate.sort_types); - sort_chunk.data.back().Reference(payload_chunk.data[0]); - - gastate.locals++; -} - -unique_ptr WindowDistinctAggregator::GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const { - return make_uniq(context, *this, group_count); -} - -void WindowDistinctAggregator::Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered) { - WindowAggregator::Sink(gsink, lstate, sink_chunk, coll_chunk, input_idx, filter_sel, filtered); - - auto &ldstate = lstate.Cast(); - ldstate.Sink(sink_chunk, coll_chunk, input_idx, filter_sel, filtered); -} - -void WindowDistinctAggregatorLocalState::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx, - optional_ptr filter_sel, idx_t filtered) { - // 3: for i ← 0 to in.size do - // 4: sorted[i] ← (in[i], i) - const auto count = sink_chunk.size(); - payload_chunk.Reset(); - auto &sorted_vec = payload_chunk.data[0]; - auto sorted = FlatVector::GetData(sorted_vec); - std::iota(sorted, sorted + count, input_idx); - - // Our arguments are being fully materialised, - // but we also need them as sort keys. - auto &child_idx = gastate.aggregator.child_idx; - for (column_t c = 0; c < child_idx.size(); ++c) { - sort_chunk.data[c].Reference(coll_chunk.data[child_idx[c]]); - } - sort_chunk.data.back().Reference(sorted_vec); - sort_chunk.SetCardinality(sink_chunk); - payload_chunk.SetCardinality(sort_chunk); - - // Apply FILTER clause, if any - if (filter_sel) { - sort_chunk.Slice(*filter_sel, filtered); - payload_chunk.Slice(*filter_sel, filtered); - } - - if (!local_sort) { - local_sort = gastate.InitializeLocalSort(); - } - - local_sort->SinkChunk(sort_chunk, payload_chunk); - - if (local_sort->SizeInBytes() > gastate.memory_per_thread) { - local_sort->Sort(*gastate.global_sort, true); - } -} - -void WindowDistinctAggregatorLocalState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { - WindowAggregatorLocalState::Finalize(gastate, collection); - - //! Input data chunk, used for leaf segment aggregation - leaves.Initialize(Allocator::DefaultAllocator(), cursor->chunk.GetTypes()); - sel.Initialize(); -} - -void WindowDistinctAggregatorLocalState::ExecuteTask() { - auto &global_sort = *gastate.global_sort; - switch (stage) { - case PartitionSortStage::SCAN: - global_sort.AddLocalState(*gastate.local_sorts[block_idx]); - break; - case PartitionSortStage::MERGE: { - MergeSorter merge_sorter(global_sort, global_sort.buffer_manager); - merge_sorter.PerformInMergeRound(); - break; - } - case PartitionSortStage::SORTED: - Sorted(); - break; - default: - break; - } - - ++gastate.tasks_completed; -} - -void WindowDistinctAggregatorGlobalState::MeasurePayloadBlocks() { - const auto &blocks = global_sort->sorted_blocks[0]->payload_data->data_blocks; - idx_t count = 0; - for (const auto &block : blocks) { - block_starts.emplace_back(count); - count += block->count; - } - block_starts.emplace_back(count); -} - -bool WindowDistinctAggregatorGlobalState::TryPrepareNextStage(WindowDistinctAggregatorLocalState &lstate) { - lock_guard stage_guard(lock); - - switch (stage.load()) { - case PartitionSortStage::INIT: - // 5: Sort sorted lexicographically increasing - total_tasks = local_sorts.size(); - tasks_assigned = 0; - tasks_completed = 0; - lstate.stage = stage = PartitionSortStage::SCAN; - lstate.block_idx = tasks_assigned++; - return true; - case PartitionSortStage::SCAN: - // Process all the local sorts - if (tasks_assigned < total_tasks) { - lstate.stage = PartitionSortStage::SCAN; - lstate.block_idx = tasks_assigned++; - return true; - } else if (tasks_completed < tasks_assigned) { - return false; - } - global_sort->PrepareMergePhase(); - if (!(global_sort->sorted_blocks.size() / 2)) { - if (global_sort->sorted_blocks.empty()) { - lstate.stage = stage = PartitionSortStage::FINISHED; - return true; - } - MeasurePayloadBlocks(); - seconds.resize(block_starts.size() - 1); - total_tasks = seconds.size(); - tasks_completed = 0; - tasks_assigned = 0; - lstate.stage = stage = PartitionSortStage::SORTED; - lstate.block_idx = tasks_assigned++; - return true; - } - global_sort->InitializeMergeRound(); - lstate.stage = stage = PartitionSortStage::MERGE; - total_tasks = locals; - tasks_assigned = 1; - tasks_completed = 0; - return true; - case PartitionSortStage::MERGE: - if (tasks_assigned < total_tasks) { - lstate.stage = PartitionSortStage::MERGE; - ++tasks_assigned; - return true; - } else if (tasks_completed < tasks_assigned) { - return false; - } - global_sort->CompleteMergeRound(true); - if (!(global_sort->sorted_blocks.size() / 2)) { - MeasurePayloadBlocks(); - seconds.resize(block_starts.size() - 1); - total_tasks = seconds.size(); - tasks_completed = 0; - tasks_assigned = 0; - lstate.stage = stage = PartitionSortStage::SORTED; - lstate.block_idx = tasks_assigned++; - return true; - } - global_sort->InitializeMergeRound(); - lstate.stage = PartitionSortStage::MERGE; - total_tasks = locals; - tasks_assigned = 1; - tasks_completed = 0; - return true; - case PartitionSortStage::SORTED: - if (tasks_assigned < total_tasks) { - lstate.stage = PartitionSortStage::SORTED; - lstate.block_idx = tasks_assigned++; - return true; - } else if (tasks_completed < tasks_assigned) { - lstate.stage = PartitionSortStage::FINISHED; - // Sleep while other tasks finish - return false; - } - // Last task patches the boundaries - PatchPrevIdcs(); - break; - default: - break; - } - - lstate.stage = stage = PartitionSortStage::FINISHED; - - return true; -} - -void WindowDistinctAggregator::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, - CollectionPtr collection, const FrameStats &stats) { - auto &gdsink = gsink.Cast(); - auto &ldstate = lstate.Cast(); - ldstate.Finalize(gdsink, collection); - - // Sort, merge and build the tree in parallel - while (gdsink.stage.load() != PartitionSortStage::FINISHED) { - if (gdsink.TryPrepareNextStage(ldstate)) { - ldstate.ExecuteTask(); - } else { - std::this_thread::yield(); - } - } - - // These are a parallel implementations, - // so every thread can call them. - gdsink.zipped_tree.Build(); - gdsink.merge_sort_tree.Build(ldstate); - - ++gdsink.finalized; -} - -void WindowDistinctAggregatorLocalState::Sorted() { - using ZippedTuple = WindowDistinctAggregatorGlobalState::ZippedTuple; - auto &global_sort = gastate.global_sort; - auto &prev_idcs = gastate.zipped_tree.LowestLevel(); - auto &aggregator = gastate.aggregator; - auto &scan_chunk = payload_chunk; - - auto scanner = make_uniq(*global_sort, block_idx); - const auto in_size = gastate.block_starts.at(block_idx + 1); - scanner->Scan(scan_chunk); - idx_t scan_idx = 0; - - auto *input_idx = FlatVector::GetData(scan_chunk.data[0]); - idx_t i = 0; - - SBIterator curr(*global_sort, ExpressionType::COMPARE_LESSTHAN); - SBIterator prev(*global_sort, ExpressionType::COMPARE_LESSTHAN); - auto prefix_layout = global_sort->sort_layout.GetPrefixComparisonLayout(aggregator.arg_types.size()); - - const auto block_begin = gastate.block_starts.at(block_idx); - if (!block_begin) { - // First block, so set up initial sentinel - i = input_idx[scan_idx++]; - prev_idcs[i] = ZippedTuple(0, i); - std::get<0>(gastate.seconds[block_idx]) = i; - } else { - // Move to the to end of the previous block - // so we can record the comparison result for the first row - curr.SetIndex(block_begin - 1); - prev.SetIndex(block_begin - 1); - scan_idx = 0; - std::get<0>(gastate.seconds[block_idx]) = input_idx[scan_idx]; - } - - // 8: for i ← 1 to in.size do - for (++curr; curr.GetIndex() < in_size; ++curr, ++prev) { - // Scan second one chunk at a time - // Note the scan is one behind the iterators - if (scan_idx >= scan_chunk.size()) { - scan_chunk.Reset(); - scanner->Scan(scan_chunk); - scan_idx = 0; - input_idx = FlatVector::GetData(scan_chunk.data[0]); - } - auto second = i; - i = input_idx[scan_idx++]; - - int lt = 0; - if (prefix_layout.all_constant) { - lt = FastMemcmp(prev.entry_ptr, curr.entry_ptr, prefix_layout.comparison_size); - } else { - lt = Comparators::CompareTuple(prev.scan, curr.scan, prev.entry_ptr, curr.entry_ptr, prefix_layout, - prev.external); - } - - // 9: if sorted[i].first == sorted[i-1].first then - // 10: prevIdcs[i] ← sorted[i-1].second - // 11: else - // 12: prevIdcs[i] ← “-” - if (!lt) { - prev_idcs[i] = ZippedTuple(second + 1, i); - } else { - prev_idcs[i] = ZippedTuple(0, i); - } - } - - // Save the last value of i for patching up the block boundaries - std::get<1>(gastate.seconds[block_idx]) = i; -} - -void WindowDistinctAggregatorGlobalState::PatchPrevIdcs() { - // 13: return prevIdcs - - // Patch up the indices at block boundaries - // (We don't need to patch block 0.) - auto &prev_idcs = zipped_tree.LowestLevel(); - for (idx_t block_idx = 1; block_idx < seconds.size(); ++block_idx) { - // We only need to patch if the first index in the block - // was a back link to the previous block (10:) - auto i = std::get<0>(seconds.at(block_idx)); - if (std::get<0>(prev_idcs[i])) { - auto second = std::get<1>(seconds.at(block_idx - 1)); - prev_idcs[i] = ZippedTuple(second + 1, i); - } - } -} - -bool WindowDistinctSortTree::TryNextRun(idx_t &level_idx, idx_t &run_idx) { - const auto fanout = FANOUT; - - lock_guard stage_guard(build_lock); - - // Verify we are not done - if (build_level >= tree.size()) { - return false; - } - - // Finished with this level? - if (build_complete >= build_num_runs) { - auto &zipped_tree = gdastate.zipped_tree; - std::swap(tree[build_level].second, zipped_tree.tree[build_level].second); - - ++build_level; - if (build_level >= tree.size()) { - zipped_tree.tree.clear(); - return false; - } - - const auto count = LowestLevel().size(); - build_run_length *= fanout; - build_num_runs = (count + build_run_length - 1) / build_run_length; - build_run = 0; - build_complete = 0; - } - - // If all runs are in flight, - // yield until the next level is ready - if (build_run >= build_num_runs) { - return false; - } - - level_idx = build_level; - run_idx = build_run++; - - return true; -} - -void WindowDistinctSortTree::Build(WindowDistinctAggregatorLocalState &ldastate) { - // Fan in parent levels until we are at the top - // Note that we don't build the top layer as that would just be all the data. - while (build_level.load() < tree.size()) { - idx_t level_idx; - idx_t run_idx; - if (TryNextRun(level_idx, run_idx)) { - BuildRun(level_idx, run_idx, ldastate); - } else { - std::this_thread::yield(); - } - } -} - -void WindowDistinctSortTree::BuildRun(idx_t level_nr, idx_t run_idx, WindowDistinctAggregatorLocalState &ldastate) { - auto &aggr = gdastate.aggr; - auto &allocator = gdastate.allocator; - auto &inputs = ldastate.cursor->chunk; - auto &levels_flat_native = gdastate.levels_flat_native; - - //! Input data chunk, used for leaf segment aggregation - auto &leaves = ldastate.leaves; - auto &sel = ldastate.sel; - - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - - //! The states to update - auto &update_v = ldastate.update_v; - auto updates = FlatVector::GetData(update_v); - - auto &source_v = ldastate.source_v; - auto sources = FlatVector::GetData(source_v); - auto &target_v = ldastate.target_v; - auto targets = FlatVector::GetData(target_v); - - auto &zipped_tree = gdastate.zipped_tree; - auto &zipped_level = zipped_tree.tree[level_nr].first; - auto &level = tree[level_nr].first; - - // Reset the combine state - idx_t nupdate = 0; - idx_t ncombine = 0; - data_ptr_t prev_state = nullptr; - idx_t i = run_idx * build_run_length; - auto next_limit = MinValue(zipped_level.size(), i + build_run_length); - idx_t levels_flat_offset = level_nr * zipped_level.size() + i; - for (auto j = i; j < next_limit; ++j) { - // Initialise the next aggregate - auto curr_state = levels_flat_native.GetStatePtr(levels_flat_offset++); - - // Update this state (if it matches) - const auto prev_idx = std::get<0>(zipped_level[j]); - level[j] = prev_idx; - if (prev_idx < i + 1) { - const auto update_idx = std::get<1>(zipped_level[j]); - if (!ldastate.cursor->RowIsVisible(update_idx)) { - // Flush if we have to move the cursor - // Push the updates first so they propagate - leaves.Reference(inputs); - leaves.Slice(sel, nupdate); - aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); - nupdate = 0; - - // Combine the states sequentially - aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); - ncombine = 0; - - // Move the update into range. - ldastate.cursor->Seek(update_idx); - } - - updates[nupdate] = curr_state; - // input_idx - sel[nupdate] = ldastate.cursor->RowOffset(update_idx); - ++nupdate; - } - - // Merge the previous state (if any) - if (prev_state) { - sources[ncombine] = prev_state; - targets[ncombine] = curr_state; - ++ncombine; - } - prev_state = curr_state; - - // Flush the states if one is maxed out. - if (MaxValue(ncombine, nupdate) >= STANDARD_VECTOR_SIZE) { - // Push the updates first so they propagate - leaves.Reference(inputs); - leaves.Slice(sel, nupdate); - aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); - nupdate = 0; - - // Combine the states sequentially - aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); - ncombine = 0; - } - } - - // Flush any remaining states - if (ncombine || nupdate) { - // Push the updates - leaves.Reference(inputs); - leaves.Slice(sel, nupdate); - aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), update_v, nupdate); - nupdate = 0; - - // Combine the states sequentially - aggr.function.combine(source_v, target_v, aggr_input_data, ncombine); - ncombine = 0; - } - - ++build_complete; -} - -void WindowDistinctAggregatorLocalState::FlushStates() { - if (!flush_count) { - return; - } - - const auto &aggr = gastate.aggr; - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - statel.Verify(flush_count); - aggr.function.combine(statel, statep, aggr_input_data, flush_count); - - flush_count = 0; -} - -void WindowDistinctAggregatorLocalState::Evaluate(const WindowDistinctAggregatorGlobalState &gdstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) { - auto ldata = FlatVector::GetData(statel); - auto pdata = FlatVector::GetData(statep); - - const auto &merge_sort_tree = gdstate.merge_sort_tree; - const auto &levels_flat_native = gdstate.levels_flat_native; - const auto exclude_mode = gdstate.aggregator.exclude_mode; - - // Build the finalise vector that just points to the result states - statef.Initialize(count); - - WindowAggregator::EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t rid) { - auto agg_state = statef.GetStatePtr(rid); - - // TODO: Extend AggregateLowerBound to handle subframes, just like SelectNth. - const auto lower = frames[0].start; - const auto upper = frames[0].end; - merge_sort_tree.AggregateLowerBound(lower, upper, lower + 1, - [&](idx_t level, const idx_t run_begin, const idx_t run_pos) { - if (run_pos != run_begin) { - // Find the source aggregate - // Buffer a merge of the indicated state into the current state - const auto agg_idx = gdstate.levels_flat_start[level] + run_pos - 1; - const auto running_agg = levels_flat_native.GetStatePtr(agg_idx); - pdata[flush_count] = agg_state; - ldata[flush_count++] = running_agg; - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(); - } - } - }); - }); - - // Flush the final states - FlushStates(); - - // Finalise the result aggregates and write to the result - statef.Finalize(result); - statef.Destroy(); -} - -unique_ptr WindowDistinctAggregator::GetLocalState(const WindowAggregatorState &gstate) const { - return make_uniq(gstate.Cast()); -} - -void WindowDistinctAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { - - const auto &gdstate = gsink.Cast(); - auto &ldstate = lstate.Cast(); - ldstate.Evaluate(gdstate, bounds, result, count, row_idx); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_executor.cpp b/src/duckdb/src/function/window/window_executor.cpp deleted file mode 100644 index faa7215e4..000000000 --- a/src/duckdb/src/function/window/window_executor.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "duckdb/function/window/window_executor.hpp" - -#include "duckdb/function/window/window_shared_expressions.hpp" - -#include "duckdb/common/array.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowExecutorBoundsState -//===--------------------------------------------------------------------===// -WindowExecutorBoundsState::WindowExecutorBoundsState(const WindowExecutorGlobalState &gstate) - : WindowExecutorLocalState(gstate), partition_mask(gstate.partition_mask), order_mask(gstate.order_mask), - state(gstate.executor.wexpr, gstate.payload_count) { - vector bounds_types(8, LogicalType(LogicalTypeId::UBIGINT)); - bounds.Initialize(Allocator::Get(gstate.executor.context), bounds_types); -} - -void WindowExecutorBoundsState::UpdateBounds(WindowExecutorGlobalState &gstate, idx_t row_idx, DataChunk &eval_chunk, - optional_ptr range) { - // Evaluate the row-level arguments - WindowInputExpression boundary_start(eval_chunk, gstate.executor.boundary_start_idx); - WindowInputExpression boundary_end(eval_chunk, gstate.executor.boundary_end_idx); - - const auto count = eval_chunk.size(); - state.Bounds(bounds, row_idx, range, count, boundary_start, boundary_end, partition_mask, order_mask); -} - -//===--------------------------------------------------------------------===// -// WindowExecutor -//===--------------------------------------------------------------------===// -WindowExecutor::WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared) - : wexpr(wexpr), context(context), - range_expr((WindowBoundariesState::HasPrecedingRange(wexpr) || WindowBoundariesState::HasFollowingRange(wexpr)) - ? wexpr.orders[0].expression.get() - : nullptr) { - if (range_expr) { - range_idx = shared.RegisterCollection(wexpr.orders[0].expression, false); - } - - boundary_start_idx = shared.RegisterEvaluate(wexpr.start_expr); - boundary_end_idx = shared.RegisterEvaluate(wexpr.end_expr); -} - -void WindowExecutor::Evaluate(idx_t row_idx, DataChunk &eval_chunk, Vector &result, WindowExecutorLocalState &lstate, - WindowExecutorGlobalState &gstate) const { - auto &lbstate = lstate.Cast(); - lbstate.UpdateBounds(gstate, row_idx, eval_chunk, lstate.range_cursor); - - const auto count = eval_chunk.size(); - EvaluateInternal(gstate, lstate, eval_chunk, result, count, row_idx); - - result.Verify(count); -} - -WindowExecutorGlobalState::WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) - : executor(executor), payload_count(payload_count), partition_mask(partition_mask), order_mask(order_mask) { - for (const auto &child : executor.wexpr.children) { - arg_types.emplace_back(child->return_type); - } -} - -WindowExecutorLocalState::WindowExecutorLocalState(const WindowExecutorGlobalState &gstate) { -} - -void WindowExecutorLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) { -} - -void WindowExecutorLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { - const auto range_idx = gstate.executor.range_idx; - if (range_idx != DConstants::INVALID_INDEX) { - range_cursor = make_uniq(*collection, range_idx); - } -} - -unique_ptr WindowExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -unique_ptr WindowExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - return make_uniq(gstate); -} - -void WindowExecutor::Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, - WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { - lstate.Sink(gstate, sink_chunk, coll_chunk, input_idx); -} - -void WindowExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const { - lstate.Finalize(gstate, collection); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_index_tree.cpp b/src/duckdb/src/function/window/window_index_tree.cpp deleted file mode 100644 index 5791b2af7..000000000 --- a/src/duckdb/src/function/window/window_index_tree.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "duckdb/function/window/window_index_tree.hpp" - -#include -#include - -namespace duckdb { - -WindowIndexTree::WindowIndexTree(ClientContext &context, const vector &orders, - const vector &sort_idx, const idx_t count) - : WindowMergeSortTree(context, orders, sort_idx, count) { -} - -WindowIndexTree::WindowIndexTree(ClientContext &context, const BoundOrderModifier &order_bys, - const vector &sort_idx, const idx_t count) - : WindowIndexTree(context, order_bys.orders, sort_idx, count) { -} - -unique_ptr WindowIndexTree::GetLocalState() { - return make_uniq(*this); -} - -WindowIndexTreeLocalState::WindowIndexTreeLocalState(WindowIndexTree &index_tree) - : WindowMergeSortTreeLocalState(index_tree), index_tree(index_tree) { -} - -void WindowIndexTreeLocalState::BuildLeaves() { - auto &global_sort = *index_tree.global_sort; - if (global_sort.sorted_blocks.empty()) { - return; - } - - PayloadScanner scanner(global_sort, build_task); - idx_t row_idx = index_tree.block_starts[build_task]; - for (;;) { - payload_chunk.Reset(); - scanner.Scan(payload_chunk); - const auto count = payload_chunk.size(); - if (count == 0) { - break; - } - auto &indices = payload_chunk.data[0]; - if (index_tree.mst32) { - auto &sorted = index_tree.mst32->LowestLevel(); - auto data = FlatVector::GetData(indices); - std::copy(data, data + count, sorted.data() + row_idx); - } else { - auto &sorted = index_tree.mst64->LowestLevel(); - auto data = FlatVector::GetData(indices); - std::copy(data, data + count, sorted.data() + row_idx); - } - row_idx += count; - } -} - -idx_t WindowIndexTree::SelectNth(const SubFrames &frames, idx_t n) const { - if (mst32) { - return mst32->NthElement(mst32->SelectNth(frames, n)); - } else { - return mst64->NthElement(mst64->SelectNth(frames, n)); - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_merge_sort_tree.cpp b/src/duckdb/src/function/window/window_merge_sort_tree.cpp deleted file mode 100644 index ef22694c4..000000000 --- a/src/duckdb/src/function/window/window_merge_sort_tree.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "duckdb/function/window/window_merge_sort_tree.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" - -#include -#include - -namespace duckdb { - -WindowMergeSortTree::WindowMergeSortTree(ClientContext &context, const vector &orders, - const vector &sort_idx, const idx_t count, bool unique) - : context(context), memory_per_thread(PhysicalOperator::GetMaxThreadMemory(context)), sort_idx(sort_idx), - build_stage(PartitionSortStage::INIT), tasks_completed(0) { - // Sort the unfiltered indices by the orders - const auto force_external = ClientConfig::GetConfig(context).force_external; - LogicalType index_type; - if (count < std::numeric_limits::max() && !force_external) { - index_type = LogicalType::INTEGER; - mst32 = make_uniq(); - } else { - index_type = LogicalType::BIGINT; - mst64 = make_uniq(); - } - - vector payload_types; - payload_types.emplace_back(index_type); - - RowLayout payload_layout; - payload_layout.Initialize(payload_types); - - auto &buffer_manager = BufferManager::GetBufferManager(context); - if (unique) { - vector unique_orders; - for (const auto &order : orders) { - unique_orders.emplace_back(order.Copy()); - } - auto unique_expr = make_uniq(Value(index_type)); - const auto order_type = OrderType::ASCENDING; - const auto order_by_type = OrderByNullType::NULLS_LAST; - unique_orders.emplace_back(BoundOrderByNode(order_type, order_by_type, std::move(unique_expr))); - global_sort = make_uniq(buffer_manager, unique_orders, payload_layout); - } else { - global_sort = make_uniq(buffer_manager, orders, payload_layout); - } - global_sort->external = force_external; -} - -optional_ptr WindowMergeSortTree::AddLocalSort() { - lock_guard local_sort_guard(lock); - auto local_sort = make_uniq(); - local_sort->Initialize(*global_sort, global_sort->buffer_manager); - local_sorts.emplace_back(std::move(local_sort)); - - return local_sorts.back().get(); -} - -WindowMergeSortTreeLocalState::WindowMergeSortTreeLocalState(WindowMergeSortTree &window_tree) - : window_tree(window_tree) { - sort_chunk.Initialize(window_tree.context, window_tree.global_sort->sort_layout.logical_types); - payload_chunk.Initialize(window_tree.context, window_tree.global_sort->payload_layout.GetTypes()); - local_sort = window_tree.AddLocalSort(); -} - -void WindowMergeSortTreeLocalState::SinkChunk(DataChunk &chunk, const idx_t row_idx, - optional_ptr filter_sel, idx_t filtered) { - // Sequence the payload column - auto &indices = payload_chunk.data[0]; - payload_chunk.SetCardinality(chunk); - indices.Sequence(int64_t(row_idx), 1, payload_chunk.size()); - - // Reference the sort columns - auto &sort_idx = window_tree.sort_idx; - for (column_t c = 0; c < sort_idx.size(); ++c) { - sort_chunk.data[c].Reference(chunk.data[sort_idx[c]]); - } - // Add the row numbers if we are uniquifying - if (sort_idx.size() < sort_chunk.ColumnCount()) { - sort_chunk.data[sort_idx.size()].Reference(indices); - } - sort_chunk.SetCardinality(chunk); - - // Apply FILTER clause, if any - if (filter_sel) { - sort_chunk.Slice(*filter_sel, filtered); - payload_chunk.Slice(*filter_sel, filtered); - } - - local_sort->SinkChunk(sort_chunk, payload_chunk); - - // Flush if we have too much data - if (local_sort->SizeInBytes() > window_tree.memory_per_thread) { - local_sort->Sort(*window_tree.global_sort, true); - } -} - -void WindowMergeSortTreeLocalState::ExecuteSortTask() { - switch (build_stage) { - case PartitionSortStage::SCAN: - window_tree.global_sort->AddLocalState(*window_tree.local_sorts[build_task]); - break; - case PartitionSortStage::MERGE: { - auto &global_sort = *window_tree.global_sort; - MergeSorter merge_sorter(global_sort, global_sort.buffer_manager); - merge_sorter.PerformInMergeRound(); - break; - } - case PartitionSortStage::SORTED: - BuildLeaves(); - break; - default: - break; - } - - ++window_tree.tasks_completed; -} - -idx_t WindowMergeSortTree::MeasurePayloadBlocks() { - const auto &blocks = global_sort->sorted_blocks[0]->payload_data->data_blocks; - idx_t count = 0; - for (const auto &block : blocks) { - block_starts.emplace_back(count); - count += block->count; - } - block_starts.emplace_back(count); - - // Allocate the leaves. - if (mst32) { - mst32->Allocate(count); - mst32->LowestLevel().resize(count); - } else if (mst64) { - mst64->Allocate(count); - mst64->LowestLevel().resize(count); - } - - return count; -} - -void WindowMergeSortTreeLocalState::BuildLeaves() { - auto &global_sort = *window_tree.global_sort; - if (global_sort.sorted_blocks.empty()) { - return; - } - - PayloadScanner scanner(global_sort, build_task); - idx_t row_idx = window_tree.block_starts[build_task]; - for (;;) { - payload_chunk.Reset(); - scanner.Scan(payload_chunk); - const auto count = payload_chunk.size(); - if (count == 0) { - break; - } - auto &indices = payload_chunk.data[0]; - if (window_tree.mst32) { - auto &sorted = window_tree.mst32->LowestLevel(); - auto data = FlatVector::GetData(indices); - std::copy(data, data + count, sorted.data() + row_idx); - } else { - auto &sorted = window_tree.mst64->LowestLevel(); - auto data = FlatVector::GetData(indices); - std::copy(data, data + count, sorted.data() + row_idx); - } - row_idx += count; - } -} - -void WindowMergeSortTree::CleanupSort() { - global_sort.reset(); - local_sorts.clear(); -} - -bool WindowMergeSortTree::TryPrepareSortStage(WindowMergeSortTreeLocalState &lstate) { - lock_guard stage_guard(lock); - - switch (build_stage.load()) { - case PartitionSortStage::INIT: - total_tasks = local_sorts.size(); - tasks_assigned = 0; - tasks_completed = 0; - lstate.build_stage = build_stage = PartitionSortStage::SCAN; - lstate.build_task = tasks_assigned++; - return true; - case PartitionSortStage::SCAN: - // Process all the local sorts - if (tasks_assigned < total_tasks) { - lstate.build_stage = PartitionSortStage::SCAN; - lstate.build_task = tasks_assigned++; - return true; - } else if (tasks_completed < tasks_assigned) { - return false; - } - global_sort->PrepareMergePhase(); - if (!(global_sort->sorted_blocks.size() / 2)) { - if (global_sort->sorted_blocks.empty()) { - lstate.build_stage = build_stage = PartitionSortStage::FINISHED; - return true; - } - MeasurePayloadBlocks(); - total_tasks = block_starts.size() - 1; - tasks_completed = 0; - tasks_assigned = 0; - lstate.build_stage = build_stage = PartitionSortStage::SORTED; - lstate.build_task = tasks_assigned++; - return true; - } - global_sort->InitializeMergeRound(); - lstate.build_stage = build_stage = PartitionSortStage::MERGE; - total_tasks = local_sorts.size(); - tasks_assigned = 1; - tasks_completed = 0; - return true; - case PartitionSortStage::MERGE: - if (tasks_assigned < total_tasks) { - lstate.build_stage = PartitionSortStage::MERGE; - ++tasks_assigned; - return true; - } else if (tasks_completed < tasks_assigned) { - return false; - } - global_sort->CompleteMergeRound(true); - if (!(global_sort->sorted_blocks.size() / 2)) { - MeasurePayloadBlocks(); - total_tasks = block_starts.size() - 1; - tasks_completed = 0; - tasks_assigned = 0; - lstate.build_stage = build_stage = PartitionSortStage::SORTED; - lstate.build_task = tasks_assigned++; - return true; - } - global_sort->InitializeMergeRound(); - lstate.build_stage = PartitionSortStage::MERGE; - total_tasks = local_sorts.size(); - tasks_assigned = 1; - tasks_completed = 0; - return true; - case PartitionSortStage::SORTED: - if (tasks_assigned < total_tasks) { - lstate.build_stage = PartitionSortStage::SORTED; - lstate.build_task = tasks_assigned++; - return true; - } else if (tasks_completed < tasks_assigned) { - lstate.build_stage = PartitionSortStage::FINISHED; - // Sleep while other tasks finish - return false; - } - CleanupSort(); - break; - default: - break; - } - - lstate.build_stage = build_stage = PartitionSortStage::FINISHED; - - return true; -} - -void WindowMergeSortTreeLocalState::Sort() { - // Sort, merge and build the tree in parallel - while (window_tree.build_stage.load() != PartitionSortStage::FINISHED) { - if (window_tree.TryPrepareSortStage(*this)) { - ExecuteSortTask(); - } else { - std::this_thread::yield(); - } - } -} - -void WindowMergeSortTree::Build() { - if (mst32) { - mst32->Build(); - } else { - mst64->Build(); - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_naive_aggregator.cpp b/src/duckdb/src/function/window/window_naive_aggregator.cpp deleted file mode 100644 index 448639e77..000000000 --- a/src/duckdb/src/function/window/window_naive_aggregator.cpp +++ /dev/null @@ -1,361 +0,0 @@ -#include "duckdb/function/window/window_naive_aggregator.hpp" -#include "duckdb/common/sort/sort.hpp" -#include "duckdb/function/window/window_collection.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" -#include "duckdb/function/window/window_aggregate_function.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowNaiveAggregator -//===--------------------------------------------------------------------===// -WindowNaiveAggregator::WindowNaiveAggregator(const WindowAggregateExecutor &executor, WindowSharedExpressions &shared) - : WindowAggregator(executor.wexpr, shared), executor(executor) { - - for (const auto &order : wexpr.arg_orders) { - arg_order_idx.emplace_back(shared.RegisterCollection(order.expression, false)); - } -} - -WindowNaiveAggregator::~WindowNaiveAggregator() { -} - -class WindowNaiveState : public WindowAggregatorLocalState { -public: - struct HashRow { - explicit HashRow(WindowNaiveState &state) : state(state) { - } - - inline size_t operator()(const idx_t &i) const { - return state.Hash(i); - } - - WindowNaiveState &state; - }; - - struct EqualRow { - explicit EqualRow(WindowNaiveState &state) : state(state) { - } - - inline bool operator()(const idx_t &lhs, const idx_t &rhs) const { - return state.KeyEqual(lhs, rhs); - } - - WindowNaiveState &state; - }; - - using RowSet = std::unordered_set; - - explicit WindowNaiveState(const WindowNaiveAggregator &gsink); - - void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; - - void Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, - idx_t row_idx); - -protected: - //! Flush the accumulated intermediate states into the result states - void FlushStates(const WindowAggregatorGlobalState &gsink); - - //! Hashes a value for the hash table - size_t Hash(idx_t rid); - //! Compares two values for the hash table - bool KeyEqual(const idx_t &lhs, const idx_t &rhs); - - //! The global state - const WindowNaiveAggregator &aggregator; - //! Data pointer that contains a vector of states, used for row aggregation - vector state; - //! Reused result state container for the aggregate - Vector statef; - //! A vector of pointers to "state", used for buffering intermediate aggregates - Vector statep; - //! Input data chunk, used for leaf segment aggregation - DataChunk leaves; - //! The rows beging updated. - SelectionVector update_sel; - //! Count of buffered values - idx_t flush_count; - //! The frame boundaries, used for EXCLUDE - SubFrames frames; - //! The optional hash table used for DISTINCT - Vector hashes; - //! The state used for comparing the collection across chunk boundaries - unique_ptr comparer; - - //! The state used for scanning ORDER BY values from the collection - unique_ptr arg_orderer; - //! Reusable sort key chunk - DataChunk orderby_sort; - //! Reusable sort payload chunk - DataChunk orderby_payload; - //! Reusable sort key slicer - SelectionVector orderby_sel; - //! Reusable payload layout. - RowLayout payload_layout; -}; - -WindowNaiveState::WindowNaiveState(const WindowNaiveAggregator &aggregator_p) - : aggregator(aggregator_p), state(aggregator.state_size * STANDARD_VECTOR_SIZE), statef(LogicalType::POINTER), - statep((LogicalType::POINTER)), flush_count(0), hashes(LogicalType::HASH) { - InitSubFrames(frames, aggregator.exclude_mode); - - update_sel.Initialize(); - - // Build the finalise vector that just points to the result states - data_ptr_t state_ptr = state.data(); - D_ASSERT(statef.GetVectorType() == VectorType::FLAT_VECTOR); - statef.SetVectorType(VectorType::CONSTANT_VECTOR); - statef.Flatten(STANDARD_VECTOR_SIZE); - auto fdata = FlatVector::GetData(statef); - for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; ++i) { - fdata[i] = state_ptr; - state_ptr += aggregator.state_size; - } - - // Initialise any ORDER BY data - if (!aggregator.arg_order_idx.empty() && !arg_orderer) { - orderby_payload.Initialize(Allocator::DefaultAllocator(), {LogicalType::UBIGINT}); - payload_layout.Initialize(orderby_payload.GetTypes()); - orderby_sel.Initialize(); - } -} - -void WindowNaiveState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { - WindowAggregatorLocalState::Finalize(gastate, collection); - - // Set up the comparison scanner just in case - if (!comparer) { - comparer = make_uniq(*collection, aggregator.child_idx); - } - - // Set up the argument ORDER BY scanner if needed - if (!aggregator.arg_order_idx.empty() && !arg_orderer) { - arg_orderer = make_uniq(*collection, aggregator.arg_order_idx); - orderby_sort.Initialize(BufferAllocator::Get(gastate.context), arg_orderer->chunk.GetTypes()); - } - - // Initialise the chunks - const auto types = cursor->chunk.GetTypes(); - if (leaves.ColumnCount() == 0 && !types.empty()) { - leaves.Initialize(BufferAllocator::Get(gastate.context), types); - } -} - -void WindowNaiveState::FlushStates(const WindowAggregatorGlobalState &gsink) { - if (!flush_count) { - return; - } - - auto &scanned = cursor->chunk; - leaves.Slice(scanned, update_sel, flush_count); - - const auto &aggr = gsink.aggr; - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.update(leaves.data.data(), aggr_input_data, leaves.ColumnCount(), statep, flush_count); - - flush_count = 0; -} - -size_t WindowNaiveState::Hash(idx_t rid) { - D_ASSERT(cursor->RowIsVisible(rid)); - auto s = cursor->RowOffset(rid); - auto &scanned = cursor->chunk; - SelectionVector sel(&s); - leaves.Slice(scanned, sel, 1); - leaves.Hash(hashes); - - return *FlatVector::GetData(hashes); -} - -bool WindowNaiveState::KeyEqual(const idx_t &lidx, const idx_t &ridx) { - // One of the indices will be scanned, so make it the left one - auto lhs = lidx; - auto rhs = ridx; - if (!cursor->RowIsVisible(lhs)) { - std::swap(lhs, rhs); - D_ASSERT(cursor->RowIsVisible(lhs)); - } - - auto &scanned = cursor->chunk; - auto l = cursor->RowOffset(lhs); - SelectionVector lsel(&l); - - auto rreader = cursor.get(); - if (!cursor->RowIsVisible(rhs)) { - // Values on different pages! - rreader = comparer.get(); - rreader->Seek(rhs); - } - auto rscanned = &rreader->chunk; - auto r = rreader->RowOffset(rhs); - SelectionVector rsel(&r); - - sel_t f = 0; - SelectionVector fsel(&f); - - for (column_t c = 0; c < scanned.ColumnCount(); ++c) { - Vector left(scanned.data[c], lsel, 1); - Vector right(rscanned->data[c], rsel, 1); - if (!VectorOperations::NotDistinctFrom(left, right, nullptr, 1, nullptr, &fsel)) { - return false; - } - } - - return true; -} - -void WindowNaiveState::Evaluate(const WindowAggregatorGlobalState &gsink, const DataChunk &bounds, Vector &result, - idx_t count, idx_t row_idx) { - const auto &aggr = gsink.aggr; - auto &filter_mask = gsink.filter_mask; - const auto types = cursor->chunk.GetTypes(); - - auto fdata = FlatVector::GetData(statef); - auto pdata = FlatVector::GetData(statep); - - HashRow hash_row(*this); - EqualRow equal_row(*this); - RowSet row_set(STANDARD_VECTOR_SIZE, hash_row, equal_row); - - WindowAggregator::EvaluateSubFrames(bounds, aggregator.exclude_mode, count, row_idx, frames, [&](idx_t rid) { - auto agg_state = fdata[rid]; - aggr.function.initialize(aggr.function, agg_state); - - // Reset the DISTINCT hash table - row_set.clear(); - - // Sort the input rows by the argument - if (arg_orderer) { - auto &context = aggregator.executor.context; - auto &orders = aggregator.wexpr.arg_orders; - auto &buffer_manager = BufferManager::GetBufferManager(context); - GlobalSortState global_sort(buffer_manager, orders, payload_layout); - LocalSortState local_sort; - local_sort.Initialize(global_sort, global_sort.buffer_manager); - - idx_t orderby_count = 0; - auto orderby_row = FlatVector::GetData(orderby_payload.data[0]); - for (const auto &frame : frames) { - for (auto f = frame.start; f < frame.end; ++f) { - // FILTER before the ORDER BY - if (!filter_mask.RowIsValid(f)) { - continue; - } - - if (!arg_orderer->RowIsVisible(f) || orderby_count >= STANDARD_VECTOR_SIZE) { - if (orderby_count) { - orderby_sort.Reference(arg_orderer->chunk); - orderby_sort.Slice(orderby_sel, orderby_count); - orderby_payload.SetCardinality(orderby_count); - local_sort.SinkChunk(orderby_sort, orderby_payload); - } - orderby_count = 0; - arg_orderer->Seek(f); - } - orderby_row[orderby_count] = f; - orderby_sel.set_index(orderby_count++, arg_orderer->RowOffset(f)); - } - } - if (orderby_count) { - orderby_sort.Reference(arg_orderer->chunk); - orderby_sort.Slice(orderby_sel, orderby_count); - orderby_payload.SetCardinality(orderby_count); - local_sort.SinkChunk(orderby_sort, orderby_payload); - } - - global_sort.AddLocalState(local_sort); - if (global_sort.sorted_blocks.empty()) { - return; - } - global_sort.PrepareMergePhase(); - while (global_sort.sorted_blocks.size() > 1) { - global_sort.InitializeMergeRound(); - MergeSorter merge_sorter(global_sort, global_sort.buffer_manager); - merge_sorter.PerformInMergeRound(); - global_sort.CompleteMergeRound(false); - } - - PayloadScanner scanner(global_sort); - while (scanner.Remaining()) { - orderby_payload.Reset(); - scanner.Scan(orderby_payload); - orderby_row = FlatVector::GetData(orderby_payload.data[0]); - for (idx_t i = 0; i < orderby_payload.size(); ++i) { - const auto f = orderby_row[i]; - // Seek to the current position - if (!cursor->RowIsVisible(f)) { - // We need to flush when we cross a chunk boundary - FlushStates(gsink); - cursor->Seek(f); - } - - // Filter out duplicates - if (aggr.IsDistinct() && !row_set.insert(f).second) { - continue; - } - - pdata[flush_count] = agg_state; - update_sel[flush_count++] = cursor->RowOffset(f); - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(gsink); - } - } - } - return; - } - - // Just update the aggregate with the unfiltered input rows - for (const auto &frame : frames) { - for (auto f = frame.start; f < frame.end; ++f) { - if (!filter_mask.RowIsValid(f)) { - continue; - } - - // Seek to the current position - if (!cursor->RowIsVisible(f)) { - // We need to flush when we cross a chunk boundary - FlushStates(gsink); - cursor->Seek(f); - } - - // Filter out duplicates - if (aggr.IsDistinct() && !row_set.insert(f).second) { - continue; - } - - pdata[flush_count] = agg_state; - update_sel[flush_count++] = cursor->RowOffset(f); - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(gsink); - } - } - } - }); - - // Flush the final states - FlushStates(gsink); - - // Finalise the result aggregates and write to the result - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.finalize(statef, aggr_input_data, result, count, 0); - - // Destruct the result aggregates - if (aggr.function.destructor) { - aggr.function.destructor(statef, aggr_input_data, count); - } -} - -unique_ptr WindowNaiveAggregator::GetLocalState(const WindowAggregatorState &gstate) const { - return make_uniq(*this); -} - -void WindowNaiveAggregator::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { - const auto &gnstate = gsink.Cast(); - auto &lnstate = lstate.Cast(); - lnstate.Evaluate(gnstate, bounds, result, count, row_idx); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_rank_function.cpp b/src/duckdb/src/function/window/window_rank_function.cpp deleted file mode 100644 index b128ea89a..000000000 --- a/src/duckdb/src/function/window/window_rank_function.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "duckdb/function/window/window_rank_function.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/function/window/window_token_tree.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowPeerGlobalState -//===--------------------------------------------------------------------===// -class WindowPeerGlobalState : public WindowExecutorGlobalState { -public: - WindowPeerGlobalState(const WindowPeerExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask) { - if (!executor.arg_order_idx.empty()) { - token_tree = make_uniq(executor.context, executor.wexpr.arg_orders, executor.arg_order_idx, - payload_count); - } - } - - //! The token tree for ORDER BY arguments - unique_ptr token_tree; -}; - -//===--------------------------------------------------------------------===// -// WindowPeerLocalState -//===--------------------------------------------------------------------===// -// Base class for non-aggregate functions that use peer boundaries -class WindowPeerLocalState : public WindowExecutorBoundsState { -public: - explicit WindowPeerLocalState(const WindowPeerGlobalState &gpstate) - : WindowExecutorBoundsState(gpstate), gpstate(gpstate) { - if (gpstate.token_tree) { - local_tree = gpstate.token_tree->GetLocalState(); - } - } - - //! Accumulate the secondary sort values - void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) override; - //! Finish the sinking and prepare to scan - void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) override; - - void NextRank(idx_t partition_begin, idx_t peer_begin, idx_t row_idx); - - uint64_t dense_rank = 1; - uint64_t rank_equal = 0; - uint64_t rank = 1; - - //! The corresponding global peer state - const WindowPeerGlobalState &gpstate; - //! The optional sorting state for secondary sorts - unique_ptr local_tree; -}; - -void WindowPeerLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) { - WindowExecutorBoundsState::Sink(gstate, sink_chunk, coll_chunk, input_idx); - - if (local_tree) { - auto &local_tokens = local_tree->Cast(); - local_tokens.SinkChunk(sink_chunk, input_idx, nullptr, 0); - } -} - -void WindowPeerLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { - WindowExecutorBoundsState::Finalize(gstate, collection); - - if (local_tree) { - auto &local_tokens = local_tree->Cast(); - local_tokens.Sort(); - local_tokens.window_tree.Build(); - } -} - -void WindowPeerLocalState::NextRank(idx_t partition_begin, idx_t peer_begin, idx_t row_idx) { - if (partition_begin == row_idx) { - dense_rank = 1; - rank = 1; - rank_equal = 0; - } else if (peer_begin == row_idx) { - dense_rank++; - rank += rank_equal; - rank_equal = 0; - } - rank_equal++; -} - -//===--------------------------------------------------------------------===// -// WindowPeerExecutor -//===--------------------------------------------------------------------===// -WindowPeerExecutor::WindowPeerExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowExecutor(wexpr, context, shared) { - - for (const auto &order : wexpr.arg_orders) { - arg_order_idx.emplace_back(shared.RegisterSink(order.expression)); - } -} - -unique_ptr WindowPeerExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -unique_ptr WindowPeerExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - return make_uniq(gstate.Cast()); -} - -//===--------------------------------------------------------------------===// -// WindowRankExecutor -//===--------------------------------------------------------------------===// -WindowRankExecutor::WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowPeerExecutor(wexpr, context, shared) { -} - -void WindowRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { - auto &gpeer = gstate.Cast(); - auto &lpeer = lstate.Cast(); - auto rdata = FlatVector::GetData(result); - - if (gpeer.token_tree) { - auto frame_begin = FlatVector::GetData(lpeer.bounds.data[FRAME_BEGIN]); - auto frame_end = FlatVector::GetData(lpeer.bounds.data[FRAME_END]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - rdata[i] = gpeer.token_tree->Rank(frame_begin[i], frame_end[i], row_idx); - } - return; - } - - // Reset to "previous" row - auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); - auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); - lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; - lpeer.rank_equal = (row_idx - peer_begin[0]); - - for (idx_t i = 0; i < count; ++i, ++row_idx) { - lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); - rdata[i] = lpeer.rank; - } -} - -//===--------------------------------------------------------------------===// -// WindowDenseRankExecutor -//===--------------------------------------------------------------------===// -WindowDenseRankExecutor::WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowPeerExecutor(wexpr, context, shared) { -} - -void WindowDenseRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &lpeer = lstate.Cast(); - - auto &order_mask = gstate.order_mask; - auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); - auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); - auto rdata = FlatVector::GetData(result); - - // Reset to "previous" row - lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; - lpeer.rank_equal = (row_idx - peer_begin[0]); - - // The previous dense rank is the number of order mask bits in [partition_begin, row_idx) - lpeer.dense_rank = 0; - - auto order_begin = partition_begin[0]; - idx_t begin_idx; - idx_t begin_offset; - order_mask.GetEntryIndex(order_begin, begin_idx, begin_offset); - - auto order_end = row_idx; - idx_t end_idx; - idx_t end_offset; - order_mask.GetEntryIndex(order_end, end_idx, end_offset); - - // If they are in the same entry, just loop - if (begin_idx == end_idx) { - const auto entry = order_mask.GetValidityEntry(begin_idx); - for (; begin_offset < end_offset; ++begin_offset) { - lpeer.dense_rank += order_mask.RowIsValid(entry, begin_offset); - } - } else { - // Count the ragged bits at the start of the partition - if (begin_offset) { - const auto entry = order_mask.GetValidityEntry(begin_idx); - for (; begin_offset < order_mask.BITS_PER_VALUE; ++begin_offset) { - lpeer.dense_rank += order_mask.RowIsValid(entry, begin_offset); - ++order_begin; - } - ++begin_idx; - } - - // Count the the aligned bits. - ValidityMask tail_mask(order_mask.GetData() + begin_idx, end_idx - begin_idx); - lpeer.dense_rank += tail_mask.CountValid(order_end - order_begin); - } - - for (idx_t i = 0; i < count; ++i, ++row_idx) { - lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); - rdata[i] = NumericCast(lpeer.dense_rank); - } -} - -//===--------------------------------------------------------------------===// -// WindowPercentRankExecutor -//===--------------------------------------------------------------------===// -WindowPercentRankExecutor::WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowPeerExecutor(wexpr, context, shared) { -} - -void WindowPercentRankExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &gpeer = gstate.Cast(); - auto &lpeer = lstate.Cast(); - auto rdata = FlatVector::GetData(result); - - if (gpeer.token_tree) { - auto frame_begin = FlatVector::GetData(lpeer.bounds.data[FRAME_BEGIN]); - auto frame_end = FlatVector::GetData(lpeer.bounds.data[FRAME_END]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - auto denom = static_cast(NumericCast(frame_end[i] - frame_begin[i] - 1)); - const auto rank = gpeer.token_tree->Rank(frame_begin[i], frame_end[i], row_idx); - double percent_rank = denom > 0 ? ((double)rank - 1) / denom : 0; - rdata[i] = percent_rank; - } - return; - } - - // Reset to "previous" row - auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); - auto partition_end = FlatVector::GetData(lpeer.bounds.data[PARTITION_END]); - auto peer_begin = FlatVector::GetData(lpeer.bounds.data[PEER_BEGIN]); - lpeer.rank = (peer_begin[0] - partition_begin[0]) + 1; - lpeer.rank_equal = (row_idx - peer_begin[0]); - - for (idx_t i = 0; i < count; ++i, ++row_idx) { - lpeer.NextRank(partition_begin[i], peer_begin[i], row_idx); - auto denom = static_cast(NumericCast(partition_end[i] - partition_begin[i] - 1)); - double percent_rank = denom > 0 ? ((double)lpeer.rank - 1) / denom : 0; - rdata[i] = percent_rank; - } -} - -//===--------------------------------------------------------------------===// -// WindowCumeDistExecutor -//===--------------------------------------------------------------------===// -WindowCumeDistExecutor::WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowPeerExecutor(wexpr, context, shared) { -} - -void WindowCumeDistExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { - auto &gpeer = gstate.Cast(); - auto &lpeer = lstate.Cast(); - auto rdata = FlatVector::GetData(result); - - if (gpeer.token_tree) { - auto frame_begin = FlatVector::GetData(lpeer.bounds.data[FRAME_BEGIN]); - auto frame_end = FlatVector::GetData(lpeer.bounds.data[FRAME_END]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - const auto denom = static_cast(NumericCast(frame_end[i] - frame_begin[i])); - const auto peer_end = gpeer.token_tree->PeerEnd(frame_begin[i], frame_end[i], row_idx); - const auto num = static_cast(peer_end - frame_begin[i]); - rdata[i] = denom > 0 ? (num / denom) : 0; - } - return; - } - - auto partition_begin = FlatVector::GetData(lpeer.bounds.data[PARTITION_BEGIN]); - auto partition_end = FlatVector::GetData(lpeer.bounds.data[PARTITION_END]); - auto peer_end = FlatVector::GetData(lpeer.bounds.data[PEER_END]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - const auto denom = static_cast(NumericCast(partition_end[i] - partition_begin[i])); - const auto num = static_cast(peer_end[i] - partition_begin[i]); - rdata[i] = denom > 0 ? (num / denom) : 0; - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_rownumber_function.cpp b/src/duckdb/src/function/window/window_rownumber_function.cpp deleted file mode 100644 index f946583f1..000000000 --- a/src/duckdb/src/function/window/window_rownumber_function.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "duckdb/function/window/window_rownumber_function.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/function/window/window_token_tree.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowRowNumberGlobalState -//===--------------------------------------------------------------------===// -class WindowRowNumberGlobalState : public WindowExecutorGlobalState { -public: - WindowRowNumberGlobalState(const WindowRowNumberExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask), - ntile_idx(executor.ntile_idx) { - if (!executor.arg_order_idx.empty()) { - // "The ROW_NUMBER function can be computed by disambiguating duplicate elements based on their position in - // the input data, such that two elements never compare as equal." - token_tree = make_uniq(executor.context, executor.wexpr.arg_orders, executor.arg_order_idx, - payload_count, true); - } - } - - //! The token tree for ORDER BY arguments - unique_ptr token_tree; - - //! The evaluation index for NTILE - const column_t ntile_idx; -}; - -//===--------------------------------------------------------------------===// -// WindowRowNumberLocalState -//===--------------------------------------------------------------------===// -class WindowRowNumberLocalState : public WindowExecutorBoundsState { -public: - explicit WindowRowNumberLocalState(const WindowRowNumberGlobalState &grstate) - : WindowExecutorBoundsState(grstate), grstate(grstate) { - if (grstate.token_tree) { - local_tree = grstate.token_tree->GetLocalState(); - } - } - - //! Accumulate the secondary sort values - void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) override; - //! Finish the sinking and prepare to scan - void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) override; - - //! The corresponding global peer state - const WindowRowNumberGlobalState &grstate; - //! The optional sorting state for secondary sorts - unique_ptr local_tree; -}; - -void WindowRowNumberLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) { - WindowExecutorBoundsState::Sink(gstate, sink_chunk, coll_chunk, input_idx); - - if (local_tree) { - auto &local_tokens = local_tree->Cast(); - local_tokens.SinkChunk(sink_chunk, input_idx, nullptr, 0); - } -} - -void WindowRowNumberLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { - WindowExecutorBoundsState::Finalize(gstate, collection); - - if (local_tree) { - auto &local_tokens = local_tree->Cast(); - local_tokens.Sort(); - local_tokens.window_tree.Build(); - } -} - -//===--------------------------------------------------------------------===// -// WindowRowNumberExecutor -//===--------------------------------------------------------------------===// -WindowRowNumberExecutor::WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowExecutor(wexpr, context, shared) { - - for (const auto &order : wexpr.arg_orders) { - arg_order_idx.emplace_back(shared.RegisterSink(order.expression)); - } -} - -unique_ptr WindowRowNumberExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -unique_ptr -WindowRowNumberExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - return make_uniq(gstate.Cast()); -} - -void WindowRowNumberExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &grstate = gstate.Cast(); - auto &lrstate = lstate.Cast(); - auto rdata = FlatVector::GetData(result); - - if (grstate.token_tree) { - auto frame_begin = FlatVector::GetData(lrstate.bounds.data[FRAME_BEGIN]); - auto frame_end = FlatVector::GetData(lrstate.bounds.data[FRAME_END]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - // Row numbers are unique ranks - rdata[i] = grstate.token_tree->Rank(frame_begin[i], frame_end[i], row_idx); - } - return; - } - - auto partition_begin = FlatVector::GetData(lrstate.bounds.data[PARTITION_BEGIN]); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - rdata[i] = row_idx - partition_begin[i] + 1; - } -} - -//===--------------------------------------------------------------------===// -// WindowNtileExecutor -//===--------------------------------------------------------------------===// -WindowNtileExecutor::WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowRowNumberExecutor(wexpr, context, shared) { - - // NTILE has one argument - ntile_idx = shared.RegisterEvaluate(wexpr.children[0]); -} - -void WindowNtileExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { - auto &grstate = gstate.Cast(); - auto &lrstate = lstate.Cast(); - auto partition_begin = FlatVector::GetData(lrstate.bounds.data[PARTITION_BEGIN]); - auto partition_end = FlatVector::GetData(lrstate.bounds.data[PARTITION_END]); - if (grstate.token_tree) { - // With secondary sorts, we restrict to the frame boundaries, but everything else should compute the same. - partition_begin = FlatVector::GetData(lrstate.bounds.data[FRAME_BEGIN]); - partition_end = FlatVector::GetData(lrstate.bounds.data[FRAME_END]); - } - auto rdata = FlatVector::GetData(result); - WindowInputExpression ntile_col(eval_chunk, ntile_idx); - for (idx_t i = 0; i < count; ++i, ++row_idx) { - if (ntile_col.CellIsNull(i)) { - FlatVector::SetNull(result, i, true); - } else { - auto n_param = ntile_col.GetCell(i); - if (n_param < 1) { - throw InvalidInputException("Argument for ntile must be greater than zero"); - } - // With thanks from SQLite's ntileValueFunc() - auto n_total = NumericCast(partition_end[i] - partition_begin[i]); - if (n_param > n_total) { - // more groups allowed than we have values - // map every entry to a unique group - n_param = n_total; - } - int64_t n_size = (n_total / n_param); - // find the row idx within the group - D_ASSERT(row_idx >= partition_begin[i]); - idx_t partition_idx = 0; - if (grstate.token_tree) { - partition_idx = grstate.token_tree->Rank(partition_begin[i], partition_end[i], row_idx) - 1; - } else { - partition_idx = row_idx - partition_begin[i]; - } - auto adjusted_row_idx = NumericCast(partition_idx); - - // now compute the ntile - int64_t n_large = n_total - n_param * n_size; - int64_t i_small = n_large * (n_size + 1); - int64_t result_ntile; - - D_ASSERT((n_large * (n_size + 1) + (n_param - n_large) * n_size) == n_total); - - if (adjusted_row_idx < i_small) { - result_ntile = 1 + adjusted_row_idx / (n_size + 1); - } else { - result_ntile = 1 + n_large + (adjusted_row_idx - i_small) / n_size; - } - // result has to be between [1, NTILE] - D_ASSERT(result_ntile >= 1 && result_ntile <= n_param); - rdata[i] = result_ntile; - } - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_segment_tree.cpp b/src/duckdb/src/function/window/window_segment_tree.cpp deleted file mode 100644 index 6708ae90b..000000000 --- a/src/duckdb/src/function/window/window_segment_tree.cpp +++ /dev/null @@ -1,594 +0,0 @@ -#include "duckdb/function/window/window_segment_tree.hpp" - -#include "duckdb/function/window/window_aggregate_states.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -#include - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowSegmentTree -//===--------------------------------------------------------------------===// -bool WindowSegmentTree::CanAggregate(const BoundWindowExpression &wexpr) { - if (!wexpr.aggregate) { - return false; - } - - return !wexpr.distinct && wexpr.arg_orders.empty(); -} - -WindowSegmentTree::WindowSegmentTree(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared) - : WindowAggregator(wexpr, shared) { -} - -class WindowSegmentTreeGlobalState : public WindowAggregatorGlobalState { -public: - using AtomicCounters = vector>; - - WindowSegmentTreeGlobalState(ClientContext &context, const WindowSegmentTree &aggregator, idx_t group_count); - - ArenaAllocator &CreateTreeAllocator() { - lock_guard tree_lock(lock); - tree_allocators.emplace_back(make_uniq(Allocator::DefaultAllocator())); - return *tree_allocators.back(); - } - - //! The owning aggregator - const WindowSegmentTree &tree; - //! The actual window segment tree: an array of aggregate states that represent all the intermediate nodes - WindowAggregateStates levels_flat_native; - //! For each level, the starting location in the levels_flat_native array - vector levels_flat_start; - //! The level being built (read) - std::atomic build_level; - //! The number of entries started so far at each level - unique_ptr build_started; - //! The number of entries completed so far at each level - unique_ptr build_completed; - //! The tree allocators. - //! We need to hold onto them for the tree lifetime, - //! not the lifetime of the local state that constructed part of the tree - vector> tree_allocators; - - // TREE_FANOUT needs to cleanly divide STANDARD_VECTOR_SIZE - static constexpr idx_t TREE_FANOUT = 16; -}; - -class WindowSegmentTreePart { -public: - //! Right side nodes need to be cached and processed in reverse order - using RightEntry = std::pair; - - enum FramePart : uint8_t { FULL = 0, LEFT = 1, RIGHT = 2 }; - - WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, unique_ptr cursor, - const ValidityArray &filter_mask); - ~WindowSegmentTreePart(); - - unique_ptr Copy() const { - return make_uniq(allocator, aggr, cursor->Copy(), filter_mask); - } - - void FlushStates(bool combining); - void ExtractFrame(idx_t begin, idx_t end, data_ptr_t current_state); - void WindowSegmentValue(const WindowSegmentTreeGlobalState &tree, idx_t l_idx, idx_t begin, idx_t end, - data_ptr_t current_state); - //! Writes result and calls destructors - void Finalize(Vector &result, idx_t count); - - void Combine(WindowSegmentTreePart &other, idx_t count); - - void Evaluate(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, Vector &result, - idx_t count, idx_t row_idx, FramePart frame_part); - -protected: - //! Initialises the accumulation state vector (statef) - void Initialize(idx_t count); - //! Accumulate upper tree levels - void EvaluateUpperLevels(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, - idx_t count, idx_t row_idx, FramePart frame_part); - void EvaluateLeaves(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, idx_t count, - idx_t row_idx, FramePart frame_part, FramePart leaf_part); - -public: - //! Allocator for aggregates - ArenaAllocator &allocator; - //! The aggregate function - const AggregateObject &aggr; - //! Order insensitive aggregate (we can optimise internal combines) - const bool order_insensitive; - //! The filtered rows in inputs - const ValidityArray &filter_mask; - //! The size of a single aggregate state - const idx_t state_size; - //! Data pointer that contains a vector of states, used for intermediate window segment aggregation - vector state; - //! Scanned data state - unique_ptr cursor; - //! Input data chunk, used for leaf segment aggregation - DataChunk leaves; - //! The filtered rows in inputs. - SelectionVector filter_sel; - //! A vector of pointers to "state", used for intermediate window segment aggregation - Vector statep; - //! Reused state pointers for combining segment tree levels - Vector statel; - //! Reused result state container for the window functions - Vector statef; - //! Count of buffered values - idx_t flush_count; - //! Cache of right side tree ranges for ordered aggregates - vector right_stack; -}; - -class WindowSegmentTreeState : public WindowAggregatorLocalState { -public: - WindowSegmentTreeState() { - } - - void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) override; - void Evaluate(const WindowSegmentTreeGlobalState &gsink, const DataChunk &bounds, Vector &result, idx_t count, - idx_t row_idx); - //! The left (default) segment tree part - unique_ptr part; - //! The right segment tree part (for EXCLUDE) - unique_ptr right_part; -}; - -void WindowSegmentTree::Finalize(WindowAggregatorState &gsink, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) { - WindowAggregator::Finalize(gsink, lstate, collection, stats); - - auto &gasink = gsink.Cast(); - ++gasink.finalized; -} - -WindowSegmentTreePart::WindowSegmentTreePart(ArenaAllocator &allocator, const AggregateObject &aggr, - unique_ptr cursor_p, const ValidityArray &filter_mask) - : allocator(allocator), aggr(aggr), - order_insensitive(aggr.function.order_dependent == AggregateOrderDependent::NOT_ORDER_DEPENDENT), - filter_mask(filter_mask), state_size(aggr.function.state_size(aggr.function)), - state(state_size * STANDARD_VECTOR_SIZE), cursor(std::move(cursor_p)), statep(LogicalType::POINTER), - statel(LogicalType::POINTER), statef(LogicalType::POINTER), flush_count(0) { - - auto &inputs = cursor->chunk; - if (inputs.ColumnCount() > 0) { - leaves.Initialize(Allocator::DefaultAllocator(), inputs.GetTypes()); - filter_sel.Initialize(); - } - - // Build the finalise vector that just points to the result states - data_ptr_t state_ptr = state.data(); - D_ASSERT(statef.GetVectorType() == VectorType::FLAT_VECTOR); - statef.SetVectorType(VectorType::CONSTANT_VECTOR); - statef.Flatten(STANDARD_VECTOR_SIZE); - auto fdata = FlatVector::GetData(statef); - for (idx_t i = 0; i < STANDARD_VECTOR_SIZE; ++i) { - fdata[i] = state_ptr; - state_ptr += state_size; - } -} - -WindowSegmentTreePart::~WindowSegmentTreePart() { -} - -unique_ptr WindowSegmentTree::GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const { - return make_uniq(context, *this, group_count); -} - -unique_ptr WindowSegmentTree::GetLocalState(const WindowAggregatorState &gstate) const { - return make_uniq(); -} - -void WindowSegmentTreePart::FlushStates(bool combining) { - if (!flush_count) { - return; - } - - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - if (combining) { - statel.Verify(flush_count); - aggr.function.combine(statel, statep, aggr_input_data, flush_count); - } else { - auto &scanned = cursor->chunk; - leaves.Slice(scanned, filter_sel, flush_count); - aggr.function.update(&leaves.data[0], aggr_input_data, leaves.ColumnCount(), statep, flush_count); - } - - flush_count = 0; -} - -void WindowSegmentTreePart::Combine(WindowSegmentTreePart &other, idx_t count) { - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.combine(other.statef, statef, aggr_input_data, count); -} - -void WindowSegmentTreePart::ExtractFrame(idx_t begin, idx_t end, data_ptr_t state_ptr) { - const auto count = end - begin; - - // If we are not filtering, - // just update the shared dictionary selection to the range - // Otherwise set it to the input rows that pass the filter - auto states = FlatVector::GetData(statep); - if (filter_mask.AllValid()) { - const auto offset = cursor->RowOffset(begin); - for (idx_t i = 0; i < count; ++i) { - states[flush_count] = state_ptr; - filter_sel.set_index(flush_count++, offset + i); - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(false); - } - } - } else { - for (idx_t i = begin; i < end; ++i) { - if (filter_mask.RowIsValid(i)) { - states[flush_count] = state_ptr; - filter_sel.set_index(flush_count++, cursor->RowOffset(i)); - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(false); - } - } - } - } -} - -void WindowSegmentTreePart::WindowSegmentValue(const WindowSegmentTreeGlobalState &tree, idx_t l_idx, idx_t begin, - idx_t end, data_ptr_t state_ptr) { - D_ASSERT(begin <= end); - auto &inputs = cursor->chunk; - if (begin == end || inputs.ColumnCount() == 0) { - return; - } - - const auto count = end - begin; - if (l_idx == 0) { - // Check the leaves when they cross chunk boundaries - while (begin < end) { - if (!cursor->RowIsVisible(begin)) { - FlushStates(false); - cursor->Seek(begin); - } - auto next = MinValue(end, cursor->state.next_row_index); - ExtractFrame(begin, next, state_ptr); - begin = next; - } - } else { - // find out where the states begin - auto begin_ptr = tree.levels_flat_native.GetStatePtr(begin + tree.levels_flat_start[l_idx - 1]); - // set up a vector of pointers that point towards the set of states - auto ldata = FlatVector::GetData(statel); - auto pdata = FlatVector::GetData(statep); - for (idx_t i = 0; i < count; i++) { - pdata[flush_count] = state_ptr; - ldata[flush_count++] = begin_ptr; - begin_ptr += state_size; - if (flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(true); - } - } - } -} -void WindowSegmentTreePart::Finalize(Vector &result, idx_t count) { - // Finalise the result aggregates and write to result if write_result is set - AggregateInputData aggr_input_data(aggr.GetFunctionData(), allocator); - aggr.function.finalize(statef, aggr_input_data, result, count, 0); - - // Destruct the result aggregates - if (aggr.function.destructor) { - aggr.function.destructor(statef, aggr_input_data, count); - } -} - -WindowSegmentTreeGlobalState::WindowSegmentTreeGlobalState(ClientContext &context, const WindowSegmentTree &aggregator, - idx_t group_count) - : WindowAggregatorGlobalState(context, aggregator, group_count), tree(aggregator), levels_flat_native(aggr) { - - D_ASSERT(!aggregator.wexpr.children.empty()); - - // compute space required to store internal nodes of segment tree - levels_flat_start.push_back(0); - - idx_t levels_flat_offset = 0; - idx_t level_current = 0; - // level 0 is data itself - idx_t level_size; - // iterate over the levels of the segment tree - while ((level_size = - (level_current == 0 ? group_count : levels_flat_offset - levels_flat_start[level_current - 1])) > 1) { - for (idx_t pos = 0; pos < level_size; pos += TREE_FANOUT) { - levels_flat_offset++; - } - - levels_flat_start.push_back(levels_flat_offset); - level_current++; - } - - // Corner case: single element in the window - if (levels_flat_offset == 0) { - ++levels_flat_offset; - } - - levels_flat_native.Initialize(levels_flat_offset); - - // Start by building from the bottom level - build_level = 0; - - build_started = make_uniq(levels_flat_start.size()); - for (auto &counter : *build_started) { - counter = 0; - } - - build_completed = make_uniq(levels_flat_start.size()); - for (auto &counter : *build_completed) { - counter = 0; - } -} - -void WindowSegmentTreeState::Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection) { - WindowAggregatorLocalState::Finalize(gastate, collection); - - // Single part for constructing the tree - auto &gstate = gastate.Cast(); - auto cursor = make_uniq(*collection, gastate.aggregator.child_idx); - const auto leaf_count = collection->size(); - auto &filter_mask = gstate.filter_mask; - WindowSegmentTreePart gtstate(gstate.CreateTreeAllocator(), gastate.aggr, std::move(cursor), filter_mask); - - auto &levels_flat_native = gstate.levels_flat_native; - const auto &levels_flat_start = gstate.levels_flat_start; - // iterate over the levels of the segment tree - for (;;) { - const idx_t level_current = gstate.build_level.load(); - if (level_current >= levels_flat_start.size()) { - break; - } - - // level 0 is data itself - const auto level_size = - (level_current == 0 ? leaf_count : levels_flat_start[level_current] - levels_flat_start[level_current - 1]); - if (level_size <= 1) { - break; - } - const idx_t build_count = (level_size + gstate.TREE_FANOUT - 1) / gstate.TREE_FANOUT; - - // Build the next fan-in - const idx_t build_idx = (*gstate.build_started).at(level_current)++; - if (build_idx >= build_count) { - // Nothing left at this level, so wait until other threads are done. - // Since we are only building TREE_FANOUT values at a time, this will be quick. - while (level_current == gstate.build_level.load()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - continue; - } - - // compute the aggregate for this entry in the segment tree - const idx_t pos = build_idx * gstate.TREE_FANOUT; - const idx_t levels_flat_offset = levels_flat_start[level_current] + build_idx; - auto state_ptr = levels_flat_native.GetStatePtr(levels_flat_offset); - gtstate.WindowSegmentValue(gstate, level_current, pos, MinValue(level_size, pos + gstate.TREE_FANOUT), - state_ptr); - gtstate.FlushStates(level_current > 0); - - // If that was the last one, mark the level as complete. - const idx_t build_complete = ++(*gstate.build_completed).at(level_current); - if (build_complete == build_count) { - gstate.build_level++; - continue; - } - } -} - -void WindowSegmentTree::Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, - const DataChunk &bounds, Vector &result, idx_t count, idx_t row_idx) const { - const auto >state = gsink.Cast(); - auto <state = lstate.Cast(); - ltstate.Evaluate(gtstate, bounds, result, count, row_idx); -} - -void WindowSegmentTreeState::Evaluate(const WindowSegmentTreeGlobalState >state, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) { - auto window_begin = FlatVector::GetData(bounds.data[FRAME_BEGIN]); - auto window_end = FlatVector::GetData(bounds.data[FRAME_END]); - auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); - auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); - - if (!part) { - part = make_uniq(allocator, gtstate.aggr, cursor->Copy(), gtstate.filter_mask); - } - - if (gtstate.aggregator.exclude_mode != WindowExcludeMode::NO_OTHER) { - // 1. evaluate the tree left of the excluded part - part->Evaluate(gtstate, window_begin, peer_begin, result, count, row_idx, WindowSegmentTreePart::LEFT); - - // 2. set up a second state for the right of the excluded part - if (!right_part) { - right_part = part->Copy(); - } - - // 3. evaluate the tree right of the excluded part - right_part->Evaluate(gtstate, peer_end, window_end, result, count, row_idx, WindowSegmentTreePart::RIGHT); - - // 4. combine the buffer state into the Segment Tree State - part->Combine(*right_part, count); - } else { - part->Evaluate(gtstate, window_begin, window_end, result, count, row_idx, WindowSegmentTreePart::FULL); - } - - part->Finalize(result, count); -} - -void WindowSegmentTreePart::Evaluate(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, const idx_t *ends, - Vector &result, idx_t count, idx_t row_idx, FramePart frame_part) { - Initialize(count); - - if (order_insensitive) { - // First pass: aggregate the segment tree nodes with sharing - EvaluateUpperLevels(tree, begins, ends, count, row_idx, frame_part); - - // Second pass: aggregate the ragged leaves - EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::FULL); - } else { - // Evaluate leaves in order - EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::LEFT); - EvaluateUpperLevels(tree, begins, ends, count, row_idx, frame_part); - EvaluateLeaves(tree, begins, ends, count, row_idx, frame_part, FramePart::RIGHT); - } -} - -void WindowSegmentTreePart::Initialize(idx_t count) { - auto fdata = FlatVector::GetData(statef); - for (idx_t rid = 0; rid < count; ++rid) { - auto state_ptr = fdata[rid]; - aggr.function.initialize(aggr.function, state_ptr); - } -} - -void WindowSegmentTreePart::EvaluateUpperLevels(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, - const idx_t *ends, idx_t count, idx_t row_idx, FramePart frame_part) { - auto fdata = FlatVector::GetData(statef); - - const auto exclude_mode = tree.tree.exclude_mode; - const bool begin_on_curr_row = frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::CURRENT_ROW; - const bool end_on_curr_row = frame_part == FramePart::LEFT && exclude_mode == WindowExcludeMode::CURRENT_ROW; - - const auto max_level = tree.levels_flat_start.size() + 1; - right_stack.resize(max_level, {0, 0}); - - // Share adjacent identical states - // We do this first because we want to share only tree aggregations - idx_t prev_begin = 1; - idx_t prev_end = 0; - auto ldata = FlatVector::GetData(statel); - auto pdata = FlatVector::GetData(statep); - data_ptr_t prev_state = nullptr; - for (idx_t rid = 0, cur_row = row_idx; rid < count; ++rid, ++cur_row) { - auto state_ptr = fdata[rid]; - - auto begin = begin_on_curr_row ? cur_row + 1 : begins[rid]; - auto end = end_on_curr_row ? cur_row : ends[rid]; - if (begin >= end) { - continue; - } - - // Skip level 0 - idx_t l_idx = 0; - idx_t right_max = 0; - for (; l_idx < max_level; l_idx++) { - idx_t parent_begin = begin / tree.TREE_FANOUT; - idx_t parent_end = end / tree.TREE_FANOUT; - if (prev_state && l_idx == 1 && begin == prev_begin && end == prev_end) { - // Just combine the previous top level result - ldata[flush_count] = prev_state; - pdata[flush_count] = state_ptr; - if (++flush_count >= STANDARD_VECTOR_SIZE) { - FlushStates(true); - } - break; - } - - if (order_insensitive && l_idx == 1) { - prev_state = state_ptr; - prev_begin = begin; - prev_end = end; - } - - if (parent_begin == parent_end) { - if (l_idx) { - WindowSegmentValue(tree, l_idx, begin, end, state_ptr); - } - break; - } - idx_t group_begin = parent_begin * tree.TREE_FANOUT; - if (begin != group_begin) { - if (l_idx) { - WindowSegmentValue(tree, l_idx, begin, group_begin + tree.TREE_FANOUT, state_ptr); - } - parent_begin++; - } - idx_t group_end = parent_end * tree.TREE_FANOUT; - if (end != group_end) { - if (l_idx) { - if (order_insensitive) { - WindowSegmentValue(tree, l_idx, group_end, end, state_ptr); - } else { - right_stack[l_idx] = {group_end, end}; - right_max = l_idx; - } - } - } - begin = parent_begin; - end = parent_end; - } - - // Flush the right side values from left to right for order_sensitive aggregates - // As we go up the tree, the right side ranges move left, - // so we just cache them in a fixed size, preallocated array. - // Then we can just reverse scan the array and append the cached ranges. - for (l_idx = right_max; l_idx > 0; --l_idx) { - auto &right_entry = right_stack[l_idx]; - const auto group_end = right_entry.first; - const auto end = right_entry.second; - if (end) { - WindowSegmentValue(tree, l_idx, group_end, end, state_ptr); - right_entry = {0, 0}; - } - } - } - FlushStates(true); -} - -void WindowSegmentTreePart::EvaluateLeaves(const WindowSegmentTreeGlobalState &tree, const idx_t *begins, - const idx_t *ends, idx_t count, idx_t row_idx, FramePart frame_part, - FramePart leaf_part) { - - auto fdata = FlatVector::GetData(statef); - - // For order-sensitive aggregates, we have to process the ragged leaves in two pieces. - // The left side have to be added before the main tree followed by the ragged right sides. - // The current row is the leftmost value of the right hand side. - const bool compute_left = leaf_part != FramePart::RIGHT; - const bool compute_right = leaf_part != FramePart::LEFT; - const auto exclude_mode = tree.tree.exclude_mode; - const bool begin_on_curr_row = frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::CURRENT_ROW; - const bool end_on_curr_row = frame_part == FramePart::LEFT && exclude_mode == WindowExcludeMode::CURRENT_ROW; - // with EXCLUDE TIES, in addition to the frame part right of the peer group's end, we also need to consider the - // current row - const bool add_curr_row = compute_left && frame_part == FramePart::RIGHT && exclude_mode == WindowExcludeMode::TIES; - - for (idx_t rid = 0, cur_row = row_idx; rid < count; ++rid, ++cur_row) { - auto state_ptr = fdata[rid]; - - const auto begin = begin_on_curr_row ? cur_row + 1 : begins[rid]; - const auto end = end_on_curr_row ? cur_row : ends[rid]; - if (add_curr_row) { - WindowSegmentValue(tree, 0, cur_row, cur_row + 1, state_ptr); - } - if (begin >= end) { - continue; - } - - idx_t parent_begin = begin / tree.TREE_FANOUT; - idx_t parent_end = end / tree.TREE_FANOUT; - if (parent_begin == parent_end) { - if (compute_left) { - WindowSegmentValue(tree, 0, begin, end, state_ptr); - } - continue; - } - - idx_t group_begin = parent_begin * tree.TREE_FANOUT; - if (begin != group_begin && compute_left) { - WindowSegmentValue(tree, 0, begin, group_begin + tree.TREE_FANOUT, state_ptr); - } - idx_t group_end = parent_end * tree.TREE_FANOUT; - if (end != group_end && compute_right) { - WindowSegmentValue(tree, 0, group_end, end, state_ptr); - } - } - FlushStates(false); -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_shared_expressions.cpp b/src/duckdb/src/function/window/window_shared_expressions.cpp deleted file mode 100644 index 811d3ec57..000000000 --- a/src/duckdb/src/function/window/window_shared_expressions.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/execution/expression_executor.hpp" - -namespace duckdb { - -column_t WindowSharedExpressions::RegisterExpr(const unique_ptr &expr, Shared &shared) { - auto pexpr = expr.get(); - if (!pexpr) { - return DConstants::INVALID_INDEX; - } - - // We need to make separate columns for volatile arguments - const auto is_volatile = expr->IsVolatile(); - auto i = shared.columns.find(*pexpr); - if (i != shared.columns.end() && !is_volatile) { - return i->second.front(); - } - - // New column, find maximum column number - column_t result = shared.size++; - shared.columns[*pexpr].emplace_back(result); - - return result; -} - -vector> WindowSharedExpressions::GetSortedExpressions(Shared &shared) { - vector> sorted(shared.size); - for (auto &col : shared.columns) { - auto &expr = col.first.get(); - for (auto col_idx : col.second) { - sorted[col_idx] = &expr; - } - } - - return sorted; -} -void WindowSharedExpressions::PrepareExecutors(Shared &shared, ExpressionExecutor &exec, DataChunk &chunk) { - const auto sorted = GetSortedExpressions(shared); - vector types; - for (auto expr : sorted) { - exec.AddExpression(*expr); - types.emplace_back(expr->return_type); - } - - if (!types.empty()) { - chunk.Initialize(exec.GetAllocator(), types); - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_token_tree.cpp b/src/duckdb/src/function/window/window_token_tree.cpp deleted file mode 100644 index 82b5124e4..000000000 --- a/src/duckdb/src/function/window/window_token_tree.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "duckdb/function/window/window_token_tree.hpp" - -namespace duckdb { - -class WindowTokenTreeLocalState : public WindowMergeSortTreeLocalState { -public: - explicit WindowTokenTreeLocalState(WindowTokenTree &token_tree) - : WindowMergeSortTreeLocalState(token_tree), token_tree(token_tree) { - } - //! Process sorted leaf data - void BuildLeaves() override; - - WindowTokenTree &token_tree; -}; - -void WindowTokenTreeLocalState::BuildLeaves() { - auto &global_sort = *token_tree.global_sort; - if (global_sort.sorted_blocks.empty()) { - return; - } - - // Scan the sort keys and note deltas - SBIterator curr(global_sort, ExpressionType::COMPARE_LESSTHAN); - SBIterator prev(global_sort, ExpressionType::COMPARE_LESSTHAN); - const auto &sort_layout = global_sort.sort_layout; - - const auto block_begin = token_tree.block_starts.at(build_task); - const auto block_end = token_tree.block_starts.at(build_task + 1); - auto &deltas = token_tree.deltas; - if (!block_begin) { - // First block, so set up initial delta - deltas[0] = 0; - } else { - // Move to the to end of the previous block - // so we can record the comparison result for the first row - curr.SetIndex(block_begin - 1); - prev.SetIndex(block_begin - 1); - } - - for (++curr; curr.GetIndex() < block_end; ++curr, ++prev) { - int lt = 0; - if (sort_layout.all_constant) { - lt = FastMemcmp(prev.entry_ptr, curr.entry_ptr, sort_layout.comparison_size); - } else { - lt = Comparators::CompareTuple(prev.scan, curr.scan, prev.entry_ptr, curr.entry_ptr, sort_layout, - prev.external); - } - - deltas[curr.GetIndex()] = (lt != 0); - } -} - -idx_t WindowTokenTree::MeasurePayloadBlocks() { - const auto count = WindowMergeSortTree::MeasurePayloadBlocks(); - - deltas.resize(count); - - return count; -} - -template -static void BuildTokens(WindowTokenTree &token_tree, vector &tokens) { - PayloadScanner scanner(*token_tree.global_sort); - DataChunk payload_chunk; - payload_chunk.Initialize(token_tree.context, token_tree.global_sort->payload_layout.GetTypes()); - const T *row_idx = nullptr; - idx_t i = 0; - - T token = 0; - for (auto &d : token_tree.deltas) { - if (i >= payload_chunk.size()) { - payload_chunk.Reset(); - scanner.Scan(payload_chunk); - if (!payload_chunk.size()) { - break; - } - row_idx = FlatVector::GetData(payload_chunk.data[0]); - i = 0; - } - - token += d; - tokens[row_idx[i++]] = token; - } -} - -unique_ptr WindowTokenTree::GetLocalState() { - return make_uniq(*this); -} - -void WindowTokenTree::CleanupSort() { - // Convert the deltas to tokens - if (mst64) { - BuildTokens(*this, mst64->LowestLevel()); - } else { - BuildTokens(*this, mst32->LowestLevel()); - } - - // Deallocate memory - vector empty; - deltas.swap(empty); - - WindowMergeSortTree::CleanupSort(); -} - -template -static idx_t TokenRank(const TREE &tree, const idx_t lower, const idx_t upper, const idx_t row_idx) { - idx_t rank = 1; - const auto needle = tree.LowestLevel()[row_idx]; - tree.AggregateLowerBound(lower, upper, needle, [&](idx_t level, const idx_t run_begin, const idx_t run_pos) { - rank += run_pos - run_begin; - }); - return rank; -} - -idx_t WindowTokenTree::Rank(const idx_t lower, const idx_t upper, const idx_t row_idx) const { - if (mst64) { - return TokenRank(*mst64, lower, upper, row_idx); - } else { - return TokenRank(*mst32, lower, upper, row_idx); - } -} - -template -static idx_t NextPeer(const TREE &tree, const idx_t lower, const idx_t upper, const idx_t row_idx) { - idx_t rank = 0; - // Because tokens are dense, we can find the next peer by adding 1 to the probed token value - const auto needle = tree.LowestLevel()[row_idx] + 1; - tree.AggregateLowerBound(lower, upper, needle, [&](idx_t level, const idx_t run_begin, const idx_t run_pos) { - rank += run_pos - run_begin; - }); - return rank; -} - -idx_t WindowTokenTree::PeerEnd(const idx_t lower, const idx_t upper, const idx_t row_idx) const { - if (mst64) { - return NextPeer(*mst64, lower, upper, row_idx); - } else { - return NextPeer(*mst32, lower, upper, row_idx); - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/function/window/window_value_function.cpp b/src/duckdb/src/function/window/window_value_function.cpp deleted file mode 100644 index 6b8a7038e..000000000 --- a/src/duckdb/src/function/window/window_value_function.cpp +++ /dev/null @@ -1,566 +0,0 @@ -#include "duckdb/common/operator/add.hpp" -#include "duckdb/common/operator/subtract.hpp" -#include "duckdb/function/window/window_aggregator.hpp" -#include "duckdb/function/window/window_collection.hpp" -#include "duckdb/function/window/window_index_tree.hpp" -#include "duckdb/function/window/window_shared_expressions.hpp" -#include "duckdb/function/window/window_token_tree.hpp" -#include "duckdb/function/window/window_value_function.hpp" -#include "duckdb/planner/expression/bound_window_expression.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// WindowValueGlobalState -//===--------------------------------------------------------------------===// - -class WindowValueGlobalState : public WindowExecutorGlobalState { -public: - using WindowCollectionPtr = unique_ptr; - WindowValueGlobalState(const WindowValueExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) - : WindowExecutorGlobalState(executor, payload_count, partition_mask, order_mask), ignore_nulls(&all_valid), - child_idx(executor.child_idx) { - - if (!executor.arg_order_idx.empty()) { - value_tree = make_uniq(executor.context, executor.wexpr.arg_orders, executor.arg_order_idx, - payload_count); - } - } - - void Finalize(CollectionPtr collection) { - lock_guard ignore_nulls_guard(lock); - if (child_idx != DConstants::INVALID_INDEX && executor.wexpr.ignore_nulls) { - ignore_nulls = &collection->validities[child_idx]; - } - } - - // IGNORE NULLS - mutex lock; - ValidityMask all_valid; - optional_ptr ignore_nulls; - - //! Copy of the executor child_idx - const column_t child_idx; - - //! Merge sort tree to map unfiltered row number to value - unique_ptr value_tree; -}; - -//===--------------------------------------------------------------------===// -// WindowValueLocalState -//===--------------------------------------------------------------------===// - -//! A class representing the state of the first_value, last_value and nth_value functions -class WindowValueLocalState : public WindowExecutorBoundsState { -public: - explicit WindowValueLocalState(const WindowValueGlobalState &gvstate) - : WindowExecutorBoundsState(gvstate), gvstate(gvstate) { - WindowAggregatorLocalState::InitSubFrames(frames, gvstate.executor.wexpr.exclude_clause); - - if (gvstate.value_tree) { - local_value = gvstate.value_tree->GetLocalState(); - if (gvstate.executor.wexpr.ignore_nulls) { - sort_nulls.Initialize(); - } - } - } - - //! Accumulate the secondary sort values - void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) override; - //! Finish the sinking and prepare to scan - void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) override; - - //! The corresponding global value state - const WindowValueGlobalState &gvstate; - //! The optional sorting state for secondary sorts - unique_ptr local_value; - //! Reusable selection vector for NULLs - SelectionVector sort_nulls; - //! The frame boundaries, used for EXCLUDE - SubFrames frames; - - //! The state used for reading the collection - unique_ptr cursor; -}; - -void WindowValueLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) { - WindowExecutorBoundsState::Sink(gstate, sink_chunk, coll_chunk, input_idx); - - if (local_value) { - idx_t filtered = 0; - optional_ptr filter_sel; - - // If we need to IGNORE NULLS for the child, and there are NULLs, - // then build an SV to hold them - const auto coll_count = coll_chunk.size(); - auto &child = coll_chunk.data[gvstate.child_idx]; - UnifiedVectorFormat child_data; - child.ToUnifiedFormat(coll_count, child_data); - const auto &validity = child_data.validity; - if (gstate.executor.wexpr.ignore_nulls && !validity.AllValid()) { - for (sel_t i = 0; i < coll_count; ++i) { - if (validity.RowIsValidUnsafe(i)) { - sort_nulls[filtered++] = i; - } - } - filter_sel = &sort_nulls; - } - - auto &value_state = local_value->Cast(); - value_state.SinkChunk(sink_chunk, input_idx, filter_sel, filtered); - } -} - -void WindowValueLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { - WindowExecutorBoundsState::Finalize(gstate, collection); - - if (local_value) { - auto &value_state = local_value->Cast(); - value_state.Sort(); - value_state.index_tree.Build(); - } - - // Prepare to scan - if (!cursor && gvstate.child_idx != DConstants::INVALID_INDEX) { - cursor = make_uniq(*collection, gvstate.child_idx); - } -} - -//===--------------------------------------------------------------------===// -// WindowValueExecutor -//===--------------------------------------------------------------------===// -WindowValueExecutor::WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowExecutor(wexpr, context, shared) { - - for (const auto &order : wexpr.arg_orders) { - arg_order_idx.emplace_back(shared.RegisterSink(order.expression)); - } - - // The children have to be handled separately because only the first one is global - if (!wexpr.children.empty()) { - child_idx = shared.RegisterCollection(wexpr.children[0], wexpr.ignore_nulls); - - if (wexpr.children.size() > 1) { - nth_idx = shared.RegisterEvaluate(wexpr.children[1]); - } - } - - offset_idx = shared.RegisterEvaluate(wexpr.offset_expr); - default_idx = shared.RegisterEvaluate(wexpr.default_expr); -} - -unique_ptr WindowValueExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -void WindowValueExecutor::Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const { - auto &gvstate = gstate.Cast(); - gvstate.Finalize(collection); - - WindowExecutor::Finalize(gstate, lstate, collection); -} - -unique_ptr WindowValueExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - const auto &gvstate = gstate.Cast(); - return make_uniq(gvstate); -} - -//===--------------------------------------------------------------------===// -// WindowLeadLagGlobalState -//===--------------------------------------------------------------------===// -// The functions LEAD and LAG can be extended to a windowed version with -// two independent ORDER BY clauses just like first_value and other value -// functions. -// To evaluate a windowed LEAD/LAG, one has to (1) compute the ROW_NUMBER -// of the own row, (2) adjust the row number by adding or subtracting an -// offset, (3) find the row at that offset, and (4) evaluate the expression -// provided to LEAD/LAG on this row. One can use the algorithm from Section -// 4.4 to determine the row number of the own row (step 1) and the -// algorithm from Section 4.5 to find the row with the adjusted position -// (step 3). Both algorithms are in O(𝑛 log𝑛), so the overall algorithm -// for LEAD/LAG is also O(𝑛 log𝑛). -// -// 4.4: unique WindowTokenTree -// 4.5: WindowIndexTree - -class WindowLeadLagGlobalState : public WindowValueGlobalState { -public: - explicit WindowLeadLagGlobalState(const WindowValueExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask) - : WindowValueGlobalState(executor, payload_count, partition_mask, order_mask) { - - if (value_tree) { - // "The ROW_NUMBER function can be computed by disambiguating duplicate elements based on their position in - // the input data, such that two elements never compare as equal." - // Note: If the user specifies an partial secondary sort, the disambiguation will use the - // partition's row numbers, not the secondary sort's row numbers. - row_tree = make_uniq(executor.context, executor.wexpr.arg_orders, executor.arg_order_idx, - payload_count, true); - } - } - - //! Merge sort tree to map partition offset to row number (algorithm from Section 4.5) - unique_ptr row_tree; -}; - -//===--------------------------------------------------------------------===// -// WindowLeadLagLocalState -//===--------------------------------------------------------------------===// -class WindowLeadLagLocalState : public WindowValueLocalState { -public: - explicit WindowLeadLagLocalState(const WindowLeadLagGlobalState &gstate) : WindowValueLocalState(gstate) { - if (gstate.row_tree) { - local_row = gstate.row_tree->GetLocalState(); - } - } - - //! Accumulate the secondary sort values - void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) override; - //! Finish the sinking and prepare to scan - void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) override; - - //! The optional sorting state for the secondary sort row mapping - unique_ptr local_row; -}; - -void WindowLeadLagLocalState::Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx) { - WindowValueLocalState::Sink(gstate, sink_chunk, coll_chunk, input_idx); - - if (local_row) { - idx_t filtered = 0; - optional_ptr filter_sel; - - auto &row_state = local_row->Cast(); - row_state.SinkChunk(sink_chunk, input_idx, filter_sel, filtered); - } -} - -void WindowLeadLagLocalState::Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection) { - WindowValueLocalState::Finalize(gstate, collection); - - if (local_row) { - auto &row_state = local_row->Cast(); - row_state.Sort(); - row_state.window_tree.Build(); - } -} - -//===--------------------------------------------------------------------===// -// WindowLeadLagExecutor -//===--------------------------------------------------------------------===// -WindowLeadLagExecutor::WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowValueExecutor(wexpr, context, shared) { -} - -unique_ptr WindowLeadLagExecutor::GetGlobalState(const idx_t payload_count, - const ValidityMask &partition_mask, - const ValidityMask &order_mask) const { - return make_uniq(*this, payload_count, partition_mask, order_mask); -} - -unique_ptr -WindowLeadLagExecutor::GetLocalState(const WindowExecutorGlobalState &gstate) const { - const auto &glstate = gstate.Cast(); - return make_uniq(glstate); -} - -void WindowLeadLagExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { - auto &glstate = gstate.Cast(); - auto &llstate = lstate.Cast(); - auto &cursor = *llstate.cursor; - - WindowInputExpression leadlag_offset(eval_chunk, offset_idx); - WindowInputExpression leadlag_default(eval_chunk, default_idx); - - if (glstate.row_tree) { - auto frame_begin = FlatVector::GetData(llstate.bounds.data[FRAME_BEGIN]); - auto frame_end = FlatVector::GetData(llstate.bounds.data[FRAME_END]); - // TODO: Handle subframes. - auto &frames = llstate.frames; - frames.resize(1); - auto &frame = frames[0]; - for (idx_t i = 0; i < count; ++i, ++row_idx) { - // (1) compute the ROW_NUMBER of the own row - frame = FrameBounds(frame_begin[i], frame_end[i]); - const auto own_row = glstate.row_tree->Rank(frame.start, frame.end, row_idx) - 1; - // (2) adjust the row number by adding or subtracting an offset - auto val_idx = NumericCast(own_row); - int64_t offset = 1; - if (wexpr.offset_expr) { - offset = leadlag_offset.GetCell(i); - } - if (wexpr.GetExpressionType() == ExpressionType::WINDOW_LEAD) { - val_idx = AddOperatorOverflowCheck::Operation(val_idx, offset); - } else { - val_idx = SubtractOperatorOverflowCheck::Operation(val_idx, offset); - } - const auto frame_width = NumericCast(frame.end - frame.start); - if (val_idx >= 0 && val_idx < frame_width) { - // (3) find the row at that offset - const auto n = NumericCast(val_idx); - const auto nth_index = glstate.value_tree->SelectNth(frames, n); - // (4) evaluate the expression provided to LEAD/LAG on this row. - cursor.CopyCell(0, nth_index, result, i); - } else if (wexpr.default_expr) { - leadlag_default.CopyCell(result, i); - } else { - FlatVector::SetNull(result, i, true); - } - } - return; - } - - auto partition_begin = FlatVector::GetData(llstate.bounds.data[PARTITION_BEGIN]); - auto partition_end = FlatVector::GetData(llstate.bounds.data[PARTITION_END]); - - auto &ignore_nulls = glstate.ignore_nulls; - bool can_shift = ignore_nulls->AllValid(); - if (wexpr.offset_expr) { - can_shift = can_shift && wexpr.offset_expr->IsFoldable(); - } - if (wexpr.default_expr) { - can_shift = can_shift && wexpr.default_expr->IsFoldable(); - } - - const auto row_end = row_idx + count; - for (idx_t i = 0; i < count;) { - int64_t offset = 1; - if (wexpr.offset_expr) { - offset = leadlag_offset.GetCell(i); - } - int64_t val_idx = (int64_t)row_idx; - if (wexpr.GetExpressionType() == ExpressionType::WINDOW_LEAD) { - val_idx = AddOperatorOverflowCheck::Operation(val_idx, offset); - } else { - val_idx = SubtractOperatorOverflowCheck::Operation(val_idx, offset); - } - - idx_t delta = 0; - if (val_idx < (int64_t)row_idx) { - // Count backwards - delta = idx_t(row_idx - idx_t(val_idx)); - val_idx = int64_t(WindowBoundariesState::FindPrevStart(*ignore_nulls, partition_begin[i], row_idx, delta)); - } else if (val_idx > (int64_t)row_idx) { - delta = idx_t(idx_t(val_idx) - row_idx); - val_idx = - int64_t(WindowBoundariesState::FindNextStart(*ignore_nulls, row_idx + 1, partition_end[i], delta)); - } - // else offset is zero, so don't move. - - if (can_shift) { - const auto target_limit = MinValue(partition_end[i], row_end) - row_idx; - if (!delta) { - // Copy source[index:index+width] => result[i:] - auto index = NumericCast(val_idx); - const auto source_limit = partition_end[i] - index; - auto width = MinValue(source_limit, target_limit); - // We may have to scan multiple blocks here, so loop until we have copied everything - const idx_t col_idx = 0; - while (width) { - const auto source_offset = cursor.Seek(index); - auto &source = cursor.chunk.data[col_idx]; - const auto copied = MinValue(cursor.chunk.size() - source_offset, width); - VectorOperations::Copy(source, result, source_offset + copied, source_offset, i); - i += copied; - row_idx += copied; - index += copied; - width -= copied; - } - } else if (wexpr.default_expr) { - const auto width = MinValue(delta, target_limit); - leadlag_default.CopyCell(result, i, width); - i += width; - row_idx += width; - } else { - for (idx_t nulls = MinValue(delta, target_limit); nulls--; ++i, ++row_idx) { - FlatVector::SetNull(result, i, true); - } - } - } else { - if (!delta) { - cursor.CopyCell(0, NumericCast(val_idx), result, i); - } else if (wexpr.default_expr) { - leadlag_default.CopyCell(result, i); - } else { - FlatVector::SetNull(result, i, true); - } - ++i; - ++row_idx; - } - } -} - -WindowFirstValueExecutor::WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowValueExecutor(wexpr, context, shared) { -} - -void WindowFirstValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &lvstate = lstate.Cast(); - auto &cursor = *lvstate.cursor; - auto &bounds = lvstate.bounds; - auto &frames = lvstate.frames; - auto &ignore_nulls = *gvstate.ignore_nulls; - auto exclude_mode = gvstate.executor.wexpr.exclude_clause; - WindowAggregator::EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t i) { - if (gvstate.value_tree) { - idx_t frame_width = 0; - for (const auto &frame : frames) { - frame_width += frame.end - frame.start; - } - - if (frame_width) { - const auto first_idx = gvstate.value_tree->SelectNth(frames, 0); - cursor.CopyCell(0, first_idx, result, i); - } else { - FlatVector::SetNull(result, i, true); - } - return; - } - - for (const auto &frame : frames) { - if (frame.start >= frame.end) { - continue; - } - - // Same as NTH_VALUE(..., 1) - idx_t n = 1; - const auto first_idx = WindowBoundariesState::FindNextStart(ignore_nulls, frame.start, frame.end, n); - if (!n) { - cursor.CopyCell(0, first_idx, result, i); - return; - } - } - - // Didn't find one - FlatVector::SetNull(result, i, true); - }); -} - -WindowLastValueExecutor::WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowValueExecutor(wexpr, context, shared) { -} - -void WindowLastValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, - idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &lvstate = lstate.Cast(); - auto &cursor = *lvstate.cursor; - auto &bounds = lvstate.bounds; - auto &frames = lvstate.frames; - auto &ignore_nulls = *gvstate.ignore_nulls; - auto exclude_mode = gvstate.executor.wexpr.exclude_clause; - WindowAggregator::EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t i) { - if (gvstate.value_tree) { - idx_t frame_width = 0; - for (const auto &frame : frames) { - frame_width += frame.end - frame.start; - } - - if (frame_width) { - const auto last_idx = gvstate.value_tree->SelectNth(frames, frame_width - 1); - cursor.CopyCell(0, last_idx, result, i); - } else { - FlatVector::SetNull(result, i, true); - } - return; - } - - for (idx_t f = frames.size(); f-- > 0;) { - const auto &frame = frames[f]; - if (frame.start >= frame.end) { - continue; - } - - idx_t n = 1; - const auto last_idx = WindowBoundariesState::FindPrevStart(ignore_nulls, frame.start, frame.end, n); - if (!n) { - cursor.CopyCell(0, last_idx, result, i); - return; - } - } - - // Didn't find one - FlatVector::SetNull(result, i, true); - }); -} - -WindowNthValueExecutor::WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, - WindowSharedExpressions &shared) - : WindowValueExecutor(wexpr, context, shared) { -} - -void WindowNthValueExecutor::EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const { - auto &gvstate = gstate.Cast(); - auto &lvstate = lstate.Cast(); - auto &cursor = *lvstate.cursor; - auto &bounds = lvstate.bounds; - auto &frames = lvstate.frames; - auto &ignore_nulls = *gvstate.ignore_nulls; - auto exclude_mode = gvstate.executor.wexpr.exclude_clause; - D_ASSERT(cursor.chunk.ColumnCount() == 1); - WindowInputExpression nth_col(eval_chunk, nth_idx); - WindowAggregator::EvaluateSubFrames(bounds, exclude_mode, count, row_idx, frames, [&](idx_t i) { - // Returns value evaluated at the row that is the n'th row of the window frame (counting from 1); - // returns NULL if there is no such row. - if (nth_col.CellIsNull(i)) { - FlatVector::SetNull(result, i, true); - return; - } - auto n_param = nth_col.GetCell(i); - if (n_param < 1) { - FlatVector::SetNull(result, i, true); - return; - } - - // Decrement as we go along. - auto n = idx_t(n_param); - - if (gvstate.value_tree) { - idx_t frame_width = 0; - for (const auto &frame : frames) { - frame_width += frame.end - frame.start; - } - - if (n < frame_width) { - const auto nth_index = gvstate.value_tree->SelectNth(frames, n - 1); - cursor.CopyCell(0, nth_index, result, i); - } else { - FlatVector::SetNull(result, i, true); - } - return; - } - - for (const auto &frame : frames) { - if (frame.start >= frame.end) { - continue; - } - - const auto nth_index = WindowBoundariesState::FindNextStart(ignore_nulls, frame.start, frame.end, n); - if (!n) { - cursor.CopyCell(0, nth_index, result, i); - return; - } - } - FlatVector::SetNull(result, i, true); - }); -} - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb.h b/src/duckdb/src/include/duckdb.h index ae52abd33..30b79fd9a 100644 --- a/src/duckdb/src/include/duckdb.h +++ b/src/duckdb/src/include/duckdb.h @@ -85,7 +85,7 @@ typedef enum DUCKDB_TYPE { DUCKDB_TYPE_FLOAT = 10, // double DUCKDB_TYPE_DOUBLE = 11, - // duckdb_timestamp (microseconds) + // duckdb_timestamp, in microseconds DUCKDB_TYPE_TIMESTAMP = 12, // duckdb_date DUCKDB_TYPE_DATE = 13, @@ -101,13 +101,13 @@ typedef enum DUCKDB_TYPE { DUCKDB_TYPE_VARCHAR = 17, // duckdb_blob DUCKDB_TYPE_BLOB = 18, - // duckdb_decimal + // decimal DUCKDB_TYPE_DECIMAL = 19, - // duckdb_timestamp_s (seconds) + // duckdb_timestamp, in seconds DUCKDB_TYPE_TIMESTAMP_S = 20, - // duckdb_timestamp_ms (milliseconds) + // duckdb_timestamp, in milliseconds DUCKDB_TYPE_TIMESTAMP_MS = 21, - // duckdb_timestamp_ns (nanoseconds) + // duckdb_timestamp, in nanoseconds DUCKDB_TYPE_TIMESTAMP_NS = 22, // enum type, only useful as logical type DUCKDB_TYPE_ENUM = 23, @@ -127,7 +127,7 @@ typedef enum DUCKDB_TYPE { DUCKDB_TYPE_BIT = 29, // duckdb_time_tz DUCKDB_TYPE_TIME_TZ = 30, - // duckdb_timestamp (microseconds) + // duckdb_timestamp DUCKDB_TYPE_TIMESTAMP_TZ = 31, // ANY type DUCKDB_TYPE_ANY = 34, @@ -282,32 +282,15 @@ typedef struct { int32_t offset; } duckdb_time_tz_struct; -//! TIMESTAMP values are stored as microseconds since 1970-01-01. -//! Use the duckdb_from_timestamp and duckdb_to_timestamp functions to extract individual information. +//! Timestamps are stored as microseconds since 1970-01-01 +//! Use the duckdb_from_timestamp/duckdb_to_timestamp function to extract individual information typedef struct { int64_t micros; } duckdb_timestamp; - -//! TIMESTAMP_S values are stored as seconds since 1970-01-01. -typedef struct { - int64_t seconds; -} duckdb_timestamp_s; - -//! TIMESTAMP_MS values are stored as milliseconds since 1970-01-01. -typedef struct { - int64_t millis; -} duckdb_timestamp_ms; - -//! TIMESTAMP_NS values are stored as nanoseconds since 1970-01-01. -typedef struct { - int64_t nanos; -} duckdb_timestamp_ns; - typedef struct { duckdb_date_struct date; duckdb_time_struct time; } duckdb_timestamp_struct; - typedef struct { int32_t months; int32_t days; @@ -406,25 +389,6 @@ typedef struct { idx_t size; } duckdb_blob; -//! BITs are composed of a byte pointer and a size. -//! BIT byte data has 0 to 7 bits of padding. -//! The first byte contains the number of padding bits. -//! This number of bits of the second byte are set to 1, starting from the MSB. -//! You must free `data` with `duckdb_free`. -typedef struct { - uint8_t *data; - idx_t size; -} duckdb_bit; - -//! VARINTs are composed of a byte pointer, a size, and an is_negative bool. -//! The absolute value of the number is stored in `data` in little endian format. -//! You must free `data` with `duckdb_free`. -typedef struct { - uint8_t *data; - idx_t size; - bool is_negative; -} duckdb_varint; - //! A query result consists of a pointer to its internal data. //! Must be freed with 'duckdb_destroy_result'. typedef struct { @@ -441,12 +405,7 @@ typedef struct { void *internal_data; } duckdb_result; -//! A database instance cache object. Must be destroyed with `duckdb_destroy_instance_cache`. -typedef struct _duckdb_instance_cache { - void *internal_ptr; -} * duckdb_instance_cache; - -//! A database object. Must be closed with `duckdb_close`. +//! A database object. Should be closed with `duckdb_close`. typedef struct _duckdb_database { void *internal_ptr; } * duckdb_database; @@ -675,8 +634,6 @@ struct duckdb_extension_access { const void *(*get_api)(duckdb_extension_info info, const char *version); }; -#ifndef DUCKDB_API_EXCLUDE_FUNCTIONS - //===--------------------------------------------------------------------===// // Functions //===--------------------------------------------------------------------===// @@ -685,44 +642,12 @@ struct duckdb_extension_access { // Open Connect //===--------------------------------------------------------------------===// -/*! -Creates a new database instance cache. -The instance cache is necessary if a client/program (re)opens multiple databases to the same file within the same -process. Must be destroyed with 'duckdb_destroy_instance_cache'. - -* @return The database instance cache. -*/ -DUCKDB_API duckdb_instance_cache duckdb_create_instance_cache(); - -/*! -Creates a new database instance in the instance cache, or retrieves an existing database instance. -Must be closed with 'duckdb_close'. - -* @param instance_cache The instance cache in which to create the database, or from which to take the database. -* @param path Path to the database file on disk. Both `nullptr` and `:memory:` open or retrieve an in-memory database. -* @param out_database The resulting cached database. -* @param config (Optional) configuration used to create the database. -* @param out_error If set and the function returns `DuckDBError`, this contains the error message. -Note that the error message must be freed using `duckdb_free`. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_get_or_create_from_cache(duckdb_instance_cache instance_cache, const char *path, - duckdb_database *out_database, duckdb_config config, - char **out_error); - -/*! -Destroys an existing database instance cache and de-allocates its memory. - -* @param instance_cache The instance cache to destroy. -*/ -DUCKDB_API void duckdb_destroy_instance_cache(duckdb_instance_cache *instance_cache); - /*! Creates a new database or opens an existing database file stored at the given path. If no path is given a new in-memory database is created instead. -The database must be closed with 'duckdb_close'. +The instantiated database should be closed with 'duckdb_close'. -* @param path Path to the database file on disk. Both `nullptr` and `:memory:` open an in-memory database. +* @param path Path to the database file on disk, or `nullptr` or `:memory:` to open an in-memory database. * @param out_database The result database object. * @return `DuckDBSuccess` on success or `DuckDBError` on failure. */ @@ -730,13 +655,13 @@ DUCKDB_API duckdb_state duckdb_open(const char *path, duckdb_database *out_datab /*! Extended version of duckdb_open. Creates a new database or opens an existing database file stored at the given path. -The database must be closed with 'duckdb_close'. +The instantiated database should be closed with 'duckdb_close'. -* @param path Path to the database file on disk. Both `nullptr` and `:memory:` open an in-memory database. +* @param path Path to the database file on disk, or `nullptr` or `:memory:` to open an in-memory database. * @param out_database The result database object. -* @param config (Optional) configuration used to start up the database. -* @param out_error If set and the function returns `DuckDBError`, this contains the error message. -Note that the error message must be freed using `duckdb_free`. +* @param config (Optional) configuration used to start up the database system. +* @param out_error If set and the function returns DuckDBError, this will contain the reason why the start-up failed. +Note that the error must be freed using `duckdb_free`. * @return `DuckDBSuccess` on success or `DuckDBError` on failure. */ DUCKDB_API duckdb_state duckdb_open_ext(const char *path, duckdb_database *out_database, duckdb_config config, @@ -1398,35 +1323,11 @@ DUCKDB_API duckdb_timestamp duckdb_to_timestamp(duckdb_timestamp_struct ts); /*! Test a `duckdb_timestamp` to see if it is a finite value. -* @param ts The duckdb_timestamp object, as obtained from a `DUCKDB_TYPE_TIMESTAMP` column. +* @param ts The timestamp object, as obtained from a `DUCKDB_TYPE_TIMESTAMP` column. * @return True if the timestamp is finite, false if it is ±infinity. */ DUCKDB_API bool duckdb_is_finite_timestamp(duckdb_timestamp ts); -/*! -Test a `duckdb_timestamp_s` to see if it is a finite value. - -* @param ts The duckdb_timestamp_s object, as obtained from a `DUCKDB_TYPE_TIMESTAMP_S` column. -* @return True if the timestamp is finite, false if it is ±infinity. -*/ -DUCKDB_API bool duckdb_is_finite_timestamp_s(duckdb_timestamp_s ts); - -/*! -Test a `duckdb_timestamp_ms` to see if it is a finite value. - -* @param ts The duckdb_timestamp_ms object, as obtained from a `DUCKDB_TYPE_TIMESTAMP_MS` column. -* @return True if the timestamp is finite, false if it is ±infinity. -*/ -DUCKDB_API bool duckdb_is_finite_timestamp_ms(duckdb_timestamp_ms ts); - -/*! -Test a `duckdb_timestamp_ns` to see if it is a finite value. - -* @param ts The duckdb_timestamp_ns object, as obtained from a `DUCKDB_TYPE_TIMESTAMP_NS` column. -* @return True if the timestamp is finite, false if it is ±infinity. -*/ -DUCKDB_API bool duckdb_is_finite_timestamp_ns(duckdb_timestamp_ns ts); - //===--------------------------------------------------------------------===// // Hugeint Helpers //===--------------------------------------------------------------------===// @@ -1570,19 +1471,6 @@ Returns `DUCKDB_TYPE_INVALID` if the parameter index is out of range or the stat */ DUCKDB_API duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx); -/*! -Returns the logical type for the parameter at the given index. - -Returns `nullptr` if the parameter index is out of range or the statement was not successfully prepared. - -The return type of this call should be destroyed with `duckdb_destroy_logical_type`. - -* @param prepared_statement The prepared statement. -* @param param_idx The parameter index. -* @return The logical type of the parameter -*/ -DUCKDB_API duckdb_logical_type duckdb_param_logical_type(duckdb_prepared_statement prepared_statement, idx_t param_idx); - /*! Clear the params bind to the prepared statement. */ @@ -2049,22 +1937,6 @@ Creates a value from a uhugeint */ DUCKDB_API duckdb_value duckdb_create_uhugeint(duckdb_uhugeint input); -/*! -Creates a VARINT value from a duckdb_varint - -* @param input The duckdb_varint value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_varint(duckdb_varint input); - -/*! -Creates a DECIMAL value from a duckdb_decimal - -* @param input The duckdb_decimal value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_decimal(duckdb_decimal input); - /*! Creates a value from a float @@ -2107,45 +1979,13 @@ Not to be confused with `duckdb_create_time_tz`, which creates a duckdb_time_tz_ DUCKDB_API duckdb_value duckdb_create_time_tz_value(duckdb_time_tz value); /*! -Creates a TIMESTAMP value from a duckdb_timestamp +Creates a value from a timestamp -* @param input The duckdb_timestamp value +* @param input The timestamp value * @return The value. This must be destroyed with `duckdb_destroy_value`. */ DUCKDB_API duckdb_value duckdb_create_timestamp(duckdb_timestamp input); -/*! -Creates a TIMESTAMP_TZ value from a duckdb_timestamp - -* @param input The duckdb_timestamp value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_timestamp_tz(duckdb_timestamp input); - -/*! -Creates a TIMESTAMP_S value from a duckdb_timestamp_s - -* @param input The duckdb_timestamp_s value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_timestamp_s(duckdb_timestamp_s input); - -/*! -Creates a TIMESTAMP_MS value from a duckdb_timestamp_ms - -* @param input The duckdb_timestamp_ms value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_timestamp_ms(duckdb_timestamp_ms input); - -/*! -Creates a TIMESTAMP_NS value from a duckdb_timestamp_ns - -* @param input The duckdb_timestamp_ns value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_timestamp_ns(duckdb_timestamp_ns input); - /*! Creates a value from an interval @@ -2163,22 +2003,6 @@ Creates a value from a blob */ DUCKDB_API duckdb_value duckdb_create_blob(const uint8_t *data, idx_t length); -/*! -Creates a BIT value from a duckdb_bit - -* @param input The duckdb_bit value -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_bit(duckdb_bit input); - -/*! -Creates a UUID value from a uhugeint - -* @param input The duckdb_uhugeint containing the UUID -* @return The value. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_uuid(duckdb_uhugeint input); - /*! Returns the boolean value of the given value. @@ -2267,23 +2091,6 @@ Returns the uhugeint value of the given value. */ DUCKDB_API duckdb_uhugeint duckdb_get_uhugeint(duckdb_value val); -/*! -Returns the duckdb_varint value of the given value. -The `data` field must be destroyed with `duckdb_free`. - -* @param val A duckdb_value containing a VARINT -* @return A duckdb_varint. The `data` field must be destroyed with `duckdb_free`. -*/ -DUCKDB_API duckdb_varint duckdb_get_varint(duckdb_value val); - -/*! -Returns the duckdb_decimal value of the given value. - -* @param val A duckdb_value containing a DECIMAL -* @return A duckdb_decimal, or MinValue if the value cannot be converted -*/ -DUCKDB_API duckdb_decimal duckdb_get_decimal(duckdb_value val); - /*! Returns the float value of the given value. @@ -2325,45 +2132,13 @@ Returns the time_tz value of the given value. DUCKDB_API duckdb_time_tz duckdb_get_time_tz(duckdb_value val); /*! -Returns the TIMESTAMP value of the given value. +Returns the timestamp value of the given value. -* @param val A duckdb_value containing a TIMESTAMP +* @param val A duckdb_value containing a timestamp * @return A duckdb_timestamp, or MinValue if the value cannot be converted */ DUCKDB_API duckdb_timestamp duckdb_get_timestamp(duckdb_value val); -/*! -Returns the TIMESTAMP_TZ value of the given value. - -* @param val A duckdb_value containing a TIMESTAMP_TZ -* @return A duckdb_timestamp, or MinValue if the value cannot be converted -*/ -DUCKDB_API duckdb_timestamp duckdb_get_timestamp_tz(duckdb_value val); - -/*! -Returns the duckdb_timestamp_s value of the given value. - -* @param val A duckdb_value containing a TIMESTAMP_S -* @return A duckdb_timestamp_s, or MinValue if the value cannot be converted -*/ -DUCKDB_API duckdb_timestamp_s duckdb_get_timestamp_s(duckdb_value val); - -/*! -Returns the duckdb_timestamp_ms value of the given value. - -* @param val A duckdb_value containing a TIMESTAMP_MS -* @return A duckdb_timestamp_ms, or MinValue if the value cannot be converted -*/ -DUCKDB_API duckdb_timestamp_ms duckdb_get_timestamp_ms(duckdb_value val); - -/*! -Returns the duckdb_timestamp_ns value of the given value. - -* @param val A duckdb_value containing a TIMESTAMP_NS -* @return A duckdb_timestamp_ns, or MinValue if the value cannot be converted -*/ -DUCKDB_API duckdb_timestamp_ns duckdb_get_timestamp_ns(duckdb_value val); - /*! Returns the interval value of the given value. @@ -2389,23 +2164,6 @@ Returns the blob value of the given value. */ DUCKDB_API duckdb_blob duckdb_get_blob(duckdb_value val); -/*! -Returns the duckdb_bit value of the given value. -The `data` field must be destroyed with `duckdb_free`. - -* @param val A duckdb_value containing a BIT -* @return A duckdb_bit -*/ -DUCKDB_API duckdb_bit duckdb_get_bit(duckdb_value val); - -/*! -Returns a duckdb_uhugeint representing the UUID value of the given value. - -* @param val A duckdb_value containing a UUID -* @return A duckdb_uhugeint representing the UUID value -*/ -DUCKDB_API duckdb_uhugeint duckdb_get_uuid(duckdb_value val); - /*! Obtains a string representation of the given value. The result must be destroyed with `duckdb_free`. @@ -2472,64 +2230,6 @@ Returns the MAP value at index as a duckdb_value. */ DUCKDB_API duckdb_value duckdb_get_map_value(duckdb_value value, idx_t index); -/*! -Returns whether the value's type is SQLNULL or not. - -* @param value The value to check. -* @return True, if the value's type is SQLNULL, otherwise false. -*/ -DUCKDB_API bool duckdb_is_null_value(duckdb_value value); - -/*! -Creates a value of type SQLNULL. - -* @return The duckdb_value representing SQLNULL. This must be destroyed with `duckdb_destroy_value`. -*/ -DUCKDB_API duckdb_value duckdb_create_null_value(); - -/*! -Returns the number of elements in a LIST value. - -* @param value The LIST value. -* @return The number of elements in the list. -*/ -DUCKDB_API idx_t duckdb_get_list_size(duckdb_value value); - -/*! -Returns the LIST child at index as a duckdb_value. - -* @param value The LIST value. -* @param index The index of the child. -* @return The child as a duckdb_value. -*/ -DUCKDB_API duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index); - -/*! -Creates an enum value from a type and a value. Must be destroyed with `duckdb_destroy_value`. - -* @param type The type of the enum -* @param value The value for the enum -* @return The enum value, or nullptr. -*/ -DUCKDB_API duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value); - -/*! -Returns the enum value of the given value. - -* @param value A duckdb_value containing an enum -* @return A uint64_t, or MinValue if the value cannot be converted -*/ -DUCKDB_API uint64_t duckdb_get_enum_value(duckdb_value value); - -/*! -Returns the STRUCT child at index as a duckdb_value. - -* @param value The STRUCT value. -* @param index The index of the child. -* @return The child as a duckdb_value. -*/ -DUCKDB_API duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index); - //===--------------------------------------------------------------------===// // Logical Type Interface //===--------------------------------------------------------------------===// @@ -2936,7 +2636,7 @@ DUCKDB_API uint64_t *duckdb_vector_get_validity(duckdb_vector vector); Ensures the validity mask is writable by allocating it. After this function is called, `duckdb_vector_get_validity` will ALWAYS return non-NULL. -This allows NULL values to be written to the vector, regardless of whether a validity mask was present before. +This allows null values to be written to the vector, regardless of whether a validity mask was present before. * @param vector The vector to alter */ @@ -3783,20 +3483,18 @@ DUCKDB_API duckdb_profiling_info duckdb_profiling_info_get_child(duckdb_profilin // Appender //===--------------------------------------------------------------------===// -// Appenders are the most efficient way of loading data into DuckDB from within the C API. -// They are recommended for fast data loading as they perform better than prepared statements or individual `INSERT -// INTO` statements. - -// Appends are possible in row-wise format, and by appending entire data chunks. +// Appenders are the most efficient way of loading data into DuckDB from within the C interface, and are recommended for +// fast data loading. The appender is much faster than using prepared statements or individual `INSERT INTO` statements. -// Row-wise: for every column, a `duckdb_append_[type]` call should be made. After finishing all appends to a row, call -// `duckdb_appender_end_row`. +// Appends are made in row-wise format. For every column, a `duckdb_append_[type]` call should be made, after which +// the row should be finished by calling `duckdb_appender_end_row`. After all rows have been appended, +// `duckdb_appender_destroy` should be used to finalize the appender and clean up the resulting memory. -// Chunk-wise: Consecutively call `duckdb_append_data_chunk` until all chunks have been appended. - -// After all data has been appended, call `duckdb_appender_close` to finalize the appender followed by -// `duckdb_appender_destroy` to clean up the memory. +// Instead of appending rows with `duckdb_appender_end_row`, it is also possible to fill and append +// chunks-at-a-time. +// Note that `duckdb_appender_destroy` should always be called on the resulting appender, even if the function returns +// `DuckDBError`. /*! Creates an appender object. @@ -3812,39 +3510,21 @@ DUCKDB_API duckdb_state duckdb_appender_create(duckdb_connection connection, con duckdb_appender *out_appender); /*! -Creates an appender object. - -Note that the object must be destroyed with `duckdb_appender_destroy`. - -* @param connection The connection context to create the appender in. -* @param catalog The catalog of the table to append to, or `nullptr` for the default catalog. -* @param schema The schema of the table to append to, or `nullptr` for the default schema. -* @param table The table name to append to. -* @param out_appender The resulting appender object. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, - const char *schema, const char *table, - duckdb_appender *out_appender); - -/*! -Returns the number of columns that belong to the appender. -If there is no active column list, then this equals the table's physical columns. +Returns the number of columns in the table that belongs to the appender. * @param appender The appender to get the column count from. -* @return The number of columns in the data chunks. +* @return The number of columns in the table. */ DUCKDB_API idx_t duckdb_appender_column_count(duckdb_appender appender); /*! -Returns the type of the column at the specified index. This is either a type in the active column list, or the same type -as a column in the receiving table. +Returns the type of the column at the specified index. -Note: The resulting type must be destroyed with `duckdb_destroy_logical_type`. +Note: The resulting type should be destroyed with `duckdb_destroy_logical_type`. * @param appender The appender to get the column type from. * @param col_idx The index of the column to get the type of. -* @return The `duckdb_logical_type` of the column. +* @return The duckdb_logical_type of the column. */ DUCKDB_API duckdb_logical_type duckdb_appender_column_type(duckdb_appender appender, idx_t col_idx); @@ -3893,26 +3573,6 @@ before destroying the appender, if you need insights into the specific error. */ DUCKDB_API duckdb_state duckdb_appender_destroy(duckdb_appender *appender); -/*! -Appends a column to the active column list of the appender. Immediately flushes all previous data. - -The active column list specifies all columns that are expected when flushing the data. Any non-active columns are filled -with their default values, or NULL. - -* @param appender The appender to add the column to. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_appender_add_column(duckdb_appender appender, const char *name); - -/*! -Removes all columns from the active column list of the appender, resetting the appender to treat all columns as active. -Immediately flushes all previous data. - -* @param appender The appender to clear the columns from. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_appender_clear_columns(duckdb_appender appender); - /*! A nop function, provided for backwards compatibility reasons. Does nothing. Only `duckdb_appender_end_row` is required. */ @@ -3931,20 +3591,6 @@ Append a DEFAULT value (NULL if DEFAULT not available for column) to the appende */ DUCKDB_API duckdb_state duckdb_append_default(duckdb_appender appender); -/*! -Append a DEFAULT value, at the specified row and column, (NULL if DEFAULT not available for column) to the chunk created -from the specified appender. The default value of the column must be a constant value. Non-deterministic expressions -like nextval('seq') or random() are not supported. - -* @param appender The appender to get the default value from. -* @param chunk The data chunk to append the default value to. -* @param col The chunk column index to append the default value to. -* @param row The chunk row index to append the default value to. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_append_default_to_chunk(duckdb_appender appender, duckdb_data_chunk chunk, idx_t col, - idx_t row); - /*! Append a bool value to the appender. */ @@ -4050,18 +3696,16 @@ Append a NULL value to the appender (of any type). */ DUCKDB_API duckdb_state duckdb_append_null(duckdb_appender appender); -/*! -Append a duckdb_value to the appender. -*/ -DUCKDB_API duckdb_state duckdb_append_value(duckdb_appender appender, duckdb_value value); - /*! Appends a pre-filled data chunk to the specified appender. - Attempts casting, if the data chunk types do not match the active appender types. + +The types of the data chunk must exactly match the types of the table, no casting is performed. +If the types do not match or the appender is in an invalid state, DuckDBError is returned. +If the append is successful, DuckDBSuccess is returned. * @param appender The appender to append to. * @param chunk The data chunk to append. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. +* @return The return state. */ DUCKDB_API duckdb_state duckdb_append_data_chunk(duckdb_appender appender, duckdb_data_chunk chunk); @@ -4082,21 +3726,6 @@ resulting table_description, even if the function returns `DuckDBError`. DUCKDB_API duckdb_state duckdb_table_description_create(duckdb_connection connection, const char *schema, const char *table, duckdb_table_description *out); -/*! -Creates a table description object. Note that `duckdb_table_description_destroy` must be called on the resulting -table_description, even if the function returns `DuckDBError`. - -* @param connection The connection context. -* @param catalog The catalog (database) name of the table, or `nullptr` for the default catalog. -* @param schema The schema of the table, or `nullptr` for the default schema. -* @param table The table name. -* @param out The resulting table description object. -* @return `DuckDBSuccess` on success or `DuckDBError` on failure. -*/ -DUCKDB_API duckdb_state duckdb_table_description_create_ext(duckdb_connection connection, const char *catalog, - const char *schema, const char *table, - duckdb_table_description *out); - /*! Destroy the TableDescription object. @@ -4124,16 +3753,6 @@ Check if the column at 'index' index of the table has a DEFAULT expression. */ DUCKDB_API duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out); -/*! -Obtain the column name at 'index'. -The out result must be destroyed with `duckdb_free`. - -* @param table_description The table_description to query. -* @param index The index of the column to query. -* @return The column name. -*/ -DUCKDB_API char *duckdb_table_description_get_column_name(duckdb_table_description table_description, idx_t index); - //===--------------------------------------------------------------------===// // Arrow Interface //===--------------------------------------------------------------------===// @@ -4538,8 +4157,6 @@ Destroys the cast function object. */ DUCKDB_API void duckdb_destroy_cast_function(duckdb_cast_function *cast_function); -#endif - #ifdef __cplusplus } #endif diff --git a/src/duckdb/src/include/duckdb/catalog/catalog.hpp b/src/duckdb/src/include/duckdb/catalog/catalog.hpp index dbef14ee5..278866020 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog.hpp @@ -9,18 +9,17 @@ #pragma once #include "duckdb/catalog/catalog_entry.hpp" +#include "duckdb/common/mutex.hpp" +#include "duckdb/parser/query_error_context.hpp" #include "duckdb/catalog/catalog_transaction.hpp" +#include "duckdb/common/reference_map.hpp" #include "duckdb/common/atomic.hpp" -#include "duckdb/common/enums/catalog_lookup_behavior.hpp" +#include "duckdb/common/map.hpp" +#include "duckdb/common/optional_ptr.hpp" #include "duckdb/common/enums/on_entry_not_found.hpp" #include "duckdb/common/error_data.hpp" #include "duckdb/common/exception/catalog_exception.hpp" -#include "duckdb/common/map.hpp" -#include "duckdb/common/mutex.hpp" -#include "duckdb/common/optional_ptr.hpp" -#include "duckdb/common/reference_map.hpp" -#include "duckdb/parser/query_error_context.hpp" - +#include "duckdb/common/enums/catalog_lookup_behavior.hpp" #include namespace duckdb { @@ -71,18 +70,6 @@ class LogicalInsert; class LogicalDelete; class LogicalUpdate; class CreateStatement; -class CatalogEntryRetriever; - -//! Return value of Catalog::LookupEntry -struct CatalogEntryLookup { - optional_ptr schema; - optional_ptr entry; - ErrorData error; - - DUCKDB_API bool Found() const { - return entry; - } -}; //! The Catalog object represents the catalog of the database. class Catalog { @@ -97,15 +84,10 @@ class Catalog { DUCKDB_API static Catalog &GetSystemCatalog(DatabaseInstance &db); //! Get the specified Catalog from the ClientContext DUCKDB_API static Catalog &GetCatalog(ClientContext &context, const string &catalog_name); - //! Get the specified Catalog from the ClientContext - DUCKDB_API static Catalog &GetCatalog(CatalogEntryRetriever &retriever, const string &catalog_name); //! Get the specified Catalog from the DatabaseInstance DUCKDB_API static Catalog &GetCatalog(DatabaseInstance &db, const string &catalog_name); //! Gets the specified Catalog from the database if it exists DUCKDB_API static optional_ptr GetCatalogEntry(ClientContext &context, const string &catalog_name); - //! Gets the specified Catalog from the database if it exists - DUCKDB_API static optional_ptr GetCatalogEntry(CatalogEntryRetriever &retriever, - const string &catalog_name); //! Get the specific Catalog from the AttachedDatabase DUCKDB_API static Catalog &GetCatalog(AttachedDatabase &db); @@ -232,10 +214,6 @@ class Catalog { const string &schema_name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - DUCKDB_API static optional_ptr GetSchema(CatalogEntryRetriever &retriever, - const string &catalog_name, const string &schema_name, - OnEntryNotFound if_not_found, - QueryErrorContext error_context = QueryErrorContext()); //! Scans all the schemas in the system one-by-one, invoking the callback for each entry DUCKDB_API virtual void ScanSchemas(ClientContext &context, std::function callback) = 0; @@ -243,10 +221,6 @@ class Catalog { DUCKDB_API optional_ptr GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - DUCKDB_API optional_ptr GetEntry(CatalogEntryRetriever &retriever, CatalogType type, - const string &schema, const string &name, - OnEntryNotFound if_not_found, - QueryErrorContext error_context = QueryErrorContext()); DUCKDB_API CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, QueryErrorContext error_context = QueryErrorContext()); //! Gets the "catalog.schema.name" entry of the specified type, if entry does not exist behavior depends on @@ -255,10 +229,6 @@ class Catalog { const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - DUCKDB_API static optional_ptr GetEntry(CatalogEntryRetriever &retriever, CatalogType type, - const string &catalog, const string &schema, - const string &name, OnEntryNotFound if_not_found, - QueryErrorContext error_context = QueryErrorContext()); DUCKDB_API static CatalogEntry &GetEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, QueryErrorContext error_context = QueryErrorContext()); @@ -299,10 +269,6 @@ class Catalog { unique_ptr plan) = 0; virtual unique_ptr BindCreateIndex(Binder &binder, CreateStatement &stmt, TableCatalogEntry &table, unique_ptr plan) = 0; - virtual unique_ptr BindAlterAddIndex(Binder &binder, TableCatalogEntry &table_entry, - unique_ptr plan, - unique_ptr create_info, - unique_ptr alter_info); virtual DatabaseSize GetDatabaseSize(ClientContext &context) = 0; virtual vector GetMetadataInfo(ClientContext &context); @@ -315,15 +281,6 @@ class Catalog { return CatalogLookupBehavior::STANDARD; } - //! The default table is used for `SELECT * FROM ;` - DUCKDB_API bool HasDefaultTable() const; - DUCKDB_API void SetDefaultTable(const string &schema, const string &name); - DUCKDB_API string GetDefaultTable() const; - DUCKDB_API string GetDefaultTableSchema() const; - - //! Returns the dependency manager of this catalog - if the catalog has anye - virtual optional_ptr GetDependencyManager(); - public: template static optional_ptr GetEntry(ClientContext &context, const string &catalog_name, const string &schema_name, @@ -349,8 +306,6 @@ class Catalog { DUCKDB_API vector> GetSchemas(ClientContext &context); DUCKDB_API static vector> GetSchemas(ClientContext &context, const string &catalog_name); - DUCKDB_API static vector> GetSchemas(CatalogEntryRetriever &retriever, - const string &catalog_name); DUCKDB_API static vector> GetAllSchemas(ClientContext &context); virtual void Verify(); @@ -367,47 +322,35 @@ class Catalog { //! Reference to the database AttachedDatabase &db; - //! (optionally) a default table to query for `SELECT * FROM ;` - string default_table; - string default_table_schema; - public: - //! Lookup an entry using TryLookupEntry, throws if entry not found and if_not_found == THROW_EXCEPTION - CatalogEntryLookup LookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, - const string &name, OnEntryNotFound if_not_found, - QueryErrorContext error_context = QueryErrorContext()); - private: //! Lookup an entry in the schema, returning a lookup with the entry and schema if they exist CatalogEntryLookup TryLookupEntryInternal(CatalogTransaction transaction, CatalogType type, const string &schema, const string &name); //! Calls LookupEntryInternal on the schema, trying other schemas if the schema is invalid. Sets //! CatalogEntryLookup->error depending on if_not_found when no entry is found - CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &schema, + CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - static CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, vector &lookups, - CatalogType type, const string &name, OnEntryNotFound if_not_found, + //! Lookup an entry using TryLookupEntry, throws if entry not found and if_not_found == THROW_EXCEPTION + CatalogEntryLookup LookupEntry(ClientContext &context, CatalogType type, const string &schema, const string &name, + OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); + static CatalogEntryLookup TryLookupEntry(ClientContext &context, vector &lookups, CatalogType type, + const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context = QueryErrorContext()); - static CatalogEntryLookup TryLookupEntry(CatalogEntryRetriever &retriever, CatalogType type, const string &catalog, + static CatalogEntryLookup TryLookupEntry(ClientContext &context, CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound if_not_found, QueryErrorContext error_context); - //! Looks for a Catalog with a DefaultTable that matches the lookup - static CatalogEntryLookup TryLookupDefaultTable(CatalogEntryRetriever &retriever, CatalogType type, - const string &catalog, const string &schema, const string &name, - OnEntryNotFound if_not_found, QueryErrorContext error_context); - //! Return an exception with did-you-mean suggestion. - static CatalogException CreateMissingEntryException(CatalogEntryRetriever &retriever, const string &entry_name, + static CatalogException CreateMissingEntryException(ClientContext &context, const string &entry_name, CatalogType type, const reference_set_t &schemas, QueryErrorContext error_context); //! Return the close entry name, the distance and the belonging schema. - static vector SimilarEntriesInSchemas(ClientContext &context, const string &entry_name, - CatalogType type, - const reference_set_t &schemas); + static SimilarCatalogEntry SimilarEntryInSchemas(ClientContext &context, const string &entry_name, CatalogType type, + const reference_set_t &schemas); virtual void DropSchema(ClientContext &context, DropInfo &info) = 0; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp index 88c9706a1..33802d1d9 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry.hpp @@ -18,16 +18,15 @@ #include namespace duckdb { - +struct AlterInfo; class Catalog; class CatalogSet; class ClientContext; -class Deserializer; class SchemaCatalogEntry; class Serializer; +class Deserializer; class Value; -struct AlterInfo; struct CatalogTransaction; struct CreateInfo; @@ -69,7 +68,6 @@ class CatalogEntry { virtual unique_ptr AlterEntry(ClientContext &context, AlterInfo &info); virtual unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info); virtual void UndoAlter(ClientContext &context, AlterInfo &info); - virtual void Rollback(CatalogEntry &prev_entry); virtual unique_ptr Copy(ClientContext &context) const; @@ -99,7 +97,6 @@ class CatalogEntry { bool HasParent() const; CatalogEntry &Child(); CatalogEntry &Parent(); - const CatalogEntry &Parent() const; public: template diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp index bb3ecd596..541963429 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp @@ -16,6 +16,7 @@ class TableCatalogEntry; //! Wrapper class to allow copying a DuckIndexEntry (for altering the DuckIndexEntry metadata such as comments) struct IndexDataTableInfo { IndexDataTableInfo(shared_ptr info_p, const string &index_name_p); + ~IndexDataTableInfo(); //! Pointer to the DataTableInfo shared_ptr info; @@ -33,7 +34,6 @@ class DuckIndexEntry : public IndexCatalogEntry { shared_ptr storage_info); unique_ptr Copy(ClientContext &context) const override; - void Rollback(CatalogEntry &prev_entry) override; //! The indexed table information shared_ptr info; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp index 188424015..54ba310a8 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_schema_entry.hpp @@ -62,8 +62,6 @@ class DuckSchemaEntry : public SchemaCatalogEntry { void Scan(CatalogType type, const std::function &callback) override; void DropEntry(ClientContext &context, DropInfo &info) override; optional_ptr GetEntry(CatalogTransaction transaction, CatalogType type, const string &name) override; - CatalogSet::EntryLookup GetEntryDetailed(CatalogTransaction transaction, CatalogType type, - const string &name) override; SimilarCatalogEntry GetSimilarEntry(CatalogTransaction transaction, CatalogType type, const string &name) override; unique_ptr Copy(ClientContext &context) const override; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp index fb9d5ae67..c728b2954 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_table_entry.hpp @@ -9,13 +9,9 @@ #pragma once #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" -#include "duckdb/planner/constraints/bound_unique_constraint.hpp" namespace duckdb { -struct AddConstraintInfo; - //! A table catalog entry class DuckTableEntry : public TableCatalogEntry { public: @@ -27,16 +23,12 @@ class DuckTableEntry : public TableCatalogEntry { unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; unique_ptr AlterEntry(CatalogTransaction, AlterInfo &info) override; void UndoAlter(ClientContext &context, AlterInfo &info) override; - void Rollback(CatalogEntry &prev_entry) override; - //! Returns the underlying storage of the table DataTable &GetStorage() override; //! Get statistics of a column (physical or virtual) within the table unique_ptr GetStatistics(ClientContext &context, column_t column_id) override; - unique_ptr GetSample() override; - unique_ptr Copy(ClientContext &context) const override; void SetAsRoot() override; @@ -65,7 +57,6 @@ class DuckTableEntry : public TableCatalogEntry { unique_ptr AddForeignKeyConstraint(optional_ptr context, AlterForeignKeyInfo &info); unique_ptr DropForeignKeyConstraint(ClientContext &context, AlterForeignKeyInfo &info); unique_ptr SetColumnComment(ClientContext &context, SetColumnCommentInfo &info); - unique_ptr AddConstraint(ClientContext &context, AddConstraintInfo &info); void UpdateConstraintsOnColumnDrop(const LogicalIndex &removed_index, const vector &adjusted_indices, const RemoveColumnInfo &info, CreateTableInfo &create_info, diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp index 955e5cd87..788c6561f 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/function_entry.hpp @@ -13,16 +13,22 @@ namespace duckdb { -//! A function in the catalog +//! An aggregate function in the catalog class FunctionEntry : public StandardEntry { public: FunctionEntry(CatalogType type, Catalog &catalog, SchemaCatalogEntry &schema, CreateFunctionInfo &info) : StandardEntry(type, schema, catalog, info.name) { - descriptions = std::move(info.descriptions); + description = std::move(info.description); + parameter_names = std::move(info.parameter_names); + example = std::move(info.example); this->dependencies = info.dependencies; - this->internal = info.internal; } - vector descriptions; + //! The description (if any) + string description; + //! Parameter names (if any) + vector parameter_names; + //! The example (if any) + string example; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp index 0deb03fd3..5a6e57316 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/pragma_function_catalog_entry.hpp @@ -17,7 +17,7 @@ namespace duckdb { class Catalog; struct CreatePragmaFunctionInfo; -//! A pragma function in the catalog +//! A table function in the catalog class PragmaFunctionCatalogEntry : public FunctionEntry { public: static constexpr const CatalogType Type = CatalogType::PRAGMA_FUNCTION_ENTRY; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp index 2055a5a76..a4440a862 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp @@ -15,7 +15,7 @@ namespace duckdb { -//! A scalar function in the catalog +//! A table function in the catalog class ScalarFunctionCatalogEntry : public FunctionEntry { public: static constexpr const CatalogType Type = CatalogType::SCALAR_FUNCTION_ENTRY; @@ -28,6 +28,6 @@ class ScalarFunctionCatalogEntry : public FunctionEntry { ScalarFunctionSet functions; public: - unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info) override; + unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp index a82ea56cd..a6f7d728a 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/schema_catalog_entry.hpp @@ -85,8 +85,6 @@ class SchemaCatalogEntry : public InCatalogEntry { DUCKDB_API virtual optional_ptr GetEntry(CatalogTransaction transaction, CatalogType type, const string &name) = 0; - DUCKDB_API virtual CatalogSet::EntryLookup GetEntryDetailed(CatalogTransaction transaction, CatalogType type, - const string &name); DUCKDB_API virtual SimilarCatalogEntry GetSimilarEntry(CatalogTransaction transaction, CatalogType type, const string &name); diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp index 398e49974..0dd78f3cc 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_catalog_entry.hpp @@ -13,7 +13,6 @@ #include "duckdb/parser/column_list.hpp" #include "duckdb/parser/constraint.hpp" #include "duckdb/planner/bound_constraint.hpp" -#include "duckdb/storage/table/table_statistics.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/catalog/catalog_entry/table_column_type.hpp" @@ -22,6 +21,8 @@ namespace duckdb { class DataTable; +struct CreateTableInfo; +struct BoundCreateTableInfo; struct RenameColumnInfo; struct AddColumnInfo; @@ -32,13 +33,12 @@ struct AlterForeignKeyInfo; struct SetNotNullInfo; struct DropNotNullInfo; struct SetColumnCommentInfo; -struct CreateTableInfo; -struct BoundCreateTableInfo; class TableFunction; struct FunctionData; class Binder; +class TableColumnInfo; struct ColumnSegmentInfo; class TableStorageInfo; @@ -83,8 +83,6 @@ class TableCatalogEntry : public StandardEntry { //! Get statistics of a column (physical or virtual) within the table virtual unique_ptr GetStatistics(ClientContext &context, column_t column_id) = 0; - virtual unique_ptr GetSample(); - //! Returns the column index of the specified column name. //! If the column does not exist: //! If if_column_exists is true, returns DConstants::INVALID_INDEX @@ -100,9 +98,6 @@ class TableCatalogEntry : public StandardEntry { DUCKDB_API static string ColumnsToSQL(const ColumnList &columns, const vector> &constraints); - //! Returns the expression string list of the column names e.g. (col1, col2, col3) - static string ColumnNamesToSQL(const ColumnList &columns); - //! Returns a list of segment information for this table, if exists virtual vector GetColumnSegmentInfo(); @@ -112,16 +107,6 @@ class TableCatalogEntry : public StandardEntry { virtual void BindUpdateConstraints(Binder &binder, LogicalGet &get, LogicalProjection &proj, LogicalUpdate &update, ClientContext &context); - //! Returns a pointer to the table's primary key, if exists, else nullptr. - optional_ptr GetPrimaryKey() const; - //! Returns true, if the table has a primary key, else false. - bool HasPrimaryKey() const; - - //! Returns the rowid type of this table - virtual LogicalType GetRowIdType() const { - return LogicalType::ROW_TYPE; - } - protected: //! A list of columns that are part of this table ColumnList columns; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp index a2e275700..fc784e554 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp @@ -28,6 +28,6 @@ class TableFunctionCatalogEntry : public FunctionEntry { TableFunctionSet functions; public: - unique_ptr AlterEntry(CatalogTransaction transaction, AlterInfo &info) override; + unique_ptr AlterEntry(ClientContext &context, AlterInfo &info) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp index 3b479541b..064ba4c08 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry/type_catalog_entry.hpp @@ -11,7 +11,6 @@ #include "duckdb/catalog/standard_entry.hpp" #include "duckdb/common/mutex.hpp" #include "duckdb/parser/parsed_data/create_type_info.hpp" -#include "duckdb/catalog/dependency_list.hpp" namespace duckdb { @@ -27,7 +26,7 @@ class TypeCatalogEntry : public StandardEntry { LogicalType user_type; - bind_logical_type_function_t bind_function; + bind_type_modifiers_function_t bind_modifiers; public: unique_ptr GetInfo() const override; diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp index 4e771cdc5..14466cb37 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_entry_retriever.hpp @@ -1,11 +1,3 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/catalog/catalog_entry_retriever.hpp -// -// -//===----------------------------------------------------------------------===// - #pragma once #include @@ -14,7 +6,6 @@ #include "duckdb/common/string.hpp" #include "duckdb/parser/query_error_context.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" -#include "duckdb/catalog/catalog_search_path.hpp" namespace duckdb { @@ -33,11 +24,6 @@ class CatalogEntryRetriever { } public: - void Inherit(const CatalogEntryRetriever &parent); - ClientContext &GetContext() { - return context; - } - optional_ptr GetEntry(CatalogType type, const string &catalog, const string &schema, const string &name, OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION, @@ -56,20 +42,31 @@ class CatalogEntryRetriever { OnEntryNotFound on_entry_not_found = OnEntryNotFound::THROW_EXCEPTION, QueryErrorContext error_context = QueryErrorContext()); - CatalogSearchPath &GetSearchPath(); - void SetSearchPath(vector entries); - - void SetCallback(catalog_entry_callback_t callback); - catalog_entry_callback_t GetCallback(); + void SetCallback(catalog_entry_callback_t callback) { + this->callback = std::move(callback); + } + catalog_entry_callback_t GetCallback() { + return callback; + } private: - optional_ptr ReturnAndCallback(optional_ptr result); + using catalog_entry_retrieve_func_t = std::function()>; + optional_ptr GetEntryInternal(const catalog_entry_retrieve_func_t &retriever) { + auto result = retriever(); + if (!result) { + return result; + } + if (callback) { + // Call the callback if it's set + callback(*result); + } + return result; + } private: //! (optional) callback, called on every successful entry retrieval catalog_entry_callback_t callback = nullptr; ClientContext &context; - shared_ptr search_path; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp index ff0def0fc..479d6c529 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_search_path.hpp @@ -41,7 +41,6 @@ enum class CatalogSetPathType { SET_SCHEMA, SET_SCHEMAS }; class CatalogSearchPath { public: DUCKDB_API explicit CatalogSearchPath(ClientContext &client_p); - DUCKDB_API CatalogSearchPath(ClientContext &client_p, vector entries); CatalogSearchPath(const CatalogSearchPath &other) = delete; DUCKDB_API void Set(CatalogSearchEntry new_value, CatalogSetPathType set_type); @@ -62,8 +61,8 @@ class CatalogSearchPath { DUCKDB_API bool SchemaInSearchPath(ClientContext &context, const string &catalog_name, const string &schema_name); private: - //! Set paths without checking if they exist - void SetPathsInternal(vector new_paths); + void SetPaths(vector new_paths); + string GetSetName(CatalogSetPathType set_type); private: diff --git a/src/duckdb/src/include/duckdb/catalog/catalog_set.hpp b/src/duckdb/src/include/duckdb/catalog/catalog_set.hpp index 27364e773..aaef6af93 100644 --- a/src/duckdb/src/include/duckdb/catalog/catalog_set.hpp +++ b/src/duckdb/src/include/duckdb/catalog/catalog_set.hpp @@ -53,7 +53,7 @@ class CatalogEntryMap { class CatalogSet { public: struct EntryLookup { - enum class FailureReason { SUCCESS, DELETED, NOT_PRESENT, INVISIBLE }; + enum class FailureReason { SUCCESS, DELETED, NOT_PRESENT }; optional_ptr result; FailureReason reason; }; @@ -75,10 +75,6 @@ class CatalogSet { bool allow_drop_internal = false); DUCKDB_API bool DropEntry(ClientContext &context, const string &name, bool cascade, bool allow_drop_internal = false); - //! Verify that the entry referenced by the dependency is still alive - DUCKDB_API void VerifyExistenceOfDependency(transaction_t commit_id, CatalogEntry &entry); - //! Verify we can still drop the entry while committing - DUCKDB_API void CommitDrop(transaction_t commit_id, transaction_t start_time, CatalogEntry &entry); DUCKDB_API DuckCatalog &GetCatalog(); @@ -118,9 +114,8 @@ class CatalogSet { DUCKDB_API bool CommittedAfterStarting(CatalogTransaction transaction, transaction_t timestamp); DUCKDB_API bool HasConflict(CatalogTransaction transaction, transaction_t timestamp); DUCKDB_API bool UseTimestamp(CatalogTransaction transaction, transaction_t timestamp); - static bool IsCommitted(transaction_t timestamp); - static void UpdateTimestamp(CatalogEntry &entry, transaction_t timestamp); + void UpdateTimestamp(CatalogEntry &entry, transaction_t timestamp); mutex &GetCatalogLock() { return catalog_lock; @@ -131,9 +126,6 @@ class CatalogSet { private: bool DropDependencies(CatalogTransaction transaction, const string &name, bool cascade, bool allow_drop_internal = false); - //! Given a root entry, gets the entry valid for this transaction, 'visible' is used to indicate whether the entry - //! is actually visible to the transaction - CatalogEntry &GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry ¤t, bool &visible); //! Given a root entry, gets the entry valid for this transaction CatalogEntry &GetEntryForTransaction(CatalogTransaction transaction, CatalogEntry ¤t); CatalogEntry &GetCommittedEntry(CatalogEntry ¤t); diff --git a/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp b/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp index 804d2e7cf..9b191036f 100644 --- a/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp +++ b/src/duckdb/src/include/duckdb/catalog/dependency_manager.hpp @@ -91,10 +91,6 @@ class DependencyManager { void AddOwnership(CatalogTransaction transaction, CatalogEntry &owner, CatalogEntry &entry); - //! Get the order of entries needed by EXPORT, the objects with no dependencies are exported first - void ReorderEntries(catalog_entry_vector_t &entries); - void ReorderEntries(catalog_entry_vector_t &entries, ClientContext &context); - private: DuckCatalog &catalog; CatalogSet subjects; @@ -114,14 +110,7 @@ class DependencyManager { static CatalogEntryInfo GetLookupProperties(const CatalogEntry &entry); private: - void ReorderEntry(CatalogTransaction transaction, CatalogEntry &entry, catalog_entry_set_t &visited, - catalog_entry_vector_t &order); - void ReorderEntries(catalog_entry_vector_t &entries, CatalogTransaction transaction); void AddObject(CatalogTransaction transaction, CatalogEntry &object, const LogicalDependencyList &dependencies); - void VerifyExistence(CatalogTransaction transaction, DependencyEntry &object); - void VerifyCommitDrop(CatalogTransaction transaction, transaction_t start_time, CatalogEntry &object); - //! Returns the objects that should be dropped alongside the object - catalog_entry_set_t CheckDropDependencies(CatalogTransaction transaction, CatalogEntry &object, bool cascade); void DropObject(CatalogTransaction transaction, CatalogEntry &object, bool cascade); void AlterObject(CatalogTransaction transaction, CatalogEntry &old_obj, CatalogEntry &new_obj, AlterInfo &info); diff --git a/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp b/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp index 54bcb40d6..830bd38e7 100644 --- a/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp +++ b/src/duckdb/src/include/duckdb/catalog/duck_catalog.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/catalog/duck_catalog.hpp +// duckdb/catalog/dcatalog.hpp // // //===----------------------------------------------------------------------===// @@ -25,6 +25,9 @@ class DuckCatalog : public Catalog { return "duckdb"; } + DependencyManager &GetDependencyManager() { + return *dependency_manager; + } mutex &GetWriteLock() { return write_lock; } @@ -49,12 +52,6 @@ class DuckCatalog : public Catalog { DUCKDB_API unique_ptr BindCreateIndex(Binder &binder, CreateStatement &stmt, TableCatalogEntry &table, unique_ptr plan) override; - DUCKDB_API unique_ptr BindAlterAddIndex(Binder &binder, TableCatalogEntry &table_entry, - unique_ptr plan, - unique_ptr create_info, - unique_ptr alter_info) override; - - CatalogSet &GetSchemaCatalogSet(); DatabaseSize GetDatabaseSize(ClientContext &context) override; vector GetMetadataInfo(ClientContext &context) override; @@ -64,8 +61,6 @@ class DuckCatalog : public Catalog { DUCKDB_API optional_idx GetCatalogVersion(ClientContext &context) override; - optional_ptr GetDependencyManager() override; - private: DUCKDB_API void DropSchema(CatalogTransaction transaction, DropInfo &info); DUCKDB_API void DropSchema(ClientContext &context, DropInfo &info) override; diff --git a/src/duckdb/src/include/duckdb/common/allocator.hpp b/src/duckdb/src/include/duckdb/common/allocator.hpp index cd058645f..f4550ef61 100644 --- a/src/duckdb/src/include/duckdb/common/allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/allocator.hpp @@ -65,9 +65,6 @@ class AllocatedData { data_ptr_t get() { // NOLINT: matching std style return pointer; } - operator bool() const { // NOLINT: missing explicit - return pointer != nullptr; - } const_data_ptr_t get() const { // NOLINT: matching std style return pointer; } diff --git a/src/duckdb/src/include/duckdb/common/array_ptr.hpp b/src/duckdb/src/include/duckdb/common/array_ptr.hpp index 6c268945c..5300a3490 100644 --- a/src/duckdb/src/include/duckdb/common/array_ptr.hpp +++ b/src/duckdb/src/include/duckdb/common/array_ptr.hpp @@ -1,11 +1,3 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/array_ptr.hpp -// -// -//===----------------------------------------------------------------------===// - #pragma once #include "duckdb/common/exception.hpp" diff --git a/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp b/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp index 5f0f86215..0c2a1de6c 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/appender/list_data.hpp @@ -1,7 +1,6 @@ #pragma once #include "duckdb/common/arrow/appender/append_data.hpp" -#include "duckdb/common/arrow/arrow_appender.hpp" namespace duckdb { @@ -75,8 +74,7 @@ struct ArrowListData { (uint64_t)last_offset + list_length > NumericLimits::Maximum()) { throw InvalidInputException( "Arrow Appender: The maximum combined list offset for regular list buffers is " - "%u but the offset of %lu exceeds this.\n* SET arrow_large_buffer_size=true to use large list " - "buffers", + "%u but the offset of %lu exceeds this.", NumericLimits::Maximum(), last_offset); } last_offset += list_length; diff --git a/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp b/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp index 158120c46..889e2614f 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/appender/list_view_data.hpp @@ -1,7 +1,6 @@ #pragma once #include "duckdb/common/arrow/appender/append_data.hpp" -#include "duckdb/common/arrow/arrow_appender.hpp" namespace duckdb { @@ -76,8 +75,7 @@ struct ArrowListViewData { (uint64_t)last_offset + list_length > NumericLimits::Maximum()) { throw InvalidInputException( "Arrow Appender: The maximum combined list offset for regular list buffers is " - "%u but the offset of %lu exceeds this.\n* SET arrow_large_buffer_size=true to use large list " - "buffers", + "%u but the offset of %lu exceeds this.", NumericLimits::Maximum(), last_offset); } offset_data[offset_idx] = last_offset; diff --git a/src/duckdb/src/include/duckdb/common/arrow/appender/varchar_data.hpp b/src/duckdb/src/include/duckdb/common/arrow/appender/varchar_data.hpp index 6dc37652d..12f68e431 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/appender/varchar_data.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/appender/varchar_data.hpp @@ -87,8 +87,7 @@ struct ArrowVarcharData { D_ASSERT(append_data.options.arrow_offset_size == ArrowOffsetSize::REGULAR); throw InvalidInputException( "Arrow Appender: The maximum total string size for regular string buffers is " - "%u but the offset of %lu exceeds this.\n* SET arrow_large_buffer_size=true to use large string " - "buffers", + "%u but the offset of %lu exceeds this.", NumericLimits::Maximum(), current_offset); } offset_data[offset_idx] = UnsafeNumericCast(current_offset); diff --git a/src/duckdb/src/include/duckdb/common/arrow/schema_metadata.hpp b/src/duckdb/src/include/duckdb/common/arrow/schema_metadata.hpp index 833d455a8..0a25a840f 100644 --- a/src/duckdb/src/include/duckdb/common/arrow/schema_metadata.hpp +++ b/src/duckdb/src/include/duckdb/common/arrow/schema_metadata.hpp @@ -21,31 +21,23 @@ class ArrowSchemaMetadata { ArrowSchemaMetadata() {}; //! Adds an option to the metadata void AddOption(const string &key, const string &value); - //! Gets an option from the metadata, returns an empty string if it does not exist. + //! Gets an option from the metadata, returns an empty string if does not exist. string GetOption(const string &key) const; //! Transforms metadata to a char*, used when creating an arrow object unsafe_unique_array SerializeMetadata() const; //! If the arrow extension is set - bool HasExtension() const; - //! If this extension type is an 'arrow.opaque', and the internal type and vendors match. - bool IsNonCanonicalType(const string &type, const string &vendor = "DuckDB") const; + bool HasExtension(); //! Get the extension name if set, otherwise returns empty string GetExtensionName() const; //! Key for encode of the extension type name static constexpr const char *ARROW_EXTENSION_NAME = "ARROW:extension:name"; //! Key for encode of the metadata key static constexpr const char *ARROW_METADATA_KEY = "ARROW:extension:metadata"; - //! Arrow Extension for non-canonical types. - static constexpr const char *ARROW_EXTENSION_NON_CANONICAL = "arrow.opaque"; //! Creates the metadata based on an extension name - static ArrowSchemaMetadata ArrowCanonicalType(const string &extension_name); - //! Creates the metadata based on an extension name - static ArrowSchemaMetadata DuckDBInternalType(const string &type_name); + static ArrowSchemaMetadata MetadataFromName(const string &extension_name); private: //! The unordered map that holds the metadata - unordered_map schema_metadata_map; - //! The extension metadata map, currently only used for internal types in arrow.opaque - unordered_map extension_metadata_map; + unordered_map metadata_map; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/assert.hpp b/src/duckdb/src/include/duckdb/common/assert.hpp index 916f5c1c7..62721f73f 100644 --- a/src/duckdb/src/include/duckdb/common/assert.hpp +++ b/src/duckdb/src/include/duckdb/common/assert.hpp @@ -10,19 +10,8 @@ #pragma once -// clang-format off -#if ( \ - /* Not a debug build */ \ - !defined(DEBUG) && \ - /* FORCE_ASSERT is not set (enables assertions even on release mode when set to true) */ \ - !defined(DUCKDB_FORCE_ASSERT) && \ - /* The project is not compiled for Microsoft Visual Studio */ \ - !defined(__MVS__) \ -) -// clang-format on +#if (defined(DUCKDB_USE_STANDARD_ASSERT) || !defined(DEBUG)) && !defined(DUCKDB_FORCE_ASSERT) && !defined(__MVS__) -//! On most builds, NDEBUG is defined, turning the assert call into a NO-OP -//! Only the 'else' condition is supposed to check the assertions #include #define D_ASSERT assert namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/common/atomic_ptr.hpp b/src/duckdb/src/include/duckdb/common/atomic_ptr.hpp deleted file mode 100644 index da2281d87..000000000 --- a/src/duckdb/src/include/duckdb/common/atomic_ptr.hpp +++ /dev/null @@ -1,102 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/atomic_ptr.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/exception.hpp" -#include "duckdb/common/atomic.hpp" -#include "duckdb/common/shared_ptr.hpp" -#include "duckdb/common/unique_ptr.hpp" - -namespace duckdb { - -template -class atomic_ptr { // NOLINT: mimic std casing -public: - atomic_ptr() noexcept : ptr(nullptr) { - } - atomic_ptr(T *ptr_p) : ptr(ptr_p) { // NOLINT: allow implicit creation from pointer - } - atomic_ptr(T &ref) : ptr(&ref) { // NOLINT: allow implicit creation from reference - } - atomic_ptr(const unique_ptr &ptr_p) : ptr(ptr_p.get()) { // NOLINT: allow implicit creation from unique pointer - } - atomic_ptr(const shared_ptr &ptr_p) : ptr(ptr_p.get()) { // NOLINT: allow implicit creation from shared pointer - } - - void CheckValid(const T *ptr) const { - if (MemorySafety::ENABLED) { - return; - } - if (!ptr) { - throw InternalException("Attempting to dereference an optional pointer that is not set"); - } - } - - T *GetPointer() { - auto res = ptr.load(); - CheckValid(res); - return res; - } - - const T *GetPointer() const { - auto res = ptr.load(); - CheckValid(res); - return res; - } - - operator bool() const { // NOLINT: allow implicit conversion to bool - return ptr; - } - T &operator*() { - return *GetPointer(); - } - const T &operator*() const { - return *GetPointer(); - } - T *operator->() { - return GetPointer(); - } - const T *operator->() const { - return GetPointer(); - } - T *get() { // NOLINT: mimic std casing - return GetPointer(); - } - const T *get() const { // NOLINT: mimic std casing - return GetPointer(); - } - // this looks dirty - but this is the default behavior of raw pointers - T *get_mutable() const { // NOLINT: mimic std casing - return GetPointer(); - } - - void set(T &ref) { - ptr = &ref; - } - - void reset() { - ptr = nullptr; - } - - bool operator==(const atomic_ptr &rhs) const { - return ptr.load() == rhs.ptr.load(); - } - - bool operator!=(const atomic_ptr &rhs) const { - return ptr.load() != rhs.ptr.load(); - } - -private: - atomic ptr; -}; - -template -using unsafe_atomic_ptr = atomic_ptr; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/box_renderer.hpp b/src/duckdb/src/include/duckdb/common/box_renderer.hpp index aaed6b8b3..fa9493ef4 100644 --- a/src/duckdb/src/include/duckdb/common/box_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/box_renderer.hpp @@ -20,51 +20,6 @@ class ColumnDataRowCollection; enum class ValueRenderAlignment { LEFT, MIDDLE, RIGHT }; enum class RenderMode : uint8_t { ROWS, COLUMNS }; -enum class ResultRenderType { LAYOUT, COLUMN_NAME, COLUMN_TYPE, VALUE, NULL_VALUE, FOOTER }; - -class BaseResultRenderer { -public: - BaseResultRenderer(); - virtual ~BaseResultRenderer(); - - virtual void RenderLayout(const string &text) = 0; - virtual void RenderColumnName(const string &text) = 0; - virtual void RenderType(const string &text) = 0; - virtual void RenderValue(const string &text, const LogicalType &type) = 0; - virtual void RenderNull(const string &text, const LogicalType &type) = 0; - virtual void RenderFooter(const string &text) = 0; - - BaseResultRenderer &operator<<(char c); - BaseResultRenderer &operator<<(const string &val); - - void Render(ResultRenderType render_mode, const string &val); - void SetValueType(const LogicalType &type); - -private: - LogicalType value_type; -}; - -class StringResultRenderer : public BaseResultRenderer { -public: - void RenderLayout(const string &text) override; - void RenderColumnName(const string &text) override; - void RenderType(const string &text) override; - void RenderValue(const string &text, const LogicalType &type) override; - void RenderNull(const string &text, const LogicalType &type) override; - void RenderFooter(const string &text) override; - - const string &str(); // NOLINT: mimic string stream - -private: - string result; -}; - -enum class LargeNumberRendering { - NONE = 0, // render all numbers as-is - FOOTER = 1, // if there is a single row, adds a second footer row with a readable summarization of large numbers - ALL = 2 // renders all large numbers -}; - struct BoxRendererConfig { // a max_width of 0 means we default to the terminal width idx_t max_width = 0; @@ -78,14 +33,8 @@ struct BoxRendererConfig { idx_t max_col_width = 20; //! how to render NULL values string null_value = "NULL"; - //! Decimal separator (if any) - char decimal_separator = '\0'; - //! Thousand separator (if any) - char thousand_separator = '\0'; //! Whether or not to render row-wise or column-wise RenderMode render_mode = RenderMode::ROWS; - //! How to render large numbers - LargeNumberRendering large_number_rendering = LargeNumberRendering::NONE; #ifndef DUCKDB_ASCII_TREE_RENDERER const char *LTCORNER = "\342\224\214"; // NOLINT: "┌"; @@ -136,8 +85,7 @@ class BoxRenderer { string ToString(ClientContext &context, const vector &names, const ColumnDataCollection &op); - void Render(ClientContext &context, const vector &names, const ColumnDataCollection &op, - BaseResultRenderer &ss); + void Render(ClientContext &context, const vector &names, const ColumnDataCollection &op, std::ostream &ss); void Print(ClientContext &context, const vector &names, const ColumnDataCollection &op); private: @@ -145,12 +93,11 @@ class BoxRenderer { BoxRendererConfig config; private: - void RenderValue(BaseResultRenderer &ss, const string &value, idx_t column_width, ResultRenderType render_mode, + void RenderValue(std::ostream &ss, const string &value, idx_t column_width, ValueRenderAlignment alignment = ValueRenderAlignment::MIDDLE); string RenderType(const LogicalType &type); ValueRenderAlignment TypeAlignment(const LogicalType &type); - string GetRenderValue(BaseResultRenderer &ss, ColumnDataRowCollection &rows, idx_t c, idx_t r, - const LogicalType &type, ResultRenderType &render_mode); + string GetRenderValue(ColumnDataRowCollection &rows, idx_t c, idx_t r); list FetchRenderCollections(ClientContext &context, const ColumnDataCollection &result, idx_t top_rows, idx_t bottom_rows); list PivotCollections(ClientContext &context, list input, @@ -161,19 +108,13 @@ class BoxRenderer { vector &column_map, idx_t &total_length); void RenderHeader(const vector &names, const vector &result_types, const vector &column_map, const vector &widths, const vector &boundaries, - idx_t total_length, bool has_results, BaseResultRenderer &renderer); + idx_t total_length, bool has_results, std::ostream &ss); void RenderValues(const list &collections, const vector &column_map, - const vector &widths, const vector &result_types, BaseResultRenderer &ss); + const vector &widths, const vector &result_types, std::ostream &ss); void RenderRowCount(string row_count_str, string shown_str, const string &column_count_str, const vector &boundaries, bool has_hidden_rows, bool has_hidden_columns, idx_t total_length, idx_t row_count, idx_t column_count, idx_t minimum_row_length, - BaseResultRenderer &ss); - - string FormatNumber(const string &input); - string ConvertRenderValue(const string &input, const LogicalType &type); - string ConvertRenderValue(const string &input); - //! Try to format a large number in a readable way (e.g. 1234567 -> 1.23 million) - string TryFormatLargeNumber(const string &numeric); + std::ostream &ss); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/chrono.hpp b/src/duckdb/src/include/duckdb/common/chrono.hpp index c46e27b15..797a867c5 100644 --- a/src/duckdb/src/include/duckdb/common/chrono.hpp +++ b/src/duckdb/src/include/duckdb/common/chrono.hpp @@ -15,7 +15,6 @@ using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::high_resolution_clock; using std::chrono::milliseconds; -using std::chrono::nanoseconds; using std::chrono::system_clock; using std::chrono::time_point; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/column_index.hpp b/src/duckdb/src/include/duckdb/common/column_index.hpp deleted file mode 100644 index 32d2e1828..000000000 --- a/src/duckdb/src/include/duckdb/common/column_index.hpp +++ /dev/null @@ -1,72 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/column_index.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/constants.hpp" -#include "duckdb/common/vector.hpp" - -namespace duckdb { - -struct ColumnIndex { - ColumnIndex() : index(DConstants::INVALID_INDEX) { - } - explicit ColumnIndex(idx_t index) : index(index) { - } - ColumnIndex(idx_t index, vector child_indexes_p) - : index(index), child_indexes(std::move(child_indexes_p)) { - } - - inline bool operator==(const ColumnIndex &rhs) const { - return index == rhs.index; - } - inline bool operator!=(const ColumnIndex &rhs) const { - return index != rhs.index; - } - inline bool operator<(const ColumnIndex &rhs) const { - return index < rhs.index; - } - idx_t GetPrimaryIndex() const { - return index; - } - LogicalIndex ToLogical() const { - return LogicalIndex(index); - } - bool HasChildren() const { - return !child_indexes.empty(); - } - idx_t ChildIndexCount() const { - return child_indexes.size(); - } - const ColumnIndex &GetChildIndex(idx_t idx) const { - return child_indexes[idx]; - } - ColumnIndex &GetChildIndex(idx_t idx) { - return child_indexes[idx]; - } - const vector &GetChildIndexes() const { - return child_indexes; - } - vector &GetChildIndexesMutable() { - return child_indexes; - } - void AddChildIndex(ColumnIndex new_index) { - this->child_indexes.push_back(std::move(new_index)); - } - bool IsRowIdColumn() const { - return index == DConstants::INVALID_INDEX; - } - void Serialize(Serializer &serializer) const; - static ColumnIndex Deserialize(Deserializer &deserializer); - -private: - idx_t index; - vector child_indexes; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enum_util.hpp b/src/duckdb/src/include/duckdb/common/enum_util.hpp index 852f43436..3e6a235aa 100644 --- a/src/duckdb/src/include/duckdb/common/enum_util.hpp +++ b/src/duckdb/src/include/duckdb/common/enum_util.hpp @@ -32,16 +32,10 @@ struct EnumUtil { static string ToString(T value) { return string(ToChars(value)); } }; -enum class ARTAppendMode : uint8_t; - -enum class ARTConflictType : uint8_t; - enum class AccessMode : uint8_t; enum class AggregateCombineType : uint8_t; -enum class AggregateDistinctDependent : uint8_t; - enum class AggregateHandling : uint8_t; enum class AggregateOrderDependent : uint8_t; @@ -102,8 +96,6 @@ enum class CompressedMaterializationDirection : uint8_t; enum class CompressionType : uint8_t; -enum class CompressionValidity : uint8_t; - enum class ConflictManagerMode : uint8_t; enum class ConstraintType : uint8_t; @@ -116,8 +108,6 @@ enum class CopyToType : uint8_t; enum class DataFileType : uint8_t; -enum class DateCastResult : uint8_t; - enum class DatePartSpecifier : uint8_t; enum class DebugInitialize : uint8_t; @@ -176,10 +166,6 @@ enum class FilterPropagateResult : uint8_t; enum class ForeignKeyType : uint8_t; -enum class FunctionCollationHandling : uint8_t; - -enum class FunctionErrors : uint8_t; - enum class FunctionNullHandling : uint8_t; enum class FunctionStability : uint8_t; @@ -286,8 +272,6 @@ enum class SampleMethod : uint8_t; enum class SampleType : uint8_t; -enum class SamplingState : uint8_t; - enum class ScanType : uint8_t; enum class SecretDisplayType : uint8_t; @@ -338,8 +322,6 @@ enum class TableColumnType : uint8_t; enum class TableFilterType : uint8_t; -enum class TablePartitionInfo : uint8_t; - enum class TableReferenceType : uint8_t; enum class TableScanType : uint8_t; @@ -348,10 +330,6 @@ enum class TaskExecutionMode : uint8_t; enum class TaskExecutionResult : uint8_t; -enum class TemporaryBufferSize : uint64_t; - -enum class TemporaryCompressionLevel : int; - enum class TimestampCastResult : uint8_t; enum class TransactionModifierType : uint8_t; @@ -383,21 +361,12 @@ enum class WindowBoundary : uint8_t; enum class WindowExcludeMode : uint8_t; -template<> -const char* EnumUtil::ToChars(ARTAppendMode value); - -template<> -const char* EnumUtil::ToChars(ARTConflictType value); - template<> const char* EnumUtil::ToChars(AccessMode value); template<> const char* EnumUtil::ToChars(AggregateCombineType value); -template<> -const char* EnumUtil::ToChars(AggregateDistinctDependent value); - template<> const char* EnumUtil::ToChars(AggregateHandling value); @@ -488,9 +457,6 @@ const char* EnumUtil::ToChars(CompressedMate template<> const char* EnumUtil::ToChars(CompressionType value); -template<> -const char* EnumUtil::ToChars(CompressionValidity value); - template<> const char* EnumUtil::ToChars(ConflictManagerMode value); @@ -509,9 +475,6 @@ const char* EnumUtil::ToChars(CopyToType value); template<> const char* EnumUtil::ToChars(DataFileType value); -template<> -const char* EnumUtil::ToChars(DateCastResult value); - template<> const char* EnumUtil::ToChars(DatePartSpecifier value); @@ -599,12 +562,6 @@ const char* EnumUtil::ToChars(FilterPropagateResult value template<> const char* EnumUtil::ToChars(ForeignKeyType value); -template<> -const char* EnumUtil::ToChars(FunctionCollationHandling value); - -template<> -const char* EnumUtil::ToChars(FunctionErrors value); - template<> const char* EnumUtil::ToChars(FunctionNullHandling value); @@ -764,9 +721,6 @@ const char* EnumUtil::ToChars(SampleMethod value); template<> const char* EnumUtil::ToChars(SampleType value); -template<> -const char* EnumUtil::ToChars(SamplingState value); - template<> const char* EnumUtil::ToChars(ScanType value); @@ -842,9 +796,6 @@ const char* EnumUtil::ToChars(TableColumnType value); template<> const char* EnumUtil::ToChars(TableFilterType value); -template<> -const char* EnumUtil::ToChars(TablePartitionInfo value); - template<> const char* EnumUtil::ToChars(TableReferenceType value); @@ -857,12 +808,6 @@ const char* EnumUtil::ToChars(TaskExecutionMode value); template<> const char* EnumUtil::ToChars(TaskExecutionResult value); -template<> -const char* EnumUtil::ToChars(TemporaryBufferSize value); - -template<> -const char* EnumUtil::ToChars(TemporaryCompressionLevel value); - template<> const char* EnumUtil::ToChars(TimestampCastResult value); @@ -909,21 +854,12 @@ template<> const char* EnumUtil::ToChars(WindowExcludeMode value); -template<> -ARTAppendMode EnumUtil::FromString(const char *value); - -template<> -ARTConflictType EnumUtil::FromString(const char *value); - template<> AccessMode EnumUtil::FromString(const char *value); template<> AggregateCombineType EnumUtil::FromString(const char *value); -template<> -AggregateDistinctDependent EnumUtil::FromString(const char *value); - template<> AggregateHandling EnumUtil::FromString(const char *value); @@ -1014,9 +950,6 @@ CompressedMaterializationDirection EnumUtil::FromString CompressionType EnumUtil::FromString(const char *value); -template<> -CompressionValidity EnumUtil::FromString(const char *value); - template<> ConflictManagerMode EnumUtil::FromString(const char *value); @@ -1035,9 +968,6 @@ CopyToType EnumUtil::FromString(const char *value); template<> DataFileType EnumUtil::FromString(const char *value); -template<> -DateCastResult EnumUtil::FromString(const char *value); - template<> DatePartSpecifier EnumUtil::FromString(const char *value); @@ -1125,12 +1055,6 @@ FilterPropagateResult EnumUtil::FromString(const char *va template<> ForeignKeyType EnumUtil::FromString(const char *value); -template<> -FunctionCollationHandling EnumUtil::FromString(const char *value); - -template<> -FunctionErrors EnumUtil::FromString(const char *value); - template<> FunctionNullHandling EnumUtil::FromString(const char *value); @@ -1290,9 +1214,6 @@ SampleMethod EnumUtil::FromString(const char *value); template<> SampleType EnumUtil::FromString(const char *value); -template<> -SamplingState EnumUtil::FromString(const char *value); - template<> ScanType EnumUtil::FromString(const char *value); @@ -1368,9 +1289,6 @@ TableColumnType EnumUtil::FromString(const char *value); template<> TableFilterType EnumUtil::FromString(const char *value); -template<> -TablePartitionInfo EnumUtil::FromString(const char *value); - template<> TableReferenceType EnumUtil::FromString(const char *value); @@ -1383,12 +1301,6 @@ TaskExecutionMode EnumUtil::FromString(const char *value); template<> TaskExecutionResult EnumUtil::FromString(const char *value); -template<> -TemporaryBufferSize EnumUtil::FromString(const char *value); - -template<> -TemporaryCompressionLevel EnumUtil::FromString(const char *value); - template<> TimestampCastResult EnumUtil::FromString(const char *value); diff --git a/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp b/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp index a8753f12b..19bfa4cc8 100644 --- a/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/compression_type.hpp @@ -16,7 +16,7 @@ namespace duckdb { enum class CompressionType : uint8_t { COMPRESSION_AUTO = 0, COMPRESSION_UNCOMPRESSED = 1, - COMPRESSION_CONSTANT = 2, // internal only + COMPRESSION_CONSTANT = 2, COMPRESSION_RLE = 3, COMPRESSION_DICTIONARY = 4, COMPRESSION_PFOR_DELTA = 5, @@ -26,10 +26,7 @@ enum class CompressionType : uint8_t { COMPRESSION_PATAS = 9, COMPRESSION_ALP = 10, COMPRESSION_ALPRD = 11, - COMPRESSION_ZSTD = 12, - COMPRESSION_ROARING = 13, - COMPRESSION_EMPTY = 14, // internal only - COMPRESSION_COUNT // This has to stay the last entry of the type! + COMPRESSION_COUNT // This has to stay the last entry of the type! }; bool CompressionTypeIsDeprecated(CompressionType compression_type); diff --git a/src/duckdb/src/include/duckdb/common/enums/function_errors.hpp b/src/duckdb/src/include/duckdb/common/enums/function_errors.hpp deleted file mode 100644 index 3d37c53e0..000000000 --- a/src/duckdb/src/include/duckdb/common/enums/function_errors.hpp +++ /dev/null @@ -1,18 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/enums/function_errors.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" - -namespace duckdb { - -//! Whether or not a function can throw an error or not -enum class FunctionErrors : uint8_t { CANNOT_ERROR = 0, CAN_THROW_RUNTIME_ERROR = 1 }; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp b/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp index e38a720e4..109332b17 100644 --- a/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/memory_tag.hpp @@ -24,10 +24,9 @@ enum class MemoryTag : uint8_t { OVERFLOW_STRINGS = 8, IN_MEMORY_TABLE = 9, ALLOCATOR = 10, - EXTENSION = 11, - TRANSACTION = 12 + EXTENSION = 11 }; -static constexpr const idx_t MEMORY_TAG_COUNT = 13; +static constexpr const idx_t MEMORY_TAG_COUNT = 12; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp b/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp index c133faada..6510abbea 100644 --- a/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/metric_type.hpp @@ -30,10 +30,9 @@ enum class MetricsType : uint8_t { CUMULATIVE_ROWS_SCANNED, OPERATOR_ROWS_SCANNED, OPERATOR_TIMING, + LATENCY, + ROWS_RETURNED, RESULT_SET_SIZE, - LATENCY, - ROWS_RETURNED, - OPERATOR_NAME, ALL_OPTIMIZERS, CUMULATIVE_OPTIMIZER_TIMING, PLANNER, @@ -45,7 +44,6 @@ enum class MetricsType : uint8_t { OPTIMIZER_EXPRESSION_REWRITER, OPTIMIZER_FILTER_PULLUP, OPTIMIZER_FILTER_PUSHDOWN, - OPTIMIZER_EMPTY_RESULT_PULLUP, OPTIMIZER_CTE_FILTER_PUSHER, OPTIMIZER_REGEX_RANGE, OPTIMIZER_IN_CLAUSE, @@ -63,11 +61,9 @@ enum class MetricsType : uint8_t { OPTIMIZER_COMPRESSED_MATERIALIZATION, OPTIMIZER_DUPLICATE_GROUPS, OPTIMIZER_REORDER_FILTER, - OPTIMIZER_SAMPLING_PUSHDOWN, OPTIMIZER_JOIN_FILTER_PUSHDOWN, OPTIMIZER_EXTENSION, OPTIMIZER_MATERIALIZED_CTE, - OPTIMIZER_SUM_REWRITER, }; struct MetricsTypeHashFunction { diff --git a/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp b/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp index cfb7acb6a..8eea1ca48 100644 --- a/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/optimizer_type.hpp @@ -18,7 +18,6 @@ enum class OptimizerType : uint32_t { EXPRESSION_REWRITER, FILTER_PULLUP, FILTER_PUSHDOWN, - EMPTY_RESULT_PULLUP, CTE_FILTER_PUSHER, REGEX_RANGE, IN_CLAUSE, @@ -36,11 +35,9 @@ enum class OptimizerType : uint32_t { COMPRESSED_MATERIALIZATION, DUPLICATE_GROUPS, REORDER_FILTER, - SAMPLING_PUSHDOWN, JOIN_FILTER_PUSHDOWN, EXTENSION, MATERIALIZED_CTE, - SUM_REWRITER }; string OptimizerTypeToString(OptimizerType type); diff --git a/src/duckdb/src/include/duckdb/common/enums/order_preservation_type.hpp b/src/duckdb/src/include/duckdb/common/enums/order_preservation_type.hpp index d28edb20e..ef590c03b 100644 --- a/src/duckdb/src/include/duckdb/common/enums/order_preservation_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/order_preservation_type.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/common/enums/order_preservation_type.hpp +// src/include/duckdb/common/enums/order_preservation_type.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp b/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp index 607588c11..4f170b497 100644 --- a/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/physical_operator_type.hpp @@ -27,7 +27,6 @@ enum class PhysicalOperatorType : uint8_t { UNGROUPED_AGGREGATE, HASH_GROUP_BY, PERFECT_HASH_GROUP_BY, - PARTITIONED_AGGREGATE, FILTER, PROJECTION, COPY_TO_FILE, diff --git a/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp b/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp index 1a416d546..25a7912fd 100644 --- a/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/profiler_format.hpp @@ -12,6 +12,6 @@ namespace duckdb { -enum class ProfilerPrintFormat : uint8_t { QUERY_TREE, JSON, QUERY_TREE_OPTIMIZER, NO_OUTPUT, HTML, GRAPHVIZ }; +enum class ProfilerPrintFormat : uint8_t { QUERY_TREE, JSON, QUERY_TREE_OPTIMIZER, NO_OUTPUT }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/enums/scan_vector_type.hpp b/src/duckdb/src/include/duckdb/common/enums/scan_vector_type.hpp index 73224f40f..dcdf6e90c 100644 --- a/src/duckdb/src/include/duckdb/common/enums/scan_vector_type.hpp +++ b/src/duckdb/src/include/duckdb/common/enums/scan_vector_type.hpp @@ -14,6 +14,4 @@ namespace duckdb { enum class ScanVectorType { SCAN_ENTIRE_VECTOR, SCAN_FLAT_VECTOR }; -enum class ScanVectorMode { REGULAR_SCAN, SCAN_COMMITTED, SCAN_COMMITTED_NO_UPDATES }; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/error_data.hpp b/src/duckdb/src/include/duckdb/common/error_data.hpp index 20b7541f6..93ff5ccbb 100644 --- a/src/duckdb/src/include/duckdb/common/error_data.hpp +++ b/src/duckdb/src/include/duckdb/common/error_data.hpp @@ -47,7 +47,6 @@ class ErrorData { return extra_info; } - DUCKDB_API void FinalizeError(); DUCKDB_API void AddErrorLocation(const string &query); DUCKDB_API void ConvertErrorToJSON(); diff --git a/src/duckdb/src/include/duckdb/common/exception.hpp b/src/duckdb/src/include/duckdb/common/exception.hpp index 71c4ff8b2..3bb605926 100644 --- a/src/duckdb/src/include/duckdb/common/exception.hpp +++ b/src/duckdb/src/include/duckdb/common/exception.hpp @@ -137,7 +137,7 @@ class Exception : public std::runtime_error { DUCKDB_API static bool UncaughtException(); - DUCKDB_API static string GetStackTrace(idx_t max_depth = 120); + DUCKDB_API static string GetStackTrace(int max_depth = 120); static string FormatStackTrace(const string &message = "") { return (message + "\n" + GetStackTrace()); } diff --git a/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp b/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp index 363a34457..5ae6a5e87 100644 --- a/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp +++ b/src/duckdb/src/include/duckdb/common/exception/parser_exception.hpp @@ -26,10 +26,6 @@ class ParserException : public Exception { explicit ParserException(optional_idx error_location, const string &msg, ARGS... params) : ParserException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(error_location)) { } - template - explicit ParserException(const ParsedExpression &expr, const string &msg, ARGS... params) - : ParserException(ConstructMessage(msg, params...), Exception::InitializeExtraInfo(expr)) { - } static ParserException SyntaxError(const string &query, const string &error_message, optional_idx error_location); }; diff --git a/src/duckdb/src/include/duckdb/common/extension_type_info.hpp b/src/duckdb/src/include/duckdb/common/extension_type_info.hpp deleted file mode 100644 index b8ee0f440..000000000 --- a/src/duckdb/src/include/duckdb/common/extension_type_info.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "duckdb/common/string.hpp" -#include "duckdb/common/types/value.hpp" - -namespace duckdb { - -class Serializer; -class Deserializer; - -struct LogicalTypeModifier { -public: - explicit LogicalTypeModifier(Value value_p) : value(std::move(value_p)) { - } - string ToString() const { - return label.empty() ? value.ToString() : label; - } - -public: - Value value; - string label; - - void Serialize(Serializer &serializer) const; - static LogicalTypeModifier Deserialize(Deserializer &source); -}; - -struct ExtensionTypeInfo { - vector modifiers; - unordered_map properties; - -public: - void Serialize(Serializer &serializer) const; - static unique_ptr Deserialize(Deserializer &source); - static bool Equals(optional_ptr rhs, optional_ptr lhs); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp b/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp index 117be6c61..ceb24638a 100644 --- a/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp +++ b/src/duckdb/src/include/duckdb/common/extra_operator_info.hpp @@ -12,17 +12,14 @@ #include #include #include "duckdb/common/operator/comparison_operators.hpp" -#include "duckdb/common/optional_idx.hpp" -#include "duckdb/parser/parsed_data/sample_options.hpp" namespace duckdb { class ExtraOperatorInfo { public: - ExtraOperatorInfo() : file_filters(""), sample_options(nullptr) { + ExtraOperatorInfo() : file_filters("") { } - ExtraOperatorInfo(ExtraOperatorInfo &extra_info) - : file_filters(extra_info.file_filters), sample_options(std::move(extra_info.sample_options)) { + ExtraOperatorInfo(ExtraOperatorInfo &extra_info) : file_filters(extra_info.file_filters) { if (extra_info.total_files.IsValid()) { total_files = extra_info.total_files.GetIndex(); } @@ -37,8 +34,6 @@ class ExtraOperatorInfo { optional_idx total_files; //! Size of file list after applying filters optional_idx filtered_files; - //! Sample options that have been pushed down into the table scan - unique_ptr sample_options; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/extra_type_info.hpp b/src/duckdb/src/include/duckdb/common/extra_type_info.hpp index 8e9afe0d2..7ed7197b5 100644 --- a/src/duckdb/src/include/duckdb/common/extra_type_info.hpp +++ b/src/duckdb/src/include/duckdb/common/extra_type_info.hpp @@ -10,7 +10,6 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/types/vector.hpp" -#include "duckdb/common/extension_type_info.hpp" namespace duckdb { @@ -31,18 +30,13 @@ enum class ExtraTypeInfoType : uint8_t { }; struct ExtraTypeInfo { - ExtraTypeInfoType type; - string alias; - unique_ptr extension_info; - explicit ExtraTypeInfo(ExtraTypeInfoType type); explicit ExtraTypeInfo(ExtraTypeInfoType type, string alias); virtual ~ExtraTypeInfo(); -protected: - // copy constructor (protected) - ExtraTypeInfo(const ExtraTypeInfo &other); - ExtraTypeInfo &operator=(const ExtraTypeInfo &other); + ExtraTypeInfoType type; + string alias; + vector modifiers; public: bool Equals(ExtraTypeInfo *other_p) const; diff --git a/src/duckdb/src/include/duckdb/common/fast_mem.hpp b/src/duckdb/src/include/duckdb/common/fast_mem.hpp index f18130862..dc2730f34 100644 --- a/src/duckdb/src/include/duckdb/common/fast_mem.hpp +++ b/src/duckdb/src/include/duckdb/common/fast_mem.hpp @@ -11,17 +11,17 @@ #include "duckdb/common/types.hpp" template -inline void MemcpyFixed(void *dest, const void *src) { +static inline void MemcpyFixed(void *dest, const void *src) { memcpy(dest, src, SIZE); } template -inline int MemcmpFixed(const void *str1, const void *str2) { +static inline int MemcmpFixed(const void *str1, const void *str2) { return memcmp(str1, str2, SIZE); } template -inline void MemsetFixed(void *ptr, int value) { +static inline void MemsetFixed(void *ptr, int value) { memset(ptr, value, SIZE); } @@ -30,7 +30,7 @@ namespace duckdb { //! This templated memcpy is significantly faster than std::memcpy, //! but only when you are calling memcpy with a const size in a loop. //! For instance `while () { memcpy(, , const_size); ... }` -inline void FastMemcpy(void *dest, const void *src, const size_t size) { +static inline void FastMemcpy(void *dest, const void *src, const size_t size) { // LCOV_EXCL_START switch (size) { case 0: @@ -556,7 +556,7 @@ inline void FastMemcpy(void *dest, const void *src, const size_t size) { //! This templated memcmp is significantly faster than std::memcmp, //! but only when you are calling memcmp with a const size in a loop. //! For instance `while () { memcmp(, , const_size); ... }` -inline int FastMemcmp(const void *str1, const void *str2, const size_t size) { +static inline int FastMemcmp(const void *str1, const void *str2, const size_t size) { // LCOV_EXCL_START switch (size) { case 0: @@ -695,7 +695,7 @@ inline int FastMemcmp(const void *str1, const void *str2, const size_t size) { // LCOV_EXCL_STOP } -inline void FastMemset(void *ptr, int value, size_t size) { +static inline void FastMemset(void *ptr, int value, size_t size) { // LCOV_EXCL_START switch (size) { case 0: diff --git a/src/duckdb/src/include/duckdb/common/file_buffer.hpp b/src/duckdb/src/include/duckdb/common/file_buffer.hpp index 8db3e0d0c..1a3e6e9cb 100644 --- a/src/duckdb/src/include/duckdb/common/file_buffer.hpp +++ b/src/duckdb/src/include/duckdb/common/file_buffer.hpp @@ -17,7 +17,7 @@ struct FileHandle; enum class FileBufferType : uint8_t { BLOCK = 1, MANAGED_BUFFER = 2, TINY_BUFFER = 3 }; -static constexpr idx_t FILE_BUFFER_TYPE_COUNT = 3; +static constexpr const idx_t FILE_BUFFER_TYPE_COUNT = 3; //! The FileBuffer represents a buffer that can be read or written to a Direct IO FileHandle. class FileBuffer { @@ -32,10 +32,11 @@ class FileBuffer { virtual ~FileBuffer(); Allocator &allocator; + //! The type of the buffer + FileBufferType type; //! The buffer that users can write to data_ptr_t buffer; - //! The user-facing size of the buffer. - //! This is equivalent to internal_size - BLOCK_HEADER_SIZE. + //! The size of the portion that users can write to, this is equivalent to internal_size - BLOCK_HEADER_SIZE uint64_t size; public: @@ -46,20 +47,13 @@ class FileBuffer { void Clear(); - FileBufferType GetBufferType() const { - return type; - } - - // Same rules as the constructor. We add room for a header, in addition to - // the requested user bytes. We then sector-align the result. + // Same rules as the constructor. We will add room for a header, in additio to + // the requested user bytes. We will then sector-align the result. void Resize(uint64_t user_size); uint64_t AllocSize() const { return internal_size; } - uint64_t Size() const { - return size; - } data_ptr_t InternalBuffer() { return internal_buffer; } @@ -70,19 +64,16 @@ class FileBuffer { }; MemoryRequirement CalculateMemory(uint64_t user_size); + void Initialize(DebugInitialize info); protected: - //! The type of the buffer. - FileBufferType type; - //! The pointer to the internal buffer that will be read from or written to. - //! This includes the buffer header. + //! The pointer to the internal buffer that will be read or written, including the buffer header data_ptr_t internal_buffer; - //! The aligned size as passed to the constructor. - //! This is the size that is read from or written to disk. + //! The aligned size as passed to the constructor. This is the size that is read or written to disk. uint64_t internal_size; - void ReallocBuffer(idx_t new_size); + void ReallocBuffer(size_t malloc_size); void Init(); }; diff --git a/src/duckdb/src/include/duckdb/common/file_system.hpp b/src/duckdb/src/include/duckdb/common/file_system.hpp index e3aac6e9b..0b83c4f39 100644 --- a/src/duckdb/src/include/duckdb/common/file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/file_system.hpp @@ -53,7 +53,7 @@ enum class FileType { struct FileHandle { public: - DUCKDB_API FileHandle(FileSystem &file_system, string path, FileOpenFlags flags); + DUCKDB_API FileHandle(FileSystem &file_system, string path); FileHandle(const FileHandle &) = delete; DUCKDB_API virtual ~FileHandle(); @@ -84,10 +84,6 @@ struct FileHandle { return path; } - FileOpenFlags GetFlags() const { - return flags; - } - template TARGET &Cast() { DynamicCastCheck(this); @@ -102,7 +98,6 @@ struct FileHandle { public: FileSystem &file_system; string path; - FileOpenFlags flags; }; class FileSystem { diff --git a/src/duckdb/src/include/duckdb/common/fsst.hpp b/src/duckdb/src/include/duckdb/common/fsst.hpp index 47398d270..d92e8704b 100644 --- a/src/duckdb/src/include/duckdb/common/fsst.hpp +++ b/src/duckdb/src/include/duckdb/common/fsst.hpp @@ -20,7 +20,7 @@ class FSSTPrimitives { public: static string_t DecompressValue(void *duckdb_fsst_decoder, Vector &result, const char *compressed_string, const idx_t compressed_string_len, vector &decompress_buffer); - static string DecompressValue(void *duckdb_fsst_decoder, const char *compressed_string, - const idx_t compressed_string_len, vector &decompress_buffer); + static Value DecompressValue(void *duckdb_fsst_decoder, const char *compressed_string, + const idx_t compressed_string_len, vector &decompress_buffer); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/hugeint.hpp b/src/duckdb/src/include/duckdb/common/hugeint.hpp index c9b54bd95..0abc91e6d 100644 --- a/src/duckdb/src/include/duckdb/common/hugeint.hpp +++ b/src/duckdb/src/include/duckdb/common/hugeint.hpp @@ -80,13 +80,3 @@ struct hugeint_t { // NOLINT: use numeric casing }; } // namespace duckdb - -namespace std { -template <> -struct hash { - size_t operator()(const duckdb::hugeint_t &val) const { - using std::hash; - return hash {}(val.upper) ^ hash {}(val.lower); - } -}; -} // namespace std diff --git a/src/duckdb/src/include/duckdb/common/insertion_order_preserving_map.hpp b/src/duckdb/src/include/duckdb/common/insertion_order_preserving_map.hpp index fe694f362..d1ff08670 100644 --- a/src/duckdb/src/include/duckdb/common/insertion_order_preserving_map.hpp +++ b/src/duckdb/src/include/duckdb/common/insertion_order_preserving_map.hpp @@ -96,33 +96,23 @@ class InsertionOrderPreservingMap { } void insert(const string &key, V &&value) { // NOLINT: match stl API - if (contains(key)) { - return; - } map.emplace_back(key, std::move(value)); map_idx[key] = map.size() - 1; } void insert(const string &key, const V &value) { // NOLINT: match stl API - if (contains(key)) { - return; - } map.emplace_back(key, value); map_idx[key] = map.size() - 1; } void insert(pair &&value) { // NOLINT: match stl API - auto &key = value.first; - if (contains(key)) { - return; - } - map_idx[key] = map.size(); + map_idx[value.first] = map.size(); map.push_back(std::move(value)); } void erase(typename VECTOR_TYPE::iterator it) { // NOLINT: match stl API auto key = it->first; - auto idx = map_idx[key]; + auto idx = map_idx[it->first]; map.erase(it); map_idx.erase(key); for (auto &kv : map_idx) { diff --git a/src/duckdb/src/include/duckdb/common/local_file_system.hpp b/src/duckdb/src/include/duckdb/common/local_file_system.hpp index c2d38152a..fe4e02ad8 100644 --- a/src/duckdb/src/include/duckdb/common/local_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/local_file_system.hpp @@ -96,9 +96,6 @@ class LocalFileSystem : public FileSystem { //! Checks a file is private (checks for 600 on linux/macos, TODO: currently always returns true on windows) static bool IsPrivateFile(const string &path_p, FileOpener *opener); - // returns a C-string of the path that trims any file:/ prefix - static const char *NormalizeLocalPath(const string &path); - private: //! Set the file pointer of a file handle to a specified location. Reads and writes will happen from this location void SetFilePointer(FileHandle &handle, idx_t location); diff --git a/src/duckdb/src/include/duckdb/common/multi_file_list.hpp b/src/duckdb/src/include/duckdb/common/multi_file_list.hpp index 5adc321cb..65ae86930 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file_list.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file_list.hpp @@ -59,8 +59,7 @@ struct MultiFilePushdownInfo { idx_t table_index; const vector &column_names; - vector column_ids; - vector column_indexes; + const vector &column_ids; ExtraOperatorInfo &extra_info; }; diff --git a/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp b/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp index 364f8641c..ad848187d 100644 --- a/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp +++ b/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp @@ -93,8 +93,6 @@ struct MultiFileConstantEntry { struct MultiFileReaderData { //! The column ids to read from the file vector column_ids; - //! The column indexes to read from the file - vector column_indexes; //! The mapping of column id -> result column id //! The result chunk will be filled as follows: chunk.data[column_mapping[i]] = ReadColumn(column_ids[i]); vector column_mapping; @@ -134,11 +132,11 @@ struct MultiFileReader { //! Parse a Value containing 1 or more paths into a vector of paths. Note: no expansion is performed here DUCKDB_API virtual vector ParsePaths(const Value &input); //! Create a MultiFileList from a vector of paths. Any globs will be expanded using the default filesystem - DUCKDB_API virtual shared_ptr + DUCKDB_API virtual unique_ptr CreateFileList(ClientContext &context, const vector &paths, FileGlobOptions options = FileGlobOptions::DISALLOW_EMPTY); //! Shorthand for ParsePaths + CreateFileList - DUCKDB_API shared_ptr CreateFileList(ClientContext &context, const Value &input, + DUCKDB_API unique_ptr CreateFileList(ClientContext &context, const Value &input, FileGlobOptions options = FileGlobOptions::DISALLOW_EMPTY); //! Parse the named parameters of a multi-file reader @@ -169,22 +167,21 @@ struct MultiFileReader { InitializeGlobalState(ClientContext &context, const MultiFileReaderOptions &file_options, const MultiFileReaderBindData &bind_data, const MultiFileList &file_list, const vector &global_types, const vector &global_names, - const vector &global_column_ids); + const vector &global_column_ids); //! Finalize the bind phase of the multi-file reader after we know (1) the required (output) columns, and (2) the //! pushed down table filters DUCKDB_API virtual void FinalizeBind(const MultiFileReaderOptions &file_options, const MultiFileReaderBindData &options, const string &filename, const vector &local_names, const vector &global_types, - const vector &global_names, - const vector &global_column_ids, MultiFileReaderData &reader_data, - ClientContext &context, optional_ptr global_state); + const vector &global_names, const vector &global_column_ids, + MultiFileReaderData &reader_data, ClientContext &context, + optional_ptr global_state); //! Create all required mappings from the global types/names to the file-local types/names DUCKDB_API virtual void CreateMapping(const string &file_name, const vector &local_types, const vector &local_names, const vector &global_types, - const vector &global_names, - const vector &global_column_ids, + const vector &global_names, const vector &global_column_ids, optional_ptr filters, MultiFileReaderData &reader_data, const string &initial_file, const MultiFileReaderBindData &options, optional_ptr global_state); @@ -198,13 +195,6 @@ struct MultiFileReader { const MultiFileReaderData &reader_data, DataChunk &chunk, optional_ptr global_state); - //! Fetch the partition data for the current chunk - DUCKDB_API virtual void GetPartitionData(ClientContext &context, const MultiFileReaderBindData &bind_data, - const MultiFileReaderData &reader_data, - optional_ptr global_state, - const OperatorPartitionInfo &partition_info, - OperatorPartitionData &partition_data); - template MultiFileReaderBindData BindUnionReader(ClientContext &context, vector &return_types, vector &names, MultiFileList &files, RESULT_CLASS &result, @@ -251,7 +241,7 @@ struct MultiFileReader { template void InitializeReader(READER_CLASS &reader, const MultiFileReaderOptions &options, const MultiFileReaderBindData &bind_data, const vector &global_types, - const vector &global_names, const vector &global_column_ids, + const vector &global_names, const vector &global_column_ids, optional_ptr table_filters, const string &initial_file, ClientContext &context, optional_ptr global_state) { FinalizeBind(options, bind_data, reader.GetFileName(), reader.GetNames(), global_types, global_names, @@ -297,15 +287,10 @@ struct MultiFileReader { } } - //! Get partition info - DUCKDB_API virtual TablePartitionInfo GetPartitionInfo(ClientContext &context, - const MultiFileReaderBindData &bind_data, - TableFunctionPartitionInput &input); - protected: virtual void CreateNameMapping(const string &file_name, const vector &local_types, const vector &local_names, const vector &global_types, - const vector &global_names, const vector &global_column_ids, + const vector &global_names, const vector &global_column_ids, MultiFileReaderData &reader_data, const string &initial_file, optional_ptr global_state); diff --git a/src/duckdb/src/include/duckdb/common/numeric_utils.hpp b/src/duckdb/src/include/duckdb/common/numeric_utils.hpp index 813213dde..ef9a7bc81 100644 --- a/src/duckdb/src/include/duckdb/common/numeric_utils.hpp +++ b/src/duckdb/src/include/duckdb/common/numeric_utils.hpp @@ -119,8 +119,13 @@ TO UnsafeNumericCast(FROM in) { // LossyNumericCast // When: between double/float to other convertible types // Checks: no checks performed (at the moment, to be improved adding range checks) -template -TO LossyNumericCast(FROM val) { +template +TO LossyNumericCast(double val) { + return static_cast(val); +} + +template +TO LossyNumericCast(float val) { return static_cast(val); } diff --git a/src/duckdb/src/include/duckdb/common/opener_file_system.hpp b/src/duckdb/src/include/duckdb/common/opener_file_system.hpp index 216f393d6..2d35512b2 100644 --- a/src/duckdb/src/include/duckdb/common/opener_file_system.hpp +++ b/src/duckdb/src/include/duckdb/common/opener_file_system.hpp @@ -18,14 +18,15 @@ class OpenerFileSystem : public FileSystem { virtual FileSystem &GetFileSystem() const = 0; virtual optional_ptr GetOpener() const = 0; - void VerifyNoOpener(optional_ptr opener); - void VerifyCanAccessDirectory(const string &path); - void VerifyCanAccessFile(const string &path); + void VerifyNoOpener(optional_ptr opener) { + if (opener) { + throw InternalException("OpenerFileSystem cannot take an opener - the opener is pushed automatically"); + } + } unique_ptr OpenFile(const string &path, FileOpenFlags flags, optional_ptr opener = nullptr) override { VerifyNoOpener(opener); - VerifyCanAccessFile(path); return GetFileSystem().OpenFile(path, flags, GetOpener()); } @@ -65,32 +66,26 @@ class OpenerFileSystem : public FileSystem { bool DirectoryExists(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessDirectory(directory); return GetFileSystem().DirectoryExists(directory, GetOpener()); } void CreateDirectory(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessDirectory(directory); return GetFileSystem().CreateDirectory(directory, GetOpener()); } void RemoveDirectory(const string &directory, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessDirectory(directory); return GetFileSystem().RemoveDirectory(directory, GetOpener()); } bool ListFiles(const string &directory, const std::function &callback, FileOpener *opener = nullptr) override { VerifyNoOpener(opener); - VerifyCanAccessDirectory(directory); return GetFileSystem().ListFiles(directory, callback, GetOpener().get()); } void MoveFile(const string &source, const string &target, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessFile(source); - VerifyCanAccessFile(target); GetFileSystem().MoveFile(source, target, GetOpener()); } @@ -104,7 +99,6 @@ class OpenerFileSystem : public FileSystem { bool FileExists(const string &filename, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessFile(filename); return GetFileSystem().FileExists(filename, GetOpener()); } @@ -114,7 +108,6 @@ class OpenerFileSystem : public FileSystem { } void RemoveFile(const string &filename, optional_ptr opener) override { VerifyNoOpener(opener); - VerifyCanAccessFile(filename); GetFileSystem().RemoveFile(filename, GetOpener()); } @@ -124,7 +117,6 @@ class OpenerFileSystem : public FileSystem { vector Glob(const string &path, FileOpener *opener = nullptr) override { VerifyNoOpener(opener); - VerifyCanAccessFile(path); return GetFileSystem().Glob(path, GetOpener().get()); } @@ -151,9 +143,6 @@ class OpenerFileSystem : public FileSystem { vector ListSubSystems() override { return GetFileSystem().ListSubSystems(); } - -private: - void VerifyCanAccessFileInternal(const string &path, FileType type); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp b/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp index d86b29d9c..3e4cb35e9 100644 --- a/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp +++ b/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp @@ -614,22 +614,6 @@ template <> DUCKDB_API bool TryCast::Operation(timestamp_t input, dtime_tz_t &result, bool strict); template <> DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_sec_t input, timestamp_sec_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_sec_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_ms_t input, timestamp_ms_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_ms_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_ns_t input, timestamp_ns_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_ns_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_tz_t input, timestamp_tz_t &result, bool strict); -template <> -DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_tz_t &result, bool strict); //===--------------------------------------------------------------------===// // Interval Casts diff --git a/src/duckdb/src/include/duckdb/common/optional_idx.hpp b/src/duckdb/src/include/duckdb/common/optional_idx.hpp index fc88f8234..7656fe6e7 100644 --- a/src/duckdb/src/include/duckdb/common/optional_idx.hpp +++ b/src/duckdb/src/include/duckdb/common/optional_idx.hpp @@ -32,10 +32,6 @@ class optional_idx { return index != INVALID_INDEX; } - void SetInvalid() { - index = INVALID_INDEX; - } - idx_t GetIndex() const { if (index == INVALID_INDEX) { throw InternalException("Attempting to get the index of an optional_idx that is not set"); diff --git a/src/duckdb/src/include/duckdb/common/platform.hpp b/src/duckdb/src/include/duckdb/common/platform.hpp index cba08883f..3166ff968 100644 --- a/src/duckdb/src/include/duckdb/common/platform.hpp +++ b/src/duckdb/src/include/duckdb/common/platform.hpp @@ -1,12 +1,3 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/platform.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once #include // duplicated from string_util.h to avoid linking issues @@ -15,23 +6,6 @@ #define DUCKDB_QUOTE_DEFINE(x) DUCKDB_QUOTE_DEFINE_IMPL(x) #endif -#if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) -#else -#if !defined(_GNU_SOURCE) -#define _GNU_SOURCE -#include -#ifndef __USE_GNU -#define __MUSL__ -#endif -#undef _GNU_SOURCE /* don't contaminate other includes unnecessarily */ -#else -#include -#ifndef __USE_GNU -#define __MUSL__ -#endif -#endif -#endif - namespace duckdb { std::string DuckDBPlatform() { // NOLINT: allow definition in header @@ -63,25 +37,20 @@ std::string DuckDBPlatform() { // NOLINT: allow definition in header arch = "arm64"; #endif -#if defined(__MUSL__) - if (os == "linux") { - postfix = "_musl"; - } -#elif !defined(_GLIBCXX_USE_CXX11_ABI) || _GLIBCXX_USE_CXX11_ABI == 0 +#if !defined(_GLIBCXX_USE_CXX11_ABI) || _GLIBCXX_USE_CXX11_ABI == 0 if (os == "linux") { postfix = "_gcc4"; } #endif - #if defined(__ANDROID__) postfix += "_android"; // using + because it may also be gcc4 #endif #ifdef __MINGW32__ postfix = "_mingw"; #endif -// this is used for the windows R builds which use `mingw` equivalent extensions +// this is used for the windows R builds which use a separate build environment #ifdef DUCKDB_PLATFORM_RTOOLS - postfix = "_mingw"; + postfix = "_rtools"; #endif return os + "_" + arch + postfix; } diff --git a/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp b/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp index 5c4a0e2a1..aa5efc286 100644 --- a/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp +++ b/src/duckdb/src/include/duckdb/common/radix_partitioning.hpp @@ -8,7 +8,7 @@ #pragma once -#include "duckdb/common/bit_utils.hpp" +#include "duckdb/common/fast_mem.hpp" #include "duckdb/common/types/column/partitioned_column_data.hpp" #include "duckdb/common/types/row/partitioned_tuple_data.hpp" @@ -30,15 +30,15 @@ struct RadixPartitioning { return idx_t(1) << radix_bits; } - template - static inline idx_t RadixBits(T n) { - return sizeof(T) * 8 - CountZeros::Leading(n); - } - //! Inverse of NumberOfPartitions, given a number of partitions, get the number of radix bits - static inline idx_t RadixBitsOfPowerOfTwo(idx_t n_partitions) { + static inline idx_t RadixBits(idx_t n_partitions) { D_ASSERT(IsPowerOfTwo(n_partitions)); - return RadixBits(n_partitions) - 1; + for (idx_t r = 0; r < sizeof(idx_t) * 8; r++) { + if (n_partitions == NumberOfPartitions(r)) { + return r; + } + } + throw InternalException("RadixPartitioning::RadixBits unable to find partition count!"); } //! Radix bits begin after uint16_t because these bits are used as salt in the aggregate HT @@ -52,8 +52,8 @@ struct RadixPartitioning { } //! Select using a cutoff on the radix bits of the hash - static idx_t Select(Vector &hashes, const SelectionVector *sel, idx_t count, idx_t radix_bits, - const ValidityMask &partition_mask, SelectionVector *true_sel, SelectionVector *false_sel); + static idx_t Select(Vector &hashes, const SelectionVector *sel, idx_t count, idx_t radix_bits, idx_t cutoff, + SelectionVector *true_sel, SelectionVector *false_sel); }; //! RadixPartitionedColumnData is a PartitionedColumnData that partitions input based on the radix of a hash @@ -132,6 +132,9 @@ class RadixPartitionedTupleData : public PartitionedTupleData { return RadixPartitioning::NumberOfPartitions(radix_bits) - 1; } + bool RepartitionReverseOrder() const override { + return true; + } void RepartitionFinalizeStates(PartitionedTupleData &old_partitioned_data, PartitionedTupleData &new_partitioned_data, PartitionedTupleDataAppendState &state, idx_t finished_partition_idx) const override; diff --git a/src/duckdb/src/include/duckdb/common/random_engine.hpp b/src/duckdb/src/include/duckdb/common/random_engine.hpp index 8a5a3097e..224a5a203 100644 --- a/src/duckdb/src/include/duckdb/common/random_engine.hpp +++ b/src/duckdb/src/include/duckdb/common/random_engine.hpp @@ -18,25 +18,20 @@ namespace duckdb { class ClientContext; struct RandomState; -class RandomEngine { -public: +struct RandomEngine { explicit RandomEngine(int64_t seed = -1); ~RandomEngine(); +public: //! Generate a random number between min and max double NextRandom(double min, double max); //! Generate a random number between 0 and 1 double NextRandom(); - //! Generate a random number between 0 and 1, using 32-bits as a base - double NextRandom32(); - double NextRandom32(double min, double max); - uint32_t NextRandomInteger32(uint32_t min, uint32_t max); uint32_t NextRandomInteger(); uint32_t NextRandomInteger(uint32_t min, uint32_t max); - uint64_t NextRandomInteger64(); - void SetSeed(uint64_t seed); + void SetSeed(uint32_t seed); static RandomEngine &Get(ClientContext &context); diff --git a/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp b/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp index 06ae00f4e..2973c6b69 100644 --- a/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp +++ b/src/duckdb/src/include/duckdb/common/row_operations/row_operations.hpp @@ -82,6 +82,8 @@ struct RowOperations { static void Gather(Vector &rows, const SelectionVector &row_sel, Vector &col, const SelectionVector &col_sel, const idx_t count, const RowLayout &layout, const idx_t col_no, const idx_t build_size = 0, data_ptr_t heap_ptr = nullptr); + //! Full Scan an entire columns + static void FullScanColumn(const TupleDataLayout &layout, Vector &rows, Vector &col, idx_t count, idx_t col_idx); //===--------------------------------------------------------------------===// // Comparison Operators diff --git a/src/duckdb/src/include/duckdb/common/serializer/buffered_file_writer.hpp b/src/duckdb/src/include/duckdb/common/serializer/buffered_file_writer.hpp index 9b70b1730..b360c3ea1 100644 --- a/src/duckdb/src/include/duckdb/common/serializer/buffered_file_writer.hpp +++ b/src/duckdb/src/include/duckdb/common/serializer/buffered_file_writer.hpp @@ -43,7 +43,7 @@ class BufferedFileWriter : public WriteStream { //! Truncate the size to a previous size (given that size <= GetFileSize()) DUCKDB_API void Truncate(idx_t size); - DUCKDB_API idx_t GetTotalWritten() const; + DUCKDB_API idx_t GetTotalWritten(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp b/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp index 863a99815..f8f539c44 100644 --- a/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp +++ b/src/duckdb/src/include/duckdb/common/serializer/memory_stream.hpp @@ -33,13 +33,6 @@ class MemoryStream : public WriteStream, public ReadStream { // is destroyed explicit MemoryStream(data_ptr_t buffer, idx_t capacity); - // Cant copy! - MemoryStream(const MemoryStream &) = delete; - MemoryStream &operator=(const MemoryStream &) = delete; - - MemoryStream(MemoryStream &&other) noexcept; - MemoryStream &operator=(MemoryStream &&other) noexcept; - ~MemoryStream() override; // Write data to the stream. diff --git a/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp b/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp index 5bde0f9a1..a1c91b8e6 100644 --- a/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp +++ b/src/duckdb/src/include/duckdb/common/serializer/serialization_traits.hpp @@ -32,7 +32,6 @@ using void_t = void; // Check for anything implementing a `void Serialize(Serializer &Serializer)` method template struct has_serialize : std::false_type {}; - template struct has_serialize< T, typename std::enable_if< diff --git a/src/duckdb/src/include/duckdb/common/serializer/serializer.hpp b/src/duckdb/src/include/duckdb/common/serializer/serializer.hpp index 54b994e4b..60531fd1a 100644 --- a/src/duckdb/src/include/duckdb/common/serializer/serializer.hpp +++ b/src/duckdb/src/include/duckdb/common/serializer/serializer.hpp @@ -16,7 +16,6 @@ #include "duckdb/common/types/uhugeint.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/unordered_set.hpp" -#include "duckdb/common/queue.hpp" #include "duckdb/common/optional_idx.hpp" #include "duckdb/common/optionally_owned_ptr.hpp" #include "duckdb/common/value_operations/value_operations.hpp" diff --git a/src/duckdb/src/include/duckdb/common/stacktrace.hpp b/src/duckdb/src/include/duckdb/common/stacktrace.hpp deleted file mode 100644 index eb3f8e693..000000000 --- a/src/duckdb/src/include/duckdb/common/stacktrace.hpp +++ /dev/null @@ -1,25 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/common/stacktrace.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" - -namespace duckdb { - -class StackTrace { -public: - static string GetStacktracePointers(idx_t max_depth = 120); - static string ResolveStacktraceSymbols(const string &pointers); - - inline static string GetStackTrace(idx_t max_depth = 120) { - return ResolveStacktraceSymbols(GetStacktracePointers(max_depth)); - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/string_util.hpp b/src/duckdb/src/include/duckdb/common/string_util.hpp index 7ccc80429..bf8c272d3 100644 --- a/src/duckdb/src/include/duckdb/common/string_util.hpp +++ b/src/duckdb/src/include/duckdb/common/string_util.hpp @@ -86,9 +86,6 @@ class StringUtil { static bool CharacterIsAlpha(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } - static bool CharacterIsAlphaNumeric(char c) { - return CharacterIsAlpha(c) || CharacterIsDigit(c); - } static bool CharacterIsOperator(char c) { if (c == '_') { return false; @@ -127,10 +124,6 @@ class StringUtil { //! Returns true if the needle string exists in the haystack DUCKDB_API static bool Contains(const string &haystack, const string &needle); - DUCKDB_API static bool Contains(const string &haystack, const char &needle_char); - - //! Returns the position of needle string within the haystack - DUCKDB_API static optional_idx Find(const string &haystack, const string &needle); //! Returns true if the target string starts with the given prefix DUCKDB_API static bool StartsWith(string str, string prefix); @@ -144,10 +137,6 @@ class StringUtil { //! Split the input string based on newline char DUCKDB_API static vector Split(const string &str, char delimiter); - //! Split the input string, ignore delimiters within parentheses. Note: leading/trailing spaces are NOT stripped - DUCKDB_API static vector SplitWithParentheses(const string &str, char delimiter = ',', char par_open = '(', - char par_close = ')'); - //! Split the input string allong a quote. Note that any escaping is NOT supported. DUCKDB_API static vector SplitWithQuote(const string &str, char delimiter = ',', char quote = '"'); @@ -165,8 +154,6 @@ class StringUtil { DUCKDB_API static void URLDecodeBuffer(const char *input, idx_t input_size, char *output, bool plus_to_space = false); - DUCKDB_API static idx_t ToUnsigned(const string &str); - template static string ToString(const vector &input, const string &separator) { vector input_list; @@ -210,7 +197,6 @@ class StringUtil { DUCKDB_API static string Title(const string &str); DUCKDB_API static bool IsLower(const string &str); - DUCKDB_API static bool IsUpper(const string &str); //! Case insensitive hash DUCKDB_API static uint64_t CIHash(const string &str); @@ -303,27 +289,13 @@ class StringUtil { //! JSON method that constructs a { string: value } JSON map //! This is the inverse of ParseJSONMap //! NOTE: this method is not efficient - DUCKDB_API static string ExceptionToJSONMap(ExceptionType type, const string &message, - const unordered_map &map); - - DUCKDB_API static string ToJSONMap(const unordered_map &map); + DUCKDB_API static string ToJSONMap(ExceptionType type, const string &message, + const unordered_map &map); DUCKDB_API static string GetFileName(const string &file_path); DUCKDB_API static string GetFileExtension(const string &file_name); DUCKDB_API static string GetFileStem(const string &file_name); DUCKDB_API static string GetFilePath(const string &file_path); - - struct EnumStringLiteral { - uint32_t number; - const char *string; - }; - - DUCKDB_API static uint32_t StringToEnum(const EnumStringLiteral enum_list[], idx_t enum_count, - const char *enum_name, const char *str_value); - DUCKDB_API static const char *EnumToString(const EnumStringLiteral enum_list[], idx_t enum_count, - const char *enum_name, uint32_t enum_value); - DUCKDB_API static const uint8_t ASCII_TO_LOWER_MAP[]; - DUCKDB_API static const uint8_t ASCII_TO_UPPER_MAP[]; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer.hpp index 981836b63..4e0337405 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer.hpp @@ -30,8 +30,6 @@ class TreeRenderer { virtual bool UsesRawKeyNames() { return false; } - virtual void Render(const ProfilingNode &op, std::ostream &ss) { - } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp index a4ed7f75f..5f9cebf17 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/graphviz_tree_renderer.hpp @@ -35,7 +35,7 @@ class GRAPHVIZTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss) override; + void Render(const ProfilingNode &op, std::ostream &ss); void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp index e5d038a27..56cdb4b17 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/html_tree_renderer.hpp @@ -35,7 +35,7 @@ class HTMLTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss) override; + void Render(const ProfilingNode &op, std::ostream &ss); void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp index 15e7c5037..13a5383e4 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/json_tree_renderer.hpp @@ -35,7 +35,7 @@ class JSONTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss) override; + void Render(const ProfilingNode &op, std::ostream &ss); void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; diff --git a/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp b/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp index 1bf43191a..fa560e65a 100644 --- a/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp +++ b/src/duckdb/src/include/duckdb/common/tree_renderer/text_tree_renderer.hpp @@ -84,7 +84,7 @@ class TextTreeRenderer : public TreeRenderer { void Render(const LogicalOperator &op, std::ostream &ss); void Render(const PhysicalOperator &op, std::ostream &ss); - void Render(const ProfilingNode &op, std::ostream &ss) override; + void Render(const ProfilingNode &op, std::ostream &ss); void Render(const Pipeline &op, std::ostream &ss); void ToStreamInternal(RenderTree &root, std::ostream &ss) override; @@ -112,8 +112,7 @@ class TextTreeRenderer : public TreeRenderer { bool CanSplitOnThisChar(char l); bool IsPadding(char l); string RemovePadding(string l); - void SplitUpExtraInfo(const InsertionOrderPreservingMap &extra_info, vector &result, - idx_t max_lines); + void SplitUpExtraInfo(const InsertionOrderPreservingMap &extra_info, vector &result); void SplitStringBuffer(const string &source, vector &result); }; diff --git a/src/duckdb/src/include/duckdb/common/type_util.hpp b/src/duckdb/src/include/duckdb/common/type_util.hpp index d63f528ba..c198bafcd 100644 --- a/src/duckdb/src/include/duckdb/common/type_util.hpp +++ b/src/duckdb/src/include/duckdb/common/type_util.hpp @@ -48,14 +48,6 @@ PhysicalType GetTypeId() { return PhysicalType::INT64; } else if (std::is_same()) { return PhysicalType::INT64; - } else if (std::is_same()) { - return PhysicalType::INT64; - } else if (std::is_same()) { - return PhysicalType::INT64; - } else if (std::is_same()) { - return PhysicalType::INT64; - } else if (std::is_same()) { - return PhysicalType::INT64; } else if (std::is_same()) { return PhysicalType::FLOAT; } else if (std::is_same()) { diff --git a/src/duckdb/src/include/duckdb/common/types.hpp b/src/duckdb/src/include/duckdb/common/types.hpp index 1bc43811a..6e85f35d3 100644 --- a/src/duckdb/src/include/duckdb/common/types.hpp +++ b/src/duckdb/src/include/duckdb/common/types.hpp @@ -234,7 +234,6 @@ enum class LogicalTypeId : uint8_t { }; struct ExtraTypeInfo; -struct ExtensionTypeInfo; struct aggregate_state_t; // NOLINT: mimic std casing @@ -253,7 +252,7 @@ struct LogicalType { inline PhysicalType InternalType() const { return physical_type_; } - inline const optional_ptr AuxInfo() const { + inline const ExtraTypeInfo *AuxInfo() const { return type_info_.get(); } inline bool IsNested() const { @@ -324,11 +323,11 @@ struct LogicalType { DUCKDB_API void SetAlias(string alias); DUCKDB_API bool HasAlias() const; DUCKDB_API string GetAlias() const; - - DUCKDB_API bool HasExtensionInfo() const; - DUCKDB_API optional_ptr GetExtensionInfo() const; - DUCKDB_API optional_ptr GetExtensionInfo(); - DUCKDB_API void SetExtensionInfo(unique_ptr info); + DUCKDB_API void SetModifiers(vector modifiers); + DUCKDB_API bool HasModifiers() const; + DUCKDB_API vector GetModifiersCopy() const; + DUCKDB_API optional_ptr> GetModifiers(); + DUCKDB_API optional_ptr> GetModifiers() const; //! Returns the maximum logical type when combining the two types - or throws an exception if combining is not possible DUCKDB_API static LogicalType MaxLogicalType(ClientContext &context, const LogicalType &left, const LogicalType &right); @@ -339,16 +338,12 @@ struct LogicalType { DUCKDB_API static LogicalType NormalizeType(const LogicalType &type); - //! Gets the decimal properties of a numeric type. Fails if the type is not numeric. + //! Gets the decimal properties of a numeric type. Fails if the type is not numeric. DUCKDB_API bool GetDecimalProperties(uint8_t &width, uint8_t &scale) const; DUCKDB_API void Verify() const; DUCKDB_API bool IsValid() const; - DUCKDB_API bool IsComplete() const; - - //! True, if this type supports in-place updates. - bool SupportsRegularUpdate() const; private: diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp index 38a295320..194b40ca3 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_allocator.hpp @@ -62,12 +62,6 @@ class ColumnDataAllocator { idx_t AllocationSize() const { return allocated_size; } - //! Sets the partition index of this tuple data collection - void SetPartitionIndex(idx_t index) { - D_ASSERT(!partition_index.IsValid()); - D_ASSERT(blocks.empty() && allocated_data.empty()); - partition_index = index; - } public: void AllocateData(idx_t size, uint32_t &block_id, uint32_t &offset, ChunkManagementState *chunk_state); @@ -113,8 +107,6 @@ class ColumnDataAllocator { mutex lock; //! Total allocated size idx_t allocated_size = 0; - //! Partition index (optional, if partitioned) - optional_idx partition_index; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp index f02d49001..1a7473236 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection.hpp @@ -65,8 +65,6 @@ class ColumnDataCollection { idx_t SizeInBytes() const; //! The allocation size (in bytes) of this ColumnDataCollection - this property is cached idx_t AllocationSize() const; - //! Sets the partition index of this ColumnDataCollection - void SetPartitionIndex(idx_t index); //! Get the allocator DUCKDB_API Allocator &GetAllocator() const; @@ -143,17 +141,10 @@ class ColumnDataCollection { //! Obtains the next scan index to scan from bool NextScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, idx_t &row_index) const; - //! Obtains the previous scan index to scan from - bool PrevScanIndex(ColumnDataScanState &state, idx_t &chunk_index, idx_t &segment_index, idx_t &row_index) const; //! Scans at the indices (obtained from NextScanIndex) void ScanAtIndex(ColumnDataParallelScanState &state, ColumnDataLocalScanState &lstate, DataChunk &result, idx_t chunk_index, idx_t segment_index, idx_t row_index) const; - //! Seeks to the chunk _containing_ the row. Returns false if it is past the end. - //! Note that the returned chunk will likely not be aligned to the given row - //! but the scan state will provide the actual range - bool Seek(idx_t row_idx, ColumnDataScanState &state, DataChunk &result) const; - //! Initialize the column data collection void Initialize(vector types); @@ -187,8 +178,6 @@ class ColumnDataCollection { vector copy_functions; //! When the column data collection is marked as finished - new tuples can no longer be appended to it bool finished_append; - //! Partition index (optional, if partitioned) - optional_idx partition_index; }; //! The ColumnDataRowCollection represents a set of materialized rows, as obtained from the ColumnDataCollection @@ -201,8 +190,8 @@ class ColumnDataRowCollection { public: // container API - bool empty() const { // NOLINT: match stl API - return rows.empty(); // NOLINT + bool empty() const { // NOLINT: match stl API + return rows.empty(); } idx_t size() const { // NOLINT: match stl API return rows.size(); diff --git a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp index 76ba2b90c..33dba6ad9 100644 --- a/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp +++ b/src/duckdb/src/include/duckdb/common/types/column/column_data_collection_segment.hpp @@ -137,8 +137,7 @@ class ColumnDataCollectionSegment { void Verify(); static idx_t GetDataSize(idx_t type_size); - static validity_t *GetValidityPointerForWriting(data_ptr_t base_ptr, idx_t type_size); - static validity_t *GetValidityPointer(data_ptr_t base_ptr, idx_t type_size, idx_t count); + static validity_t *GetValidityPointer(data_ptr_t base_ptr, idx_t type_size); private: idx_t ReadVectorInternal(ChunkManagementState &state, VectorDataIndex vector_index, Vector &result); diff --git a/src/duckdb/src/include/duckdb/common/types/conflict_manager.hpp b/src/duckdb/src/include/duckdb/common/types/conflict_manager.hpp index f120b91d9..f9d71375d 100644 --- a/src/duckdb/src/include/duckdb/common/types/conflict_manager.hpp +++ b/src/duckdb/src/include/duckdb/common/types/conflict_manager.hpp @@ -31,6 +31,7 @@ class ConflictManager { optional_ptr conflict_info = nullptr); public: + void SetIndexCount(idx_t count); // These methods return a boolean indicating whether we should throw or not bool AddMiss(idx_t chunk_index); bool AddHit(idx_t chunk_index, row_t row_id); @@ -38,25 +39,13 @@ class ConflictManager { VerifyExistenceType LookupType() const; // This should be called before using the conflicts selection vector void Finalize(); - + idx_t ConflictCount() const; + const ManagedSelection &Conflicts() const; Vector &RowIds(); const ConflictInfo &GetConflictInfo() const; void FinishLookup(); void SetMode(ConflictManagerMode mode); - //! Returns a reference to all conflicts in this conflict manager. - const ManagedSelection &Conflicts() const; - //! Returns the number of conflicts in this conflict manager. - idx_t ConflictCount() const; - //! Adds an index and its respective delete_index to the conflict manager's matches. - void AddIndex(BoundIndex &index, optional_ptr delete_index); - //! Returns true, if the index is in this conflict manager. - bool MatchedIndex(BoundIndex &index); - //! Returns a reference to the matched indexes. - const vector> &MatchedIndexes() const; - //! Returns a reference to the matched delete indexes. - const vector> &MatchedDeleteIndexes() const; - private: bool IsConflict(LookupResultType type); const unordered_set &InternalConflictSet() const; @@ -73,6 +62,7 @@ class ConflictManager { VerifyExistenceType lookup_type; idx_t input_size; optional_ptr conflict_info; + idx_t index_count; bool finalized = false; ManagedSelection conflicts; unique_ptr row_ids; @@ -85,13 +75,6 @@ class ConflictManager { // Whether we have already found the one conflict target we're interested in bool single_index_finished = false; ConflictManagerMode mode; - - //! Indexes matching the conflict target. - vector> matched_indexes; - //! Delete indexes matching the conflict target. - vector> matched_delete_indexes; - //! All matched indexes by their name, which is their unique identifier. - case_insensitive_set_t matched_index_names; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp b/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp index cb6ebcba5..7433c93aa 100644 --- a/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp +++ b/src/duckdb/src/include/duckdb/common/types/data_chunk.hpp @@ -63,9 +63,6 @@ class DataChunk { inline void SetCardinality(const DataChunk &other) { SetCardinality(other.size()); } - inline idx_t GetCapacity() const { - return capacity; - } inline void SetCapacity(idx_t capacity_p) { this->capacity = capacity_p; } @@ -109,7 +106,7 @@ class DataChunk { //! Destroy all data and columns owned by this DataChunk DUCKDB_API void Destroy(); - //! Copies the data from this chunk to another chunk. + //! Copies the data from this vector to another vector. DUCKDB_API void Copy(DataChunk &other, idx_t offset = 0) const; DUCKDB_API void Copy(DataChunk &other, const SelectionVector &sel, const idx_t source_count, const idx_t offset = 0) const; diff --git a/src/duckdb/src/include/duckdb/common/types/date.hpp b/src/duckdb/src/include/duckdb/common/types/date.hpp index ea6b52ce7..f2cb08d50 100644 --- a/src/duckdb/src/include/duckdb/common/types/date.hpp +++ b/src/duckdb/src/include/duckdb/common/types/date.hpp @@ -83,8 +83,6 @@ struct date_t { // NOLINT } // NOLINT }; -enum class DateCastResult : uint8_t { SUCCESS, ERROR_INCORRECT_FORMAT, ERROR_RANGE }; - //! The Date class is a static class that holds helper functions for the Date type. class Date { public: @@ -129,8 +127,8 @@ class Date { DUCKDB_API static bool TryConvertDateSpecial(const char *buf, idx_t len, idx_t &pos, const char *special); //! Try to convert text in a buffer to a date; returns true if parsing was successful //! If the date was a "special" value, the special flag will be set. - DUCKDB_API static DateCastResult TryConvertDate(const char *buf, idx_t len, idx_t &pos, date_t &result, - bool &special, bool strict = false); + DUCKDB_API static bool TryConvertDate(const char *buf, idx_t len, idx_t &pos, date_t &result, bool &special, + bool strict = false); //! Create a string "YYYY-MM-DD" from a specified (year, month, day) //! combination @@ -204,11 +202,8 @@ class Date { //! Helper function to parse two digits from a string (e.g. "30" -> 30, "03" -> 3, "3" -> 3) DUCKDB_API static bool ParseDoubleDigit(const char *buf, idx_t len, idx_t &pos, int32_t &result); - DUCKDB_API static string FormatError(const string &str); - DUCKDB_API static string FormatError(string_t str); - - DUCKDB_API static string RangeError(const string &str); - DUCKDB_API static string RangeError(string_t str); + DUCKDB_API static string ConversionError(const string &str); + DUCKDB_API static string ConversionError(string_t str); private: static void ExtractYearOffset(int32_t &n, int32_t &year, int32_t &year_offset); diff --git a/src/duckdb/src/include/duckdb/common/types/date_lookup_cache.hpp b/src/duckdb/src/include/duckdb/common/types/date_lookup_cache.hpp index b276bbe32..044493ef1 100644 --- a/src/duckdb/src/include/duckdb/common/types/date_lookup_cache.hpp +++ b/src/duckdb/src/include/duckdb/common/types/date_lookup_cache.hpp @@ -30,7 +30,7 @@ class DateLookupCache { //! Extracts the component, or sets the validity mask to NULL if the date is infinite int64_t ExtractElement(date_t date, ValidityMask &mask, idx_t idx) const { - if (DUCKDB_UNLIKELY(date.days < CACHE_MIN_DATE || date.days >= CACHE_MAX_DATE)) { + if (DUCKDB_UNLIKELY(date.days < CACHE_MIN_DATE || date.days > CACHE_MAX_DATE)) { if (DUCKDB_UNLIKELY(!Value::IsFinite(date))) { mask.SetInvalid(idx); return 0; diff --git a/src/duckdb/src/include/duckdb/common/types/interval.hpp b/src/duckdb/src/include/duckdb/common/types/interval.hpp index 825000d57..d8a9672b0 100644 --- a/src/duckdb/src/include/duckdb/common/types/interval.hpp +++ b/src/duckdb/src/include/duckdb/common/types/interval.hpp @@ -27,11 +27,6 @@ struct interval_t { // NOLINT int64_t micros; inline void Normalize(int64_t &months, int64_t &days, int64_t µs) const; - - // Normalize to interval bounds. - inline static void Borrow(const int64_t msf, int64_t &lsf, int32_t &f, const int64_t scale); - inline interval_t Normalize() const; - inline bool operator==(const interval_t &right) const { // Quick equality check const auto &left = *this; @@ -170,62 +165,19 @@ class Interval { return left > right; } }; - void interval_t::Normalize(int64_t &months, int64_t &days, int64_t µs) const { - auto &input = *this; - - // Carry left - micros = input.micros; - int64_t carry_days = micros / Interval::MICROS_PER_DAY; - micros -= carry_days * Interval::MICROS_PER_DAY; - - days = input.days; - days += carry_days; - int64_t carry_months = days / Interval::DAYS_PER_MONTH; - days -= carry_months * Interval::DAYS_PER_MONTH; - - months = input.months; - months += carry_months; -} - -void interval_t::Borrow(const int64_t msf, int64_t &lsf, int32_t &f, const int64_t scale) { - if (msf > NumericLimits::Maximum()) { - f = NumericLimits::Maximum(); - lsf += (msf - f) * scale; - } else if (msf < NumericLimits::Minimum()) { - f = NumericLimits::Minimum(); - lsf += (msf - f) * scale; - } else { - f = UnsafeNumericCast(msf); - } -} - -interval_t interval_t::Normalize() const { - interval_t result; + auto input = *this; + int64_t extra_months_d = input.days / Interval::DAYS_PER_MONTH; + int64_t extra_months_micros = input.micros / Interval::MICROS_PER_MONTH; + input.days -= UnsafeNumericCast(extra_months_d * Interval::DAYS_PER_MONTH); + input.micros -= extra_months_micros * Interval::MICROS_PER_MONTH; - int64_t mm; - int64_t dd; - Normalize(mm, dd, result.micros); + int64_t extra_days_micros = input.micros / Interval::MICROS_PER_DAY; + input.micros -= extra_days_micros * Interval::MICROS_PER_DAY; - // Borrow right on overflow - Borrow(mm, dd, result.months, Interval::DAYS_PER_MONTH); - Borrow(dd, result.micros, result.days, Interval::MICROS_PER_DAY); - - return result; + months = input.months + extra_months_d + extra_months_micros; + days = input.days + extra_days_micros; + micros = input.micros; } } // namespace duckdb - -namespace std { -template <> -struct hash { - size_t operator()(const duckdb::interval_t &val) const { - int64_t months, days, micros; - val.Normalize(months, days, micros); - using std::hash; - - return hash {}(duckdb::UnsafeNumericCast(days)) ^ - hash {}(duckdb::UnsafeNumericCast(months)) ^ hash {}(micros); - } -}; -} // namespace std diff --git a/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp b/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp index 878b1bfa0..999c7218a 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/partitioned_tuple_data.hpp @@ -153,6 +153,10 @@ class PartitionedTupleData { return DConstants::INVALID_INDEX; } + //! Whether or not to iterate over the original partitions in reverse order when repartitioning (optional) + virtual bool RepartitionReverseOrder() const { + return false; + } //! Finalize states while repartitioning - useful for unpinning blocks that are no longer needed (optional) virtual void RepartitionFinalizeStates(PartitionedTupleData &old_partitioned_data, PartitionedTupleData &new_partitioned_data, diff --git a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp index b68d3606b..840d48602 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_allocator.hpp @@ -67,8 +67,6 @@ class TupleDataAllocator { idx_t RowBlockCount() const; //! Number of heap blocks idx_t HeapBlockCount() const; - //! Sets the partition index of this tuple data allocator - void SetPartitionIndex(idx_t index); public: //! Builds out the chunks for next append, given the metadata in the append state @@ -115,8 +113,6 @@ class TupleDataAllocator { BufferManager &buffer_manager; //! The layout of the data const TupleDataLayout layout; - //! Partition index (optional, if partitioned) - optional_idx partition_index; //! Blocks storing the fixed-size rows unsafe_vector row_blocks; //! Blocks storing the variable-size data of the fixed-size rows (e.g., string, list) diff --git a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp index 71b700922..b87b40024 100644 --- a/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp +++ b/src/duckdb/src/include/duckdb/common/types/row/tuple_data_collection.hpp @@ -66,8 +66,6 @@ class TupleDataCollection { idx_t SizeInBytes() const; //! Unpins all held pins void Unpin(); - //! Sets the partition index of this tuple data collection - void SetPartitionIndex(idx_t index); //! Gets the scatter function for the given type static TupleDataScatterFunction GetScatterFunction(const LogicalType &type, bool within_collection = false); @@ -254,8 +252,6 @@ class TupleDataCollection { vector scatter_functions; //! The set of gather functions vector gather_functions; - //! Partition index (optional, if partitioned) - optional_idx partition_index; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/string_type.hpp b/src/duckdb/src/include/duckdb/common/types/string_type.hpp index 0a88e3321..882e0625c 100644 --- a/src/duckdb/src/include/duckdb/common/types/string_type.hpp +++ b/src/duckdb/src/include/duckdb/common/types/string_type.hpp @@ -13,7 +13,6 @@ #include "duckdb/common/helper.hpp" #include "duckdb/common/numeric_utils.hpp" #include "duckdb/common/limits.hpp" -#include "duckdb/common/types/hash.hpp" #include #include @@ -235,12 +234,3 @@ struct string_t { }; } // namespace duckdb - -namespace std { -template <> -struct hash { - size_t operator()(const duckdb::string_t &val) const { - return Hash(val); - } -}; -} // namespace std diff --git a/src/duckdb/src/include/duckdb/common/types/timestamp.hpp b/src/duckdb/src/include/duckdb/common/types/timestamp.hpp index c56168251..683d39650 100644 --- a/src/duckdb/src/include/duckdb/common/types/timestamp.hpp +++ b/src/duckdb/src/include/duckdb/common/types/timestamp.hpp @@ -22,17 +22,15 @@ struct date_t; // NOLINT struct dtime_t; // NOLINT struct dtime_tz_t; // NOLINT -//! Type used to represent a TIMESTAMP. timestamp_t holds the microseconds since 1970-01-01. +//! Type used to represent timestamps (seconds,microseconds,milliseconds or nanoseconds since 1970-01-01) struct timestamp_t { // NOLINT - // NOTE: The unit of value is microseconds for timestamp_t, but it can be - // different for subclasses (e.g. it's nanos for timestamp_ns, etc). int64_t value; timestamp_t() = default; - explicit inline constexpr timestamp_t(int64_t micros) : value(micros) { + explicit inline constexpr timestamp_t(int64_t value_p) : value(value_p) { } - inline timestamp_t &operator=(int64_t micros) { - value = micros; + inline timestamp_t &operator=(int64_t value_p) { + value = value_p; return *this; } @@ -81,40 +79,19 @@ struct timestamp_t { // NOLINT } // NOLINT }; -//! Type used to represent TIMESTAMP_S. timestamp_sec_t holds the seconds since 1970-01-01. -struct timestamp_sec_t : public timestamp_t { // NOLINT - timestamp_sec_t() = default; - explicit inline constexpr timestamp_sec_t(int64_t seconds) : timestamp_t(seconds) { - } -}; - -//! Type used to represent TIMESTAMP_MS. timestamp_ms_t holds the milliseconds since 1970-01-01. -struct timestamp_ms_t : public timestamp_t { // NOLINT - timestamp_ms_t() = default; - explicit inline constexpr timestamp_ms_t(int64_t millis) : timestamp_t(millis) { - } +struct timestamp_tz_t : public timestamp_t { // NOLINT }; - -//! Type used to represent TIMESTAMP_NS. timestamp_ns_t holds the nanoseconds since 1970-01-01. struct timestamp_ns_t : public timestamp_t { // NOLINT - timestamp_ns_t() = default; - explicit inline constexpr timestamp_ns_t(int64_t nanos) : timestamp_t(nanos) { - } }; - -//! Type used to represent TIMESTAMPTZ. timestamp_tz_t holds the microseconds since 1970-01-01 (UTC). -//! It is physically the same as timestamp_t, both hold microseconds since epoch. -struct timestamp_tz_t : public timestamp_t { // NOLINT - timestamp_tz_t() = default; - explicit inline constexpr timestamp_tz_t(int64_t micros) : timestamp_t(micros) { - } - explicit inline constexpr timestamp_tz_t(timestamp_t ts) : timestamp_t(ts) { - } +struct timestamp_ms_t : public timestamp_t { // NOLINT +}; +struct timestamp_sec_t : public timestamp_t { // NOLINT }; -enum class TimestampCastResult : uint8_t { SUCCESS, ERROR_INCORRECT_FORMAT, ERROR_NON_UTC_TIMEZONE, ERROR_RANGE }; +enum class TimestampCastResult : uint8_t { SUCCESS, ERROR_INCORRECT_FORMAT, ERROR_NON_UTC_TIMEZONE }; -//! The static Timestamp class holds helper functions for the timestamp types. +//! The Timestamp class is a static class that holds helper functions for the Timestamp +//! type. class Timestamp { public: // min timestamp is 290308-12-22 (BC) @@ -128,9 +105,8 @@ class Timestamp { //! Convert a string where the offset can also be a time zone string: / [A_Za-z0-9/_]+/ //! If has_offset is true, then the result is an instant that was offset from UTC //! If the tz is not empty, the result is still an instant, but the parts can be extracted and applied to the TZ - DUCKDB_API static TimestampCastResult TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &result, - bool &has_offset, string_t &tz, - optional_ptr nanos = nullptr); + DUCKDB_API static bool TryConvertTimestampTZ(const char *str, idx_t len, timestamp_t &result, bool &has_offset, + string_t &tz, optional_ptr nanos = nullptr); DUCKDB_API static TimestampCastResult TryConvertTimestamp(const char *str, idx_t len, timestamp_t &result, optional_ptr nanos = nullptr); DUCKDB_API static TimestampCastResult TryConvertTimestamp(const char *str, idx_t len, timestamp_ns_t &result); @@ -154,7 +130,7 @@ class Timestamp { c == '-'; } - //! True, if the timestamp is finite, else false. + //! Is the timestamp finite or infinite? static inline bool IsFinite(timestamp_t timestamp) { return timestamp != timestamp_t::infinity() && timestamp != timestamp_t::ninfinity(); } @@ -192,7 +168,6 @@ class Timestamp { DUCKDB_API static int64_t GetEpochMicroSeconds(timestamp_t timestamp); //! Convert a timestamp to epoch (in nanoseconds) DUCKDB_API static int64_t GetEpochNanoSeconds(timestamp_t timestamp); - DUCKDB_API static int64_t GetEpochNanoSeconds(timestamp_ns_t timestamp); //! Convert a timestamp to a rounded epoch at a given resolution. DUCKDB_API static int64_t GetEpochRounded(timestamp_t timestamp, const int64_t power_of_ten); //! Convert a timestamp to a Julian Day @@ -201,12 +176,10 @@ class Timestamp { DUCKDB_API static bool TryParseUTCOffset(const char *str, idx_t &pos, idx_t len, int &hour_offset, int &minute_offset); - DUCKDB_API static string FormatError(const string &str); - DUCKDB_API static string FormatError(string_t str); + DUCKDB_API static string ConversionError(const string &str); + DUCKDB_API static string ConversionError(string_t str); DUCKDB_API static string UnsupportedTimezoneError(const string &str); DUCKDB_API static string UnsupportedTimezoneError(string_t str); - DUCKDB_API static string RangeError(const string &str); - DUCKDB_API static string RangeError(string_t str); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/uuid.hpp b/src/duckdb/src/include/duckdb/common/types/uuid.hpp index bf5ade17a..ae0d8a996 100644 --- a/src/duckdb/src/include/duckdb/common/types/uuid.hpp +++ b/src/duckdb/src/include/duckdb/common/types/uuid.hpp @@ -13,7 +13,7 @@ namespace duckdb { class ClientContext; -class RandomEngine; +struct RandomEngine; //! The UUID class contains static operations for the UUID type class UUID { @@ -30,8 +30,6 @@ class UUID { //! Convert a uhugeint_t object to a uuid value static hugeint_t FromUHugeint(uhugeint_t input); - //! Convert a uuid value to a uhugeint_t object - static uhugeint_t ToUHugeint(hugeint_t input); //! Convert a hugeint object to a uuid style string static hugeint_t GenerateRandomUUID(RandomEngine &engine); diff --git a/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp b/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp index 05583cddd..897488e5f 100644 --- a/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp +++ b/src/duckdb/src/include/duckdb/common/types/validity_mask.hpp @@ -66,11 +66,11 @@ struct TemplatedValidityMask { static constexpr const idx_t STANDARD_MASK_SIZE = STANDARD_ENTRY_COUNT * sizeof(validity_t); public: - inline TemplatedValidityMask() : validity_mask(nullptr), capacity(STANDARD_VECTOR_SIZE) { + inline TemplatedValidityMask() : validity_mask(nullptr), target_count(STANDARD_VECTOR_SIZE) { } - inline explicit TemplatedValidityMask(idx_t target_count) : validity_mask(nullptr), capacity(target_count) { + inline explicit TemplatedValidityMask(idx_t target_count) : validity_mask(nullptr), target_count(target_count) { } - inline explicit TemplatedValidityMask(V *ptr, idx_t capacity) : validity_mask(ptr), capacity(capacity) { + inline explicit TemplatedValidityMask(V *ptr) : validity_mask(ptr), target_count(STANDARD_VECTOR_SIZE) { } inline TemplatedValidityMask(const TemplatedValidityMask &original, idx_t count) { Copy(original, count); @@ -85,9 +85,6 @@ struct TemplatedValidityMask { inline bool CheckAllValid(idx_t count) const { return CountValid(count) == count; } - inline bool CheckAllInvalid(idx_t count) const { - return CountValid(count) == 0; - } inline bool CheckAllValid(idx_t to, idx_t from) const { if (AllValid()) { @@ -142,7 +139,7 @@ struct TemplatedValidityMask { inline void Reset(idx_t target_count_p = STANDARD_VECTOR_SIZE) { validity_mask = nullptr; validity_data.reset(); - capacity = target_count_p; + target_count = target_count_p; } static inline idx_t EntryCount(idx_t count) { @@ -158,7 +155,6 @@ struct TemplatedValidityMask { return validity_mask[entry_idx]; } static inline bool AllValid(V entry) { - // Check if all the tuples that are covered by this entry (usually 64) are valid return entry == ValidityBuffer::MAX_ENTRY; } static inline bool NoneValid(V entry) { @@ -194,12 +190,6 @@ struct TemplatedValidityMask { //! Returns true if a row is valid (i.e. not null), false otherwise inline bool RowIsValid(idx_t row_idx) const { -#ifdef DEBUG - if (row_idx >= capacity) { - throw InternalException("ValidityMask::RowIsValid - row_idx %d is out-of-range for mask with capacity %llu", - row_idx, capacity); - } -#endif if (!validity_mask) { return true; } @@ -216,12 +206,6 @@ struct TemplatedValidityMask { //! Marks the entry at the specified row index as valid (i.e. not-null) inline void SetValid(idx_t row_idx) { -#ifdef DEBUG - if (row_idx >= capacity) { - throw InternalException("ValidityMask::SetValid - row_idx %d is out-of-range for mask with capacity %llu", - row_idx, capacity); - } -#endif if (!validity_mask) { // if AllValid() we don't need to do anything // the row is already valid @@ -245,14 +229,9 @@ struct TemplatedValidityMask { //! Marks the entry at the specified row index as invalid (i.e. null) inline void SetInvalid(idx_t row_idx) { -#ifdef DEBUG - if (row_idx >= capacity) { - throw InternalException("ValidityMask::SetInvalid - row_idx %d is out-of-range for mask with capacity %llu", - row_idx, capacity); - } -#endif if (!validity_mask) { - Initialize(capacity); + D_ASSERT(row_idx <= target_count); + Initialize(target_count); } SetInvalidUnsafe(row_idx); } @@ -312,26 +291,25 @@ struct TemplatedValidityMask { } public: - inline void Initialize(validity_t *validity, idx_t new_capacity) { + inline void Initialize(validity_t *validity) { validity_data.reset(); validity_mask = validity; - capacity = new_capacity; } inline void Initialize(const TemplatedValidityMask &other) { validity_mask = other.validity_mask; validity_data = other.validity_data; - capacity = other.capacity; + target_count = other.target_count; } inline void Initialize(idx_t count) { - capacity = count; + target_count = count; validity_data = make_buffer(count); validity_mask = validity_data->owned_data.get(); } inline void Initialize() { - Initialize(capacity); + Initialize(target_count); } inline void Copy(const TemplatedValidityMask &other, idx_t count) { - capacity = count; + target_count = count; if (other.AllValid()) { validity_data = nullptr; validity_mask = nullptr; @@ -344,30 +322,30 @@ struct TemplatedValidityMask { protected: V *validity_mask; buffer_ptr validity_data; - idx_t capacity; + // The size to initialize the validity mask to when/if the mask is lazily initialized + idx_t target_count; }; struct ValidityMask : public TemplatedValidityMask { public: - inline ValidityMask() : TemplatedValidityMask(nullptr, STANDARD_VECTOR_SIZE) { + inline ValidityMask() : TemplatedValidityMask(nullptr) { } - inline explicit ValidityMask(idx_t capacity) : TemplatedValidityMask(capacity) { + inline explicit ValidityMask(idx_t target_count) : TemplatedValidityMask(target_count) { } - inline explicit ValidityMask(validity_t *ptr, idx_t capacity) : TemplatedValidityMask(ptr, capacity) { + inline explicit ValidityMask(validity_t *ptr) : TemplatedValidityMask(ptr) { } inline ValidityMask(const ValidityMask &original, idx_t count) : TemplatedValidityMask(original, count) { } public: - DUCKDB_API void Resize(idx_t new_size); - DUCKDB_API idx_t Capacity() const; + DUCKDB_API void Resize(idx_t old_size, idx_t new_size); + DUCKDB_API idx_t TargetCount() const; DUCKDB_API void SliceInPlace(const ValidityMask &other, idx_t target_offset, idx_t source_offset, idx_t count); DUCKDB_API void Slice(const ValidityMask &other, idx_t source_offset, idx_t count); DUCKDB_API void CopySel(const ValidityMask &other, const SelectionVector &sel, idx_t source_offset, idx_t target_offset, idx_t count); DUCKDB_API void Combine(const ValidityMask &other, idx_t count); DUCKDB_API string ToString(idx_t count) const; - DUCKDB_API string ToString() const; DUCKDB_API static bool IsAligned(idx_t count); @@ -387,18 +365,11 @@ struct ValidityArray { } inline void Initialize(idx_t count, bool initial = true) { - capacity = count; + target_count = count; validity_data = make_unsafe_uniq_array(count); validity_mask = validity_data.get(); memset(validity_mask, initial, sizeof(bool) * count); } - inline void InitializeEmpty(idx_t count) { - capacity = count; - } - - idx_t Capacity() const { - return capacity; - } //! RowIsValidUnsafe should only be used if AllValid() is false: it achieves the same as RowIsValid but skips a //! not-null check @@ -409,12 +380,6 @@ struct ValidityArray { //! Returns true if a row is valid (i.e. not null), false otherwise inline bool RowIsValid(idx_t row_idx) const { -#ifdef DEBUG - if (row_idx >= capacity) { - throw InternalException("ValidityData::RowIsValid - row_idx %d is out-of-range for mask with capacity %llu", - row_idx, capacity); - } -#endif if (!validity_mask) { return true; } @@ -429,12 +394,6 @@ struct ValidityArray { //! Marks the entry at the specified row index as valid (i.e. not-null) inline void SetValid(idx_t row_idx) { -#ifdef DEBUG - if (row_idx >= capacity) { - throw InternalException("ValidityData::SetValid - row_idx %d is out-of-range for mask with capacity %llu", - row_idx, capacity); - } -#endif if (!validity_mask) { // if AllValid() we don't need to do anything // the row is already valid @@ -446,7 +405,7 @@ struct ValidityArray { inline void Pack(ValidityMask &mask, const idx_t count) const { if (AllValid()) { - mask.Reset(count); + mask.Reset(); return; } mask.Initialize(count); @@ -475,10 +434,9 @@ struct ValidityArray { } } -private: bool *validity_mask = nullptr; unsafe_unique_array validity_data; - idx_t capacity = 0; + idx_t target_count = 0; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/value.hpp b/src/duckdb/src/include/duckdb/common/types/value.hpp index 079541587..7918fa8c3 100644 --- a/src/duckdb/src/include/duckdb/common/types/value.hpp +++ b/src/duckdb/src/include/duckdb/common/types/value.hpp @@ -130,18 +130,14 @@ class Value { DUCKDB_API static Value TIMETZ(dtime_tz_t time); //! Create a time Value from a specified time DUCKDB_API static Value TIME(int32_t hour, int32_t min, int32_t sec, int32_t micros); - //! Create a timestamp Value from a specified date/time combination. + //! Create a timestamp Value from a specified date/time combination DUCKDB_API static Value TIMESTAMP(date_t date, dtime_t time); - //! Create a timestamp Value from a specified value. + //! Create a timestamp Value from a specified timestamp DUCKDB_API static Value TIMESTAMP(timestamp_t timestamp); - //! Create a timestamp_s Value from a specified value. - DUCKDB_API static Value TIMESTAMPSEC(timestamp_sec_t timestamp); - //! Create a timestamp_ms Value from a specified value. - DUCKDB_API static Value TIMESTAMPMS(timestamp_ms_t timestamp); - //! Create a timestamp_ns Value from a specified value. - DUCKDB_API static Value TIMESTAMPNS(timestamp_ns_t timestamp); - //! Create a timestamp_tz Value from a specified value. - DUCKDB_API static Value TIMESTAMPTZ(timestamp_tz_t timestamp); + DUCKDB_API static Value TIMESTAMPNS(timestamp_t timestamp); + DUCKDB_API static Value TIMESTAMPMS(timestamp_t timestamp); + DUCKDB_API static Value TIMESTAMPSEC(timestamp_t timestamp); + DUCKDB_API static Value TIMESTAMPTZ(timestamp_t timestamp); //! Create a timestamp Value from a specified timestamp in separate values DUCKDB_API static Value TIMESTAMP(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t micros); @@ -163,13 +159,20 @@ class Value { //! Create a struct value with given list of entries DUCKDB_API static Value STRUCT(child_list_t values); DUCKDB_API static Value STRUCT(const LogicalType &type, vector struct_values); + //! Create a list value with the given entries, list type is inferred from children + //! Cannot be called with an empty list, use either EMPTYLIST or LIST with a type instead + DUCKDB_API static Value LIST(vector values); //! Create a list value with the given entries DUCKDB_API static Value LIST(const LogicalType &child_type, vector values); - //! Create a list value with the given entries - //! The type of the first value determines the list type. The list cannot be empty. - DUCKDB_API static Value LIST(vector values); + //! Create an empty list with the specified child-type + DUCKDB_API static Value EMPTYLIST(const LogicalType &child_type); + //! Create an array value with the given entries. Array type is inferred from children + //! Cannot be called with an empty list, use either EMPTYARRAY or ARRAY with a type instead + DUCKDB_API static Value ARRAY(vector values); // Create an array value with the given entries DUCKDB_API static Value ARRAY(const LogicalType &type, vector values); + //! Create an empty array of the given type and size + DUCKDB_API static Value EMPTYARRAY(const LogicalType &type, uint32_t size); //! Create a map value with the given entries DUCKDB_API static Value MAP(const LogicalType &child_type, vector values); //! Create a map value with the given entries @@ -298,11 +301,6 @@ class Value { } DUCKDB_API void Print() const; -private: - void SerializeInternal(Serializer &serializer, bool serialize_type) const; - static void SerializeChildren(Serializer &serializer, const vector &children, - const LogicalType &parent_type); - private: //! The logical of the value LogicalType type_; // NOLINT @@ -331,10 +329,6 @@ class Value { dtime_t time; dtime_tz_t timetz; timestamp_t timestamp; - timestamp_sec_t timestamp_s; - timestamp_ms_t timestamp_ms; - timestamp_ns_t timestamp_ns; - timestamp_tz_t timestamp_tz; interval_t interval; } value_; // NOLINT @@ -418,22 +412,6 @@ struct TimestampValue { DUCKDB_API static timestamp_t Get(const Value &value); }; -struct TimestampSValue { - DUCKDB_API static timestamp_sec_t Get(const Value &value); -}; - -struct TimestampMSValue { - DUCKDB_API static timestamp_ms_t Get(const Value &value); -}; - -struct TimestampNSValue { - DUCKDB_API static timestamp_ns_t Get(const Value &value); -}; - -struct TimestampTZValue { - DUCKDB_API static timestamp_tz_t Get(const Value &value); -}; - struct IntervalValue { DUCKDB_API static interval_t Get(const Value &value); }; @@ -556,14 +534,6 @@ DUCKDB_API dtime_tz_t Value::GetValue() const; template <> DUCKDB_API timestamp_t Value::GetValue() const; template <> -DUCKDB_API timestamp_sec_t Value::GetValue() const; -template <> -DUCKDB_API timestamp_ms_t Value::GetValue() const; -template <> -DUCKDB_API timestamp_ns_t Value::GetValue() const; -template <> -DUCKDB_API timestamp_tz_t Value::GetValue() const; -template <> DUCKDB_API interval_t Value::GetValue() const; template <> DUCKDB_API Value Value::GetValue() const; @@ -607,14 +577,6 @@ DUCKDB_API dtime_tz_t Value::GetValueUnsafe() const; template <> DUCKDB_API timestamp_t Value::GetValueUnsafe() const; template <> -DUCKDB_API timestamp_sec_t Value::GetValueUnsafe() const; -template <> -DUCKDB_API timestamp_ms_t Value::GetValueUnsafe() const; -template <> -DUCKDB_API timestamp_ns_t Value::GetValueUnsafe() const; -template <> -DUCKDB_API timestamp_tz_t Value::GetValueUnsafe() const; -template <> DUCKDB_API interval_t Value::GetValueUnsafe() const; template <> @@ -630,13 +592,5 @@ template <> DUCKDB_API bool Value::IsFinite(date_t input); template <> DUCKDB_API bool Value::IsFinite(timestamp_t input); -template <> -DUCKDB_API bool Value::IsFinite(timestamp_sec_t input); -template <> -DUCKDB_API bool Value::IsFinite(timestamp_ms_t input); -template <> -DUCKDB_API bool Value::IsFinite(timestamp_ns_t input); -template <> -DUCKDB_API bool Value::IsFinite(timestamp_tz_t input); } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/types/varint.hpp b/src/duckdb/src/include/duckdb/common/types/varint.hpp index 7a4b5b485..023c2cfef 100644 --- a/src/duckdb/src/include/duckdb/common/types/varint.hpp +++ b/src/duckdb/src/include/duckdb/common/types/varint.hpp @@ -47,8 +47,6 @@ class Varint { DUCKDB_API static char DigitToChar(int digit); //! Function to convert a string_t into a vector of bytes DUCKDB_API static void GetByteArray(vector &byte_array, bool &is_negative, const string_t &blob); - //! Function to create a VARINT blob from a byte array containing the absolute value, plus an is_negative bool - DUCKDB_API static string FromByteArray(uint8_t *data, idx_t size, bool is_negative); //! Function to convert VARINT blob to a VARCHAR DUCKDB_API static string VarIntToVarchar(const string_t &blob); //! Function to convert Varchar to VARINT blob diff --git a/src/duckdb/src/include/duckdb/common/types/vector.hpp b/src/duckdb/src/include/duckdb/common/types/vector.hpp index 61e0b714e..7150a5d72 100644 --- a/src/duckdb/src/include/duckdb/common/types/vector.hpp +++ b/src/duckdb/src/include/duckdb/common/types/vector.hpp @@ -109,10 +109,9 @@ class Vector { /*! Create a new vector If create_data is true, the vector will be an owning empty vector. - If initialize_to_zero is true, the allocated data will be zero-initialized. + If zero_data is true, the allocated data will be zero-initialized. */ - DUCKDB_API Vector(LogicalType type, bool create_data, bool initialize_to_zero, - idx_t capacity = STANDARD_VECTOR_SIZE); + DUCKDB_API Vector(LogicalType type, bool create_data, bool zero_data, idx_t capacity = STANDARD_VECTOR_SIZE); // implicit copying of Vectors is not allowed Vector(const Vector &) = delete; // but moving of vectors is allowed @@ -145,14 +144,10 @@ class Vector { DUCKDB_API void Slice(const SelectionVector &sel, idx_t count); //! Slice the vector, keeping the result around in a cache or potentially using the cache instead of slicing DUCKDB_API void Slice(const SelectionVector &sel, idx_t count, SelCache &cache); - //! Turn this vector into a dictionary vector - DUCKDB_API void Dictionary(idx_t dictionary_size, const SelectionVector &sel, idx_t count); - //! Creates a reference to a dictionary of the other vector - DUCKDB_API void Dictionary(const Vector &dict, idx_t dictionary_size, const SelectionVector &sel, idx_t count); //! Creates the data of this vector with the specified type. Any data that //! is currently in the vector is destroyed. - DUCKDB_API void Initialize(bool initialize_to_zero = false, idx_t capacity = STANDARD_VECTOR_SIZE); + DUCKDB_API void Initialize(bool zero_data = false, idx_t capacity = STANDARD_VECTOR_SIZE); //! Converts this Vector to a printable string representation DUCKDB_API string ToString(idx_t count) const; @@ -309,44 +304,22 @@ struct ConstantVector { }; struct DictionaryVector { - static void VerifyDictionary(const Vector &vector) { -#ifdef DUCKDB_DEBUG_NO_SAFETY - D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR); -#else - if (vector.GetVectorType() != VectorType::DICTIONARY_VECTOR) { - throw InternalException( - "Operation requires a dictionary vector but a non-dictionary vector was encountered"); - } -#endif - } static inline const SelectionVector &SelVector(const Vector &vector) { - VerifyDictionary(vector); + D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR); return vector.buffer->Cast().GetSelVector(); } static inline SelectionVector &SelVector(Vector &vector) { - VerifyDictionary(vector); + D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR); return vector.buffer->Cast().GetSelVector(); } static inline const Vector &Child(const Vector &vector) { - VerifyDictionary(vector); + D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR); return vector.auxiliary->Cast().data; } static inline Vector &Child(Vector &vector) { - VerifyDictionary(vector); + D_ASSERT(vector.GetVectorType() == VectorType::DICTIONARY_VECTOR); return vector.auxiliary->Cast().data; } - static inline optional_idx DictionarySize(const Vector &vector) { - VerifyDictionary(vector); - return vector.buffer->Cast().GetDictionarySize(); - } - static inline const string &DictionaryId(const Vector &vector) { - VerifyDictionary(vector); - return vector.buffer->Cast().GetDictionaryId(); - } - static inline void SetDictionaryId(Vector &vector, string new_id) { - VerifyDictionary(vector); - vector.buffer->Cast().SetDictionaryId(std::move(new_id)); - } }; struct FlatVector { diff --git a/src/duckdb/src/include/duckdb/common/types/vector_buffer.hpp b/src/duckdb/src/include/duckdb/common/types/vector_buffer.hpp index 00ee20c2b..9221b896b 100644 --- a/src/duckdb/src/include/duckdb/common/types/vector_buffer.hpp +++ b/src/duckdb/src/include/duckdb/common/types/vector_buffer.hpp @@ -159,24 +159,9 @@ class DictionaryBuffer : public VectorBuffer { void SetSelVector(const SelectionVector &vector) { this->sel_vector.Initialize(vector); } - void SetDictionarySize(idx_t dict_size) { - dictionary_size = dict_size; - } - optional_idx GetDictionarySize() const { - return dictionary_size; - } - void SetDictionaryId(string id) { - dictionary_id = std::move(id); - } - const string &GetDictionaryId() const { - return dictionary_id; - } private: SelectionVector sel_vector; - optional_idx dictionary_size; - //! A unique identifier for the dictionary that can be used to check if two dictionaries are equivalent - string dictionary_id; }; class VectorStringBuffer : public VectorBuffer { diff --git a/src/duckdb/src/include/duckdb/common/uhugeint.hpp b/src/duckdb/src/include/duckdb/common/uhugeint.hpp index a579e37e4..ba98df46b 100644 --- a/src/duckdb/src/include/duckdb/common/uhugeint.hpp +++ b/src/duckdb/src/include/duckdb/common/uhugeint.hpp @@ -79,13 +79,3 @@ struct uhugeint_t { // NOLINT }; } // namespace duckdb - -namespace std { -template <> -struct hash { - size_t operator()(const duckdb::uhugeint_t &val) const { - using std::hash; - return hash {}(val.upper) ^ hash {}(val.lower); - } -}; -} // namespace std diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp index 6abe7ff1e..87895f7b2 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp @@ -31,7 +31,6 @@ using SubFrames = vector; class AggregateExecutor { private: -#ifndef DUCKDB_SMALLER_BINARY template static inline void NullaryFlatLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data, idx_t count) { @@ -39,7 +38,6 @@ class AggregateExecutor { OP::template Operation(*states[i], aggr_input_data, i); } } -#endif template static inline void NullaryScatterLoop(STATE_TYPE **__restrict states, AggregateInputData &aggr_input_data, @@ -51,7 +49,6 @@ class AggregateExecutor { } } -#ifndef DUCKDB_SMALLER_BINARY template static inline void UnaryFlatLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, STATE_TYPE **__restrict states, ValidityMask &mask, idx_t count) { @@ -91,7 +88,6 @@ class AggregateExecutor { } } } -#endif template static inline void UnaryScatterLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, @@ -118,7 +114,6 @@ class AggregateExecutor { } } -#ifndef DUCKDB_SMALLER_BINARY template static inline void UnaryFlatUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, STATE_TYPE *__restrict state, idx_t count, ValidityMask &mask) { @@ -149,7 +144,6 @@ class AggregateExecutor { } } } -#endif template static inline void UnaryUpdateLoop(const INPUT_TYPE *__restrict idata, AggregateInputData &aggr_input_data, @@ -236,11 +230,9 @@ class AggregateExecutor { if (states.GetVectorType() == VectorType::CONSTANT_VECTOR) { auto sdata = ConstantVector::GetData(states); OP::template ConstantOperation(**sdata, aggr_input_data, count); -#ifndef DUCKDB_SMALLER_BINARY } else if (states.GetVectorType() == VectorType::FLAT_VECTOR) { auto sdata = FlatVector::GetData(states); NullaryFlatLoop(sdata, aggr_input_data, count); -#endif } else { UnifiedVectorFormat sdata; states.ToUnifiedFormat(count, sdata); @@ -266,14 +258,12 @@ class AggregateExecutor { auto sdata = ConstantVector::GetData(states); AggregateUnaryInput input_data(aggr_input_data, ConstantVector::Validity(input)); OP::template ConstantOperation(**sdata, *idata, input_data, count); -#ifndef DUCKDB_SMALLER_BINARY } else if (input.GetVectorType() == VectorType::FLAT_VECTOR && states.GetVectorType() == VectorType::FLAT_VECTOR) { auto idata = FlatVector::GetData(input); auto sdata = FlatVector::GetData(states); UnaryFlatLoop(idata, aggr_input_data, sdata, FlatVector::Validity(input), count); -#endif } else { UnifiedVectorFormat idata, sdata; input.ToUnifiedFormat(count, idata); @@ -297,14 +287,12 @@ class AggregateExecutor { input_data, count); break; } -#ifndef DUCKDB_SMALLER_BINARY case VectorType::FLAT_VECTOR: { auto idata = FlatVector::GetData(input); UnaryFlatUpdateLoop(idata, aggr_input_data, (STATE_TYPE *)state, count, FlatVector::Validity(input)); break; } -#endif default: { UnifiedVectorFormat idata; input.ToUnifiedFormat(count, idata); @@ -399,6 +387,19 @@ class AggregateExecutor { } } + template + static void UnaryWindow(const Vector &input, const ValidityMask &ifilter, AggregateInputData &aggr_input_data, + data_ptr_t state_p, const SubFrames &frames, Vector &result, idx_t ridx, + const_data_ptr_t gstate_p) { + + auto idata = FlatVector::GetData(input); + const auto &ivalid = FlatVector::Validity(input); + auto &state = *reinterpret_cast(state_p); + auto gstate = reinterpret_cast(gstate_p); + OP::template Window(idata, ifilter, ivalid, aggr_input_data, state, frames, + result, ridx, gstate); + } + template static void IntersectFrames(const SubFrames &lefts, const SubFrames &rights, OP &op) { const auto cover_start = MinValue(rights[0].start, lefts[0].start); diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp index 57e669d5d..55c10bb28 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/binary_executor.hpp @@ -68,7 +68,6 @@ struct BinaryLambdaWrapperWithNulls { }; struct BinaryExecutor { -#ifndef DUCKDB_SMALLER_BINARY template static void ExecuteFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -122,7 +121,6 @@ struct BinaryExecutor { } } } -#endif template static void ExecuteConstant(Vector &left, Vector &right, Vector &result, FUNC fun) { @@ -140,7 +138,6 @@ struct BinaryExecutor { fun, *ldata, *rdata, ConstantVector::Validity(result), 0); } -#ifndef DUCKDB_SMALLER_BINARY template static void ExecuteFlat(Vector &left, Vector &right, Vector &result, idx_t count, FUNC fun) { @@ -185,7 +182,6 @@ struct BinaryExecutor { ExecuteFlatLoop( ldata, rdata, result_data, count, result_validity, fun); } -#endif template static void ExecuteGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -236,7 +232,6 @@ struct BinaryExecutor { auto right_vector_type = right.GetVectorType(); if (left_vector_type == VectorType::CONSTANT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) { ExecuteConstant(left, right, result, fun); -#ifndef DUCKDB_SMALLER_BINARY } else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::CONSTANT_VECTOR) { ExecuteFlat(left, right, result, count, fun); @@ -246,7 +241,6 @@ struct BinaryExecutor { } else if (left_vector_type == VectorType::FLAT_VECTOR && right_vector_type == VectorType::FLAT_VECTOR) { ExecuteFlat(left, right, result, count, fun); -#endif } else { ExecuteGeneric(left, right, result, count, fun); } @@ -305,7 +299,6 @@ struct BinaryExecutor { } } -#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t SelectFlatLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -424,24 +417,14 @@ struct BinaryExecutor { ldata, rdata, sel, count, combined_mask, true_sel, false_sel); } } -#endif -#ifndef DUCKDB_SMALLER_BINARY template -#else - template -#endif static inline idx_t SelectGenericLoop(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity, ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) { idx_t true_count = 0, false_count = 0; -#ifdef DUCKDB_SMALLER_BINARY - const bool HAS_TRUE_SEL = true_sel; - const bool HAS_FALSE_SEL = false_sel; - const bool NO_NULL = false; -#endif for (idx_t i = 0; i < count; i++) { auto result_idx = result_sel->get_index(i); auto lindex = lsel->get_index(i); @@ -463,8 +446,6 @@ struct BinaryExecutor { return count - false_count; } } - -#ifndef DUCKDB_SMALLER_BINARY template static inline idx_t SelectGenericLoopSelSwitch(const LEFT_TYPE *__restrict ldata, const RIGHT_TYPE *__restrict rdata, @@ -483,7 +464,6 @@ struct BinaryExecutor { ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); } } -#endif template static inline idx_t @@ -491,7 +471,6 @@ struct BinaryExecutor { const SelectionVector *__restrict lsel, const SelectionVector *__restrict rsel, const SelectionVector *__restrict result_sel, idx_t count, ValidityMask &lvalidity, ValidityMask &rvalidity, SelectionVector *true_sel, SelectionVector *false_sel) { -#ifndef DUCKDB_SMALLER_BINARY if (!lvalidity.AllValid() || !rvalidity.AllValid()) { return SelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); @@ -499,10 +478,6 @@ struct BinaryExecutor { return SelectGenericLoopSelSwitch( ldata, rdata, lsel, rsel, result_sel, count, lvalidity, rvalidity, true_sel, false_sel); } -#else - return SelectGenericLoop(ldata, rdata, lsel, rsel, result_sel, count, lvalidity, - rvalidity, true_sel, false_sel); -#endif } template @@ -527,7 +502,6 @@ struct BinaryExecutor { if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::CONSTANT_VECTOR) { return SelectConstant(left, right, sel, count, true_sel, false_sel); -#ifndef DUCKDB_SMALLER_BINARY } else if (left.GetVectorType() == VectorType::CONSTANT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return SelectFlat(left, right, sel, count, true_sel, false_sel); @@ -537,7 +511,6 @@ struct BinaryExecutor { } else if (left.GetVectorType() == VectorType::FLAT_VECTOR && right.GetVectorType() == VectorType::FLAT_VECTOR) { return SelectFlat(left, right, sel, count, true_sel, false_sel); -#endif } else { return SelectGeneric(left, right, sel, count, true_sel, false_sel); } diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp index 1a31822ff..9f29d7410 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/unary_executor.hpp @@ -11,7 +11,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/common/enums/function_errors.hpp" #include @@ -91,7 +90,6 @@ struct UnaryExecutor { } } -#ifndef DUCKDB_SMALLER_BINARY template static inline void ExecuteFlat(const INPUT_TYPE *__restrict ldata, RESULT_TYPE *__restrict result_data, idx_t count, ValidityMask &mask, ValidityMask &result_mask, void *dataptr, bool adds_nulls) { @@ -137,11 +135,9 @@ struct UnaryExecutor { } } } -#endif template - static inline void ExecuteStandard(Vector &input, Vector &result, idx_t count, void *dataptr, bool adds_nulls, - FunctionErrors errors = FunctionErrors::CAN_THROW_RUNTIME_ERROR) { + static inline void ExecuteStandard(Vector &input, Vector &result, idx_t count, void *dataptr, bool adds_nulls) { switch (input.GetVectorType()) { case VectorType::CONSTANT_VECTOR: { result.SetVectorType(VectorType::CONSTANT_VECTOR); @@ -157,7 +153,6 @@ struct UnaryExecutor { } break; } -#ifndef DUCKDB_SMALLER_BINARY case VectorType::FLAT_VECTOR: { result.SetVectorType(VectorType::FLAT_VECTOR); auto result_data = FlatVector::GetData(result); @@ -167,35 +162,6 @@ struct UnaryExecutor { FlatVector::Validity(result), dataptr, adds_nulls); break; } - case VectorType::DICTIONARY_VECTOR: { - // dictionary vector - we can run the function ONLY on the dictionary in some cases - // we can only do this if the function does not throw errors - // we can execute the function on a value that is in the dictionary but that is not referenced - // if the function can throw errors - this will result in us (incorrectly) throwing an error - if (errors == FunctionErrors::CANNOT_ERROR) { - static constexpr idx_t DICTIONARY_THRESHOLD = 2; - auto dict_size = DictionaryVector::DictionarySize(input); - if (dict_size.IsValid() && dict_size.GetIndex() * DICTIONARY_THRESHOLD <= count) { - // we can operate directly on the dictionary if we have a dictionary size - // but this only makes sense if the dictionary size is smaller than the count by some factor - auto &dictionary_values = DictionaryVector::Child(input); - if (dictionary_values.GetVectorType() == VectorType::FLAT_VECTOR) { - // execute the function over the dictionary - auto result_data = FlatVector::GetData(result); - auto ldata = FlatVector::GetData(dictionary_values); - ExecuteFlat( - ldata, result_data, dict_size.GetIndex(), FlatVector::Validity(dictionary_values), - FlatVector::Validity(result), dataptr, adds_nulls); - // slice the result with the original offsets - auto &offsets = DictionaryVector::SelVector(input); - result.Dictionary(result, dict_size.GetIndex(), offsets, count); - break; - } - } - } - DUCKDB_EXPLICIT_FALLTHROUGH; - } -#endif default: { UnifiedVectorFormat vdata; input.ToUnifiedFormat(count, vdata); @@ -218,10 +184,9 @@ struct UnaryExecutor { } template > - static void Execute(Vector &input, Vector &result, idx_t count, FUNC fun, - FunctionErrors errors = FunctionErrors::CAN_THROW_RUNTIME_ERROR) { - ExecuteStandard( - input, result, count, reinterpret_cast(&fun), false, errors); + static void Execute(Vector &input, Vector &result, idx_t count, FUNC fun) { + ExecuteStandard(input, result, count, + reinterpret_cast(&fun), false); } template @@ -241,78 +206,6 @@ struct UnaryExecutor { UnaryExecutor::GenericExecute>(input, result, count, (void *)&result); } - -private: - // Select logic copied from TernaryExecutor, but with a lambda instead of a static functor - template , bool NO_NULL, bool HAS_TRUE_SEL, - bool HAS_FALSE_SEL> - static inline idx_t SelectLoop(const INPUT_TYPE *__restrict input_data, const SelectionVector *result_sel, - const idx_t count, FUNC fun, const SelectionVector &input_sel, - ValidityMask &input_validity, SelectionVector *true_sel, - SelectionVector *false_sel) { - idx_t true_count = 0, false_count = 0; - for (idx_t i = 0; i < count; i++) { - const auto result_idx = result_sel->get_index(i); - const auto idx = input_sel.get_index(i); - const bool comparison_result = (NO_NULL || input_validity.RowIsValid(idx)) && fun(input_data[idx]); - if (HAS_TRUE_SEL) { - true_sel->set_index(true_count, result_idx); - true_count += comparison_result; - } - if (HAS_FALSE_SEL) { - false_sel->set_index(false_count, result_idx); - false_count += !comparison_result; - } - } - if (HAS_TRUE_SEL) { - return true_count; - } else { - return count - false_count; - } - } - - template , bool NO_NULL> - static inline idx_t SelectLoopSelSwitch(UnifiedVectorFormat &input_data, const SelectionVector *sel, - const idx_t count, FUNC fun, SelectionVector *true_sel, - SelectionVector *false_sel) { - if (true_sel && false_sel) { - return SelectLoop( - UnifiedVectorFormat::GetData(input_data), sel, count, fun, *input_data.sel, - input_data.validity, true_sel, false_sel); - } else if (true_sel) { - return SelectLoop( - UnifiedVectorFormat::GetData(input_data), sel, count, fun, *input_data.sel, - input_data.validity, true_sel, false_sel); - } else { - D_ASSERT(false_sel); - return SelectLoop( - UnifiedVectorFormat::GetData(input_data), sel, count, fun, *input_data.sel, - input_data.validity, true_sel, false_sel); - } - } - - template > - static inline idx_t SelectLoopSwitch(UnifiedVectorFormat &input_data, const SelectionVector *sel, const idx_t count, - FUNC fun, SelectionVector *true_sel, SelectionVector *false_sel) { - if (!input_data.validity.AllValid()) { - return SelectLoopSelSwitch(input_data, sel, count, fun, true_sel, false_sel); - } else { - return SelectLoopSelSwitch(input_data, sel, count, fun, true_sel, false_sel); - } - } - -public: - template > - static idx_t Select(Vector &input, const SelectionVector *sel, const idx_t count, FUNC fun, - SelectionVector *true_sel, SelectionVector *false_sel) { - if (!sel) { - sel = FlatVector::IncrementalSelectionVector(); - } - UnifiedVectorFormat input_data; - input.ToUnifiedFormat(count, input_data); - - return SelectLoopSwitch(input_data, sel, count, fun, true_sel, false_sel); - } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp b/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp index 20219ea42..bd772fcad 100644 --- a/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp +++ b/src/duckdb/src/include/duckdb/common/vector_operations/vector_operations.hpp @@ -129,6 +129,7 @@ struct VectorOperations { idx_t count, optional_ptr true_sel, optional_ptr false_sel, optional_ptr null_mask = nullptr); + // true := A > B with nulls being minimal static idx_t DistinctGreaterThanNullsFirst(Vector &left, Vector &right, optional_ptr sel, idx_t count, optional_ptr true_sel, diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/corr.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp similarity index 91% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/corr.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp index 05cdfb145..0d595b11a 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/corr.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/corr.hpp @@ -9,8 +9,8 @@ #pragma once #include "duckdb/function/aggregate_function.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" -#include "core_functions/aggregate/algebraic/stddev.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" namespace duckdb { @@ -58,7 +58,11 @@ struct CorrOperation { if (!Value::DoubleIsFinite(std_y)) { throw OutOfRangeException("STDDEV_POP for Y is out of range!"); } - target = std_x * std_y != 0 ? cov / (std_x * std_y) : NAN; + if (std_x * std_y == 0) { + finalize_data.ReturnNull(); + return; + } + target = cov / (std_x * std_y); } } diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/covar.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/covar.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/covar.hpp diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/stddev.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic/stddev.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic/stddev.hpp diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp similarity index 98% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp index da08c769a..41ecd18a4 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/algebraic_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/algebraic_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/aggregate/algebraic_functions.hpp +// duckdb/core_functions/aggregate/algebraic_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/distributive_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp similarity index 92% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/distributive_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp index 50c0197a9..8891a2dd0 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/distributive_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/distributive_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/aggregate/distributive_functions.hpp +// duckdb/core_functions/aggregate/distributive_functions.hpp // // //===----------------------------------------------------------------------===// @@ -138,21 +138,6 @@ struct BoolOrFun { static AggregateFunction GetFunction(); }; -struct CountIfFun { - static constexpr const char *Name = "count_if"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Counts the total number of TRUE values for a boolean column"; - static constexpr const char *Example = "count_if(A)"; - - static AggregateFunction GetFunction(); -}; - -struct CountifFun { - using ALIAS = CountIfFun; - - static constexpr const char *Name = "countif"; -}; - struct EntropyFun { static constexpr const char *Name = "entropy"; static constexpr const char *Parameters = "x"; @@ -201,6 +186,26 @@ struct KurtosisPopFun { static AggregateFunction GetFunction(); }; +struct MinFun { + static constexpr const char *Name = "min"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the minimum value present in arg."; + static constexpr const char *Example = "min(A)"; + + static AggregateFunctionSet GetFunctions(); + static AggregateFunction GetFunction(); +}; + +struct MaxFun { + static constexpr const char *Name = "max"; + static constexpr const char *Parameters = "arg"; + static constexpr const char *Description = "Returns the maximum value present in arg."; + static constexpr const char *Example = "max(A)"; + + static AggregateFunctionSet GetFunctions(); + static AggregateFunction GetFunction(); +}; + struct ProductFun { static constexpr const char *Name = "product"; static constexpr const char *Parameters = "arg"; diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/histogram_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp similarity index 98% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/histogram_helpers.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp index 7d73a3caf..3b8240776 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/histogram_helpers.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/histogram_helpers.hpp @@ -9,7 +9,7 @@ #pragma once #include "duckdb/common/common.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/holistic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp similarity index 98% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/holistic_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp index f8b96a166..99b216498 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/holistic_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/holistic_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/aggregate/holistic_functions.hpp +// duckdb/core_functions/aggregate/holistic_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp similarity index 99% rename from src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp index 9c59d11cb..55a7a1507 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate/minmax_n_helpers.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/minmax_n_helpers.hpp @@ -8,7 +8,7 @@ #include "duckdb/common/types/vector.hpp" #include "duckdb/common/enums/order_type.hpp" #include "duckdb/function/aggregate_function.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/nested_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp similarity index 96% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/nested_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp index eb83e5e15..faaa2f4d6 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/nested_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/nested_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/aggregate/nested_functions.hpp +// duckdb/core_functions/aggregate/nested_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp similarity index 83% rename from src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp index bcb90b2ce..161f1a90e 100644 --- a/src/duckdb/src/include/duckdb/common/enums/quantile_enum.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_enum.hpp @@ -1,15 +1,13 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/common/enums/quantile_enum.hpp +// duckdb/core_functions/aggregate/quantile_enum.hpp // // //===----------------------------------------------------------------------===// #pragma once -#include "duckdb/common/constants.hpp" - namespace duckdb { enum class QuantileSerializationType : uint8_t { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp similarity index 92% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_helpers.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp index 253657f5a..a2d41deba 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_helpers.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_helpers.hpp @@ -9,8 +9,8 @@ #pragma once #include "duckdb/common/common.hpp" -#include "duckdb/common/enums/quantile_enum.hpp" -#include "core_functions/aggregate/holistic_functions.hpp" +#include "duckdb/core_functions/aggregate/quantile_enum.hpp" +#include "duckdb/core_functions/aggregate/holistic_functions.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_sort_tree.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp similarity index 62% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_sort_tree.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp index a330c0a4b..146c1259f 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_sort_tree.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_sort_tree.hpp @@ -8,15 +8,10 @@ #pragma once -#include "duckdb/common/sort/sort.hpp" -#include "duckdb/common/types/column/column_data_collection.hpp" -#include "duckdb/common/types/row/row_layout.hpp" -#include "core_functions/aggregate/quantile_helpers.hpp" +#include "duckdb/core_functions/aggregate/quantile_helpers.hpp" #include "duckdb/execution/merge_sort_tree.hpp" #include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/operator/multiply.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/function/window/window_index_tree.hpp" #include #include #include @@ -24,64 +19,6 @@ namespace duckdb { -// Paged access -template -struct QuantileCursor { - explicit QuantileCursor(const WindowPartitionInput &partition) : inputs(*partition.inputs) { - D_ASSERT(partition.column_ids.size() == 1); - inputs.InitializeScan(scan, partition.column_ids); - inputs.InitializeScanChunk(scan, page); - - D_ASSERT(partition.all_valid.size() == 1); - all_valid = partition.all_valid[0]; - } - - inline sel_t RowOffset(idx_t row_idx) const { - D_ASSERT(RowIsVisible(row_idx)); - return UnsafeNumericCast(row_idx - scan.current_row_index); - } - - inline bool RowIsVisible(idx_t row_idx) const { - return (row_idx < scan.next_row_index && scan.current_row_index <= row_idx); - } - - inline idx_t Seek(idx_t row_idx) { - if (!RowIsVisible(row_idx)) { - inputs.Seek(row_idx, scan, page); - data = FlatVector::GetData(page.data[0]); - validity = &FlatVector::Validity(page.data[0]); - } - return RowOffset(row_idx); - } - - inline const INPUT_TYPE &operator[](idx_t row_idx) { - const auto offset = Seek(row_idx); - return data[offset]; - } - - inline bool RowIsValid(idx_t row_idx) { - const auto offset = Seek(row_idx); - return validity->RowIsValid(offset); - } - - inline bool AllValid() { - return all_valid; - } - - //! Windowed paging - const ColumnDataCollection &inputs; - //! The state used for reading the collection on this thread - ColumnDataScanState scan; - //! The data chunk paged into into - DataChunk page; - //! The data pointer - const INPUT_TYPE *data = nullptr; - //! The validity mask - const ValidityMask *validity = nullptr; - //! Paged chunks do not track this but it is really necessary for performance - bool all_valid; -}; - // Direct access template struct QuantileDirect { @@ -98,13 +35,12 @@ template struct QuantileIndirect { using INPUT_TYPE = idx_t; using RESULT_TYPE = T; - using CURSOR = QuantileCursor; - CURSOR &data; + const RESULT_TYPE *data; - explicit QuantileIndirect(CURSOR &data_p) : data(data_p) { + explicit QuantileIndirect(const RESULT_TYPE *data_p) : data(data_p) { } - inline RESULT_TYPE operator()(const INPUT_TYPE &input) const { + inline RESULT_TYPE operator()(const idx_t &input) const { return data[input]; } }; @@ -130,23 +66,14 @@ struct QuantileComposed { template struct QuantileCompare { using INPUT_TYPE = typename ACCESSOR::INPUT_TYPE; - const ACCESSOR &accessor_l; - const ACCESSOR &accessor_r; + const ACCESSOR &accessor; const bool desc; - - // Single cursor for linear operations - explicit QuantileCompare(const ACCESSOR &accessor, bool desc_p) - : accessor_l(accessor), accessor_r(accessor), desc(desc_p) { - } - - // Independent cursors for sorting - explicit QuantileCompare(const ACCESSOR &accessor_l, const ACCESSOR &accessor_r, bool desc_p) - : accessor_l(accessor_l), accessor_r(accessor_r), desc(desc_p) { + explicit QuantileCompare(const ACCESSOR &accessor_p, bool desc_p) : accessor(accessor_p), desc(desc_p) { } inline bool operator()(const INPUT_TYPE &lhs, const INPUT_TYPE &rhs) const { - const auto lval = accessor_l(lhs); - const auto rval = accessor_r(rhs); + const auto lval = accessor(lhs); + const auto rval = accessor(rhs); return desc ? (rval < lval) : (lval < rval); } @@ -216,12 +143,12 @@ struct Interpolator { } template - inline TARGET_TYPE Extract(const INPUT_TYPE *dest, Vector &result) const { + inline TARGET_TYPE Extract(const INPUT_TYPE **dest, Vector &result) const { if (CRN == FRN) { - return CastInterpolation::Cast(dest[0], result); + return CastInterpolation::Cast(*dest[0], result); } else { - auto lo = CastInterpolation::Cast(dest[0], result); - auto hi = CastInterpolation::Cast(dest[1], result); + auto lo = CastInterpolation::Cast(*dest[0], result); + auto hi = CastInterpolation::Cast(*dest[1], result); return CastInterpolation::Interpolate(lo, RN - FRN, hi); } } @@ -285,8 +212,8 @@ struct Interpolator { } template - TARGET_TYPE Extract(const INPUT_TYPE *dest, Vector &result) const { - return CastInterpolation::Cast(dest[0], result); + TARGET_TYPE Extract(const INPUT_TYPE **dest, Vector &result) const { + return CastInterpolation::Cast(*dest[0], result); } const bool desc; @@ -297,84 +224,75 @@ struct Interpolator { idx_t end; }; -template struct QuantileIncluded { - using CURSOR_TYPE = QuantileCursor; - - inline explicit QuantileIncluded(const ValidityMask &fmask_p, CURSOR_TYPE &dmask_p) + inline explicit QuantileIncluded(const ValidityMask &fmask_p, const ValidityMask &dmask_p) : fmask(fmask_p), dmask(dmask_p) { } - inline bool operator()(const idx_t &idx) { + inline bool operator()(const idx_t &idx) const { return fmask.RowIsValid(idx) && dmask.RowIsValid(idx); } - inline bool AllValid() { + inline bool AllValid() const { return fmask.AllValid() && dmask.AllValid(); } const ValidityMask &fmask; - CURSOR_TYPE &dmask; + const ValidityMask &dmask; }; -struct QuantileSortTree { +template +struct QuantileSortTree : public MergeSortTree { - unique_ptr index_tree; + using BaseTree = MergeSortTree; + using Elements = typename BaseTree::Elements; - QuantileSortTree(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition) { - // TODO: Two pass parallel sorting using Build - auto &inputs = *partition.inputs; - ColumnDataScanState scan; - DataChunk sort; - inputs.InitializeScan(scan, partition.column_ids); - inputs.InitializeScanChunk(scan, sort); + explicit QuantileSortTree(Elements &&lowest_level) { + BaseTree::Allocate(lowest_level.size()); + BaseTree::LowestLevel() = std::move(lowest_level); + } - // Sort on the single argument - auto &bind_data = aggr_input_data.bind_data->Cast(); - auto order_expr = make_uniq(Value(sort.GetTypes()[0])); - auto order_type = bind_data.desc ? OrderType::DESCENDING : OrderType::ASCENDING; - BoundOrderModifier order_bys; - order_bys.orders.emplace_back(BoundOrderByNode(order_type, OrderByNullType::NULLS_LAST, std::move(order_expr))); - vector sort_idx(1, 0); - const auto count = partition.count; - - index_tree = make_uniq(partition.context, order_bys, sort_idx, count); - auto index_state = index_tree->GetLocalState(); - auto &local_state = index_state->Cast(); - - // Build the indirection array by scanning the valid indices - const auto &filter_mask = partition.filter_mask; - SelectionVector filter_sel(STANDARD_VECTOR_SIZE); - while (inputs.Scan(scan, sort)) { - const auto row_idx = scan.current_row_index; - if (!filter_mask.AllValid() || !partition.all_valid[0]) { - auto &key = sort.data[0]; - auto &validity = FlatVector::Validity(key); - idx_t filtered = 0; - for (sel_t i = 0; i < sort.size(); ++i) { - if (filter_mask.RowIsValid(i + row_idx) && validity.RowIsValid(i)) { - filter_sel[filtered++] = i; - } + template + static unique_ptr WindowInit(const INPUT_TYPE *data, AggregateInputData &aggr_input_data, + const ValidityMask &data_mask, const ValidityMask &filter_mask, + idx_t count) { + // Build the indirection array + using ElementType = typename QuantileSortTree::ElementType; + vector sorted(count); + if (filter_mask.AllValid() && data_mask.AllValid()) { + std::iota(sorted.begin(), sorted.end(), 0); + } else { + size_t valid = 0; + QuantileIncluded included(filter_mask, data_mask); + for (ElementType i = 0; i < count; ++i) { + if (included(i)) { + sorted[valid++] = i; } - local_state.SinkChunk(sort, row_idx, filter_sel, filtered); - } else { - local_state.SinkChunk(sort, row_idx, nullptr, 0); } + sorted.resize(valid); } - local_state.Sort(); + + // Sort it + auto &bind_data = aggr_input_data.bind_data->Cast(); + using Accessor = QuantileIndirect; + Accessor indirect(data); + QuantileCompare cmp(indirect, bind_data.desc); + std::sort(sorted.begin(), sorted.end(), cmp); + + return make_uniq(std::move(sorted)); } - inline idx_t SelectNth(const SubFrames &frames, size_t n) const { - return index_tree->SelectNth(frames, n); + inline IDX SelectNth(const SubFrames &frames, size_t n) const { + return BaseTree::NthElement(BaseTree::SelectNth(frames, n)); } template - RESULT_TYPE WindowScalar(QuantileCursor &data, const SubFrames &frames, const idx_t n, Vector &result, + RESULT_TYPE WindowScalar(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &result, const QuantileValue &q) { D_ASSERT(n > 0); // Thread safe and idempotent. - index_tree->Build(); + BaseTree::Build(); // Find the interpolated indicies within the frame Interpolator interp(q, n, false); @@ -391,12 +309,12 @@ struct QuantileSortTree { } template - void WindowList(QuantileCursor &data, const SubFrames &frames, const idx_t n, Vector &list, - const idx_t lidx, const QuantileBindData &bind_data) { + void WindowList(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &list, const idx_t lidx, + const QuantileBindData &bind_data) { D_ASSERT(n > 0); // Thread safe and idempotent. - index_tree->Build(); + BaseTree::Build(); // Result is a constant LIST with a fixed length auto ldata = FlatVector::GetData(list); diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_state.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp similarity index 73% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_state.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp index 00f4baf77..a46340955 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/quantile_state.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/quantile_state.hpp @@ -8,7 +8,7 @@ #pragma once -#include "core_functions/aggregate/quantile_sort_tree.hpp" +#include "duckdb/core_functions/aggregate/quantile_sort_tree.hpp" #include "SkipList.h" namespace duckdb { @@ -52,8 +52,11 @@ struct QuantileOperation { template static void WindowInit(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, data_ptr_t g_state) { - D_ASSERT(partition.inputs); + D_ASSERT(partition.input_count == 1); + auto inputs = partition.inputs; + const auto count = partition.count; + const auto &filter_mask = partition.filter_mask; const auto &stats = partition.stats; // If frames overlap significantly, then use local skip lists. @@ -67,14 +70,22 @@ struct QuantileOperation { } } + const auto data = FlatVector::GetData(inputs[0]); + const auto &data_mask = FlatVector::Validity(inputs[0]); + // Build the tree auto &state = *reinterpret_cast(g_state); auto &window_state = state.GetOrCreateWindowState(); - window_state.qst = make_uniq(aggr_input_data, partition); + if (count < std::numeric_limits::max()) { + window_state.qst32 = QuantileSortTree::WindowInit(data, aggr_input_data, data_mask, + filter_mask, count); + } else { + window_state.qst64 = QuantileSortTree::WindowInit(data, aggr_input_data, data_mask, + filter_mask, count); + } } - template - static idx_t FrameSize(QuantileIncluded &included, const SubFrames &frames) { + static idx_t FrameSize(const QuantileIncluded &included, const SubFrames &frames) { // Count the number of valid values idx_t n = 0; if (included.AllValid()) { @@ -95,31 +106,31 @@ struct QuantileOperation { }; template -struct SkipLess { +struct PointerLess { inline bool operator()(const T &lhi, const T &rhi) const { - return lhi.second < rhi.second; + return *lhi < *rhi; } }; template struct WindowQuantileState { // Windowed Quantile merge sort trees - unique_ptr qst; + using QuantileSortTree32 = QuantileSortTree; + using QuantileSortTree64 = QuantileSortTree; + unique_ptr qst32; + unique_ptr qst64; // Windowed Quantile skip lists - using SkipType = pair; - using SkipListType = duckdb_skiplistlib::skip_list::HeadNode>; + using PointerType = const INPUT_TYPE *; + using SkipListType = duckdb_skiplistlib::skip_list::HeadNode>; SubFrames prevs; unique_ptr s; - mutable vector skips; + mutable vector dest; // Windowed MAD indirection idx_t count; vector m; - using IncludedType = QuantileIncluded; - using CursorType = QuantileCursor; - WindowQuantileState() : count(0) { } @@ -140,10 +151,10 @@ struct WindowQuantileState { struct SkipListUpdater { SkipListType &skip; - CursorType &data; - IncludedType &included; + const INPUT_TYPE *data; + const QuantileIncluded &included; - inline SkipListUpdater(SkipListType &skip, CursorType &data, IncludedType &included) + inline SkipListUpdater(SkipListType &skip, const INPUT_TYPE *data, const QuantileIncluded &included) : skip(skip), data(data), included(included) { } @@ -153,7 +164,7 @@ struct WindowQuantileState { inline void Left(idx_t begin, idx_t end) { for (; begin < end; ++begin) { if (included(begin)) { - skip.remove(SkipType(begin, data[begin])); + skip.remove(data + begin); } } } @@ -161,7 +172,7 @@ struct WindowQuantileState { inline void Right(idx_t begin, idx_t end) { for (; begin < end; ++begin) { if (included(begin)) { - skip.insert(SkipType(begin, data[begin])); + skip.insert(data + begin); } } } @@ -170,14 +181,14 @@ struct WindowQuantileState { } }; - void UpdateSkip(CursorType &data, const SubFrames &frames, IncludedType &included) { + void UpdateSkip(const INPUT_TYPE *data, const SubFrames &frames, const QuantileIncluded &included) { // No overlap, or no data if (!s || prevs.back().end <= frames.front().start || frames.back().end <= prevs.front().start) { auto &skip = GetSkipList(true); for (const auto &frame : frames) { for (auto i = frame.start; i < frame.end; ++i) { if (included(i)) { - skip.insert(SkipType(i, data[i])); + skip.insert(data + i); } } } @@ -188,26 +199,23 @@ struct WindowQuantileState { } } - bool HasTree() const { - return qst.get(); + bool HasTrees() const { + return qst32 || qst64; } template - RESULT_TYPE WindowScalar(CursorType &data, const SubFrames &frames, const idx_t n, Vector &result, + RESULT_TYPE WindowScalar(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &result, const QuantileValue &q) const { D_ASSERT(n > 0); - if (qst) { - return qst->WindowScalar(data, frames, n, result, q); + if (qst32) { + return qst32->WindowScalar(data, frames, n, result, q); + } else if (qst64) { + return qst64->WindowScalar(data, frames, n, result, q); } else if (s) { // Find the position(s) needed try { Interpolator interp(q, s->size(), false); - s->at(interp.FRN, interp.CRN - interp.FRN + 1, skips); - array dest; - dest[0] = skips[0].second; - if (skips.size() > 1) { - dest[1] = skips[1].second; - } + s->at(interp.FRN, interp.CRN - interp.FRN + 1, dest); return interp.template Extract(dest.data(), result); } catch (const duckdb_skiplistlib::skip_list::IndexError &idx_err) { throw InternalException(idx_err.message()); @@ -218,7 +226,7 @@ struct WindowQuantileState { } template - void WindowList(CursorType &data, const SubFrames &frames, const idx_t n, Vector &list, const idx_t lidx, + void WindowList(const INPUT_TYPE *data, const SubFrames &frames, const idx_t n, Vector &list, const idx_t lidx, const QuantileBindData &bind_data) const { D_ASSERT(n > 0); // Result is a constant LIST with a fixed length @@ -261,21 +269,19 @@ struct QuantileStringType { template struct QuantileState { using InputType = INPUT_TYPE; - using CursorType = QuantileCursor; // Regular aggregation vector v; // Window Quantile State unique_ptr> window_state; - unique_ptr window_cursor; void AddElement(INPUT_TYPE element, AggregateInputData &aggr_input) { v.emplace_back(TYPE_OP::Operation(element, aggr_input)); } - bool HasTree() const { - return window_state && window_state->HasTree(); + bool HasTrees() const { + return window_state && window_state->HasTrees(); } WindowQuantileState &GetOrCreateWindowState() { if (!window_state) { @@ -289,19 +295,6 @@ struct QuantileState { const WindowQuantileState &GetWindowState() const { return *window_state; } - - CursorType &GetOrCreateWindowCursor(const WindowPartitionInput &partition) { - if (!window_cursor) { - window_cursor = make_uniq(partition); - } - return *window_cursor; - } - CursorType &GetWindowCursor() { - return *window_cursor; - } - const CursorType &GetWindowCursor() const { - return *window_cursor; - } }; } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_count.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp similarity index 88% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_count.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp index 40366ef6a..2b13a2abf 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_count.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_count.hpp @@ -10,8 +10,8 @@ #pragma once #include "duckdb/function/aggregate_function.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" -#include "core_functions/aggregate/algebraic/stddev.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_slope.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp similarity index 88% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_slope.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp index d89af040e..701050419 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression/regr_slope.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression/regr_slope.hpp @@ -7,8 +7,8 @@ //! Output : Double #pragma once -#include "core_functions/aggregate/algebraic/stddev.hpp" -#include "core_functions/aggregate/algebraic/covar.hpp" +#include "duckdb/core_functions/aggregate/algebraic/stddev.hpp" +#include "duckdb/core_functions/aggregate/algebraic/covar.hpp" namespace duckdb { @@ -46,7 +46,11 @@ struct RegrSlopeOperation { if (!Value::DoubleIsFinite(var_pop)) { throw OutOfRangeException("VARPOP is out of range!"); } - target = var_pop != 0 ? cov / var_pop : NAN; + if (var_pop == 0) { + finalize_data.ReturnNull(); + return; + } + target = cov / var_pop; } } diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp similarity index 98% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/regression_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp index e82b9fdff..70cd5f07d 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/aggregate/regression_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/regression_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/aggregate/regression_functions.hpp +// duckdb/core_functions/aggregate/regression_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp similarity index 93% rename from src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp index f1ecb86f9..12798ae3d 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate/sort_key_helpers.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/aggregate/sort_key_helpers.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/aggregate/sort_key_helpers.hpp +// duckdb/core_functions/aggregate/sort_key_helpers.hpp // // //===----------------------------------------------------------------------===// @@ -9,7 +9,7 @@ #pragma once #include "duckdb/common/common.hpp" -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" namespace duckdb { diff --git a/src/duckdb/extension/core_functions/include/core_functions/aggregate/sum_helpers.hpp b/src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/aggregate/sum_helpers.hpp rename to src/duckdb/src/include/duckdb/core_functions/aggregate/sum_helpers.hpp diff --git a/src/duckdb/extension/core_functions/include/core_functions/array_kernels.hpp b/src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/array_kernels.hpp rename to src/duckdb/src/include/duckdb/core_functions/array_kernels.hpp diff --git a/src/duckdb/src/include/duckdb/common/enums/collation_type.hpp b/src/duckdb/src/include/duckdb/core_functions/core_functions.hpp similarity index 60% rename from src/duckdb/src/include/duckdb/common/enums/collation_type.hpp rename to src/duckdb/src/include/duckdb/core_functions/core_functions.hpp index bd1a6e95a..3705be140 100644 --- a/src/duckdb/src/include/duckdb/common/enums/collation_type.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/core_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/common/enums/collation_type.hpp +// duckdb/core_functions/core_functions.hpp // // //===----------------------------------------------------------------------===// @@ -12,6 +12,11 @@ namespace duckdb { -enum class CollationType { ALL_COLLATIONS, COMBINABLE_COLLATIONS }; +class Catalog; +struct CatalogTransaction; + +struct CoreFunctions { + static void RegisterFunctions(Catalog &catalog, CatalogTransaction transaction); +}; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/create_sort_key.hpp b/src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp similarity index 86% rename from src/duckdb/src/include/duckdb/function/create_sort_key.hpp rename to src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp index ab5e6bc19..1f464945f 100644 --- a/src/duckdb/src/include/duckdb/function/create_sort_key.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/create_sort_key.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/create_sort_key.hpp +// duckdb/core_functions/create_sort_key.hpp // // //===----------------------------------------------------------------------===// @@ -46,11 +46,8 @@ struct OrderModifiers { }; struct CreateSortKeyHelpers { - static void CreateSortKey(DataChunk &input, const vector &modifiers, Vector &result); static void CreateSortKey(Vector &input, idx_t input_count, OrderModifiers modifiers, Vector &result); static void DecodeSortKey(string_t sort_key, Vector &result, idx_t result_idx, OrderModifiers modifiers); - static void DecodeSortKey(string_t sort_key, DataChunk &result, idx_t result_idx, - const vector &modifiers); static void CreateSortKeyWithValidity(Vector &input, Vector &result, const OrderModifiers &modifiers, const idx_t count); }; diff --git a/src/duckdb/extension/core_functions/include/core_functions/function_list.hpp b/src/duckdb/src/include/duckdb/core_functions/function_list.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/function_list.hpp rename to src/duckdb/src/include/duckdb/core_functions/function_list.hpp diff --git a/src/duckdb/src/include/duckdb/function/lambda_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp similarity index 99% rename from src/duckdb/src/include/duckdb/function/lambda_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp index a47894a39..ea4db5acf 100644 --- a/src/duckdb/src/include/duckdb/function/lambda_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/lambda_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/lambda_functions.hpp +// duckdb/core_functions/lambda_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/array_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp similarity index 98% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/array_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp index 561643be4..865d77bf6 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/array_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/array_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/array_functions.hpp +// duckdb/core_functions/scalar/array_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/bit_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp similarity index 97% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/bit_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp index e01a2fc58..f66427b6d 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/bit_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/bit_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/bit_functions.hpp +// duckdb/core_functions/scalar/bit_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/blob_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp similarity index 81% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/blob_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp index 051e212c1..29c4034f4 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/blob_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/blob_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/blob_functions.hpp +// duckdb/core_functions/scalar/blob_functions.hpp // // //===----------------------------------------------------------------------===// @@ -57,4 +57,13 @@ struct Base64Fun { static constexpr const char *Name = "base64"; }; +struct CreateSortKeyFun { + static constexpr const char *Name = "create_sort_key"; + static constexpr const char *Parameters = "parameters..."; + static constexpr const char *Description = "Constructs a binary-comparable sort key based on a set of input parameters and sort qualifiers"; + static constexpr const char *Example = "create_sort_key('A', 'DESC')"; + + static ScalarFunction GetFunction(); +}; + } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/date_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp similarity index 91% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/date_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp index 7256502a9..1d0723009 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/date_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/date_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/date_functions.hpp +// duckdb/core_functions/scalar/date_functions.hpp // // //===----------------------------------------------------------------------===// @@ -33,6 +33,21 @@ struct CenturyFun { static ScalarFunctionSet GetFunctions(); }; +struct CurrentDateFun { + static constexpr const char *Name = "current_date"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = "Returns the current date"; + static constexpr const char *Example = "current_date()"; + + static ScalarFunction GetFunction(); +}; + +struct TodayFun { + using ALIAS = CurrentDateFun; + + static constexpr const char *Name = "today"; +}; + struct DateDiffFun { static constexpr const char *Name = "date_diff"; static constexpr const char *Parameters = "part,startdate,enddate"; @@ -192,6 +207,15 @@ struct EraFun { static ScalarFunctionSet GetFunctions(); }; +struct CurrentTimeFun { + static constexpr const char *Name = "get_current_time"; + static constexpr const char *Parameters = ""; + static constexpr const char *Description = "Returns the current time"; + static constexpr const char *Example = "get_current_time()"; + + static ScalarFunction GetFunction(); +}; + struct GetCurrentTimestampFun { static constexpr const char *Name = "get_current_timestamp"; static constexpr const char *Parameters = ""; @@ -260,9 +284,9 @@ struct LastDayFun { struct MakeDateFun { static constexpr const char *Name = "make_date"; - static constexpr const char *Parameters = "year,month,day\1date-struct::STRUCT(year BIGINT, month BIGINT, day BIGINT)"; - static constexpr const char *Description = "The date for the given parts\1The date for the given struct."; - static constexpr const char *Example = "make_date(1992, 9, 20)\1make_date({'year': 2024, 'month': 11, 'day': 14})"; + static constexpr const char *Parameters = "year,month,day"; + static constexpr const char *Description = "The date for the given parts"; + static constexpr const char *Example = "make_date(1992, 9, 20)"; static ScalarFunctionSet GetFunctions(); }; @@ -285,15 +309,6 @@ struct MakeTimestampFun { static ScalarFunctionSet GetFunctions(); }; -struct MakeTimestampNsFun { - static constexpr const char *Name = "make_timestamp_ns"; - static constexpr const char *Parameters = "nanos"; - static constexpr const char *Description = "The timestamp for the given nanoseconds since epoch"; - static constexpr const char *Example = "make_timestamp(1732117793000000000)"; - - static ScalarFunctionSet GetFunctions(); -}; - struct MicrosecondsFun { static constexpr const char *Name = "microsecond"; static constexpr const char *Parameters = "ts"; @@ -357,15 +372,6 @@ struct NanosecondsFun { static ScalarFunctionSet GetFunctions(); }; -struct NormalizedIntervalFun { - static constexpr const char *Name = "normalized_interval"; - static constexpr const char *Parameters = "interval"; - static constexpr const char *Description = "Normalizes an INTERVAL to an equivalent interval"; - static constexpr const char *Example = "normalized_interval(INTERVAL '30 days')"; - - static ScalarFunction GetFunction(); -}; - struct QuarterFun { static constexpr const char *Name = "quarter"; static constexpr const char *Parameters = "ts"; @@ -384,6 +390,24 @@ struct SecondsFun { static ScalarFunctionSet GetFunctions(); }; +struct StrfTimeFun { + static constexpr const char *Name = "strftime"; + static constexpr const char *Parameters = "text,format"; + static constexpr const char *Description = "Converts timestamp to string according to the format string"; + static constexpr const char *Example = "strftime(timestamp '1992-01-01 20:38:40', '%a, %-d %B %Y - %I:%M:%S %p')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StrpTimeFun { + static constexpr const char *Name = "strptime"; + static constexpr const char *Parameters = "text,format"; + static constexpr const char *Description = "Converts string to timestamp with time zone according to the format string if %Z is specified"; + static constexpr const char *Example = "strptime('Wed, 1 January 1992 - 08:38:40 PST', '%a, %-d %B %Y - %H:%M:%S %Z')"; + + static ScalarFunctionSet GetFunctions(); +}; + struct TimeBucketFun { static constexpr const char *Name = "time_bucket"; static constexpr const char *Parameters = "bucket_width,timestamp,origin"; @@ -555,6 +579,15 @@ struct ToYearsFun { static ScalarFunction GetFunction(); }; +struct TryStrpTimeFun { + static constexpr const char *Name = "try_strptime"; + static constexpr const char *Parameters = "text,format"; + static constexpr const char *Description = "Converts string to timestamp using the format string (timestamp with time zone if %Z is specified). Returns NULL on failure"; + static constexpr const char *Example = "try_strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')"; + + static ScalarFunctionSet GetFunctions(); +}; + struct WeekFun { static constexpr const char *Name = "week"; static constexpr const char *Parameters = "ts"; diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/debug_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp similarity index 94% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/debug_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp index ce4debc6d..5c83d51c8 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/debug_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/debug_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/debug_functions.hpp +// duckdb/core_functions/scalar/debug_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/enum_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp similarity index 97% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/enum_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp index 73791f8a5..66c7d6814 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/enum_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/enum_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/enum_functions.hpp +// duckdb/core_functions/scalar/enum_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp similarity index 94% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp index d874e72a9..c7c72387e 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/generic_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/generic_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/generic_functions.hpp +// duckdb/core_functions/scalar/generic_functions.hpp // // //===----------------------------------------------------------------------===// @@ -33,6 +33,15 @@ struct CurrentSettingFun { static ScalarFunction GetFunction(); }; +struct ErrorFun { + static constexpr const char *Name = "error"; + static constexpr const char *Parameters = "message"; + static constexpr const char *Description = "Throws the given error message"; + static constexpr const char *Example = "error('access_mode')"; + + static ScalarFunction GetFunction(); +}; + struct HashFun { static constexpr const char *Name = "hash"; static constexpr const char *Parameters = "param"; diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/list_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp similarity index 96% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/list_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp index 2b9318b40..a5fbfdfe0 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/list_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/list_functions.hpp +// duckdb/core_functions/scalar/list_functions.hpp // // //===----------------------------------------------------------------------===// @@ -104,9 +104,9 @@ struct ListPackFun { struct ListSliceFun { static constexpr const char *Name = "list_slice"; - static constexpr const char *Parameters = "list,begin,end\1list,begin,end,step"; - static constexpr const char *Description = "Extract a sublist using slice conventions. Negative values are accepted.\1list_slice with added step feature."; - static constexpr const char *Example = "list_slice([4, 5, 6], 2, 3)\2array_slice('DuckDB', 3, 4)\2array_slice('DuckDB', 3, NULL)\2array_slice('DuckDB', 0, -3)\1list_slice([4, 5, 6], 1, 3, 2)"; + static constexpr const char *Parameters = "list,begin,end[,step]"; + static constexpr const char *Description = "Extract a sublist using slice conventions. Negative values are accepted"; + static constexpr const char *Example = "list_slice(l, 2, 4)"; static ScalarFunctionSet GetFunctions(); }; diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/map_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp similarity index 89% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/map_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp index 0998a3156..eb9aae54e 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/map_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/map_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/map_functions.hpp +// duckdb/core_functions/scalar/map_functions.hpp // // //===----------------------------------------------------------------------===// @@ -93,4 +93,13 @@ struct MapValuesFun { static ScalarFunction GetFunction(); }; +struct MapContainsFun { + static constexpr const char *Name = "map_contains"; + static constexpr const char *Parameters = "map,key"; + static constexpr const char *Description = "Returns true if the map contains the key, false otherwise"; + static constexpr const char *Example = "map_contains(map(['key'], ['val']), 'key')"; + + static ScalarFunction GetFunction(); +}; + } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/math_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp similarity index 99% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/math_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp index 7b8e2befd..cb1125a10 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/math_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/math_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/math_functions.hpp +// duckdb/core_functions/scalar/math_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/operators_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp similarity index 97% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/operators_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp index 3bbfc565a..908ec939b 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/operators_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/operators_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/operators_functions.hpp +// duckdb/core_functions/scalar/operators_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/random_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp similarity index 96% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/random_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp index 1002f0e44..995c3df66 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/random_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/random_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/random_functions.hpp +// duckdb/core_functions/scalar/random_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/secret_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/secret_functions.hpp similarity index 100% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/secret_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/secret_functions.hpp diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/string_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp similarity index 83% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/string_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp index 6a6db36da..7f3181b0b 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/string_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/string_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/string_functions.hpp +// duckdb/core_functions/scalar/string_functions.hpp // // //===----------------------------------------------------------------------===// @@ -176,20 +176,20 @@ struct JaccardFun { struct JaroSimilarityFun { static constexpr const char *Name = "jaro_similarity"; - static constexpr const char *Parameters = "str1,str2,score_cutoff"; + static constexpr const char *Parameters = "str1,str2"; static constexpr const char *Description = "The Jaro similarity between two strings. Different case is considered different. Returns a number between 0 and 1"; - static constexpr const char *Example = "jaro_similarity('duck', 'duckdb', 0.5)"; + static constexpr const char *Example = "jaro_similarity('duck','duckdb')"; - static ScalarFunctionSet GetFunctions(); + static ScalarFunction GetFunction(); }; struct JaroWinklerSimilarityFun { static constexpr const char *Name = "jaro_winkler_similarity"; - static constexpr const char *Parameters = "str1,str2,score_cutoff"; + static constexpr const char *Parameters = "str1,str2"; static constexpr const char *Description = "The Jaro-Winkler similarity between two strings. Different case is considered different. Returns a number between 0 and 1"; - static constexpr const char *Example = "jaro_winkler_similarity('duck', 'duckdb', 0.5)"; + static constexpr const char *Example = "jaro_winkler_similarity('duck','duckdb')"; - static ScalarFunctionSet GetFunctions(); + static ScalarFunction GetFunction(); }; struct LeftFun { @@ -243,6 +243,24 @@ struct LtrimFun { static ScalarFunctionSet GetFunctions(); }; +struct MD5Fun { + static constexpr const char *Name = "md5"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the MD5 hash of the value as a string"; + static constexpr const char *Example = "md5('123')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct MD5NumberFun { + static constexpr const char *Name = "md5_number"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the MD5 hash of the value as an INT128"; + static constexpr const char *Example = "md5_number('123')"; + + static ScalarFunctionSet GetFunctions(); +}; + struct ParseDirnameFun { static constexpr const char *Name = "parse_dirname"; static constexpr const char *Parameters = "string,separator"; @@ -351,6 +369,72 @@ struct RtrimFun { static ScalarFunctionSet GetFunctions(); }; +struct SHA1Fun { + static constexpr const char *Name = "sha1"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the SHA1 hash of the value"; + static constexpr const char *Example = "sha1('hello')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct SHA256Fun { + static constexpr const char *Name = "sha256"; + static constexpr const char *Parameters = "value"; + static constexpr const char *Description = "Returns the SHA256 hash of the value"; + static constexpr const char *Example = "sha256('hello')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StringSplitFun { + static constexpr const char *Name = "string_split"; + static constexpr const char *Parameters = "string,separator"; + static constexpr const char *Description = "Splits the string along the separator"; + static constexpr const char *Example = "string_split('hello-world', '-')"; + + static ScalarFunction GetFunction(); +}; + +struct StrSplitFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "str_split"; +}; + +struct StringToArrayFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "string_to_array"; +}; + +struct SplitFun { + using ALIAS = StringSplitFun; + + static constexpr const char *Name = "split"; +}; + +struct StringSplitRegexFun { + static constexpr const char *Name = "string_split_regex"; + static constexpr const char *Parameters = "string,separator"; + static constexpr const char *Description = "Splits the string along the regex"; + static constexpr const char *Example = "string_split_regex('hello␣world; 42', ';?␣')"; + + static ScalarFunctionSet GetFunctions(); +}; + +struct StrSplitRegexFun { + using ALIAS = StringSplitRegexFun; + + static constexpr const char *Name = "str_split_regex"; +}; + +struct RegexpSplitToArrayFun { + using ALIAS = StringSplitRegexFun; + + static constexpr const char *Name = "regexp_split_to_array"; +}; + struct TranslateFun { static constexpr const char *Name = "translate"; static constexpr const char *Parameters = "string,from,to"; @@ -362,9 +446,9 @@ struct TranslateFun { struct TrimFun { static constexpr const char *Name = "trim"; - static constexpr const char *Parameters = "string::VARCHAR\1string::VARCHAR,characters::VARCHAR"; - static constexpr const char *Description = "Removes any spaces from either side of the string.\1Removes any occurrences of any of the characters from either side of the string"; - static constexpr const char *Example = "trim(' test ')\1trim('>>>>test<<', '><')"; + static constexpr const char *Parameters = "string,characters"; + static constexpr const char *Description = "Removes any occurrences of any of the characters from either side of the string"; + static constexpr const char *Example = "trim('>>>>test<<', '><')"; static ScalarFunctionSet GetFunctions(); }; @@ -423,6 +507,15 @@ struct ToBaseFun { static ScalarFunctionSet GetFunctions(); }; +struct RegexpEscapeFun { + static constexpr const char *Name = "regexp_escape"; + static constexpr const char *Parameters = "string"; + static constexpr const char *Description = "Escapes all potentially meaningful regexp characters in the input string"; + static constexpr const char *Example = "regexp_escape('https://duckdb.org')"; + + static ScalarFunction GetFunction(); +}; + struct UrlEncodeFun { static constexpr const char *Name = "url_encode"; static constexpr const char *Parameters = "input"; diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/struct_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp similarity index 55% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/struct_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp index f921bf434..b83c5e953 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/struct_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/struct_functions.hpp +// duckdb/core_functions/scalar/struct_functions.hpp // // //===----------------------------------------------------------------------===// @@ -24,4 +24,22 @@ struct StructInsertFun { static ScalarFunction GetFunction(); }; +struct StructPackFun { + static constexpr const char *Name = "struct_pack"; + static constexpr const char *Parameters = "any"; + static constexpr const char *Description = "Creates a STRUCT containing the argument values. The entry name will be the bound variable name"; + static constexpr const char *Example = "struct_pack(i := 4, s := 'string')"; + + static ScalarFunction GetFunction(); +}; + +struct RowFun { + static constexpr const char *Name = "row"; + static constexpr const char *Parameters = "any"; + static constexpr const char *Description = "Creates an unnamed STRUCT containing the argument values."; + static constexpr const char *Example = "row(4, 'hello')"; + + static ScalarFunction GetFunction(); +}; + } // namespace duckdb diff --git a/src/duckdb/extension/core_functions/include/core_functions/scalar/union_functions.hpp b/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp similarity index 96% rename from src/duckdb/extension/core_functions/include/core_functions/scalar/union_functions.hpp rename to src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp index 766c12e8f..8b8694602 100644 --- a/src/duckdb/extension/core_functions/include/core_functions/scalar/union_functions.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/scalar/union_functions.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// core_functions/scalar/union_functions.hpp +// duckdb/core_functions/scalar/union_functions.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/function/to_interval.hpp b/src/duckdb/src/include/duckdb/core_functions/to_interval.hpp similarity index 94% rename from src/duckdb/src/include/duckdb/function/to_interval.hpp rename to src/duckdb/src/include/duckdb/core_functions/to_interval.hpp index 3ef1e82c1..a0f6bf8f6 100644 --- a/src/duckdb/src/include/duckdb/function/to_interval.hpp +++ b/src/duckdb/src/include/duckdb/core_functions/to_interval.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/function/to_interval.hpp +// duckdb/core_functions/to_interval.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/execution/adaptive_filter.hpp b/src/duckdb/src/include/duckdb/execution/adaptive_filter.hpp index 6aea5ab51..82a6bd553 100644 --- a/src/duckdb/src/include/duckdb/execution/adaptive_filter.hpp +++ b/src/duckdb/src/include/duckdb/execution/adaptive_filter.hpp @@ -33,8 +33,6 @@ class AdaptiveFilter { void EndFilter(AdaptiveFilterState state); private: - bool disable_permutations = false; - //! used for adaptive expression reordering idx_t iteration_count = 0; idx_t swap_idx = 0; diff --git a/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp b/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp index e44c90363..2b424152f 100644 --- a/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp +++ b/src/duckdb/src/include/duckdb/execution/aggregate_hashtable.hpp @@ -43,7 +43,7 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { public: //! The hash table load factor, when a resize is triggered - constexpr static double LOAD_FACTOR = 1.25; + constexpr static double LOAD_FACTOR = 1.5; //! Get the layout of this HT const TupleDataLayout &GetLayout() const; @@ -57,7 +57,6 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { idx_t Capacity() const; //! Threshold at which to resize the HT idx_t ResizeThreshold() const; - static idx_t ResizeThreshold(idx_t capacity); //! Add the given data to the HT, computing the aggregates grouped by the //! data in the group chunk. When resize = true, aggregates will not be @@ -65,9 +64,6 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { idx_t AddChunk(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter); idx_t AddChunk(DataChunk &groups, Vector &group_hashes, DataChunk &payload, const unsafe_vector &filter); idx_t AddChunk(DataChunk &groups, DataChunk &payload, AggregateType filter); - optional_idx TryAddCompressedGroups(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter); - optional_idx TryAddDictionaryGroups(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter); - optional_idx TryAddConstantGroups(DataChunk &groups, DataChunk &payload, const unsafe_vector &filter); //! Fetch the aggregates for specific groups from the HT and place them in the result void FetchAggregates(DataChunk &groups, DataChunk &result); @@ -80,53 +76,36 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { idx_t FindOrCreateGroups(DataChunk &groups, Vector &addresses_out, SelectionVector &new_groups_out); void FindOrCreateGroups(DataChunk &groups, Vector &addresses_out); - const PartitionedTupleData &GetPartitionedData() const; - unique_ptr AcquirePartitionedData(); - void Abandon(); - void Repartition(); + unique_ptr &GetPartitionedData(); shared_ptr GetAggregateAllocator(); //! Resize the HT to the specified size. Must be larger than the current size. void Resize(idx_t size); //! Resets the pointer table of the HT to all 0's void ClearPointerTable(); + //! Resets the group count to 0 + void ResetCount(); //! Set the radix bits for this HT void SetRadixBits(idx_t radix_bits); - //! Get the radix bits for this HT - idx_t GetRadixBits() const; - //! Get the total amount of data sunk into this HT - idx_t GetSinkCount() const; - //! Skips lookups from here on out - void SkipLookups(); + //! Initializes the PartitionedTupleData + void InitializePartitionedData(); //! Executes the filter(if any) and update the aggregates void Combine(GroupedAggregateHashTable &other); void Combine(TupleDataCollection &other_data, optional_ptr> progress = nullptr); + //! Unpins the data blocks + void UnpinData(); + private: //! Efficiently matches groups RowMatcher row_matcher; - struct AggregateDictionaryState { - AggregateDictionaryState(); - - //! The current dictionary vector id (if any) - string dictionary_id; - DataChunk unique_values; - Vector hashes; - Vector new_dictionary_pointers; - SelectionVector unique_entries; - unique_ptr dictionary_addresses; - unsafe_unique_array found_entry; - idx_t capacity = 0; - }; - //! Append state struct AggregateHTAppendState { AggregateHTAppendState(); - PartitionedTupleDataAppendState partitioned_append_state; - PartitionedTupleDataAppendState unpartitioned_append_state; + PartitionedTupleDataAppendState append_state; Vector ht_offsets; Vector hash_salts; @@ -137,16 +116,12 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { Vector addresses; unsafe_unique_array group_data; DataChunk group_chunk; - AggregateDictionaryState dict_state; } state; - //! If we have this many or more radix bits, we use the unpartitioned data collection too - static constexpr idx_t UNPARTITIONED_RADIX_BITS_THRESHOLD = 3; //! The number of radix bits to partition by idx_t radix_bits; //! The data of the HT unique_ptr partitioned_data; - unique_ptr unpartitioned_data; //! Predicates for matching groups (always ExpressionType::COMPARE_EQUAL) vector predicates; @@ -163,11 +138,6 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { //! Bitmask for getting relevant bits from the hashes to determine the position hash_t bitmask; - //! How many tuples went into this HT (before de-duplication) - idx_t sink_count; - //! If true, we just append, skipping HT lookups - bool skip_lookups; - //! The active arena allocator used by the aggregates for their internal state shared_ptr aggregate_allocator; //! Owning arena allocators that this HT has data from @@ -179,16 +149,8 @@ class GroupedAggregateHashTable : public BaseAggregateHashTable { //! Destroy the HT void Destroy(); - //! Initializes the PartitionedTupleData - void InitializePartitionedData(); - //! Initializes the PartitionedTupleData that only has 1 partition - void InitializeUnpartitionedData(); //! Apply bitmask to get the entry in the HT inline idx_t ApplyBitMask(hash_t hash) const; - //! Reinserts tuples (triggered by Resize) - void ReinsertTuples(PartitionedTupleData &data); - - void UpdateAggregates(DataChunk &payload, const unsafe_vector &filter); //! Does the actual group matching / creation idx_t FindOrCreateGroupsInternal(DataChunk &groups, Vector &group_hashes, Vector &addresses, diff --git a/src/duckdb/src/include/duckdb/execution/executor.hpp b/src/duckdb/src/include/duckdb/execution/executor.hpp index 46315a989..66f663431 100644 --- a/src/duckdb/src/include/duckdb/execution/executor.hpp +++ b/src/duckdb/src/include/duckdb/execution/executor.hpp @@ -15,7 +15,6 @@ #include "duckdb/common/reference_map.hpp" #include "duckdb/main/query_result.hpp" #include "duckdb/execution/task_error_manager.hpp" -#include "duckdb/execution/progress_data.hpp" #include "duckdb/parallel/pipeline.hpp" #include @@ -87,7 +86,7 @@ class Executor { void AddToBeRescheduled(shared_ptr &task); //! Returns the progress of the pipelines - idx_t GetPipelinesProgress(ProgressData &progress); + bool GetPipelinesProgress(double ¤t_progress, uint64_t ¤t_cardinality, uint64_t &total_cardinality); void CompletePipeline() { completed_pipelines++; diff --git a/src/duckdb/src/include/duckdb/execution/expression_executor.hpp b/src/duckdb/src/include/duckdb/execution/expression_executor.hpp index 7aeb3c2da..80c380d68 100644 --- a/src/duckdb/src/include/duckdb/execution/expression_executor.hpp +++ b/src/duckdb/src/include/duckdb/execution/expression_executor.hpp @@ -21,6 +21,7 @@ class ExecutionContext; //! ExpressionExecutor is responsible for executing a set of expressions and storing the result in a data chunk class ExpressionExecutor { friend class BoundIndex; + friend class CreateIndexLocalSinkState; public: DUCKDB_API explicit ExpressionExecutor(ClientContext &context); diff --git a/src/duckdb/src/include/duckdb/execution/ht_entry.hpp b/src/duckdb/src/include/duckdb/execution/ht_entry.hpp index 8be70f4ed..d6ba04988 100644 --- a/src/duckdb/src/include/duckdb/execution/ht_entry.hpp +++ b/src/duckdb/src/include/duckdb/execution/ht_entry.hpp @@ -13,11 +13,6 @@ namespace duckdb { -#if !defined(DISABLE_POINTER_SALT) && defined(__ANDROID__) -// Google, why does Android need 18446744 TB of address space? -#define DISABLE_POINTER_SALT -#endif - //! The ht_entry_t struct represents an individual entry within a hash table. /*! This struct is used by the JoinHashTable and AggregateHashTable to store entries within the hash table. It stores @@ -26,38 +21,31 @@ namespace duckdb { */ struct ht_entry_t { // NOLINT public: -#ifdef DISABLE_POINTER_SALT - //! No salt, all pointer - static constexpr const hash_t SALT_MASK = 0x0000000000000000; - static constexpr const hash_t POINTER_MASK = 0xFFFFFFFFFFFFFFFF; -#else - //! Upper 16 bits are salt, lower 48 bits are the pointer + //! Upper 16 bits are salt static constexpr const hash_t SALT_MASK = 0xFFFF000000000000; + //! Lower 48 bits are the pointer static constexpr const hash_t POINTER_MASK = 0x0000FFFFFFFFFFFF; -#endif - ht_entry_t() noexcept : value(0) { + explicit inline ht_entry_t(hash_t value_p) noexcept : value(value_p) { } - explicit ht_entry_t(hash_t value_p) noexcept : value(value_p) { - } - - ht_entry_t(const hash_t &salt, const data_ptr_t &pointer) - : value(cast_pointer_to_uint64(pointer) | (salt & SALT_MASK)) { + // Add a default constructor for 32-bit linux test case + ht_entry_t() noexcept : value(0) { } inline bool IsOccupied() const { return value != 0; } - //! Returns a pointer based on the stored value (asserts if the cell is occupied) - inline data_ptr_t GetPointer() const { - D_ASSERT(IsOccupied()); - return GetPointerOrNull(); + // Returns a pointer based on the stored value without checking cell occupancy. + // This can return a nullptr if the cell is not occupied. + inline data_ptr_t GetPointerOrNull() const { + return cast_uint64_to_pointer(value & POINTER_MASK); } - //! Returns a pointer based on the stored value - inline data_ptr_t GetPointerOrNull() const { + // Returns a pointer based on the stored value if the cell is occupied + inline data_ptr_t GetPointer() const { + D_ASSERT(IsOccupied()); return cast_uint64_to_pointer(value & POINTER_MASK); } @@ -71,10 +59,15 @@ struct ht_entry_t { // NOLINT } // Returns the salt, leaves upper salt bits intact, sets lower bits to all 1's - static inline hash_t ExtractSalt(const hash_t &hash) { + static inline hash_t ExtractSalt(hash_t hash) { return hash | POINTER_MASK; } + // Returns the salt, leaves upper salt bits intact, sets lower bits to all 0's + static inline hash_t ExtractSaltWithNulls(hash_t hash) { + return hash & SALT_MASK; + } + inline hash_t GetSalt() const { return ExtractSalt(value); } @@ -88,6 +81,15 @@ struct ht_entry_t { // NOLINT value = salt; } + static inline ht_entry_t GetDesiredEntry(const data_ptr_t &pointer, const hash_t &salt) { + auto desired = cast_pointer_to_uint64(pointer) | (salt & SALT_MASK); + return ht_entry_t(desired); + } + + static inline ht_entry_t GetEmptyEntry() { + return ht_entry_t(0); + } + private: hash_t value; }; diff --git a/src/duckdb/src/include/duckdb/execution/index/art/art.hpp b/src/duckdb/src/include/duckdb/execution/index/art/art.hpp index 31a560ad5..00299952c 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/art.hpp @@ -14,10 +14,14 @@ namespace duckdb { -enum class VerifyExistenceType : uint8_t { APPEND = 0, APPEND_FK = 1, DELETE_FK = 2 }; -enum class ARTConflictType : uint8_t { NO_CONFLICT = 0, CONSTRAINT = 1, TRANSACTION = 2 }; -enum class ARTAppendMode : uint8_t { DEFAULT = 0, IGNORE_DUPLICATES = 1, INSERT_DUPLICATES = 2 }; - +enum class VerifyExistenceType : uint8_t { + // Appends to a table. + APPEND = 0, + // Appends to a table that has a foreign key. + APPEND_FK = 1, + // Delete from a table that has a foreign key. + DELETE_FK = 2 +}; class ConflictManager; class ARTKey; class ARTKeySection; @@ -62,8 +66,6 @@ class ART : public BoundIndex { bool owns_data; //! The number of bytes fitting in the prefix. uint8_t prefix_count; - //! The append mode. - ARTAppendMode append_mode; public: //! Try to initialize a scan on the ART with the given expression and filter. @@ -72,23 +74,15 @@ class ART : public BoundIndex { //! If all row IDs were fetched, it return true, else false. bool Scan(IndexScanState &state, idx_t max_count, unsafe_vector &row_ids); - //! Appends data to the locked index. - ErrorData Append(IndexLock &l, DataChunk &chunk, Vector &row_ids) override; - //! Appends data to the locked index and verifies constraint violations against a delete index. - ErrorData AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids, - optional_ptr delete_index) override; - - //! Internally inserts a chunk. - ARTConflictType Insert(Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, const GateStatus status, - optional_ptr delete_art); + //! Append a chunk by first executing the ART's expressions. + ErrorData Append(IndexLock &lock, DataChunk &input, Vector &row_ids) override; //! Insert a chunk. - ErrorData Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids) override; - //! Insert a chunk and verifies constraint violations against a delete index. - ErrorData Insert(IndexLock &l, DataChunk &data, Vector &row_ids, optional_ptr delete_index) override; + bool Insert(Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, const GateStatus status); + ErrorData Insert(IndexLock &lock, DataChunk &data, Vector &row_ids) override; - //! Verify that data can be appended to the index without a constraint violation. - void VerifyAppend(DataChunk &chunk, optional_ptr delete_index, - optional_ptr manager) override; + //! Constraint verification for a chunk. + void VerifyAppend(DataChunk &chunk) override; + void VerifyAppend(DataChunk &chunk, ConflictManager &conflict_manager) override; //! Delete a chunk from the ART. void Delete(IndexLock &lock, DataChunk &entries, Vector &row_ids) override; @@ -130,16 +124,12 @@ class ART : public BoundIndex { void InsertIntoEmpty(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, const GateStatus status); - ARTConflictType InsertIntoInlined(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art); - ARTConflictType InsertIntoNode(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art); + bool InsertIntoNode(Node &node, const ARTKey &key, const idx_t depth, const ARTKey &row_id, + const GateStatus status); string GenerateErrorKeyName(DataChunk &input, idx_t row); string GenerateConstraintErrorMessage(VerifyExistenceType verify_type, const string &key_name); - void VerifyLeaf(const Node &leaf, const ARTKey &key, optional_ptr delete_art, ConflictManager &manager, - optional_idx &conflict_idx, idx_t i); - void VerifyConstraint(DataChunk &chunk, optional_ptr delete_index, ConflictManager &manager) override; + void CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_manager) override; string GetConstraintViolationMessage(VerifyExistenceType verify_type, idx_t failed_index, DataChunk &input) override; diff --git a/src/duckdb/src/include/duckdb/execution/index/art/node.hpp b/src/duckdb/src/include/duckdb/execution/index/art/node.hpp index 316ecc5f2..725cc2d3c 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/node.hpp @@ -143,7 +143,6 @@ class Node : public IndexPointer { inline void SetGateStatus(const GateStatus status) { switch (status) { case GateStatus::GATE_SET: - D_ASSERT(GetType() != NType::LEAF_INLINED); SetMetadata(GetMetadata() | AND_GATE); break; case GateStatus::GATE_NOT_SET: diff --git a/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp b/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp index 5d656c742..670ab32ef 100644 --- a/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp @@ -84,8 +84,8 @@ class Prefix { static GateStatus Split(ART &art, reference &node, Node &child, const uint8_t pos); //! Insert a key into a prefix. - static ARTConflictType Insert(ART &art, Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, - const GateStatus status, optional_ptr delete_art); + static bool Insert(ART &art, Node &node, const ARTKey &key, idx_t depth, const ARTKey &row_id, + const GateStatus status); //! Returns the string representation of the node, or only traverses and verifies the node and its subtree static string VerifyAndToString(ART &art, const Node &node, const bool only_verify); diff --git a/src/duckdb/src/include/duckdb/execution/index/bound_index.hpp b/src/duckdb/src/include/duckdb/execution/index/bound_index.hpp index 522c7c78e..a73ede0f9 100644 --- a/src/duckdb/src/include/duckdb/execution/index/bound_index.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/bound_index.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/execution/index/bound_index.hpp +// duckdb/storage/index.hpp // // //===----------------------------------------------------------------------===// @@ -15,8 +15,8 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/planner/expression.hpp" -#include "duckdb/storage/index.hpp" #include "duckdb/storage/table_storage_info.hpp" +#include "duckdb/storage/index.hpp" namespace duckdb { @@ -64,24 +64,19 @@ class BoundIndex : public Index { return index_constraint_type; } -public: - //! Obtains a lock on the index. +public: // Index interface + //! Obtain a lock on the index void InitializeLock(IndexLock &state); - //! Appends data to the locked index. - virtual ErrorData Append(IndexLock &l, DataChunk &chunk, Vector &row_ids) = 0; - //! Obtains a lock and calls Append while holding that lock. - ErrorData Append(DataChunk &chunk, Vector &row_ids); - //! Appends data to the locked index and verifies constraint violations against a delete index. - virtual ErrorData AppendWithDeleteIndex(IndexLock &l, DataChunk &chunk, Vector &row_ids, - optional_ptr delete_index); - //! Obtains a lock and calls Append with an delete_index while holding that lock. - ErrorData AppendWithDeleteIndex(DataChunk &chunk, Vector &row_ids, optional_ptr delete_index); - - //! Verify that data can be appended to the index without a constraint violation. - virtual void VerifyAppend(DataChunk &chunk, optional_ptr delete_index, - optional_ptr manager); - //! Verifies the constraint for a chunk of data. - virtual void VerifyConstraint(DataChunk &chunk, optional_ptr delete_index, ConflictManager &manager); + //! Called when data is appended to the index. The lock obtained from InitializeLock must be held + virtual ErrorData Append(IndexLock &state, DataChunk &entries, Vector &row_identifiers) = 0; + //! Obtains a lock and calls Append while holding that lock + ErrorData Append(DataChunk &entries, Vector &row_identifiers); + //! Verify that data can be appended to the index without a constraint violation + virtual void VerifyAppend(DataChunk &chunk) = 0; + //! Verify that data can be appended to the index without a constraint violation using the conflict manager + virtual void VerifyAppend(DataChunk &chunk, ConflictManager &conflict_manager) = 0; + //! Performs constraint checking for a chunk of input data + virtual void CheckConstraintsForChunk(DataChunk &input, ConflictManager &conflict_manager) = 0; //! Deletes all data from the index. The lock obtained from InitializeLock must be held virtual void CommitDrop(IndexLock &index_lock) = 0; @@ -92,10 +87,8 @@ class BoundIndex : public Index { //! Obtains a lock and calls Delete while holding that lock void Delete(DataChunk &entries, Vector &row_identifiers); - //! Insert a chunk. - virtual ErrorData Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids) = 0; - //! Insert a chunk and verifies constraint violations against a delete index. - virtual ErrorData Insert(IndexLock &l, DataChunk &chunk, Vector &row_ids, optional_ptr delete_index); + //! Insert a chunk of entries into the index + virtual ErrorData Insert(IndexLock &lock, DataChunk &input, Vector &row_identifiers) = 0; //! Merge another index into this index. The lock obtained from InitializeLock must be held, and the other //! index must also be locked during the merge diff --git a/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp b/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp index 520e24376..9942bb814 100644 --- a/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/fixed_size_allocator.hpp @@ -94,10 +94,6 @@ class FixedSizeAllocator { return total_segment_count; } - inline idx_t GetMaxSegmentsPerBuffer() const { - return available_segments_per_buffer; - } - //! Returns the upper bound of the available buffer IDs, i.e., upper_bound > max_buffer_id idx_t GetUpperBoundBufferId() const; //! Merge another FixedSizeAllocator into this allocator. Both must have the same segment size diff --git a/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp b/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp index bf9b35d14..b9c858a8d 100644 --- a/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp +++ b/src/duckdb/src/include/duckdb/execution/index/fixed_size_buffer.hpp @@ -89,7 +89,7 @@ class FixedSizeBuffer { //! Pin a buffer (if not in-memory) void Pin(); //! Returns the first free offset in a bitmask - uint32_t GetOffset(const idx_t bitmask_count, const idx_t available_segments); + uint32_t GetOffset(const idx_t bitmask_count); //! Sets the allocation size, if dirty void SetAllocationSize(const idx_t available_segments, const idx_t segment_size, const idx_t bitmask_offset); @@ -102,7 +102,7 @@ class FixedSizeBuffer { private: //! Sets all uninitialized regions of a buffer in the respective partial block allocation void SetUninitializedRegions(PartialBlockForIndex &p_block_for_index, const idx_t segment_size, const idx_t offset, - const idx_t bitmask_offset, const idx_t available_segments); + const idx_t bitmask_offset); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/join_hashtable.hpp b/src/duckdb/src/include/duckdb/execution/join_hashtable.hpp index 441c3ecd8..add3a271f 100644 --- a/src/duckdb/src/include/duckdb/execution/join_hashtable.hpp +++ b/src/duckdb/src/include/duckdb/execution/join_hashtable.hpp @@ -82,14 +82,6 @@ class JoinHashTable { bool finished; bool is_null; - // it records the RHS pointers for the result chunk - Vector rhs_pointers; - // it records the LHS sel vector for the result chunk - SelectionVector lhs_sel_vector; - // these two variable records the last match results - idx_t last_match_count; - SelectionVector last_sel_vector; - explicit ScanStructure(JoinHashTable &ht, TupleDataChunkState &key_state); //! Get the next batch of data from the scan structure void Next(DataChunk &keys, DataChunk &left, DataChunk &result); @@ -122,35 +114,33 @@ class JoinHashTable { idx_t ScanInnerJoin(DataChunk &keys, SelectionVector &result_vector); - //! Update the data chunk compaction buffer - void UpdateCompactionBuffer(idx_t base_count, SelectionVector &result_vector, idx_t result_count); - public: void AdvancePointers(); void AdvancePointers(const SelectionVector &sel, idx_t sel_count); void GatherResult(Vector &result, const SelectionVector &result_vector, const SelectionVector &sel_vector, const idx_t count, const idx_t col_idx); void GatherResult(Vector &result, const SelectionVector &sel_vector, const idx_t count, const idx_t col_idx); - void GatherResult(Vector &result, const idx_t count, const idx_t col_idx); idx_t ResolvePredicates(DataChunk &keys, SelectionVector &match_sel, SelectionVector *no_match_sel); }; public: struct SharedState { + SharedState(); // The ptrs to the row to which a key should be inserted into during building // or matched against during probing Vector rhs_row_locations; - Vector salt_v; SelectionVector salt_match_sel; SelectionVector key_no_match_sel; }; struct ProbeState : SharedState { + ProbeState(); + Vector salt_v; Vector ht_offsets_v; Vector ht_offsets_dense_v; @@ -381,6 +371,14 @@ class JoinHashTable { return radix_bits; } + idx_t GetPartitionStart() const { + return partition_start; + } + + idx_t GetPartitionEnd() const { + return partition_end; + } + //! Capacity of the pointer table given the ht count //! (minimum of 1024 to prevent collision chance for small HT's) static idx_t PointerTableCapacity(idx_t count) { @@ -401,12 +399,6 @@ class JoinHashTable { //! Sets number of radix bits according to the max ht size void SetRepartitionRadixBits(const idx_t max_ht_size, const idx_t max_partition_size, const idx_t max_partition_count); - //! Initialized "current_partitions" and "completed_partitions" - void InitializePartitionMasks(); - //! How many partitions are currently active - idx_t CurrentPartitionCount() const; - //! How many partitions are fully done - idx_t FinishedPartitionCount() const; //! Partition this HT void Repartition(JoinHashTable &global_ht); @@ -415,18 +407,17 @@ class JoinHashTable { //! Build HT for the next partitioned probe round bool PrepareExternalFinalize(const idx_t max_ht_size); //! Probe whatever we can, sink the rest into a thread-local HT - void ProbeAndSpill(ScanStructure &scan_structure, DataChunk &probe_keys, TupleDataChunkState &key_state, - ProbeState &probe_state, DataChunk &probe_chunk, ProbeSpill &probe_spill, + void ProbeAndSpill(ScanStructure &scan_structure, DataChunk &keys, TupleDataChunkState &key_state, + ProbeState &probe_state, DataChunk &payload, ProbeSpill &probe_spill, ProbeSpillLocalAppendState &spill_state, DataChunk &spill_chunk); private: //! The current number of radix bits used to partition idx_t radix_bits; - //! Bits set to 1 for currently active partitions - ValidityMask current_partitions; - //! Bits set to 1 for completed partitions - ValidityMask completed_partitions; + //! First and last partition of the current probe round + idx_t partition_start; + idx_t partition_end; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/merge_sort_tree.hpp b/src/duckdb/src/include/duckdb/execution/merge_sort_tree.hpp index 672aaa56c..b13a8a76f 100644 --- a/src/duckdb/src/include/duckdb/execution/merge_sort_tree.hpp +++ b/src/duckdb/src/include/duckdb/execution/merge_sort_tree.hpp @@ -110,10 +110,6 @@ struct MergeSortTree { return tree[0].first; } - inline const Elements &LowestLevel() const { - return tree[0].first; - } - Elements &Allocate(idx_t count); void Build(); @@ -125,7 +121,7 @@ struct MergeSortTree { } template - void AggregateLowerBound(const idx_t lower, const idx_t upper, const E needle, L aggregate) const; + void AggregateLowerBound(const idx_t lower, const idx_t upper, const idx_t needle, L aggregate) const; Tree tree; CompareElements cmp; @@ -257,7 +253,6 @@ struct MergeSortTree { return level; } -public: void Print() const { std::ostringstream out; const char *separator = " "; @@ -571,7 +566,7 @@ idx_t MergeSortTree::SelectNth(const SubFrames &frames, idx_t n template template -void MergeSortTree::AggregateLowerBound(const idx_t lower, const idx_t upper, const E needle, +void MergeSortTree::AggregateLowerBound(const idx_t lower, const idx_t upper, const idx_t needle, L aggregate) const { if (lower >= upper) { @@ -638,7 +633,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons // Search based on cascading info from previous level const auto *search_begin = level_data + cascading_idcs[cascading_idx.first]; const auto *search_end = level_data + cascading_idcs[cascading_idx.first + FANOUT]; - const auto run_pos = std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data; + const auto run_pos = std::lower_bound(search_begin, search_end, needle) - level_data; // Compute runBegin and pass it to our callback const auto run_begin = curr.first - level_width; aggregate(level, run_begin, NumericCast(run_pos)); @@ -650,7 +645,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons if (curr.first != lower) { const auto *search_begin = level_data + cascading_idcs[cascading_idx.first]; const auto *search_end = level_data + cascading_idcs[cascading_idx.first + FANOUT]; - auto idx = NumericCast(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data); + auto idx = NumericCast(std::lower_bound(search_begin, search_end, needle) - level_data); cascading_idx.first = (idx / CASCADING + 2 * (lower / level_width)) * FANOUT; } @@ -660,7 +655,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons // Search based on cascading info from previous level const auto *search_begin = level_data + cascading_idcs[cascading_idx.second]; const auto *search_end = level_data + cascading_idcs[cascading_idx.second + FANOUT]; - const auto run_pos = std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data; + const auto run_pos = std::lower_bound(search_begin, search_end, needle) - level_data; // Compute runBegin and pass it to our callback const auto run_begin = curr.second; aggregate(level, run_begin, NumericCast(run_pos)); @@ -672,7 +667,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons if (curr.second != upper) { const auto *search_begin = level_data + cascading_idcs[cascading_idx.second]; const auto *search_end = level_data + cascading_idcs[cascading_idx.second + FANOUT]; - auto idx = NumericCast(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data); + auto idx = NumericCast(std::lower_bound(search_begin, search_end, needle) - level_data); cascading_idx.second = (idx / CASCADING + 2 * (upper / level_width)) * FANOUT; } } while (level >= LowestCascadingLevel()); @@ -688,7 +683,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons const auto *search_end = level_data + curr.first; const auto *search_begin = search_end - level_width; const auto run_pos = - NumericCast(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data); + NumericCast(std::lower_bound(search_begin, search_end, needle) - level_data); const auto run_begin = NumericCast(search_begin - level_data); aggregate(level, run_begin, run_pos); curr.first -= level_width; @@ -698,7 +693,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons const auto *search_begin = level_data + curr.second; const auto *search_end = search_begin + level_width; const auto run_pos = - NumericCast(std::lower_bound(search_begin, search_end, needle, cmp.cmp) - level_data); + NumericCast(std::lower_bound(search_begin, search_end, needle) - level_data); const auto run_begin = NumericCast(search_begin - level_data); aggregate(level, run_begin, run_pos); curr.second += level_width; @@ -714,7 +709,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons while (lower_it != curr.first) { const auto *search_begin = level_data + lower_it; const auto run_begin = lower_it; - const auto run_pos = run_begin + cmp.cmp(*search_begin, needle); + const auto run_pos = run_begin + (*search_begin < needle); aggregate(level, run_begin, run_pos); ++lower_it; } @@ -722,7 +717,7 @@ void MergeSortTree::AggregateLowerBound(const idx_t lower, cons while (curr.second != upper) { const auto *search_begin = level_data + curr.second; const auto run_begin = curr.second; - const auto run_pos = run_begin + cmp.cmp(*search_begin, needle); + const auto run_pos = run_begin + (*search_begin < needle); aggregate(level, run_begin, run_pos); ++curr.second; } diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp index 195d1fb99..9f04e1b9d 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp @@ -93,7 +93,7 @@ class PhysicalHashAggregate : public PhysicalOperator { GlobalSourceState &gstate) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; bool IsSource() const override { return true; diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp deleted file mode 100644 index 071a82ed1..000000000 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp +++ /dev/null @@ -1,70 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/execution/operator/aggregate/physical_partitioned_aggregate.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/execution/physical_operator.hpp" -#include "duckdb/planner/expression.hpp" -#include "duckdb/execution/operator/aggregate/grouped_aggregate_data.hpp" -#include "duckdb/parser/group_by_node.hpp" -#include "duckdb/execution/radix_partitioned_hashtable.hpp" -#include "duckdb/common/unordered_map.hpp" - -namespace duckdb { - -//! PhysicalPartitionedAggregate is an aggregate operator that can only perform aggregates on data that is partitioned -// by the grouping columns -class PhysicalPartitionedAggregate : public PhysicalOperator { -public: - static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::PARTITIONED_AGGREGATE; - -public: - PhysicalPartitionedAggregate(ClientContext &context, vector types, - vector> expressions, vector> groups, - vector partitions, idx_t estimated_cardinality); - - //! The partitions over which this is grouped - vector partitions; - //! The groups over which the aggregate is partitioned - note that this is only - vector> groups; - //! The aggregates that have to be computed - vector> aggregates; - -public: - // Source interface - SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - unique_ptr GetGlobalSourceState(ClientContext &context) const override; - - bool IsSource() const override { - return true; - } - -public: - // Sink interface - SinkResultType Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const override; - SinkCombineResultType Combine(ExecutionContext &context, OperatorSinkCombineInput &input) const override; - SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, - OperatorSinkFinalizeInput &input) const override; - SinkNextBatchType NextBatch(ExecutionContext &context, OperatorSinkNextBatchInput &input) const override; - - unique_ptr GetLocalSinkState(ExecutionContext &context) const override; - unique_ptr GetGlobalSinkState(ClientContext &context) const override; - - InsertionOrderPreservingMap ParamsToString() const override; - - OperatorPartitionInfo RequiredPartitionInfo() const override; - bool IsSink() const override { - return true; - } - - bool ParallelSink() const override { - return true; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp index cd7d2a64a..0f3937566 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_ungrouped_aggregate.hpp @@ -18,7 +18,8 @@ namespace duckdb { -//! PhysicalUngroupedAggregate is an aggregate operator that can only perform aggregates without any groups +//! PhysicalUngroupedAggregate is an aggregate operator that can only perform aggregates (1) without any groups, (2) +//! without any DISTINCT aggregates, and (3) when all aggregates are combineable class PhysicalUngroupedAggregate : public PhysicalOperator { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::UNGROUPED_AGGREGATE; diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp index 5a485bca7..b1fb6e9ae 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_window.hpp @@ -37,9 +37,8 @@ class PhysicalWindow : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const override; + idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate) const override; bool IsSource() const override { return true; @@ -48,10 +47,10 @@ class PhysicalWindow : public PhysicalOperator { return true; } - bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override; + bool SupportsBatchIndex() const override; OrderPreservationType SourceOrder() const override; - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const override; public: // Sink interface diff --git a/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp index cf1b13c55..0f18a169e 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/aggregate/ungrouped_aggregate_state.hpp @@ -11,7 +11,6 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/aggregate_function.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" namespace duckdb { struct DistinctAggregateData; @@ -57,7 +56,7 @@ struct GlobalUngroupedAggregateState { ArenaAllocator &CreateAllocator() const; void Combine(LocalUngroupedAggregateState &other); void CombineDistinct(LocalUngroupedAggregateState &other, DistinctAggregateData &distinct_data); - void Finalize(DataChunk &result, idx_t column_offset = 0); + void Finalize(DataChunk &result); }; struct LocalUngroupedAggregateState { @@ -73,23 +72,4 @@ struct LocalUngroupedAggregateState { void Sink(DataChunk &payload_chunk, idx_t payload_idx, idx_t aggr_idx); }; -struct UngroupedAggregateExecuteState { -public: - UngroupedAggregateExecuteState(ClientContext &context, const vector> &aggregates, - const vector &child_types); - - //! The set of aggregates - const vector> &aggregates; - //! The executor - ExpressionExecutor child_executor; - //! The payload chunk, containing all the Vectors for the aggregates - DataChunk aggregate_input_chunk; - //! Aggregate filter data set - AggregateFilterDataSet filter_set; - -public: - void Sink(LocalUngroupedAggregateState &state, DataChunk &input); - void Reset(); -}; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp index 93b8bf9ac..8a10868d7 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/base_scanner.hpp @@ -21,23 +21,13 @@ class ScannerResult { public: ScannerResult(CSVStates &states, CSVStateMachine &state_machine, idx_t result_size); + //! Adds a Value to the result static inline void SetQuoted(ScannerResult &result, idx_t quoted_position) { if (!result.quoted) { result.quoted_position = quoted_position; } result.quoted = true; - result.unquoted = true; } - - static inline void SetUnquoted(ScannerResult &result) { - if (result.states.states[0] == CSVState::UNQUOTED && result.states.states[1] == CSVState::UNQUOTED && - result.state_machine.dialect_options.state_machine_options.escape != '\0') { - // This means we touched an unescaped quote, we must go through the remove escape code to remove it. - result.escaped = true; - } - result.quoted = true; - } - static inline void SetEscaped(ScannerResult &result) { result.escaped = true; } @@ -54,11 +44,8 @@ class ScannerResult { //! Variable to keep information regarding quoted and escaped values bool quoted = false; - //! If the current quoted value is unquoted - bool unquoted = false; - //! If the current value has been escaped bool escaped = false; - //! Variable to keep track if we are in a comment row. Hence, won't add it + //! Variable to keep track if we are in a comment row. Hence won't add it bool comment = false; idx_t quoted_position = 0; @@ -127,8 +114,6 @@ class BaseScanner { bool ever_quoted = false; - bool ever_escaped = false; - //! Shared pointer to the buffer_manager, this is shared across multiple scanners shared_ptr buffer_manager; @@ -137,10 +122,6 @@ class BaseScanner { static CSVIterator SkipCSVRows(shared_ptr buffer_manager, const shared_ptr &state_machine, idx_t rows_to_skip); - inline static bool ContainsZeroByte(uint64_t v) { - return (v - UINT64_C(0x0101010101010101)) & ~(v)&UINT64_C(0x8080808080808080); - } - protected: //! Boundaries of this scanner CSVIterator iterator; @@ -161,11 +142,14 @@ class BaseScanner { //! Initializes the scanner virtual void Initialize(); + inline static bool ContainsZeroByte(uint64_t v) { + return (v - UINT64_C(0x0101010101010101)) & ~(v)&UINT64_C(0x8080808080808080); + } + //! Process one chunk template void Process(T &result) { idx_t to_pos; - const bool has_escaped_value = state_machine->dialect_options.state_machine_options.escape != '\0'; const idx_t start_pos = iterator.pos.buffer_pos; if (iterator.IsBoundarySet()) { to_pos = iterator.GetEndPos(); @@ -246,15 +230,14 @@ class BaseScanner { iterator.pos.buffer_pos++; break; case CSVState::QUOTED: { - if ((states.states[0] == CSVState::UNQUOTED || states.states[0] == CSVState::MAYBE_QUOTED) && - has_escaped_value) { + if (states.states[0] == CSVState::UNQUOTED) { T::SetEscaped(result); } ever_quoted = true; T::SetQuoted(result, iterator.pos.buffer_pos); iterator.pos.buffer_pos++; while (iterator.pos.buffer_pos + 8 < to_pos) { - const uint64_t value = + uint64_t value = Load(reinterpret_cast(&buffer_handle_ptr[iterator.pos.buffer_pos])); if (ContainsZeroByte((value ^ state_machine->transition_array.quote) & (value ^ state_machine->transition_array.escape))) { @@ -269,19 +252,8 @@ class BaseScanner { iterator.pos.buffer_pos++; } } break; - case CSVState::UNQUOTED: { - if (states.states[0] == CSVState::MAYBE_QUOTED) { - T::SetEscaped(result); - } - T::SetUnquoted(result); - iterator.pos.buffer_pos++; - break; - } case CSVState::ESCAPE: - case CSVState::UNQUOTED_ESCAPE: - case CSVState::ESCAPED_RETURN: T::SetEscaped(result); - ever_escaped = true; iterator.pos.buffer_pos++; break; case CSVState::STANDARD: { @@ -292,7 +264,6 @@ class BaseScanner { if (ContainsZeroByte((value ^ state_machine->transition_array.delimiter) & (value ^ state_machine->transition_array.new_line) & (value ^ state_machine->transition_array.carriage_return) & - (value ^ state_machine->transition_array.escape) & (value ^ state_machine->transition_array.comment))) { break; } @@ -313,7 +284,7 @@ class BaseScanner { T::SetComment(result, iterator.pos.buffer_pos); iterator.pos.buffer_pos++; while (iterator.pos.buffer_pos + 8 < to_pos) { - const uint64_t value = + uint64_t value = Load(reinterpret_cast(&buffer_handle_ptr[iterator.pos.buffer_pos])); if (ContainsZeroByte((value ^ state_machine->transition_array.new_line) & (value ^ state_machine->transition_array.carriage_return))) { diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp index 99ce3c5ba..7b86f238f 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer.hpp @@ -55,10 +55,10 @@ class CSVBuffer { shared_ptr Next(CSVFileHandle &file_handle, idx_t buffer_size, idx_t file_number, bool &has_seaked); //! Gets the buffer actual size - idx_t GetBufferSize() const; + idx_t GetBufferSize(); //! If this buffer is the last buffer of the CSV File - bool IsCSVFileLastBuffer() const; + bool IsCSVFileLastBuffer(); //! Allocates internal buffer, sets 'block' and 'handle' variables. void AllocateBuffer(idx_t buffer_size); @@ -72,14 +72,15 @@ class CSVBuffer { char *Ptr() { return char_ptr_cast(handle.Ptr()); } - bool IsUnloaded() { - return block->IsUnloaded(); - } //! By default, we use CSV_BUFFER_SIZE to allocate each buffer - static constexpr idx_t ROWS_PER_BUFFER = 16; - static constexpr idx_t MIN_ROWS_PER_BUFFER = 4; - + //! TODO: Should benchmarks other values + static constexpr idx_t CSV_BUFFER_SIZE = 32000000; // 32MB + //! In case the file has a size < 32MB, we will use this size instead + //! This is to avoid mallocing a lot of memory for a small file + //! And if it's a compressed file we can't use the actual size of the file + static constexpr idx_t CSV_MINIMUM_BUFFER_SIZE = 8000000; // 8MB + //! If this is the last buffer of the CSV File bool last_buffer = false; private: diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp index 6c9674229..5bcf0af65 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_buffer_manager.hpp @@ -22,9 +22,7 @@ class CSVStateMachine; class CSVBufferManager { public: CSVBufferManager(ClientContext &context, const CSVReaderOptions &options, const string &file_path, - const idx_t file_idx, bool per_file_single_threaded = false, - unique_ptr file_handle = nullptr); - + const idx_t file_idx, bool per_file_single_threaded = false); //! Returns a buffer from a buffer id (starting from 0). If it's in the auto-detection then we cache new buffers //! Otherwise we remove them from the cache if they are already there, or just return them bypassing the cache. shared_ptr GetBuffer(const idx_t buffer_idx); @@ -47,10 +45,6 @@ class CSVBufferManager { void ResetBufferManager(); string GetFilePath() const; - bool IsBlockUnloaded(idx_t block_idx); - - idx_t GetBytesRead() const; - ClientContext &context; idx_t skip_rows = 0; bool sniffing = false; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_error.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_error.hpp index a31fd6190..2c254e265 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_error.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_error.hpp @@ -17,12 +17,9 @@ #include "duckdb/execution/operator/csv_scanner/header_value.hpp" namespace duckdb { -class InternalAppender; -class CSVFileScan; -class CSVRejectsTable; -struct ReadCSVData; //! Object that holds information on how many lines each csv batch read. + class LinesPerBoundary { public: LinesPerBoundary(); @@ -30,6 +27,13 @@ class LinesPerBoundary { idx_t boundary_idx = 0; idx_t lines_in_batch = 0; + + bool operator<(const LinesPerBoundary &other) const { + if (boundary_idx < other.boundary_idx) { + return true; + } + return lines_in_batch < other.lines_in_batch; + } }; enum CSVErrorType : uint8_t { @@ -41,8 +45,7 @@ enum CSVErrorType : uint8_t { SNIFFING = 5, //! If something went wrong during sniffing and was not possible to find suitable candidates MAXIMUM_LINE_SIZE = 6, //! Maximum line size was exceeded by a line in the CSV File NULLPADDED_QUOTED_NEW_VALUE = 7, //! If the null_padding option is set, and we have quoted new values in parallel - INVALID_UNICODE = 8, //! If we have invalid unicode values - INVALID_STATE = 9 //! If our CSV Scanner ended up in an invalid state + INVALID_UNICODE = 8 //! If we have invalid unicode values }; class CSVError { @@ -59,22 +62,18 @@ class CSVError { idx_t column_idx, string &csv_row, LinesPerBoundary error_info, idx_t row_byte_position, optional_idx byte_position, LogicalTypeId type, const string ¤t_path); //! Produces error for when the line size exceeds the maximum line size option - static CSVError LineSizeError(const CSVReaderOptions &options, LinesPerBoundary error_info, string &csv_row, - idx_t byte_position, const string ¤t_path); - //! Produces error for when the state machine reaches an invalid state - static CSVError InvalidState(const CSVReaderOptions &options, idx_t current_column, LinesPerBoundary error_info, - string &csv_row, idx_t row_byte_position, optional_idx byte_position, - const string ¤t_path); + static CSVError LineSizeError(const CSVReaderOptions &options, idx_t actual_size, LinesPerBoundary error_info, + string &csv_row, idx_t byte_position, const string ¤t_path); //! Produces an error message for a dialect sniffing error. static CSVError SniffingError(const CSVReaderOptions &options, const string &search_space); //! Produces an error message for a header sniffing error. static CSVError HeaderSniffingError(const CSVReaderOptions &options, const vector &best_header_row, - idx_t column_count, const string &delimiter); + idx_t column_count, char delimiter); //! Produces error messages for unterminated quoted values static CSVError UnterminatedQuotesError(const CSVReaderOptions &options, idx_t current_column, LinesPerBoundary error_info, string &csv_row, idx_t row_byte_position, optional_idx byte_position, const string ¤t_path); - //! Produces error messages for null_padding option is set, and we have quoted new values in parallel + //! Produces error messages for null_padding option is set and we have quoted new values in parallel static CSVError NullPaddingFail(const CSVReaderOptions &options, LinesPerBoundary error_info, const string ¤t_path); //! Produces error for incorrect (e.g., smaller and lower than the predefined) number of columns in a CSV Line @@ -117,27 +116,24 @@ class CSVErrorHandler { public: explicit CSVErrorHandler(bool ignore_errors = false); //! Throws the error - void Error(const CSVError &csv_error, bool force_error = false); + void Error(CSVError csv_error, bool force_error = false); //! If we have a cached error, and we can now error, we error. void ErrorIfNeeded(); - //! Throws an error if a given type exists - void ErrorIfTypeExists(CSVErrorType error_type); //! Inserts a finished error info void Insert(idx_t boundary_idx, idx_t rows); idx_t GetLine(const LinesPerBoundary &error_info); void NewMaxLineSize(idx_t scan_line_size); //! Returns true if there are any errors bool AnyErrors(); - bool HasError(CSVErrorType error_type); - idx_t GetMaxLineLength(); - - void DontPrintErrorLine(); - - void SetIgnoreErrors(bool ignore_errors); - idx_t GetSize(); + //! Set of errors + map> errors; - void FillRejectsTable(InternalAppender &errors_appender, idx_t file_idx, idx_t scan_idx, const CSVFileScan &file, - CSVRejectsTable &rejects, const ReadCSVData &bind_data, idx_t limit); + idx_t GetMaxLineLength() const { + return max_line_length; + } + void DontPrintErrorLine() { + print_line = false; + } private: //! Private methods should always be locked by parent method. @@ -156,8 +152,6 @@ class CSVErrorHandler { idx_t max_line_length = 0; bool ignore_errors = false; bool print_line = true; - //! Set of errors - vector errors; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_handle.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_handle.hpp index c124bf092..58aac7b53 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_handle.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_handle.hpp @@ -12,29 +12,28 @@ #include "duckdb/common/mutex.hpp" #include "duckdb/common/helper.hpp" #include "duckdb/common/allocator.hpp" -#include "duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp" + namespace duckdb { class Allocator; class FileSystem; -struct CSVReaderOptions; -class CSVFileHandle { +struct CSVFileHandle { public: - CSVFileHandle(DBConfig &config, unique_ptr file_handle_p, const string &path_p, - const CSVReaderOptions &options); + CSVFileHandle(FileSystem &fs, Allocator &allocator, unique_ptr file_handle_p, const string &path_p, + FileCompressionType compression); mutex main_mutex; - bool CanSeek() const; - void Seek(idx_t position) const; - bool OnDiskFile() const; - bool IsPipe() const; + bool CanSeek(); + void Seek(idx_t position); + bool OnDiskFile(); + bool IsPipe(); void Reset(); - idx_t FileSize() const; + idx_t FileSize(); - bool FinishedReading() const; + bool FinishedReading(); idx_t Read(void *buffer, idx_t nr_bytes); @@ -44,15 +43,14 @@ class CSVFileHandle { static unique_ptr OpenFileHandle(FileSystem &fs, Allocator &allocator, const string &path, FileCompressionType compression); - static unique_ptr OpenFile(DBConfig &config, FileSystem &fs, Allocator &allocator, - const string &path, const CSVReaderOptions &options); + static unique_ptr OpenFile(FileSystem &fs, Allocator &allocator, const string &path, + FileCompressionType compression); FileCompressionType compression_type; - double GetProgress() const; + double GetProgress(); private: unique_ptr file_handle; - CSVEncoder encoder; string path; bool can_seek = false; bool on_disk_file = false; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp index 3ebc88ff3..09c7b6a82 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp @@ -42,11 +42,11 @@ class CSVFileScan { //! This means the options are alreadu set, and the buffer manager is already up and runinng. CSVFileScan(ClientContext &context, shared_ptr buffer_manager, shared_ptr state_machine, const CSVReaderOptions &options, - const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema); + const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema); //! Constructor for new CSV Files, we must initialize the buffer manager and the state machine //! Path to this file - CSVFileScan(ClientContext &context, const string &file_path, const CSVReaderOptions &options, idx_t file_idx, - const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema, + CSVFileScan(ClientContext &context, const string &file_path, const CSVReaderOptions &options, const idx_t file_idx, + const ReadCSVData &bind_data, const vector &column_ids, CSVSchema &file_schema, bool per_file_single_threaded); CSVFileScan(ClientContext &context, const string &file_name, const CSVReaderOptions &options); diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_option.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_option.hpp index 90ef7943f..52cd26878 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_option.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_option.hpp @@ -32,7 +32,6 @@ struct CSVOption { // NOLINT: work-around bug in clang-tidy } CSVOption(T value_p, bool set_by_user_p) : value(value_p), set_by_user(set_by_user_p) { } - CSVOption() {}; //! Sets value. @@ -78,7 +77,7 @@ struct CSVOption { // NOLINT: work-around bug in clang-tidy return value != other; } //! Returns CSV Option value - inline const T &GetValue() const { + inline const T GetValue() const { return value; } bool IsSetByUser() const { diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp index 4e0ee86fd..fe05ff653 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_reader_options.hpp @@ -24,7 +24,7 @@ struct DialectOptions { CSVStateMachineOptions state_machine_options; //! Expected number of columns idx_t num_cols = 0; - //! Whether the file has a header line + //! Whether or not the file has a header line CSVOption header = false; //! The date format to use (if any is specified) map> date_format = {{LogicalTypeId::DATE, {}}, @@ -35,8 +35,6 @@ struct DialectOptions { }; struct CSVReaderOptions { - CSVReaderOptions() {}; - CSVReaderOptions(CSVOption single_byte_delimiter, const CSVOption &multi_byte_delimiter); //===--------------------------------------------------------------------===// // CommonCSVOptions //===--------------------------------------------------------------------===// @@ -61,7 +59,7 @@ struct CSVReaderOptions { FileCompressionType compression = FileCompressionType::AUTO_DETECT; //! Option to convert quoted values to NULL values bool allow_quoted_nulls = true; - char comment = '\0'; + char comment; //===--------------------------------------------------------------------===// // CSVAutoOptions @@ -74,7 +72,7 @@ struct CSVReaderOptions { vector name_list; //! If the names and types were set by the columns parameter bool columns_set = false; - //! Types considered as candidates for auto-detection ordered by descending specificity (~ from high to low) + //! Types considered as candidates for auto detection ordered by descending specificity (~ from high to low) vector auto_type_candidates = {LogicalType::VARCHAR, LogicalType::DOUBLE, LogicalType::BIGINT, LogicalType::TIMESTAMP, LogicalType::DATE, LogicalType::TIME, LogicalType::BOOLEAN, LogicalType::SQLNULL}; @@ -87,9 +85,8 @@ struct CSVReaderOptions { //===--------------------------------------------------------------------===// //! Maximum CSV line size: specified because if we reach this amount, we likely have wrong delimiters (default: 2MB) //! note that this is the guaranteed line length that will succeed, longer lines may be accepted if slightly above - static constexpr idx_t max_line_size_default = 2000000; - CSVOption maximum_line_size = max_line_size_default; - //! Whether header names shall be normalized + idx_t maximum_line_size = 2097152; + //! Whether or not header names shall be normalized bool normalize_names = false; //! True, if column with that index must skip null check unordered_set force_not_null_names; @@ -97,28 +94,25 @@ struct CSVReaderOptions { vector force_not_null; //! Result size of sniffing phases static constexpr idx_t sniff_size = 2048; - //! Number of sample chunks used in auto-detection idx_t sample_size_chunks = 20480 / sniff_size; //! Consider all columns to be of type varchar bool all_varchar = false; - //! Whether to automatically detect dialect and datatypes + //! Whether or not to automatically detect dialect and datatypes bool auto_detect = true; //! The file path of the CSV file to read string file_path; //! Multi-file reader options MultiFileReaderOptions file_options; //! Buffer Size (Parallel Scan) - CSVOption buffer_size_option = CSVBuffer::ROWS_PER_BUFFER * max_line_size_default; + idx_t buffer_size = CSVBuffer::CSV_BUFFER_SIZE; //! Decimal separator when reading as numeric string decimal_separator = "."; - //! Whether to pad rows that do not have enough columns with NULL values + //! Whether or not to pad rows that do not have enough columns with NULL values bool null_padding = false; //! If we should attempt to run parallel scanning over one file bool parallel = true; - //! By default, our encoding is always UTF-8 - string encoding = "utf-8"; //! User defined parameters for the csv function concatenated on a string string user_defined_parameters; @@ -134,10 +128,8 @@ struct CSVReaderOptions { //! The date format to use for writing (if any is specified) map write_date_format = {{LogicalTypeId::DATE, Value()}, {LogicalTypeId::TIMESTAMP, Value()}}; - //! Whether a type format is specified + //! Whether or not a type format is specified map has_format = {{LogicalTypeId::DATE, false}, {LogicalTypeId::TIMESTAMP, false}}; - //! If this reader is a multifile reader - bool multi_file_reader = false; void Serialize(Serializer &serializer) const; static CSVReaderOptions Deserialize(Deserializer &deserializer); @@ -151,6 +143,7 @@ struct CSVReaderOptions { void SetEscape(const string &escape); idx_t GetSkipRows() const; + void SetSkipRows(int64_t rows); void SetQuote(const string "e); @@ -165,13 +158,6 @@ struct CSVReaderOptions { string GetNewline() const; void SetNewline(const string &input); - - bool GetRFC4180() const; - void SetRFC4180(bool rfc4180); - - char GetSingleByteDelimiter() const; - string GetMultiByteDelimiter() const; - //! Set an option that is supported by both reading and writing functions, called by //! the SetReadOption and SetWriteOption methods bool SetBaseOption(const string &loption, const Value &value, bool write_option = false); diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_schema.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_schema.hpp index 3e7a90c99..39e1b809a 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_schema.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_schema.hpp @@ -22,50 +22,15 @@ struct CSVColumnInfo { //! Basic CSV Schema struct CSVSchema { - explicit CSVSchema(const bool empty = false) : empty(empty) { - } - - CSVSchema(vector &names, vector &types, const string &file_path, idx_t rows_read, - const bool empty = false); - - //! Initializes the schema based on names and types - void Initialize(const vector &names, const vector &types, const string &file_path); - - //! If the schema is empty + void Initialize(vector &names, vector &types, const string &file_path); bool Empty() const; - - //! If the columns of the schema match - bool MatchColumns(const CSVSchema &other) const; - - //! We merge two schemas by ensuring that the column types are compatible between both - void MergeSchemas(CSVSchema &other, bool null_padding); - - //! What's the file path for the file that generated this schema - string GetPath() const; - - //! How many columns we have in this schema - idx_t GetColumnCount() const; - - //! Check if two schemas match. bool SchemasMatch(string &error_message, SnifferResult &sniffer_result, const string &cur_file_path, bool is_minimal_sniffer) const; - //! How many rows were read when generating this schema, this is only used for sniffing during the binder - idx_t GetRowsRead() const; - - //! Get a vector with names - vector GetNames() const; - - //! Get a vector with types - vector GetTypes() const; - private: - //! If a type can be cast to another static bool CanWeCastIt(LogicalTypeId source, LogicalTypeId destination); vector columns; unordered_map name_idx_map; string file_path; - idx_t rows_read = 0; - bool empty = false; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp index 017ccfe39..ecb40e440 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state.hpp @@ -14,26 +14,18 @@ namespace duckdb { //! All States of CSV Parsing enum class CSVState : uint8_t { - STANDARD = 0, //! Regular unquoted field state - DELIMITER = 1, //! State after encountering a field separator (e.g., ;) - This is always the last delimiter byte - //! ------------- Multi-byte Delimiter States (up to 4 bytes) ----------------------------------------------!// - DELIMITER_FIRST_BYTE = 2, //! State when encountering the first delimiter byte of a multi-byte delimiter - DELIMITER_SECOND_BYTE = 3, //! State when encountering the second delimiter byte of a multi-byte delimiter - DELIMITER_THIRD_BYTE = 4, //! State when encountering the third delimiter byte of a multi-byte delimiter - //! --------------------------------------------------------------------------------------------------------!// - RECORD_SEPARATOR = 5, //! State after encountering a record separator (i.e., \n) - CARRIAGE_RETURN = 6, //! State after encountering a carriage return(i.e., \r) - QUOTED = 7, //! State when inside a quoted field - UNQUOTED = 8, //! State when leaving a quoted field - ESCAPE = 9, //! State when encountering an escape character (e.g., \) - INVALID = 10, //! Got to an Invalid State, this should error. - NOT_SET = 11, //! If the state is not set, usually the first state before getting the first character - QUOTED_NEW_LINE = 12, //! If we have a quoted newline - EMPTY_SPACE = 13, //! If we have empty spaces in the beginning and end of value - COMMENT = 14, //! If we are in a comment state, and hence have to skip the whole line - STANDARD_NEWLINE = 15, //! State used for figuring out a new line. - UNQUOTED_ESCAPE = 16, //! State when encountering an escape character (e.g., \) in an unquoted field - ESCAPED_RETURN = 17, //! State when the carriage return is preceded by an escape character (for '\r\n' newline only) - MAYBE_QUOTED = 18 //! We are potentially in a quoted value or the end of an unquoted value + STANDARD = 0, //! Regular unquoted field state + DELIMITER = 1, //! State after encountering a field separator (e.g., ;) + RECORD_SEPARATOR = 2, //! State after encountering a record separator (i.e., \n) + CARRIAGE_RETURN = 3, //! State after encountering a carriage return(i.e., \r) + QUOTED = 4, //! State when inside a quoted field + UNQUOTED = 5, //! State when leaving a quoted field + ESCAPE = 6, //! State when encountering an escape character (e.g., \) + INVALID = 7, //! Got to an Invalid State, this should error. + NOT_SET = 8, //! If the state is not set, usually the first state before getting the first character + QUOTED_NEW_LINE = 9, //! If we have a quoted newline + EMPTY_SPACE = 10, //! If we have empty spaces in the beginning and end of value + COMMENT = 11 //! If we are in a comment state, and hence have to skip the whole line }; + } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp index 71eb1c11e..13933a180 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine.hpp @@ -17,94 +17,64 @@ namespace duckdb { //! State of necessary CSV States to parse file //! Current, previous, and state before the previous struct CSVStates { - void Initialize(CSVState initial_state = CSVState::NOT_SET) { - states[0] = initial_state; - states[1] = initial_state; + void Initialize() { + states[0] = CSVState::NOT_SET; + states[1] = CSVState::NOT_SET; } - inline bool NewValue() const { + inline bool NewValue() { return states[1] == CSVState::DELIMITER; } - inline bool NewRow() const { + inline bool NewRow() { // It is a new row, if the previous state is not a record separator, and the current one is return states[0] != CSVState::RECORD_SEPARATOR && states[0] != CSVState::CARRIAGE_RETURN && (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN); } - inline bool WasStandard() const { + inline bool WasStandard() { return states[0] == CSVState::STANDARD; } - inline bool EmptyLastValue() const { + inline bool EmptyLastValue() { // It is a new row, if the previous state is not a record separator, and the current one is - return (states[0] == CSVState::DELIMITER && - (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN || - states[1] == CSVState::DELIMITER)) || - (states[0] == CSVState::STANDARD && states[1] == CSVState::DELIMITER); + return states[0] == CSVState::DELIMITER && + (states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN || + states[1] == CSVState::DELIMITER); } - inline bool EmptyLine() const { + inline bool EmptyLine() { return (states[1] == CSVState::CARRIAGE_RETURN || states[1] == CSVState::RECORD_SEPARATOR) && (states[0] == CSVState::RECORD_SEPARATOR || states[0] == CSVState::NOT_SET); } - inline bool IsDelimiterBytes() const { - return states[0] == CSVState::DELIMITER_FIRST_BYTE || states[0] == CSVState::DELIMITER_SECOND_BYTE || - states[0] == CSVState::DELIMITER_THIRD_BYTE; - } - - inline bool IsDelimiter() const { - return states[1] == CSVState::DELIMITER; - } - - inline bool IsNotSet() const { + inline bool IsNotSet() { return states[1] == CSVState::NOT_SET; } - inline bool IsComment() const { + inline bool IsComment() { return states[1] == CSVState::COMMENT; } - inline bool IsCurrentNewRow() const { + inline bool IsCurrentNewRow() { return states[1] == CSVState::RECORD_SEPARATOR || states[1] == CSVState::CARRIAGE_RETURN; } - inline bool IsCarriageReturn() const { + inline bool IsCarriageReturn() { return states[1] == CSVState::CARRIAGE_RETURN; } - inline bool IsInvalid() const { + inline bool IsInvalid() { return states[1] == CSVState::INVALID; } - inline bool IsQuoted() const { + inline bool IsQuoted() { return states[0] == CSVState::QUOTED; } - inline bool IsUnquoted() const { - return states[0] == CSVState::UNQUOTED; - } - inline bool IsEscaped() const { - switch (states[1]) { - case CSVState::ESCAPE: - case CSVState::UNQUOTED_ESCAPE: - case CSVState::ESCAPED_RETURN: - return true; - case CSVState::QUOTED: - return states[0] == CSVState::UNQUOTED || states[0] == CSVState::MAYBE_QUOTED; - case CSVState::UNQUOTED: - return states[0] == CSVState::MAYBE_QUOTED; - default: - return false; - } - } - inline bool IsQuotedCurrent() const { - return states[1] == CSVState::QUOTED || states[1] == CSVState::QUOTED_NEW_LINE; - } - inline bool IsState(const CSVState state) const { - return states[1] == state; + inline bool IsEscaped() { + return states[1] == CSVState::ESCAPE || (states[0] == CSVState::UNQUOTED && states[1] == CSVState::QUOTED); } - inline bool WasState(const CSVState state) const { - return states[0] == state; + inline bool IsQuotedCurrent() { + return states[1] == CSVState::QUOTED || states[1] == CSVState::QUOTED_NEW_LINE; } CSVState states[2]; }; @@ -128,7 +98,7 @@ class CSVStateMachine { states.states[1] = transition_array[static_cast(current_char)][static_cast(states.states[1])]; } - void Print() const { + void Print() { std::cout << "State Machine Options" << '\n'; std::cout << "Delim: " << state_machine_options.delimiter.GetValue() << '\n'; std::cout << "Quote: " << state_machine_options.quote.GetValue() << '\n'; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp index 2980370d5..decf46d46 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_state_machine_cache.hpp @@ -19,7 +19,7 @@ namespace duckdb { //! Class to wrap the state machine matrix class StateMachine { public: - static constexpr uint32_t NUM_STATES = 19; + static constexpr uint32_t NUM_STATES = 13; static constexpr uint32_t NUM_TRANSITIONS = 256; CSVState state_machine[NUM_TRANSITIONS][NUM_STATES]; //! Transitions where we might skip processing @@ -37,11 +37,11 @@ class StateMachine { uint64_t escape = 0; uint64_t comment = 0; - const CSVState *operator[](const idx_t i) const { + const CSVState *operator[](idx_t i) const { return state_machine[i]; } - CSVState *operator[](const idx_t i) { + CSVState *operator[](idx_t i) { return state_machine[i]; } }; @@ -49,7 +49,7 @@ class StateMachine { //! Hash function used in out state machine cache, it hashes and combines all options used to generate a state machine struct HashCSVStateMachineConfig { size_t operator()(CSVStateMachineOptions const &config) const noexcept { - auto h_delimiter = Hash(config.delimiter.GetValue().c_str()); + auto h_delimiter = Hash(config.delimiter.GetValue()); auto h_quote = Hash(config.quote.GetValue()); auto h_escape = Hash(config.escape.GetValue()); auto h_newline = Hash(static_cast(config.new_line.GetValue())); @@ -60,7 +60,7 @@ struct HashCSVStateMachineConfig { //! The CSVStateMachineCache caches state machines, although small ~2kb, the actual creation of multiple State Machines //! can become a bottleneck on sniffing, when reading very small csv files. -//! Hence, the cache stores State Machines based on their different delimiter|quote|escape options. +//! Hence the cache stores State Machines based on their different delimiter|quote|escape options. class CSVStateMachineCache : public ObjectCacheEntry { public: CSVStateMachineCache(); @@ -85,7 +85,7 @@ class CSVStateMachineCache : public ObjectCacheEntry { void Insert(const CSVStateMachineOptions &state_machine_options); //! Cache on delimiter|quote|escape|newline unordered_map state_machine_cache; - //! Default value for options used to initialize CSV State Machine Cache + //! Default value for options used to intialize CSV State Machine Cache //! Because the state machine cache can be accessed in Parallel we need a mutex. mutex main_mutex; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp deleted file mode 100644 index 20d031707..000000000 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/csv_validator.hpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/execution/operator/csv_scanner/csv_validator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/map.hpp" -#include "duckdb/common/typedefs.hpp" -#include "duckdb/common/string.hpp" -#include "duckdb/common/vector.hpp" - -namespace duckdb { - -//! Information used to validate -struct ValidatorLine { - ValidatorLine(idx_t start_pos_p, idx_t end_pos_p) : start_pos(start_pos_p), end_pos(end_pos_p) { - } - const idx_t start_pos; - const idx_t end_pos; -}; - -struct ThreadLines { - ThreadLines() {}; - //! Validate everything is as it should be, returns true if it's all good, false o.w. - void Verify() const; - - void Insert(idx_t thread, ValidatorLine line_info); - - string Print() const; - -private: - map thread_lines; - //! We allow up to 2 bytes of error margin (basically \r\n) - static constexpr idx_t error_margin = 2; -}; - -//! The validator works by double-checking that threads started and ended in the right positions -struct CSVValidator { - CSVValidator() { - } - //! Validate that all files are good - void Verify() const; - - //! Inserts line_info to a given thread index of a given file. - void Insert(idx_t file_idx, idx_t thread, ValidatorLine line_info); - - string Print(idx_t file_idx) const; - -private: - //! Per file thread lines. - vector per_file_thread_lines; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp deleted file mode 100644 index 764d9694d..000000000 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp +++ /dev/null @@ -1,62 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/execution/operator/csv_scanner/encode/csv_encoder.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/common/file_system.hpp" -#include "duckdb/function/encoding_function.hpp" - -namespace duckdb { - -struct DBConfig; - -//! Struct that holds encoder buffers -struct CSVEncoderBuffer { - CSVEncoderBuffer() : encoded_buffer_size(0) {}; - void Initialize(idx_t encoded_buffer_size); - - char *Ptr() const; - - idx_t GetCapacity() const; - - idx_t GetSize() const; - - void SetSize(const idx_t buffer_size); - - bool HasDataToRead() const; - - void Reset(); - idx_t cur_pos = 0; - //! The actual encoded buffer size, from the last file_handle read. - idx_t actual_encoded_buffer_size = 0; - -private: - //! The encoded buffer, we only have one per file, so we cache it and make sure to pass over unused bytes. - std::unique_ptr encoded_buffer; - //! The encoded buffer size is defined as buffer_size/GetRatio() - idx_t encoded_buffer_size; -}; - -class CSVEncoder { -public: - //! Constructor, basically takes an encoding and the output buffer size - CSVEncoder(DBConfig &config, const string &encoding_name, idx_t buffer_size); - //! Main encode function, it reads the file into an encoded buffer and converts it to the output buffer - idx_t Encode(FileHandle &file_handle_input, char *output_buffer, const idx_t decoded_buffer_size); - string encoding_name; - -private: - //! The actual encoded buffer - CSVEncoderBuffer encoded_buffer; - //! Potential remaining bytes - CSVEncoderBuffer remaining_bytes_buffer; - //! Actual Encoding Function - optional_ptr encoding_function; -}; -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp index 5381071ab..de2448d52 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/global_csv_state.hpp @@ -15,7 +15,6 @@ #include "duckdb/function/table/read_csv.hpp" #include "duckdb/execution/operator/csv_scanner/csv_file_scanner.hpp" #include "duckdb/execution/operator/csv_scanner/string_value_scanner.hpp" -#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" namespace duckdb { @@ -23,7 +22,7 @@ namespace duckdb { struct CSVGlobalState : public GlobalTableFunctionState { CSVGlobalState(ClientContext &context, const shared_ptr &buffer_manager_p, const CSVReaderOptions &options, idx_t system_threads_p, const vector &files, - vector column_ids_p, const ReadCSVData &bind_data); + vector column_ids_p, const ReadCSVData &bind_data); ~CSVGlobalState() override { } @@ -32,7 +31,7 @@ struct CSVGlobalState : public GlobalTableFunctionState { //! In case it returns a nullptr it means we are done reading these files. unique_ptr Next(optional_ptr previous_scanner); - void FillRejectsTable() const; + void FillRejectsTable(); void DecrementThread(); @@ -59,7 +58,7 @@ struct CSVGlobalState : public GlobalTableFunctionState { //! Number of threads being used in this scanner idx_t running_threads = 1; //! The column ids to read - vector column_ids; + vector column_ids; string sniffer_mismatch_error; @@ -79,8 +78,6 @@ struct CSVGlobalState : public GlobalTableFunctionState { unordered_map threads_per_file; //! We hold information on the current scanner boundary CSVIterator current_boundary; - - CSVValidator validator; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp index da796d79e..9e38f9bed 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/scanner_boundary.hpp @@ -27,7 +27,7 @@ namespace duckdb { struct CSVBoundary { CSVBoundary(idx_t buffer_idx, idx_t buffer_pos, idx_t boundary_idx, idx_t end_pos); CSVBoundary(); - void Print() const; + void Print(); //! Start Buffer index of the file where we start scanning idx_t buffer_idx = 0; //! Start Buffer position of the buffer of the file where we start scanning @@ -53,10 +53,10 @@ struct CSVIterator { public: CSVIterator(); - void Print() const; + void Print(); //! Moves the boundary to the next one to be scanned, if there are no next boundaries, it returns False //! Otherwise, if there are boundaries, it returns True - bool Next(CSVBufferManager &buffer_manager, const CSVReaderOptions &reader_options); + bool Next(CSVBufferManager &buffer_manager); //! If boundary is set bool IsBoundarySet() const; @@ -67,20 +67,12 @@ struct CSVIterator { void SetCurrentPositionToBoundary(); - void SetCurrentBoundaryToPosition(bool single_threaded, const CSVReaderOptions &reader_options); + void SetCurrentBoundaryToPosition(bool single_threaded); void SetStart(idx_t pos); - void SetEnd(idx_t pos); - // Gets the current position for the file - idx_t GetGlobalCurrentPos() const; - - //! Checks if we are done with this iterator - void CheckIfDone(); - - static idx_t BytesPerThread(const CSVReaderOptions &reader_options); - - static constexpr idx_t ROWS_PER_THREAD = 4; + //! 8 MB TODO: Should benchmarks other values + static constexpr idx_t BYTES_PER_THREAD = 8000000; CSVPosition pos; @@ -88,8 +80,6 @@ struct CSVIterator { bool first_one = true; - idx_t buffer_size; - private: //! The original setting CSVBoundary boundary; diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp index 5715d25db..6de097dea 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/sniffer/csv_sniffer.hpp @@ -30,7 +30,7 @@ struct DialectCandidates { explicit DialectCandidates(const CSVStateMachineOptions &options); //! Static functions to get defaults of the search space - static vector GetDefaultDelimiter(); + static vector GetDefaultDelimiter(); static vector> GetDefaultQuote(); @@ -43,7 +43,7 @@ struct DialectCandidates { string Print(); //! Candidates for the delimiter - vector delim_candidates; + vector delim_candidates; //! Candidates for the comment vector comment_candidates; //! Quote-Rule Candidates @@ -136,8 +136,6 @@ class CSVSniffer { static bool CanYouCastIt(ClientContext &context, const string_t value, const LogicalType &type, const DialectOptions &dialect_options, const bool is_null, const char decimal_separator); - idx_t LinesSniffed() const; - private: //! CSV State Machine Cache CSVStateMachineCache &state_machine_cache; @@ -153,10 +151,9 @@ class CSVSniffer { SetColumns set_columns; shared_ptr error_handler; shared_ptr detection_error_handler; - //! Number of lines sniffed in this sniffer - idx_t lines_sniffed; + //! Sets the result options - void SetResultOptions() const; + void SetResultOptions(); //! ------------------------------------------------------// //! ----------------- Dialect Detection ----------------- // diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/state_machine_options.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/state_machine_options.hpp index 53b306585..826a19030 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/state_machine_options.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/state_machine_options.hpp @@ -15,13 +15,11 @@ namespace duckdb { //! Basically which char, quote and escape were used to generate it. struct CSVStateMachineOptions { CSVStateMachineOptions() {}; - CSVStateMachineOptions(string delimiter_p, char quote_p, char escape_p, char comment_p, - NewLineIdentifier new_line_p, bool rfc_4180_p) - : delimiter(std::move(delimiter_p)), quote(quote_p), escape(escape_p), comment(comment_p), new_line(new_line_p), - rfc_4180(rfc_4180_p) {}; + CSVStateMachineOptions(char delimiter_p, char quote_p, char escape_p, char comment_p, NewLineIdentifier new_line_p) + : delimiter(delimiter_p), quote(quote_p), escape(escape_p), comment(comment_p), new_line(new_line_p) {}; //! Delimiter to separate columns within each line - CSVOption delimiter {","}; + CSVOption delimiter = ','; //! Quote used for columns that contain reserved characters, e.g ' CSVOption quote = '\"'; //! Escape character to escape quote character @@ -30,12 +28,10 @@ struct CSVStateMachineOptions { CSVOption comment = '\0'; //! New Line separator CSVOption new_line = NewLineIdentifier::NOT_SET; - //! RFC 4180 conformance - CSVOption rfc_4180 = false; bool operator==(const CSVStateMachineOptions &other) const { return delimiter == other.delimiter && quote == other.quote && escape == other.escape && - new_line == other.new_line && comment == other.comment && rfc_4180 == other.rfc_4180; + new_line == other.new_line && comment == other.comment; } }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp index a2a3d5372..e0047a66a 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/csv_scanner/string_value_scanner.hpp @@ -12,7 +12,7 @@ #include "duckdb/execution/operator/csv_scanner/csv_state_machine.hpp" #include "duckdb/execution/operator/csv_scanner/scanner_boundary.hpp" #include "duckdb/execution/operator/csv_scanner/base_scanner.hpp" -#include "duckdb/execution/operator/csv_scanner/csv_validator.hpp" + namespace duckdb { struct CSVBufferUsage { @@ -96,8 +96,7 @@ class CurrentError { class LineError { public: - explicit LineError(const idx_t scan_id_p, const bool ignore_errors_p) - : is_error_in_line(false), ignore_errors(ignore_errors_p), scan_id(scan_id_p) {}; + explicit LineError(bool ignore_errors_p) : is_error_in_line(false), ignore_errors(ignore_errors_p) {}; //! We clear up our CurrentError Vector void Reset() { current_errors.clear(); @@ -133,19 +132,10 @@ class LineError { bool HandleErrors(StringValueResult &result); - bool HasError() const { - return !current_errors.empty(); - } - - idx_t Size() const { - return current_errors.size(); - } - private: vector current_errors; bool is_error_in_line; bool ignore_errors; - idx_t scan_id; }; struct ParseTypeInfo { @@ -165,14 +155,13 @@ struct ParseTypeInfo { uint8_t scale; uint8_t width; }; - class StringValueResult : public ScannerResult { public: StringValueResult(CSVStates &states, CSVStateMachine &state_machine, const shared_ptr &buffer_handle, Allocator &buffer_allocator, idx_t result_size_p, idx_t buffer_position, CSVErrorHandler &error_handler, CSVIterator &iterator, bool store_line_size, shared_ptr csv_file_scan, idx_t &lines_read, bool sniffing, - string path, idx_t scan_id); + string path); ~StringValueResult(); @@ -191,8 +180,6 @@ class StringValueResult : public ScannerResult { const bool null_padding; const bool ignore_errors; - const idx_t extra_delimiter_bytes = 0; - unsafe_unique_array null_str_ptr; unsafe_unique_array null_str_size; idx_t null_str_count; @@ -247,9 +234,6 @@ class StringValueResult : public ScannerResult { //! Specialized code for quoted values, makes sure to remove quotes and escapes static inline void AddQuotedValue(StringValueResult &result, const idx_t buffer_pos); - //! Specialized code for possibly escaped values, makes sure to remove escapes - static inline void AddPossiblyEscapedValue(StringValueResult &result, const idx_t buffer_pos, const char *value_ptr, - const idx_t length, const bool empty); //! Adds a Value to the result static inline void AddValue(StringValueResult &result, const idx_t buffer_pos); //! Adds a Row to the result @@ -262,15 +246,13 @@ class StringValueResult : public ScannerResult { //! Handles EmptyLine states static inline bool EmptyLine(StringValueResult &result, const idx_t buffer_pos); inline bool AddRowInternal(); - //! Force the throw of a Unicode error + //! Force the throw of a unicode error void HandleUnicodeError(idx_t col_idx, LinePosition &error_position); bool HandleTooManyColumnsError(const char *value_ptr, const idx_t size); inline void AddValueToVector(const char *value_ptr, const idx_t size, bool allocate = false); static inline void SetComment(StringValueResult &result, idx_t buffer_pos); static inline bool UnsetComment(StringValueResult &result, idx_t buffer_pos); - inline idx_t HandleMultiDelimiter(const idx_t buffer_pos) const; - DataChunk &ToChunk(); //! Resets the state of the result void Reset(); @@ -285,18 +267,6 @@ class StringValueResult : public ScannerResult { void RemoveLastLine(); }; -struct ValidRowInfo { - ValidRowInfo(bool is_valid_p, idx_t start_pos_p, idx_t end_buffer_idx_p, idx_t end_pos_p, bool last_state_quote_p) - : is_valid(is_valid_p), start_pos(start_pos_p), end_buffer_idx(end_buffer_idx_p), end_pos(end_pos_p), - last_state_quote(last_state_quote_p) {}; - ValidRowInfo() : is_valid(false), start_pos(0), end_buffer_idx(0), end_pos(0) {}; - - bool is_valid; - idx_t start_pos; - idx_t end_buffer_idx; - idx_t end_pos; - bool last_state_quote = false; -}; //! Our dialect scanner basically goes over the CSV and actually parses the values to a DuckDB vector of string_t class StringValueScanner : public BaseScanner { public: @@ -322,17 +292,12 @@ class StringValueScanner : public BaseScanner { bool FinishedIterator() const; //! Creates a new string with all escaped values removed - static string_t RemoveEscape(const char *str_ptr, idx_t end, char escape, char quote, Vector &vector); + static string_t RemoveEscape(const char *str_ptr, idx_t end, char escape, Vector &vector); //! If we can directly cast the type when consuming the CSV file, or we have to do it later static bool CanDirectlyCast(const LogicalType &type, bool icu_loaded); - //! Gets validation line information - ValidatorLine GetValidationLine(); - const idx_t scanner_idx; - //! We use the max of idx_t to signify this is a line finder scanner. - static constexpr idx_t LINE_FINDER_ID = NumericLimits::Maximum(); //! Variable that manages buffer tracking shared_ptr buffer_tracker; @@ -343,31 +308,21 @@ class StringValueScanner : public BaseScanner { void FinalizeChunkProcess() override; //! Function used to process values that go over the first buffer, extra allocation might be necessary - void ProcessOverBufferValue(); + void ProcessOverbufferValue(); void ProcessExtraRow(); //! Function used to move from one buffer to the other, if necessary bool MoveToNextBuffer(); - //! -------- Functions used to figure out where lines start ---------!// - //! Main function, sets the correct start + void SkipUntilNewLine(); + void SetStart(); - //! From a given initial state, it skips until we reach the until_state - bool SkipUntilState(CSVState initial_state, CSVState until_state, CSVIterator ¤t_iterator, - bool "ed) const; - //! If the current row we found is valid - bool IsRowValid(CSVIterator ¤t_iterator) const; - ValidRowInfo TryRow(CSVState state, idx_t start_pos, idx_t end_pos) const; - bool FirstValueEndsOnQuote(CSVIterator iterator) const; StringValueResult result; vector types; - //! True Position where this scanner started scanning(i.e., after figuring out where the first line starts) - idx_t start_pos; - //! Pointer to the previous buffer handle, necessary for over-buffer values + + //! Pointer to the previous buffer handle, necessary for overbuffer values shared_ptr previous_buffer_handle; - //! Strict state machine, is basically a state machine with rfc 4180 set to true, used to figure out new line. - shared_ptr state_machine_strict; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp index 29a58c7a6..f630187f8 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_batch_collector.hpp @@ -30,8 +30,8 @@ class PhysicalBatchCollector : public PhysicalResultCollector { unique_ptr GetLocalSinkState(ExecutionContext &context) const override; unique_ptr GetGlobalSinkState(ClientContext &context) const override; - OperatorPartitionInfo RequiredPartitionInfo() const override { - return OperatorPartitionInfo::BatchIndex(); + bool RequiresBatchIndex() const override { + return true; } bool ParallelSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp index 1ab923968..6e2661c8b 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_buffered_batch_collector.hpp @@ -37,8 +37,8 @@ class PhysicalBufferedBatchCollector : public PhysicalResultCollector { unique_ptr GetLocalSinkState(ExecutionContext &context) const override; unique_ptr GetGlobalSinkState(ClientContext &context) const override; - OperatorPartitionInfo RequiredPartitionInfo() const override { - return OperatorPartitionInfo::BatchIndex(); + bool RequiresBatchIndex() const override { + return true; } bool ParallelSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp index 47f01b2b5..2734066bb 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_limit.hpp @@ -57,8 +57,8 @@ class PhysicalLimit : public PhysicalOperator { return true; } - OperatorPartitionInfo RequiredPartitionInfo() const override { - return OperatorPartitionInfo::BatchIndex(); + bool RequiresBatchIndex() const override { + return true; } public: diff --git a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_reservoir_sample.hpp b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_reservoir_sample.hpp index e4a581dca..9ff7bf62a 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/helper/physical_reservoir_sample.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/helper/physical_reservoir_sample.hpp @@ -41,7 +41,7 @@ class PhysicalReservoirSample : public PhysicalOperator { SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const override; bool ParallelSink() const override { - return !options->repeatable; + return true; } bool IsSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp index 3a5663c6a..0a270b545 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/join_filter_pushdown.hpp @@ -8,19 +8,19 @@ #pragma once -#include "duckdb/planner/column_binding.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/planner/table_filter.hpp" +#include "duckdb/planner/column_binding.hpp" namespace duckdb { class DataChunk; class DynamicTableFilterSet; -class LogicalGet; -class JoinHashTable; struct GlobalUngroupedAggregateState; struct LocalUngroupedAggregateState; struct JoinFilterPushdownColumn { + //! The join condition from which this filter pushdown is generated + idx_t join_condition; //! The probe column index to which this filter should be applied ColumnBinding probe_column_index; }; @@ -39,27 +39,11 @@ struct JoinFilterLocalState { unique_ptr local_aggregate_state; }; -struct JoinFilterPushdownFilter { +struct JoinFilterPushdownInfo { //! The dynamic table filter set where to push filters into shared_ptr dynamic_filters; - //! The columns for which we should generate filters - vector columns; -}; - -struct PushdownFilterTarget { - PushdownFilterTarget(LogicalGet &get, vector columns_p) - : get(get), columns(std::move(columns_p)) { - } - - LogicalGet &get; - vector columns; -}; - -struct JoinFilterPushdownInfo { - //! The join condition indexes for which we compute the min/max aggregates - vector join_condition; - //! The probes to push the filter into - vector probe_info; + //! The filters that we should generate + vector filters; //! Min/Max aggregates vector> min_max_aggregates; @@ -69,12 +53,7 @@ struct JoinFilterPushdownInfo { void Sink(DataChunk &chunk, JoinFilterLocalState &lstate) const; void Combine(JoinFilterGlobalState &gstate, JoinFilterLocalState &lstate) const; - unique_ptr Finalize(ClientContext &context, JoinHashTable &ht, JoinFilterGlobalState &gstate, - const PhysicalOperator &op) const; - -private: - void PushInFilter(const JoinFilterPushdownFilter &info, JoinHashTable &ht, const PhysicalOperator &op, - idx_t filter_idx, idx_t filter_col_idx) const; + void PushFilters(JoinFilterGlobalState &gstate, const PhysicalOperator &op) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp index 0affaf4cc..d5dd3e4aa 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/perfect_hash_join_executor.hpp @@ -22,9 +22,12 @@ class PhysicalHashJoin; struct PerfectHashJoinStats { Value build_min; Value build_max; + Value probe_min; + Value probe_max; bool is_build_small = false; bool is_build_dense = false; idx_t build_range = 0; + idx_t estimated_cardinality = 0; }; //! PhysicalHashJoin represents a hash loop join between two tables @@ -32,14 +35,14 @@ class PerfectHashJoinExecutor { using PerfectHashTable = vector; public: - PerfectHashJoinExecutor(const PhysicalHashJoin &join, JoinHashTable &ht); + explicit PerfectHashJoinExecutor(const PhysicalHashJoin &join, JoinHashTable &ht, PerfectHashJoinStats pjoin_stats); public: - bool CanDoPerfectHashJoin(const PhysicalHashJoin &op, const Value &min, const Value &max); + bool CanDoPerfectHashJoin(); unique_ptr GetOperatorState(ExecutionContext &context); - OperatorResultType ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, DataChunk &lhs_output_columns, - DataChunk &chunk, OperatorState &state); + OperatorResultType ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, DataChunk &chunk, + OperatorState &state); bool BuildPerfectHashTable(LogicalType &type); private: @@ -61,9 +64,9 @@ class PerfectHashJoinExecutor { JoinHashTable &ht; //! Columnar perfect hash table PerfectHashTable perfect_hash_table; - //! Build statistics + //! Build and probe statistics PerfectHashJoinStats perfect_join_statistics; - //! Stores the occurrences of each value in the build side + //! Stores the occurences of each value in the build side unsafe_unique_array bitmap_build_idx; //! Stores the number of unique keys in the build side idx_t unique_keys = 0; diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp index 849423a25..5b8d9c081 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/physical_hash_join.hpp @@ -22,18 +22,15 @@ class PhysicalHashJoin : public PhysicalComparisonJoin { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::HASH_JOIN; - struct JoinProjectionColumns { - vector col_idxs; - vector col_types; - }; - public: PhysicalHashJoin(LogicalOperator &op, unique_ptr left, unique_ptr right, vector cond, JoinType join_type, const vector &left_projection_map, const vector &right_projection_map, vector delim_types, - idx_t estimated_cardinality, unique_ptr pushdown_info); + idx_t estimated_cardinality, PerfectHashJoinStats perfect_join_stats, + unique_ptr pushdown_info); PhysicalHashJoin(LogicalOperator &op, unique_ptr left, unique_ptr right, - vector cond, JoinType join_type, idx_t estimated_cardinality); + vector cond, JoinType join_type, idx_t estimated_cardinality, + PerfectHashJoinStats join_state); //! Initialize HT for this operator unique_ptr InitializeHashTable(ClientContext &context) const; @@ -41,18 +38,20 @@ class PhysicalHashJoin : public PhysicalComparisonJoin { //! The types of the join keys vector condition_types; - //! The indices/types of the payload columns - JoinProjectionColumns payload_columns; - //! The indices/types of the lhs columns that need to be output - JoinProjectionColumns lhs_output_columns; - //! The indices/types of the rhs columns that need to be output - JoinProjectionColumns rhs_output_columns; + //! The indices for getting the payload columns + vector payload_column_idxs; + //! The types of the payload columns + vector payload_types; + + //! Positions of the RHS columns that need to output + vector rhs_output_columns; + //! The types of the output + vector rhs_output_types; //! Duplicate eliminated types; only used for delim_joins (i.e. correlated subqueries) vector delim_types; - - //! Join Keys statistics (optional) - vector> join_stats; + //! Used in perfect hash join + PerfectHashJoinStats perfect_join_statistics; public: InsertionOrderPreservingMap ParamsToString() const override; @@ -76,7 +75,7 @@ class PhysicalHashJoin : public PhysicalComparisonJoin { GlobalSourceState &gstate) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; //! Becomes a source when it is an external join bool IsSource() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/join/physical_iejoin.hpp b/src/duckdb/src/include/duckdb/execution/operator/join/physical_iejoin.hpp index 5c0183726..0fe4b9626 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/join/physical_iejoin.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/join/physical_iejoin.hpp @@ -46,7 +46,7 @@ class PhysicalIEJoin : public PhysicalRangeJoin { return true; } - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate_p) const override; public: // Sink Interface diff --git a/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp b/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp index b62fea5dd..b3b28992d 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/order/physical_order.hpp @@ -35,9 +35,8 @@ class PhysicalOrder : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const override; + idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate) const override; bool IsSource() const override { return true; @@ -47,10 +46,7 @@ class PhysicalOrder : public PhysicalOperator { return true; } - bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override { - if (partition_info.RequiresPartitionColumns()) { - return false; - } + bool SupportsBatchIndex() const override { return true; } diff --git a/src/duckdb/src/include/duckdb/execution/operator/order/physical_top_n.hpp b/src/duckdb/src/include/duckdb/execution/operator/order/physical_top_n.hpp index a7d5559fb..0cd33528f 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/order/physical_top_n.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/order/physical_top_n.hpp @@ -12,7 +12,6 @@ #include "duckdb/planner/bound_query_node.hpp" namespace duckdb { -struct DynamicFilterData; //! Represents a physical ordering of the data. Note that this will not change //! the data but only add a selection vector. @@ -22,14 +21,11 @@ class PhysicalTopN : public PhysicalOperator { public: PhysicalTopN(vector types, vector orders, idx_t limit, idx_t offset, - shared_ptr dynamic_filter, idx_t estimated_cardinality); - ~PhysicalTopN() override; + idx_t estimated_cardinality); vector orders; idx_t limit; idx_t offset; - //! Dynamic table filter (if any) - shared_ptr dynamic_filter; public: // Source interface diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp index 56f8a43a5..4f01747d4 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_copy_to_file.hpp @@ -49,8 +49,8 @@ class PhysicalBatchCopyToFile : public PhysicalOperator { unique_ptr GetGlobalSinkState(ClientContext &context) const override; SinkNextBatchType NextBatch(ExecutionContext &context, OperatorSinkNextBatchInput &input) const override; - OperatorPartitionInfo RequiredPartitionInfo() const override { - return OperatorPartitionInfo::BatchIndex(); + bool RequiresBatchIndex() const override { + return true; } bool IsSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp index 57c349280..bce3ac633 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_batch_insert.hpp @@ -60,8 +60,8 @@ class PhysicalBatchInsert : public PhysicalOperator { SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const override; - OperatorPartitionInfo RequiredPartitionInfo() const override { - return OperatorPartitionInfo::BatchIndex(); + bool RequiresBatchIndex() const override { + return true; } bool IsSink() const override { diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp index ccb113c4f..9680b5837 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_insert.hpp @@ -13,58 +13,10 @@ #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" #include "duckdb/common/index_vector.hpp" #include "duckdb/parser/statement/insert_statement.hpp" -#include "duckdb/storage/table/append_state.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" -#include "duckdb/storage/table/delete_state.hpp" namespace duckdb { -//===--------------------------------------------------------------------===// -// Sink -//===--------------------------------------------------------------------===// -class InsertGlobalState : public GlobalSinkState { -public: - explicit InsertGlobalState(ClientContext &context, const vector &return_types, DuckTableEntry &table); - -public: - mutex lock; - DuckTableEntry &table; - idx_t insert_count; - bool initialized; - LocalAppendState append_state; - ColumnDataCollection return_collection; -}; - -class InsertLocalState : public LocalSinkState { -public: -public: - InsertLocalState(ClientContext &context, const vector &types, - const vector> &bound_defaults, - const vector> &bound_constraints); - -public: - ConstraintState &GetConstraintState(DataTable &table, TableCatalogEntry &table_ref); - TableDeleteState &GetDeleteState(DataTable &table, TableCatalogEntry &table_ref, ClientContext &context); - -public: - //! The chunk that ends up getting inserted - DataChunk insert_chunk; - //! The chunk containing the tuples that become an update (if DO UPDATE) - DataChunk update_chunk; - ExpressionExecutor default_executor; - TableAppendState local_append_state; - unique_ptr local_collection; - optional_ptr writer; - // Rows that have been updated by a DO UPDATE conflict - unordered_set updated_rows; - idx_t update_count = 0; - unique_ptr constraint_state; - const vector> &bound_constraints; - //! The delete state for ON CONFLICT handling that is rewritten into DELETE + INSERT. - unique_ptr delete_state; - //! The append chunk for ON CONFLICT handling that is rewritting into DELETE + INSERT. - DataChunk append_chunk; -}; +class InsertLocalState; //! Physically insert a set of data into a table class PhysicalInsert : public PhysicalOperator { @@ -79,7 +31,7 @@ class PhysicalInsert : public PhysicalOperator { vector set_types, idx_t estimated_cardinality, bool return_chunk, bool parallel, OnConflictAction action_type, unique_ptr on_conflict_condition, unique_ptr do_update_condition, unordered_set on_conflict_filter, - vector columns_to_fetch, bool update_is_del_and_insert); + vector columns_to_fetch); //! CREATE TABLE AS PhysicalInsert(LogicalOperator &op, SchemaCatalogEntry &schema, unique_ptr info, idx_t estimated_cardinality, bool parallel); @@ -119,11 +71,9 @@ class PhysicalInsert : public PhysicalOperator { unique_ptr do_update_condition; // The column ids to apply the ON CONFLICT on unordered_set conflict_target; - //! True, if the INSERT OR REPLACE requires delete + insert. - bool update_is_del_and_insert; // Column ids from the original table to fetch - vector columns_to_fetch; + vector columns_to_fetch; // Matching types to the column ids to fetch vector types_to_fetch; @@ -170,8 +120,7 @@ class PhysicalInsert : public PhysicalOperator { //! Returns the amount of updated tuples void CreateUpdateChunk(ExecutionContext &context, DataChunk &chunk, TableCatalogEntry &table, Vector &row_ids, DataChunk &result) const; - idx_t OnConflictHandling(TableCatalogEntry &table, ExecutionContext &context, InsertGlobalState &gstate, - InsertLocalState &lstate) const; + idx_t OnConflictHandling(TableCatalogEntry &table, ExecutionContext &context, InsertLocalState &lstate) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_update.hpp b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_update.hpp index d86b805e0..9556b48c9 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_update.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/persistent/physical_update.hpp @@ -35,8 +35,6 @@ class PhysicalUpdate : public PhysicalOperator { bool update_is_del_and_insert; //! If the returning statement is present, return the whole chunk bool return_chunk; - //! Set to true, if we are updating an index column. - bool index_update; public: // Source interface diff --git a/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp b/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp index f505f4166..1fb4eebe6 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/projection/physical_tableinout_function.hpp @@ -20,7 +20,7 @@ class PhysicalTableInOutFunction : public PhysicalOperator { public: PhysicalTableInOutFunction(vector types, TableFunction function_p, - unique_ptr bind_data_p, vector column_ids_p, + unique_ptr bind_data_p, vector column_ids_p, idx_t estimated_cardinality, vector projected_input); public: @@ -47,7 +47,7 @@ class PhysicalTableInOutFunction : public PhysicalOperator { //! Bind data of the function unique_ptr bind_data; //! The set of column ids to fetch - vector column_ids; + vector column_ids; //! The set of input columns to project out vector projected_input; }; diff --git a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp index 2a39fb239..c142009d2 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_positional_scan.hpp @@ -30,7 +30,6 @@ class PhysicalPositionalScan : public PhysicalOperator { public: bool Equals(const PhysicalOperator &other) const override; - vector> GetChildren() const override; public: unique_ptr GetLocalSourceState(ExecutionContext &context, @@ -38,7 +37,7 @@ class PhysicalPositionalScan : public PhysicalOperator { unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; bool IsSource() const override { return true; diff --git a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp index 45ac1e34c..621282e2d 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/scan/physical_table_scan.hpp @@ -13,7 +13,6 @@ #include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/common/extra_operator_info.hpp" -#include "duckdb/common/column_index.hpp" namespace duckdb { @@ -25,7 +24,7 @@ class PhysicalTableScan : public PhysicalOperator { public: //! Table scan that immediately projects out filter columns that are unused in the remainder of the query plan PhysicalTableScan(vector types, TableFunction function, unique_ptr bind_data, - vector returned_types, vector column_ids, vector projection_ids, + vector returned_types, vector column_ids, vector projection_ids, vector names, unique_ptr table_filters, idx_t estimated_cardinality, ExtraOperatorInfo extra_info, vector parameters); @@ -36,15 +35,14 @@ class PhysicalTableScan : public PhysicalOperator { //! The types of ALL columns that can be returned by the table function vector returned_types; //! The column ids used within the table function - vector column_ids; + vector column_ids; //! The projected-out column ids vector projection_ids; //! The names of the columns vector names; //! The table filters unique_ptr table_filters; - //! Currently stores info related to filters pushed down into MultiFileLists and sample rate pushed down into the - //! table scan + //! Currently stores info related to filters pushed down into MultiFileLists ExtraOperatorInfo extra_info; //! Parameters vector parameters; @@ -62,18 +60,19 @@ class PhysicalTableScan : public PhysicalOperator { GlobalSourceState &gstate) const override; unique_ptr GetGlobalSourceState(ClientContext &context) const override; SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const override; - OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, - LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const override; + idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate) const override; bool IsSource() const override { return true; } bool ParallelSource() const override; - bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const override; + bool SupportsBatchIndex() const override { + return function.get_batch_index != nullptr; + } - ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; + double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp b/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp index cc3178386..edd949fb7 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_art_index.hpp @@ -8,18 +8,18 @@ #pragma once -#include "duckdb/execution/index/art/art.hpp" #include "duckdb/execution/physical_operator.hpp" +#include "duckdb/execution/index/art/art.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" + #include "duckdb/storage/data_table.hpp" #include namespace duckdb { - class DuckTableEntry; -//! Physical index creation operator. +//! Physical CREATE (UNIQUE) INDEX statement class PhysicalCreateARTIndex : public PhysicalOperator { public: static constexpr const PhysicalOperatorType TYPE = PhysicalOperatorType::CREATE_INDEX; @@ -27,21 +27,18 @@ class PhysicalCreateARTIndex : public PhysicalOperator { public: PhysicalCreateARTIndex(LogicalOperator &op, TableCatalogEntry &table, const vector &column_ids, unique_ptr info, vector> unbound_expressions, - idx_t estimated_cardinality, const bool sorted, - unique_ptr alter_table_info = nullptr); + idx_t estimated_cardinality, const bool sorted); - //! The table to create the index for. + //! The table to create the index for DuckTableEntry &table; - //! The list of column IDs of the index. + //! The list of column IDs required for the index vector storage_ids; - //! Index creation information. + //! Info for index creation unique_ptr info; - //! Unbound expressions of the indexed columns. + //! Unbound expressions to be used in the optimizer vector> unbound_expressions; - //! True, if the pipeline sorts the index data prior to index creation. + //! Whether the pipeline sorts the data prior to index creation const bool sorted; - //! Alter table information for adding indexes. - unique_ptr alter_table_info; public: //! Source interface, NOP for this operator @@ -52,14 +49,14 @@ class PhysicalCreateARTIndex : public PhysicalOperator { } public: - //! Sink interface, thread-local sink states. Contains an index for each state. + //! Sink interface, thread-local sink states unique_ptr GetLocalSinkState(ExecutionContext &context) const override; - //! Sink interface, global sink state. Contains the global index. + //! Sink interface, global sink state unique_ptr GetGlobalSinkState(ClientContext &context) const override; - //! Sink for unsorted data: insert iteratively. + //! Sink for unsorted data: insert iteratively SinkResultType SinkUnsorted(OperatorSinkInput &input) const; - //! Sink for sorted data: build + merge. + //! Sink for sorted data: build + merge SinkResultType SinkSorted(OperatorSinkInput &input) const; SinkResultType Sink(ExecutionContext &context, DataChunk &chunk, OperatorSinkInput &input) const override; diff --git a/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp b/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp index 3ce30ce67..5416c8fd3 100644 --- a/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp +++ b/src/duckdb/src/include/duckdb/execution/operator/set/physical_cte.hpp @@ -52,6 +52,10 @@ class PhysicalCTE : public PhysicalOperator { return false; } + bool RequiresBatchIndex() const override { + return false; + } + InsertionOrderPreservingMap ParamsToString() const override; public: diff --git a/src/duckdb/src/include/duckdb/execution/partition_info.hpp b/src/duckdb/src/include/duckdb/execution/partition_info.hpp deleted file mode 100644 index 8a56f77fb..000000000 --- a/src/duckdb/src/include/duckdb/execution/partition_info.hpp +++ /dev/null @@ -1,79 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/execution/partition_info.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/types/value.hpp" -#include "duckdb/common/optional_idx.hpp" - -namespace duckdb { - -enum class PartitionInfo { NONE, REQUIRES_BATCH_INDEX }; - -struct ColumnPartitionData { - explicit ColumnPartitionData(Value partition_val) : min_val(partition_val), max_val(std::move(partition_val)) { - } - - Value min_val; - Value max_val; -}; - -struct SourcePartitionInfo { - //! The current batch index - //! This is only set in case RequiresBatchIndex() is true, and the source has support for it (SupportsBatchIndex()) - //! Otherwise this is left on INVALID_INDEX - //! The batch index is a globally unique, increasing index that should be used to maintain insertion order - //! //! in conjunction with parallelism - optional_idx batch_index; - //! The minimum batch index that any thread is currently actively reading - optional_idx min_batch_index; - //! Column partition data - vector partition_data; -}; - -struct OperatorPartitionInfo { - OperatorPartitionInfo() = default; - explicit OperatorPartitionInfo(bool batch_index) : batch_index(batch_index) { - } - explicit OperatorPartitionInfo(vector partition_columns_p) - : partition_columns(std::move(partition_columns_p)) { - } - - bool batch_index = false; - vector partition_columns; - - static OperatorPartitionInfo NoPartitionInfo() { - return OperatorPartitionInfo(false); - } - static OperatorPartitionInfo BatchIndex() { - return OperatorPartitionInfo(true); - } - static OperatorPartitionInfo PartitionColumns(vector columns) { - return OperatorPartitionInfo(std::move(columns)); - } - bool RequiresPartitionColumns() const { - return !partition_columns.empty(); - } - bool RequiresBatchIndex() const { - return batch_index; - } - bool AnyRequired() const { - return RequiresPartitionColumns() || RequiresBatchIndex(); - } -}; - -struct OperatorPartitionData { - explicit OperatorPartitionData(idx_t batch_index) : batch_index(batch_index) { - } - - idx_t batch_index; - vector partition_data; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/physical_operator.hpp b/src/duckdb/src/include/duckdb/execution/physical_operator.hpp index 50529d594..be63efb25 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_operator.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_operator.hpp @@ -15,13 +15,11 @@ #include "duckdb/common/enums/explain_format.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/execution/execution_context.hpp" -#include "duckdb/execution/progress_data.hpp" #include "duckdb/optimizer/join_order/join_node.hpp" #include "duckdb/common/optional_idx.hpp" #include "duckdb/execution/physical_operator_states.hpp" #include "duckdb/common/enums/order_preservation_type.hpp" #include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/execution/partition_info.hpp" namespace duckdb { class Event; @@ -115,9 +113,8 @@ class PhysicalOperator { virtual unique_ptr GetGlobalSourceState(ClientContext &context) const; virtual SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, OperatorSourceInput &input) const; - virtual OperatorPartitionData GetPartitionData(ExecutionContext &context, DataChunk &chunk, - GlobalSourceState &gstate, LocalSourceState &lstate, - const OperatorPartitionInfo &partition_info) const; + virtual idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate, + LocalSourceState &lstate) const; virtual bool IsSource() const { return false; @@ -127,11 +124,8 @@ class PhysicalOperator { return false; } - virtual bool SupportsPartitioning(const OperatorPartitionInfo &partition_info) const { - if (partition_info.AnyRequired()) { - return false; - } - return true; + virtual bool SupportsBatchIndex() const { + return false; } //! The type of order emitted by the operator (as a source) @@ -140,11 +134,10 @@ class PhysicalOperator { } //! Returns the current progress percentage, or a negative value if progress bars are not supported - virtual ProgressData GetProgress(ClientContext &context, GlobalSourceState &gstate) const; + virtual double GetProgress(ClientContext &context, GlobalSourceState &gstate) const; //! Returns the current progress percentage, or a negative value if progress bars are not supported - virtual ProgressData GetSinkProgress(ClientContext &context, GlobalSinkState &gstate, - const ProgressData source_progress) const { + virtual double GetSinkProgress(ClientContext &context, GlobalSinkState &gstate, double source_progress) const { return source_progress; } @@ -164,7 +157,7 @@ class PhysicalOperator { virtual void PrepareFinalize(ClientContext &context, GlobalSinkState &sink_state) const; //! The finalize is called when ALL threads are finished execution. It is called only once per pipeline, and is //! entirely single threaded. - //! If Finalize returns SinkResultType::Finished, the sink is marked as finished + //! If Finalize returns SinkResultType::FINISHED, the sink is marked as finished virtual SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context, OperatorSinkFinalizeInput &input) const; //! For sinks with RequiresBatchIndex set to true, when a new batch starts being processed this method is called @@ -188,8 +181,8 @@ class PhysicalOperator { return false; } - virtual OperatorPartitionInfo RequiredPartitionInfo() const { - return OperatorPartitionInfo::NoPartitionInfo(); + virtual bool RequiresBatchIndex() const { + return false; } //! Whether or not the sink operator depends on the order of the input chunks @@ -248,12 +241,8 @@ class CachingPhysicalOperator : public PhysicalOperator { bool caching_supported; public: - //! This Execute will prevent small chunks from entering the pipeline, buffering them until a bigger chunk is - //! created. OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk, GlobalOperatorState &gstate, OperatorState &state) const final; - //! FinalExecute is used here to send out the remainder of the chunk (< STANDARD_VECTOR_SIZE) that we still had - //! cached. OperatorFinalizeResultType FinalExecute(ExecutionContext &context, DataChunk &chunk, GlobalOperatorState &gstate, OperatorState &state) const final; diff --git a/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp b/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp index 9c0d6df1f..6c6717c49 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_operator_states.hpp @@ -16,7 +16,6 @@ #include "duckdb/execution/execution_context.hpp" #include "duckdb/optimizer/join_order/join_node.hpp" #include "duckdb/parallel/interrupt.hpp" -#include "duckdb/execution/partition_info.hpp" namespace duckdb { class Event; @@ -27,6 +26,17 @@ class PipelineBuildState; class MetaPipeline; class InterruptState; +struct SourcePartitionInfo { + //! The current batch index + //! This is only set in case RequiresBatchIndex() is true, and the source has support for it (SupportsBatchIndex()) + //! Otherwise this is left on INVALID_INDEX + //! The batch index is a globally unique, increasing index that should be used to maintain insertion order + //! //! in conjunction with parallelism + optional_idx batch_index; + //! The minimum batch index that any thread is currently actively reading + optional_idx min_batch_index; +}; + // LCOV_EXCL_START class OperatorState { public: diff --git a/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp b/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp index 51797f589..0b09b3494 100644 --- a/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp +++ b/src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp @@ -45,6 +45,8 @@ class PhysicalPlanGenerator { //! Whether or not we should preserve insertion order for executing the given sink static bool PreserveInsertionOrder(ClientContext &context, PhysicalOperator &plan); + static bool HasEquality(vector &conds, idx_t &range_count); + protected: unique_ptr CreatePlan(LogicalOperator &op); diff --git a/src/duckdb/src/include/duckdb/execution/progress_data.hpp b/src/duckdb/src/include/duckdb/execution/progress_data.hpp deleted file mode 100644 index 1d234d653..000000000 --- a/src/duckdb/src/include/duckdb/execution/progress_data.hpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/execution/progress_data.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/assert.hpp" - -namespace duckdb { - -struct ProgressData { - double done = 0.0; - double total = 0.0; - bool invalid = false; - -public: - double ProgressDone() const { - // ProgressDone requires a valid state - D_ASSERT(IsValid()); - - return done / total; - } - - void Add(const ProgressData &other) { - // Add is unchecked, propagating invalid - done += other.done; - total += other.total; - invalid = invalid || other.invalid; - } - void Normalize(const double target = 1.0) { - // Normalize checks only `target`, propagating invalid - D_ASSERT(target > 0.0); - if (IsValid()) { - if (total > 0.0) { - done /= total; - } - total = 1.0; - done *= target; - total *= target; - } else { - SetInvalid(); - } - } - void SetInvalid() { - invalid = true; - done = 0.0; - total = 1.0; - } - bool IsValid() const { - return (!invalid) && (done >= 0.0) && (done <= total) && (total >= 0.0); - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/radix_partitioned_hashtable.hpp b/src/duckdb/src/include/duckdb/execution/radix_partitioned_hashtable.hpp index b14ebb173..2134de075 100644 --- a/src/duckdb/src/include/duckdb/execution/radix_partitioned_hashtable.hpp +++ b/src/duckdb/src/include/duckdb/execution/radix_partitioned_hashtable.hpp @@ -10,7 +10,6 @@ #include "duckdb/common/types/row/tuple_data_layout.hpp" #include "duckdb/execution/operator/aggregate/grouped_aggregate_data.hpp" -#include "duckdb/execution/progress_data.hpp" #include "duckdb/parser/group_by_node.hpp" namespace duckdb { @@ -51,7 +50,7 @@ class RadixPartitionedHashTable { SourceResultType GetData(ExecutionContext &context, DataChunk &chunk, GlobalSinkState &sink, OperatorSourceInput &input) const; - ProgressData GetProgress(ClientContext &context, GlobalSinkState &sink_p, GlobalSourceState &gstate) const; + double GetProgress(ClientContext &context, GlobalSinkState &sink_p, GlobalSourceState &gstate) const; const TupleDataLayout &GetLayout() const; idx_t MaxThreads(GlobalSinkState &sink) const; diff --git a/src/duckdb/src/include/duckdb/execution/reservoir_sample.hpp b/src/duckdb/src/include/duckdb/execution/reservoir_sample.hpp index b794328bb..0edc7e073 100644 --- a/src/duckdb/src/include/duckdb/execution/reservoir_sample.hpp +++ b/src/duckdb/src/include/duckdb/execution/reservoir_sample.hpp @@ -12,64 +12,25 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/random_engine.hpp" #include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/windows_undefs.hpp" #include "duckdb/common/queue.hpp" -// Originally intended to be the vector size, but in order to run on -// vector size = 2, we had to change it. -#define FIXED_SAMPLE_SIZE 2048 - namespace duckdb { enum class SampleType : uint8_t { BLOCKING_SAMPLE = 0, RESERVOIR_SAMPLE = 1, RESERVOIR_PERCENTAGE_SAMPLE = 2 }; -enum class SamplingState : uint8_t { RANDOM = 0, RESERVOIR = 1 }; - -class ReservoirRNG : public RandomEngine { -public: - // return type must be called result type to be a valid URNG - typedef uint32_t result_type; - - explicit ReservoirRNG(int64_t seed) : RandomEngine(seed) {}; - - result_type operator()() { - return NextRandomInteger(); - }; - - static constexpr result_type min() { - return NumericLimits::Minimum(); - }; - static constexpr result_type max() { - return NumericLimits::Maximum(); - }; -}; - -//! Resevoir sampling is based on the 2005 paper "Weighted Random Sampling" by Efraimidis and Spirakis class BaseReservoirSampling { public: explicit BaseReservoirSampling(int64_t seed); BaseReservoirSampling(); - void InitializeReservoirWeights(idx_t cur_size, idx_t sample_size); + void InitializeReservoir(idx_t cur_size, idx_t sample_size); void SetNextEntry(); - void ReplaceElementWithIndex(idx_t entry_index, double with_weight, bool pop = true); void ReplaceElement(double with_weight = -1); - - void UpdateMinWeightThreshold(); - - //! Go from the naive sampling to the reservoir sampling - //! Naive samping will not collect weights, but when we serialize - //! we need to serialize weights again. - void FillWeights(SelectionVector &sel, idx_t &sel_size); - - unique_ptr Copy(); - //! The random generator - ReservoirRNG random; - + RandomEngine random; //! The next element to sample idx_t next_index_to_sample; //! The reservoir threshold of the current min entry @@ -87,13 +48,6 @@ class BaseReservoirSampling { void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); - - static double GetMinWeightFromTuplesSeen(idx_t rows_seen_total); - // static unordered_map tuples_to_min_weight_map; - // Blocking sample is a virtual class. It should be allowed to see the weights and - // of tuples in the sample. The blocking sample can then easily maintain statisitcal properties - // from the sample point of view. - friend class BlockingSample; }; class BlockingSample { @@ -107,31 +61,24 @@ class BlockingSample { bool destroyed; public: - explicit BlockingSample(int64_t seed = -1) - : base_reservoir_sample(make_uniq(seed)), type(SampleType::BLOCKING_SAMPLE), - destroyed(false) { + explicit BlockingSample(int64_t seed) : old_base_reservoir_sample(seed), random(old_base_reservoir_sample.random) { + base_reservoir_sample = nullptr; } virtual ~BlockingSample() { } //! Add a chunk of data to the sample virtual void AddToReservoir(DataChunk &input) = 0; - virtual unique_ptr Copy() const = 0; - virtual void Finalize() = 0; - virtual void Destroy(); - //! Fetches a chunk from the sample. destroy = true should only be used when - //! querying from a sample defined in a query and not a duckdb_table_sample. + virtual void Finalize() = 0; + //! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the + //! sample is completely built. virtual unique_ptr GetChunk() = 0; + BaseReservoirSampling old_base_reservoir_sample; virtual void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); - //! Helper functions needed to merge two reservoirs while respecting weights of sampled rows - std::pair PopFromWeightQueue(); - double GetMinWeightThreshold(); - idx_t GetPriorityQueueSize(); - public: template TARGET &Cast() { @@ -148,6 +95,8 @@ class BlockingSample { } return reinterpret_cast(*this); } + //! The reservoir sampling + RandomEngine &random; }; class ReservoirChunk { @@ -158,120 +107,45 @@ class ReservoirChunk { DataChunk chunk; void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); - - unique_ptr Copy() const; -}; - -struct SelectionVectorHelper { - SelectionVector sel; - uint32_t size; }; +//! The reservoir sample class maintains a streaming sample of fixed size "sample_count" class ReservoirSample : public BlockingSample { public: static constexpr const SampleType TYPE = SampleType::RESERVOIR_SAMPLE; - constexpr static idx_t FIXED_SAMPLE_SIZE_MULTIPLIER = 10; - constexpr static idx_t FAST_TO_SLOW_THRESHOLD = 60; - - // If the table has less than 204800 rows, this is the percentage - // of values we save when serializing/returning a sample. - constexpr static double SAVE_PERCENTAGE = 0.01; - +public: ReservoirSample(Allocator &allocator, idx_t sample_count, int64_t seed = 1); - explicit ReservoirSample(idx_t sample_count, unique_ptr = nullptr); - - //! methods used to help with serializing and deserializing - void EvictOverBudgetSamples(); - void ExpandSerializedSample(); - - SamplingState GetSamplingState() const; - - //! Vacuum the Reservoir Sample so it throws away tuples that are not in the - //! reservoir weights or in the selection vector - void Vacuum(); - - //! Transform To sample based on reservoir sampling paper - void ConvertToReservoirSample(); - - //! Get the capactiy of the data chunk reserved for storing samples - idx_t GetReservoirChunkCapacity() const; + explicit ReservoirSample(idx_t sample_count, int64_t seed = 1); - //! If for_serialization=true then the sample_chunk is not padded with extra spaces for - //! future sampling values - unique_ptr Copy() const override; - - //! create the first chunk called by AddToReservoir() - idx_t FillReservoir(DataChunk &chunk); //! Add a chunk of data to the sample void AddToReservoir(DataChunk &input) override; - //! Merge two Reservoir Samples. Other must be a reservoir sample - void Merge(unique_ptr other); - - void ShuffleSel(SelectionVector &sel, idx_t range, idx_t size) const; - - //! Update the sample by pushing new sample rows to the end of the sample_chunk. - //! The new sample rows are the tuples rows resulting from applying sel to other - void UpdateSampleAppend(DataChunk &this_, DataChunk &other, SelectionVector &other_sel, idx_t append_count) const; - - idx_t GetTuplesSeen() const; - idx_t NumSamplesCollected() const; - idx_t GetActiveSampleCount() const; - static bool ValidSampleType(const LogicalType &type); - - // get the chunk from Reservoir chunk - DataChunk &Chunk(); //! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the //! sample is completely built. - // unique_ptr GetChunkAndDestroy() override; unique_ptr GetChunk() override; - void Destroy() override; void Finalize() override; - void Verify(); - - idx_t GetSampleCount(); - - // map is [index in input chunk] -> [index in sample chunk]. Both are zero-based - // [index in sample chunk] is incremented by 1 - // index in input chunk have random values, however, they are increasing. - // The base_reservoir_sampling gets updated however, so the indexes point to (sample_chunk_offset + - // index_in_sample_chunk) this data is used to make a selection vector to copy samples from the input chunk to the - // sample chunk - //! Get indexes from current sample that can be replaced. - SelectionVectorHelper GetReplacementIndexes(idx_t sample_chunk_offset, idx_t theoretical_chunk_length); - void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); private: - // when we serialize, we may have collected too many samples since we fill a standard vector size, then - // truncate if the table is still <=204800 values. The problem is, in our weights, we store indexes into - // the selection vector. If throw away values at selection vector index i = 5 , we need to update all indexes - // i > 5. Otherwise we will have indexes in the weights that are greater than the length of our sample. - void NormalizeWeights(); - - SelectionVectorHelper GetReplacementIndexesSlow(const idx_t sample_chunk_offset, const idx_t chunk_length); - SelectionVectorHelper GetReplacementIndexesFast(const idx_t sample_chunk_offset, const idx_t chunk_length); - void SimpleMerge(ReservoirSample &other); - void WeightedMerge(ReservoirSample &other_sample); - - // Helper methods for Shrink(). - // Shrink has different logic depending on if the Reservoir sample is still in - // "Random" mode or in "reservoir" mode. This function creates a new sample chunk - // to copy the old sample chunk into - unique_ptr CreateNewSampleChunk(vector &types, idx_t size) const; - - // Get a vector where each index is a random int in the range 0, size. - // This is used to shuffle selection vector indexes - vector GetRandomizedVector(uint32_t range, uint32_t size) const; + //! Replace a single element of the input + void ReplaceElement(DataChunk &input, idx_t index_in_chunk, double with_weight = -1); + void InitializeReservoir(DataChunk &input); + //! Fills the reservoir up until sample_count entries, returns how many entries are still required + idx_t FillReservoir(DataChunk &input); - idx_t sample_count; +public: Allocator &allocator; + //! The size of the reservoir sample. + //! when calculating percentages, it is set to reservoir_threshold * percentage + //! when explicit number used, sample_count = number + idx_t sample_count; + bool reservoir_initialized; + + //! The current reservoir + unique_ptr reservoir_data_chunk; unique_ptr reservoir_chunk; - bool stats_sample; - SelectionVector sel; - idx_t sel_size; }; //! The reservoir sample sample_size class maintains a streaming sample of variable size @@ -281,16 +155,15 @@ class ReservoirSamplePercentage : public BlockingSample { public: static constexpr const SampleType TYPE = SampleType::RESERVOIR_PERCENTAGE_SAMPLE; +public: ReservoirSamplePercentage(Allocator &allocator, double percentage, int64_t seed = -1); - ReservoirSamplePercentage(double percentage, int64_t seed, idx_t reservoir_sample_size); explicit ReservoirSamplePercentage(double percentage, int64_t seed = -1); //! Add a chunk of data to the sample void AddToReservoir(DataChunk &input) override; - unique_ptr Copy() const override; - - //! Fetches a chunk from the sample. If destory = true this method is descructive + //! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the + //! sample is completely built. unique_ptr GetChunk() override; void Finalize() override; @@ -309,11 +182,9 @@ class ReservoirSamplePercentage : public BlockingSample { //! The set of finished samples of the reservoir sample vector> finished_samples; - //! The amount of tuples that have been processed so far (not put in the reservoir, just processed) idx_t current_count = 0; - //! Whether or not the stream is finalized. The stream is automatically finalized on the first call to - //! GetChunkAndShrink(); + //! Whether or not the stream is finalized. The stream is automatically finalized on the first call to GetChunk(); bool is_finalized; }; diff --git a/src/duckdb/src/include/duckdb/execution/window_executor.hpp b/src/duckdb/src/include/duckdb/execution/window_executor.hpp new file mode 100644 index 000000000..0c9a7c340 --- /dev/null +++ b/src/duckdb/src/include/duckdb/execution/window_executor.hpp @@ -0,0 +1,343 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/execution/window_executor.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/execution/expression_executor.hpp" +#include "duckdb/execution/window_segment_tree.hpp" +#include "duckdb/planner/expression/bound_window_expression.hpp" +#include "duckdb/common/vector_operations/vector_operations.hpp" + +namespace duckdb { + +// A wrapper for building DataChunks in parallel +class WindowDataChunk { +public: + // True if the vector data can just be copied to + static bool IsSimple(const Vector &v); + + static inline bool IsMaskAligned(idx_t begin, idx_t end, idx_t count) { + return ValidityMask::IsAligned(begin) && (ValidityMask::IsAligned(end) || (end == count)); + } + + explicit WindowDataChunk(DataChunk &chunk); + + void Initialize(Allocator &allocator, const vector &types, idx_t capacity); + + void Copy(DataChunk &src, idx_t begin); + + //! The wrapped chunk + DataChunk &chunk; + +private: + //! True if the column is a scalar only value + vector is_simple; + //! Exclusive lock for each column + vector locks; +}; + +struct WindowInputExpression { + static void PrepareInputExpression(Expression &expr, ExpressionExecutor &executor, DataChunk &chunk) { + vector types; + types.push_back(expr.return_type); + executor.AddExpression(expr); + + auto &allocator = executor.GetAllocator(); + chunk.Initialize(allocator, types); + } + + WindowInputExpression(optional_ptr expr_p, ClientContext &context) + : expr(expr_p), ptype(PhysicalType::INVALID), scalar(true), executor(context) { + if (expr) { + PrepareInputExpression(*expr, executor, chunk); + ptype = expr->return_type.InternalType(); + scalar = expr->IsScalar(); + } + } + + void Execute(DataChunk &input_chunk) { + if (expr) { + chunk.Reset(); + executor.Execute(input_chunk, chunk); + chunk.Verify(); + chunk.Flatten(); + } + } + + template + inline T GetCell(idx_t i) const { + D_ASSERT(!chunk.data.empty()); + const auto data = FlatVector::GetData(chunk.data[0]); + return data[scalar ? 0 : i]; + } + + inline bool CellIsNull(idx_t i) const { + D_ASSERT(!chunk.data.empty()); + if (chunk.data[0].GetVectorType() == VectorType::CONSTANT_VECTOR) { + return ConstantVector::IsNull(chunk.data[0]); + } + return FlatVector::IsNull(chunk.data[0], i); + } + + inline void CopyCell(Vector &target, idx_t target_offset, idx_t width = 1) const { + D_ASSERT(!chunk.data.empty()); + auto &source = chunk.data[0]; + auto source_offset = scalar ? 0 : target_offset; + VectorOperations::Copy(source, target, source_offset + width, source_offset, target_offset); + } + + optional_ptr expr; + PhysicalType ptype; + bool scalar; + ExpressionExecutor executor; + DataChunk chunk; +}; + +struct WindowInputColumn { + WindowInputColumn(optional_ptr expr_p, ClientContext &context, idx_t count); + + void Copy(DataChunk &input_chunk, idx_t input_idx); + + inline bool CellIsNull(idx_t i) const { + D_ASSERT(!target.data.empty()); + D_ASSERT(i < count); + return FlatVector::IsNull((target.data[0]), scalar ? 0 : i); + } + + template + inline T GetCell(idx_t i) const { + D_ASSERT(!target.data.empty()); + D_ASSERT(i < count); + const auto data = FlatVector::GetData(target.data[0]); + return data[scalar ? 0 : i]; + } + + optional_ptr expr; + PhysicalType ptype; + const bool scalar; + const idx_t count; + +private: + DataChunk target; + WindowDataChunk wtarget; +}; + +// Column indexes of the bounds chunk +enum WindowBounds : uint8_t { PARTITION_BEGIN, PARTITION_END, PEER_BEGIN, PEER_END, WINDOW_BEGIN, WINDOW_END }; + +class WindowExecutorState { +public: + WindowExecutorState() {}; + virtual ~WindowExecutorState() { + } + + template + TARGET &Cast() { + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + template + const TARGET &Cast() const { + DynamicCastCheck(this); + return reinterpret_cast(*this); + } +}; + +class WindowExecutor; + +class WindowExecutorGlobalState : public WindowExecutorState { +public: + WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, + const ValidityMask &partition_mask, const ValidityMask &order_mask); + + const WindowExecutor &executor; + + const idx_t payload_count; + const ValidityMask &partition_mask; + const ValidityMask &order_mask; + vector arg_types; + + // evaluate RANGE expressions, if needed + WindowInputColumn range; +}; + +class WindowExecutorLocalState : public WindowExecutorState { +public: + explicit WindowExecutorLocalState(const WindowExecutorGlobalState &gstate); + + void Sink(WindowExecutorGlobalState &gstate, DataChunk &input_chunk, idx_t input_idx); + + // Argument evaluation + ExpressionExecutor payload_executor; + DataChunk payload_chunk; + + //! Range evaluation + ExpressionExecutor range_executor; + DataChunk range_chunk; +}; + +class WindowExecutor { +public: + WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context); + virtual ~WindowExecutor() { + } + + virtual unique_ptr + GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) const; + virtual unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const; + + virtual void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, + WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const; + + virtual void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const { + } + + void Evaluate(idx_t row_idx, DataChunk &input_chunk, Vector &result, WindowExecutorLocalState &lstate, + WindowExecutorGlobalState &gstate) const; + + // The function + const BoundWindowExpression &wexpr; + ClientContext &context; + +protected: + virtual void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const = 0; +}; + +class WindowAggregateExecutor : public WindowExecutor { +public: + WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowAggregationMode mode); + + void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, WindowExecutorGlobalState &gstate, + WindowExecutorLocalState &lstate) const override; + void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const override; + + unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, + const ValidityMask &order_mask) const override; + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + + const WindowAggregationMode mode; + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowRowNumberExecutor : public WindowExecutor { +public: + WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +// Base class for non-aggregate functions that use peer boundaries +class WindowRankExecutor : public WindowExecutor { +public: + WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowDenseRankExecutor : public WindowExecutor { +public: + WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowPercentRankExecutor : public WindowExecutor { +public: + WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context); + + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowCumeDistExecutor : public WindowExecutor { +public: + WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +// Base class for non-aggregate functions that have a payload +class WindowValueExecutor : public WindowExecutor { +public: + WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + + void Sink(DataChunk &input_chunk, const idx_t input_idx, const idx_t total_count, WindowExecutorGlobalState &gstate, + WindowExecutorLocalState &lstate) const override; + + unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, + const ValidityMask &order_mask) const override; + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; +}; + +// +class WindowNtileExecutor : public WindowValueExecutor { +public: + WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; +class WindowLeadLagExecutor : public WindowValueExecutor { +public: + WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context); + + unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowFirstValueExecutor : public WindowValueExecutor { +public: + WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowLastValueExecutor : public WindowValueExecutor { +public: + WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +class WindowNthValueExecutor : public WindowValueExecutor { +public: + WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context); + +protected: + void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, Vector &result, + idx_t count, idx_t row_idx) const override; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp b/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp new file mode 100644 index 000000000..d70b47898 --- /dev/null +++ b/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp @@ -0,0 +1,165 @@ +//===----------------------------------------------------------------------===// +// DuckDB +// +// duckdb/execution/window_segment_tree.hpp +// +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "duckdb/common/sort/sort.hpp" +#include "duckdb/common/types/data_chunk.hpp" +#include "duckdb/execution/physical_operator.hpp" +#include "duckdb/function/aggregate_function.hpp" +#include "duckdb/common/enums/window_aggregation_mode.hpp" +#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" +#include "duckdb/parser/expression/window_expression.hpp" + +namespace duckdb { + +class WindowAggregatorState { +public: + WindowAggregatorState(); + virtual ~WindowAggregatorState() { + } + + template + TARGET &Cast() { + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + template + const TARGET &Cast() const { + DynamicCastCheck(this); + return reinterpret_cast(*this); + } + + //! Allocator for aggregates + ArenaAllocator allocator; +}; + +class WindowAggregator { +public: + WindowAggregator(AggregateObject aggr, const vector &arg_types_p, const LogicalType &result_type_p, + const WindowExcludeMode exclude_mode_p); + virtual ~WindowAggregator(); + + // Threading states + virtual unique_ptr GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const; + virtual unique_ptr GetLocalState(const WindowAggregatorState &gstate) const = 0; + + // Build + virtual void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &arg_chunk, + idx_t input_idx, optional_ptr filter_sel, idx_t filtered); + virtual void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats); + + // Probe + virtual void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const = 0; + + //! A description of the aggregator + const AggregateObject aggr; + //! The argument types for the function + const vector arg_types; + //! The result type of the window function + const LogicalType result_type; + //! The size of a single aggregate state + const idx_t state_size; + //! The window exclusion clause + const WindowExcludeMode exclude_mode; +}; + +// Used for validation +class WindowNaiveAggregator : public WindowAggregator { +public: + WindowNaiveAggregator(AggregateObject aggr, const vector &arg_types_p, + const LogicalType &result_type_p, const WindowExcludeMode exclude_mode); + ~WindowNaiveAggregator() override; + + unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; + void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const override; +}; + +class WindowConstantAggregator : public WindowAggregator { +public: + WindowConstantAggregator(AggregateObject aggr, const vector &arg_types_p, + const LogicalType &result_type_p, WindowExcludeMode exclude_mode_p); + ~WindowConstantAggregator() override { + } + + unique_ptr GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const override; + void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &arg_chunk, idx_t input_idx, + optional_ptr filter_sel, idx_t filtered) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + + unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; + void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const override; +}; + +class WindowCustomAggregator : public WindowAggregator { +public: + WindowCustomAggregator(AggregateObject aggr, const vector &arg_types_p, + const LogicalType &result_type_p, const WindowExcludeMode exclude_mode); + ~WindowCustomAggregator() override; + + unique_ptr GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + + unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; + void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const override; +}; + +class WindowSegmentTree : public WindowAggregator { + +public: + WindowSegmentTree(AggregateObject aggr, const vector &arg_types_p, const LogicalType &result_type_p, + WindowAggregationMode mode_p, const WindowExcludeMode exclude_mode); + + unique_ptr GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const override; + unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + + void Evaluate(const WindowAggregatorState &gstate, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const override; + +public: + //! Use the combine API, if available + inline bool UseCombineAPI() const { + return mode < WindowAggregationMode::SEPARATE; + } + + //! Use the combine API, if available + WindowAggregationMode mode; +}; + +class WindowDistinctAggregator : public WindowAggregator { +public: + WindowDistinctAggregator(AggregateObject aggr, const vector &arg_types_p, + const LogicalType &result_type_p, const WindowExcludeMode exclude_mode_p, + ClientContext &context); + + // Build + unique_ptr GetGlobalState(idx_t group_count, + const ValidityMask &partition_mask) const override; + void Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &arg_chunk, idx_t input_idx, + optional_ptr filter_sel, idx_t filtered) override; + void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, const FrameStats &stats) override; + + // Evaluate + unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; + void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, + Vector &result, idx_t count, idx_t row_idx) const override; + + //! Context for sorting + ClientContext &context; +}; + +} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp b/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp deleted file mode 100644 index 9f32d453f..000000000 --- a/src/duckdb/src/include/duckdb/function/aggregate/distributive_function_utils.hpp +++ /dev/null @@ -1,31 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/aggregate/distributive_function_utils.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct CountFunctionBase { - static AggregateFunction GetFunction(); -}; - -struct FirstFunctionGetter { - static AggregateFunction GetFunction(const LogicalType &type); -}; - -struct MinFunction { - static AggregateFunction GetFunction(); -}; - -struct MaxFunction { - static AggregateFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp b/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp index 7d6eb3274..cba1a7dec 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp @@ -1,87 +1,36 @@ //===----------------------------------------------------------------------===// // DuckDB // -// function/aggregate/distributive_functions.hpp +// duckdb/function/aggregate/distributive_functions.hpp // // //===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// #pragma once +#include "duckdb/function/aggregate_function.hpp" #include "duckdb/function/function_set.hpp" +#include "duckdb/common/types/null_value.hpp" +#include "duckdb/function/built_in_functions.hpp" namespace duckdb { struct CountStarFun { - static constexpr const char *Name = "count_star"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - static AggregateFunction GetFunction(); + + static void RegisterFunction(BuiltinFunctions &set); }; struct CountFun { - static constexpr const char *Name = "count"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the number of non-null values in arg."; - static constexpr const char *Example = "count(A)"; + static AggregateFunction GetFunction(); - static AggregateFunctionSet GetFunctions(); + static void RegisterFunction(BuiltinFunctions &set); }; struct FirstFun { - static constexpr const char *Name = "first"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the first value (null or non-null) from arg. This function is affected by ordering."; - static constexpr const char *Example = "first(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct ArbitraryFun { - using ALIAS = FirstFun; - - static constexpr const char *Name = "arbitrary"; -}; - -struct LastFun { - static constexpr const char *Name = "last"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the last value of a column. This function is affected by ordering."; - static constexpr const char *Example = "last(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct AnyValueFun { - static constexpr const char *Name = "any_value"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the first non-null value from arg. This function is affected by ordering."; - static constexpr const char *Example = ""; - - static AggregateFunctionSet GetFunctions(); -}; - -struct MinFun { - static constexpr const char *Name = "min"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the minimum value present in arg."; - static constexpr const char *Example = "min(A)"; - - static AggregateFunctionSet GetFunctions(); -}; - -struct MaxFun { - static constexpr const char *Name = "max"; - static constexpr const char *Parameters = "arg"; - static constexpr const char *Description = "Returns the maximum value present in arg."; - static constexpr const char *Example = "max(A)"; + static AggregateFunction GetFunction(const LogicalType &type); - static AggregateFunctionSet GetFunctions(); + static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/aggregate_function.hpp b/src/duckdb/src/include/duckdb/function/aggregate_function.hpp index e63533d5c..4d4ef63ff 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate_function.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate_function.hpp @@ -16,8 +16,6 @@ namespace duckdb { -class BufferManager; - //! A half-open range of frame boundary values _relative to the current row_ //! This is why they are signed values. struct FrameDelta { @@ -31,21 +29,14 @@ struct FrameDelta { using FrameStats = array; //! The partition data for custom window functions -//! Note that if the inputs is nullptr then the column count is 0, -//! but the row count will still be valid -class ColumnDataCollection; struct WindowPartitionInput { - WindowPartitionInput(ClientContext &context, const ColumnDataCollection *inputs, idx_t count, - vector &column_ids, vector &all_valid, const ValidityMask &filter_mask, + WindowPartitionInput(const Vector inputs[], idx_t input_count, idx_t count, const ValidityMask &filter_mask, const FrameStats &stats) - : context(context), inputs(inputs), count(count), column_ids(column_ids), all_valid(all_valid), - filter_mask(filter_mask), stats(stats) { + : inputs(inputs), input_count(input_count), count(count), filter_mask(filter_mask), stats(stats) { } - ClientContext &context; - const ColumnDataCollection *inputs; + const Vector *inputs; + idx_t input_count; idx_t count; - vector column_ids; - vector all_valid; const ValidityMask &filter_mask; const FrameStats stats; }; @@ -103,13 +94,6 @@ struct AggregateFunctionInfo { } }; -enum class AggregateDestructorType { - STANDARD, - // legacy destructors allow non-trivial destructors in aggregate states - // these might not be trivial to off-load to disk - LEGACY -}; - class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug in clang-tidy public: AggregateFunction(const string &name, const vector &arguments, const LogicalType &return_type, @@ -124,8 +108,7 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug LogicalType(LogicalTypeId::INVALID), null_handling), state_size(state_size), initialize(initialize), update(update), combine(combine), finalize(finalize), simple_update(simple_update), window(window), bind(bind), destructor(destructor), statistics(statistics), - serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT), - distinct_dependent(AggregateDistinctDependent::DISTINCT_DEPENDENT) { + serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT) { } AggregateFunction(const string &name, const vector &arguments, const LogicalType &return_type, @@ -139,8 +122,7 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug LogicalType(LogicalTypeId::INVALID)), state_size(state_size), initialize(initialize), update(update), combine(combine), finalize(finalize), simple_update(simple_update), window(window), bind(bind), destructor(destructor), statistics(statistics), - serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT), - distinct_dependent(AggregateDistinctDependent::DISTINCT_DEPENDENT) { + serialize(serialize), deserialize(deserialize), order_dependent(AggregateOrderDependent::ORDER_DEPENDENT) { } AggregateFunction(const vector &arguments, const LogicalType &return_type, aggregate_size_t state_size, @@ -195,8 +177,6 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug aggregate_deserialize_t deserialize; //! Whether or not the aggregate is order dependent AggregateOrderDependent order_dependent; - //! Whether or not the aggregate is affect by distinct modifiers - AggregateDistinctDependent distinct_dependent; //! Additional function info, passed to the bind shared_ptr function_info; @@ -217,33 +197,29 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug AggregateFunction::StateFinalize, AggregateFunction::NullaryUpdate); } - template + template static AggregateFunction UnaryAggregate(const LogicalType &input_type, LogicalType return_type, FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING) { - return AggregateFunction({input_type}, return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, - AggregateFunction::UnaryScatterUpdate, - AggregateFunction::StateCombine, - AggregateFunction::StateFinalize, null_handling, - AggregateFunction::UnaryUpdate); + return AggregateFunction( + {input_type}, return_type, AggregateFunction::StateSize, + AggregateFunction::StateInitialize, AggregateFunction::UnaryScatterUpdate, + AggregateFunction::StateCombine, AggregateFunction::StateFinalize, + null_handling, AggregateFunction::UnaryUpdate); } - template + template static AggregateFunction UnaryAggregateDestructor(LogicalType input_type, LogicalType return_type) { - auto aggregate = UnaryAggregate(input_type, return_type); + auto aggregate = UnaryAggregate(input_type, return_type); aggregate.destructor = AggregateFunction::StateDestroy; return aggregate; } - template + template static AggregateFunction BinaryAggregate(const LogicalType &a_type, const LogicalType &b_type, LogicalType return_type) { return AggregateFunction({a_type, b_type}, return_type, AggregateFunction::StateSize, - AggregateFunction::StateInitialize, + AggregateFunction::StateInitialize, AggregateFunction::BinaryScatterUpdate, AggregateFunction::StateCombine, AggregateFunction::StateFinalize, @@ -256,14 +232,8 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug return sizeof(STATE); } - template + template static void StateInitialize(const AggregateFunction &, data_ptr_t state) { - // FIXME: we should remove the "destructor_type" option in the future -#if !defined(__GNUC__) || (__GNUC__ >= 5) - static_assert(std::is_trivially_move_constructible::value || - destructor_type == AggregateDestructorType::LEGACY, - "Aggregate state must be trivially move constructible"); -#endif OP::Initialize(*reinterpret_cast(state)); } @@ -295,6 +265,16 @@ class AggregateFunction : public BaseScalarFunction { // NOLINT: work-around bug AggregateExecutor::UnaryUpdate(inputs[0], aggr_input_data, state, count); } + template + static void UnaryWindow(AggregateInputData &aggr_input_data, const WindowPartitionInput &partition, + const_data_ptr_t g_state, data_ptr_t l_state, const SubFrames &subframes, Vector &result, + idx_t rid) { + + D_ASSERT(partition.input_count == 1); + AggregateExecutor::UnaryWindow( + partition.inputs[0], partition.filter_mask, aggr_input_data, l_state, subframes, result, rid, g_state); + } + template static void BinaryScatterUpdate(Vector inputs[], AggregateInputData &aggr_input_data, idx_t input_count, Vector &states, idx_t count) { diff --git a/src/duckdb/src/include/duckdb/function/aggregate_state.hpp b/src/duckdb/src/include/duckdb/function/aggregate_state.hpp index bb0d096df..9b0015d2d 100644 --- a/src/duckdb/src/include/duckdb/function/aggregate_state.hpp +++ b/src/duckdb/src/include/duckdb/function/aggregate_state.hpp @@ -17,8 +17,6 @@ namespace duckdb { enum class AggregateType : uint8_t { NON_DISTINCT = 1, DISTINCT = 2 }; //! Whether or not the input order influences the result of the aggregate enum class AggregateOrderDependent : uint8_t { ORDER_DEPENDENT = 1, NOT_ORDER_DEPENDENT = 2 }; -//! Whether or not the input distinctness influences the result of the aggregate -enum class AggregateDistinctDependent : uint8_t { DISTINCT_DEPENDENT = 1, NOT_DISTINCT_DEPENDENT = 2 }; //! Whether or not the combiner needs to preserve the source enum class AggregateCombineType : uint8_t { PRESERVE_INPUT = 1, ALLOW_DESTRUCTIVE = 2 }; diff --git a/src/duckdb/src/include/duckdb/function/built_in_functions.hpp b/src/duckdb/src/include/duckdb/function/built_in_functions.hpp index fb8ef3166..3e665afeb 100644 --- a/src/duckdb/src/include/duckdb/function/built_in_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/built_in_functions.hpp @@ -54,12 +54,19 @@ class BuiltinFunctions { void RegisterArrowFunctions(); void RegisterSnifferFunction(); - void RegisterExtensionOverloads(); + // aggregates + void RegisterDistributiveAggregates(); + + // scalar functions + void RegisterCompressedMaterializationFunctions(); + void RegisterGenericFunctions(); + void RegisterOperators(); + void RegisterStringFunctions(); + void RegisterNestedFunctions(); + void RegisterSequenceFunctions(); // pragmas void RegisterPragmaFunctions(); - - void AddExtensionFunction(ScalarFunctionSet set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/cast/bound_cast_data.hpp b/src/duckdb/src/include/duckdb/function/cast/bound_cast_data.hpp index fe950d0d1..50b4c70ab 100644 --- a/src/duckdb/src/include/duckdb/function/cast/bound_cast_data.hpp +++ b/src/duckdb/src/include/duckdb/function/cast/bound_cast_data.hpp @@ -48,27 +48,21 @@ struct ListCast { }; struct StructBoundCastData : public BoundCastData { - StructBoundCastData(vector child_casts, LogicalType target_p, vector source_indexes_p, - vector target_indexes_p, vector target_null_indexes_p) + StructBoundCastData(vector child_casts, LogicalType target_p, vector child_member_map_p) : child_cast_info(std::move(child_casts)), target(std::move(target_p)), - source_indexes(std::move(source_indexes_p)), target_indexes(std::move(target_indexes_p)), - target_null_indexes(std::move(target_null_indexes_p)) { - D_ASSERT(child_cast_info.size() == source_indexes.size()); - D_ASSERT(source_indexes.size() == target_indexes.size()); + child_member_map(std::move(child_member_map_p)) { + D_ASSERT(child_cast_info.size() == child_member_map.size()); } StructBoundCastData(vector child_casts, LogicalType target_p) : child_cast_info(std::move(child_casts)), target(std::move(target_p)) { for (idx_t i = 0; i < child_cast_info.size(); i++) { - source_indexes.push_back(i); - target_indexes.push_back(i); + child_member_map.push_back(i); } } vector child_cast_info; LogicalType target; - vector source_indexes; - vector target_indexes; - vector target_null_indexes; + vector child_member_map; static unique_ptr BindStructToStructCast(BindCastInput &input, const LogicalType &source, const LogicalType &target); @@ -80,8 +74,7 @@ struct StructBoundCastData : public BoundCastData { for (auto &info : child_cast_info) { copy_info.push_back(info.Copy()); } - return make_uniq(std::move(copy_info), target, source_indexes, target_indexes, - target_null_indexes); + return make_uniq(std::move(copy_info), target, child_member_map); } }; diff --git a/src/duckdb/src/include/duckdb/function/compression/compression.hpp b/src/duckdb/src/include/duckdb/function/compression/compression.hpp index adf5364b7..cddfc8067 100644 --- a/src/duckdb/src/include/duckdb/function/compression/compression.hpp +++ b/src/duckdb/src/include/duckdb/function/compression/compression.hpp @@ -63,19 +63,4 @@ struct FSSTFun { static bool TypeIsSupported(const PhysicalType physical_type); }; -struct ZSTDFun { - static CompressionFunction GetFunction(PhysicalType type); - static bool TypeIsSupported(PhysicalType type); -}; - -struct RoaringCompressionFun { - static CompressionFunction GetFunction(PhysicalType type); - static bool TypeIsSupported(const PhysicalType physical_type); -}; - -struct EmptyValidityCompressionFun { - static CompressionFunction GetFunction(PhysicalType type); - static bool TypeIsSupported(const PhysicalType physical_type); -}; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/compression_function.hpp b/src/duckdb/src/include/duckdb/function/compression_function.hpp index b0546a5a2..40f50653b 100644 --- a/src/duckdb/src/include/duckdb/function/compression_function.hpp +++ b/src/duckdb/src/include/duckdb/function/compression_function.hpp @@ -19,10 +19,9 @@ namespace duckdb { class DatabaseInstance; class ColumnData; -struct ColumnDataCheckpointData; +class ColumnDataCheckpointer; class ColumnSegment; class SegmentStatistics; -class TableFilter; struct ColumnSegmentState; struct ColumnFetchState; @@ -96,11 +95,6 @@ struct CompressedSegmentState { return ""; } // LCOV_EXCL_STOP - //! Get the block ids of additional pages created by the segment - virtual vector GetAdditionalBlocks() const { // LCOV_EXCL_START - return vector(); - } // LCOV_EXCL_STOP - template TARGET &Cast() { DynamicCastCheck(this); @@ -152,7 +146,7 @@ typedef idx_t (*compression_final_analyze_t)(AnalyzeState &state); //===--------------------------------------------------------------------===// // Compress //===--------------------------------------------------------------------===// -typedef unique_ptr (*compression_init_compression_t)(ColumnDataCheckpointData &checkpoint_data, +typedef unique_ptr (*compression_init_compression_t)(ColumnDataCheckpointer &checkpointer, unique_ptr state); typedef void (*compression_compress_data_t)(CompressionState &state, Vector &scan_vector, idx_t count); typedef void (*compression_compress_finalize_t)(CompressionState &state); @@ -169,12 +163,6 @@ typedef void (*compression_scan_vector_t)(ColumnSegment &segment, ColumnScanStat //! Function prototype used for reading an arbitrary ('scan_count') number of values typedef void (*compression_scan_partial_t)(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset); -//! Function prototype used for reading a subset of the values of a vector indicated by a selection vector -typedef void (*compression_select_t)(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count); -//! Function prototype used for applying a filter to a vector while scanning that vector -typedef void (*compression_filter_t)(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - SelectionVector &sel, idx_t &sel_count, const TableFilter &filter); //! Function prototype used for reading a single value typedef void (*compression_fetch_row_t)(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx); @@ -203,8 +191,6 @@ typedef unique_ptr (*compression_deserialize_state_t)(Deseri //! Function prototype for cleaning up the segment state when the column data is dropped typedef void (*compression_cleanup_state_t)(ColumnSegment &segment); -enum class CompressionValidity : uint8_t { REQUIRES_VALIDITY, NO_VALIDITY_REQUIRED }; - class CompressionFunction { public: CompressionFunction(CompressionType type, PhysicalType data_type, compression_init_analyze_t init_analyze, @@ -220,14 +206,13 @@ class CompressionFunction { compression_serialize_state_t serialize_state = nullptr, compression_deserialize_state_t deserialize_state = nullptr, compression_cleanup_state_t cleanup_state = nullptr, - compression_init_prefetch_t init_prefetch = nullptr, compression_select_t select = nullptr, - compression_filter_t filter = nullptr) + compression_init_prefetch_t init_prefetch = nullptr) : type(type), data_type(data_type), init_analyze(init_analyze), analyze(analyze), final_analyze(final_analyze), init_compression(init_compression), compress(compress), compress_finalize(compress_finalize), init_prefetch(init_prefetch), init_scan(init_scan), scan_vector(scan_vector), scan_partial(scan_partial), - select(select), filter(filter), fetch_row(fetch_row), skip(skip), init_segment(init_segment), - init_append(init_append), append(append), finalize_append(finalize_append), revert_append(revert_append), - serialize_state(serialize_state), deserialize_state(deserialize_state), cleanup_state(cleanup_state) { + fetch_row(fetch_row), skip(skip), init_segment(init_segment), init_append(init_append), append(append), + finalize_append(finalize_append), revert_append(revert_append), serialize_state(serialize_state), + deserialize_state(deserialize_state), cleanup_state(cleanup_state) { } //! Compression type @@ -266,10 +251,6 @@ class CompressionFunction { //! this can request > vector_size as well //! this is used if a vector crosses segment boundaries, or for child columns of lists compression_scan_partial_t scan_partial; - //! scan a subset of a vector - compression_select_t select; - //! Scan and apply a filter to a vector while scanning - compression_filter_t filter; //! fetch an individual row from the compressed vector //! used for index lookups compression_fetch_row_t fetch_row; @@ -299,10 +280,6 @@ class CompressionFunction { compression_deserialize_state_t deserialize_state; //! Cleanup the segment state (optional) compression_cleanup_state_t cleanup_state; - - //! Whether the validity mask should be separately compressed - //! or this compression function can also be used to decompress the validity - CompressionValidity validity = CompressionValidity::REQUIRES_VALIDITY; }; //! The set of compression functions diff --git a/src/duckdb/src/include/duckdb/function/encoding_function.hpp b/src/duckdb/src/include/duckdb/function/encoding_function.hpp deleted file mode 100644 index f9e042e11..000000000 --- a/src/duckdb/src/include/duckdb/function/encoding_function.hpp +++ /dev/null @@ -1,78 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/encoding_function.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/enums/compression_type.hpp" -#include "duckdb/common/map.hpp" -#include "duckdb/common/mutex.hpp" -#include "duckdb/function/function.hpp" -#include "duckdb/storage/data_pointer.hpp" -#include "duckdb/storage/storage_info.hpp" - -namespace duckdb { - -struct DBConfig; - -//! Decode function, basically takes information about the decoded and the encoded buffers. -typedef void (*encode_t)(const char *encoded_buffer, idx_t &encoded_buffer_current_position, - const idx_t encoded_buffer_size, char *decoded_buffer, idx_t &decoded_buffer_current_position, - const idx_t decoded_buffer_size, char *remaining_bytes_buffer, idx_t &remaining_bytes_size); - -class EncodingFunction { -public: - EncodingFunction() : encode_function(nullptr), ratio(0), bytes_per_iteration(0) { - } - - EncodingFunction(const string &encode_type, encode_t encode_function, const idx_t ratio, - const idx_t bytes_per_iteration) - : encoding_type(encode_type), encode_function(encode_function), ratio(ratio), - bytes_per_iteration(bytes_per_iteration) { - D_ASSERT(ratio > 0); - D_ASSERT(encode_function); - D_ASSERT(bytes_per_iteration > 0); - }; - - ~EncodingFunction() {}; - - string GetType() const { - return encoding_type; - } - encode_t GetFunction() const { - return encode_function; - } - idx_t GetRatio() const { - return ratio; - } - idx_t GetBytesPerIteration() const { - return bytes_per_iteration; - } - -private: - //! The encoding type of this function (e.g., utf-8) - string encoding_type; - //! The actual encoding function - encode_t encode_function; - //! Ratio of the max size this encoded buffer could ever reach on a decoded buffer - idx_t ratio; - //! How many bytes in the decoded buffer one iteration of the encoded function can cause. - //! e.g., one iteration of Latin-1 to UTF-8 can generate max 2 bytes. - //! However, one iteration of UTF-16 to UTF-8, can generate up to 3 UTF-8 bytes. - idx_t bytes_per_iteration; -}; - -//! The set of encoding functions -struct EncodingFunctionSet { - EncodingFunctionSet() {}; - static void Initialize(DBConfig &config); - mutex lock; - case_insensitive_map_t functions; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/function.hpp b/src/duckdb/src/include/duckdb/function/function.hpp index 9d39ef2f5..8575f270f 100644 --- a/src/duckdb/src/include/duckdb/function/function.hpp +++ b/src/duckdb/src/include/duckdb/function/function.hpp @@ -13,7 +13,6 @@ #include "duckdb/common/unordered_set.hpp" #include "duckdb/main/external_dependencies.hpp" #include "duckdb/parser/column_definition.hpp" -#include "duckdb/common/enums/function_errors.hpp" namespace duckdb { class CatalogEntry; @@ -45,16 +44,6 @@ enum class FunctionNullHandling : uint8_t { DEFAULT_NULL_HANDLING = 0, SPECIAL_H //! VOLATILE -> the result of this function might change per row (e.g. RANDOM()) enum class FunctionStability : uint8_t { CONSISTENT = 0, VOLATILE = 1, CONSISTENT_WITHIN_QUERY = 2 }; -//! How to handle collations -//! PROPAGATE_COLLATIONS -> this function combines collation from its inputs and emits them again (default) -//! PUSH_COMBINABLE_COLLATIONS -> combinable collations are executed for the input arguments -//! IGNORE_COLLATIONS -> collations are completely ignored by the function -enum class FunctionCollationHandling : uint8_t { - PROPAGATE_COLLATIONS = 0, - PUSH_COMBINABLE_COLLATIONS = 1, - IGNORE_COLLATIONS = 2 -}; - struct FunctionData { DUCKDB_API virtual ~FunctionData(); @@ -161,8 +150,7 @@ class BaseScalarFunction : public SimpleFunction { DUCKDB_API BaseScalarFunction(string name, vector arguments, LogicalType return_type, FunctionStability stability, LogicalType varargs = LogicalType(LogicalTypeId::INVALID), - FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING, - FunctionErrors errors = FunctionErrors::CANNOT_ERROR); + FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING); DUCKDB_API ~BaseScalarFunction() override; //! Return type of the function @@ -171,15 +159,6 @@ class BaseScalarFunction : public SimpleFunction { FunctionStability stability; //! How this function handles NULL values FunctionNullHandling null_handling; - //! Whether or not this function can throw an error - FunctionErrors errors; - //! Collation handling of the function - FunctionCollationHandling collation_handling; - - static BaseScalarFunction SetReturnsError(BaseScalarFunction &function) { - function.errors = FunctionErrors::CAN_THROW_RUNTIME_ERROR; - return function; - } public: DUCKDB_API hash_t Hash() const; diff --git a/src/duckdb/src/include/duckdb/function/function_binder.hpp b/src/duckdb/src/include/duckdb/function/function_binder.hpp index 3bec4d379..9f1fb315d 100644 --- a/src/duckdb/src/include/duckdb/function/function_binder.hpp +++ b/src/duckdb/src/include/duckdb/function/function_binder.hpp @@ -21,10 +21,8 @@ namespace duckdb { //! The FunctionBinder class is responsible for binding functions class FunctionBinder { public: - DUCKDB_API explicit FunctionBinder(Binder &binder); DUCKDB_API explicit FunctionBinder(ClientContext &context); - optional_ptr binder; ClientContext &context; public: @@ -71,7 +69,6 @@ class FunctionBinder { DUCKDB_API static void BindSortedAggregate(ClientContext &context, BoundAggregateExpression &expr, const vector> &groups); - DUCKDB_API static void BindSortedAggregate(ClientContext &context, BoundWindowExpression &expr); private: //! Cast a set of expressions to the arguments of this function diff --git a/src/duckdb/src/include/duckdb/function/function_list.hpp b/src/duckdb/src/include/duckdb/function/function_list.hpp deleted file mode 100644 index feccb823b..000000000 --- a/src/duckdb/src/include/duckdb/function/function_list.hpp +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/function_list.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb.hpp" - -namespace duckdb { - -typedef ScalarFunction (*get_scalar_function_t)(); -typedef ScalarFunctionSet (*get_scalar_function_set_t)(); -typedef AggregateFunction (*get_aggregate_function_t)(); -typedef AggregateFunctionSet (*get_aggregate_function_set_t)(); - -struct StaticFunctionDefinition { - const char *name; - const char *parameters; - const char *description; - const char *example; - get_scalar_function_t get_function; - get_scalar_function_set_t get_function_set; - get_aggregate_function_t get_aggregate_function; - get_aggregate_function_set_t get_aggregate_function_set; -}; - -class Catalog; -struct CatalogTransaction; - -struct FunctionList { - static const StaticFunctionDefinition *GetInternalFunctionList(); - static void RegisterFunctions(Catalog &catalog, CatalogTransaction transaction); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/function_set.hpp b/src/duckdb/src/include/duckdb/function/function_set.hpp index 3a0a223b1..d20a52737 100644 --- a/src/duckdb/src/include/duckdb/function/function_set.hpp +++ b/src/duckdb/src/include/duckdb/function/function_set.hpp @@ -41,29 +41,23 @@ class FunctionSet { D_ASSERT(offset < functions.size()); return functions[offset]; } - bool MergeFunctionSet(FunctionSet new_functions, bool override = false) { + bool MergeFunctionSet(FunctionSet new_functions) { D_ASSERT(!new_functions.functions.empty()); + bool need_rewrite_entry = false; for (auto &new_func : new_functions.functions) { - bool overwritten = false; + bool can_add = true; for (auto &func : functions) { if (new_func.Equal(func)) { - // function overload already exists - if (override) { - // override it - overwritten = true; - func = new_func; - } else { - // throw an error - return false; - } + can_add = false; break; } } - if (!overwritten) { + if (can_add) { functions.push_back(new_func); + need_rewrite_entry = true; } } - return true; + return need_rewrite_entry; } }; diff --git a/src/duckdb/src/include/duckdb/function/partition_stats.hpp b/src/duckdb/src/include/duckdb/function/partition_stats.hpp deleted file mode 100644 index d703ddbe1..000000000 --- a/src/duckdb/src/include/duckdb/function/partition_stats.hpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/partition_stats.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" - -namespace duckdb { - -//! How a table is partitioned by a given set of columns -enum class TablePartitionInfo : uint8_t { - NOT_PARTITIONED, // the table is not partitioned by the given set of columns - SINGLE_VALUE_PARTITIONS, // each partition has exactly one unique value (e.g. bounds = [1,1][2,2][3,3]) - OVERLAPPING_PARTITIONS, // the partitions overlap **only** at the boundaries (e.g. bounds = [1,2][2,3][3,4] - DISJOINT_PARTITIONS // the partitions are disjoint (e.g. bounds = [1,2][3,4][5,6]) -}; - -enum class CountType { COUNT_EXACT, COUNT_APPROXIMATE }; - -struct PartitionStatistics { - PartitionStatistics(); - - //! The row id start - idx_t row_start; - //! The amount of rows in the partition - idx_t count; - //! Whether or not the count is exact or approximate - CountType count_type; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/register_function_list_helper.hpp b/src/duckdb/src/include/duckdb/function/register_function_list_helper.hpp deleted file mode 100644 index fc389cff2..000000000 --- a/src/duckdb/src/include/duckdb/function/register_function_list_helper.hpp +++ /dev/null @@ -1,69 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/register_function_list_helper.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/main/config.hpp" -#include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" - -namespace duckdb { - -static void FillFunctionParameters(FunctionDescription &function_description, const char *function_name, - vector ¶meters, vector &descriptions, vector &examples) { - for (string ¶meter : parameters) { - vector parameter_name_type = StringUtil::Split(parameter, "::"); - if (parameter_name_type.size() == 1) { - function_description.parameter_names.push_back(std::move(parameter_name_type[0])); - function_description.parameter_types.push_back(LogicalType::ANY); - } else if (parameter_name_type.size() == 2) { - function_description.parameter_names.push_back(std::move(parameter_name_type[0])); - function_description.parameter_types.push_back(DBConfig::ParseLogicalType(parameter_name_type[1])); - } else { - throw InternalException("Ill formed function variant for function '%s'", function_name); - } - } -} - -template -static void FillFunctionDescriptions(const FunctionDefinition &function, T &info) { - vector variants = StringUtil::Split(function.parameters, '\1'); - vector descriptions = StringUtil::Split(function.description, '\1'); - vector examples = StringUtil::Split(function.example, '\1'); - - // add single variant for functions that take no arguments - if (variants.empty()) { - variants.push_back(""); - } - - for (idx_t variant_index = 0; variant_index < variants.size(); variant_index++) { - FunctionDescription function_description; - // parameter_names and parameter_types - vector parameters = StringUtil::SplitWithParentheses(variants[variant_index], ','); - FillFunctionParameters(function_description, function.name, parameters, descriptions, examples); - // description - if (descriptions.size() == variants.size()) { - function_description.description = descriptions[variant_index]; - } else if (descriptions.size() == 1) { - function_description.description = descriptions[0]; - } else if (!descriptions.empty()) { - throw InternalException("Incorrect number of function descriptions for function '%s'", function.name); - } - // examples - if (examples.size() == variants.size()) { - function_description.examples = StringUtil::Split(examples[variant_index], '\2'); - } else if (examples.size() == 1) { - function_description.examples = StringUtil::Split(examples[0], '\2'); - } else if (!examples.empty()) { - throw InternalException("Incorrect number of function examples for function '%s'", function.name); - } - info.descriptions.push_back(std::move(function_description)); - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp index f9e4fe930..aab5dede1 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_functions.hpp @@ -1,180 +1,49 @@ //===----------------------------------------------------------------------===// // DuckDB // -// function/scalar/compressed_materialization_functions.hpp +// duckdb/function/scalar/compressed_materialization_functions.hpp // // //===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// #pragma once +#include "duckdb/function/built_in_functions.hpp" #include "duckdb/function/function_set.hpp" namespace duckdb { -struct InternalCompressIntegralUtinyintFun { - static constexpr const char *Name = "__internal_compress_integral_utinyint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalCompressIntegralUsmallintFun { - static constexpr const char *Name = "__internal_compress_integral_usmallint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalCompressIntegralUintegerFun { - static constexpr const char *Name = "__internal_compress_integral_uinteger"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalCompressIntegralUbigintFun { - static constexpr const char *Name = "__internal_compress_integral_ubigint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalCompressStringUtinyintFun { - static constexpr const char *Name = "__internal_compress_string_utinyint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; +struct CompressedMaterializationFunctions { + //! The types we compress integral types to + static const vector IntegralTypes(); + //! The types we compress strings to + static const vector StringTypes(); - static ScalarFunction GetFunction(); + static unique_ptr Bind(ClientContext &context, ScalarFunction &bound_function, + vector> &arguments); }; -struct InternalCompressStringUsmallintFun { - static constexpr const char *Name = "__internal_compress_string_usmallint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; +//! Needed for (de)serialization without binding +enum class CompressedMaterializationDirection : uint8_t { INVALID = 0, COMPRESS = 1, DECOMPRESS = 2 }; - static ScalarFunction GetFunction(); +struct CMIntegralCompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); + static void RegisterFunction(BuiltinFunctions &set); }; -struct InternalCompressStringUintegerFun { - static constexpr const char *Name = "__internal_compress_string_uinteger"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); +struct CMIntegralDecompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); + static void RegisterFunction(BuiltinFunctions &set); }; -struct InternalCompressStringUbigintFun { - static constexpr const char *Name = "__internal_compress_string_ubigint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); +struct CMStringCompressFun { + static ScalarFunction GetFunction(const LogicalType &result_type); + static void RegisterFunction(BuiltinFunctions &set); }; -struct InternalCompressStringHugeintFun { - static constexpr const char *Name = "__internal_compress_string_hugeint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct InternalDecompressIntegralSmallintFun { - static constexpr const char *Name = "__internal_decompress_integral_smallint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralIntegerFun { - static constexpr const char *Name = "__internal_decompress_integral_integer"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralBigintFun { - static constexpr const char *Name = "__internal_decompress_integral_bigint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralHugeintFun { - static constexpr const char *Name = "__internal_decompress_integral_hugeint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralUsmallintFun { - static constexpr const char *Name = "__internal_decompress_integral_usmallint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralUintegerFun { - static constexpr const char *Name = "__internal_decompress_integral_uinteger"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralUbigintFun { - static constexpr const char *Name = "__internal_decompress_integral_ubigint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressIntegralUhugeintFun { - static constexpr const char *Name = "__internal_decompress_integral_uhugeint"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct InternalDecompressStringFun { - static constexpr const char *Name = "__internal_decompress_string"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); +struct CMStringDecompressFun { + static ScalarFunction GetFunction(const LogicalType &input_type); + static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp deleted file mode 100644 index 8609999a9..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/compressed_materialization_utils.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/scalar/compressed_materialization_utils.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/built_in_functions.hpp" -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct CMUtils { - //! The types we compress integral types to - static const vector IntegralTypes(); - //! The types we compress strings to - static const vector StringTypes(); - - static unique_ptr Bind(ClientContext &context, ScalarFunction &bound_function, - vector> &arguments); -}; - -//! Needed for (de)serialization without binding -enum class CompressedMaterializationDirection : uint8_t { INVALID = 0, COMPRESS = 1, DECOMPRESS = 2 }; - -struct CMIntegralCompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); -}; - -struct CMIntegralDecompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type, const LogicalType &result_type); -}; - -struct CMStringCompressFun { - static ScalarFunction GetFunction(const LogicalType &result_type); -}; - -struct CMStringDecompressFun { - static ScalarFunction GetFunction(const LogicalType &input_type); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp deleted file mode 100644 index 8aac94b28..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/date_functions.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/date_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct StrfTimeFun { - static constexpr const char *Name = "strftime"; - static constexpr const char *Parameters = "data,format"; - static constexpr const char *Description = "Converts a date to a string according to the format string."; - static constexpr const char *Example = "strftime(date '1992-01-01', '%a, %-d %B %Y')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StrpTimeFun { - static constexpr const char *Name = "strptime"; - static constexpr const char *Parameters = "text::VARCHAR,format::VARCHAR\1text::VARCHAR,format-list::VARCHAR[]"; - static constexpr const char *Description = "Converts the string text to timestamp according to the format string. Throws an error on failure. To return NULL on failure, use try_strptime.\1Converts the string text to timestamp applying the format strings in the list until one succeeds. Throws an error on failure. To return NULL on failure, use try_strptime."; - static constexpr const char *Example = "strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')\1strptime('4/15/2023 10:56:00', ['%d/%m/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S'])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct TryStrpTimeFun { - static constexpr const char *Name = "try_strptime"; - static constexpr const char *Parameters = "text,format"; - static constexpr const char *Description = "Converts the string text to timestamp according to the format string. Returns NULL on failure."; - static constexpr const char *Example = "try_strptime('Wed, 1 January 1992 - 08:38:40 PM', '%a, %-d %B %Y - %I:%M:%S %p')"; - - static ScalarFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp b/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp deleted file mode 100644 index f4a4089e6..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/generic_common.hpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/scalar/generic_common.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/scalar_function.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/function/built_in_functions.hpp" -#include "duckdb/common/serializer/serializer.hpp" -#include "duckdb/common/serializer/deserializer.hpp" - -namespace duckdb { -class BoundFunctionExpression; - -struct ConstantOrNull { - static unique_ptr Bind(Value value); - static bool IsConstantOrNull(BoundFunctionExpression &expr, const Value &val); -}; - -struct ExportAggregateFunctionBindData : public FunctionData { - unique_ptr aggregate; - explicit ExportAggregateFunctionBindData(unique_ptr aggregate_p); - unique_ptr Copy() const override; - bool Equals(const FunctionData &other_p) const override; -}; - -struct ExportAggregateFunction { - static unique_ptr Bind(unique_ptr child_aggregate); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp index fd2865e6c..abd1713ed 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/generic_functions.hpp @@ -1,54 +1,45 @@ //===----------------------------------------------------------------------===// // DuckDB // -// function/scalar/generic_functions.hpp +// duckdb/function/scalar/generic_functions.hpp // // //===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// #pragma once +#include "duckdb/function/scalar_function.hpp" #include "duckdb/function/function_set.hpp" +#include "duckdb/function/built_in_functions.hpp" +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" namespace duckdb { +class BoundFunctionExpression; -struct ConstantOrNullFun { - static constexpr const char *Name = "constant_or_null"; - static constexpr const char *Parameters = "arg1,arg2"; - static constexpr const char *Description = "If arg2 is NULL, return NULL. Otherwise, return arg1."; - static constexpr const char *Example = "constant_or_null(42, NULL)"; - - static ScalarFunction GetFunction(); +struct ConstantOrNull { + static ScalarFunction GetFunction(const LogicalType &return_type); + static unique_ptr Bind(Value value); + static bool IsConstantOrNull(BoundFunctionExpression &expr, const Value &val); + static void RegisterFunction(BuiltinFunctions &set); }; -struct GetVariableFun { - static constexpr const char *Name = "getvariable"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); +struct ExportAggregateFunctionBindData : public FunctionData { + unique_ptr aggregate; + explicit ExportAggregateFunctionBindData(unique_ptr aggregate_p); + unique_ptr Copy() const override; + bool Equals(const FunctionData &other_p) const override; }; -struct ErrorFun { - static constexpr const char *Name = "error"; - static constexpr const char *Parameters = "message"; - static constexpr const char *Description = "Throws the given error message"; - static constexpr const char *Example = "error('access_mode')"; - - static ScalarFunction GetFunction(); +struct ExportAggregateFunction { + static unique_ptr Bind(unique_ptr child_aggregate); + static ScalarFunction GetCombine(); + static ScalarFunction GetFinalize(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct CreateSortKeyFun { - static constexpr const char *Name = "create_sort_key"; - static constexpr const char *Parameters = "parameters..."; - static constexpr const char *Description = "Constructs a binary-comparable sort key based on a set of input parameters and sort qualifiers"; - static constexpr const char *Example = "create_sort_key('A', 'DESC')"; - - static ScalarFunction GetFunction(); +struct GetVariableFun { + static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp b/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp index 1c091e7da..2af4b12d7 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/list/contains_or_position.hpp @@ -1,5 +1,5 @@ #pragma once -#include "duckdb/function/create_sort_key.hpp" +#include "duckdb/core_functions/create_sort_key.hpp" #include "duckdb/common/operator/comparison_operators.hpp" namespace duckdb { diff --git a/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp deleted file mode 100644 index 577b643f6..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/list_functions.hpp +++ /dev/null @@ -1,156 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/list_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct ListSelectFun { - static constexpr const char *Name = "list_select"; - static constexpr const char *Parameters = "value_list,index_list"; - static constexpr const char *Description = "Returns a list based on the elements selected by the index_list."; - static constexpr const char *Example = "list_select([10, 20, 30, 40], [1, 4])"; - - static ScalarFunction GetFunction(); -}; - -struct ArraySelectFun { - using ALIAS = ListSelectFun; - - static constexpr const char *Name = "array_select"; -}; - -struct ListWhereFun { - static constexpr const char *Name = "list_where"; - static constexpr const char *Parameters = "value_list,mask_list"; - static constexpr const char *Description = "Returns a list with the BOOLEANs in mask_list applied as a mask to the value_list."; - static constexpr const char *Example = "list_where([10, 20, 30, 40], [true, false, false, true])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayWhereFun { - using ALIAS = ListWhereFun; - - static constexpr const char *Name = "array_where"; -}; - -struct ListContainsFun { - static constexpr const char *Name = "list_contains"; - static constexpr const char *Parameters = "list,element"; - static constexpr const char *Description = "Returns true if the list contains the element."; - static constexpr const char *Example = "list_contains([1, 2, NULL], 1)"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayContainsFun { - using ALIAS = ListContainsFun; - - static constexpr const char *Name = "array_contains"; -}; - -struct ListHasFun { - using ALIAS = ListContainsFun; - - static constexpr const char *Name = "list_has"; -}; - -struct ArrayHasFun { - using ALIAS = ListContainsFun; - - static constexpr const char *Name = "array_has"; -}; - -struct ListPositionFun { - static constexpr const char *Name = "list_position"; - static constexpr const char *Parameters = "list,element"; - static constexpr const char *Description = "Returns the index of the element if the list contains the element. If the element is not found, it returns NULL."; - static constexpr const char *Example = "list_position([1, 2, NULL], 2)"; - - static ScalarFunction GetFunction(); -}; - -struct ListIndexofFun { - using ALIAS = ListPositionFun; - - static constexpr const char *Name = "list_indexof"; -}; - -struct ArrayPositionFun { - using ALIAS = ListPositionFun; - - static constexpr const char *Name = "array_position"; -}; - -struct ArrayIndexofFun { - using ALIAS = ListPositionFun; - - static constexpr const char *Name = "array_indexof"; -}; - -struct ListZipFun { - static constexpr const char *Name = "list_zip"; - static constexpr const char *Parameters = "list1,list2,..."; - static constexpr const char *Description = "Zips k LISTs to a new LIST whose length will be that of the longest list. Its elements are structs of k elements from each list list_1, …, list_k, missing elements are replaced with NULL. If truncate is set, all lists are truncated to the smallest list length."; - static constexpr const char *Example = "list_zip([1, 2], [3, 4], [5, 6])"; - - static ScalarFunction GetFunction(); -}; - -struct ArrayZipFun { - using ALIAS = ListZipFun; - - static constexpr const char *Name = "array_zip"; -}; - -struct ListExtractFun { - static constexpr const char *Name = "list_extract"; - static constexpr const char *Parameters = "list,index"; - static constexpr const char *Description = "Extract the indexth (1-based) value from the list."; - static constexpr const char *Example = "list_extract([4, 5, 6], 3)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ListElementFun { - using ALIAS = ListExtractFun; - - static constexpr const char *Name = "list_element"; -}; - -struct ListResizeFun { - static constexpr const char *Name = "list_resize"; - static constexpr const char *Parameters = "list,size[,value]"; - static constexpr const char *Description = "Resizes the list to contain size elements. Initializes new elements with value or NULL if value is not set."; - static constexpr const char *Example = "list_resize([1, 2, 3], 5, 0)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayResizeFun { - using ALIAS = ListResizeFun; - - static constexpr const char *Name = "array_resize"; -}; - -struct ArrayExtractFun { - static constexpr const char *Name = "array_extract"; - static constexpr const char *Parameters = "list,index"; - static constexpr const char *Description = "Extract the indexth (1-based) value from the array."; - static constexpr const char *Example = "array_extract('DuckDB', 2)"; - - static ScalarFunctionSet GetFunctions(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp deleted file mode 100644 index 5814a00e3..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/map_functions.hpp +++ /dev/null @@ -1,27 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/map_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct MapContainsFun { - static constexpr const char *Name = "map_contains"; - static constexpr const char *Parameters = "map,key"; - static constexpr const char *Description = "Checks if a map contains a given key."; - static constexpr const char *Example = "map_contains(MAP {'key1': 10, 'key2': 20, 'key3': 30}, 'key2')"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp index 07b16a151..e7b2f55ca 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp @@ -82,9 +82,50 @@ struct HistogramAggState { MAP_TYPE *hist; }; -unique_ptr GetBindData(idx_t index); -ScalarFunction GetKeyExtractFunction(); -ScalarFunction GetIndexExtractFunction(); -ScalarFunction GetExtractAtFunction(); +struct ListExtractFun { + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListConcatFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListContainsFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListPositionFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListResizeFun { + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListZipFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListSelectFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ListWhereFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct StructExtractFun { + static ScalarFunction KeyExtractFunction(); + static ScalarFunction IndexExtractFunction(); + static ScalarFunctionSet GetFunctions(); + static unique_ptr GetBindData(idx_t index); + static void RegisterFunction(BuiltinFunctions &set); +}; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp deleted file mode 100644 index dbb7a1461..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/operator_functions.hpp +++ /dev/null @@ -1,102 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/operator_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct OperatorAddFun { - static constexpr const char *Name = "+"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct AddFun { - using ALIAS = OperatorAddFun; - - static constexpr const char *Name = "add"; -}; - -struct OperatorSubtractFun { - static constexpr const char *Name = "-"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SubtractFun { - using ALIAS = OperatorSubtractFun; - - static constexpr const char *Name = "subtract"; -}; - -struct OperatorMultiplyFun { - static constexpr const char *Name = "*"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MultiplyFun { - using ALIAS = OperatorMultiplyFun; - - static constexpr const char *Name = "multiply"; -}; - -struct OperatorFloatDivideFun { - static constexpr const char *Name = "/"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct OperatorIntegerDivideFun { - static constexpr const char *Name = "//"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct DivideFun { - using ALIAS = OperatorIntegerDivideFun; - - static constexpr const char *Name = "divide"; -}; - -struct OperatorModuloFun { - static constexpr const char *Name = "%"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ModFun { - using ALIAS = OperatorModuloFun; - - static constexpr const char *Name = "mod"; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/operators.hpp b/src/duckdb/src/include/duckdb/function/scalar/operators.hpp index f23c5c3bc..90689a335 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/operators.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/operators.hpp @@ -14,14 +14,28 @@ namespace duckdb { -struct AddFunction { +struct AddFun { static ScalarFunction GetFunction(const LogicalType &type); static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type); + static void RegisterFunction(BuiltinFunctions &set); }; -struct SubtractFunction { +struct SubtractFun { static ScalarFunction GetFunction(const LogicalType &type); static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type); + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct MultiplyFun { + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct DivideFun { + static void RegisterFunction(BuiltinFunctions &set); +}; + +struct ModFun { + static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp index d7f6eb01a..34103bfc1 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/sequence_functions.hpp @@ -1,36 +1,45 @@ //===----------------------------------------------------------------------===// // DuckDB // -// function/scalar/sequence_functions.hpp +// duckdb/function/scalar/sequence_functions.hpp // // //===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// #pragma once +#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" +#include "duckdb/function/scalar_function.hpp" #include "duckdb/function/function_set.hpp" +#include "duckdb/function/built_in_functions.hpp" namespace duckdb { -struct CurrvalFun { - static constexpr const char *Name = "currval"; - static constexpr const char *Parameters = "'sequence_name'"; - static constexpr const char *Description = "Return the current value of the sequence. Note that nextval must be called at least once prior to calling currval."; - static constexpr const char *Example = "currval('my_sequence_name')"; +struct NextvalBindData : public FunctionData { + explicit NextvalBindData(SequenceCatalogEntry &sequence) : sequence(sequence), create_info(sequence.GetInfo()) { + } + + //! The sequence to use for the nextval computation; only if the sequence is a constant + SequenceCatalogEntry &sequence; + + //! The CreateInfo for the above sequence, if it exists + unique_ptr create_info; - static ScalarFunction GetFunction(); + unique_ptr Copy() const override { + return make_uniq(sequence); + } + + bool Equals(const FunctionData &other_p) const override { + auto &other = other_p.Cast(); + return RefersToSameObject(sequence, other.sequence); + } }; struct NextvalFun { - static constexpr const char *Name = "nextval"; - static constexpr const char *Parameters = "'sequence_name'"; - static constexpr const char *Description = "Return the following value of the sequence."; - static constexpr const char *Example = "nextval('my_sequence_name')"; - - static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; +struct CurrvalFun { + static void RegisterFunction(BuiltinFunctions &set); +}; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp deleted file mode 100644 index 642e53f9c..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/sequence_utils.hpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/scalar/sequence_functions.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" -#include "duckdb/function/scalar_function.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/function/built_in_functions.hpp" - -namespace duckdb { - -struct NextvalBindData : public FunctionData { - explicit NextvalBindData(SequenceCatalogEntry &sequence) : sequence(sequence), create_info(sequence.GetInfo()) { - } - - //! The sequence to use for the nextval computation; only if the sequence is a constant - SequenceCatalogEntry &sequence; - - //! The CreateInfo for the above sequence, if it exists - unique_ptr create_info; - - unique_ptr Copy() const override { - return make_uniq(sequence); - } - - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return RefersToSameObject(sequence, other.sequence); - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp b/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp deleted file mode 100644 index 4cf00d8c4..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/string_common.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/function/scalar_function.hpp" -#include "utf8proc_wrapper.hpp" - -namespace duckdb { - -bool IsAscii(const char *input, idx_t n); -idx_t LowerLength(const char *input_data, idx_t input_length); -void LowerCase(const char *input_data, idx_t input_length, char *result_data); -idx_t FindStrInStr(const string_t &haystack_s, const string_t &needle_s); -idx_t FindStrInStr(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, idx_t needle_size); -string_t SubstringASCII(Vector &result, string_t input, int64_t offset, int64_t length); -string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length); -string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length); - -ScalarFunction GetStringContains(); -DUCKDB_API bool Glob(const char *s, idx_t slen, const char *pattern, idx_t plen, bool allow_question_mark = true); - -static inline bool IsCharacter(char c) { - return (c & 0xc0) != 0x80; -} - -template -static inline TR Length(TA input) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - TR length = 0; - for (idx_t i = 0; i < input_length; i++) { - length += IsCharacter(input_data[i]); - } - return length; -} - -template -static inline TR GraphemeCount(TA input) { - auto input_data = input.GetData(); - auto input_length = input.GetSize(); - for (idx_t i = 0; i < input_length; i++) { - if (input_data[i] & 0x80) { - // non-ascii character: use grapheme iterator on remainder of string - return UnsafeNumericCast(Utf8Proc::GraphemeCount(input_data, input_length)); - } - } - return UnsafeNumericCast(input_length); -} - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp index ffca2c073..76dda0878 100644 --- a/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar/string_functions.hpp @@ -1,456 +1,131 @@ //===----------------------------------------------------------------------===// // DuckDB // -// function/scalar/string_functions.hpp +// duckdb/function/scalar/string_functions.hpp // // //===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// #pragma once #include "duckdb/function/function_set.hpp" +#include "utf8proc_wrapper.hpp" +#include "duckdb/function/built_in_functions.hpp" -namespace duckdb { - -struct UpperFun { - static constexpr const char *Name = "upper"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Convert string to upper case."; - static constexpr const char *Example = "upper('Hello')"; - - static ScalarFunction GetFunction(); -}; - -struct UcaseFun { - using ALIAS = UpperFun; +namespace duckdb_re2 { +class RE2; +} - static constexpr const char *Name = "ucase"; -}; +namespace duckdb { struct LowerFun { - static constexpr const char *Name = "lower"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Convert string to lower case"; - static constexpr const char *Example = "lower('Hello')"; - - static ScalarFunction GetFunction(); -}; - -struct LcaseFun { - using ALIAS = LowerFun; - - static constexpr const char *Name = "lcase"; -}; - -struct ConcatWsFun { - static constexpr const char *Name = "concat_ws"; - static constexpr const char *Parameters = "separator,string,..."; - static constexpr const char *Description = "Concatenate strings together separated by the specified separator."; - static constexpr const char *Example = "concat_ws(', ', 'Banana', 'Apple', 'Melon')"; - - static ScalarFunction GetFunction(); -}; - -struct ConcatFun { - static constexpr const char *Name = "concat"; - static constexpr const char *Parameters = "string,..."; - static constexpr const char *Description = "Concatenate many strings together."; - static constexpr const char *Example = "concat('Hello', ' ', 'World')"; - - static ScalarFunction GetFunction(); -}; - -struct ListConcatFun { - static constexpr const char *Name = "list_concat"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Concatenates two lists."; - static constexpr const char *Example = "list_concat([2, 3], [4, 5, 6])"; - - static ScalarFunction GetFunction(); -}; - -struct ListCatFun { - using ALIAS = ListConcatFun; - - static constexpr const char *Name = "list_cat"; -}; - -struct ArrayConcatFun { - using ALIAS = ListConcatFun; - - static constexpr const char *Name = "array_concat"; -}; - -struct ArrayCatFun { - using ALIAS = ListConcatFun; - - static constexpr const char *Name = "array_cat"; -}; - -struct ConcatOperatorFun { - static constexpr const char *Name = "||"; - static constexpr const char *Parameters = "list1,list2"; - static constexpr const char *Description = "Concatenates two lists."; - static constexpr const char *Example = "list_concat([2, 3], [4, 5, 6])"; - - static ScalarFunction GetFunction(); -}; - -struct PrefixFun { - static constexpr const char *Name = "prefix"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; + static const uint8_t ASCII_TO_LOWER_MAP[]; -struct SuffixFun { - static constexpr const char *Name = "suffix"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; + //! Returns the length of the result string obtained from lowercasing the given input (in bytes) + static idx_t LowerLength(const char *input_data, idx_t input_length); + //! Lowercases the string to the target output location, result_data must have space for at least LowerLength bytes + static void LowerCase(const char *input_data, idx_t input_length, char *result_data); static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct EndsWithFun { - using ALIAS = SuffixFun; - - static constexpr const char *Name = "ends_with"; -}; - -struct ContainsFun { - static constexpr const char *Name = "contains"; - static constexpr const char *Parameters = "string::VARCHAR,search_string::VARCHAR\1list::ANY[],element::ANY\1map::MAP(ANY,ANY),key::ANY"; - static constexpr const char *Description = "Returns true if search_string is found within string.\1Returns true if the list contains the element.\1Checks if a map contains a given key."; - static constexpr const char *Example = "contains('abc', 'a')\1contains([1, 2, NULL], 1)\1contains(MAP {'key1': 10, 'key2': 20, 'key3': 30}, 'key2')"; +struct UpperFun { + static const uint8_t ASCII_TO_UPPER_MAP[]; - static ScalarFunctionSet GetFunctions(); + static void RegisterFunction(BuiltinFunctions &set); }; struct StripAccentsFun { - static constexpr const char *Name = "strip_accents"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Strips accents from string."; - static constexpr const char *Example = "strip_accents('mühleisen')"; - - static ScalarFunction GetFunction(); -}; - -struct NFCNormalizeFun { - static constexpr const char *Name = "nfc_normalize"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Convert string to Unicode NFC normalized string. Useful for comparisons and ordering if text data is mixed between NFC normalized and not."; - static constexpr const char *Example = "nfc_normalize('ardèch')"; - - static ScalarFunction GetFunction(); -}; - -struct LengthFun { - static constexpr const char *Name = "length"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Number of characters in string."; - static constexpr const char *Example = "length('Hello🦆')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct LenFun { - using ALIAS = LengthFun; - - static constexpr const char *Name = "len"; -}; - -struct StrlenFun { - static constexpr const char *Name = "strlen"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Number of bytes in string."; - static constexpr const char *Example = "strlen('🦆')"; - + static bool IsAscii(const char *input, idx_t n); static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct BitLengthFun { - static constexpr const char *Name = "bit_length"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunctionSet GetFunctions(); -}; - -struct OctetLengthFun { - static constexpr const char *Name = "octet_length"; - static constexpr const char *Parameters = "blob"; - static constexpr const char *Description = "Number of bytes in blob."; - static constexpr const char *Example = "octet_length('\\xAA\\xBB'::BLOB)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct LengthGraphemeFun { - static constexpr const char *Name = "length_grapheme"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Number of grapheme clusters in string."; - static constexpr const char *Example = "length_grapheme('🤦🏼‍♂️🤦🏽‍♀️')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct ArrayLengthFun { - static constexpr const char *Name = "array_length"; - static constexpr const char *Parameters = "list"; - static constexpr const char *Description = "Returns the length of the list."; - static constexpr const char *Example = "array_length([1,2,3])"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SubstringFun { - static constexpr const char *Name = "substring"; - static constexpr const char *Parameters = "string,start,length"; - static constexpr const char *Description = "Extract substring of length characters starting from character start. Note that a start value of 1 refers to the first character of the string."; - static constexpr const char *Example = "substring('Hello', 2, 2)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct SubstrFun { - using ALIAS = SubstringFun; - - static constexpr const char *Name = "substr"; -}; - -struct SubstringGraphemeFun { - static constexpr const char *Name = "substring_grapheme"; - static constexpr const char *Parameters = "string,start,length"; - static constexpr const char *Description = "Extract substring of length grapheme clusters starting from character start. Note that a start value of 1 refers to the first character of the string."; - static constexpr const char *Example = "substring_grapheme('🦆🤦🏼‍♂️🤦🏽‍♀️🦆', 3, 2)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StringSplitFun { - static constexpr const char *Name = "string_split"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Splits the string along the separator"; - static constexpr const char *Example = "string_split('hello-world', '-')"; - +struct ConcatFun { + static void RegisterFunction(BuiltinFunctions &set); static ScalarFunction GetFunction(); }; -struct StrSplitFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "str_split"; -}; - -struct StringToArrayFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "string_to_array"; -}; - -struct SplitFun { - using ALIAS = StringSplitFun; - - static constexpr const char *Name = "split"; -}; - -struct StringSplitRegexFun { - static constexpr const char *Name = "string_split_regex"; - static constexpr const char *Parameters = "string,separator"; - static constexpr const char *Description = "Splits the string along the regex"; - static constexpr const char *Example = "string_split_regex('hello␣world; 42', ';?␣')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StrSplitRegexFun { - using ALIAS = StringSplitRegexFun; - - static constexpr const char *Name = "str_split_regex"; -}; - -struct RegexpSplitToArrayFun { - using ALIAS = StringSplitRegexFun; - - static constexpr const char *Name = "regexp_split_to_array"; -}; - -struct RegexpFun { - static constexpr const char *Name = "regexp_full_match"; - static constexpr const char *Parameters = "string,regex[,options]"; - static constexpr const char *Description = "Returns true if the entire string matches the regex. A set of optional options can be set."; - static constexpr const char *Example = "regexp_full_match('anabanana', '(an)*')"; - - static ScalarFunctionSet GetFunctions(); +struct ConcatWSFun { + static void RegisterFunction(BuiltinFunctions &set); }; -struct RegexpMatchesFun { - static constexpr const char *Name = "regexp_matches"; - static constexpr const char *Parameters = "string,pattern[,options]"; - static constexpr const char *Description = "Returns true if string contains the regexp pattern, false otherwise. A set of optional options can be set."; - static constexpr const char *Example = "regexp_matches('anabanana', '(an)*')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RegexpReplaceFun { - static constexpr const char *Name = "regexp_replace"; - static constexpr const char *Parameters = "string,pattern,replacement[,options]"; - static constexpr const char *Description = "If string contains the regexp pattern, replaces the matching part with replacement. A set of optional options can be set."; - static constexpr const char *Example = "regexp_replace('hello', '[lo]', '-')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RegexpExtractFun { - static constexpr const char *Name = "regexp_extract"; - static constexpr const char *Parameters = "string,pattern[,group = 0][,options]"; - static constexpr const char *Description = "If string contains the regexp pattern, returns the capturing group specified by optional parameter group. The group must be a constant value. If no group is given, it defaults to 0. A set of optional options can be set."; - static constexpr const char *Example = "regexp_extract('abc', '([a-z])(b)', 1)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RegexpExtractAllFun { - static constexpr const char *Name = "regexp_extract_all"; - static constexpr const char *Parameters = "string, regex[, group = 0][, options]"; - static constexpr const char *Description = "Split the string along the regex and extract all occurrences of group. A set of optional options can be set."; - static constexpr const char *Example = "regexp_extract_all('hello_world', '([a-z ]+)_?', 1)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct RegexpEscapeFun { - static constexpr const char *Name = "regexp_escape"; - static constexpr const char *Parameters = "string"; - static constexpr const char *Description = "Escapes all potentially meaningful regexp characters in the input string"; - static constexpr const char *Example = "regexp_escape('https://duckdb.org')"; - - static ScalarFunction GetFunction(); +struct LengthFun { + static void RegisterFunction(BuiltinFunctions &set); + static inline bool IsCharacter(char c) { + return (c & 0xc0) != 0x80; + } + + template + static inline TR Length(TA input) { + auto input_data = input.GetData(); + auto input_length = input.GetSize(); + TR length = 0; + for (idx_t i = 0; i < input_length; i++) { + length += IsCharacter(input_data[i]); + } + return length; + } + + template + static inline TR GraphemeCount(TA input) { + auto input_data = input.GetData(); + auto input_length = input.GetSize(); + for (idx_t i = 0; i < input_length; i++) { + if (input_data[i] & 0x80) { + // non-ascii character: use grapheme iterator on remainder of string + return UnsafeNumericCast(Utf8Proc::GraphemeCount(input_data, input_length)); + } + } + return UnsafeNumericCast(input_length); + } }; struct LikeFun { - static constexpr const char *Name = "~~"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct NotLikeFun { - static constexpr const char *Name = "!~~"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct GlobPatternFun { - static constexpr const char *Name = "~~~"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct ILikeFun { - static constexpr const char *Name = "~~*"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct NotILikeFun { - static constexpr const char *Name = "!~~*"; - static constexpr const char *Parameters = ""; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); + static ScalarFunction GetLikeFunction(); + static void RegisterFunction(BuiltinFunctions &set); + DUCKDB_API static bool Glob(const char *s, idx_t slen, const char *pattern, idx_t plen, + bool allow_question_mark = true); }; struct LikeEscapeFun { - static constexpr const char *Name = "like_escape"; - static constexpr const char *Parameters = "string,like_specifier,escape_character"; - static constexpr const char *Description = "Returns true if the string matches the like_specifier (see Pattern Matching) using case-sensitive matching. escape_character is used to search for wildcard characters in the string."; - static constexpr const char *Example = "like_escape('a%c', 'a$%c', '$')"; - - static ScalarFunction GetFunction(); + static ScalarFunction GetLikeEscapeFun(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct NotLikeEscapeFun { - static constexpr const char *Name = "not_like_escape"; - static constexpr const char *Parameters = "string,like_specifier,escape_character"; - static constexpr const char *Description = "Returns false if the string matches the like_specifier (see Pattern Matching) using case-sensitive matching. escape_character is used to search for wildcard characters in the string."; - static constexpr const char *Example = "not_like_escape('a%c', 'a$%c', '$')"; - +struct NFCNormalizeFun { static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct IlikeEscapeFun { - static constexpr const char *Name = "ilike_escape"; - static constexpr const char *Parameters = "string,like_specifier,escape_character"; - static constexpr const char *Description = "Returns true if the string matches the like_specifier (see Pattern Matching) using case-insensitive matching. escape_character is used to search for wildcard characters in the string."; - static constexpr const char *Example = "ilike_escape('A%c', 'a$%C', '$')"; - - static ScalarFunction GetFunction(); +struct SubstringFun { + static void RegisterFunction(BuiltinFunctions &set); + static string_t SubstringUnicode(Vector &result, string_t input, int64_t offset, int64_t length); + static string_t SubstringGrapheme(Vector &result, string_t input, int64_t offset, int64_t length); }; -struct NotIlikeEscapeFun { - static constexpr const char *Name = "not_ilike_escape"; - static constexpr const char *Parameters = "string,like_specifier,escape_character"; - static constexpr const char *Description = "Returns false if the string matches the like_specifier (see Pattern Matching) using case-insensitive matching. escape_character is used to search for wildcard characters in the string."; - static constexpr const char *Example = "not_ilike_escape('A%c', 'a$%C', '$')"; - +struct PrefixFun { static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct MD5Fun { - static constexpr const char *Name = "md5"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the MD5 hash of the value as a string"; - static constexpr const char *Example = "md5('123')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct MD5NumberFun { - static constexpr const char *Name = "md5_number"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the MD5 hash of the value as an INT128"; - static constexpr const char *Example = "md5_number('123')"; - - static ScalarFunctionSet GetFunctions(); +struct SuffixFun { + static ScalarFunction GetFunction(); + static void RegisterFunction(BuiltinFunctions &set); }; -struct SHA1Fun { - static constexpr const char *Name = "sha1"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the SHA1 hash of the value"; - static constexpr const char *Example = "sha1('hello')"; - +struct ContainsFun { static ScalarFunctionSet GetFunctions(); + static ScalarFunction GetStringContains(); + static void RegisterFunction(BuiltinFunctions &set); + static idx_t Find(const string_t &haystack, const string_t &needle); + static idx_t Find(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle, + idx_t needle_size); }; -struct SHA256Fun { - static constexpr const char *Name = "sha256"; - static constexpr const char *Parameters = "value"; - static constexpr const char *Description = "Returns the SHA256 hash of the value"; - static constexpr const char *Example = "sha256('hello')"; - - static ScalarFunctionSet GetFunctions(); +struct RegexpFun { + static void RegisterFunction(BuiltinFunctions &set); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp deleted file mode 100644 index fa11d636f..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/struct_functions.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/struct_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct StructExtractFun { - static constexpr const char *Name = "struct_extract"; - static constexpr const char *Parameters = "struct,'entry'"; - static constexpr const char *Description = "Extract the named entry from the STRUCT."; - static constexpr const char *Example = "struct_extract({'i': 3, 'v2': 3, 'v3': 0}, 'i')"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StructExtractAtFun { - static constexpr const char *Name = "struct_extract_at"; - static constexpr const char *Parameters = "struct,'entry'"; - static constexpr const char *Description = "Extract the entry from the STRUCT by position (starts at 1!)."; - static constexpr const char *Example = "struct_extract_at({'i': 3, 'v2': 3, 'v3': 0}, 2)"; - - static ScalarFunctionSet GetFunctions(); -}; - -struct StructPackFun { - static constexpr const char *Name = "struct_pack"; - static constexpr const char *Parameters = "name:=any,..."; - static constexpr const char *Description = "Create a STRUCT containing the argument values. The entry name will be the bound variable name."; - static constexpr const char *Example = "struct_pack(i := 4, s := 'string')"; - - static ScalarFunction GetFunction(); -}; - -struct RowFun { - static constexpr const char *Name = "row"; - static constexpr const char *Parameters = "any,..."; - static constexpr const char *Description = "Create an unnamed STRUCT (tuple) containing the argument values."; - static constexpr const char *Example = "row(i, i % 4, i / 4)"; - - static ScalarFunction GetFunction(); -}; - -struct StructConcatFun { - static constexpr const char *Name = "struct_concat"; - static constexpr const char *Parameters = "struct,struct,..."; - static constexpr const char *Description = "Merge the multiple STRUCTs into a single STRUCT."; - static constexpr const char *Example = "struct_concat(struct_pack(i := 4), struct_pack(s := 'string'))"; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/struct_utils.hpp b/src/duckdb/src/include/duckdb/function/scalar/struct_utils.hpp deleted file mode 100644 index d92acd59e..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/struct_utils.hpp +++ /dev/null @@ -1,33 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/scalar/struct_utils.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/scalar_function.hpp" -#include "duckdb/function/function_set.hpp" -#include "duckdb/function/built_in_functions.hpp" - -namespace duckdb { - -struct StructExtractBindData : public FunctionData { - explicit StructExtractBindData(idx_t index) : index(index) { - } - - idx_t index; - -public: - unique_ptr Copy() const override { - return make_uniq(index); - } - bool Equals(const FunctionData &other_p) const override { - auto &other = other_p.Cast(); - return index == other.index; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp b/src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp deleted file mode 100644 index c7a2fe269..000000000 --- a/src/duckdb/src/include/duckdb/function/scalar/system_functions.hpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// function/scalar/system_functions.hpp -// -// -//===----------------------------------------------------------------------===// -// This file is automatically generated by scripts/generate_functions.py -// Do not edit this file manually, your changes will be overwritten -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/function_set.hpp" - -namespace duckdb { - -struct FinalizeFun { - static constexpr const char *Name = "finalize"; - static constexpr const char *Parameters = "col0"; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -struct CombineFun { - static constexpr const char *Name = "combine"; - static constexpr const char *Parameters = "col0,col1"; - static constexpr const char *Description = ""; - static constexpr const char *Example = ""; - - static ScalarFunction GetFunction(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/scalar_function.hpp b/src/duckdb/src/include/duckdb/function/scalar_function.hpp index 236356b9a..ff658383e 100644 --- a/src/duckdb/src/include/duckdb/function/scalar_function.hpp +++ b/src/duckdb/src/include/duckdb/function/scalar_function.hpp @@ -51,8 +51,8 @@ struct ScalarFunctionInfo { class Binder; class BoundFunctionExpression; +class LogicalDependencyList; class ScalarFunctionCatalogEntry; - struct StatementProperties; struct FunctionStatisticsInput { @@ -87,25 +87,17 @@ struct FunctionBindExpressionInput { BoundFunctionExpression &function; }; -struct ScalarFunctionBindInput { - explicit ScalarFunctionBindInput(Binder &binder) : binder(binder) { - } - - Binder &binder; -}; - //! The scalar function type typedef std::function scalar_function_t; //! The type to bind the scalar function and to create the function data typedef unique_ptr (*bind_scalar_function_t)(ClientContext &context, ScalarFunction &bound_function, vector> &arguments); -typedef unique_ptr (*bind_scalar_function_extended_t)(ScalarFunctionBindInput &bind_input, - ScalarFunction &bound_function, - vector> &arguments); //! The type to initialize a thread local state for the scalar function typedef unique_ptr (*init_local_state_t)(ExpressionState &state, const BoundFunctionExpression &expr, FunctionData *bind_data); +//! The type to add the dependencies of this BoundFunctionExpression to the set of dependencies +typedef void (*dependency_function_t)(BoundFunctionExpression &expr, LogicalDependencyList &dependencies); //! The type to propagate statistics for this scalar function typedef unique_ptr (*function_statistics_t)(ClientContext &context, FunctionStatisticsInput &input); //! The type to bind lambda-specific parameter types @@ -124,16 +116,15 @@ class ScalarFunction : public BaseScalarFunction { // NOLINT: work-around bug in public: DUCKDB_API ScalarFunction(string name, vector arguments, LogicalType return_type, scalar_function_t function, bind_scalar_function_t bind = nullptr, - bind_scalar_function_extended_t bind_extended = nullptr, - function_statistics_t statistics = nullptr, init_local_state_t init_local_state = nullptr, + dependency_function_t dependency = nullptr, function_statistics_t statistics = nullptr, + init_local_state_t init_local_state = nullptr, LogicalType varargs = LogicalType(LogicalTypeId::INVALID), FunctionStability stability = FunctionStability::CONSISTENT, FunctionNullHandling null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING, bind_lambda_function_t bind_lambda = nullptr); DUCKDB_API ScalarFunction(vector arguments, LogicalType return_type, scalar_function_t function, - bind_scalar_function_t bind = nullptr, - bind_scalar_function_extended_t bind_extended = nullptr, + bind_scalar_function_t bind = nullptr, dependency_function_t dependency = nullptr, function_statistics_t statistics = nullptr, init_local_state_t init_local_state = nullptr, LogicalType varargs = LogicalType(LogicalTypeId::INVALID), FunctionStability stability = FunctionStability::CONSISTENT, @@ -144,10 +135,10 @@ class ScalarFunction : public BaseScalarFunction { // NOLINT: work-around bug in scalar_function_t function; //! The bind function (if any) bind_scalar_function_t bind; - //! The bind function that receives extra input to perform more complex binding operations (if any) - bind_scalar_function_extended_t bind_extended = nullptr; //! Init thread local state for the function (if any) init_local_state_t init_local_state; + //! The dependency function (if any) + dependency_function_t dependency; //! The statistics propagation function (if any) function_statistics_t statistics; //! The lambda bind function (if any) diff --git a/src/duckdb/src/include/duckdb/function/table/arrow.hpp b/src/duckdb/src/include/duckdb/function/table/arrow.hpp index 7db6cd363..bc88fed02 100644 --- a/src/duckdb/src/include/duckdb/function/table/arrow.hpp +++ b/src/duckdb/src/include/duckdb/function/table/arrow.hpp @@ -65,8 +65,6 @@ struct ArrowScanFunctionData : public TableFunctionData { shared_ptr dependency; //! Arrow table data ArrowTableType arrow_table; - //! Whether projection pushdown is enabled on the scan - bool projection_pushdown_enabled = true; }; struct ArrowRunEndEncodingState { @@ -186,12 +184,9 @@ struct ArrowTableFunction { //! Binds an arrow table static unique_ptr ArrowScanBind(ClientContext &context, TableFunctionBindInput &input, vector &return_types, vector &names); - static unique_ptr ArrowScanBindDumb(ClientContext &context, TableFunctionBindInput &input, - vector &return_types, vector &names); //! Actual conversion from Arrow to DuckDB static void ArrowToDuckDB(ArrowScanLocalState &scan_state, const arrow_column_map_t &arrow_convert_data, - DataChunk &output, idx_t start, bool arrow_scan_is_projected = true, - idx_t rowid_column_index = COLUMN_IDENTIFIER_ROW_ID); + DataChunk &output, idx_t start, bool arrow_scan_is_projected = true); //! Get next scan state static bool ArrowScanParallelStateNext(ClientContext &context, const FunctionData *bind_data_p, @@ -219,7 +214,8 @@ struct ArrowTableFunction { static idx_t ArrowScanMaxThreads(ClientContext &context, const FunctionData *bind_data); //! Allows parallel Create Table / Insertion - static OperatorPartitionData ArrowGetPartitionData(ClientContext &context, TableFunctionGetPartitionInput &input); + static idx_t ArrowGetBatchIndex(ClientContext &context, const FunctionData *bind_data_p, + LocalTableFunctionState *local_state, GlobalTableFunctionState *global_state); //! Specify if a given type can be pushed-down by the arrow engine static bool ArrowPushdownType(const LogicalType &type); diff --git a/src/duckdb/src/include/duckdb/function/table/read_csv.hpp b/src/duckdb/src/include/duckdb/function/table/read_csv.hpp index 67ab686b3..ef9622b7d 100644 --- a/src/duckdb/src/include/duckdb/function/table/read_csv.hpp +++ b/src/duckdb/src/include/duckdb/function/table/read_csv.hpp @@ -25,7 +25,7 @@ class StringValueScanner; class ReadCSV { public: - static unique_ptr OpenCSV(const string &file_path, const CSVReaderOptions &options, + static unique_ptr OpenCSV(const string &file_path, FileCompressionType compression, ClientContext &context); }; @@ -35,8 +35,8 @@ struct BaseCSVData : public TableFunctionData { //! The CSV reader options CSVReaderOptions options; //! Offsets for generated columns - idx_t filename_col_idx {}; - idx_t hive_partition_col_idx {}; + idx_t filename_col_idx; + idx_t hive_partition_col_idx; void Finalize(); }; @@ -46,9 +46,6 @@ struct WriteCSVData : public BaseCSVData { : sql_types(std::move(sql_types)) { files.push_back(std::move(file_path)); options.name_list = std::move(names); - if (options.dialect_options.state_machine_options.escape == '\0') { - options.dialect_options.state_machine_options.escape = options.dialect_options.state_machine_options.quote; - } } //! The SQL types to write @@ -57,7 +54,7 @@ struct WriteCSVData : public BaseCSVData { string newline = "\n"; //! The size of the CSV file (in bytes) that we buffer before we flush it to disk idx_t flush_size = 4096ULL * 8ULL; - //! For each byte whether the CSV file requires quotes when containing the byte + //! For each byte whether or not the CSV file requires quotes when containing the byte unsafe_unique_array requires_quotes; //! Expressions used to convert the input into strings vector> cast_expressions; diff --git a/src/duckdb/src/include/duckdb/function/table/system_functions.hpp b/src/duckdb/src/include/duckdb/function/table/system_functions.hpp index 689b55201..fae4b5100 100644 --- a/src/duckdb/src/include/duckdb/function/table/system_functions.hpp +++ b/src/duckdb/src/include/duckdb/function/table/system_functions.hpp @@ -18,8 +18,6 @@ struct PragmaCollations { }; struct PragmaTableInfo { - static void GetColumnInfo(TableCatalogEntry &table, const ColumnDefinition &column, DataChunk &output, idx_t index); - static void RegisterFunction(BuiltinFunctions &set); }; @@ -107,10 +105,6 @@ struct DuckDBTablesFun { static void RegisterFunction(BuiltinFunctions &set); }; -struct DuckDBTableSample { - static void RegisterFunction(BuiltinFunctions &set); -}; - struct DuckDBTemporaryFilesFun { static void RegisterFunction(BuiltinFunctions &set); }; diff --git a/src/duckdb/src/include/duckdb/function/table/table_scan.hpp b/src/duckdb/src/include/duckdb/function/table/table_scan.hpp index e5c88e84f..23015d33f 100644 --- a/src/duckdb/src/include/duckdb/function/table/table_scan.hpp +++ b/src/duckdb/src/include/duckdb/function/table/table_scan.hpp @@ -20,26 +20,28 @@ struct TableScanBindData : public TableFunctionData { explicit TableScanBindData(DuckTableEntry &table) : table(table), is_index_scan(false), is_create_index(false) { } - //! The table to scan. + //! The table to scan DuckTableEntry &table; - //! The old purpose of this field has been deprecated. - //! We now use it to express an index scan in the ANALYZE call. - //! I.e., we const-cast the bind data and set this to true, if we opt for an index scan. + + //! Whether or not the table scan is an index scan. bool is_index_scan; //! Whether or not the table scan is for index creation. bool is_create_index; + //! The row ids to fetch in case of an index scan. + unsafe_vector row_ids; public: bool Equals(const FunctionData &other_p) const override { auto &other = other_p.Cast(); - return &other.table == &table; + return &other.table == &table && row_ids == other.row_ids; } }; -//! The table scan function represents a sequential or index scan over one of DuckDB's base tables. +//! The table scan function represents a sequential scan over one of DuckDB's base tables. struct TableScanFunction { static void RegisterFunction(BuiltinFunctions &set); static TableFunction GetFunction(); + static TableFunction GetIndexScanFunction(); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/table_function.hpp b/src/duckdb/src/include/duckdb/function/table_function.hpp index 6293100ef..d15990d07 100644 --- a/src/duckdb/src/include/duckdb/function/table_function.hpp +++ b/src/duckdb/src/include/duckdb/function/table_function.hpp @@ -15,8 +15,6 @@ #include "duckdb/planner/bind_context.hpp" #include "duckdb/planner/logical_operator.hpp" #include "duckdb/storage/statistics/node_statistics.hpp" -#include "duckdb/common/column_index.hpp" -#include "duckdb/function/partition_stats.hpp" #include @@ -25,12 +23,9 @@ namespace duckdb { class BaseStatistics; class LogicalDependencyList; class LogicalGet; -class TableFunction; class TableFilterSet; class TableCatalogEntry; struct MultiFileReader; -struct OperatorPartitionData; -struct OperatorPartitionInfo; struct TableFunctionInfo { DUCKDB_API virtual ~TableFunctionInfo(); @@ -106,44 +101,27 @@ struct TableFunctionBindInput { }; struct TableFunctionInitInput { - TableFunctionInitInput(optional_ptr bind_data_p, vector column_ids_p, - const vector &projection_ids_p, optional_ptr filters_p, - optional_ptr sample_options_p = nullptr) - : bind_data(bind_data_p), column_ids(std::move(column_ids_p)), projection_ids(projection_ids_p), - filters(filters_p), sample_options(sample_options_p) { - for (auto &col_id : column_ids) { - column_indexes.emplace_back(col_id); - } - } - - TableFunctionInitInput(optional_ptr bind_data_p, vector column_indexes_p, - const vector &projection_ids_p, optional_ptr filters_p, - optional_ptr sample_options_p = nullptr) - : bind_data(bind_data_p), column_indexes(std::move(column_indexes_p)), projection_ids(projection_ids_p), - filters(filters_p), sample_options(sample_options_p) { - for (auto &col_id : column_indexes) { - column_ids.emplace_back(col_id.GetPrimaryIndex()); - } + TableFunctionInitInput(optional_ptr bind_data_p, const vector &column_ids_p, + const vector &projection_ids_p, optional_ptr filters_p) + : bind_data(bind_data_p), column_ids(column_ids_p), projection_ids(projection_ids_p), filters(filters_p) { } optional_ptr bind_data; - vector column_ids; - vector column_indexes; + const vector &column_ids; const vector projection_ids; optional_ptr filters; - optional_ptr sample_options; bool CanRemoveFilterColumns() const { if (projection_ids.empty()) { - // No filter columns to remove. + // Not set, can't remove filter columns return false; - } - if (projection_ids.size() == column_ids.size()) { - // Filter column is used in remainder of plan, so we cannot remove it. + } else if (projection_ids.size() == column_ids.size()) { + // Filter column is used in remainder of plan, can't remove return false; + } else { + // Less columns need to be projected out than that we scan + return true; } - // Fewer columns need to be projected out than that we scan. - return true; } }; @@ -161,50 +139,7 @@ struct TableFunctionInput { optional_ptr global_state; }; -struct TableFunctionPartitionInput { - TableFunctionPartitionInput(optional_ptr bind_data_p, const vector &partition_ids) - : bind_data(bind_data_p), partition_ids(partition_ids) { - } - - optional_ptr bind_data; - const vector &partition_ids; -}; - -struct TableFunctionToStringInput { - TableFunctionToStringInput(const TableFunction &table_function_p, optional_ptr bind_data_p) - : table_function(table_function_p), bind_data(bind_data_p) { - } - const TableFunction &table_function; - optional_ptr bind_data; -}; - -struct TableFunctionGetPartitionInput { -public: - TableFunctionGetPartitionInput(optional_ptr bind_data_p, - optional_ptr local_state_p, - optional_ptr global_state_p, - const OperatorPartitionInfo &partition_info_p) - : bind_data(bind_data_p), local_state(local_state_p), global_state(global_state_p), - partition_info(partition_info_p) { - } - -public: - optional_ptr bind_data; - optional_ptr local_state; - optional_ptr global_state; - const OperatorPartitionInfo &partition_info; -}; - -struct GetPartitionStatsInput { - GetPartitionStatsInput(const TableFunction &table_function_p, optional_ptr bind_data_p) - : table_function(table_function_p), bind_data(bind_data_p) { - } - - const TableFunction &table_function; - optional_ptr bind_data; -}; - -enum class ScanType : uint8_t { TABLE, PARQUET, EXTERNAL }; +enum class ScanType : uint8_t { TABLE, PARQUET }; struct BindInfo { public: @@ -261,12 +196,13 @@ typedef OperatorResultType (*table_in_out_function_t)(ExecutionContext &context, DataChunk &input, DataChunk &output); typedef OperatorFinalizeResultType (*table_in_out_function_final_t)(ExecutionContext &context, TableFunctionInput &data, DataChunk &output); -typedef OperatorPartitionData (*table_function_get_partition_data_t)(ClientContext &context, - TableFunctionGetPartitionInput &input); +typedef idx_t (*table_function_get_batch_index_t)(ClientContext &context, const FunctionData *bind_data, + LocalTableFunctionState *local_state, + GlobalTableFunctionState *global_state); typedef BindInfo (*table_function_get_bind_info_t)(const optional_ptr bind_data); -typedef unique_ptr (*table_function_get_multi_file_reader_t)(const TableFunction &); +typedef unique_ptr (*table_function_get_multi_file_reader_t)(); typedef bool (*table_function_supports_pushdown_type_t)(const LogicalType &type); @@ -278,7 +214,7 @@ typedef unique_ptr (*table_function_cardinality_t)(ClientContext typedef void (*table_function_pushdown_complex_filter_t)(ClientContext &context, LogicalGet &get, FunctionData *bind_data, vector> &filters); -typedef InsertionOrderPreservingMap (*table_function_to_string_t)(TableFunctionToStringInput &input); +typedef string (*table_function_to_string_t)(const FunctionData *bind_data); typedef void (*table_function_serialize_t)(Serializer &serializer, const optional_ptr bind_data, const TableFunction &function); @@ -286,11 +222,6 @@ typedef unique_ptr (*table_function_deserialize_t)(Deserializer &d typedef void (*table_function_type_pushdown_t)(ClientContext &context, optional_ptr bind_data, const unordered_map &new_column_types); -typedef TablePartitionInfo (*table_function_get_partition_info_t)(ClientContext &context, - TableFunctionPartitionInput &input); - -typedef vector (*table_function_get_partition_stats_t)(ClientContext &context, - GetPartitionStatsInput &input); //! When to call init_global to initialize the table function enum class TableFunctionInitialization { INITIALIZE_ON_EXECUTE, INITIALIZE_ON_SCHEDULE }; @@ -346,8 +277,8 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou table_function_to_string_t to_string; //! (Optional) return how much of the table we have scanned up to this point (% of the data) table_function_progress_t table_scan_progress; - //! (Optional) returns the partition info of the current scan operator - table_function_get_partition_data_t get_partition_data; + //! (Optional) returns the current batch index of the current scan operator + table_function_get_batch_index_t get_batch_index; //! (Optional) returns extra bind info table_function_get_bind_info_t get_bind_info; //! (Optional) pushes down type information to scanner, returns true if pushdown was successful @@ -356,10 +287,6 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou table_function_get_multi_file_reader_t get_multi_file_reader; //! (Optional) If this scanner supports filter pushdown, but not to all data types table_function_supports_pushdown_type_t supports_pushdown_type; - //! Get partition info of the table - table_function_get_partition_info_t get_partition_info; - //! (Optional) get a list of all the partition stats of the table - table_function_get_partition_stats_t get_partition_stats; table_function_serialize_t serialize; table_function_deserialize_t deserialize; @@ -374,9 +301,6 @@ class TableFunction : public SimpleNamedParameterFunction { // NOLINT: work-arou //! Whether or not the table function can immediately prune out filter columns that are unused in the remainder of //! the query plan, e.g., "SELECT i FROM tbl WHERE j = 42;" - j does not need to leave the table function at all bool filter_prune; - //! Whether or not the table function supports sampling pushdown. If not supported a sample will be taken after the - //! table function. - bool sampling_pushdown; //! Additional function info, passed to the bind shared_ptr function_info; diff --git a/src/duckdb/src/include/duckdb/function/window/window_aggregate_function.hpp b/src/duckdb/src/include/duckdb/function/window/window_aggregate_function.hpp deleted file mode 100644 index efc782b8c..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_aggregate_function.hpp +++ /dev/null @@ -1,44 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_aggregate_function.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_executor.hpp" -#include "duckdb/common/enums/window_aggregation_mode.hpp" -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowAggregateExecutor : public WindowExecutor { -public: - WindowAggregateExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared, - WindowAggregationMode mode); - - void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, WindowExecutorGlobalState &gstate, - WindowExecutorLocalState &lstate) const override; - void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const override; - - unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) const override; - unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; - - const WindowAggregationMode mode; - - // aggregate computation algorithm - unique_ptr aggregator; - - // FILTER reference expression in sink_chunk - unique_ptr filter_ref; - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_aggregate_states.hpp b/src/duckdb/src/include/duckdb/function/window/window_aggregate_states.hpp deleted file mode 100644 index 1382a522c..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_aggregate_states.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_aggregate_states.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" - -namespace duckdb { - -struct WindowAggregateStates { - explicit WindowAggregateStates(const AggregateObject &aggr); - ~WindowAggregateStates() { - Destroy(); - } - - //! The number of states - idx_t GetCount() const { - return states.size() / state_size; - } - data_ptr_t *GetData() { - return FlatVector::GetData(*statef); - } - data_ptr_t GetStatePtr(idx_t idx) { - return states.data() + idx * state_size; - } - const_data_ptr_t GetStatePtr(idx_t idx) const { - return states.data() + idx * state_size; - } - //! Initialise all the states - void Initialize(idx_t count); - //! Combine the states into the target - void Combine(WindowAggregateStates &target, - AggregateCombineType combine_type = AggregateCombineType::PRESERVE_INPUT); - //! Finalize the states into an output vector - void Finalize(Vector &result); - //! Destroy the states - void Destroy(); - - //! A description of the aggregator - const AggregateObject aggr; - //! The size of each state - const idx_t state_size; - //! The allocator to use - ArenaAllocator allocator; - //! Data pointer that contains the state data - vector states; - //! Reused result state container for the window functions - unique_ptr statef; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_aggregator.hpp b/src/duckdb/src/include/duckdb/function/window/window_aggregator.hpp deleted file mode 100644 index 1caa6326d..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_aggregator.hpp +++ /dev/null @@ -1,194 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_aggregator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/execution/operator/aggregate/aggregate_object.hpp" -#include "duckdb/function/window/window_boundaries_state.hpp" - -namespace duckdb { - -class WindowCollection; -class WindowCursor; -struct WindowSharedExpressions; - -class WindowAggregatorState { -public: - WindowAggregatorState(); - virtual ~WindowAggregatorState() { - } - - template - TARGET &Cast() { - DynamicCastCheck(this); - return reinterpret_cast(*this); - } - template - const TARGET &Cast() const { - DynamicCastCheck(this); - return reinterpret_cast(*this); - } - - //! Allocator for aggregates - ArenaAllocator allocator; -}; - -class WindowAggregator { -public: - using CollectionPtr = optional_ptr; - - template - static void EvaluateSubFrames(const DataChunk &bounds, const WindowExcludeMode exclude_mode, idx_t count, - idx_t row_idx, SubFrames &frames, OP operation) { - auto begins = FlatVector::GetData(bounds.data[FRAME_BEGIN]); - auto ends = FlatVector::GetData(bounds.data[FRAME_END]); - auto peer_begin = FlatVector::GetData(bounds.data[PEER_BEGIN]); - auto peer_end = FlatVector::GetData(bounds.data[PEER_END]); - - for (idx_t i = 0, cur_row = row_idx; i < count; ++i, ++cur_row) { - idx_t nframes = 0; - if (exclude_mode == WindowExcludeMode::NO_OTHER) { - auto begin = begins[i]; - auto end = ends[i]; - frames[nframes++] = FrameBounds(begin, end); - } else { - // The frame_exclusion option allows rows around the current row to be excluded from the frame, - // even if they would be included according to the frame start and frame end options. - // EXCLUDE CURRENT ROW excludes the current row from the frame. - // EXCLUDE GROUP excludes the current row and its ordering peers from the frame. - // EXCLUDE TIES excludes any peers of the current row from the frame, but not the current row itself. - // EXCLUDE NO OTHERS simply specifies explicitly the default behavior - // of not excluding the current row or its peers. - // https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS - // - // For the sake of the client, we make some guarantees about the subframes: - // * They are in order left-to-right - // * They do not intersect - // * start <= end - // * The number is always the same - // - // Since we always have peer_begin <= cur_row < cur_row + 1 <= peer_end - // this is not too hard to arrange, but it may be that some subframes are contiguous, - // and some are empty. - - // WindowExcludePart::LEFT - const auto frame_begin = begins[i]; - const auto frame_end = ends[i]; - auto begin = frame_begin; - auto end = (exclude_mode == WindowExcludeMode::CURRENT_ROW) ? cur_row : peer_begin[i]; - end = MinValue(end, frame_end); - end = MaxValue(end, frame_begin); - frames[nframes++] = FrameBounds(begin, end); - - // with EXCLUDE TIES, in addition to the frame part right of the peer group's end, - // we also need to consider the current row - if (exclude_mode == WindowExcludeMode::TIES) { - begin = MinValue(MaxValue(cur_row, frame_begin), frame_end); - end = MaxValue(MinValue(cur_row + 1, frame_end), frame_begin); - frames[nframes++] = FrameBounds(begin, end); - } - - // WindowExcludePart::RIGHT - end = frame_end; - begin = (exclude_mode == WindowExcludeMode::CURRENT_ROW) ? (cur_row + 1) : peer_end[i]; - begin = MaxValue(begin, frame_begin); - begin = MinValue(begin, frame_end); - frames[nframes++] = FrameBounds(begin, end); - } - - operation(i); - } - } - - explicit WindowAggregator(const BoundWindowExpression &wexpr); - WindowAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared); - virtual ~WindowAggregator(); - - // Threading states - virtual unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const; - virtual unique_ptr GetLocalState(const WindowAggregatorState &gstate) const = 0; - - // Build - virtual void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, idx_t filtered); - virtual void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats); - - // Probe - virtual void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const = 0; - - //! The window function - const BoundWindowExpression &wexpr; - //! A description of the aggregator - const AggregateObject aggr; - //! The argument types for the function - vector arg_types; - //! The result type of the window function - const LogicalType result_type; - //! The size of a single aggregate state - const idx_t state_size; - //! The window exclusion clause - const WindowExcludeMode exclude_mode; - //! Partition collection column indicies - vector child_idx; -}; - -class WindowAggregatorGlobalState : public WindowAggregatorState { -public: - WindowAggregatorGlobalState(ClientContext &context, const WindowAggregator &aggregator_p, idx_t group_count) - : context(context), aggregator(aggregator_p), aggr(aggregator.wexpr), locals(0), finalized(0) { - - if (aggr.filter) { - // Start with all invalid and set the ones that pass - filter_mask.Initialize(group_count, false); - } else { - filter_mask.InitializeEmpty(group_count); - } - } - - //! The context we are in - ClientContext &context; - - //! The aggregator data - const WindowAggregator &aggregator; - - //! The aggregate function - const AggregateObject aggr; - - //! The filtered rows in inputs. - ValidityArray filter_mask; - - //! Lock for single threading - mutable mutex lock; - - //! Count of local tasks - mutable std::atomic locals; - - //! Number of finalised states - std::atomic finalized; -}; - -class WindowAggregatorLocalState : public WindowAggregatorState { -public: - using CollectionPtr = optional_ptr; - - static void InitSubFrames(SubFrames &frames, const WindowExcludeMode exclude_mode); - - WindowAggregatorLocalState() { - } - - void Sink(WindowAggregatorGlobalState &gastate, DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t row_idx); - virtual void Finalize(WindowAggregatorGlobalState &gastate, CollectionPtr collection); - - //! The state used for reading the collection - unique_ptr cursor; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_boundaries_state.hpp b/src/duckdb/src/include/duckdb/function/window/window_boundaries_state.hpp deleted file mode 100644 index 35e0fdb68..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_boundaries_state.hpp +++ /dev/null @@ -1,153 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_boundaries_state.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/types.hpp" -#include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" -#include "duckdb/function/window/window_collection.hpp" -#include "duckdb/parser/expression/window_expression.hpp" -#include "duckdb/common/vector_operations/aggregate_executor.hpp" - -namespace duckdb { - -class BoundWindowExpression; - -// Column indexes of the bounds chunk -enum WindowBounds : uint8_t { - PARTITION_BEGIN, - PARTITION_END, - PEER_BEGIN, - PEER_END, - VALID_BEGIN, - VALID_END, - FRAME_BEGIN, - FRAME_END -}; - -// C++ 11 won't do this automatically... -struct WindowBoundsHash { - inline uint64_t operator()(const WindowBounds &value) const { - return value; - } -}; - -using WindowBoundsSet = unordered_set; - -struct WindowInputExpression { - WindowInputExpression(DataChunk &chunk, column_t col_idx) - : ptype(PhysicalType::INVALID), scalar(true), chunk(chunk), col_idx(col_idx) { - if (col_idx < chunk.data.size()) { - auto &col = chunk.data[col_idx]; - ptype = col.GetType().InternalType(); - scalar = (col.GetVectorType() == VectorType::CONSTANT_VECTOR); - if (!scalar && col.GetVectorType() != VectorType::FLAT_VECTOR) { - col.Flatten(chunk.size()); - } - } - } - - inline PhysicalType InternalType() const { - return ptype; - } - - template - inline T GetCell(idx_t i) const { - D_ASSERT(!chunk.data.empty()); - const auto data = FlatVector::GetData(chunk.data[col_idx]); - return data[scalar ? 0 : i]; - } - - inline bool CellIsNull(idx_t i) const { - D_ASSERT(!chunk.data.empty()); - auto &col = chunk.data[col_idx]; - - if (scalar) { - return ConstantVector::IsNull(col); - } - return FlatVector::IsNull(col, i); - } - - inline void CopyCell(Vector &target, idx_t target_offset, idx_t width = 1) const { - D_ASSERT(!chunk.data.empty()); - auto &source = chunk.data[col_idx]; - auto source_offset = scalar ? 0 : target_offset; - VectorOperations::Copy(source, target, source_offset + width, source_offset, target_offset); - } - -private: - PhysicalType ptype; - bool scalar; - DataChunk &chunk; - const column_t col_idx; -}; - -struct WindowBoundariesState { - - static bool HasPrecedingRange(const BoundWindowExpression &wexpr); - static bool HasFollowingRange(const BoundWindowExpression &wexpr); - static WindowBoundsSet GetWindowBounds(const BoundWindowExpression &wexpr); - static idx_t FindNextStart(const ValidityMask &mask, idx_t l, const idx_t r, idx_t &n); - static idx_t FindPrevStart(const ValidityMask &mask, const idx_t l, idx_t r, idx_t &n); - - WindowBoundariesState(const BoundWindowExpression &wexpr, const idx_t input_size); - - // Generate the partition start indices - void PartitionBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask); - void PartitionEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask); - void PeerBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask, const ValidityMask &order_mask); - void PeerEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, const ValidityMask &partition_mask, - const ValidityMask &order_mask); - void ValidBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, - const ValidityMask &partition_mask, const ValidityMask &order_mask, - optional_ptr range); - void ValidEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, bool is_jump, const ValidityMask &partition_mask, - const ValidityMask &order_mask, optional_ptr range); - void FrameBegin(DataChunk &bounds, idx_t row_idx, const idx_t count, WindowInputExpression &boundary_begin, - optional_ptr range); - void FrameEnd(DataChunk &bounds, idx_t row_idx, const idx_t count, WindowInputExpression &boundary_end, - optional_ptr range); - - static void ClampFrame(const idx_t count, idx_t *values, const idx_t *begin, const idx_t *end) { - for (idx_t i = 0; i < count; ++i) { - values[i] = MinValue(MaxValue(values[i], begin[i]), end[i]); - } - } - - void Bounds(DataChunk &bounds, idx_t row_idx, optional_ptr range, const idx_t count, - WindowInputExpression &boundary_start, WindowInputExpression &boundary_end, - const ValidityMask &partition_mask, const ValidityMask &order_mask); - - // Cached lookups - WindowBoundsSet required; - const ExpressionType type; - const idx_t input_size; - const WindowBoundary start_boundary; - const WindowBoundary end_boundary; - const size_t partition_count; - const size_t order_count; - const OrderType range_sense; - const bool has_preceding_range; - const bool has_following_range; - - // Carried between chunks - idx_t next_pos = 0; - idx_t partition_start = 0; - idx_t partition_end = 0; - idx_t peer_start = 0; - idx_t valid_start = 0; - idx_t valid_end = 0; - - FrameBounds prev; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_collection.hpp b/src/duckdb/src/include/duckdb/function/window/window_collection.hpp deleted file mode 100644 index d946a1d79..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_collection.hpp +++ /dev/null @@ -1,146 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_collection.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/atomic.hpp" -#include "duckdb/common/types/column/column_data_collection.hpp" -#include "duckdb/common/vector_operations/vector_operations.hpp" - -namespace duckdb { - -// A wrapper for building ColumnDataCollections in parallel -class WindowCollection { -public: - using ColumnDataCollectionPtr = unique_ptr; - using ColumnDataCollectionSpec = pair>; - using ColumnSet = unordered_set; - - WindowCollection(BufferManager &buffer_manager, idx_t count, const vector &types); - - idx_t ColumnCount() const { - return types.size(); - } - - idx_t size() const { // NOLINT - return count; - } - - const vector &GetTypes() const { - return types; - } - - //! Update a thread-local collection for appending data to a given row - void GetCollection(idx_t row_idx, ColumnDataCollectionSpec &spec); - //! Single-threaded, idempotent ordered combining of all the appended data. - void Combine(const ColumnSet &build_validity); - - //! The collection data. May be null if the column count is 0. - ColumnDataCollectionPtr inputs; - //! Global validity mask - vector> all_valids; - //! Optional validity mask for the entire collection - vector validities; - - //! The collection columns - const vector types; - //! The collection rows - const idx_t count; - - //! Guard for range updates - mutex lock; - //! The paging buffer manager to use - BufferManager &buffer_manager; - //! The component column data collections - vector collections; - //! The (sorted) collection ranges - using Range = pair; - vector ranges; -}; - -class WindowBuilder { -public: - explicit WindowBuilder(WindowCollection &collection); - - //! Add a new chunk at the given index - void Sink(DataChunk &chunk, idx_t input_idx); - - //! The collection we are helping to build - WindowCollection &collection; - //! The thread's current input collection - using ColumnDataCollectionSpec = WindowCollection::ColumnDataCollectionSpec; - ColumnDataCollectionSpec sink; - //! The state used for appending to the collection - ColumnDataAppendState appender; - //! Are all the sunk rows valid? - bool all_valid = true; -}; - -class WindowCursor { -public: - WindowCursor(const WindowCollection &paged, column_t col_idx); - WindowCursor(const WindowCollection &paged, vector column_ids); - - //! Is the scan in range? - inline bool RowIsVisible(idx_t row_idx) const { - return (row_idx < state.next_row_index && state.current_row_index <= row_idx); - } - //! The offset of the row in the given state - inline sel_t RowOffset(idx_t row_idx) const { - D_ASSERT(RowIsVisible(row_idx)); - return UnsafeNumericCast(row_idx - state.current_row_index); - } - //! Scan the next chunk - inline bool Scan() { - return paged.inputs->Scan(state, chunk); - } - //! Seek to the given row - inline idx_t Seek(idx_t row_idx) { - if (!RowIsVisible(row_idx)) { - D_ASSERT(paged.inputs.get()); - paged.inputs->Seek(row_idx, state, chunk); - } - return RowOffset(row_idx); - } - //! Check a collection cell for nullity - bool CellIsNull(idx_t col_idx, idx_t row_idx) { - D_ASSERT(chunk.ColumnCount() > col_idx); - auto index = Seek(row_idx); - auto &source = chunk.data[col_idx]; - return FlatVector::IsNull(source, index); - } - //! Read a typed cell - template - T GetCell(idx_t col_idx, idx_t row_idx) { - D_ASSERT(chunk.ColumnCount() > col_idx); - auto index = Seek(row_idx); - auto &source = chunk.data[col_idx]; - const auto data = FlatVector::GetData(source); - return data[index]; - } - //! Copy a single value - void CopyCell(idx_t col_idx, idx_t row_idx, Vector &target, idx_t target_offset) { - D_ASSERT(chunk.ColumnCount() > col_idx); - auto index = Seek(row_idx); - auto &source = chunk.data[col_idx]; - VectorOperations::Copy(source, target, index + 1, index, target_offset); - } - - unique_ptr Copy() const { - return make_uniq(paged, state.column_ids); - } - - //! The pageable data - const WindowCollection &paged; - //! The state used for reading the collection - ColumnDataScanState state; - //! The data chunk read into - DataChunk chunk; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_constant_aggregator.hpp b/src/duckdb/src/include/duckdb/function/window/window_constant_aggregator.hpp deleted file mode 100644 index c3ca63f36..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_constant_aggregator.hpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_constant_aggregator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowConstantAggregator : public WindowAggregator { -public: - static bool CanAggregate(const BoundWindowExpression &wexpr); - - static BoundWindowExpression &RebindAggregate(ClientContext &context, BoundWindowExpression &wexpr); - - WindowConstantAggregator(BoundWindowExpression &wexpr, WindowSharedExpressions &shared, ClientContext &context); - ~WindowConstantAggregator() override { - } - - unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const override; - void Sink(WindowAggregatorState &gstate, WindowAggregatorState &lstate, DataChunk &sink_chunk, - DataChunk &coll_chunk, idx_t input_idx, optional_ptr filter_sel, - idx_t filtered) override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) override; - - unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_custom_aggregator.hpp b/src/duckdb/src/include/duckdb/function/window/window_custom_aggregator.hpp deleted file mode 100644 index ab664ca59..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_custom_aggregator.hpp +++ /dev/null @@ -1,32 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_custom_aggregator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowCustomAggregator : public WindowAggregator { -public: - static bool CanAggregate(const BoundWindowExpression &wexpr, WindowAggregationMode mode); - - WindowCustomAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared); - ~WindowCustomAggregator() override; - - unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) override; - - unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_distinct_aggregator.hpp b/src/duckdb/src/include/duckdb/function/window/window_distinct_aggregator.hpp deleted file mode 100644 index 7fe9040c0..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_distinct_aggregator.hpp +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_distinct_aggregator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowDistinctAggregator : public WindowAggregator { -public: - static bool CanAggregate(const BoundWindowExpression &wexpr); - - WindowDistinctAggregator(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared, - ClientContext &context); - - // Build - unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const override; - void Sink(WindowAggregatorState &gsink, WindowAggregatorState &lstate, DataChunk &sink_chunk, DataChunk &coll_chunk, - idx_t input_idx, optional_ptr filter_sel, idx_t filtered) override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) override; - - // Evaluate - unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const override; - - //! Context for sorting - ClientContext &context; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_executor.hpp b/src/duckdb/src/include/duckdb/function/window/window_executor.hpp deleted file mode 100644 index 44d3a9050..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_executor.hpp +++ /dev/null @@ -1,122 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_executor.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_boundaries_state.hpp" -#include "duckdb/function/window/window_collection.hpp" - -namespace duckdb { - -class WindowCollection; - -struct WindowSharedExpressions; - -class WindowExecutorState { -public: - WindowExecutorState() {}; - virtual ~WindowExecutorState() { - } - - template - TARGET &Cast() { - DynamicCastCheck(this); - return reinterpret_cast(*this); - } - template - const TARGET &Cast() const { - DynamicCastCheck(this); - return reinterpret_cast(*this); - } -}; - -class WindowExecutor; - -class WindowExecutorGlobalState : public WindowExecutorState { -public: - using CollectionPtr = optional_ptr; - - WindowExecutorGlobalState(const WindowExecutor &executor, const idx_t payload_count, - const ValidityMask &partition_mask, const ValidityMask &order_mask); - - const WindowExecutor &executor; - - const idx_t payload_count; - const ValidityMask &partition_mask; - const ValidityMask &order_mask; - vector arg_types; -}; - -class WindowExecutorLocalState : public WindowExecutorState { -public: - using CollectionPtr = optional_ptr; - - explicit WindowExecutorLocalState(const WindowExecutorGlobalState &gstate); - - virtual void Sink(WindowExecutorGlobalState &gstate, DataChunk &sink_chunk, DataChunk &coll_chunk, idx_t input_idx); - virtual void Finalize(WindowExecutorGlobalState &gstate, CollectionPtr collection); - - //! The state used for reading the range collection - unique_ptr range_cursor; -}; - -class WindowExecutorBoundsState : public WindowExecutorLocalState { -public: - explicit WindowExecutorBoundsState(const WindowExecutorGlobalState &gstate); - ~WindowExecutorBoundsState() override { - } - - virtual void UpdateBounds(WindowExecutorGlobalState &gstate, idx_t row_idx, DataChunk &eval_chunk, - optional_ptr range); - - // Frame management - const ValidityMask &partition_mask; - const ValidityMask &order_mask; - DataChunk bounds; - WindowBoundariesState state; -}; - -class WindowExecutor { -public: - using CollectionPtr = optional_ptr; - - WindowExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - virtual ~WindowExecutor() { - } - - virtual unique_ptr - GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, const ValidityMask &order_mask) const; - virtual unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const; - - virtual void Sink(DataChunk &sink_chunk, DataChunk &coll_chunk, const idx_t input_idx, - WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate) const; - - virtual void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const; - - void Evaluate(idx_t row_idx, DataChunk &eval_chunk, Vector &result, WindowExecutorLocalState &lstate, - WindowExecutorGlobalState &gstate) const; - - // The function - const BoundWindowExpression &wexpr; - ClientContext &context; - - // evaluate frame expressions, if needed - column_t boundary_start_idx = DConstants::INVALID_INDEX; - column_t boundary_end_idx = DConstants::INVALID_INDEX; - - // evaluate RANGE expressions, if needed - optional_ptr range_expr; - column_t range_idx = DConstants::INVALID_INDEX; - -protected: - virtual void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - DataChunk &eval_chunk, Vector &result, idx_t count, idx_t row_idx) const = 0; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_index_tree.hpp b/src/duckdb/src/include/duckdb/function/window/window_index_tree.hpp deleted file mode 100644 index e9f9f4014..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_index_tree.hpp +++ /dev/null @@ -1,42 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_index_tree.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_merge_sort_tree.hpp" - -namespace duckdb { - -class WindowIndexTree; - -class WindowIndexTreeLocalState : public WindowMergeSortTreeLocalState { -public: - explicit WindowIndexTreeLocalState(WindowIndexTree &index_tree); - - //! Process sorted leaf data - void BuildLeaves() override; - - //! The index tree we are building - WindowIndexTree &index_tree; -}; - -class WindowIndexTree : public WindowMergeSortTree { -public: - WindowIndexTree(ClientContext &context, const vector &orders, const vector &sort_idx, - const idx_t count); - WindowIndexTree(ClientContext &context, const BoundOrderModifier &order_bys, const vector &sort_idx, - const idx_t count); - ~WindowIndexTree() override = default; - - unique_ptr GetLocalState() override; - - //! Find the Nth index in the set of subframes - idx_t SelectNth(const SubFrames &frames, idx_t n) const; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_merge_sort_tree.hpp b/src/duckdb/src/include/duckdb/function/window/window_merge_sort_tree.hpp deleted file mode 100644 index 6faecbbf8..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_merge_sort_tree.hpp +++ /dev/null @@ -1,108 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_merge_sort_tree.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/execution/merge_sort_tree.hpp" -#include "duckdb/planner/bound_result_modifier.hpp" - -#include "duckdb/function/window/window_aggregator.hpp" -#include "duckdb/common/sort/sort.hpp" -#include "duckdb/common/sort/partition_state.hpp" - -namespace duckdb { - -class WindowMergeSortTree; - -class WindowMergeSortTreeLocalState : public WindowAggregatorState { -public: - explicit WindowMergeSortTreeLocalState(WindowMergeSortTree &index_tree); - - //! Add a chunk to the local sort - void SinkChunk(DataChunk &chunk, const idx_t row_idx, optional_ptr filter_sel, idx_t filtered); - //! Sort the data - void Sort(); - //! Process sorted leaf data - virtual void BuildLeaves() = 0; - - //! The index tree we are building - WindowMergeSortTree &window_tree; - //! Thread-local sorting data - optional_ptr local_sort; - //! Buffer for the sort keys - DataChunk sort_chunk; - //! Buffer for the payload data - DataChunk payload_chunk; - //! Build stage - PartitionSortStage build_stage = PartitionSortStage::INIT; - //! Build task number - idx_t build_task; - -private: - void ExecuteSortTask(); -}; - -class WindowMergeSortTree { -public: - using GlobalSortStatePtr = unique_ptr; - using LocalSortStatePtr = unique_ptr; - - WindowMergeSortTree(ClientContext &context, const vector &orders, - const vector &sort_idx, const idx_t count, bool unique = false); - virtual ~WindowMergeSortTree() = default; - - virtual unique_ptr GetLocalState() = 0; - - //! Make a local sort for a thread - optional_ptr AddLocalSort(); - - //! Thread-safe post-sort cleanup - virtual void CleanupSort(); - - //! Sort state machine - bool TryPrepareSortStage(WindowMergeSortTreeLocalState &lstate); - //! Build the MST in parallel from the sorted data - void Build(); - - //! The query context - ClientContext &context; - //! Thread memory limit - const idx_t memory_per_thread; - //! The column indices for sorting - const vector sort_idx; - //! The sorted data - GlobalSortStatePtr global_sort; - //! Finalize guard - mutex lock; - //! Local sort set - vector local_sorts; - //! Finalize stage - atomic build_stage; - //! Tasks launched - idx_t total_tasks = 0; - //! Tasks launched - idx_t tasks_assigned = 0; - //! Tasks landed - atomic tasks_completed; - //! The block starts (the scanner doesn't know this) plus the total count - vector block_starts; - - // Merge sort trees for various sizes - // Smaller is probably not worth the effort. - using MergeSortTree32 = MergeSortTree; - using MergeSortTree64 = MergeSortTree; - unique_ptr mst32; - unique_ptr mst64; - -protected: - //! Find the starts of all the blocks - //! Returns the total number of rows - virtual idx_t MeasurePayloadBlocks(); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_naive_aggregator.hpp b/src/duckdb/src/include/duckdb/function/window/window_naive_aggregator.hpp deleted file mode 100644 index 1fdf497ee..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_naive_aggregator.hpp +++ /dev/null @@ -1,33 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_naive_aggregator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowAggregateExecutor; - -// Used for validation -class WindowNaiveAggregator : public WindowAggregator { -public: - WindowNaiveAggregator(const WindowAggregateExecutor &executor, WindowSharedExpressions &shared); - ~WindowNaiveAggregator() override; - - unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Evaluate(const WindowAggregatorState &gsink, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const override; - - //! The parent executor - const WindowAggregateExecutor &executor; - //! The column indices of any ORDER BY argument expressions - vector arg_order_idx; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_rank_function.hpp b/src/duckdb/src/include/duckdb/function/window/window_rank_function.hpp deleted file mode 100644 index 9afb7e970..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_rank_function.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_rank_function.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_executor.hpp" - -namespace duckdb { - -class WindowPeerExecutor : public WindowExecutor { -public: - WindowPeerExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - - unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) const override; - unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; - - //! The column indices of any ORDER BY argument expressions - vector arg_order_idx; -}; - -class WindowRankExecutor : public WindowPeerExecutor { -public: - WindowRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowDenseRankExecutor : public WindowPeerExecutor { -public: - WindowDenseRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowPercentRankExecutor : public WindowPeerExecutor { -public: - WindowPercentRankExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowCumeDistExecutor : public WindowPeerExecutor { -public: - WindowCumeDistExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_rownumber_function.hpp b/src/duckdb/src/include/duckdb/function/window/window_rownumber_function.hpp deleted file mode 100644 index be9bf4713..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_rownumber_function.hpp +++ /dev/null @@ -1,43 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_rownumber_function.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_executor.hpp" - -namespace duckdb { - -class WindowRowNumberExecutor : public WindowExecutor { -public: - WindowRowNumberExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - - unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) const override; - unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; - - //! The evaluation index of the NTILE column - column_t ntile_idx = DConstants::INVALID_INDEX; - //! The column indices of any ORDER BY argument expressions - vector arg_order_idx; - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -// NTILE is just scaled ROW_NUMBER -class WindowNtileExecutor : public WindowRowNumberExecutor { -public: - WindowNtileExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_segment_tree.hpp b/src/duckdb/src/include/duckdb/function/window/window_segment_tree.hpp deleted file mode 100644 index 0b574b959..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_segment_tree.hpp +++ /dev/null @@ -1,31 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_segment_tree.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_aggregator.hpp" - -namespace duckdb { - -class WindowSegmentTree : public WindowAggregator { -public: - static bool CanAggregate(const BoundWindowExpression &wexpr); - - WindowSegmentTree(const BoundWindowExpression &wexpr, WindowSharedExpressions &shared); - - unique_ptr GetGlobalState(ClientContext &context, idx_t group_count, - const ValidityMask &partition_mask) const override; - unique_ptr GetLocalState(const WindowAggregatorState &gstate) const override; - void Finalize(WindowAggregatorState &gstate, WindowAggregatorState &lstate, CollectionPtr collection, - const FrameStats &stats) override; - - void Evaluate(const WindowAggregatorState &gstate, WindowAggregatorState &lstate, const DataChunk &bounds, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_shared_expressions.hpp b/src/duckdb/src/include/duckdb/function/window/window_shared_expressions.hpp deleted file mode 100644 index fa4a40d10..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_shared_expressions.hpp +++ /dev/null @@ -1,76 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_shared_expressions.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/parser/expression_map.hpp" - -namespace duckdb { - -class ExpressionExecutor; -class DataChunk; - -//! A shared set of expressions -struct WindowSharedExpressions { - struct Shared { - column_t size = 0; - expression_map_t> columns; - }; - - //! Register a shared expression in a shared set - static column_t RegisterExpr(const unique_ptr &expr, Shared &shared); - - //! Register a shared collection expression - column_t RegisterCollection(const unique_ptr &expr, bool build_validity) { - auto result = RegisterExpr(expr, coll_shared); - if (build_validity) { - coll_validity.insert(result); - } - return result; - } - //! Register a shared collection expression - inline column_t RegisterSink(const unique_ptr &expr) { - return RegisterExpr(expr, sink_shared); - } - //! Register a shared evaluation expression - inline column_t RegisterEvaluate(const unique_ptr &expr) { - return RegisterExpr(expr, eval_shared); - } - - //! Expression layout - static vector> GetSortedExpressions(Shared &shared); - - //! Expression execution utility - static void PrepareExecutors(Shared &shared, ExpressionExecutor &exec, DataChunk &chunk); - - //! Prepare collection expressions - inline void PrepareCollection(ExpressionExecutor &exec, DataChunk &chunk) { - PrepareExecutors(coll_shared, exec, chunk); - } - - //! Prepare collection expressions - inline void PrepareSink(ExpressionExecutor &exec, DataChunk &chunk) { - PrepareExecutors(sink_shared, exec, chunk); - } - - //! Prepare collection expressions - inline void PrepareEvaluate(ExpressionExecutor &exec, DataChunk &chunk) { - PrepareExecutors(eval_shared, exec, chunk); - } - - //! Fully materialised shared expressions - Shared coll_shared; - //! Sink shared expressions - Shared sink_shared; - //! Evaluate shared expressions - Shared eval_shared; - //! Requested collection validity masks - unordered_set coll_validity; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_token_tree.hpp b/src/duckdb/src/include/duckdb/function/window/window_token_tree.hpp deleted file mode 100644 index 4df4dab8f..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_token_tree.hpp +++ /dev/null @@ -1,46 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_token_tree.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_merge_sort_tree.hpp" - -namespace duckdb { - -// Builds a merge sort tree that uses integer tokens for the comparison values instead of the sort keys. -class WindowTokenTree : public WindowMergeSortTree { -public: - WindowTokenTree(ClientContext &context, const vector &orders, const vector &sort_idx, - const idx_t count, bool unique = false) - : WindowMergeSortTree(context, orders, sort_idx, count, unique) { - } - WindowTokenTree(ClientContext &context, const BoundOrderModifier &order_bys, const vector &sort_idx, - const idx_t count, bool unique = false) - : WindowTokenTree(context, order_bys.orders, sort_idx, count, unique) { - } - - unique_ptr GetLocalState() override; - - //! Thread-safe post-sort cleanup - void CleanupSort() override; - - //! Find the rank of the row within the range - idx_t Rank(const idx_t lower, const idx_t upper, const idx_t row_idx) const; - - //! Find the next peer after the row and within the range - idx_t PeerEnd(const idx_t lower, const idx_t upper, const idx_t row_idx) const; - - //! Peer boundaries. - vector deltas; - -protected: - //! Find the starts of all the blocks - idx_t MeasurePayloadBlocks() override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp b/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp deleted file mode 100644 index 1c734e1f8..000000000 --- a/src/duckdb/src/include/duckdb/function/window/window_value_function.hpp +++ /dev/null @@ -1,79 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/function/window/window_value_function.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/function/window/window_executor.hpp" - -namespace duckdb { - -// Base class for non-aggregate functions that have a payload -class WindowValueExecutor : public WindowExecutor { -public: - WindowValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - - void Finalize(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, - CollectionPtr collection) const override; - - unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) const override; - unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; - - //! The column index of the value column - column_t child_idx = DConstants::INVALID_INDEX; - //! The column index of the Nth column - column_t nth_idx = DConstants::INVALID_INDEX; - //! The column index of the offset column - column_t offset_idx = DConstants::INVALID_INDEX; - //! The column index of the default value column - column_t default_idx = DConstants::INVALID_INDEX; - //! The column indices of any ORDER BY argument expressions - vector arg_order_idx; -}; - -class WindowLeadLagExecutor : public WindowValueExecutor { -public: - WindowLeadLagExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - - unique_ptr GetGlobalState(const idx_t payload_count, const ValidityMask &partition_mask, - const ValidityMask &order_mask) const override; - unique_ptr GetLocalState(const WindowExecutorGlobalState &gstate) const override; - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowFirstValueExecutor : public WindowValueExecutor { -public: - WindowFirstValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowLastValueExecutor : public WindowValueExecutor { -public: - WindowLastValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -class WindowNthValueExecutor : public WindowValueExecutor { -public: - WindowNthValueExecutor(BoundWindowExpression &wexpr, ClientContext &context, WindowSharedExpressions &shared); - -protected: - void EvaluateInternal(WindowExecutorGlobalState &gstate, WindowExecutorLocalState &lstate, DataChunk &eval_chunk, - Vector &result, idx_t count, idx_t row_idx) const override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/appender.hpp b/src/duckdb/src/include/duckdb/main/appender.hpp index 0f0f0a4ff..9662e2744 100644 --- a/src/duckdb/src/include/duckdb/main/appender.hpp +++ b/src/duckdb/src/include/duckdb/main/appender.hpp @@ -28,31 +28,28 @@ enum class AppenderType : uint8_t { //! The Appender class can be used to append elements to a table. class BaseAppender { public: - //! The amount of tuples that are gathered in the column data collection before flushing. + //! The amount of tuples that will be gathered in the column data collection before flushing static constexpr const idx_t DEFAULT_FLUSH_COUNT = STANDARD_VECTOR_SIZE * 100ULL; protected: - //! The allocator for the column data collection. Allocator &allocator; - //! The column types of the associated table. + //! The append types vector types; - //! The active column types. - vector active_types; - //! The buffered to-be-appended data. + //! The buffered data for the append unique_ptr collection; - //! The active chunk for row-based appends. + //! Internal chunk used for appends DataChunk chunk; - //! The currently active column of row-based appends. + //! The current column to append to idx_t column = 0; - //! The type of the appender. + //! The type of the appender AppenderType appender_type; - //! The amount of rows after which the appender flushes automatically. + //! The amount of rows after which we flush the appender automatically idx_t flush_count = DEFAULT_FLUSH_COUNT; protected: - DUCKDB_API BaseAppender(Allocator &allocator, const AppenderType type); - DUCKDB_API BaseAppender(Allocator &allocator, vector types, const AppenderType type, - const idx_t flush_count = DEFAULT_FLUSH_COUNT); + DUCKDB_API BaseAppender(Allocator &allocator, AppenderType type); + DUCKDB_API BaseAppender(Allocator &allocator, vector types, AppenderType type, + idx_t flush_count = DEFAULT_FLUSH_COUNT); public: DUCKDB_API virtual ~BaseAppender(); @@ -67,7 +64,6 @@ class BaseAppender { // Append functions template void Append(T value) = delete; - DUCKDB_API void Append(DataChunk &target, const Value &value, idx_t col, idx_t row); DUCKDB_API void Append(const char *value, uint32_t length); @@ -82,21 +78,15 @@ class BaseAppender { DUCKDB_API void Flush(); //! Flush the changes made by the appender and close it. The appender cannot be used after this point DUCKDB_API void Close(); - //! Returns the active types of the appender. - const vector &GetActiveTypes() const; + vector &GetTypes() { + return types; + } idx_t CurrentColumn() const { return column; } DUCKDB_API void AppendDataChunk(DataChunk &value); - //! Appends a column to the active column list. - //! Immediately flushes all previous data. - virtual void AddColumn(const string &name) = 0; - //! Removes all columns from the active column list. - //! Immediately flushes all previous data. - virtual void ClearColumns() = 0; - protected: void Destructor(); virtual void FlushInternal(ColumnDataCollection &collection) = 0; @@ -121,37 +111,26 @@ class BaseAppender { } void AppendValue(const Value &value); - void AppendValue(DataChunk target, const Value &value); }; class Appender : public BaseAppender { - //! A shared pointer to the context of this appender. + //! A reference to a database connection that created this appender shared_ptr context; - //! The table description including the column names. + //! The table description (including column names) unique_ptr description; - //! All table default values. - unordered_map default_values; - - //! If not empty, then this holds all logical column IDs of columns provided by the appender. - //! Any other columns default to NULL, or their default values. - vector column_ids; + //! The default expressions + unordered_map default_values; public: - DUCKDB_API Appender(Connection &con, const string &database_name, const string &schema_name, - const string &table_name); DUCKDB_API Appender(Connection &con, const string &schema_name, const string &table_name); DUCKDB_API Appender(Connection &con, const string &table_name); DUCKDB_API ~Appender() override; public: void AppendDefault(); - void AppendDefault(DataChunk &chunk, idx_t col, idx_t row); - void AddColumn(const string &name) override; - void ClearColumns() override; protected: void FlushInternal(ColumnDataCollection &collection) override; - Value GetDefaultValue(idx_t column); }; class InternalAppender : public BaseAppender { @@ -162,13 +141,11 @@ class InternalAppender : public BaseAppender { public: DUCKDB_API InternalAppender(ClientContext &context, TableCatalogEntry &table, - const idx_t flush_count = DEFAULT_FLUSH_COUNT); + idx_t flush_count = DEFAULT_FLUSH_COUNT); DUCKDB_API ~InternalAppender() override; protected: void FlushInternal(ColumnDataCollection &collection) override; - void AddColumn(const string &name) override; - void ClearColumns() override; }; template <> diff --git a/src/duckdb/src/include/duckdb/main/attached_database.hpp b/src/duckdb/src/include/duckdb/main/attached_database.hpp index 098edf9f7..db2e8ef53 100644 --- a/src/duckdb/src/include/duckdb/main/attached_database.hpp +++ b/src/duckdb/src/include/duckdb/main/attached_database.hpp @@ -13,7 +13,6 @@ #include "duckdb/common/mutex.hpp" #include "duckdb/main/config.hpp" #include "duckdb/catalog/catalog_entry.hpp" -#include "duckdb/storage/storage_options.hpp" namespace duckdb { class Catalog; @@ -44,10 +43,8 @@ struct AttachOptions { AccessMode access_mode; //! The file format type. The default type is a duckdb database file, but other file formats are possible. string db_type; - //! Set of remaining (key, value) options - unordered_map options; - //! (optionally) a catalog can be provided with a default table - QualifiedName default_table; + //! We only set this, if we detect any unrecognized option. + string unrecognized_option; }; //! The AttachedDatabase represents an attached database instance. @@ -64,7 +61,7 @@ class AttachedDatabase : public CatalogEntry { ~AttachedDatabase() override; //! Initializes the catalog and storage of the attached database. - void Initialize(StorageOptions options = StorageOptions()); + void Initialize(const optional_idx block_alloc_size = optional_idx()); void Close(); Catalog &ParentCatalog() override; diff --git a/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp b/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp index c00425420..f2d825f29 100644 --- a/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +++ b/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp @@ -16,7 +16,6 @@ #include "duckdb/common/case_insensitive_map.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/planner/expression/bound_parameter_data.hpp" -#include "duckdb/main/db_instance_cache.hpp" #include #include @@ -29,12 +28,8 @@ namespace duckdb { -struct DBInstanceCacheWrapper { - unique_ptr instance_cache; -}; - -struct DatabaseWrapper { - shared_ptr database; +struct DatabaseData { + unique_ptr database; }; struct PreparedStatementWrapper { diff --git a/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp b/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp index 71e6d18bc..932730c0e 100644 --- a/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp +++ b/src/duckdb/src/include/duckdb/main/capi/extension_api.hpp @@ -6,7 +6,7 @@ // Function pointer struct //===--------------------------------------------------------------------===// typedef struct { - // v1.2.0 + // v0.0.1 duckdb_state (*duckdb_open)(const char *path, duckdb_database *out_database); duckdb_state (*duckdb_open_ext)(const char *path, duckdb_database *out_database, duckdb_config config, char **out_error); @@ -30,14 +30,10 @@ typedef struct { idx_t (*duckdb_column_count)(duckdb_result *result); idx_t (*duckdb_rows_changed)(duckdb_result *result); const char *(*duckdb_result_error)(duckdb_result *result); - duckdb_error_type (*duckdb_result_error_type)(duckdb_result *result); - duckdb_result_type (*duckdb_result_return_type)(duckdb_result result); void *(*duckdb_malloc)(size_t size); void (*duckdb_free)(void *ptr); idx_t (*duckdb_vector_size)(); bool (*duckdb_string_is_inlined)(duckdb_string_t string); - uint32_t (*duckdb_string_t_length)(duckdb_string_t string); - const char *(*duckdb_string_t_data)(duckdb_string_t *string); duckdb_date_struct (*duckdb_from_date)(duckdb_date date); duckdb_date (*duckdb_to_date)(duckdb_date_struct date); bool (*duckdb_is_finite_date)(duckdb_date date); @@ -61,7 +57,6 @@ typedef struct { idx_t (*duckdb_nparams)(duckdb_prepared_statement prepared_statement); const char *(*duckdb_parameter_name)(duckdb_prepared_statement prepared_statement, idx_t index); duckdb_type (*duckdb_param_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); - duckdb_logical_type (*duckdb_param_logical_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); duckdb_state (*duckdb_clear_bindings)(duckdb_prepared_statement prepared_statement); duckdb_statement_type (*duckdb_prepared_statement_type)(duckdb_prepared_statement statement); duckdb_state (*duckdb_bind_value)(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_value val); @@ -117,70 +112,14 @@ typedef struct { void (*duckdb_destroy_value)(duckdb_value *value); duckdb_value (*duckdb_create_varchar)(const char *text); duckdb_value (*duckdb_create_varchar_length)(const char *text, idx_t length); - duckdb_value (*duckdb_create_bool)(bool input); - duckdb_value (*duckdb_create_int8)(int8_t input); - duckdb_value (*duckdb_create_uint8)(uint8_t input); - duckdb_value (*duckdb_create_int16)(int16_t input); - duckdb_value (*duckdb_create_uint16)(uint16_t input); - duckdb_value (*duckdb_create_int32)(int32_t input); - duckdb_value (*duckdb_create_uint32)(uint32_t input); - duckdb_value (*duckdb_create_uint64)(uint64_t input); duckdb_value (*duckdb_create_int64)(int64_t val); - duckdb_value (*duckdb_create_hugeint)(duckdb_hugeint input); - duckdb_value (*duckdb_create_uhugeint)(duckdb_uhugeint input); - duckdb_value (*duckdb_create_float)(float input); - duckdb_value (*duckdb_create_double)(double input); - duckdb_value (*duckdb_create_date)(duckdb_date input); - duckdb_value (*duckdb_create_time)(duckdb_time input); - duckdb_value (*duckdb_create_time_tz_value)(duckdb_time_tz value); - duckdb_value (*duckdb_create_timestamp)(duckdb_timestamp input); - duckdb_value (*duckdb_create_interval)(duckdb_interval input); - duckdb_value (*duckdb_create_blob)(const uint8_t *data, idx_t length); - duckdb_value (*duckdb_create_varint)(duckdb_varint input); - duckdb_value (*duckdb_create_decimal)(duckdb_decimal input); - duckdb_value (*duckdb_create_bit)(duckdb_bit input); - duckdb_value (*duckdb_create_uuid)(duckdb_uhugeint input); - bool (*duckdb_get_bool)(duckdb_value val); - int8_t (*duckdb_get_int8)(duckdb_value val); - uint8_t (*duckdb_get_uint8)(duckdb_value val); - int16_t (*duckdb_get_int16)(duckdb_value val); - uint16_t (*duckdb_get_uint16)(duckdb_value val); - int32_t (*duckdb_get_int32)(duckdb_value val); - uint32_t (*duckdb_get_uint32)(duckdb_value val); - int64_t (*duckdb_get_int64)(duckdb_value val); - uint64_t (*duckdb_get_uint64)(duckdb_value val); - duckdb_hugeint (*duckdb_get_hugeint)(duckdb_value val); - duckdb_uhugeint (*duckdb_get_uhugeint)(duckdb_value val); - float (*duckdb_get_float)(duckdb_value val); - double (*duckdb_get_double)(duckdb_value val); - duckdb_date (*duckdb_get_date)(duckdb_value val); - duckdb_time (*duckdb_get_time)(duckdb_value val); - duckdb_time_tz (*duckdb_get_time_tz)(duckdb_value val); - duckdb_timestamp (*duckdb_get_timestamp)(duckdb_value val); - duckdb_interval (*duckdb_get_interval)(duckdb_value val); - duckdb_logical_type (*duckdb_get_value_type)(duckdb_value val); - duckdb_blob (*duckdb_get_blob)(duckdb_value val); - duckdb_varint (*duckdb_get_varint)(duckdb_value val); - duckdb_decimal (*duckdb_get_decimal)(duckdb_value val); - duckdb_bit (*duckdb_get_bit)(duckdb_value val); - duckdb_uhugeint (*duckdb_get_uuid)(duckdb_value val); - char *(*duckdb_get_varchar)(duckdb_value value); duckdb_value (*duckdb_create_struct_value)(duckdb_logical_type type, duckdb_value *values); duckdb_value (*duckdb_create_list_value)(duckdb_logical_type type, duckdb_value *values, idx_t value_count); duckdb_value (*duckdb_create_array_value)(duckdb_logical_type type, duckdb_value *values, idx_t value_count); - idx_t (*duckdb_get_map_size)(duckdb_value value); - duckdb_value (*duckdb_get_map_key)(duckdb_value value, idx_t index); - duckdb_value (*duckdb_get_map_value)(duckdb_value value, idx_t index); - bool (*duckdb_is_null_value)(duckdb_value value); - duckdb_value (*duckdb_create_null_value)(); - idx_t (*duckdb_get_list_size)(duckdb_value value); - duckdb_value (*duckdb_get_list_child)(duckdb_value value, idx_t index); - duckdb_value (*duckdb_create_enum_value)(duckdb_logical_type type, uint64_t value); - uint64_t (*duckdb_get_enum_value)(duckdb_value value); - duckdb_value (*duckdb_get_struct_child)(duckdb_value value, idx_t index); + char *(*duckdb_get_varchar)(duckdb_value value); + int64_t (*duckdb_get_int64)(duckdb_value val); duckdb_logical_type (*duckdb_create_logical_type)(duckdb_type type); char *(*duckdb_logical_type_get_alias)(duckdb_logical_type type); - void (*duckdb_logical_type_set_alias)(duckdb_logical_type type, const char *alias); duckdb_logical_type (*duckdb_create_list_type)(duckdb_logical_type type); duckdb_logical_type (*duckdb_create_array_type)(duckdb_logical_type type, idx_t array_size); duckdb_logical_type (*duckdb_create_map_type)(duckdb_logical_type key_type, duckdb_logical_type value_type); @@ -209,8 +148,7 @@ typedef struct { char *(*duckdb_union_type_member_name)(duckdb_logical_type type, idx_t index); duckdb_logical_type (*duckdb_union_type_member_type)(duckdb_logical_type type, idx_t index); void (*duckdb_destroy_logical_type)(duckdb_logical_type *type); - duckdb_state (*duckdb_register_logical_type)(duckdb_connection con, duckdb_logical_type type, - duckdb_create_type_info info); + duckdb_data_chunk (*duckdb_fetch_chunk)(duckdb_result result); duckdb_data_chunk (*duckdb_create_data_chunk)(duckdb_logical_type *types, idx_t column_count); void (*duckdb_destroy_data_chunk)(duckdb_data_chunk *chunk); void (*duckdb_data_chunk_reset)(duckdb_data_chunk chunk); @@ -237,9 +175,6 @@ typedef struct { duckdb_scalar_function (*duckdb_create_scalar_function)(); void (*duckdb_destroy_scalar_function)(duckdb_scalar_function *scalar_function); void (*duckdb_scalar_function_set_name)(duckdb_scalar_function scalar_function, const char *name); - void (*duckdb_scalar_function_set_varargs)(duckdb_scalar_function scalar_function, duckdb_logical_type type); - void (*duckdb_scalar_function_set_special_handling)(duckdb_scalar_function scalar_function); - void (*duckdb_scalar_function_set_volatile)(duckdb_scalar_function scalar_function); void (*duckdb_scalar_function_add_parameter)(duckdb_scalar_function scalar_function, duckdb_logical_type type); void (*duckdb_scalar_function_set_return_type)(duckdb_scalar_function scalar_function, duckdb_logical_type type); void (*duckdb_scalar_function_set_extra_info)(duckdb_scalar_function scalar_function, void *extra_info, @@ -247,39 +182,6 @@ typedef struct { void (*duckdb_scalar_function_set_function)(duckdb_scalar_function scalar_function, duckdb_scalar_function_t function); duckdb_state (*duckdb_register_scalar_function)(duckdb_connection con, duckdb_scalar_function scalar_function); - void *(*duckdb_scalar_function_get_extra_info)(duckdb_function_info info); - void (*duckdb_scalar_function_set_error)(duckdb_function_info info, const char *error); - duckdb_scalar_function_set (*duckdb_create_scalar_function_set)(const char *name); - void (*duckdb_destroy_scalar_function_set)(duckdb_scalar_function_set *scalar_function_set); - duckdb_state (*duckdb_add_scalar_function_to_set)(duckdb_scalar_function_set set, duckdb_scalar_function function); - duckdb_state (*duckdb_register_scalar_function_set)(duckdb_connection con, duckdb_scalar_function_set set); - duckdb_aggregate_function (*duckdb_create_aggregate_function)(); - void (*duckdb_destroy_aggregate_function)(duckdb_aggregate_function *aggregate_function); - void (*duckdb_aggregate_function_set_name)(duckdb_aggregate_function aggregate_function, const char *name); - void (*duckdb_aggregate_function_add_parameter)(duckdb_aggregate_function aggregate_function, - duckdb_logical_type type); - void (*duckdb_aggregate_function_set_return_type)(duckdb_aggregate_function aggregate_function, - duckdb_logical_type type); - void (*duckdb_aggregate_function_set_functions)(duckdb_aggregate_function aggregate_function, - duckdb_aggregate_state_size state_size, - duckdb_aggregate_init_t state_init, - duckdb_aggregate_update_t update, - duckdb_aggregate_combine_t combine, - duckdb_aggregate_finalize_t finalize); - void (*duckdb_aggregate_function_set_destructor)(duckdb_aggregate_function aggregate_function, - duckdb_aggregate_destroy_t destroy); - duckdb_state (*duckdb_register_aggregate_function)(duckdb_connection con, - duckdb_aggregate_function aggregate_function); - void (*duckdb_aggregate_function_set_special_handling)(duckdb_aggregate_function aggregate_function); - void (*duckdb_aggregate_function_set_extra_info)(duckdb_aggregate_function aggregate_function, void *extra_info, - duckdb_delete_callback_t destroy); - void *(*duckdb_aggregate_function_get_extra_info)(duckdb_function_info info); - void (*duckdb_aggregate_function_set_error)(duckdb_function_info info, const char *error); - duckdb_aggregate_function_set (*duckdb_create_aggregate_function_set)(const char *name); - void (*duckdb_destroy_aggregate_function_set)(duckdb_aggregate_function_set *aggregate_function_set); - duckdb_state (*duckdb_add_aggregate_function_to_set)(duckdb_aggregate_function_set set, - duckdb_aggregate_function function); - duckdb_state (*duckdb_register_aggregate_function_set)(duckdb_connection con, duckdb_aggregate_function_set set); duckdb_table_function (*duckdb_create_table_function)(); void (*duckdb_destroy_table_function)(duckdb_table_function *table_function); void (*duckdb_table_function_set_name)(duckdb_table_function table_function, const char *name); @@ -320,68 +222,14 @@ typedef struct { void (*duckdb_replacement_scan_set_function_name)(duckdb_replacement_scan_info info, const char *function_name); void (*duckdb_replacement_scan_add_parameter)(duckdb_replacement_scan_info info, duckdb_value parameter); void (*duckdb_replacement_scan_set_error)(duckdb_replacement_scan_info info, const char *error); - duckdb_value (*duckdb_profiling_info_get_metrics)(duckdb_profiling_info info); - idx_t (*duckdb_profiling_info_get_child_count)(duckdb_profiling_info info); - duckdb_profiling_info (*duckdb_profiling_info_get_child)(duckdb_profiling_info info, idx_t index); duckdb_state (*duckdb_appender_create)(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender); - duckdb_state (*duckdb_appender_create_ext)(duckdb_connection connection, const char *catalog, const char *schema, - const char *table, duckdb_appender *out_appender); idx_t (*duckdb_appender_column_count)(duckdb_appender appender); duckdb_logical_type (*duckdb_appender_column_type)(duckdb_appender appender, idx_t col_idx); const char *(*duckdb_appender_error)(duckdb_appender appender); duckdb_state (*duckdb_appender_flush)(duckdb_appender appender); duckdb_state (*duckdb_appender_close)(duckdb_appender appender); duckdb_state (*duckdb_appender_destroy)(duckdb_appender *appender); - duckdb_state (*duckdb_appender_add_column)(duckdb_appender appender, const char *name); - duckdb_state (*duckdb_appender_clear_columns)(duckdb_appender appender); - duckdb_state (*duckdb_append_data_chunk)(duckdb_appender appender, duckdb_data_chunk chunk); - duckdb_state (*duckdb_table_description_create)(duckdb_connection connection, const char *schema, const char *table, - duckdb_table_description *out); - duckdb_state (*duckdb_table_description_create_ext)(duckdb_connection connection, const char *catalog, - const char *schema, const char *table, - duckdb_table_description *out); - void (*duckdb_table_description_destroy)(duckdb_table_description *table_description); - const char *(*duckdb_table_description_error)(duckdb_table_description table_description); - duckdb_state (*duckdb_column_has_default)(duckdb_table_description table_description, idx_t index, bool *out); - char *(*duckdb_table_description_get_column_name)(duckdb_table_description table_description, idx_t index); - void (*duckdb_execute_tasks)(duckdb_database database, idx_t max_tasks); - duckdb_task_state (*duckdb_create_task_state)(duckdb_database database); - void (*duckdb_execute_tasks_state)(duckdb_task_state state); - idx_t (*duckdb_execute_n_tasks_state)(duckdb_task_state state, idx_t max_tasks); - void (*duckdb_finish_execution)(duckdb_task_state state); - bool (*duckdb_task_state_is_finished)(duckdb_task_state state); - void (*duckdb_destroy_task_state)(duckdb_task_state state); - bool (*duckdb_execution_is_finished)(duckdb_connection con); - duckdb_data_chunk (*duckdb_fetch_chunk)(duckdb_result result); - duckdb_cast_function (*duckdb_create_cast_function)(); - void (*duckdb_cast_function_set_source_type)(duckdb_cast_function cast_function, duckdb_logical_type source_type); - void (*duckdb_cast_function_set_target_type)(duckdb_cast_function cast_function, duckdb_logical_type target_type); - void (*duckdb_cast_function_set_implicit_cast_cost)(duckdb_cast_function cast_function, int64_t cost); - void (*duckdb_cast_function_set_function)(duckdb_cast_function cast_function, duckdb_cast_function_t function); - void (*duckdb_cast_function_set_extra_info)(duckdb_cast_function cast_function, void *extra_info, - duckdb_delete_callback_t destroy); - void *(*duckdb_cast_function_get_extra_info)(duckdb_function_info info); - duckdb_cast_mode (*duckdb_cast_function_get_cast_mode)(duckdb_function_info info); - void (*duckdb_cast_function_set_error)(duckdb_function_info info, const char *error); - void (*duckdb_cast_function_set_row_error)(duckdb_function_info info, const char *error, idx_t row, - duckdb_vector output); - duckdb_state (*duckdb_register_cast_function)(duckdb_connection con, duckdb_cast_function cast_function); - void (*duckdb_destroy_cast_function)(duckdb_cast_function *cast_function); - bool (*duckdb_is_finite_timestamp_s)(duckdb_timestamp_s ts); - bool (*duckdb_is_finite_timestamp_ms)(duckdb_timestamp_ms ts); - bool (*duckdb_is_finite_timestamp_ns)(duckdb_timestamp_ns ts); - duckdb_value (*duckdb_create_timestamp_tz)(duckdb_timestamp input); - duckdb_value (*duckdb_create_timestamp_s)(duckdb_timestamp_s input); - duckdb_value (*duckdb_create_timestamp_ms)(duckdb_timestamp_ms input); - duckdb_value (*duckdb_create_timestamp_ns)(duckdb_timestamp_ns input); - duckdb_timestamp (*duckdb_get_timestamp_tz)(duckdb_value val); - duckdb_timestamp_s (*duckdb_get_timestamp_s)(duckdb_value val); - duckdb_timestamp_ms (*duckdb_get_timestamp_ms)(duckdb_value val); - duckdb_timestamp_ns (*duckdb_get_timestamp_ns)(duckdb_value val); - duckdb_state (*duckdb_append_value)(duckdb_appender appender, duckdb_value value); - duckdb_profiling_info (*duckdb_get_profiling_info)(duckdb_connection connection); - duckdb_value (*duckdb_profiling_info_get_value)(duckdb_profiling_info info, const char *key); duckdb_state (*duckdb_appender_begin_row)(duckdb_appender appender); duckdb_state (*duckdb_appender_end_row)(duckdb_appender appender); duckdb_state (*duckdb_append_default)(duckdb_appender appender); @@ -406,14 +254,127 @@ typedef struct { duckdb_state (*duckdb_append_varchar_length)(duckdb_appender appender, const char *val, idx_t length); duckdb_state (*duckdb_append_blob)(duckdb_appender appender, const void *data, idx_t length); duckdb_state (*duckdb_append_null)(duckdb_appender appender); - // These functions have been deprecated and may be removed in future versions of DuckDB - + duckdb_state (*duckdb_append_data_chunk)(duckdb_appender appender, duckdb_data_chunk chunk); + void (*duckdb_execute_tasks)(duckdb_database database, idx_t max_tasks); + duckdb_task_state (*duckdb_create_task_state)(duckdb_database database); + void (*duckdb_execute_tasks_state)(duckdb_task_state state); + idx_t (*duckdb_execute_n_tasks_state)(duckdb_task_state state, idx_t max_tasks); + void (*duckdb_finish_execution)(duckdb_task_state state); + bool (*duckdb_task_state_is_finished)(duckdb_task_state state); + void (*duckdb_destroy_task_state)(duckdb_task_state state); + bool (*duckdb_execution_is_finished)(duckdb_connection con); + duckdb_profiling_info (*duckdb_get_profiling_info)(duckdb_connection connection); + duckdb_value (*duckdb_profiling_info_get_value)(duckdb_profiling_info info, const char *key); + idx_t (*duckdb_profiling_info_get_child_count)(duckdb_profiling_info info); + duckdb_profiling_info (*duckdb_profiling_info_get_child)(duckdb_profiling_info info, idx_t index); + duckdb_value (*duckdb_profiling_info_get_metrics)(duckdb_profiling_info info); + void (*duckdb_scalar_function_set_varargs)(duckdb_scalar_function scalar_function, duckdb_logical_type type); + void (*duckdb_scalar_function_set_special_handling)(duckdb_scalar_function scalar_function); + void (*duckdb_scalar_function_set_volatile)(duckdb_scalar_function scalar_function); + void *(*duckdb_scalar_function_get_extra_info)(duckdb_function_info info); + void (*duckdb_scalar_function_set_error)(duckdb_function_info info, const char *error); + duckdb_state (*duckdb_table_description_create)(duckdb_connection connection, const char *schema, const char *table, + duckdb_table_description *out); + void (*duckdb_table_description_destroy)(duckdb_table_description *table_description); + const char *(*duckdb_table_description_error)(duckdb_table_description table_description); + duckdb_error_type (*duckdb_result_error_type)(duckdb_result *result); + uint32_t (*duckdb_string_t_length)(duckdb_string_t string); + const char *(*duckdb_string_t_data)(duckdb_string_t *string); + duckdb_value (*duckdb_create_bool)(bool input); + duckdb_value (*duckdb_create_int8)(int8_t input); + duckdb_value (*duckdb_create_uint8)(uint8_t input); + duckdb_value (*duckdb_create_int16)(int16_t input); + duckdb_value (*duckdb_create_uint16)(uint16_t input); + duckdb_value (*duckdb_create_int32)(int32_t input); + duckdb_value (*duckdb_create_uint32)(uint32_t input); + duckdb_value (*duckdb_create_uint64)(uint64_t input); + duckdb_value (*duckdb_create_hugeint)(duckdb_hugeint input); + duckdb_value (*duckdb_create_uhugeint)(duckdb_uhugeint input); + duckdb_value (*duckdb_create_float)(float input); + duckdb_value (*duckdb_create_double)(double input); + duckdb_value (*duckdb_create_date)(duckdb_date input); + duckdb_value (*duckdb_create_time)(duckdb_time input); + duckdb_value (*duckdb_create_time_tz_value)(duckdb_time_tz value); + duckdb_value (*duckdb_create_timestamp)(duckdb_timestamp input); + duckdb_value (*duckdb_create_interval)(duckdb_interval input); + duckdb_value (*duckdb_create_blob)(const uint8_t *data, idx_t length); + bool (*duckdb_get_bool)(duckdb_value val); + int8_t (*duckdb_get_int8)(duckdb_value val); + uint8_t (*duckdb_get_uint8)(duckdb_value val); + int16_t (*duckdb_get_int16)(duckdb_value val); + uint16_t (*duckdb_get_uint16)(duckdb_value val); + int32_t (*duckdb_get_int32)(duckdb_value val); + uint32_t (*duckdb_get_uint32)(duckdb_value val); + uint64_t (*duckdb_get_uint64)(duckdb_value val); + duckdb_hugeint (*duckdb_get_hugeint)(duckdb_value val); + duckdb_uhugeint (*duckdb_get_uhugeint)(duckdb_value val); + float (*duckdb_get_float)(duckdb_value val); + double (*duckdb_get_double)(duckdb_value val); + duckdb_date (*duckdb_get_date)(duckdb_value val); + duckdb_time (*duckdb_get_time)(duckdb_value val); + duckdb_time_tz (*duckdb_get_time_tz)(duckdb_value val); + duckdb_timestamp (*duckdb_get_timestamp)(duckdb_value val); + duckdb_interval (*duckdb_get_interval)(duckdb_value val); + duckdb_logical_type (*duckdb_get_value_type)(duckdb_value val); + duckdb_blob (*duckdb_get_blob)(duckdb_value val); + duckdb_scalar_function_set (*duckdb_create_scalar_function_set)(const char *name); + void (*duckdb_destroy_scalar_function_set)(duckdb_scalar_function_set *scalar_function_set); + duckdb_state (*duckdb_add_scalar_function_to_set)(duckdb_scalar_function_set set, duckdb_scalar_function function); + duckdb_state (*duckdb_register_scalar_function_set)(duckdb_connection con, duckdb_scalar_function_set set); + duckdb_aggregate_function_set (*duckdb_create_aggregate_function_set)(const char *name); + void (*duckdb_destroy_aggregate_function_set)(duckdb_aggregate_function_set *aggregate_function_set); + duckdb_state (*duckdb_add_aggregate_function_to_set)(duckdb_aggregate_function_set set, + duckdb_aggregate_function function); + duckdb_state (*duckdb_register_aggregate_function_set)(duckdb_connection con, duckdb_aggregate_function_set set); + idx_t (*duckdb_get_map_size)(duckdb_value value); + duckdb_value (*duckdb_get_map_key)(duckdb_value value, idx_t index); + duckdb_value (*duckdb_get_map_value)(duckdb_value value, idx_t index); + duckdb_aggregate_function (*duckdb_create_aggregate_function)(); + void (*duckdb_destroy_aggregate_function)(duckdb_aggregate_function *aggregate_function); + void (*duckdb_aggregate_function_set_name)(duckdb_aggregate_function aggregate_function, const char *name); + void (*duckdb_aggregate_function_add_parameter)(duckdb_aggregate_function aggregate_function, + duckdb_logical_type type); + void (*duckdb_aggregate_function_set_return_type)(duckdb_aggregate_function aggregate_function, + duckdb_logical_type type); + void (*duckdb_aggregate_function_set_functions)(duckdb_aggregate_function aggregate_function, + duckdb_aggregate_state_size state_size, + duckdb_aggregate_init_t state_init, + duckdb_aggregate_update_t update, + duckdb_aggregate_combine_t combine, + duckdb_aggregate_finalize_t finalize); + void (*duckdb_aggregate_function_set_destructor)(duckdb_aggregate_function aggregate_function, + duckdb_aggregate_destroy_t destroy); + duckdb_state (*duckdb_register_aggregate_function)(duckdb_connection con, + duckdb_aggregate_function aggregate_function); + void (*duckdb_aggregate_function_set_special_handling)(duckdb_aggregate_function aggregate_function); + void (*duckdb_aggregate_function_set_extra_info)(duckdb_aggregate_function aggregate_function, void *extra_info, + duckdb_delete_callback_t destroy); + void *(*duckdb_aggregate_function_get_extra_info)(duckdb_function_info info); + void (*duckdb_aggregate_function_set_error)(duckdb_function_info info, const char *error); + void (*duckdb_logical_type_set_alias)(duckdb_logical_type type, const char *alias); + duckdb_state (*duckdb_register_logical_type)(duckdb_connection con, duckdb_logical_type type, + duckdb_create_type_info info); + duckdb_cast_function (*duckdb_create_cast_function)(); + void (*duckdb_cast_function_set_source_type)(duckdb_cast_function cast_function, duckdb_logical_type source_type); + void (*duckdb_cast_function_set_target_type)(duckdb_cast_function cast_function, duckdb_logical_type target_type); + void (*duckdb_cast_function_set_implicit_cast_cost)(duckdb_cast_function cast_function, int64_t cost); + void (*duckdb_cast_function_set_function)(duckdb_cast_function cast_function, duckdb_cast_function_t function); + void (*duckdb_cast_function_set_extra_info)(duckdb_cast_function cast_function, void *extra_info, + duckdb_delete_callback_t destroy); + void *(*duckdb_cast_function_get_extra_info)(duckdb_function_info info); + duckdb_cast_mode (*duckdb_cast_function_get_cast_mode)(duckdb_function_info info); + void (*duckdb_cast_function_set_error)(duckdb_function_info info, const char *error); + void (*duckdb_cast_function_set_row_error)(duckdb_function_info info, const char *error, idx_t row, + duckdb_vector output); + duckdb_state (*duckdb_register_cast_function)(duckdb_connection con, duckdb_cast_function cast_function); + void (*duckdb_destroy_cast_function)(duckdb_cast_function *cast_function); idx_t (*duckdb_row_count)(duckdb_result *result); void *(*duckdb_column_data)(duckdb_result *result, idx_t col); bool *(*duckdb_nullmask_data)(duckdb_result *result, idx_t col); duckdb_data_chunk (*duckdb_result_get_chunk)(duckdb_result result, idx_t chunk_index); bool (*duckdb_result_is_streaming)(duckdb_result result); idx_t (*duckdb_result_chunk_count)(duckdb_result result); + duckdb_result_type (*duckdb_result_return_type)(duckdb_result result); bool (*duckdb_value_boolean)(duckdb_result *result, idx_t col, idx_t row); int8_t (*duckdb_value_int8)(duckdb_result *result, idx_t col, idx_t row); int16_t (*duckdb_value_int16)(duckdb_result *result, idx_t col, idx_t row); @@ -442,6 +403,7 @@ typedef struct { duckdb_result *out_result); duckdb_state (*duckdb_pending_prepared_streaming)(duckdb_prepared_statement prepared_statement, duckdb_pending_result *out_result); + duckdb_state (*duckdb_column_has_default)(duckdb_table_description table_description, idx_t index, bool *out); duckdb_state (*duckdb_query_arrow)(duckdb_connection connection, const char *query, duckdb_arrow *out_result); duckdb_state (*duckdb_query_arrow_schema)(duckdb_arrow result, duckdb_arrow_schema *out_schema); duckdb_state (*duckdb_prepared_arrow_schema)(duckdb_prepared_statement prepared, duckdb_arrow_schema *out_schema); @@ -460,24 +422,13 @@ typedef struct { duckdb_arrow_schema arrow_schema, duckdb_arrow_array arrow_array, duckdb_arrow_stream *out_stream); duckdb_data_chunk (*duckdb_stream_fetch_chunk)(duckdb_result result); - // Exposing the instance cache - - duckdb_instance_cache (*duckdb_create_instance_cache)(); - duckdb_state (*duckdb_get_or_create_from_cache)(duckdb_instance_cache instance_cache, const char *path, - duckdb_database *out_database, duckdb_config config, - char **out_error); - void (*duckdb_destroy_instance_cache)(duckdb_instance_cache *instance_cache); - // New append functions that are added - - duckdb_state (*duckdb_append_default_to_chunk)(duckdb_appender appender, duckdb_data_chunk chunk, idx_t col, - idx_t row); -} duckdb_ext_api_v1; +} duckdb_ext_api_v0; //===--------------------------------------------------------------------===// // Struct Create Method //===--------------------------------------------------------------------===// -inline duckdb_ext_api_v1 CreateAPIv1() { - duckdb_ext_api_v1 result; +inline duckdb_ext_api_v0 CreateAPIv0() { + duckdb_ext_api_v0 result; result.duckdb_open = duckdb_open; result.duckdb_open_ext = duckdb_open_ext; result.duckdb_close = duckdb_close; @@ -500,14 +451,10 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_column_count = duckdb_column_count; result.duckdb_rows_changed = duckdb_rows_changed; result.duckdb_result_error = duckdb_result_error; - result.duckdb_result_error_type = duckdb_result_error_type; - result.duckdb_result_return_type = duckdb_result_return_type; result.duckdb_malloc = duckdb_malloc; result.duckdb_free = duckdb_free; result.duckdb_vector_size = duckdb_vector_size; result.duckdb_string_is_inlined = duckdb_string_is_inlined; - result.duckdb_string_t_length = duckdb_string_t_length; - result.duckdb_string_t_data = duckdb_string_t_data; result.duckdb_from_date = duckdb_from_date; result.duckdb_to_date = duckdb_to_date; result.duckdb_is_finite_date = duckdb_is_finite_date; @@ -530,7 +477,6 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_nparams = duckdb_nparams; result.duckdb_parameter_name = duckdb_parameter_name; result.duckdb_param_type = duckdb_param_type; - result.duckdb_param_logical_type = duckdb_param_logical_type; result.duckdb_clear_bindings = duckdb_clear_bindings; result.duckdb_prepared_statement_type = duckdb_prepared_statement_type; result.duckdb_bind_value = duckdb_bind_value; @@ -573,70 +519,14 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_destroy_value = duckdb_destroy_value; result.duckdb_create_varchar = duckdb_create_varchar; result.duckdb_create_varchar_length = duckdb_create_varchar_length; - result.duckdb_create_bool = duckdb_create_bool; - result.duckdb_create_int8 = duckdb_create_int8; - result.duckdb_create_uint8 = duckdb_create_uint8; - result.duckdb_create_int16 = duckdb_create_int16; - result.duckdb_create_uint16 = duckdb_create_uint16; - result.duckdb_create_int32 = duckdb_create_int32; - result.duckdb_create_uint32 = duckdb_create_uint32; - result.duckdb_create_uint64 = duckdb_create_uint64; result.duckdb_create_int64 = duckdb_create_int64; - result.duckdb_create_hugeint = duckdb_create_hugeint; - result.duckdb_create_uhugeint = duckdb_create_uhugeint; - result.duckdb_create_float = duckdb_create_float; - result.duckdb_create_double = duckdb_create_double; - result.duckdb_create_date = duckdb_create_date; - result.duckdb_create_time = duckdb_create_time; - result.duckdb_create_time_tz_value = duckdb_create_time_tz_value; - result.duckdb_create_timestamp = duckdb_create_timestamp; - result.duckdb_create_interval = duckdb_create_interval; - result.duckdb_create_blob = duckdb_create_blob; - result.duckdb_create_varint = duckdb_create_varint; - result.duckdb_create_decimal = duckdb_create_decimal; - result.duckdb_create_bit = duckdb_create_bit; - result.duckdb_create_uuid = duckdb_create_uuid; - result.duckdb_get_bool = duckdb_get_bool; - result.duckdb_get_int8 = duckdb_get_int8; - result.duckdb_get_uint8 = duckdb_get_uint8; - result.duckdb_get_int16 = duckdb_get_int16; - result.duckdb_get_uint16 = duckdb_get_uint16; - result.duckdb_get_int32 = duckdb_get_int32; - result.duckdb_get_uint32 = duckdb_get_uint32; - result.duckdb_get_int64 = duckdb_get_int64; - result.duckdb_get_uint64 = duckdb_get_uint64; - result.duckdb_get_hugeint = duckdb_get_hugeint; - result.duckdb_get_uhugeint = duckdb_get_uhugeint; - result.duckdb_get_float = duckdb_get_float; - result.duckdb_get_double = duckdb_get_double; - result.duckdb_get_date = duckdb_get_date; - result.duckdb_get_time = duckdb_get_time; - result.duckdb_get_time_tz = duckdb_get_time_tz; - result.duckdb_get_timestamp = duckdb_get_timestamp; - result.duckdb_get_interval = duckdb_get_interval; - result.duckdb_get_value_type = duckdb_get_value_type; - result.duckdb_get_blob = duckdb_get_blob; - result.duckdb_get_varint = duckdb_get_varint; - result.duckdb_get_decimal = duckdb_get_decimal; - result.duckdb_get_bit = duckdb_get_bit; - result.duckdb_get_uuid = duckdb_get_uuid; - result.duckdb_get_varchar = duckdb_get_varchar; result.duckdb_create_struct_value = duckdb_create_struct_value; result.duckdb_create_list_value = duckdb_create_list_value; result.duckdb_create_array_value = duckdb_create_array_value; - result.duckdb_get_map_size = duckdb_get_map_size; - result.duckdb_get_map_key = duckdb_get_map_key; - result.duckdb_get_map_value = duckdb_get_map_value; - result.duckdb_is_null_value = duckdb_is_null_value; - result.duckdb_create_null_value = duckdb_create_null_value; - result.duckdb_get_list_size = duckdb_get_list_size; - result.duckdb_get_list_child = duckdb_get_list_child; - result.duckdb_create_enum_value = duckdb_create_enum_value; - result.duckdb_get_enum_value = duckdb_get_enum_value; - result.duckdb_get_struct_child = duckdb_get_struct_child; + result.duckdb_get_varchar = duckdb_get_varchar; + result.duckdb_get_int64 = duckdb_get_int64; result.duckdb_create_logical_type = duckdb_create_logical_type; result.duckdb_logical_type_get_alias = duckdb_logical_type_get_alias; - result.duckdb_logical_type_set_alias = duckdb_logical_type_set_alias; result.duckdb_create_list_type = duckdb_create_list_type; result.duckdb_create_array_type = duckdb_create_array_type; result.duckdb_create_map_type = duckdb_create_map_type; @@ -663,7 +553,7 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_union_type_member_name = duckdb_union_type_member_name; result.duckdb_union_type_member_type = duckdb_union_type_member_type; result.duckdb_destroy_logical_type = duckdb_destroy_logical_type; - result.duckdb_register_logical_type = duckdb_register_logical_type; + result.duckdb_fetch_chunk = duckdb_fetch_chunk; result.duckdb_create_data_chunk = duckdb_create_data_chunk; result.duckdb_destroy_data_chunk = duckdb_destroy_data_chunk; result.duckdb_data_chunk_reset = duckdb_data_chunk_reset; @@ -690,36 +580,11 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_create_scalar_function = duckdb_create_scalar_function; result.duckdb_destroy_scalar_function = duckdb_destroy_scalar_function; result.duckdb_scalar_function_set_name = duckdb_scalar_function_set_name; - result.duckdb_scalar_function_set_varargs = duckdb_scalar_function_set_varargs; - result.duckdb_scalar_function_set_special_handling = duckdb_scalar_function_set_special_handling; - result.duckdb_scalar_function_set_volatile = duckdb_scalar_function_set_volatile; result.duckdb_scalar_function_add_parameter = duckdb_scalar_function_add_parameter; result.duckdb_scalar_function_set_return_type = duckdb_scalar_function_set_return_type; result.duckdb_scalar_function_set_extra_info = duckdb_scalar_function_set_extra_info; result.duckdb_scalar_function_set_function = duckdb_scalar_function_set_function; result.duckdb_register_scalar_function = duckdb_register_scalar_function; - result.duckdb_scalar_function_get_extra_info = duckdb_scalar_function_get_extra_info; - result.duckdb_scalar_function_set_error = duckdb_scalar_function_set_error; - result.duckdb_create_scalar_function_set = duckdb_create_scalar_function_set; - result.duckdb_destroy_scalar_function_set = duckdb_destroy_scalar_function_set; - result.duckdb_add_scalar_function_to_set = duckdb_add_scalar_function_to_set; - result.duckdb_register_scalar_function_set = duckdb_register_scalar_function_set; - result.duckdb_create_aggregate_function = duckdb_create_aggregate_function; - result.duckdb_destroy_aggregate_function = duckdb_destroy_aggregate_function; - result.duckdb_aggregate_function_set_name = duckdb_aggregate_function_set_name; - result.duckdb_aggregate_function_add_parameter = duckdb_aggregate_function_add_parameter; - result.duckdb_aggregate_function_set_return_type = duckdb_aggregate_function_set_return_type; - result.duckdb_aggregate_function_set_functions = duckdb_aggregate_function_set_functions; - result.duckdb_aggregate_function_set_destructor = duckdb_aggregate_function_set_destructor; - result.duckdb_register_aggregate_function = duckdb_register_aggregate_function; - result.duckdb_aggregate_function_set_special_handling = duckdb_aggregate_function_set_special_handling; - result.duckdb_aggregate_function_set_extra_info = duckdb_aggregate_function_set_extra_info; - result.duckdb_aggregate_function_get_extra_info = duckdb_aggregate_function_get_extra_info; - result.duckdb_aggregate_function_set_error = duckdb_aggregate_function_set_error; - result.duckdb_create_aggregate_function_set = duckdb_create_aggregate_function_set; - result.duckdb_destroy_aggregate_function_set = duckdb_destroy_aggregate_function_set; - result.duckdb_add_aggregate_function_to_set = duckdb_add_aggregate_function_to_set; - result.duckdb_register_aggregate_function_set = duckdb_register_aggregate_function_set; result.duckdb_create_table_function = duckdb_create_table_function; result.duckdb_destroy_table_function = duckdb_destroy_table_function; result.duckdb_table_function_set_name = duckdb_table_function_set_name; @@ -756,61 +621,13 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_replacement_scan_set_function_name = duckdb_replacement_scan_set_function_name; result.duckdb_replacement_scan_add_parameter = duckdb_replacement_scan_add_parameter; result.duckdb_replacement_scan_set_error = duckdb_replacement_scan_set_error; - result.duckdb_profiling_info_get_metrics = duckdb_profiling_info_get_metrics; - result.duckdb_profiling_info_get_child_count = duckdb_profiling_info_get_child_count; - result.duckdb_profiling_info_get_child = duckdb_profiling_info_get_child; result.duckdb_appender_create = duckdb_appender_create; - result.duckdb_appender_create_ext = duckdb_appender_create_ext; result.duckdb_appender_column_count = duckdb_appender_column_count; result.duckdb_appender_column_type = duckdb_appender_column_type; result.duckdb_appender_error = duckdb_appender_error; result.duckdb_appender_flush = duckdb_appender_flush; result.duckdb_appender_close = duckdb_appender_close; result.duckdb_appender_destroy = duckdb_appender_destroy; - result.duckdb_appender_add_column = duckdb_appender_add_column; - result.duckdb_appender_clear_columns = duckdb_appender_clear_columns; - result.duckdb_append_data_chunk = duckdb_append_data_chunk; - result.duckdb_table_description_create = duckdb_table_description_create; - result.duckdb_table_description_create_ext = duckdb_table_description_create_ext; - result.duckdb_table_description_destroy = duckdb_table_description_destroy; - result.duckdb_table_description_error = duckdb_table_description_error; - result.duckdb_column_has_default = duckdb_column_has_default; - result.duckdb_table_description_get_column_name = duckdb_table_description_get_column_name; - result.duckdb_execute_tasks = duckdb_execute_tasks; - result.duckdb_create_task_state = duckdb_create_task_state; - result.duckdb_execute_tasks_state = duckdb_execute_tasks_state; - result.duckdb_execute_n_tasks_state = duckdb_execute_n_tasks_state; - result.duckdb_finish_execution = duckdb_finish_execution; - result.duckdb_task_state_is_finished = duckdb_task_state_is_finished; - result.duckdb_destroy_task_state = duckdb_destroy_task_state; - result.duckdb_execution_is_finished = duckdb_execution_is_finished; - result.duckdb_fetch_chunk = duckdb_fetch_chunk; - result.duckdb_create_cast_function = duckdb_create_cast_function; - result.duckdb_cast_function_set_source_type = duckdb_cast_function_set_source_type; - result.duckdb_cast_function_set_target_type = duckdb_cast_function_set_target_type; - result.duckdb_cast_function_set_implicit_cast_cost = duckdb_cast_function_set_implicit_cast_cost; - result.duckdb_cast_function_set_function = duckdb_cast_function_set_function; - result.duckdb_cast_function_set_extra_info = duckdb_cast_function_set_extra_info; - result.duckdb_cast_function_get_extra_info = duckdb_cast_function_get_extra_info; - result.duckdb_cast_function_get_cast_mode = duckdb_cast_function_get_cast_mode; - result.duckdb_cast_function_set_error = duckdb_cast_function_set_error; - result.duckdb_cast_function_set_row_error = duckdb_cast_function_set_row_error; - result.duckdb_register_cast_function = duckdb_register_cast_function; - result.duckdb_destroy_cast_function = duckdb_destroy_cast_function; - result.duckdb_is_finite_timestamp_s = duckdb_is_finite_timestamp_s; - result.duckdb_is_finite_timestamp_ms = duckdb_is_finite_timestamp_ms; - result.duckdb_is_finite_timestamp_ns = duckdb_is_finite_timestamp_ns; - result.duckdb_create_timestamp_tz = duckdb_create_timestamp_tz; - result.duckdb_create_timestamp_s = duckdb_create_timestamp_s; - result.duckdb_create_timestamp_ms = duckdb_create_timestamp_ms; - result.duckdb_create_timestamp_ns = duckdb_create_timestamp_ns; - result.duckdb_get_timestamp_tz = duckdb_get_timestamp_tz; - result.duckdb_get_timestamp_s = duckdb_get_timestamp_s; - result.duckdb_get_timestamp_ms = duckdb_get_timestamp_ms; - result.duckdb_get_timestamp_ns = duckdb_get_timestamp_ns; - result.duckdb_append_value = duckdb_append_value; - result.duckdb_get_profiling_info = duckdb_get_profiling_info; - result.duckdb_profiling_info_get_value = duckdb_profiling_info_get_value; result.duckdb_appender_begin_row = duckdb_appender_begin_row; result.duckdb_appender_end_row = duckdb_appender_end_row; result.duckdb_append_default = duckdb_append_default; @@ -835,12 +652,112 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_append_varchar_length = duckdb_append_varchar_length; result.duckdb_append_blob = duckdb_append_blob; result.duckdb_append_null = duckdb_append_null; + result.duckdb_append_data_chunk = duckdb_append_data_chunk; + result.duckdb_execute_tasks = duckdb_execute_tasks; + result.duckdb_create_task_state = duckdb_create_task_state; + result.duckdb_execute_tasks_state = duckdb_execute_tasks_state; + result.duckdb_execute_n_tasks_state = duckdb_execute_n_tasks_state; + result.duckdb_finish_execution = duckdb_finish_execution; + result.duckdb_task_state_is_finished = duckdb_task_state_is_finished; + result.duckdb_destroy_task_state = duckdb_destroy_task_state; + result.duckdb_execution_is_finished = duckdb_execution_is_finished; + result.duckdb_get_profiling_info = duckdb_get_profiling_info; + result.duckdb_profiling_info_get_value = duckdb_profiling_info_get_value; + result.duckdb_profiling_info_get_child_count = duckdb_profiling_info_get_child_count; + result.duckdb_profiling_info_get_child = duckdb_profiling_info_get_child; + result.duckdb_profiling_info_get_metrics = duckdb_profiling_info_get_metrics; + result.duckdb_scalar_function_set_varargs = duckdb_scalar_function_set_varargs; + result.duckdb_scalar_function_set_special_handling = duckdb_scalar_function_set_special_handling; + result.duckdb_scalar_function_set_volatile = duckdb_scalar_function_set_volatile; + result.duckdb_scalar_function_get_extra_info = duckdb_scalar_function_get_extra_info; + result.duckdb_scalar_function_set_error = duckdb_scalar_function_set_error; + result.duckdb_table_description_create = duckdb_table_description_create; + result.duckdb_table_description_destroy = duckdb_table_description_destroy; + result.duckdb_table_description_error = duckdb_table_description_error; + result.duckdb_result_error_type = duckdb_result_error_type; + result.duckdb_string_t_length = duckdb_string_t_length; + result.duckdb_string_t_data = duckdb_string_t_data; + result.duckdb_create_bool = duckdb_create_bool; + result.duckdb_create_int8 = duckdb_create_int8; + result.duckdb_create_uint8 = duckdb_create_uint8; + result.duckdb_create_int16 = duckdb_create_int16; + result.duckdb_create_uint16 = duckdb_create_uint16; + result.duckdb_create_int32 = duckdb_create_int32; + result.duckdb_create_uint32 = duckdb_create_uint32; + result.duckdb_create_uint64 = duckdb_create_uint64; + result.duckdb_create_hugeint = duckdb_create_hugeint; + result.duckdb_create_uhugeint = duckdb_create_uhugeint; + result.duckdb_create_float = duckdb_create_float; + result.duckdb_create_double = duckdb_create_double; + result.duckdb_create_date = duckdb_create_date; + result.duckdb_create_time = duckdb_create_time; + result.duckdb_create_time_tz_value = duckdb_create_time_tz_value; + result.duckdb_create_timestamp = duckdb_create_timestamp; + result.duckdb_create_interval = duckdb_create_interval; + result.duckdb_create_blob = duckdb_create_blob; + result.duckdb_get_bool = duckdb_get_bool; + result.duckdb_get_int8 = duckdb_get_int8; + result.duckdb_get_uint8 = duckdb_get_uint8; + result.duckdb_get_int16 = duckdb_get_int16; + result.duckdb_get_uint16 = duckdb_get_uint16; + result.duckdb_get_int32 = duckdb_get_int32; + result.duckdb_get_uint32 = duckdb_get_uint32; + result.duckdb_get_uint64 = duckdb_get_uint64; + result.duckdb_get_hugeint = duckdb_get_hugeint; + result.duckdb_get_uhugeint = duckdb_get_uhugeint; + result.duckdb_get_float = duckdb_get_float; + result.duckdb_get_double = duckdb_get_double; + result.duckdb_get_date = duckdb_get_date; + result.duckdb_get_time = duckdb_get_time; + result.duckdb_get_time_tz = duckdb_get_time_tz; + result.duckdb_get_timestamp = duckdb_get_timestamp; + result.duckdb_get_interval = duckdb_get_interval; + result.duckdb_get_value_type = duckdb_get_value_type; + result.duckdb_get_blob = duckdb_get_blob; + result.duckdb_create_scalar_function_set = duckdb_create_scalar_function_set; + result.duckdb_destroy_scalar_function_set = duckdb_destroy_scalar_function_set; + result.duckdb_add_scalar_function_to_set = duckdb_add_scalar_function_to_set; + result.duckdb_register_scalar_function_set = duckdb_register_scalar_function_set; + result.duckdb_create_aggregate_function_set = duckdb_create_aggregate_function_set; + result.duckdb_destroy_aggregate_function_set = duckdb_destroy_aggregate_function_set; + result.duckdb_add_aggregate_function_to_set = duckdb_add_aggregate_function_to_set; + result.duckdb_register_aggregate_function_set = duckdb_register_aggregate_function_set; + result.duckdb_get_map_size = duckdb_get_map_size; + result.duckdb_get_map_key = duckdb_get_map_key; + result.duckdb_get_map_value = duckdb_get_map_value; + result.duckdb_create_aggregate_function = duckdb_create_aggregate_function; + result.duckdb_destroy_aggregate_function = duckdb_destroy_aggregate_function; + result.duckdb_aggregate_function_set_name = duckdb_aggregate_function_set_name; + result.duckdb_aggregate_function_add_parameter = duckdb_aggregate_function_add_parameter; + result.duckdb_aggregate_function_set_return_type = duckdb_aggregate_function_set_return_type; + result.duckdb_aggregate_function_set_functions = duckdb_aggregate_function_set_functions; + result.duckdb_aggregate_function_set_destructor = duckdb_aggregate_function_set_destructor; + result.duckdb_register_aggregate_function = duckdb_register_aggregate_function; + result.duckdb_aggregate_function_set_special_handling = duckdb_aggregate_function_set_special_handling; + result.duckdb_aggregate_function_set_extra_info = duckdb_aggregate_function_set_extra_info; + result.duckdb_aggregate_function_get_extra_info = duckdb_aggregate_function_get_extra_info; + result.duckdb_aggregate_function_set_error = duckdb_aggregate_function_set_error; + result.duckdb_logical_type_set_alias = duckdb_logical_type_set_alias; + result.duckdb_register_logical_type = duckdb_register_logical_type; + result.duckdb_create_cast_function = duckdb_create_cast_function; + result.duckdb_cast_function_set_source_type = duckdb_cast_function_set_source_type; + result.duckdb_cast_function_set_target_type = duckdb_cast_function_set_target_type; + result.duckdb_cast_function_set_implicit_cast_cost = duckdb_cast_function_set_implicit_cast_cost; + result.duckdb_cast_function_set_function = duckdb_cast_function_set_function; + result.duckdb_cast_function_set_extra_info = duckdb_cast_function_set_extra_info; + result.duckdb_cast_function_get_extra_info = duckdb_cast_function_get_extra_info; + result.duckdb_cast_function_get_cast_mode = duckdb_cast_function_get_cast_mode; + result.duckdb_cast_function_set_error = duckdb_cast_function_set_error; + result.duckdb_cast_function_set_row_error = duckdb_cast_function_set_row_error; + result.duckdb_register_cast_function = duckdb_register_cast_function; + result.duckdb_destroy_cast_function = duckdb_destroy_cast_function; result.duckdb_row_count = duckdb_row_count; result.duckdb_column_data = duckdb_column_data; result.duckdb_nullmask_data = duckdb_nullmask_data; result.duckdb_result_get_chunk = duckdb_result_get_chunk; result.duckdb_result_is_streaming = duckdb_result_is_streaming; result.duckdb_result_chunk_count = duckdb_result_chunk_count; + result.duckdb_result_return_type = duckdb_result_return_type; result.duckdb_value_boolean = duckdb_value_boolean; result.duckdb_value_int8 = duckdb_value_int8; result.duckdb_value_int16 = duckdb_value_int16; @@ -867,6 +784,7 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_value_is_null = duckdb_value_is_null; result.duckdb_execute_prepared_streaming = duckdb_execute_prepared_streaming; result.duckdb_pending_prepared_streaming = duckdb_pending_prepared_streaming; + result.duckdb_column_has_default = duckdb_column_has_default; result.duckdb_query_arrow = duckdb_query_arrow; result.duckdb_query_arrow_schema = duckdb_query_arrow_schema; result.duckdb_prepared_arrow_schema = duckdb_prepared_arrow_schema; @@ -882,14 +800,10 @@ inline duckdb_ext_api_v1 CreateAPIv1() { result.duckdb_arrow_scan = duckdb_arrow_scan; result.duckdb_arrow_array_scan = duckdb_arrow_array_scan; result.duckdb_stream_fetch_chunk = duckdb_stream_fetch_chunk; - result.duckdb_create_instance_cache = duckdb_create_instance_cache; - result.duckdb_get_or_create_from_cache = duckdb_get_or_create_from_cache; - result.duckdb_destroy_instance_cache = duckdb_destroy_instance_cache; - result.duckdb_append_default_to_chunk = duckdb_append_default_to_chunk; return result; } -#define DUCKDB_EXTENSION_API_VERSION_MAJOR 1 -#define DUCKDB_EXTENSION_API_VERSION_MINOR 2 -#define DUCKDB_EXTENSION_API_VERSION_PATCH 0 -#define DUCKDB_EXTENSION_API_VERSION_STRING "v1.2.0" +#define DUCKDB_EXTENSION_API_VERSION_MAJOR 0 +#define DUCKDB_EXTENSION_API_VERSION_MINOR 0 +#define DUCKDB_EXTENSION_API_VERSION_PATCH 1 +#define DUCKDB_EXTENSION_API_VERSION_STRING "v0.0.1" diff --git a/src/duckdb/src/include/duckdb/main/client_config.hpp b/src/duckdb/src/include/duckdb/main/client_config.hpp index 8b919c821..306aa0a62 100644 --- a/src/duckdb/src/include/duckdb/main/client_config.hpp +++ b/src/duckdb/src/include/duckdb/main/client_config.hpp @@ -117,9 +117,6 @@ struct ClientConfig { //! The threshold at which we switch from using filtered aggregates to LIST with a dedicated pivot operator idx_t pivot_filter_threshold = 20; - //! The maximum amount of OR filters we generate dynamically from a hash join - idx_t dynamic_or_filter_threshold = 50; - //! Whether or not the "/" division operator defaults to integer division or floating point division bool integer_division = false; //! When a scalar subquery returns multiple rows - return a random row instead of returning an error @@ -173,16 +170,6 @@ struct ClientConfig { user_variables.erase(name); } - template - static typename OP::RETURN_TYPE GetSetting(const ClientContext &context) { - return OP::GetSetting(context).template GetValue(); - } - - template - static Value GetSettingValue(const ClientContext &context) { - return OP::GetSetting(context); - } - public: void SetDefaultStreamingBufferSize(); }; diff --git a/src/duckdb/src/include/duckdb/main/client_context.hpp b/src/duckdb/src/include/duckdb/main/client_context.hpp index 6f5115cb1..c03e38ae0 100644 --- a/src/duckdb/src/include/duckdb/main/client_context.hpp +++ b/src/duckdb/src/include/duckdb/main/client_context.hpp @@ -114,32 +114,17 @@ class ClientContext : public enable_shared_from_this { DUCKDB_API unique_ptr PendingQuery(unique_ptr statement, bool allow_stream_result); - //! Create a pending query with a list of parameters - DUCKDB_API unique_ptr PendingQuery(unique_ptr statement, - case_insensitive_map_t &values, - bool allow_stream_result); - DUCKDB_API unique_ptr - PendingQuery(const string &query, case_insensitive_map_t &values, bool allow_stream_result); - //! Destroy the client context DUCKDB_API void Destroy(); - //! Get the table info of a specific table, or nullptr if it cannot be found. - DUCKDB_API unique_ptr TableInfo(const string &database_name, const string &schema_name, - const string &table_name); - //! Get the table info of a specific table, or nullptr if it cannot be found. Uses INVALID_CATALOG. + //! Get the table info of a specific table, or nullptr if it cannot be found DUCKDB_API unique_ptr TableInfo(const string &schema_name, const string &table_name); - //! Appends a DataChunk and its default columns to the specified table. - DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection, - optional_ptr> column_ids = nullptr); - + //! Appends a DataChunk to the specified table. Returns whether or not the append was successful. + DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection); //! Try to bind a relation in the current client context; either throws an exception or fills the result_columns //! list with the set of returned columns DUCKDB_API void TryBindRelation(Relation &relation, vector &result_columns); - //! Internal function for try bind relation. It does not require a client-context lock. - DUCKDB_API void InternalTryBindRelation(Relation &relation, vector &result_columns); - //! Execute a relation DUCKDB_API unique_ptr PendingQuery(const shared_ptr &relation, bool allow_stream_result); @@ -226,8 +211,7 @@ class ClientContext : public enable_shared_from_this { vector> ParseStatementsInternal(ClientContextLock &lock, const string &query); //! Perform aggressive query verification of a SELECT statement. Only called when query_verification_enabled is //! true. - ErrorData VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr statement, - optional_ptr> values = nullptr); + ErrorData VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr statement); void InitialCleanup(ClientContextLock &lock); //! Internal clean up, does not lock. Caller must hold the context_lock. @@ -255,7 +239,6 @@ class ClientContext : public enable_shared_from_this { const PendingQueryParameters ¶meters); unique_ptr RunStatementInternal(ClientContextLock &lock, const string &query, unique_ptr statement, bool allow_stream_result, - optional_ptr> params, bool verify = true); unique_ptr PrepareInternal(ClientContextLock &lock, unique_ptr statement); void LogQueryInternal(ClientContextLock &lock, const string &query); diff --git a/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp b/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp index 41c102255..2ee703458 100644 --- a/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp +++ b/src/duckdb/src/include/duckdb/main/client_context_wrapper.hpp @@ -9,21 +9,16 @@ #pragma once #include "duckdb/common/shared_ptr.hpp" -#include "duckdb/parser/column_definition.hpp" namespace duckdb { class ClientContext; -class Relation; - class ClientContextWrapper { public: - virtual ~ClientContextWrapper() = default; explicit ClientContextWrapper(const shared_ptr &context); shared_ptr GetContext(); shared_ptr TryGetContext(); - virtual void TryBindRelation(Relation &relation, vector &columns); private: weak_ptr client_context; diff --git a/src/duckdb/src/include/duckdb/main/client_data.hpp b/src/duckdb/src/include/duckdb/main/client_data.hpp index b3e326267..777859755 100644 --- a/src/duckdb/src/include/duckdb/main/client_data.hpp +++ b/src/duckdb/src/include/duckdb/main/client_data.hpp @@ -27,7 +27,7 @@ class QueryProfiler; class PreparedStatementData; class SchemaCatalogEntry; class HTTPLogger; -class RandomEngine; +struct RandomEngine; struct ClientData { explicit ClientData(ClientContext &context); diff --git a/src/duckdb/src/include/duckdb/main/config.hpp b/src/duckdb/src/include/duckdb/main/config.hpp index 604ef264b..162109bad 100644 --- a/src/duckdb/src/include/duckdb/main/config.hpp +++ b/src/duckdb/src/include/duckdb/main/config.hpp @@ -24,16 +24,15 @@ #include "duckdb/common/types/value.hpp" #include "duckdb/common/vector.hpp" #include "duckdb/common/winapi.hpp" -#include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/function/cast/default_casts.hpp" #include "duckdb/function/replacement_scan.hpp" -#include "duckdb/main/client_properties.hpp" #include "duckdb/optimizer/optimizer_extension.hpp" #include "duckdb/parser/parsed_data/create_info.hpp" #include "duckdb/parser/parser_extension.hpp" #include "duckdb/planner/operator_extension.hpp" #include "duckdb/storage/compression/bitpacking.hpp" -#include "duckdb/function/encoding_function.hpp" +#include "duckdb/main/client_properties.hpp" +#include "duckdb/execution/index/index_type_set.hpp" namespace duckdb { @@ -71,7 +70,7 @@ typedef Value (*get_setting_function_t)(const ClientContext &context); struct ConfigurationOption { const char *name; const char *description; - const char *parameter_type; + LogicalTypeId parameter_type; set_global_function_t set_global; set_local_function_t set_local; reset_global_function_t reset_global; @@ -169,10 +168,12 @@ struct DBConfigOptions { string collation = string(); //! The order type used when none is specified (default: ASC) OrderType default_order_type = OrderType::ASCENDING; - //! NULL ordering used when none is specified (default: NULLS LAST) + //! Null ordering used when none is specified (default: NULLS LAST) DefaultOrderByNullType default_null_order = DefaultOrderByNullType::NULLS_LAST; //! enable COPY and related commands bool enable_external_access = true; + //! Whether or not object cache is used + bool object_cache_enable = false; //! Whether or not the global http metadata cache is used bool http_metadata_cache_enable = false; //! HTTP Proxy config as 'hostname:port' @@ -194,15 +195,13 @@ struct DBConfigOptions { bool initialize_default_database = true; //! The set of disabled optimizers (default empty) set disabled_optimizers; - //! The average string length required to use ZSTD compression. - uint64_t zstd_min_string_length = 4096; //! Force a specific compression method to be used when checkpointing (if available) CompressionType force_compression = CompressionType::COMPRESSION_AUTO; //! Force a specific bitpacking mode to be used when using the bitpacking compression method BitpackingMode force_bitpacking_mode = BitpackingMode::AUTO; //! Debug setting for window aggregation mode: (window, combine, separate) WindowAggregationMode window_mode = WindowAggregationMode::WINDOW; - //! Whether preserving insertion order should be preserved + //! Whether or not preserving insertion order should be preserved bool preserve_insertion_order = true; //! Whether Arrow Arrays use Large or Regular buffers ArrowOffsetSize arrow_offset_size = ArrowOffsetSize::REGULAR; @@ -210,7 +209,7 @@ struct DBConfigOptions { bool arrow_use_list_view = false; //! Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types //! with a duckdb.type_name extension name - bool arrow_lossless_conversion = false; + bool arrow_arrow_lossless_conversion = false; //! Whether when producing arrow objects we produce string_views or regular strings bool produce_arrow_string_views = false; //! Database configuration variables as controlled by SET @@ -273,10 +272,6 @@ struct DBConfigOptions { bool debug_skip_checkpoint_on_commit = false; //! The maximum amount of vacuum tasks to schedule during a checkpoint idx_t max_vacuum_tasks = 100; - //! Paths that are explicitly allowed, even if enable_external_access is false - unordered_set allowed_paths; - //! Directories that are explicitly allowed, even if enable_external_access is false - set allowed_directories; bool operator==(const DBConfigOptions &other) const; }; @@ -351,7 +346,6 @@ struct DBConfig { DUCKDB_API void ResetOption(DatabaseInstance *db, const ConfigurationOption &option); DUCKDB_API void SetOption(const string &name, Value value); DUCKDB_API void ResetOption(const string &name); - static LogicalType ParseLogicalType(const string &type); DUCKDB_API void CheckLock(const string &name); @@ -363,12 +357,6 @@ struct DBConfig { DUCKDB_API optional_ptr GetCompressionFunction(CompressionType type, const PhysicalType physical_type); - //! Returns the encode function matching the encoding name. - DUCKDB_API optional_ptr GetEncodeFunction(const string &name) const; - DUCKDB_API void RegisterEncodeFunction(const EncodingFunction &function) const; - - //! Returns the encode function names. - DUCKDB_API vector> GetLoadedEncodedFunctions() const; bool operator==(const DBConfig &other); bool operator!=(const DBConfig &other); @@ -385,26 +373,8 @@ struct DBConfig { OrderByNullType ResolveNullOrder(OrderType order_type, OrderByNullType null_type) const; const string UserAgent() const; - template - typename OP::RETURN_TYPE GetSetting(const ClientContext &context) { - std::lock_guard lock(config_lock); - return OP::GetSetting(context).template GetValue(); - } - - template - Value GetSettingValue(const ClientContext &context) { - std::lock_guard lock(config_lock); - return OP::GetSetting(context); - } - - bool CanAccessFile(const string &path, FileType type); - void AddAllowedDirectory(const string &path); - void AddAllowedPath(const string &path); - string SanitizeAllowedPath(const string &path) const; - private: unique_ptr compression_functions; - unique_ptr encoding_functions; unique_ptr cast_functions; unique_ptr collation_bindings; unique_ptr index_types; diff --git a/src/duckdb/src/include/duckdb/main/connection.hpp b/src/duckdb/src/include/duckdb/main/connection.hpp index d0935ca8e..aec41c7d5 100644 --- a/src/duckdb/src/include/duckdb/main/connection.hpp +++ b/src/duckdb/src/include/duckdb/main/connection.hpp @@ -97,30 +97,16 @@ class Connection { //! Issues a query to the database and returns a Pending Query Result DUCKDB_API unique_ptr PendingQuery(unique_ptr statement, bool allow_stream_result = false); - DUCKDB_API unique_ptr PendingQuery(unique_ptr statement, - case_insensitive_map_t &named_values, - bool allow_stream_result = false); - DUCKDB_API unique_ptr PendingQuery(const string &query, - case_insensitive_map_t &named_values, - bool allow_stream_result = false); - DUCKDB_API unique_ptr PendingQuery(const string &query, vector &values, - bool allow_stream_result = false); - DUCKDB_API unique_ptr PendingQuery(unique_ptr statement, vector &values, - bool allow_stream_result = false); //! Prepare the specified query, returning a prepared statement object DUCKDB_API unique_ptr Prepare(const string &query); //! Prepare the specified statement, returning a prepared statement object DUCKDB_API unique_ptr Prepare(unique_ptr statement); - //! Get the table info of a specific table, or nullptr if it cannot be found. - DUCKDB_API unique_ptr TableInfo(const string &database_name, const string &schema_name, - const string &table_name); - //! Get the table info of a specific table, or nullptr if it cannot be found. Uses INVALID_CATALOG. - DUCKDB_API unique_ptr TableInfo(const string &schema_name, const string &table_name); - //! Get the table info of a specific table, or nullptr if it cannot be found. Uses INVALID_CATALOG and - //! DEFAULT_SCHEMA. + //! Get the table info of a specific table (in the default schema), or nullptr if it cannot be found DUCKDB_API unique_ptr TableInfo(const string &table_name); + //! Get the table info of a specific table, or nullptr if it cannot be found + DUCKDB_API unique_ptr TableInfo(const string &schema_name, const string &table_name); //! Extract a set of SQL statements from a specific query DUCKDB_API vector> ExtractStatements(const string &query); @@ -145,7 +131,6 @@ class Connection { DUCKDB_API shared_ptr TableFunction(const string &tname, const vector &values); //! Returns a relation that produces values DUCKDB_API shared_ptr Values(const vector> &values); - DUCKDB_API shared_ptr Values(vector>> &&values); DUCKDB_API shared_ptr Values(const vector> &values, const vector &column_names, const string &alias = "values"); DUCKDB_API shared_ptr Values(const string &values); diff --git a/src/duckdb/src/include/duckdb/main/database.hpp b/src/duckdb/src/include/duckdb/main/database.hpp index 12bb6fbee..2a6fffa99 100644 --- a/src/duckdb/src/include/duckdb/main/database.hpp +++ b/src/duckdb/src/include/duckdb/main/database.hpp @@ -59,7 +59,7 @@ class DatabaseInstance : public enable_shared_from_this { DUCKDB_API ValidChecker &GetValidChecker(); DUCKDB_API void SetExtensionLoaded(const string &extension_name, ExtensionInstallInfo &install_info); - DUCKDB_API const duckdb_ext_api_v1 GetExtensionAPIV1(); + DUCKDB_API const duckdb_ext_api_v0 GetExtensionAPIV0(); idx_t NumberOfThreads(); @@ -95,7 +95,7 @@ class DatabaseInstance : public enable_shared_from_this { unique_ptr db_file_system; shared_ptr db_cache_entry; - duckdb_ext_api_v1 (*create_api_v1)(); + duckdb_ext_api_v0 (*create_api_v0)(); }; //! The database object. This object holds the catalog and all the diff --git a/src/duckdb/src/include/duckdb/main/database_file_opener.hpp b/src/duckdb/src/include/duckdb/main/database_file_opener.hpp index 024956aaa..6cf210867 100644 --- a/src/duckdb/src/include/duckdb/main/database_file_opener.hpp +++ b/src/duckdb/src/include/duckdb/main/database_file_opener.hpp @@ -22,7 +22,7 @@ class DatabaseFileOpener : public FileOpener { } SettingLookupResult TryGetCurrentSetting(const string &key, Value &result) override { - return db.TryGetCurrentSetting(key, result); + return SettingLookupResult(); } optional_ptr TryGetClientContext() override { diff --git a/src/duckdb/src/include/duckdb/main/database_manager.hpp b/src/duckdb/src/include/duckdb/main/database_manager.hpp index c193c979f..c06b5505a 100644 --- a/src/duckdb/src/include/duckdb/main/database_manager.hpp +++ b/src/duckdb/src/include/duckdb/main/database_manager.hpp @@ -21,7 +21,6 @@ namespace duckdb { class AttachedDatabase; class Catalog; -class CatalogEntryRetriever; class CatalogSet; class ClientContext; class DatabaseInstance; @@ -84,8 +83,6 @@ class DatabaseManager { bool HasDefaultDatabase() { return !default_database.empty(); } - //! Gets a list of all attached database paths - vector GetAttachedDatabasePaths(); private: //! Returns a database with a specified path diff --git a/src/duckdb/src/include/duckdb/main/extension.hpp b/src/duckdb/src/include/duckdb/main/extension.hpp index 53de1481d..15408048d 100644 --- a/src/duckdb/src/include/duckdb/main/extension.hpp +++ b/src/duckdb/src/include/duckdb/main/extension.hpp @@ -28,12 +28,8 @@ class Extension { enum class ExtensionABIType : uint8_t { UNKNOWN = 0, - //! Uses C++ ABI, version needs to match precisely CPP = 1, - //! Uses C ABI using the duckdb_ext_api_v1 struct, version needs to be equal or higher C_STRUCT = 2, - //! Uses C ABI using the duckdb_ext_api_v1 struct including "unstable" functions, version needs to match precisely - C_STRUCT_UNSTABLE = 3 }; //! The parsed extension metadata footer @@ -48,11 +44,9 @@ struct ParsedExtensionMetaData { ExtensionABIType abi_type; string platform; - // (For ExtensionABIType::CPP or ExtensionABIType::C_STRUCT_UNSTABLE) the DuckDB version this extension is compiled - // for + // (only for ExtensionABIType::CPP) the DuckDB version this extension is compiled for string duckdb_version; - // (only for ExtensionABIType::C_STRUCT) the CAPI version of the C_STRUCT (Currently interpreted as the minimum - // DuckDB version) + // (only for ExtensionABIType::C_STRUCT) the CAPI version of the C_STRUCT string duckdb_capi_version; string extension_version; string signature; diff --git a/src/duckdb/src/include/duckdb/main/extension_entries.hpp b/src/duckdb/src/include/duckdb/main/extension_entries.hpp index b0d0c0c41..ae31c576d 100644 --- a/src/duckdb/src/include/duckdb/main/extension_entries.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_entries.hpp @@ -11,13 +11,8 @@ #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/enums/catalog_type.hpp" -// NOTE: this file is generated by scripts/generate_extensions_function.py. -// Example usage to refresh one extension (replace "icu" with the desired extension): -// GENERATE_EXTENSION_ENTRIES=1 make debug -// python3 scripts/generate_extensions_function.py --extensions icu --shell build/debug/duckdb --extension_dir -// build/debug - -// Check out the check-load-install-extensions job in .github/workflows/LinuxRelease.yml for more details +// NOTE: this file is generated by scripts/generate_extensions_function.py. Check out the check-load-install-extensions +// job in .github/workflows/LinuxRelease.yml on how to use it namespace duckdb { @@ -32,174 +27,31 @@ struct ExtensionFunctionEntry { CatalogType type; }; -struct ExtensionFunctionOverloadEntry { - char name[48]; - char extension[48]; - CatalogType type; - char signature[96]; -}; - static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { - {"!__postfix", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"&", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"&&", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"**", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"->>", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"<->", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"<<", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"<<=", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"<=>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"<@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {">>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {">>=", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"@>", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"^", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"^@", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"abs", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"acos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"acosh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"add_numbers_together", "demo_capi", CatalogType::SCALAR_FUNCTION_ENTRY}, {"add_parquet_key", "parquet", CatalogType::PRAGMA_FUNCTION_ENTRY}, - {"aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"alias", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"approx_count_distinct", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"approx_quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"approx_top_k", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"arg_max", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"arg_max_null", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"arg_min", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"arg_min_null", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"argmax", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"argmin", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"array_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"array_aggr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_cosine_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_cosine_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_cross_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_distinct", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_has_all", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_has_any", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_negative_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_negative_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_reverse_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_slice", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"array_to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_transform", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_unique", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"array_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"ascii", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"asin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"asinh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"atan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"atan2", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"atanh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"avg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bar", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"bin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"bit_and", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bit_count", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"bit_or", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bit_position", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"bit_xor", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bitstring", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"bitstring_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bool_and", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"bool_or", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"broadcast", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"can_cast_implicitly", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"cardinality", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"cbrt", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"ceil", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"ceiling", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"check_peg_parser", "autocomplete", CatalogType::TABLE_FUNCTION_ENTRY}, - {"chr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"corr", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"cos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"cosh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"cot", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"count_if", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"countif", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"covar_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"covar_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"create_fts_index", "fts", CatalogType::PRAGMA_FUNCTION_ENTRY}, - {"current_database", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"current_localtime", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"current_localtimestamp", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"current_query", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"current_schema", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"current_schemas", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"current_setting", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"damerau_levenshtein", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"dbgen", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, - {"decode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"degrees", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"delta_scan", "delta", CatalogType::TABLE_FUNCTION_ENTRY}, {"drop_fts_index", "fts", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"dsdgen", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, - {"editdist3", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"element_at", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"encode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"entropy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"enum_code", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"enum_first", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"enum_last", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"enum_range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"enum_range_boundary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"epoch_ms", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"epoch_ns", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"epoch_us", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"equi_width_bins", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"even", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"excel_text", "excel", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"exp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"factorial", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"family", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"favg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"flatten", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"floor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"format", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"format_bytes", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"formatreadabledecimalsize", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"formatreadablesize", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"from_base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"from_binary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"from_hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_json_strict", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"from_substrait", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, {"from_substrait_json", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, - {"fsum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"fuzz_all_functions", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, {"fuzzyduck", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, - {"gamma", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"gcd", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"gen_random_uuid", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"get_bit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"get_current_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"get_substrait", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, {"get_substrait_json", "substrait", CatalogType::TABLE_FUNCTION_ENTRY}, - {"grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"greatest", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"greatest_common_divisor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"group_concat", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"hamming", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"hash", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"histogram", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"histogram_exact", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"hnsw_compact_index", "vss", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"hnsw_index_scan", "vss", CatalogType::TABLE_FUNCTION_ENTRY}, {"host", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -341,15 +193,6 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"icu_collate_zh_tw", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"icu_collate_zu", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, {"icu_sort_key", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"in_search_path", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"instr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"is_histogram_other_bin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"isfinite", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"isinf", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"isnan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"jaccard", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"jaro_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"jaro_winkler_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json", "json", CatalogType::MACRO_ENTRY}, {"json_array", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_array_length", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -378,107 +221,27 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"json_type", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_valid", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, {"json_value", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"kahan_sum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"kurtosis", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"kurtosis_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"lcm", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"least", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"least_common_multiple", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"left", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"left_grapheme", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"levenshtein", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"lgamma", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"list_aggr", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_aggregate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_apply", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_cosine_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_cosine_similarity", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_distance", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_distinct", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_filter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_grade_up", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_has_all", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_has_any", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_negative_dot_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_negative_inner_product", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_pack", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_reverse_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_slice", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_sort", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_transform", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_unique", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"list_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"listagg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"ln", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"load_aws_credentials", "aws", CatalogType::TABLE_FUNCTION_ENTRY}, - {"log", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"log10", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"log2", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"lpad", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"ltrim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"mad", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"make_date", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"make_time", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"make_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"make_timestamp_ns", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"make_timestamptz", "icu", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_concat", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_entries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_extract", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_from_entries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_keys", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"map_values", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"max_by", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"mean", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"median", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"min_by", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"mismatches", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"mode", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"mysql_clear_cache", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"mysql_execute", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"mysql_query", "mysql_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, - {"nanosecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"netmask", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, {"network", "inet", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"nextafter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"normalized_interval", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"now", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"ord", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"parquet_bloom_probe", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_file_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_kv_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_metadata", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_scan", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, {"parquet_schema", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, - {"parse_dirname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"parse_dirpath", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"parse_filename", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"parse_path", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"pg_clear_cache", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"pg_timezone_names", "icu", CatalogType::TABLE_FUNCTION_ENTRY}, - {"pi", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"position", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"postgres_attach", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_execute", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_query", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_scan", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"postgres_scan_pushdown", "postgres_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, - {"pow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"power", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"pragma_hnsw_index_info", "vss", CatalogType::TABLE_FUNCTION_ENTRY}, {"pragma_rtree_index_info", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, - {"printf", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"product", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"quantile_cont", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"quantile_disc", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"radians", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"random", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"read_json", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_json_auto", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_json_objects", "json", CatalogType::TABLE_FUNCTION_ENTRY}, @@ -487,45 +250,16 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"read_ndjson_auto", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_ndjson_objects", "json", CatalogType::TABLE_FUNCTION_ENTRY}, {"read_parquet", "parquet", CatalogType::TABLE_FUNCTION_ENTRY}, - {"read_xlsx", "excel", CatalogType::TABLE_FUNCTION_ENTRY}, - {"reduce", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"reduce_sql_statement", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, - {"regr_avgx", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_avgy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_count", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_intercept", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_r2", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_slope", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_sxx", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_sxy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"regr_syy", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"repeat", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"replace", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"reservoir_quantile", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"reverse", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"right", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"right_grapheme", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"round", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"row_to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"rpad", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"rtree_index_dump", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, {"rtree_index_scan", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, - {"rtrim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"scan_arrow_ipc", "arrow", CatalogType::TABLE_FUNCTION_ENTRY}, - {"sem", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"set_bit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"setseed", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"shapefile_meta", "spatial", CatalogType::TABLE_FUNCTION_ENTRY}, - {"sign", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"signbit", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"sin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"sinh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"skewness", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"sql_auto_complete", "autocomplete", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlite_attach", "sqlite_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlite_scan", "sqlite_scanner", CatalogType::TABLE_FUNCTION_ENTRY}, {"sqlsmith", "sqlsmith", CatalogType::TABLE_FUNCTION_ENTRY}, - {"sqrt", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_area", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_area_spheroid", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_asgeojson", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, @@ -645,284 +379,20 @@ static constexpr ExtensionFunctionEntry EXTENSION_FUNCTIONS[] = { {"st_zmax", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_zmflag", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, {"st_zmin", "spatial", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"starts_with", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"stats", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"stddev", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"stddev_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"stddev_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, {"stem", "fts", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"string_agg", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"strpos", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"struct_insert", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"sum", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"sum_no_overflow", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"sumkahan", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"tan", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"tanh", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"text", "excel", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"timetz_byte_comparable", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"to_arrow_ipc", "arrow", CatalogType::TABLE_FUNCTION_ENTRY}, - {"to_base", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_base64", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_binary", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_centuries", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_days", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_decades", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_hex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_hours", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"to_json", "json", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_microseconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_millennia", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_milliseconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_minutes", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_months", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_quarters", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_seconds", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_weeks", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"to_years", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"tpcds", "tpcds", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"tpcds_answers", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpcds_queries", "tpcds", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpch", "tpch", CatalogType::PRAGMA_FUNCTION_ENTRY}, {"tpch_answers", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, {"tpch_queries", "tpch", CatalogType::TABLE_FUNCTION_ENTRY}, - {"transaction_timestamp", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"translate", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"trim", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"txid_current", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"typeof", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"unbin", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"unhex", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"unicode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"union_extract", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"union_tag", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"union_value", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"unpivot_list", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"url_decode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"url_encode", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"uuid", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"var_pop", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"var_samp", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"variance", "core_functions", CatalogType::AGGREGATE_FUNCTION_ENTRY}, - {"vector_type", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"version", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, {"vss_join", "vss", CatalogType::TABLE_MACRO_ENTRY}, {"vss_match", "vss", CatalogType::TABLE_MACRO_ENTRY}, - {"xor", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"|", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, - {"~", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY}, }; // END_OF_EXTENSION_FUNCTIONS -static constexpr ExtensionFunctionOverloadEntry EXTENSION_FUNCTION_OVERLOADS[] = { - {"age", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>INTERVAL"}, - {"age", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP,TIMESTAMP>INTERVAL"}, - {"age", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>INTERVAL"}, - {"age", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ>INTERVAL"}, - {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"century", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"century", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, - {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, - {"date_diff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, - {"date_diff", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>BIGINT"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],DATE>STRUCT()"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],INTERVAL>STRUCT()"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIME>STRUCT()"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMP>STRUCT()"}, - {"date_part", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMETZ>STRUCT()"}, - {"date_part", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>BIGINT"}, - {"date_part", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMPTZ>STRUCT()"}, - {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, - {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, - {"date_sub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, - {"date_sub", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, - {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>TIMESTAMP"}, - {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>INTERVAL"}, - {"date_trunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMP"}, - {"date_trunc", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMPTZ"}, - {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, - {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, - {"datediff", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, - {"datediff", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>BIGINT"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],DATE>STRUCT()"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],INTERVAL>STRUCT()"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIME>STRUCT()"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMP>STRUCT()"}, - {"datepart", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMETZ>STRUCT()"}, - {"datepart", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>BIGINT"}, - {"datepart", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR[],TIMESTAMPTZ>STRUCT()"}, - {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE,DATE>BIGINT"}, - {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIME,TIME>BIGINT"}, - {"datesub", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP,TIMESTAMP>BIGINT"}, - {"datesub", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ,TIMESTAMPTZ>BIGINT"}, - {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,DATE>TIMESTAMP"}, - {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,INTERVAL>INTERVAL"}, - {"datetrunc", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMP"}, - {"datetrunc", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMPTZ"}, - {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"day", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"dayname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>VARCHAR"}, - {"dayname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>VARCHAR"}, - {"dayname", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>VARCHAR"}, - {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"dayofmonth", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"dayofmonth", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"dayofweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"dayofweek", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"dayofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"dayofyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"decade", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"decade", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DOUBLE"}, - {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>DOUBLE"}, - {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>DOUBLE"}, - {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DOUBLE"}, - {"epoch", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>DOUBLE"}, - {"epoch", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DOUBLE"}, - {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"era", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"era", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT>BIGINT[]"}, - {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT>BIGINT[]"}, - {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT,BIGINT>BIGINT[]"}, - {"generate_series", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, - "TIMESTAMP,TIMESTAMP,INTERVAL>TIMESTAMP[]"}, - {"generate_series", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ[]"}, - {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, - {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, - {"hour", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"isodow", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"isodow", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"isoyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"isoyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"julian", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DOUBLE"}, - {"julian", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DOUBLE"}, - {"julian", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DOUBLE"}, - {"last_day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>DATE"}, - {"last_day", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>DATE"}, - {"last_day", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>DATE"}, - {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, - {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"microsecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, - {"microsecond", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"millennium", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"millennium", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, - {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"millisecond", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, - {"millisecond", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, - {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, - {"minute", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"month", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"month", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"monthname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>VARCHAR"}, - {"monthname", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>VARCHAR"}, - {"monthname", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>VARCHAR"}, - {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"quarter", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"quarter", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT>BIGINT[]"}, - {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT>BIGINT[]"}, - {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "BIGINT,BIGINT,BIGINT>BIGINT[]"}, - {"range", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP,TIMESTAMP,INTERVAL>TIMESTAMP[]"}, - {"range", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ[]"}, - {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIME>BIGINT"}, - {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"second", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMETZ>BIGINT"}, - {"second", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE>DATE"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE,DATE>DATE"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,DATE,INTERVAL>DATE"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP>TIMESTAMP"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP,INTERVAL>TIMESTAMP"}, - {"time_bucket", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMP,TIMESTAMP>TIMESTAMP"}, - {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ>TIMESTAMPTZ"}, - {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,INTERVAL>TIMESTAMPTZ"}, - {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,TIMESTAMPTZ>TIMESTAMPTZ"}, - {"time_bucket", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMESTAMPTZ,VARCHAR>TIMESTAMPTZ"}, - {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL,TIMETZ>TIMETZ"}, - {"timezone", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMP>TIMESTAMPTZ"}, - {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMESTAMPTZ>TIMESTAMP"}, - {"timezone", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "VARCHAR,TIMETZ>TIMETZ"}, - {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"timezone_hour", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"timezone_hour", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"timezone_minute", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"timezone_minute", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"week", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"week", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"weekday", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"weekday", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"weekofyear", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"weekofyear", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"year", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"year", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, - {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "DATE>BIGINT"}, - {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "INTERVAL>BIGINT"}, - {"yearweek", "core_functions", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMP>BIGINT"}, - {"yearweek", "icu", CatalogType::SCALAR_FUNCTION_ENTRY, "TIMESTAMPTZ>BIGINT"}, -}; // END_OF_EXTENSION_FUNCTION_OVERLOADS - static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"azure_account_name", "azure"}, {"azure_context_caching", "azure"}, @@ -940,7 +410,6 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"binary_as_string", "parquet"}, {"ca_cert_file", "httpfs"}, {"calendar", "icu"}, - {"disable_parquet_prefetching", "parquet"}, {"enable_geoparquet_conversion", "parquet"}, {"enable_server_cert_verification", "httpfs"}, {"force_download", "httpfs"}, @@ -956,7 +425,6 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"mysql_debug_show_queries", "mysql_scanner"}, {"mysql_experimental_filter_pushdown", "mysql_scanner"}, {"mysql_tinyint1_as_boolean", "mysql_scanner"}, - {"parquet_metadata_cache", "parquet"}, {"pg_array_as_varchar", "postgres_scanner"}, {"pg_connection_cache", "postgres_scanner"}, {"pg_connection_limit", "postgres_scanner"}, @@ -966,7 +434,6 @@ static constexpr ExtensionEntry EXTENSION_SETTINGS[] = { {"pg_pages_per_task", "postgres_scanner"}, {"pg_use_binary_copy", "postgres_scanner"}, {"pg_use_ctid_scan", "postgres_scanner"}, - {"prefetch_all_parquet_files", "parquet"}, {"s3_access_key_id", "httpfs"}, {"s3_endpoint", "httpfs"}, {"s3_region", "httpfs"}, @@ -1028,9 +495,8 @@ static constexpr ExtensionEntry EXTENSION_FILE_PREFIXES[] = { // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb static constexpr ExtensionEntry EXTENSION_FILE_POSTFIXES[] = { - {".parquet", "parquet"}, {".json", "json"}, {".jsonl", "json"}, {".ndjson", "json"}, - {".shp", "spatial"}, {".gpkg", "spatial"}, {".fgb", "spatial"}, {".xlsx", "excel"}, -}; // END_OF_EXTENSION_FILE_POSTFIXES + {".parquet", "parquet"}, {".json", "json"}, {".jsonl", "json"}, {".ndjson", "json"}, + {".shp", "spatial"}, {".gpkg", "spatial"}, {".fgb", "spatial"}}; // END_OF_EXTENSION_FILE_POSTFIXES // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb @@ -1042,10 +508,8 @@ static constexpr ExtensionEntry EXTENSION_FILE_CONTAINS[] = {{".parquet?", "parq // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb static constexpr ExtensionEntry EXTENSION_SECRET_TYPES[] = { - {"s3", "httpfs"}, {"r2", "httpfs"}, - {"gcs", "httpfs"}, {"azure", "azure"}, - {"huggingface", "httpfs"}, {"bearer", "httpfs"}, - {"mysql", "mysql_scanner"}, {"postgres", "postgres_scanner"}}; // EXTENSION_SECRET_TYPES + {"s3", "httpfs"}, {"r2", "httpfs"}, {"gcs", "httpfs"}, + {"azure", "azure"}, {"huggingface", "httpfs"}, {"bearer", "httpfs"}}; // EXTENSION_SECRET_TYPES // Note: these are currently hardcoded in scripts/generate_extensions_function.py // TODO: automate by passing though to script via duckdb @@ -1062,13 +526,11 @@ static constexpr ExtensionEntry EXTENSION_SECRET_PROVIDERS[] = { {"azure/service_principal", "azure"}, {"huggingface/config", "httfps"}, {"huggingface/credential_chain", "httpfs"}, - {"bearer/config", "httpfs"}, - {"mysql/config", "mysql_scanner"}, - {"postgres/config", "postgres_scanner"}}; // EXTENSION_SECRET_PROVIDERS + {"bearer/config", "httpfs"}}; // EXTENSION_SECRET_PROVIDERS static constexpr const char *AUTOLOADABLE_EXTENSIONS[] = { - "aws", "azure", "autocomplete", "core_functions", "delta", "excel", "fts", "httpfs", - "inet", "icu", "json", "mysql_scanner", "parquet", "sqlite_scanner", "sqlsmith", "postgres_scanner", + "aws", "azure", "autocomplete", "delta", "excel", "fts", "httpfs", + "inet", "icu", "json", "parquet", "sqlite_scanner", "sqlsmith", "postgres_scanner", "tpcds", "tpch"}; // END_OF_AUTOLOADABLE_EXTENSIONS } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/extension_helper.hpp b/src/duckdb/src/include/duckdb/main/extension_helper.hpp index 7a7c3ed9e..22b0e1b25 100644 --- a/src/duckdb/src/include/duckdb/main/extension_helper.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_helper.hpp @@ -35,7 +35,6 @@ struct ExtensionAlias { struct ExtensionInitResult { string filename; string filebase; - ExtensionABIType abi_type = ExtensionABIType::UNKNOWN; // The deserialized install from the `.duckdb_extension.info` file unique_ptr install_info; @@ -123,10 +122,6 @@ class ExtensionHelper { static string ExtensionDirectory(ClientContext &context); static string ExtensionDirectory(DatabaseInstance &db, FileSystem &fs); - // Get the extension directory path - static string GetExtensionDirectoryPath(ClientContext &context); - static string GetExtensionDirectoryPath(DatabaseInstance &db, FileSystem &fs); - static bool CheckExtensionSignature(FileHandle &handle, ParsedExtensionMetaData &parsed_metadata, const bool allow_community_extensions); static ParsedExtensionMetaData ParseExtensionMetaData(const char *metadata) noexcept; @@ -178,19 +173,6 @@ class ExtensionHelper { return result; } - template - static idx_t ArraySize(const ExtensionEntry (&entries)[N]) { - return N; - } - - template - static const ExtensionEntry *GetArrayEntry(const ExtensionEntry (&entries)[N], idx_t entry) { - if (entry >= N) { - return nullptr; - } - return entries + entry; - } - //! Lookup a name in an ExtensionEntry list template static string FindExtensionInEntries(const string &name, const ExtensionEntry (&entries)[N]) { diff --git a/src/duckdb/src/include/duckdb/main/extension_util.hpp b/src/duckdb/src/include/duckdb/main/extension_util.hpp index 598320b82..f91ad2277 100644 --- a/src/duckdb/src/include/duckdb/main/extension_util.hpp +++ b/src/duckdb/src/include/duckdb/main/extension_util.hpp @@ -18,9 +18,6 @@ namespace duckdb { struct CreateMacroInfo; struct CreateCollationInfo; -struct CreateAggregateFunctionInfo; -struct CreateScalarFunctionInfo; -struct CreateTableFunctionInfo; class DatabaseInstance; //! The ExtensionUtil class contains methods that are useful for extensions @@ -28,18 +25,18 @@ class ExtensionUtil { public: //! Register a new DuckDB extension DUCKDB_API static void RegisterExtension(DatabaseInstance &db, const string &name, const ExtensionLoadedInfo &info); - //! Register a new scalar function - merge overloads if the function already exists + //! Register a new scalar function - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, ScalarFunction function); + //! Register a new scalar function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, ScalarFunctionSet function); - DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateScalarFunctionInfo info); - //! Register a new aggregate function - merge overloads if the function already exists + //! Register a new aggregate function - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, AggregateFunction function); + //! Register a new aggregate function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, AggregateFunctionSet function); - DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateAggregateFunctionInfo info); - //! Register a new table function - merge overloads if the function already exists + //! Register a new table function - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, TableFunction function); + //! Register a new table function set - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, TableFunctionSet function); - DUCKDB_API static void RegisterFunction(DatabaseInstance &db, CreateTableFunctionInfo info); //! Register a new pragma function - throw an exception if the function already exists DUCKDB_API static void RegisterFunction(DatabaseInstance &db, PragmaFunction function); //! Register a new pragma function set - throw an exception if the function already exists @@ -59,8 +56,6 @@ class ExtensionUtil { //! Returns a reference to the function in the catalog - throws an exception if it does not exist DUCKDB_API static ScalarFunctionCatalogEntry &GetFunction(DatabaseInstance &db, const string &name); DUCKDB_API static TableFunctionCatalogEntry &GetTableFunction(DatabaseInstance &db, const string &name); - DUCKDB_API static optional_ptr TryGetFunction(DatabaseInstance &db, const string &name); - DUCKDB_API static optional_ptr TryGetTableFunction(DatabaseInstance &db, const string &name); //! Add a function overload DUCKDB_API static void AddFunctionOverload(DatabaseInstance &db, ScalarFunction function); @@ -69,7 +64,7 @@ class ExtensionUtil { //! Registers a new type DUCKDB_API static void RegisterType(DatabaseInstance &db, string type_name, LogicalType type, - bind_logical_type_function_t bind_function = nullptr); + bind_type_modifiers_function_t bind_type_modifiers = nullptr); //! Registers a new secret type DUCKDB_API static void RegisterSecretType(DatabaseInstance &db, SecretType secret_type); diff --git a/src/duckdb/src/include/duckdb/main/prepared_statement.hpp b/src/duckdb/src/include/duckdb/main/prepared_statement.hpp index a391f6ac4..ed3e5364c 100644 --- a/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +++ b/src/duckdb/src/include/duckdb/main/prepared_statement.hpp @@ -94,7 +94,7 @@ class PreparedStatement { template static string ExcessValuesException(const case_insensitive_map_t ¶meters, - const case_insensitive_map_t &values) { + case_insensitive_map_t &values) { // Too many values set excess_set; for (auto &pair : values) { @@ -113,7 +113,7 @@ class PreparedStatement { template static string MissingValuesException(const case_insensitive_map_t ¶meters, - const case_insensitive_map_t &values) { + case_insensitive_map_t &values) { // Missing values set missing_set; for (auto &pair : parameters) { @@ -131,7 +131,7 @@ class PreparedStatement { } template - static void VerifyParameters(const case_insensitive_map_t &provided, + static void VerifyParameters(case_insensitive_map_t &provided, const case_insensitive_map_t &expected) { if (expected.size() == provided.size()) { // Same amount of identifiers, if diff --git a/src/duckdb/src/include/duckdb/main/profiling_info.hpp b/src/duckdb/src/include/duckdb/main/profiling_info.hpp index a57166153..5e9ee287b 100644 --- a/src/duckdb/src/include/duckdb/main/profiling_info.hpp +++ b/src/duckdb/src/include/duckdb/main/profiling_info.hpp @@ -60,8 +60,8 @@ class ProfilingInfo { public: template - METRIC_TYPE GetMetricValue(const MetricsType type) const { - auto val = metrics.at(type); + METRIC_TYPE GetMetricValue(const MetricsType setting) const { + auto val = metrics.at(setting); return val.GetValue(); } diff --git a/src/duckdb/src/include/duckdb/main/query_profiler.hpp b/src/duckdb/src/include/duckdb/main/query_profiler.hpp index 1de54e9a1..240729122 100644 --- a/src/duckdb/src/include/duckdb/main/query_profiler.hpp +++ b/src/duckdb/src/include/duckdb/main/query_profiler.hpp @@ -43,7 +43,6 @@ struct OperatorInformation { idx_t elements_returned; idx_t result_set_size; string name; - InsertionOrderPreservingMap extra_info; void AddTime(double n_time) { time += n_time; @@ -89,8 +88,8 @@ class OperatorProfiler { Profiler op; //! The stack of Physical Operators that are currently active optional_ptr active_operator; - //! A mapping of physical operators to profiled operator information. - reference_map_t operator_infos; + //! A mapping of physical operators to recorded timings + reference_map_t timings; }; struct QueryInfo { @@ -114,7 +113,6 @@ class QueryProfiler { unique_ptr CreateTree(const PhysicalOperator &root, const profiler_settings_t &settings, const idx_t depth = 0); void Render(const ProfilingNode &node, std::ostream &str) const; - string RenderDisabledMessage(ProfilerPrintFormat format) const; public: DUCKDB_API bool IsEnabled() const; @@ -147,7 +145,6 @@ class QueryProfiler { //! return the printed as a string. Unlike ToString, which is always formatted as a string, //! the return value is formatted based on the current print format (see GetPrintFormat()). DUCKDB_API string ToString(ExplainFormat format = ExplainFormat::DEFAULT) const; - DUCKDB_API string ToString(ProfilerPrintFormat format) const; static InsertionOrderPreservingMap JSONSanitize(const InsertionOrderPreservingMap &input); static string JSONSanitize(const string &text); @@ -171,8 +168,8 @@ class QueryProfiler { //! Whether or not the query profiler is running bool running; - //! The lock used for accessing the global query profiler or flushing information to it from a thread - mutable std::mutex lock; + //! The lock used for flushing information from a thread into the global query profiler + mutex flush_lock; //! Whether or not the query requires profiling bool query_requires_profiling; @@ -210,7 +207,6 @@ class QueryProfiler { //! Check whether or not an operator type requires query profiling. If none of the ops in a query require profiling //! no profiling information is output. bool OperatorRequiresProfiling(PhysicalOperatorType op_type); - ExplainFormat GetExplainFormat(ProfilerPrintFormat format) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/relation.hpp b/src/duckdb/src/include/duckdb/main/relation.hpp index 37b137aae..18b125a32 100644 --- a/src/duckdb/src/include/duckdb/main/relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation.hpp @@ -34,46 +34,17 @@ class LogicalOperator; class QueryNode; class TableRef; -static string CreateRelationAlias(RelationType type, const string &alias) { - if (!alias.empty()) { - return alias; - } - return StringUtil::Format("%s_%s", EnumUtil::ToString(type), StringUtil::GenerateRandomName()); -} - -class RelationContextWrapper : public ClientContextWrapper { -public: - ~RelationContextWrapper() override = default; - explicit RelationContextWrapper(const shared_ptr &context) : ClientContextWrapper(context) {}; - - explicit RelationContextWrapper(const ClientContextWrapper &context) : ClientContextWrapper(context) {}; - - void TryBindRelation(Relation &relation, vector &columns) override { - GetContext()->InternalTryBindRelation(relation, columns); - } - -private: - weak_ptr client_context; -}; - class Relation : public enable_shared_from_this { public: - Relation(const shared_ptr &context_p, const RelationType type) : type(type) { - context = make_shared_ptr(context_p); + Relation(const shared_ptr &context, RelationType type) : context(context), type(type) { } - Relation(const shared_ptr &context, RelationType type, const string &alias_p = "") - : context(context), type(type), alias(CreateRelationAlias(type, alias_p)) { + Relation(ClientContextWrapper &context, RelationType type) : context(context.GetContext()), type(type) { } - - Relation(const shared_ptr &context, RelationType type, const string &alias_p = "") - : context(context), type(type), alias(CreateRelationAlias(type, alias_p)) { + virtual ~Relation() { } - virtual ~Relation() = default; - - shared_ptr context; + ClientContextWrapper context; RelationType type; - const string alias; vector> external_dependencies; public: @@ -93,7 +64,7 @@ class Relation : public enable_shared_from_this { DUCKDB_API shared_ptr CreateView(const string &name, bool replace = true, bool temporary = false); DUCKDB_API shared_ptr CreateView(const string &schema_name, const string &name, bool replace = true, bool temporary = false); - DUCKDB_API unique_ptr Query(const string &sql) const; + DUCKDB_API unique_ptr Query(const string &sql); DUCKDB_API unique_ptr Query(const string &name, const string &sql); //! Explain the query plan of this relation @@ -104,7 +75,6 @@ class Relation : public enable_shared_from_this { virtual bool IsReadOnly() { return true; } - DUCKDB_API void TryBindRelation(vector &columns); public: // PROJECT @@ -165,15 +135,11 @@ class Relation : public enable_shared_from_this { DUCKDB_API void Insert(const string &schema_name, const string &table_name); //! Insert a row (i.e.,list of values) into a table DUCKDB_API void Insert(const vector> &values); - DUCKDB_API void Insert(vector>> &&expressions); //! Create a table and insert the data from this relation into that table DUCKDB_API shared_ptr CreateRel(const string &schema_name, const string &table_name, - bool temporary = false, - OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT); - DUCKDB_API void Create(const string &table_name, bool temporary = false, - OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT); - DUCKDB_API void Create(const string &schema_name, const string &table_name, bool temporary = false, - OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT); + bool temporary = false); + DUCKDB_API void Create(const string &table_name, bool temporary = false); + DUCKDB_API void Create(const string &schema_name, const string &table_name, bool temporary = false); //! Write a relation to a CSV file DUCKDB_API shared_ptr @@ -191,8 +157,6 @@ class Relation : public enable_shared_from_this { //! Update a table, can only be used on a TableRelation DUCKDB_API virtual void Update(const string &update, const string &condition = string()); - DUCKDB_API virtual void Update(vector column_names, vector> &&update, - unique_ptr condition = nullptr); //! Delete from a table, can only be used on a TableRelation DUCKDB_API virtual void Delete(const string &condition = string()); //! Create a relation from calling a table in/out function on the input relation @@ -213,7 +177,7 @@ class Relation : public enable_shared_from_this { DUCKDB_API vector> GetAllDependencies(); protected: - DUCKDB_API static string RenderWhitespace(idx_t depth); + DUCKDB_API string RenderWhitespace(idx_t depth); public: template diff --git a/src/duckdb/src/include/duckdb/main/relation/create_table_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/create_table_relation.hpp index 7d5462941..54686dd34 100644 --- a/src/duckdb/src/include/duckdb/main/relation/create_table_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/create_table_relation.hpp @@ -14,15 +14,13 @@ namespace duckdb { class CreateTableRelation : public Relation { public: - CreateTableRelation(shared_ptr child, string schema_name, string table_name, bool temporary, - OnCreateConflict on_conflict); + CreateTableRelation(shared_ptr child, string schema_name, string table_name, bool temporary); shared_ptr child; string schema_name; string table_name; vector columns; bool temporary; - OnCreateConflict on_conflict; public: BoundStatement Bind(Binder &binder) override; diff --git a/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp index d72a48bd4..2e0c6564c 100644 --- a/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/delete_relation.hpp @@ -15,8 +15,8 @@ namespace duckdb { class DeleteRelation : public Relation { public: - DeleteRelation(shared_ptr &context, unique_ptr condition, - string schema_name, string table_name); + DeleteRelation(ClientContextWrapper &context, unique_ptr condition, string schema_name, + string table_name); vector columns; unique_ptr condition; diff --git a/src/duckdb/src/include/duckdb/main/relation/subquery_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/subquery_relation.hpp index 0c9c9e50d..16e9b7a8f 100644 --- a/src/duckdb/src/include/duckdb/main/relation/subquery_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/subquery_relation.hpp @@ -14,14 +14,17 @@ namespace duckdb { class SubqueryRelation : public Relation { public: - SubqueryRelation(shared_ptr child, const string &alias); + SubqueryRelation(shared_ptr child, string alias); + shared_ptr child; + string alias; public: unique_ptr GetQueryNode() override; const vector &Columns() override; string ToString(idx_t depth) override; + string GetAlias() override; public: bool InheritsColumnBindings() override { diff --git a/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp index 8781d7125..3a2208d03 100644 --- a/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/table_function_relation.hpp @@ -17,9 +17,7 @@ class TableFunctionRelation : public Relation { TableFunctionRelation(const shared_ptr &context, string name, vector parameters, named_parameter_map_t named_parameters, shared_ptr input_relation_p = nullptr, bool auto_init = true); - TableFunctionRelation(const shared_ptr &context, string name, vector parameters, - named_parameter_map_t named_parameters, shared_ptr input_relation_p = nullptr, - bool auto_init = true); + TableFunctionRelation(const shared_ptr &context, string name, vector parameters, shared_ptr input_relation_p = nullptr, bool auto_init = true); ~TableFunctionRelation() override { diff --git a/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp index 9c2fddcec..a14ce054b 100644 --- a/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/table_relation.hpp @@ -16,7 +16,6 @@ namespace duckdb { class TableRelation : public Relation { public: TableRelation(const shared_ptr &context, unique_ptr description); - TableRelation(const shared_ptr &context, unique_ptr description); unique_ptr description; @@ -30,8 +29,6 @@ class TableRelation : public Relation { unique_ptr GetTableRef() override; void Update(const string &update, const string &condition = string()) override; - void Update(vector column_names, vector> &&update, - unique_ptr condition = nullptr) override; void Delete(const string &condition = string()) override; }; diff --git a/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp index f46739dde..1cb142222 100644 --- a/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/update_relation.hpp @@ -15,9 +15,8 @@ namespace duckdb { class UpdateRelation : public Relation { public: - UpdateRelation(shared_ptr &context, unique_ptr condition, - string schema_name, string table_name, vector update_columns, - vector> expressions); + UpdateRelation(ClientContextWrapper &context, unique_ptr condition, string schema_name, + string table_name, vector update_columns, vector> expressions); vector columns; unique_ptr condition; diff --git a/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp index 9b5ae5257..81fb8c4e1 100644 --- a/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/value_relation.hpp @@ -17,13 +17,6 @@ class ValueRelation : public Relation { public: ValueRelation(const shared_ptr &context, const vector> &values, vector names, string alias = "values"); - ValueRelation(const shared_ptr &context, vector>> &&expressions, - vector names, string alias = "values"); - ValueRelation(const shared_ptr &context, const vector> &values, - vector names, string alias = "values"); - ValueRelation(const shared_ptr &context, - vector>> &&expressions, vector names, - string alias = "values"); ValueRelation(const shared_ptr &context, const string &values, vector names, string alias = "values"); diff --git a/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp index 529817d60..78f72d786 100644 --- a/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/view_relation.hpp @@ -15,7 +15,6 @@ namespace duckdb { class ViewRelation : public Relation { public: ViewRelation(const shared_ptr &context, string schema_name, string view_name); - ViewRelation(const shared_ptr &context, string schema_name, string view_name); ViewRelation(const shared_ptr &context, unique_ptr ref, const string &view_name); string schema_name; diff --git a/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp b/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp index d32089212..c67da3e20 100644 --- a/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp +++ b/src/duckdb/src/include/duckdb/main/relation/write_parquet_relation.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/main/relation/write_parquet_relation.hpp +// duckdb/main/relation/write_csv_relation.hpp // // //===----------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/main/secret/secret_storage.hpp b/src/duckdb/src/include/duckdb/main/secret/secret_storage.hpp index 5649411d8..91e059e3c 100644 --- a/src/duckdb/src/include/duckdb/main/secret/secret_storage.hpp +++ b/src/duckdb/src/include/duckdb/main/secret/secret_storage.hpp @@ -8,13 +8,8 @@ #pragma once -#include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_set.hpp" #include "duckdb/common/common.hpp" -#include "duckdb/common/enums/on_create_conflict.hpp" #include "duckdb/common/enums/on_entry_not_found.hpp" -#include "duckdb/common/optional_ptr.hpp" -#include "duckdb/common/case_insensitive_map.hpp" namespace duckdb { @@ -25,21 +20,15 @@ struct CatalogTransaction; class DatabaseInstance; struct SecretMatch; struct SecretEntry; -class SecretManager; //! Base class for SecretStorage API class SecretStorage { friend class SecretManager; public: - explicit SecretStorage(const string &name, const int64_t tie_break_offset) - : storage_name(name), tie_break_offset(tie_break_offset), persistent(false) {}; + explicit SecretStorage(const string &name) : storage_name(name), persistent(false) {}; virtual ~SecretStorage() = default; - //! Default storage backend offsets - static const int64_t TEMPORARY_STORAGE_OFFSET = 10; - static const int64_t LOCAL_FILE_STORAGE_OFFSET = 20; - public: //! SecretStorage API @@ -63,6 +52,9 @@ class SecretStorage { virtual unique_ptr GetSecretByName(const string &name, optional_ptr transaction = nullptr) = 0; + //! Return the offset associated to this storage for tie-breaking secrets between storages + virtual int64_t GetTieBreakOffset() = 0; + //! Returns include_in_lookups, used to create secret storage virtual bool IncludeInLookups() { return true; @@ -75,13 +67,16 @@ class SecretStorage { protected: //! Helper function to select the best matching secret within a storage. Tie-breaks within a storage are broken //! by secret name by default. - static SecretMatch SelectBestMatch(SecretEntry &secret_entry, const string &path, int64_t offset, - SecretMatch ¤t_best); + SecretMatch SelectBestMatch(SecretEntry &secret_entry, const string &path, SecretMatch ¤t_best); + + //! Offsets the score to tie-break secrets giving preference to the storage with the lowest storage_penalty + //! the base implementation will be chosen last in a tie-break + int64_t OffsetMatchScore(int64_t score) { + return 100 * score - GetTieBreakOffset(); + } //! Name of the storage backend (e.g. temporary, file, etc) string storage_name; - //! Offset associated to this storage for tie-breaking secrets between storages - const int64_t tie_break_offset; //! Whether entries in this storage will survive duckdb reboots bool persistent; }; @@ -99,8 +94,8 @@ struct SecretCatalogEntry : public InCatalogEntry { //! Base Implementation for catalog set based secret storage class CatalogSetSecretStorage : public SecretStorage { public: - CatalogSetSecretStorage(DatabaseInstance &db_instance, const string &name_p, const int64_t offset) - : SecretStorage(name_p, offset), db(db_instance) {}; + CatalogSetSecretStorage(DatabaseInstance &db_instance, const string &name_p) + : SecretStorage(name_p), db(db_instance) {}; public: //! SecretStorage API @@ -133,12 +128,15 @@ class CatalogSetSecretStorage : public SecretStorage { class TemporarySecretStorage : public CatalogSetSecretStorage { public: - TemporarySecretStorage(const string &name_p, DatabaseInstance &db_p) - : CatalogSetSecretStorage(db_p, name_p, TEMPORARY_STORAGE_OFFSET) { + TemporarySecretStorage(const string &name_p, DatabaseInstance &db_p) : CatalogSetSecretStorage(db_p, name_p) { secrets = make_uniq(Catalog::GetSystemCatalog(db)); persistent = false; } + int64_t GetTieBreakOffset() override { + return 10; + } + protected: }; @@ -147,6 +145,10 @@ class LocalFileSecretStorage : public CatalogSetSecretStorage { LocalFileSecretStorage(SecretManager &manager, DatabaseInstance &db, const string &name_p, const string &secret_path); + int64_t GetTieBreakOffset() override { + return 20; + } + protected: //! Implements the writes to disk void WriteSecret(const BaseSecret &secret, OnCreateConflict on_conflict) override; diff --git a/src/duckdb/src/include/duckdb/main/settings.hpp b/src/duckdb/src/include/duckdb/main/settings.hpp index 4e89c3416..f3f7ab6df 100644 --- a/src/duckdb/src/include/duckdb/main/settings.hpp +++ b/src/duckdb/src/include/duckdb/main/settings.hpp @@ -10,7 +10,6 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/types/value.hpp" -#include "duckdb/main/config.hpp" namespace duckdb { class ClientContext; @@ -53,1069 +52,906 @@ struct SettingLookupResult { SettingScope scope = SettingScope::INVALID; }; -//===----------------------------------------------------------------------===// -// This code is autogenerated from 'update_settings_header_file.py'. -// Please do not make any changes directly here, as they will be overwritten. -// -// Start of the auto-generated list of settings structures -//===----------------------------------------------------------------------===// - struct AccessModeSetting { - using RETURN_TYPE = AccessMode; static constexpr const char *Name = "access_mode"; static constexpr const char *Description = "Access mode of the database (AUTOMATIC, READ_ONLY or READ_WRITE)"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); static Value GetSetting(const ClientContext &context); }; -struct AllocatorBackgroundThreadsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allocator_background_threads"; - static constexpr const char *Description = "Whether to enable the allocator background thread."; - static constexpr const char *InputType = "BOOLEAN"; +struct AllowPersistentSecrets { + static constexpr const char *Name = "allow_persistent_secrets"; + static constexpr const char *Description = + "Allow the creation of persistent secrets, that are stored and loaded on restarts"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AllocatorBulkDeallocationFlushThresholdSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "allocator_bulk_deallocation_flush_threshold"; +struct CatalogErrorMaxSchema { + static constexpr const char *Name = "catalog_error_max_schemas"; static constexpr const char *Description = - "If a bulk deallocation larger than this occurs, flush outstanding allocations."; - static constexpr const char *InputType = "VARCHAR"; + "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AllocatorFlushThresholdSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "allocator_flush_threshold"; +struct CheckpointThresholdSetting { + static constexpr const char *Name = "checkpoint_threshold"; static constexpr const char *Description = - "Peak allocation threshold at which to flush the allocator after completing a task."; - static constexpr const char *InputType = "VARCHAR"; + "The WAL size threshold at which to automatically trigger a checkpoint (e.g. 1GB)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AllowCommunityExtensionsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allow_community_extensions"; - static constexpr const char *Description = "Allow to load community built extensions"; - static constexpr const char *InputType = "BOOLEAN"; +struct DebugCheckpointAbort { + static constexpr const char *Name = "debug_checkpoint_abort"; + static constexpr const char *Description = + "DEBUG SETTING: trigger an abort while checkpointing for testing purposes"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AllowExtensionsMetadataMismatchSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allow_extensions_metadata_mismatch"; - static constexpr const char *Description = "Allow to load extensions with not compatible metadata"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); +struct DebugForceExternal { + static constexpr const char *Name = "debug_force_external"; + static constexpr const char *Description = + "DEBUG SETTING: force out-of-core computation for operators that support it, used for testing"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct AllowPersistentSecretsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allow_persistent_secrets"; +struct DebugForceNoCrossProduct { + static constexpr const char *Name = "debug_force_no_cross_product"; static constexpr const char *Description = - "Allow the creation of persistent secrets, that are stored and loaded on restarts"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct AllowUnredactedSecretsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allow_unredacted_secrets"; - static constexpr const char *Description = "Allow printing unredacted secrets"; - static constexpr const char *InputType = "BOOLEAN"; +struct DebugSkipCheckpointOnCommit { + static constexpr const char *Name = "debug_skip_checkpoint_on_commit"; + static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AllowUnsignedExtensionsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "allow_unsigned_extensions"; - static constexpr const char *Description = "Allow to load extensions with invalid or missing signatures"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); +struct OrderedAggregateThreshold { + static constexpr const char *Name = "ordered_aggregate_threshold"; // NOLINT + static constexpr const char *Description = // NOLINT + "The number of rows to accumulate before sorting, used for tuning"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; // NOLINT + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct AllowedDirectoriesSetting { - using RETURN_TYPE = vector; - static constexpr const char *Name = "allowed_directories"; - static constexpr const char *Description = "List of directories/prefixes that are ALWAYS allowed to be queried - " - "even when enable_external_access is false"; - static constexpr const char *InputType = "VARCHAR[]"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); +struct DebugAsOfIEJoin { + static constexpr const char *Name = "debug_asof_iejoin"; // NOLINT + static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; // NOLINT + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; // NOLINT + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct AllowedPathsSetting { - using RETURN_TYPE = vector; - static constexpr const char *Name = "allowed_paths"; - static constexpr const char *Description = - "List of files that are ALWAYS allowed to be queried - even when enable_external_access is false"; - static constexpr const char *InputType = "VARCHAR[]"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); +struct PreferRangeJoins { + static constexpr const char *Name = "prefer_range_joins"; // NOLINT + static constexpr const char *Description = "Force use of range joins with mixed predicates"; // NOLINT + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; // NOLINT + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ArrowLargeBufferSizeSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "arrow_large_buffer_size"; - static constexpr const char *Description = - "Whether Arrow buffers for strings, blobs, uuids and bits should be exported using large buffers"; - static constexpr const char *InputType = "BOOLEAN"; +struct DebugWindowMode { + static constexpr const char *Name = "debug_window_mode"; + static constexpr const char *Description = "DEBUG SETTING: switch window mode to use"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct ArrowLosslessConversionSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "arrow_lossless_conversion"; - static constexpr const char *Description = - "Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types " - "with a duckdb.type_name extension name."; - static constexpr const char *InputType = "BOOLEAN"; +struct DefaultCollationSetting { + static constexpr const char *Name = "default_collation"; + static constexpr const char *Description = "The collation setting used when none is specified"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ArrowOutputListViewSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "arrow_output_list_view"; - static constexpr const char *Description = - "Whether export to Arrow format should use ListView as the physical layout for LIST columns"; - static constexpr const char *InputType = "BOOLEAN"; +struct DefaultOrderSetting { + static constexpr const char *Name = "default_order"; + static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AutoinstallExtensionRepositorySetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "autoinstall_extension_repository"; - static constexpr const char *Description = - "Overrides the custom endpoint for extension installation on autoloading"; - static constexpr const char *InputType = "VARCHAR"; +struct DefaultNullOrderSetting { + static constexpr const char *Name = "default_null_order"; + static constexpr const char *Description = "Null ordering used when none is specified (NULLS_FIRST or NULLS_LAST)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AutoinstallKnownExtensionsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "autoinstall_known_extensions"; - static constexpr const char *Description = - "Whether known extensions are allowed to be automatically installed when a query depends on them"; - static constexpr const char *InputType = "BOOLEAN"; +struct DefaultSecretStorage { + static constexpr const char *Name = "default_secret_storage"; + static constexpr const char *Description = "Allows switching the default storage for secrets"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct AutoloadKnownExtensionsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "autoload_known_extensions"; - static constexpr const char *Description = - "Whether known extensions are allowed to be automatically loaded when a query depends on them"; - static constexpr const char *InputType = "BOOLEAN"; +struct DisabledFileSystemsSetting { + static constexpr const char *Name = "disabled_filesystems"; + static constexpr const char *Description = "Disable specific file systems preventing access (e.g. LocalFileSystem)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct CatalogErrorMaxSchemasSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "catalog_error_max_schemas"; - static constexpr const char *Description = - "The maximum number of schemas the system will scan for \"did you mean...\" style errors in the catalog"; - static constexpr const char *InputType = "UBIGINT"; +struct DisabledOptimizersSetting { + static constexpr const char *Name = "disabled_optimizers"; + static constexpr const char *Description = "DEBUG SETTING: disable a specific set of optimizers (comma separated)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct CheckpointThresholdSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "checkpoint_threshold"; +struct EnableExternalAccessSetting { + static constexpr const char *Name = "enable_external_access"; static constexpr const char *Description = - "The WAL size threshold at which to automatically trigger a checkpoint (e.g. 1GB)"; - static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct CustomExtensionRepositorySetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "custom_extension_repository"; - static constexpr const char *Description = "Overrides the custom endpoint for remote extension installation"; - static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct CustomProfilingSettingsSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "custom_profiling_settings"; - static constexpr const char *Description = "Accepts a JSON enabling custom metrics"; - static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct CustomUserAgentSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "custom_user_agent"; - static constexpr const char *Description = "Metadata from DuckDB callers"; - static constexpr const char *InputType = "VARCHAR"; + "Allow the database to access external state (through e.g. loading/installing modules, COPY TO/FROM, CSV " + "readers, pandas replacement scans, etc)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DebugAsofIejoinSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "debug_asof_iejoin"; - static constexpr const char *Description = "DEBUG SETTING: force use of IEJoin to implement AsOf joins"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct DebugCheckpointAbortSetting { - using RETURN_TYPE = CheckpointAbort; - static constexpr const char *Name = "debug_checkpoint_abort"; +struct EnableMacrosDependencies { + static constexpr const char *Name = "enable_macro_dependencies"; static constexpr const char *Description = - "DEBUG SETTING: trigger an abort while checkpointing for testing purposes"; - static constexpr const char *InputType = "VARCHAR"; + "Enable created MACROs to create dependencies on the referenced objects (such as tables)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DebugForceExternalSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "debug_force_external"; - static constexpr const char *Description = - "DEBUG SETTING: force out-of-core computation for operators that support it, used for testing"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct DebugForceNoCrossProductSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "debug_force_no_cross_product"; +struct EnableViewDependencies { + static constexpr const char *Name = "enable_view_dependencies"; static constexpr const char *Description = - "DEBUG SETTING: Force disable cross product generation when hyper graph isn't connected, used for testing"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct DebugSkipCheckpointOnCommitSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "debug_skip_checkpoint_on_commit"; - static constexpr const char *Description = "DEBUG SETTING: skip checkpointing on commit"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct DebugWindowModeSetting { - using RETURN_TYPE = WindowAggregationMode; - static constexpr const char *Name = "debug_window_mode"; - static constexpr const char *Description = "DEBUG SETTING: switch window mode to use"; - static constexpr const char *InputType = "VARCHAR"; + "Enable created VIEWs to create dependencies on the referenced objects (such as tables)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DefaultBlockSizeSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "default_block_size"; +struct EnableFSSTVectors { + static constexpr const char *Name = "enable_fsst_vectors"; static constexpr const char *Description = - "The default block size for new duckdb database files (new as-in, they do not yet exist)."; - static constexpr const char *InputType = "UBIGINT"; + "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DefaultCollationSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "default_collation"; - static constexpr const char *Description = "The collation setting used when none is specified"; - static constexpr const char *InputType = "VARCHAR"; +struct AllowUnsignedExtensionsSetting { + static constexpr const char *Name = "allow_unsigned_extensions"; + static constexpr const char *Description = "Allow to load extensions with invalid or missing signatures"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct DefaultNullOrderSetting { - using RETURN_TYPE = DefaultOrderByNullType; - static constexpr const char *Name = "default_null_order"; - static constexpr const char *Description = "NULL ordering used when none is specified (NULLS_FIRST or NULLS_LAST)"; - static constexpr const char *InputType = "VARCHAR"; +struct AllowCommunityExtensionsSetting { + static constexpr const char *Name = "allow_community_extensions"; + static constexpr const char *Description = "Allow to load community built extensions"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DefaultOrderSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "default_order"; - static constexpr const char *Description = "The order type used when none is specified (ASC or DESC)"; - static constexpr const char *InputType = "VARCHAR"; +struct AllowExtensionsMetadataMismatchSetting { + static constexpr const char *Name = "allow_extensions_metadata_mismatch"; + static constexpr const char *Description = "Allow to load extensions with not compatible metadata"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DefaultSecretStorageSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "default_secret_storage"; - static constexpr const char *Description = "Allows switching the default storage for secrets"; - static constexpr const char *InputType = "VARCHAR"; +struct AllowUnredactedSecretsSetting { + static constexpr const char *Name = "allow_unredacted_secrets"; + static constexpr const char *Description = "Allow printing unredacted secrets"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DisabledFilesystemsSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "disabled_filesystems"; - static constexpr const char *Description = "Disable specific file systems preventing access (e.g. LocalFileSystem)"; - static constexpr const char *InputType = "VARCHAR"; +struct CustomExtensionRepository { + static constexpr const char *Name = "custom_extension_repository"; + static constexpr const char *Description = "Overrides the custom endpoint for remote extension installation"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DisabledOptimizersSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "disabled_optimizers"; - static constexpr const char *Description = "DEBUG SETTING: disable a specific set of optimizers (comma separated)"; - static constexpr const char *InputType = "VARCHAR"; +struct AutoloadExtensionRepository { + static constexpr const char *Name = "autoinstall_extension_repository"; + static constexpr const char *Description = + "Overrides the custom endpoint for extension installation on autoloading"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DuckDBAPISetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "duckdb_api"; - static constexpr const char *Description = "DuckDB API surface"; - static constexpr const char *InputType = "VARCHAR"; +struct AutoinstallKnownExtensions { + static constexpr const char *Name = "autoinstall_known_extensions"; + static constexpr const char *Description = + "Whether known extensions are allowed to be automatically installed when a query depends on them"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct DynamicOrFilterThresholdSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "dynamic_or_filter_threshold"; - static constexpr const char *Description = - "The maximum amount of OR filters we generate dynamically from a hash join"; - static constexpr const char *InputType = "UBIGINT"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct EnableExternalAccessSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_external_access"; +struct AutoloadKnownExtensions { + static constexpr const char *Name = "autoload_known_extensions"; static constexpr const char *Description = - "Allow the database to access external state (through e.g. loading/installing modules, COPY TO/FROM, CSV " - "readers, pandas replacement scans, etc)"; - static constexpr const char *InputType = "BOOLEAN"; + "Whether known extensions are allowed to be automatically loaded when a query depends on them"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct EnableFSSTVectorsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_fsst_vectors"; - static constexpr const char *Description = - "Allow scans on FSST compressed segments to emit compressed vectors to utilize late decompression"; - static constexpr const char *InputType = "BOOLEAN"; +struct EnableObjectCacheSetting { + static constexpr const char *Name = "enable_object_cache"; + static constexpr const char *Description = "Whether or not object cache is used to cache e.g. Parquet metadata"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct EnableHTTPLoggingSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_http_logging"; - static constexpr const char *Description = "Enables HTTP logging"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); +struct StorageCompatibilityVersion { + static constexpr const char *Name = "storage_compatibility_version"; + static constexpr const char *Description = "Serialize on checkpoint with compatibility for a given duckdb version"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct EnableHTTPMetadataCacheSetting { - using RETURN_TYPE = bool; static constexpr const char *Name = "enable_http_metadata_cache"; static constexpr const char *Description = "Whether or not the global http metadata is used to cache HTTP metadata"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct EnableMacroDependenciesSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_macro_dependencies"; - static constexpr const char *Description = - "Enable created MACROs to create dependencies on the referenced objects (such as tables)"; - static constexpr const char *InputType = "BOOLEAN"; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct EnableObjectCacheSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_object_cache"; - static constexpr const char *Description = "[PLACEHOLDER] Legacy setting - does nothing"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct EnableProfilingSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "enable_profiling"; static constexpr const char *Description = "Enables profiling, and sets the output format (JSON, QUERY_TREE, QUERY_TREE_OPTIMIZER)"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; + +struct CustomProfilingSettings { + static constexpr const char *Name = "custom_profiling_settings"; + static constexpr const char *Description = "Accepts a JSON enabling custom metrics"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct EnableProgressBarSetting { - using RETURN_TYPE = bool; static constexpr const char *Name = "enable_progress_bar"; static constexpr const char *Description = "Enables the progress bar, printing progress to the terminal for long queries"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); - static bool OnLocalSet(ClientContext &context, const Value &input); - static bool OnLocalReset(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct EnableProgressBarPrintSetting { - using RETURN_TYPE = bool; static constexpr const char *Name = "enable_progress_bar_print"; static constexpr const char *Description = "Controls the printing of the progress bar, when 'enable_progress_bar' is true"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct EnableViewDependenciesSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "enable_view_dependencies"; - static constexpr const char *Description = - "Enable created VIEWs to create dependencies on the referenced objects (such as tables)"; - static constexpr const char *InputType = "BOOLEAN"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct ErrorsAsJSONSetting { - using RETURN_TYPE = bool; +struct ErrorsAsJsonSetting { static constexpr const char *Name = "errors_as_json"; static constexpr const char *Description = "Output error messages as structured JSON instead of as a raw string"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ExplainOutputSetting { - using RETURN_TYPE = ExplainOutputType; static constexpr const char *Name = "explain_output"; static constexpr const char *Description = "Output of EXPLAIN statements (ALL, OPTIMIZED_ONLY, PHYSICAL_ONLY)"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; +struct ExportLargeBufferArrow { + static constexpr const char *Name = "arrow_large_buffer_size"; + static constexpr const char *Description = + "If arrow buffers for strings, blobs, uuids and bits should be exported using large buffers"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + struct ExtensionDirectorySetting { - using RETURN_TYPE = string; static constexpr const char *Name = "extension_directory"; static constexpr const char *Description = "Set the directory to store extensions in"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct ExternalThreadsSetting { - using RETURN_TYPE = idx_t; static constexpr const char *Name = "external_threads"; static constexpr const char *Description = "The number of external threads that work on DuckDB tasks."; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); - static bool OnGlobalReset(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct FileSearchPathSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "file_search_path"; static constexpr const char *Description = "A comma separated list of directories to search for input files"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ForceBitpackingModeSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "force_bitpacking_mode"; - static constexpr const char *Description = "DEBUG SETTING: forces a specific bitpacking mode"; - static constexpr const char *InputType = "VARCHAR"; +struct ForceCompressionSetting { + static constexpr const char *Name = "force_compression"; + static constexpr const char *Description = "DEBUG SETTING: forces a specific compression method to be used"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct ForceCompressionSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "force_compression"; - static constexpr const char *Description = "DEBUG SETTING: forces a specific compression method to be used"; - static constexpr const char *InputType = "VARCHAR"; +struct ForceBitpackingModeSetting { + static constexpr const char *Name = "force_bitpacking_mode"; + static constexpr const char *Description = "DEBUG SETTING: forces a specific bitpacking mode"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct HomeDirectorySetting { - using RETURN_TYPE = string; static constexpr const char *Name = "home_directory"; static constexpr const char *Description = "Sets the home directory used by the system"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct HTTPLoggingOutputSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "http_logging_output"; - static constexpr const char *Description = - "The file to which HTTP logging output should be saved, or empty to print to the terminal"; - static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct HTTPProxySetting { - using RETURN_TYPE = string; +struct HTTPProxy { static constexpr const char *Name = "http_proxy"; static constexpr const char *Description = "HTTP proxy host"; - static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct HTTPProxyPasswordSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "http_proxy_password"; - static constexpr const char *Description = "Password for HTTP proxy"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct HTTPProxyUsernameSetting { - using RETURN_TYPE = string; +struct HTTPProxyUsername { static constexpr const char *Name = "http_proxy_username"; static constexpr const char *Description = "Username for HTTP proxy"; - static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct IEEEFloatingPointOpsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "ieee_floating_point_ops"; - static constexpr const char *Description = - "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)."; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct ImmediateTransactionModeSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "immediate_transaction_mode"; - static constexpr const char *Description = - "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct IndexScanMaxCountSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "index_scan_max_count"; - static constexpr const char *Description = - "The maximum index scan count sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " - "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; - static constexpr const char *InputType = "UBIGINT"; +struct HTTPProxyPassword { + static constexpr const char *Name = "http_proxy_password"; + static constexpr const char *Description = "Password for HTTP proxy"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct IndexScanPercentageSetting { - using RETURN_TYPE = double; - static constexpr const char *Name = "index_scan_percentage"; +struct IntegerDivisionSetting { + static constexpr const char *Name = "integer_division"; static constexpr const char *Description = - "The index scan percentage sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " - "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; - static constexpr const char *InputType = "DOUBLE"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static bool OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input); + "Whether or not the / operator defaults to integer division, or to floating point division"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct IntegerDivisionSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "integer_division"; +struct LogQueryPathSetting { + static constexpr const char *Name = "log_query_path"; static constexpr const char *Description = - "Whether or not the / operator defaults to integer division, or to floating point division"; - static constexpr const char *InputType = "BOOLEAN"; + "Specifies the path to which queries should be logged (default: NULL, queries are not logged)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct LockConfigurationSetting { - using RETURN_TYPE = bool; static constexpr const char *Name = "lock_configuration"; static constexpr const char *Description = "Whether or not the configuration can be altered"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct LogQueryPathSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "log_query_path"; +struct IEEEFloatingPointOpsSetting { + static constexpr const char *Name = "ieee_floating_point_ops"; static constexpr const char *Description = - "Specifies the path to which queries should be logged (default: NULL, queries are not logged)"; - static constexpr const char *InputType = "VARCHAR"; + "Use IEE754-compliant floating point operations (returning NAN instead of errors/NULL)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct MaxExpressionDepthSetting { - using RETURN_TYPE = idx_t; +struct ImmediateTransactionModeSetting { + static constexpr const char *Name = "immediate_transaction_mode"; + static constexpr const char *Description = + "Whether transactions should be started lazily when needed, or immediately when BEGIN TRANSACTION is called"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct MaximumExpressionDepthSetting { static constexpr const char *Name = "max_expression_depth"; static constexpr const char *Description = "The maximum expression depth limit in the parser. WARNING: increasing this setting and using very deep " "expressions might lead to stack overflow errors."; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct MaxMemorySetting { - using RETURN_TYPE = string; +struct MaximumMemorySetting { static constexpr const char *Name = "max_memory"; static constexpr const char *Description = "The maximum memory of the system (e.g. 1GB)"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct MaxTempDirectorySizeSetting { - using RETURN_TYPE = string; +struct StreamingBufferSize { + static constexpr const char *Name = "streaming_buffer_size"; + static constexpr const char *Description = + "The maximum memory to buffer between fetching from a streaming result (e.g. 1GB)"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; + +struct MaximumTempDirectorySize { static constexpr const char *Name = "max_temp_directory_size"; static constexpr const char *Description = - "The maximum amount of data stored inside the 'temp_directory' (when set) (e.g. 1GB)"; - static constexpr const char *InputType = "VARCHAR"; + "The maximum amount of data stored inside the 'temp_directory' (when set). If the `temp_directory` is set to " + "an existing directory, this option defaults to the available disk space on " + "that drive. Otherwise, it defaults to 0 (implying that the temporary directory is not used)."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct MaxVacuumTasksSetting { - using RETURN_TYPE = idx_t; +struct MaximumVacuumTasks { static constexpr const char *Name = "max_vacuum_tasks"; - static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint."; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const char *Description = "The maximum vacuum tasks to schedule during a checkpoint"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct MergeJoinThresholdSetting { - using RETURN_TYPE = idx_t; +struct MergeJoinThreshold { static constexpr const char *Name = "merge_join_threshold"; static constexpr const char *Description = "The number of rows we need on either table to choose a merge join"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct NestedLoopJoinThresholdSetting { - using RETURN_TYPE = idx_t; +struct NestedLoopJoinThreshold { static constexpr const char *Name = "nested_loop_join_threshold"; static constexpr const char *Description = "The number of rows we need on either table to choose a nested loop join"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct OldImplicitCastingSetting { - using RETURN_TYPE = bool; +struct OldImplicitCasting { static constexpr const char *Name = "old_implicit_casting"; static constexpr const char *Description = "Allow implicit casting to/from VARCHAR"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct OrderByNonIntegerLiteralSetting { - using RETURN_TYPE = bool; +struct OrderByNonIntegerLiteral { static constexpr const char *Name = "order_by_non_integer_literal"; static constexpr const char *Description = - "Allow ordering by non-integer literals - ordering by such literals has no effect."; - static constexpr const char *InputType = "BOOLEAN"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct OrderedAggregateThresholdSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "ordered_aggregate_threshold"; - static constexpr const char *Description = "The number of rows to accumulate before sorting, used for tuning"; - static constexpr const char *InputType = "UBIGINT"; + "Allow ordering by non-integer literals - ordering by such literals has no effect"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); - static bool OnLocalSet(ClientContext &context, const Value &input); static Value GetSetting(const ClientContext &context); }; -struct PartitionedWriteFlushThresholdSetting { - using RETURN_TYPE = idx_t; +struct PartitionedWriteFlushThreshold { static constexpr const char *Name = "partitioned_write_flush_threshold"; static constexpr const char *Description = "The threshold in number of rows after which we flush a thread state when writing using PARTITION_BY"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PartitionedWriteMaxOpenFilesSetting { - using RETURN_TYPE = idx_t; +struct PartitionedWriteMaxOpenFiles { static constexpr const char *Name = "partitioned_write_max_open_files"; static constexpr const char *Description = "The maximum amount of files the system can keep open before flushing to disk when writing using PARTITION_BY"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; +struct DefaultBlockAllocSize { + static constexpr const char *Name = "default_block_size"; + static constexpr const char *Description = + "The default block size for new duckdb database files (new as-in, they do not yet exist)."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct IndexScanPercentage { + static constexpr const char *Name = "index_scan_percentage"; + static constexpr const char *Description = + "The index scan percentage sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " + "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::DOUBLE; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct IndexScanMaxCount { + static constexpr const char *Name = "index_scan_max_count"; + static constexpr const char *Description = + "The maximum index scan count sets a threshold for index scans. If fewer than MAX(index_scan_max_count, " + "index_scan_percentage * total_row_count) rows match, we perform an index scan instead of a table scan."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::UBIGINT; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + struct PasswordSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "password"; static constexpr const char *Description = "The password to use. Ignored for legacy compatibility."; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct PerfectHtThresholdSetting { - using RETURN_TYPE = idx_t; +struct PerfectHashThresholdSetting { static constexpr const char *Name = "perfect_ht_threshold"; static constexpr const char *Description = "Threshold in bytes for when to use a perfect hash table"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PivotFilterThresholdSetting { - using RETURN_TYPE = idx_t; +struct PivotFilterThreshold { static constexpr const char *Name = "pivot_filter_threshold"; static constexpr const char *Description = "The threshold to switch from using filtered aggregates to LIST with a dedicated pivot operator"; - static constexpr const char *InputType = "UBIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct PivotLimitSetting { - using RETURN_TYPE = idx_t; static constexpr const char *Name = "pivot_limit"; static constexpr const char *Description = "The maximum number of pivot columns in a pivot statement"; - static constexpr const char *InputType = "UBIGINT"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - -struct PreferRangeJoinsSetting { - using RETURN_TYPE = bool; - static constexpr const char *Name = "prefer_range_joins"; - static constexpr const char *Description = "Force use of range joins with mixed predicates"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PreserveIdentifierCaseSetting { - using RETURN_TYPE = bool; +struct PreserveIdentifierCase { static constexpr const char *Name = "preserve_identifier_case"; static constexpr const char *Description = "Whether or not to preserve the identifier case, instead of always lowercasing all non-quoted identifiers"; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct PreserveInsertionOrderSetting { - using RETURN_TYPE = bool; +struct PreserveInsertionOrder { static constexpr const char *Name = "preserve_insertion_order"; static constexpr const char *Description = "Whether or not to preserve insertion order. If set to false the system is allowed to re-order any results " "that do not contain ORDER BY clauses."; - static constexpr const char *InputType = "BOOLEAN"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct ArrowOutputListView { + static constexpr const char *Name = "arrow_output_list_view"; + static constexpr const char *Description = + "If export to arrow format should use ListView as the physical layout for LIST columns"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct ProduceArrowStringViewSetting { - using RETURN_TYPE = bool; +struct LosslessConversionArrow { + static constexpr const char *Name = "arrow_lossless_conversion"; + static constexpr const char *Description = + "Whenever a DuckDB type does not have a clear native or canonical extension match in Arrow, export the types " + "with a duckdb.type_name extension name."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct ProduceArrowStringView { static constexpr const char *Name = "produce_arrow_string_view"; static constexpr const char *Description = - "Whether strings should be produced by DuckDB in Utf8View format instead of Utf8"; - static constexpr const char *InputType = "BOOLEAN"; + "If strings should be produced by DuckDB in Utf8View format instead of Utf8"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct ProfileOutputSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "profile_output"; static constexpr const char *Description = "The file to which profile output should be saved, or empty to print to the terminal"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ProfilingModeSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "profiling_mode"; static constexpr const char *Description = "The profiling mode (STANDARD or DETAILED)"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct ProgressBarTimeSetting { - using RETURN_TYPE = int64_t; static constexpr const char *Name = "progress_bar_time"; static constexpr const char *Description = "Sets the time (in milliseconds) how long a query needs to take before we start printing a progress bar"; - static constexpr const char *InputType = "BIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; -struct ScalarSubqueryErrorOnMultipleRowsSetting { - using RETURN_TYPE = bool; +struct ScalarSubqueryErrorOnMultipleRows { static constexpr const char *Name = "scalar_subquery_error_on_multiple_rows"; static constexpr const char *Description = - "When a scalar subquery returns multiple rows - return a random row instead of returning an error."; - static constexpr const char *InputType = "BOOLEAN"; + "When a scalar subquery returns multiple rows - return a random row instead of returning an error"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct SchemaSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "schema"; static constexpr const char *Description = "Sets the default search schema. Equivalent to setting search_path to a single value."; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct SearchPathSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "search_path"; static constexpr const char *Description = "Sets the default catalog search path as a comma-separated list of values"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetLocal(ClientContext &context, const Value ¶meter); static void ResetLocal(ClientContext &context); static Value GetSetting(const ClientContext &context); }; struct SecretDirectorySetting { - using RETURN_TYPE = string; static constexpr const char *Name = "secret_directory"; static constexpr const char *Description = "Set the directory to which persistent secrets are stored"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct StorageCompatibilityVersionSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "storage_compatibility_version"; - static constexpr const char *Description = "Serialize on checkpoint with compatibility for a given duckdb version"; - static constexpr const char *InputType = "VARCHAR"; - static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); - static void ResetGlobal(DatabaseInstance *db, DBConfig &config); - static Value GetSetting(const ClientContext &context); -}; - -struct StreamingBufferSizeSetting { - using RETURN_TYPE = string; - static constexpr const char *Name = "streaming_buffer_size"; - static constexpr const char *Description = - "The maximum memory to buffer between fetching from a streaming result (e.g. 1GB)"; - static constexpr const char *InputType = "VARCHAR"; - static void SetLocal(ClientContext &context, const Value ¶meter); - static void ResetLocal(ClientContext &context); - static Value GetSetting(const ClientContext &context); -}; - struct TempDirectorySetting { - using RETURN_TYPE = string; static constexpr const char *Name = "temp_directory"; static constexpr const char *Description = "Set the directory to which to write temp files"; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct ThreadsSetting { - using RETURN_TYPE = int64_t; static constexpr const char *Name = "threads"; static constexpr const char *Description = "The number of total threads used by the system."; - static constexpr const char *InputType = "BIGINT"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; struct UsernameSetting { - using RETURN_TYPE = string; static constexpr const char *Name = "username"; static constexpr const char *Description = "The username to use. Ignored for legacy compatibility."; - static constexpr const char *InputType = "VARCHAR"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -struct ZstdMinStringLengthSetting { - using RETURN_TYPE = idx_t; - static constexpr const char *Name = "zstd_min_string_length"; +struct AllocatorFlushThreshold { + static constexpr const char *Name = "allocator_flush_threshold"; static constexpr const char *Description = - "The (average) length at which to enable ZSTD compression, defaults to 4096"; - static constexpr const char *InputType = "UBIGINT"; + "Peak allocation threshold at which to flush the allocator after completing a task."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); static void ResetGlobal(DatabaseInstance *db, DBConfig &config); static Value GetSetting(const ClientContext &context); }; -//===----------------------------------------------------------------------===// -// End of the auto-generated list of settings structures -//===--------------------------------------------------------------------===// +struct AllocatorBulkDeallocationFlushThreshold { + static constexpr const char *Name = "allocator_bulk_deallocation_flush_threshold"; + static constexpr const char *Description = + "If a bulk deallocation larger than this occurs, flush outstanding allocations."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct AllocatorBackgroundThreadsSetting { + static constexpr const char *Name = "allocator_background_threads"; + static constexpr const char *Description = "Whether to enable the allocator background thread."; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct DuckDBApiSetting { + static constexpr const char *Name = "duckdb_api"; + static constexpr const char *Description = "DuckDB API surface"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct CustomUserAgentSetting { + static constexpr const char *Name = "custom_user_agent"; + static constexpr const char *Description = "Metadata from DuckDB callers"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter); + static void ResetGlobal(DatabaseInstance *db, DBConfig &config); + static Value GetSetting(const ClientContext &context); +}; + +struct EnableHTTPLoggingSetting { + static constexpr const char *Name = "enable_http_logging"; + static constexpr const char *Description = "Enables HTTP logging"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; + +struct HTTPLoggingOutputSetting { + static constexpr const char *Name = "http_logging_output"; + static constexpr const char *Description = + "The file to which HTTP logging output should be saved, or empty to print to the terminal"; + static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR; + static void SetLocal(ClientContext &context, const Value ¶meter); + static void ResetLocal(ClientContext &context); + static Value GetSetting(const ClientContext &context); +}; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/main/table_description.hpp b/src/duckdb/src/include/duckdb/main/table_description.hpp index d1b7f6561..151592f49 100644 --- a/src/duckdb/src/include/duckdb/main/table_description.hpp +++ b/src/duckdb/src/include/duckdb/main/table_description.hpp @@ -12,23 +12,13 @@ namespace duckdb { -class TableDescription { +struct TableDescription { public: - TableDescription(const string &database_name, const string &schema_name, const string &table_name) - : database(database_name), schema(schema_name), table(table_name) {}; - - TableDescription() = delete; - -public: - //! The database of the table. - string database; - //! The schema of the table. + //! The schema of the table string schema; - //! The name of the table. + //! The table name of the table string table; - //! True, if the catalog is readonly. - bool readonly; - //! The columns of the table. + //! The columns of the table vector columns; public: diff --git a/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp index e60938745..ccc4644a5 100644 --- a/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/build_probe_side_optimizer.hpp @@ -11,6 +11,7 @@ #include "duckdb/common/unordered_set.hpp" #include "duckdb/common/vector.hpp" #include "duckdb/planner/logical_operator.hpp" +#include "duckdb/planner/operator/logical_filter.hpp" namespace duckdb { @@ -31,11 +32,12 @@ class BuildProbeSideOptimizer : LogicalOperatorVisitor { public: explicit BuildProbeSideOptimizer(ClientContext &context, LogicalOperator &op); + void VisitOperator(LogicalOperator &op) override; void VisitExpression(unique_ptr *expression) override {}; private: - void TryFlipJoinChildren(LogicalOperator &op) const; + void TryFlipJoinChildren(LogicalOperator &op); static idx_t ChildHasJoins(LogicalOperator &op); static BuildSize GetBuildSizes(const LogicalOperator &op, idx_t lhs_cardinality, idx_t rhs_cardinality); diff --git a/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp b/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp index d6fe5b72b..72848bc25 100644 --- a/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/column_lifetime_analyzer.hpp @@ -8,21 +8,18 @@ #pragma once -#include "duckdb/common/vector.hpp" -#include "duckdb/planner/column_binding_map.hpp" #include "duckdb/planner/logical_operator_visitor.hpp" +#include "duckdb/planner/column_binding_map.hpp" +#include "duckdb/common/vector.hpp" namespace duckdb { - -class Optimizer; class BoundColumnRefExpression; //! The ColumnLifetimeAnalyzer optimizer traverses the logical operator tree and ensures that columns are removed from //! the plan when no longer required class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { public: - explicit ColumnLifetimeAnalyzer(Optimizer &optimizer_p, LogicalOperator &root_p, bool is_root = false) - : optimizer(optimizer_p), root(root_p), everything_referenced(is_root) { + explicit ColumnLifetimeAnalyzer(bool is_root = false) : everything_referenced(is_root) { } void VisitOperator(LogicalOperator &op) override; @@ -32,8 +29,6 @@ class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { unique_ptr VisitReplace(BoundReferenceExpression &expr, unique_ptr *expr_ptr) override; private: - Optimizer &optimizer; - LogicalOperator &root; //! Whether or not all the columns are referenced. This happens in the case of the root expression (because the //! output implicitly refers all the columns below it) bool everything_referenced; @@ -41,12 +36,10 @@ class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor { column_binding_set_t column_references; private: - void VisitOperatorInternal(LogicalOperator &op); void StandardVisitOperator(LogicalOperator &op); - void ExtractUnusedColumnBindings(const vector &bindings, column_binding_set_t &unused_bindings); - static void GenerateProjectionMap(vector bindings, column_binding_set_t &unused_bindings, - vector &map); - void Verify(LogicalOperator &op); - void AddVerificationProjection(unique_ptr &child); + + void ExtractUnusedColumnBindings(vector bindings, column_binding_set_t &unused_bindings); + void GenerateProjectionMap(vector bindings, column_binding_set_t &unused_bindings, + vector &map); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp index 0728b2267..ff0215923 100644 --- a/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/common_aggregate_optimizer.hpp @@ -8,8 +8,8 @@ #pragma once -#include "duckdb/planner/column_binding_map.hpp" #include "duckdb/planner/logical_operator_visitor.hpp" +#include "duckdb/planner/column_binding_map.hpp" namespace duckdb { //! The CommonAggregateOptimizer optimizer eliminates duplicate aggregates from aggregate nodes @@ -18,8 +18,8 @@ class CommonAggregateOptimizer : public LogicalOperatorVisitor { void VisitOperator(LogicalOperator &op) override; private: - void StandardVisitOperator(LogicalOperator &op); unique_ptr VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) override; + void ExtractCommonAggregates(LogicalAggregate &aggr); private: diff --git a/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp b/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp deleted file mode 100644 index 8959c0ecc..000000000 --- a/src/duckdb/src/include/duckdb/optimizer/empty_result_pullup.hpp +++ /dev/null @@ -1,27 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/optimizer/deliminator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/optimizer/column_binding_replacer.hpp" - -namespace duckdb { - -//! The EmptyResultPullup Optimizer traverses the logical operator tree and Pulls up empty operators when possible -class EmptyResultPullup : LogicalOperatorVisitor { -public: - EmptyResultPullup() { - } - - unique_ptr Optimize(unique_ptr op); - -private: - unique_ptr PullUpEmptyJoinChildren(unique_ptr op); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp b/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp index 12512a32f..94c88e856 100644 --- a/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/expression_heuristics.hpp @@ -47,7 +47,7 @@ class ExpressionHeuristics : public LogicalOperatorVisitor { idx_t ExpressionCost(BoundComparisonExpression &expr); idx_t ExpressionCost(BoundConjunctionExpression &expr); idx_t ExpressionCost(BoundFunctionExpression &expr); - idx_t ExpressionCost(BoundOperatorExpression &expr, ExpressionType expr_type); + idx_t ExpressionCost(BoundOperatorExpression &expr, ExpressionType &expr_type); idx_t ExpressionCost(PhysicalType return_type, idx_t multiplier); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp b/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp index 68e22573a..c9449616d 100644 --- a/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/filter_combiner.hpp @@ -45,14 +45,9 @@ class FilterCombiner { FilterResult AddFilter(unique_ptr expr); - //! Returns whether or not a set of integral values is a dense range (i.e. 1, 2, 3, 4, 5) - //! If this returns true - this sorts "in_list" as a side-effect - static bool IsDenseRange(vector &in_list); - static bool ContainsNull(vector &in_list); - void GenerateFilters(const std::function filter)> &callback); bool HasFilters(); - TableFilterSet GenerateTableScanFilters(const vector &column_ids); + TableFilterSet GenerateTableScanFilters(const vector &column_ids); // vector> GenerateZonemapChecks(vector &column_ids, vector> // &pushed_filters); diff --git a/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp b/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp index 94706d210..1554e9a6f 100644 --- a/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/filter_pushdown.hpp @@ -57,8 +57,6 @@ class FilterPushdown { unique_ptr PushdownJoin(unique_ptr op); //! Push down a LogicalProjection op unique_ptr PushdownProjection(unique_ptr op); - //! Push down a LogicalProjection op - unique_ptr PushdownUnnest(unique_ptr op); //! Push down a LogicalSetOperation op unique_ptr PushdownSetOperation(unique_ptr op); //! Push down a LogicalGet op diff --git a/src/duckdb/src/include/duckdb/optimizer/in_clause_rewriter.hpp b/src/duckdb/src/include/duckdb/optimizer/in_clause_rewriter.hpp index 51af6e127..91e4e1f86 100644 --- a/src/duckdb/src/include/duckdb/optimizer/in_clause_rewriter.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/in_clause_rewriter.hpp @@ -9,8 +9,6 @@ #pragma once #include "duckdb/planner/logical_operator_visitor.hpp" -#include "duckdb/planner/logical_operator.hpp" -#include "duckdb/common/optional_ptr.hpp" namespace duckdb { class ClientContext; @@ -23,7 +21,6 @@ class InClauseRewriter : public LogicalOperatorVisitor { ClientContext &context; Optimizer &optimizer; - optional_ptr current_op; unique_ptr root; public: diff --git a/src/duckdb/src/include/duckdb/optimizer/join_filter_pushdown_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/join_filter_pushdown_optimizer.hpp index aef9ba055..20272f021 100644 --- a/src/duckdb/src/include/duckdb/optimizer/join_filter_pushdown_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/join_filter_pushdown_optimizer.hpp @@ -13,8 +13,6 @@ namespace duckdb { class Optimizer; -struct JoinFilterPushdownColumn; -struct PushdownFilterTarget; //! The JoinFilterPushdownOptimizer links comparison joins to data sources to enable dynamic execution-time filter //! pushdown @@ -22,10 +20,7 @@ class JoinFilterPushdownOptimizer : public LogicalOperatorVisitor { public: explicit JoinFilterPushdownOptimizer(Optimizer &optimizer); -public: void VisitOperator(LogicalOperator &op) override; - static void GetPushdownFilterTargets(LogicalOperator &op, vector columns, - vector &targets); private: void GenerateJoinFilters(LogicalComparisonJoin &join); diff --git a/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp b/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp index 29e867953..46aa5ce48 100644 --- a/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/join_order/plan_enumerator.hpp @@ -33,8 +33,6 @@ class PlanEnumerator { : query_graph(query_graph), query_graph_manager(query_graph_manager), cost_model(cost_model) { } - static constexpr idx_t THRESHOLD_TO_SWAP_TO_APPROXIMATE = 12; - //! Perform the join order solving void SolveJoinOrder(); void InitLeafPlans(); diff --git a/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp b/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp index 8a4b7035f..4e6f04bfa 100644 --- a/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/join_order/relation_statistics_helper.hpp @@ -45,8 +45,8 @@ class RelationStatisticsHelper { static constexpr double DEFAULT_SELECTIVITY = 0.2; public: - static idx_t InspectTableFilter(idx_t cardinality, idx_t column_index, TableFilter &filter, - BaseStatistics &base_stats); + static idx_t InspectConjunctionAND(idx_t cardinality, idx_t column_index, ConjunctionAndFilter &filter, + BaseStatistics &base_stats); // static idx_t InspectConjunctionOR(idx_t cardinality, idx_t column_index, ConjunctionOrFilter &filter, // BaseStatistics &base_stats); //! Extract Statistics from a LogicalGet. diff --git a/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp b/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp index 8df4fb94b..b7d2a3d72 100644 --- a/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/matcher/expression_matcher.hpp @@ -126,20 +126,6 @@ class FunctionExpressionMatcher : public ExpressionMatcher { bool Match(Expression &expr, vector> &bindings) override; }; -class AggregateExpressionMatcher : public ExpressionMatcher { -public: - AggregateExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_AGGREGATE) { - } - //! The matchers for the child expressions - vector> matchers; - //! The set matcher matching policy to use - SetMatcher::Policy policy; - //! The function name to match - unique_ptr function; - - bool Match(Expression &expr, vector> &bindings) override; -}; - //! The FoldableConstant matcher matches any expression that is foldable into a constant by the ExpressionExecutor (i.e. //! scalar but not aggregate/window/parameter) class FoldableConstantMatcher : public ExpressionMatcher { @@ -150,13 +136,4 @@ class FoldableConstantMatcher : public ExpressionMatcher { bool Match(Expression &expr, vector> &bindings) override; }; -//! The stable expression matcher matches only stable expressions (non-volatile) -class StableExpressionMatcher : public ExpressionMatcher { -public: - StableExpressionMatcher() : ExpressionMatcher(ExpressionClass::INVALID) { - } - - bool Match(Expression &expr, vector> &bindings) override; -}; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/matcher/type_matcher.hpp b/src/duckdb/src/include/duckdb/optimizer/matcher/type_matcher.hpp index 892f35f30..0536ef166 100644 --- a/src/duckdb/src/include/duckdb/optimizer/matcher/type_matcher.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/matcher/type_matcher.hpp @@ -34,24 +34,6 @@ class SpecificTypeMatcher : public TypeMatcher { private: LogicalType type; }; -//! The SpecificTypeMatcher class matches only a type out of a set of types -class SetTypesMatcher : public TypeMatcher { -public: - explicit SetTypesMatcher(vector types_p) : types(std::move(types_p)) { - } - - bool Match(const LogicalType &type_p) override { - for (auto &type : types) { - if (type == type_p) { - return true; - } - } - return false; - } - -private: - vector types; -}; //! The NumericTypeMatcher class matches any numeric type (DECIMAL, INTEGER, etc...) class NumericTypeMatcher : public TypeMatcher { diff --git a/src/duckdb/src/include/duckdb/optimizer/optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/optimizer.hpp index 5b0dea218..4e37ca8ea 100644 --- a/src/duckdb/src/include/duckdb/optimizer/optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/optimizer.hpp @@ -28,7 +28,6 @@ class Optimizer { ClientContext &GetContext(); //! Whether the specific optimizer is disabled bool OptimizerDisabled(OptimizerType type); - static bool OptimizerDisabled(ClientContext &context, OptimizerType type); public: ClientContext &context; @@ -40,16 +39,8 @@ class Optimizer { void RunOptimizer(OptimizerType type, const std::function &callback); void Verify(LogicalOperator &op); -public: - // helper functions - unique_ptr BindScalarFunction(const string &name, unique_ptr c1); - unique_ptr BindScalarFunction(const string &name, unique_ptr c1, unique_ptr c2); - private: unique_ptr plan; - -private: - unique_ptr BindScalarFunction(const string &name, vector> children); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp b/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp index a05a1d722..629efc5dc 100644 --- a/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/remove_unused_columns.hpp @@ -11,18 +11,12 @@ #include "duckdb/planner/logical_operator_visitor.hpp" #include "duckdb/planner/column_binding_map.hpp" #include "duckdb/common/vector.hpp" -#include "duckdb/common/column_index.hpp" namespace duckdb { class Binder; class BoundColumnRefExpression; class ClientContext; -struct ReferencedColumn { - vector> bindings; - vector child_columns; -}; - //! The RemoveUnusedColumns optimizer traverses the logical operator tree and removes any columns that are not required class RemoveUnusedColumns : public LogicalOperatorVisitor { public: @@ -31,7 +25,6 @@ class RemoveUnusedColumns : public LogicalOperatorVisitor { } void VisitOperator(LogicalOperator &op) override; - void VisitExpression(unique_ptr *expression) override; protected: unique_ptr VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) override; @@ -44,23 +37,14 @@ class RemoveUnusedColumns : public LogicalOperatorVisitor { //! output implicitly refers all the columns below it) bool everything_referenced; //! The map of column references - column_binding_map_t column_references; + column_binding_map_t> column_references; private: template void ClearUnusedExpressions(vector &list, idx_t table_idx, bool replace = true); - //! Add a reference to the column in its entirey - void AddBinding(BoundColumnRefExpression &col); - //! Add a reference to a sub-section of the column - void AddBinding(BoundColumnRefExpression &col, ColumnIndex child_column); //! Perform a replacement of the ColumnBinding, iterating over all the currently found column references and //! replacing the bindings void ReplaceBinding(ColumnBinding current_binding, ColumnBinding new_binding); - - bool HandleStructExtract(Expression &expr); - - bool HandleStructExtractRecursive(Expression &expr, optional_ptr &colref, - vector &indexes); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/rule/distinct_aggregate_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/rule/distinct_aggregate_optimizer.hpp deleted file mode 100644 index 65123b96b..000000000 --- a/src/duckdb/src/include/duckdb/optimizer/rule/distinct_aggregate_optimizer.hpp +++ /dev/null @@ -1,34 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/optimizer/rule/distinct_aggregate_optimizer.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/optimizer/rule.hpp" -#include "duckdb/parser/expression_map.hpp" - -namespace duckdb { - -class DistinctAggregateOptimizer : public Rule { -public: - explicit DistinctAggregateOptimizer(ExpressionRewriter &rewriter); - - static unique_ptr Apply(ClientContext &context, BoundAggregateExpression &aggr, bool &changes_made); - unique_ptr Apply(LogicalOperator &op, vector> &bindings, bool &changes_made, - bool is_root) override; -}; - -class DistinctWindowedOptimizer : public Rule { -public: - explicit DistinctWindowedOptimizer(ExpressionRewriter &rewriter); - - static unique_ptr Apply(ClientContext &context, BoundWindowExpression &wexpr, bool &changes_made); - unique_ptr Apply(LogicalOperator &op, vector> &bindings, bool &changes_made, - bool is_root) override; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp b/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp deleted file mode 100644 index 78c67a199..000000000 --- a/src/duckdb/src/include/duckdb/optimizer/sampling_pushdown.hpp +++ /dev/null @@ -1,25 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/optimizer/sampling_pushdown.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/constants.hpp" -#include "duckdb/planner/logical_operator.hpp" -#include "duckdb/common/unique_ptr.hpp" - -namespace duckdb { -class LocigalOperator; -class Optimizer; - -class SamplingPushdown { -public: - //! Optimize SYSTEM SAMPLING + SCAN to SAMPLE SCAN - unique_ptr Optimize(unique_ptr op); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp b/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp index be98b7789..618c07505 100644 --- a/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/statistics_propagator.hpp @@ -87,7 +87,7 @@ class StatisticsPropagator { unique_ptr PropagateExpression(unique_ptr &expr); unique_ptr PropagateExpression(Expression &expr, unique_ptr &expr_ptr); - //! Run a comparison between the statistics and the table filter; returns the prune result + unique_ptr PropagateExpression(BoundAggregateExpression &expr, unique_ptr &expr_ptr); unique_ptr PropagateExpression(BoundBetweenExpression &expr, unique_ptr &expr_ptr); unique_ptr PropagateExpression(BoundCaseExpression &expr, unique_ptr &expr_ptr); @@ -99,8 +99,6 @@ class StatisticsPropagator { unique_ptr PropagateExpression(BoundColumnRefExpression &expr, unique_ptr &expr_ptr); unique_ptr PropagateExpression(BoundOperatorExpression &expr, unique_ptr &expr_ptr); - //! Try to execute aggregates using only the statistics if possible - void TryExecuteAggregates(LogicalAggregate &op, unique_ptr &node_ptr); void ReplaceWithEmptyResult(unique_ptr &node); bool ExpressionIsConstant(Expression &expr, const Value &val); diff --git a/src/duckdb/src/include/duckdb/optimizer/sum_rewriter.hpp b/src/duckdb/src/include/duckdb/optimizer/sum_rewriter.hpp deleted file mode 100644 index 18cff911c..000000000 --- a/src/duckdb/src/include/duckdb/optimizer/sum_rewriter.hpp +++ /dev/null @@ -1,37 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/optimizer/sum_rewriter.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/planner/column_binding_map.hpp" -#include "duckdb/planner/logical_operator_visitor.hpp" - -namespace duckdb { -class ExpressionMatcher; -class Optimizer; - -//! Rewrites SUM(x + C) into SUM(x) + C * COUNT(x) -class SumRewriterOptimizer : public LogicalOperatorVisitor { -public: - explicit SumRewriterOptimizer(Optimizer &optimizer); - ~SumRewriterOptimizer() override; - - void Optimize(unique_ptr &op); - void VisitOperator(LogicalOperator &op) override; - -private: - void StandardVisitOperator(LogicalOperator &op); - unique_ptr VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) override; - void RewriteSums(unique_ptr &aggr); - -private: - Optimizer &optimizer; - column_binding_map_t aggregate_map; - unique_ptr sum_matcher; -}; -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/optimizer/topn_optimizer.hpp b/src/duckdb/src/include/duckdb/optimizer/topn_optimizer.hpp index aab077005..94ebaed25 100644 --- a/src/duckdb/src/include/duckdb/optimizer/topn_optimizer.hpp +++ b/src/duckdb/src/include/duckdb/optimizer/topn_optimizer.hpp @@ -12,7 +12,6 @@ namespace duckdb { class LogicalOperator; -class LogicalTopN; class Optimizer; class TopN { @@ -21,9 +20,6 @@ class TopN { unique_ptr Optimize(unique_ptr op); //! Whether we can perform the optimization on this operator static bool CanOptimize(LogicalOperator &op); - -private: - void PushdownDynamicFilters(LogicalTopN &op); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parallel/pipeline.hpp b/src/duckdb/src/include/duckdb/parallel/pipeline.hpp index 34dcdd447..a074551c2 100644 --- a/src/duckdb/src/include/duckdb/parallel/pipeline.hpp +++ b/src/duckdb/src/include/duckdb/parallel/pipeline.hpp @@ -97,7 +97,7 @@ class Pipeline : public enable_shared_from_this { void PrintDependencies() const; //! Returns query progress - bool GetProgress(ProgressData &progress_data); + bool GetProgress(double ¤t_percentage, idx_t &estimated_cardinality); //! Returns a list of all operators (including source and sink) involved in this pipeline vector> GetOperators(); diff --git a/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp b/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp index 9781e6fb8..e19c4483d 100644 --- a/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp +++ b/src/duckdb/src/include/duckdb/parallel/pipeline_executor.hpp @@ -32,28 +32,6 @@ enum class PipelineExecuteResult { INTERRUPTED }; -class ExecutionBudget { -public: - explicit ExecutionBudget(idx_t maximum) : processed(0), maximum_to_process(maximum) { - } - -public: - bool Next() { - if (IsDepleted()) { - return false; - } - processed++; - return true; - } - bool IsDepleted() const { - return processed >= maximum_to_process; - } - -private: - idx_t processed; - idx_t maximum_to_process; -}; - //! The Pipeline class represents an execution pipeline class PipelineExecutor { public: @@ -65,6 +43,10 @@ class PipelineExecutor { //! Returns true if execution is finished, false if Execute should be called again PipelineExecuteResult Execute(idx_t max_chunks); + //! Push a single input DataChunk into the pipeline. + //! Returns either OperatorResultType::NEED_MORE_INPUT or OperatorResultType::FINISHED + //! If OperatorResultType::FINISHED is returned, more input will not change the result anymore + OperatorResultType ExecutePush(DataChunk &input); //! Called after depleting the source: finalizes the execution of this pipeline executor //! This should only be called once per PipelineExecutor. PipelineExecuteResult PushFinalize(); @@ -109,8 +91,8 @@ class PipelineExecutor { bool finalized = false; //! Whether or not the pipeline has finished processing int32_t finished_processing_idx = -1; - //! Partition info that is used by this executor - OperatorPartitionInfo required_partition_info; + //! Whether or not this pipeline requires keeping track of the batch index of the source + bool requires_batch_index = false; //! Source has indicated it is exhausted bool exhausted_source = false; @@ -146,7 +128,7 @@ class PipelineExecutor { SourceResultType GetData(DataChunk &chunk, OperatorSourceInput &input); SinkResultType Sink(DataChunk &chunk, OperatorSinkInput &input); - OperatorResultType ExecutePushInternal(DataChunk &input, ExecutionBudget &chunk_budget, idx_t initial_idx = 0); + OperatorResultType ExecutePushInternal(DataChunk &input, idx_t initial_idx = 0); //! Pushes a chunk through the pipeline and returns a single result chunk //! Returns whether or not a new input chunk is needed, or whether or not we are finished OperatorResultType Execute(DataChunk &input, DataChunk &result, idx_t initial_index = 0); @@ -156,7 +138,7 @@ class PipelineExecutor { //! Tries to flush all state from intermediate operators. Will return true if all state is flushed, false in the //! case of a blocked sink. - bool TryFlushCachingOperators(ExecutionBudget &chunk_budget); + bool TryFlushCachingOperators(); static bool CanCacheType(const LogicalType &type); void CacheChunk(DataChunk &input, idx_t operator_idx); diff --git a/src/duckdb/src/include/duckdb/parser/base_expression.hpp b/src/duckdb/src/include/duckdb/parser/base_expression.hpp index 7e339e2b9..a64baf724 100644 --- a/src/duckdb/src/include/duckdb/parser/base_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/base_expression.hpp @@ -26,69 +26,21 @@ class BaseExpression { virtual ~BaseExpression() { } - //! Returns the class of the expression - ExpressionClass GetExpressionClass() const { - return expression_class; - } - //! Returns the type of the expression ExpressionType GetExpressionType() const { return type; } - - //! Sets the type of the expression unsafely. In general expressions are immutable and should not be changed after - //! creation. Only use this if you know what you are doing. - void SetExpressionTypeUnsafe(ExpressionType new_type) { - type = new_type; - } - - //! Returns the location in the query (if any) - optional_idx GetQueryLocation() const { - return query_location; - } - - //! Sets the location in the query - void SetQueryLocation(optional_idx location) { - query_location = location; - } - - //! Returns true if the expression has a non-empty alias - bool HasAlias() const { - return !alias.empty(); - } - - //! Returns the alias of the expression - const string &GetAlias() const { - return alias; - } - - //! Sets the alias of the expression - void SetAlias(const string &alias_p) { - alias = alias_p; - } - - //! Sets the alias of the expression - void SetAlias(string &&alias_p) { - alias = std::move(alias_p); - } - - //! Clears the alias of the expression - void ClearAlias() { - alias.clear(); + //! Returns the class of the expression + ExpressionClass GetExpressionClass() const { + return expression_class; } - // TODO: Make the following protected - // protected: - //! Type of the expression ExpressionType type; - //! The expression class of the node ExpressionClass expression_class; - //! The alias of the expression, string alias; - //! The location in the query (if any) optional_idx query_location; diff --git a/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp b/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp index a3811160a..570a3e27c 100644 --- a/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp +++ b/src/duckdb/src/include/duckdb/parser/constraints/unique_constraint.hpp @@ -8,11 +8,8 @@ #pragma once -#include "duckdb/common/enum_util.hpp" -#include "duckdb/common/enums/index_constraint_type.hpp" -#include "duckdb/common/vector.hpp" -#include "duckdb/parser/column_list.hpp" #include "duckdb/parser/constraint.hpp" +#include "duckdb/common/vector.hpp" namespace duckdb { @@ -21,33 +18,52 @@ class UniqueConstraint : public Constraint { static constexpr const ConstraintType TYPE = ConstraintType::UNIQUE; public: - DUCKDB_API UniqueConstraint(const LogicalIndex index, const bool is_primary_key); - DUCKDB_API UniqueConstraint(vector columns, const bool is_primary_key); + DUCKDB_API UniqueConstraint(LogicalIndex index, bool is_primary_key); + DUCKDB_API UniqueConstraint(vector columns, bool is_primary_key); public: DUCKDB_API string ToString() const override; + DUCKDB_API unique_ptr Copy() const override; + DUCKDB_API void Serialize(Serializer &serializer) const override; DUCKDB_API static unique_ptr Deserialize(Deserializer &deserializer); - //! Returns true, if the constraint is a PRIMARY KEY constraint. - bool IsPrimaryKey() const; - //! Returns true, if the constraint is defined on a single column. - bool HasIndex() const; - //! Returns the column index on which the constraint is defined. - LogicalIndex GetIndex() const; - //! Sets the column index of the constraint. - void SetIndex(const LogicalIndex new_index); - //! Returns a constant reference to the column names on which the constraint is defined. - const vector &GetColumnNames() const; - //! Returns a mutable reference to the column names on which the constraint is defined. - vector &GetColumnNamesMutable(); - //! Returns the column indexes on which the constraint is defined. - vector GetLogicalIndexes(const ColumnList &columns) const; - //! Get the name of the constraint. - string GetName(const string &table_name) const; - //! Sets a single column name. Does nothing, if the name is already set. - void SetColumnName(const string &name); + bool IsPrimaryKey() const { + return is_primary_key; + } + + bool HasIndex() const { + return index.index != DConstants::INVALID_INDEX; + } + + LogicalIndex GetIndex() const { + if (!HasIndex()) { + throw InternalException("UniqueConstraint::GetIndex called on a unique constraint without a defined index"); + } + return index; + } + void SetIndex(LogicalIndex new_index) { + D_ASSERT(new_index.index != DConstants::INVALID_INDEX); + index = new_index; + } + + const vector &GetColumnNames() const { + D_ASSERT(columns.size() >= 1); + return columns; + } + vector &GetColumnNamesMutable() { + D_ASSERT(columns.size() >= 1); + return columns; + } + + void SetColumnName(string name) { + if (!columns.empty()) { + // name has already been set + return; + } + columns.push_back(std::move(name)); + } private: UniqueConstraint(); @@ -57,12 +73,12 @@ class UniqueConstraint : public Constraint { #else public: #endif - - //! The indexed column of the constraint. Only used for single-column constraints, invalid otherwise. + //! The index of the column for which this constraint holds. Only used when the constraint relates to a single + //! column, equal to DConstants::INVALID_INDEX if not used LogicalIndex index; - //! The names of the columns on which this constraint is defined. Only set if the index field is not set. + //! The set of columns for which this constraint holds by name. Only used when the index field is not used. vector columns; - //! Whether this is a PRIMARY KEY constraint, or a UNIQUE constraint. + //! Whether or not this is a PRIMARY KEY constraint, or a UNIQUE constraint. bool is_primary_key; }; diff --git a/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp index 408dcaab3..f50717efd 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/columnref_expression.hpp @@ -12,7 +12,6 @@ #include "duckdb/common/vector.hpp" namespace duckdb { -struct BindingAlias; //! Represents a reference to a column from either the FROM clause or from an //! alias @@ -23,8 +22,6 @@ class ColumnRefExpression : public ParsedExpression { public: //! Specify both the column and table name ColumnRefExpression(string column_name, string table_name); - //! Specify both the column and table alias - ColumnRefExpression(string column_name, const BindingAlias &alias); //! Only specify the column name, the table name will be derived later explicit ColumnRefExpression(string column_name); //! Specify a set of names diff --git a/src/duckdb/src/include/duckdb/parser/expression/comparison_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/comparison_expression.hpp index 01371f5fd..9c9a82e0a 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/comparison_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/comparison_expression.hpp @@ -37,8 +37,8 @@ class ComparisonExpression : public ParsedExpression { public: template static string ToString(const T &entry) { - return StringUtil::Format("(%s %s %s)", entry.left->ToString(), - ExpressionTypeToOperator(entry.GetExpressionType()), entry.right->ToString()); + return StringUtil::Format("(%s %s %s)", entry.left->ToString(), ExpressionTypeToOperator(entry.type), + entry.right->ToString()); } private: diff --git a/src/duckdb/src/include/duckdb/parser/expression/conjunction_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/conjunction_expression.hpp index 3e343df9f..748bcb01b 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/conjunction_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/conjunction_expression.hpp @@ -43,7 +43,7 @@ class ConjunctionExpression : public ParsedExpression { static string ToString(const T &entry) { string result = "(" + entry.children[0]->ToString(); for (idx_t i = 1; i < entry.children.size(); i++) { - result += " " + ExpressionTypeToOperator(entry.GetExpressionType()) + " " + entry.children[i]->ToString(); + result += " " + ExpressionTypeToOperator(entry.type) + " " + entry.children[i]->ToString(); } return result + ")"; } diff --git a/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp index 4fc292753..d131fcebf 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/function_expression.hpp @@ -98,9 +98,9 @@ class FunctionExpression : public ParsedExpression { result += "DISTINCT "; } result += StringUtil::Join(entry.children, entry.children.size(), ", ", [&](const unique_ptr &child) { - return child->GetAlias().empty() || !add_alias + return child->alias.empty() || !add_alias ? child->ToString() - : StringUtil::Format("%s := %s", SQLIdentifier(child->GetAlias()), child->ToString()); + : StringUtil::Format("%s := %s", SQLIdentifier(child->alias), child->ToString()); }); // ordered aggregate if (order_bys && !order_bys->orders.empty()) { diff --git a/src/duckdb/src/include/duckdb/parser/expression/operator_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/operator_expression.hpp index 3bcf38146..5867860e1 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/operator_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/operator_expression.hpp @@ -40,16 +40,16 @@ class OperatorExpression : public ParsedExpression { public: template static string ToString(const T &entry) { - auto op = ExpressionTypeToOperator(entry.GetExpressionType()); + auto op = ExpressionTypeToOperator(entry.type); if (!op.empty()) { // use the operator string to represent the operator D_ASSERT(entry.children.size() == 2); return entry.children[0]->ToString() + " " + op + " " + entry.children[1]->ToString(); } - switch (entry.GetExpressionType()) { + switch (entry.type) { case ExpressionType::COMPARE_IN: case ExpressionType::COMPARE_NOT_IN: { - string op_type = entry.GetExpressionType() == ExpressionType::COMPARE_IN ? " IN " : " NOT IN "; + string op_type = entry.type == ExpressionType::COMPARE_IN ? " IN " : " NOT IN "; string in_child = entry.children[0]->ToString(); string child_list = "("; for (idx_t i = 1; i < entry.children.size(); i++) { @@ -63,7 +63,7 @@ class OperatorExpression : public ParsedExpression { } case ExpressionType::OPERATOR_NOT: { string result = "("; - result += ExpressionTypeToString(entry.GetExpressionType()); + result += ExpressionTypeToString(entry.type); result += " "; result += StringUtil::Join(entry.children, entry.children.size(), ", ", [](const unique_ptr &child) { return child->ToString(); }); @@ -72,7 +72,7 @@ class OperatorExpression : public ParsedExpression { } case ExpressionType::GROUPING_FUNCTION: case ExpressionType::OPERATOR_COALESCE: { - string result = ExpressionTypeToString(entry.GetExpressionType()); + string result = ExpressionTypeToString(entry.type); result += "("; result += StringUtil::Join(entry.children, entry.children.size(), ", ", [](const unique_ptr &child) { return child->ToString(); }); @@ -105,7 +105,7 @@ class OperatorExpression : public ParsedExpression { return entry.children[0]->ToString() + "[" + begin + ":" + end + "]"; } case ExpressionType::STRUCT_EXTRACT: { - if (entry.children[1]->GetExpressionType() != ExpressionType::VALUE_CONSTANT) { + if (entry.children[1]->type != ExpressionType::VALUE_CONSTANT) { return string(); } auto child_string = entry.children[1]->ToString(); diff --git a/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp index c35ef2029..d95b683d2 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/star_expression.hpp @@ -10,7 +10,6 @@ #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/parser/qualified_name_set.hpp" namespace duckdb { @@ -25,11 +24,9 @@ class StarExpression : public ParsedExpression { //! The relation name in case of tbl.*, or empty if this is a normal * string relation_name; //! List of columns to exclude from the STAR expression - qualified_column_set_t exclude_list; + case_insensitive_set_t exclude_list; //! List of columns to replace with another expression case_insensitive_map_t> replace_list; - //! List of columns to rename - qualified_column_map_t rename_list; //! The expression to select the columns (regular expression or list) unique_ptr expr; //! Whether or not this is a COLUMNS expression @@ -49,12 +46,5 @@ class StarExpression : public ParsedExpression { void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); - -public: - // these methods exist for backwards compatibility of (de)serialization - StarExpression(const case_insensitive_set_t &exclude_list, qualified_column_set_t qualified_set); - - case_insensitive_set_t SerializedExcludeList() const; - qualified_column_set_t SerializedQualifiedExcludeList() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/expression/window_expression.hpp b/src/duckdb/src/include/duckdb/parser/expression/window_expression.hpp index e41f4ad82..4663c0f99 100644 --- a/src/duckdb/src/include/duckdb/parser/expression/window_expression.hpp +++ b/src/duckdb/src/include/duckdb/parser/expression/window_expression.hpp @@ -69,11 +69,6 @@ class WindowExpression : public ParsedExpression { unique_ptr offset_expr; unique_ptr default_expr; - //! The set of argument ordering clauses - //! These are distinct from the frame ordering clauses e.g., the "x" in - //! FIRST_VALUE(a ORDER BY x) OVER (PARTITION BY p ORDER BY s) - vector arg_orders; - public: bool IsWindow() const override { return true; @@ -113,13 +108,6 @@ class WindowExpression : public ParsedExpression { result += ", "; result += entry.default_expr->ToString(); } - // ORDER BY arguments - if (!entry.arg_orders.empty()) { - result += " ORDER BY "; - result += StringUtil::Join(entry.arg_orders, entry.arg_orders.size(), ", ", - [](const ORDER_NODE &order) { return order.ToString(); }); - } - // IGNORE NULLS if (entry.ignore_nulls) { result += " IGNORE NULLS"; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp index 7e47a2e88..88db356af 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp @@ -74,7 +74,6 @@ struct AlterInfo : public ParseInfo { }; AlterEntryData GetAlterEntryData() const; - bool IsAddPrimaryKey() const; protected: explicit AlterInfo(AlterType type); diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp index f3a209462..625f25f31 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_scalar_function_info.hpp @@ -13,7 +13,6 @@ #include "duckdb/parser/parsed_data/alter_info.hpp" namespace duckdb { -struct CreateScalarFunctionInfo; //===--------------------------------------------------------------------===// // Alter Scalar Function @@ -34,10 +33,10 @@ struct AlterScalarFunctionInfo : public AlterInfo { // AddScalarFunctionOverloadInfo //===--------------------------------------------------------------------===// struct AddScalarFunctionOverloadInfo : public AlterScalarFunctionInfo { - AddScalarFunctionOverloadInfo(AlterEntryData data, unique_ptr new_overloads); + AddScalarFunctionOverloadInfo(AlterEntryData data, ScalarFunctionSet new_overloads); ~AddScalarFunctionOverloadInfo() override; - unique_ptr new_overloads; + ScalarFunctionSet new_overloads; public: unique_ptr Copy() const override; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp index 9506b1519..73a685f73 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_info.hpp @@ -78,8 +78,7 @@ enum class AlterTableType : uint8_t { FOREIGN_KEY_CONSTRAINT = 7, SET_NOT_NULL = 8, DROP_NOT_NULL = 9, - SET_COLUMN_COMMENT = 10, - ADD_CONSTRAINT = 11 + SET_COLUMN_COMMENT = 10 }; struct AlterTableInfo : public AlterInfo { @@ -347,24 +346,4 @@ struct RenameViewInfo : public AlterViewInfo { RenameViewInfo(); }; -//===--------------------------------------------------------------------===// -// AddConstraintInfo -//===--------------------------------------------------------------------===// -struct AddConstraintInfo : public AlterTableInfo { - AddConstraintInfo(AlterEntryData data, unique_ptr constraint); - ~AddConstraintInfo() override; - - //! The constraint to add. - unique_ptr constraint; - -public: - unique_ptr Copy() const override; - string ToString() const override; - void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &deserializer); - -private: - AddConstraintInfo(); -}; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp index 835dd9a4c..7906ac52f 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/attach_info.hpp @@ -13,7 +13,6 @@ #include "duckdb/common/unordered_map.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/common/enums/on_create_conflict.hpp" -#include "duckdb/storage/storage_options.hpp" namespace duckdb { @@ -35,8 +34,10 @@ struct AttachInfo : public ParseInfo { OnCreateConflict on_conflict = OnCreateConflict::ERROR_ON_CONFLICT; public: - //! Returns the storage options - StorageOptions GetStorageOptions() const; + //! Returns the block allocation size, which is the allocation size of blocks for this attached database file. + //! Returns DConstants::INVALID_INDEX, if not provided. This is NOT the actual memory available on a block + //! (block_size), even though the corresponding option we expose to the user is called "block_size". + optional_idx GetBlockAllocSize() const; //! Copies this AttachInfo and returns an unique pointer to the new AttachInfo. unique_ptr Copy() const; string ToString() const; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp index 60aa36ef0..c274ffb55 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/comment_on_column_info.hpp @@ -12,9 +12,9 @@ #include "duckdb/common/types/value.hpp" #include "duckdb/parser/parsed_data/alter_info.hpp" #include "duckdb/parser/qualified_name.hpp" +#include "duckdb/catalog/catalog_entry_retriever.hpp" namespace duckdb { -class CatalogEntryRetriever; class ClientContext; class CatalogEntry; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp index 355a11f7d..64018f3bf 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_function_info.hpp @@ -13,26 +13,22 @@ namespace duckdb { -struct FunctionDescription { - //! Parameter types (if any) - vector parameter_types; - //! Parameter names (if any) - vector parameter_names; - //! The description (if any) - string description; - //! Examples (if any) - vector examples; -}; - struct CreateFunctionInfo : public CreateInfo { - explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA); + explicit CreateFunctionInfo(CatalogType type, string schema = DEFAULT_SCHEMA) + : CreateInfo(type, std::move(schema)) { + D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY || + type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY || + type == CatalogType::MACRO_ENTRY || type == CatalogType::TABLE_MACRO_ENTRY); + } //! Function name string name; - //! Function description - vector descriptions; - - DUCKDB_API void CopyFunctionProperties(CreateFunctionInfo &other) const; + //! The description (if any) + string description; + //! Parameter names (if any) + vector parameter_names; + //! The example (if any) + string example; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp index 6cc6e84ce..08ff3826f 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp @@ -46,12 +46,12 @@ struct CreateIndexInfo : public CreateInfo { public: DUCKDB_API unique_ptr Copy() const override; - string ToString() const override; - void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &deserializer); + string ToString() const override; vector ExpressionsToList() const; string ExpressionsToString() const; + void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &deserializer); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp index 6b50064a1..00551cb46 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/create_type_info.hpp @@ -15,18 +15,18 @@ namespace duckdb { -struct BindLogicalTypeInput { +struct BindTypeModifiersInput { ClientContext &context; - const LogicalType &base_type; + const LogicalType &type; const vector &modifiers; }; //! The type to bind type modifiers to a type -typedef LogicalType (*bind_logical_type_function_t)(const BindLogicalTypeInput &input); +typedef LogicalType (*bind_type_modifiers_function_t)(BindTypeModifiersInput &input); struct CreateTypeInfo : public CreateInfo { CreateTypeInfo(); - CreateTypeInfo(string name_p, LogicalType type_p, bind_logical_type_function_t bind_function_p = nullptr); + CreateTypeInfo(string name_p, LogicalType type_p, bind_type_modifiers_function_t bind_modifiers_p = nullptr); //! Name of the Type string name; @@ -35,7 +35,7 @@ struct CreateTypeInfo : public CreateInfo { //! Used by create enum from query unique_ptr query; //! Bind type modifiers to the type - bind_logical_type_function_t bind_function; + bind_type_modifiers_function_t bind_modifiers; public: unique_ptr Copy() const override; diff --git a/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp b/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp index dadbcfe92..201469bcf 100644 --- a/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp +++ b/src/duckdb/src/include/duckdb/parser/parsed_data/sample_options.hpp @@ -15,30 +15,21 @@ namespace duckdb { -// Invalid is 255 because previously stored databases have SampleMethods according to the current ENUMS and we need to -// maintain that -enum class SampleMethod : uint8_t { SYSTEM_SAMPLE = 0, BERNOULLI_SAMPLE = 1, RESERVOIR_SAMPLE = 2, INVALID = 255 }; +enum class SampleMethod : uint8_t { SYSTEM_SAMPLE = 0, BERNOULLI_SAMPLE = 1, RESERVOIR_SAMPLE = 2 }; // **DEPRECATED**: Use EnumUtil directly instead. string SampleMethodToString(SampleMethod method); -class SampleOptions { - -public: - explicit SampleOptions(int64_t seed_ = -1); - +struct SampleOptions { Value sample_size; bool is_percentage; SampleMethod method; - optional_idx seed = optional_idx::Invalid(); - bool repeatable; + int64_t seed = -1; unique_ptr Copy(); - void SetSeed(idx_t new_seed); static bool Equals(SampleOptions *a, SampleOptions *b); void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); - int64_t GetSeed() const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/parser.hpp b/src/duckdb/src/include/duckdb/parser/parser.hpp index 54cf89fb7..b919f5ca3 100644 --- a/src/duckdb/src/include/duckdb/parser/parser.hpp +++ b/src/duckdb/src/include/duckdb/parser/parser.hpp @@ -44,9 +44,6 @@ class Parser { //! Tokenize a query, returning the raw tokens together with their locations static vector Tokenize(const string &query); - //! Tokenize an error message, returning the raw tokens together with their locations - static vector TokenizeError(const string &error_msg); - //! Returns true if the given text matches a keyword of the parser static KeywordCategory IsKeyword(const string &text); //! Returns a list of all keywords in the parser diff --git a/src/duckdb/src/include/duckdb/parser/qualified_name.hpp b/src/duckdb/src/include/duckdb/parser/qualified_name.hpp index b17abbab6..ee5947806 100644 --- a/src/duckdb/src/include/duckdb/parser/qualified_name.hpp +++ b/src/duckdb/src/include/duckdb/parser/qualified_name.hpp @@ -12,7 +12,6 @@ #include "duckdb/common/exception/parser_exception.hpp" #include "duckdb/parser/keyword_helper.hpp" #include "duckdb/common/string_util.hpp" -#include "duckdb/planner/binding_alias.hpp" namespace duckdb { @@ -23,29 +22,70 @@ struct QualifiedName { //! Parse the (optional) schema and a name from a string in the format of e.g. "schema"."table"; if there is no dot //! the schema will be set to INVALID_SCHEMA - static QualifiedName Parse(const string &input); - string ToString() const; + static QualifiedName Parse(const string &input) { + string catalog; + string schema; + string name; + idx_t idx = 0; + vector entries; + string entry; + normal: + //! quote + for (; idx < input.size(); idx++) { + if (input[idx] == '"') { + idx++; + goto quoted; + } else if (input[idx] == '.') { + goto separator; + } + entry += input[idx]; + } + goto end; + separator: + entries.push_back(entry); + entry = ""; + idx++; + goto normal; + quoted: + //! look for another quote + for (; idx < input.size(); idx++) { + if (input[idx] == '"') { + //! unquote + idx++; + goto normal; + } + entry += input[idx]; + } + throw ParserException("Unterminated quote in qualified name!"); + end: + if (entries.empty()) { + catalog = INVALID_CATALOG; + schema = INVALID_SCHEMA; + name = entry; + } else if (entries.size() == 1) { + catalog = INVALID_CATALOG; + schema = entries[0]; + name = entry; + } else if (entries.size() == 2) { + catalog = entries[0]; + schema = entries[1]; + name = entry; + } else { + throw ParserException("Expected catalog.entry, schema.entry or entry: too many entries found"); + } + return QualifiedName {catalog, schema, name}; + } }; struct QualifiedColumnName { - QualifiedColumnName(); - QualifiedColumnName(string column_p); // NOLINT: allow implicit conversion from string to column name - QualifiedColumnName(string table_p, string column_p); - QualifiedColumnName(const BindingAlias &alias, string column_p); + QualifiedColumnName() { + } + QualifiedColumnName(string table_p, string column_p) : table(std::move(table_p)), column(std::move(column_p)) { + } - string catalog; string schema; string table; string column; - - string ToString() const; - - void Serialize(Serializer &serializer) const; - static QualifiedColumnName Deserialize(Deserializer &deserializer); - - bool IsQualified() const; - - bool operator==(const QualifiedColumnName &rhs) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp b/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp index c17cde85d..1a1052095 100644 --- a/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp +++ b/src/duckdb/src/include/duckdb/parser/qualified_name_set.hpp @@ -16,33 +16,17 @@ namespace duckdb { struct QualifiedColumnHashFunction { uint64_t operator()(const QualifiedColumnName &a) const { - // hash only on the column name - since we match based on the shortest possible match - return StringUtil::CIHash(a.column); + std::hash str_hasher; + return str_hasher(a.schema) ^ str_hasher(a.table) ^ str_hasher(a.column); } }; struct QualifiedColumnEquality { bool operator()(const QualifiedColumnName &a, const QualifiedColumnName &b) const { - // qualified column names follow a prefix comparison - // so "tbl.i" and "i" are equivalent, as are "schema.tbl.i" and "i" - // but "tbl.i" and "tbl2.i" are not equivalent - if (!a.catalog.empty() && !b.catalog.empty() && !StringUtil::CIEquals(a.catalog, b.catalog)) { - return false; - } - if (!a.schema.empty() && !b.schema.empty() && !StringUtil::CIEquals(a.schema, b.schema)) { - return false; - } - if (!a.table.empty() && !b.table.empty() && !StringUtil::CIEquals(a.table, b.table)) { - return false; - } - return StringUtil::CIEquals(a.column, b.column); + return a.schema == b.schema && a.table == b.table && a.column == b.column; } }; using qualified_column_set_t = unordered_set; -template -using qualified_column_map_t = - unordered_map; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/simplified_token.hpp b/src/duckdb/src/include/duckdb/parser/simplified_token.hpp index 7a50824d0..edf066f9b 100644 --- a/src/duckdb/src/include/duckdb/parser/simplified_token.hpp +++ b/src/duckdb/src/include/duckdb/parser/simplified_token.hpp @@ -20,8 +20,7 @@ enum class SimplifiedTokenType : uint8_t { SIMPLIFIED_TOKEN_STRING_CONSTANT, SIMPLIFIED_TOKEN_OPERATOR, SIMPLIFIED_TOKEN_KEYWORD, - SIMPLIFIED_TOKEN_COMMENT, - SIMPLIFIED_TOKEN_ERROR + SIMPLIFIED_TOKEN_COMMENT }; struct SimplifiedToken { diff --git a/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp b/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp index b841559ea..16bc1bb86 100644 --- a/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp +++ b/src/duckdb/src/include/duckdb/parser/tableref/basetableref.hpp @@ -8,13 +8,11 @@ #pragma once -#include "duckdb/common/vector.hpp" -#include "duckdb/main/table_description.hpp" #include "duckdb/parser/tableref.hpp" +#include "duckdb/common/vector.hpp" namespace duckdb { - -//! Represents a TableReference to a base table in a catalog and schema. +//! Represents a TableReference to a base table in the schema class BaseTableRef : public TableRef { public: static constexpr const TableReferenceType TYPE = TableReferenceType::BASE_TABLE; @@ -23,24 +21,23 @@ class BaseTableRef : public TableRef { BaseTableRef() : TableRef(TableReferenceType::BASE_TABLE), catalog_name(INVALID_CATALOG), schema_name(INVALID_SCHEMA) { } - explicit BaseTableRef(const TableDescription &description) - : TableRef(TableReferenceType::BASE_TABLE), catalog_name(description.database), schema_name(description.schema), - table_name(description.table) { - } - //! The catalog name. + //! The catalog name string catalog_name; - //! The schema name. + //! Schema name string schema_name; - //! The table name. + //! Table name string table_name; public: string ToString() const override; bool Equals(const TableRef &other_p) const override; + unique_ptr Copy() override; + + //! Deserializes a blob back into a BaseTableRef void Serialize(Serializer &serializer) const override; + static unique_ptr Deserialize(Deserializer &source); }; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/tokens.hpp b/src/duckdb/src/include/duckdb/parser/tokens.hpp index d18adfd44..f5eeb2c0c 100644 --- a/src/duckdb/src/include/duckdb/parser/tokens.hpp +++ b/src/duckdb/src/include/duckdb/parser/tokens.hpp @@ -104,6 +104,6 @@ class ShowRef; //===--------------------------------------------------------------------===// // Other //===--------------------------------------------------------------------===// -class SampleOptions; +struct SampleOptions; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/parser/transformer.hpp b/src/duckdb/src/include/duckdb/parser/transformer.hpp index 00833a526..0125f2f1f 100644 --- a/src/duckdb/src/include/duckdb/parser/transformer.hpp +++ b/src/duckdb/src/include/duckdb/parser/transformer.hpp @@ -261,8 +261,8 @@ class Transformer { //===--------------------------------------------------------------------===// // Constraints transform //===--------------------------------------------------------------------===// - unique_ptr TransformConstraint(duckdb_libpgquery::PGConstraint &constraint); - unique_ptr TransformConstraint(duckdb_libpgquery::PGConstraint &constraint, ColumnDefinition &column, + unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell &cell); + unique_ptr TransformConstraint(duckdb_libpgquery::PGListCell &cell, ColumnDefinition &column, idx_t index); //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/include/duckdb/planner/bind_context.hpp b/src/duckdb/src/include/duckdb/planner/bind_context.hpp index 8234805e7..e4b63f830 100644 --- a/src/duckdb/src/include/duckdb/planner/bind_context.hpp +++ b/src/duckdb/src/include/duckdb/planner/bind_context.hpp @@ -10,7 +10,6 @@ #include "duckdb/catalog/catalog.hpp" #include "duckdb/common/case_insensitive_map.hpp" -#include "duckdb/common/column_index.hpp" #include "duckdb/common/reference_map.hpp" #include "duckdb/common/exception/binder_exception.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" @@ -31,12 +30,10 @@ class TableCatalogEntry; class TableFunctionCatalogEntry; struct UsingColumnSet { - BindingAlias primary_binding; - vector bindings; + string primary_binding; + unordered_set bindings; }; -enum class ColumnBindType { EXPAND_GENERATED_COLUMNS, DO_NOT_EXPAND_GENERATED_COLUMNS }; - //! The BindContext object keeps track of all the tables and columns that are //! encountered during the binding process. class BindContext { @@ -49,10 +46,10 @@ class BindContext { public: //! Given a column name, find the matching table it belongs to. Throws an //! exception if no table has a column of the given name. - optional_ptr GetMatchingBinding(const string &column_name); + string GetMatchingBinding(const string &column_name); //! Like GetMatchingBinding, but instead of throwing an error if multiple tables have the same binding it will //! return a list of all the matching ones - vector> GetMatchingBindings(const string &column_name); + unordered_set GetMatchingBindings(const string &column_name); //! Like GetMatchingBindings, but returns the top 3 most similar bindings (in levenshtein distance) instead of the //! matching ones vector GetSimilarBindings(const string &column_name); @@ -64,45 +61,38 @@ class BindContext { string BindColumn(PositionalReferenceExpression &ref, string &table_name, string &column_name); unique_ptr PositionToColumn(PositionalReferenceExpression &ref); - unique_ptr ExpandGeneratedColumn(TableBinding &table_binding, const string &column_name); - - unique_ptr - CreateColumnReference(const string &table_name, const string &column_name, - ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); - unique_ptr - CreateColumnReference(const string &schema_name, const string &table_name, const string &column_name, - ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); - unique_ptr - CreateColumnReference(const string &catalog_name, const string &schema_name, const string &table_name, - const string &column_name, - ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); - unique_ptr - CreateColumnReference(const BindingAlias &table_alias, const string &column_name, - ColumnBindType bind_type = ColumnBindType::EXPAND_GENERATED_COLUMNS); + unique_ptr ExpandGeneratedColumn(const string &table_name, const string &column_name); + + unique_ptr CreateColumnReference(const string &table_name, const string &column_name); + unique_ptr CreateColumnReference(const string &schema_name, const string &table_name, + const string &column_name); + unique_ptr CreateColumnReference(const string &catalog_name, const string &schema_name, + const string &table_name, const string &column_name); //! Generate column expressions for all columns that are present in the //! referenced tables. This is used to resolve the * expression in a //! selection list. void GenerateAllColumnExpressions(StarExpression &expr, vector> &new_select_list); + //! Check if the given (binding, column_name) is in the exclusion/replacement lists. + //! Returns true if it is in one of these lists, and should therefore be skipped. + bool CheckExclusionList(StarExpression &expr, const string &column_name, + vector> &new_select_list, + case_insensitive_set_t &excluded_columns); - const vector> &GetBindingsList() { + const vector> &GetBindingsList() { return bindings_list; } - vector GetBindingAliases(); void GetTypesAndNames(vector &result_names, vector &result_types); //! Adds a base table with the given alias to the BindContext. void AddBaseTable(idx_t index, const string &alias, const vector &names, const vector &types, - vector &bound_column_ids, StandardEntry &entry, bool add_row_id = true); - void AddBaseTable(idx_t index, const string &alias, const vector &names, const vector &types, - vector &bound_column_ids, const string &table_name); + vector &bound_column_ids, StandardEntry *entry, bool add_row_id = true); //! Adds a call to a table function with the given alias to the BindContext. void AddTableFunction(idx_t index, const string &alias, const vector &names, - const vector &types, vector &bound_column_ids, - optional_ptr entry); + const vector &types, vector &bound_column_ids, StandardEntry *entry); //! Adds a table view with a given alias to the BindContext. - void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry &view); + void AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, ViewCatalogEntry *view); //! Adds a subquery with a given alias to the BindContext. void AddSubquery(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery); //! Adds a subquery with a given alias to the BindContext. @@ -127,18 +117,17 @@ class BindContext { //! column sets with the same name) throw an exception. optional_ptr GetUsingBinding(const string &column_name); //! Returns any using column set for the given column name, or nullptr if there is none - optional_ptr GetUsingBinding(const string &column_name, const BindingAlias &binding); + optional_ptr GetUsingBinding(const string &column_name, const string &binding_name); //! Erase a using binding from the set of using bindings void RemoveUsingBinding(const string &column_name, UsingColumnSet &set); //! Transfer a using binding from one bind context to this bind context void TransferUsingBinding(BindContext ¤t_context, optional_ptr current_set, - UsingColumnSet &new_set, const string &using_column); + UsingColumnSet &new_set, const string &binding, const string &using_column); //! Fetch the actual column name from the given binding, or throws if none exists //! This can be different from "column_name" because of case insensitivity //! (e.g. "column_name" might return "COLUMN_NAME") - string GetActualColumnName(const BindingAlias &binding_alias, const string &column_name); - string GetActualColumnName(Binding &binding, const string &column_name); + string GetActualColumnName(const string &binding, const string &column_name); case_insensitive_map_t> GetCTEBindings() { return cte_bindings; @@ -155,27 +144,21 @@ class BindContext { //! Add all the bindings from a BindContext to this BindContext. The other BindContext is destroyed in the process. void AddContext(BindContext other); //! For semi and anti joins we remove the binding context of the right table after binding the condition. - void RemoveContext(const vector &aliases); + void RemoveContext(vector> &other_bindings_list); //! Gets a binding of the specified name. Returns a nullptr and sets the out_error if the binding could not be //! found. optional_ptr GetBinding(const string &name, ErrorData &out_error); - optional_ptr GetBinding(const BindingAlias &alias, ErrorData &out_error); - - optional_ptr GetBinding(const BindingAlias &alias, const string &column_name, ErrorData &out_error); - - //! Get all bindings that match a specific binding alias - returns an error if none match - vector> GetBindings(const BindingAlias &alias, ErrorData &out_error); - private: - void AddBinding(unique_ptr binding); - static string AmbiguityException(const BindingAlias &alias, const vector> &bindings); + void AddBinding(const string &alias, unique_ptr binding); private: Binder &binder; + //! The set of bindings + case_insensitive_map_t> bindings; //! The list of bindings in insertion order - vector> bindings_list; + vector> bindings_list; //! The set of columns used in USING join conditions case_insensitive_map_t> using_columns; //! Using column sets diff --git a/src/duckdb/src/include/duckdb/planner/binder.hpp b/src/duckdb/src/include/duckdb/planner/binder.hpp index 0cd7c0e6a..cdfc67d1b 100644 --- a/src/duckdb/src/include/duckdb/planner/binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/binder.hpp @@ -24,7 +24,6 @@ #include "duckdb/planner/bound_tokens.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/joinside.hpp" -#include "duckdb/planner/bound_constraint.hpp" #include "duckdb/planner/logical_operator.hpp" #include "duckdb/planner/tableref/bound_delimgetref.hpp" @@ -50,6 +49,7 @@ class BoundConstraint; struct CreateInfo; struct BoundCreateTableInfo; +struct BoundCreateFunctionInfo; struct CommonTableExpressionInfo; struct BoundParameterMap; struct BoundPragmaInfo; @@ -125,7 +125,6 @@ class Binder : public enable_shared_from_this { vector> &bound_defaults); static unique_ptr BindCreateTableCheckpoint(unique_ptr info, SchemaCatalogEntry &schema); - static vector> BindConstraints(ClientContext &context, const vector> &constraints, const string &table_name, const ColumnList &columns); @@ -134,11 +133,6 @@ class Binder : public enable_shared_from_this { vector> BindConstraints(const TableCatalogEntry &table); vector> BindNewConstraints(vector> &constraints, const string &table_name, const ColumnList &columns); - unique_ptr BindConstraint(Constraint &constraint, const string &table, const ColumnList &columns); - unique_ptr BindUniqueConstraint(Constraint &constraint, const string &table, - const ColumnList &columns); - - BoundStatement BindAlterAddIndex(BoundStatement &result, CatalogEntry &entry, unique_ptr alter_info); void SetCatalogLookupCallback(catalog_entry_callback_t callback); void BindCreateViewInfo(CreateViewInfo &base); @@ -195,11 +189,11 @@ class Binder : public enable_shared_from_this { void BindLogicalType(LogicalType &type, optional_ptr catalog = nullptr, const string &schema = INVALID_SCHEMA); - optional_ptr GetMatchingBinding(const string &table_name, const string &column_name, ErrorData &error); - optional_ptr GetMatchingBinding(const string &schema_name, const string &table_name, - const string &column_name, ErrorData &error); - optional_ptr GetMatchingBinding(const string &catalog_name, const string &schema_name, - const string &table_name, const string &column_name, ErrorData &error); + bool HasMatchingBinding(const string &table_name, const string &column_name, ErrorData &error); + bool HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name, + ErrorData &error); + bool HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name, + const string &column_name, ErrorData &error); void SetBindingMode(BindingMode mode); BindingMode GetBindingMode(); @@ -210,11 +204,6 @@ class Binder : public enable_shared_from_this { optional_ptr GetRootStatement() { return root_statement; } - CatalogEntryRetriever &EntryRetriever() { - return entry_retriever; - } - //! Returns a ColumnRefExpression after it was resolved (i.e. past the STAR expression/USING clauses) - static optional_ptr GetResolvedColumnExpression(ParsedExpression &root_expr); void SetCanContainNulls(bool can_contain_nulls); void SetAlwaysRequireRebind(); @@ -261,8 +250,7 @@ class Binder : public enable_shared_from_this { //! Bind the expressions of generated columns to check for errors void BindGeneratedColumns(BoundCreateTableInfo &info); //! Bind the default values of the columns of a table - void BindDefaultValues(const ColumnList &columns, vector> &bound_defaults, - const string &catalog = "", const string &schema = ""); + void BindDefaultValues(const ColumnList &columns, vector> &bound_defaults); //! Bind a limit value (LIMIT or OFFSET) BoundLimitNode BindLimitValue(OrderBinder &order_binder, unique_ptr limit_val, bool is_percentage, bool is_offset); @@ -396,12 +384,12 @@ class Binder : public enable_shared_from_this { vector &target_types, unique_ptr op); - BindingAlias FindBinding(const string &using_column, const string &join_side); - bool TryFindBinding(const string &using_column, const string &join_side, BindingAlias &result); + string FindBinding(const string &using_column, const string &join_side); + bool TryFindBinding(const string &using_column, const string &join_side, string &result); void AddUsingBindingSet(unique_ptr set); - BindingAlias RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, - const string &column_name, const string &join_side); + string RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, + const string &column_name, const string &join_side); void AddCTEMap(CommonTableExpressionMap &cte_map); diff --git a/src/duckdb/src/include/duckdb/planner/binding_alias.hpp b/src/duckdb/src/include/duckdb/planner/binding_alias.hpp deleted file mode 100644 index 2d85b521e..000000000 --- a/src/duckdb/src/include/duckdb/planner/binding_alias.hpp +++ /dev/null @@ -1,44 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/planner/binding_alias.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/case_insensitive_map.hpp" - -namespace duckdb { -class StandardEntry; - -struct BindingAlias { - BindingAlias(); - explicit BindingAlias(string alias); - BindingAlias(string schema, string alias); - BindingAlias(string catalog, string schema, string alias); - explicit BindingAlias(const StandardEntry &entry); - - bool IsSet() const; - const string &GetAlias() const; - - const string &GetCatalog() const { - return catalog; - } - const string &GetSchema() const { - return schema; - } - - bool Matches(const BindingAlias &other) const; - bool operator==(const BindingAlias &other) const; - string ToString() const; - -private: - string catalog; - string schema; - string alias; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/bound_result_modifier.hpp b/src/duckdb/src/include/duckdb/planner/bound_result_modifier.hpp index ab0b64dde..6d2b4935f 100644 --- a/src/duckdb/src/include/duckdb/planner/bound_result_modifier.hpp +++ b/src/duckdb/src/include/duckdb/planner/bound_result_modifier.hpp @@ -154,7 +154,6 @@ class BoundOrderModifier : public BoundResultModifier { //! Remove unneeded/duplicate order elements. //! Returns true of orders is not empty. - static bool Simplify(vector &orders, const vector> &groups); bool Simplify(const vector> &groups); }; diff --git a/src/duckdb/src/include/duckdb/planner/collation_binding.hpp b/src/duckdb/src/include/duckdb/planner/collation_binding.hpp index aa82a71a2..f9f86d69d 100644 --- a/src/duckdb/src/include/duckdb/planner/collation_binding.hpp +++ b/src/duckdb/src/include/duckdb/planner/collation_binding.hpp @@ -9,7 +9,6 @@ #pragma once #include "duckdb/function/cast/default_casts.hpp" -#include "duckdb/common/enums/collation_type.hpp" namespace duckdb { struct MapCastInfo; @@ -17,7 +16,7 @@ struct MapCastNode; struct DBConfig; typedef bool (*try_push_collation_t)(ClientContext &context, unique_ptr &source, - const LogicalType &sql_type, CollationType type); + const LogicalType &sql_type); struct CollationCallback { explicit CollationCallback(try_push_collation_t try_push_collation_p) : try_push_collation(try_push_collation_p) { @@ -35,8 +34,8 @@ class CollationBinding { DUCKDB_API static CollationBinding &Get(DatabaseInstance &db); DUCKDB_API void RegisterCollation(CollationCallback callback); - DUCKDB_API bool PushCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type, - CollationType type) const; + DUCKDB_API bool PushCollation(ClientContext &context, unique_ptr &source, + const LogicalType &sql_type) const; private: vector collations; diff --git a/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp b/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp index b03f6ffef..4c7468d60 100644 --- a/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp +++ b/src/duckdb/src/include/duckdb/planner/constraints/bound_unique_constraint.hpp @@ -19,23 +19,22 @@ class BoundUniqueConstraint : public BoundConstraint { static constexpr const ConstraintType TYPE = ConstraintType::UNIQUE; public: - BoundUniqueConstraint(vector keys_p, physical_index_set_t key_set_p, const bool is_primary_key) - : BoundConstraint(ConstraintType::UNIQUE), keys(std::move(keys_p)), key_set(std::move(key_set_p)), + BoundUniqueConstraint(vector keys, logical_index_set_t key_set, bool is_primary_key) + : BoundConstraint(ConstraintType::UNIQUE), keys(std::move(keys)), key_set(std::move(key_set)), is_primary_key(is_primary_key) { - #ifdef DEBUG - D_ASSERT(keys.size() == key_set.size()); - for (auto &key : keys) { - D_ASSERT(key_set.find(key) != key_set.end()); + D_ASSERT(this->keys.size() == this->key_set.size()); + for (auto &key : this->keys) { + D_ASSERT(this->key_set.find(key) != this->key_set.end()); } #endif } - //! The keys that define the unique constraint. - vector keys; - //! The same keys but stored as an unordered set. - physical_index_set_t key_set; - //! Whether this is a PRIMARY KEY constraint, or a UNIQUE constraint. + //! The keys that define the unique constraint + vector keys; + //! The same keys but stored as an unordered set + logical_index_set_t key_set; + //! Whether or not the unique constraint is a primary key bool is_primary_key; }; diff --git a/src/duckdb/src/include/duckdb/planner/expression.hpp b/src/duckdb/src/include/duckdb/planner/expression.hpp index 97094bbde..a7f9045f9 100644 --- a/src/duckdb/src/include/duckdb/planner/expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression.hpp @@ -32,12 +32,10 @@ class Expression : public BaseExpression { bool HasSubquery() const override; bool IsScalar() const override; bool HasParameter() const override; - virtual bool IsVolatile() const; virtual bool IsConsistent() const; virtual bool PropagatesNullValues() const; virtual bool IsFoldable() const; - virtual bool CanThrow() const; hash_t Hash() const override; diff --git a/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp b/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp index c625fb4f9..d45ac502f 100644 --- a/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression/bound_cast_expression.hpp @@ -54,8 +54,6 @@ class BoundCastExpression : public Expression { unique_ptr Copy() const override; - bool CanThrow() const override; - void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/planner/expression/bound_function_expression.hpp b/src/duckdb/src/include/duckdb/planner/expression/bound_function_expression.hpp index 1698670bf..e3d70c285 100644 --- a/src/duckdb/src/include/duckdb/planner/expression/bound_function_expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression/bound_function_expression.hpp @@ -37,7 +37,6 @@ class BoundFunctionExpression : public Expression { bool IsVolatile() const override; bool IsConsistent() const override; bool IsFoldable() const override; - bool CanThrow() const override; string ToString() const override; bool PropagatesNullValues() const override; hash_t Hash() const override; diff --git a/src/duckdb/src/include/duckdb/planner/expression/bound_subquery_expression.hpp b/src/duckdb/src/include/duckdb/planner/expression/bound_subquery_expression.hpp index 31501dd8c..9572036ab 100644 --- a/src/duckdb/src/include/duckdb/planner/expression/bound_subquery_expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression/bound_subquery_expression.hpp @@ -32,12 +32,12 @@ class BoundSubqueryExpression : public Expression { unique_ptr subquery; //! The subquery type SubqueryType subquery_type; - //! the child expressions to compare with (in case of IN, ANY, ALL operators) - vector> children; + //! the child expression to compare with (in case of IN, ANY, ALL operators) + unique_ptr child; //! The comparison type of the child expression with the subquery (in case of ANY, ALL operators) ExpressionType comparison_type; - //! The LogicalTypes of the subquery result. Only used for ANY expressions. - vector child_types; + //! The LogicalType of the subquery result. Only used for ANY expressions. + LogicalType child_type; //! The target LogicalType of the subquery result (i.e. to which type it should be casted, if child_type <> //! child_target). Only used for ANY expressions. LogicalType child_target; diff --git a/src/duckdb/src/include/duckdb/planner/expression/bound_window_expression.hpp b/src/duckdb/src/include/duckdb/planner/expression/bound_window_expression.hpp index acd76a42f..b105c66c5 100644 --- a/src/duckdb/src/include/duckdb/planner/expression/bound_window_expression.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression/bound_window_expression.hpp @@ -54,11 +54,6 @@ class BoundWindowExpression : public Expression { unique_ptr offset_expr; unique_ptr default_expr; - //! The set of argument ordering clauses - //! These are distinct from the frame ordering clauses e.g., the "x" in - //! FIRST_VALUE(a ORDER BY x) OVER (PARTITION BY p ORDER BY s) - vector arg_orders; - //! Statistics belonging to the other expressions (start, end, offset, default) vector> expr_stats; @@ -73,7 +68,6 @@ class BoundWindowExpression : public Expression { string ToString() const override; //! The number of ordering clauses the functions share - static idx_t GetSharedOrders(const vector &lhs, const vector &rhs); idx_t GetSharedOrders(const BoundWindowExpression &other) const; bool PartitionsAreEquivalent(const BoundWindowExpression &other) const; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp index c73ea546d..5206f8a8f 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder.hpp @@ -22,7 +22,6 @@ #include "duckdb/planner/expression/bound_lambda_expression.hpp" #include "duckdb/function/scalar_function.hpp" #include "duckdb/planner/column_binding.hpp" -#include "duckdb/common/enums/collation_type.hpp" namespace duckdb { @@ -108,7 +107,7 @@ class ExpressionBinder { //! Returns a qualified column reference from a column reference with column_names.size() > 2 unique_ptr QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, ErrorData &error); //! Returns a qualified column reference from a column reference - virtual unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error); + unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error); //! Enables special-handling of lambda parameters by tracking them in the lambda_params vector void QualifyColumnNamesInLambda(FunctionExpression &function, vector> &lambda_params); //! Recursively qualifies the column references in the (children) of the expression. Passes on the @@ -117,10 +116,8 @@ class ExpressionBinder { const bool within_function_expression = false); //! Entry point for qualifying the column references of the expression static void QualifyColumnNames(Binder &binder, unique_ptr &expr); - static void QualifyColumnNames(ExpressionBinder &binder, unique_ptr &expr); - static bool PushCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type, - CollationType type = CollationType::ALL_COLLATIONS); + static bool PushCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type); static void TestCollation(ClientContext &context, const string &collation); BindResult BindCorrelatedColumns(unique_ptr &expr, ErrorData error_message); @@ -223,9 +220,6 @@ class ExpressionBinder { //! Returns true if the function name is an alias for the UNNEST function static bool IsUnnestFunction(const string &function_name); BindResult TryBindLambdaOrJson(FunctionExpression &function, idx_t depth, CatalogEntry &func); - - unique_ptr QualifyColumnNameWithManyDotsInternal(ColumnRefExpression &col_ref, ErrorData &error, - idx_t &struct_extract_start); virtual void ThrowIfUnnestInLambda(const ColumnBinding &column_binding); }; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp index b111cc368..4cb65dab0 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder/having_binder.hpp @@ -25,8 +25,6 @@ class HavingBinder : public BaseSelectBinder { BindResult BindWindow(WindowExpression &expr, idx_t depth) override; BindResult BindColumnRef(unique_ptr &expr_ptr, idx_t depth, bool root_expression) override; - unique_ptr QualifyColumnName(ColumnRefExpression &col_ref, ErrorData &error) override; - private: ColumnAliasBinder column_alias_binder; AggregateHandling aggregate_handling; diff --git a/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp b/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp index f8972d13e..0d2ac67f0 100644 --- a/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +++ b/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp @@ -10,27 +10,22 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/common/unordered_map.hpp" -#include "duckdb/execution/index/bound_index.hpp" -#include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/planner/expression_binder.hpp" +#include "duckdb/execution/index/bound_index.hpp" +#include "duckdb/execution/index/unbound_index.hpp" namespace duckdb { class BoundColumnRefExpression; -//! The IndexBinder binds indexes and expressions within index statements. +//! The IndexBinder is responsible for binding indexes, as well as expressions within an index statement class IndexBinder : public ExpressionBinder { public: IndexBinder(Binder &binder, ClientContext &context, optional_ptr table = nullptr, optional_ptr info = nullptr); unique_ptr BindIndex(const UnboundIndex &index); - unique_ptr BindCreateIndex(ClientContext &context, unique_ptr create_index_info, - TableCatalogEntry &table_entry, unique_ptr plan, - unique_ptr alter_table_info); - - static void InitCreateIndexInfo(LogicalGet &get, CreateIndexInfo &info, const string &schema); protected: BindResult BindExpression(unique_ptr &expr_ptr, idx_t depth, @@ -38,7 +33,7 @@ class IndexBinder : public ExpressionBinder { string UnsupportedAggregateMessage() override; private: - // Only for WAL replay. + // only for WAL replay optional_ptr table; optional_ptr info; }; diff --git a/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp index 49fcf6e95..1713ad67f 100644 --- a/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/filter/conjunction_filter.hpp @@ -12,7 +12,6 @@ #include "duckdb/common/vector.hpp" namespace duckdb { - class ConjunctionFilter : public TableFilter { public: explicit ConjunctionFilter(TableFilterType filter_type_p) : TableFilter(filter_type_p) { @@ -36,6 +35,8 @@ class ConjunctionOrFilter : public ConjunctionFilter { public: ConjunctionOrFilter(); + +public: FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; string ToString(const string &column_name) override; bool Equals(const TableFilter &other) const override; diff --git a/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp deleted file mode 100644 index fbb32faff..000000000 --- a/src/duckdb/src/include/duckdb/planner/filter/dynamic_filter.hpp +++ /dev/null @@ -1,48 +0,0 @@ - -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/planner/filter/dynamic_filter.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/planner/table_filter.hpp" -#include "duckdb/common/types/value.hpp" -#include "duckdb/common/enums/expression_type.hpp" - -namespace duckdb { - -struct DynamicFilterData { - mutex lock; - unique_ptr filter; - bool initialized = false; - - void SetValue(Value val); - void Reset(); -}; - -class DynamicFilter : public TableFilter { -public: - static constexpr const TableFilterType TYPE = TableFilterType::DYNAMIC_FILTER; - -public: - DynamicFilter(); - explicit DynamicFilter(shared_ptr filter_data); - - //! The shared, dynamic filter data - shared_ptr filter_data; - -public: - FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; - string ToString(const string &column_name) override; - bool Equals(const TableFilter &other) const override; - unique_ptr Copy() const override; - unique_ptr ToExpression(const Expression &column) const override; - void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &deserializer); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/filter/in_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/in_filter.hpp deleted file mode 100644 index 19e3862a3..000000000 --- a/src/duckdb/src/include/duckdb/planner/filter/in_filter.hpp +++ /dev/null @@ -1,37 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/planner/filter/in_filter.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/planner/table_filter.hpp" -#include "duckdb/common/types/value.hpp" - -namespace duckdb { - -class InFilter : public TableFilter { -public: - static constexpr const TableFilterType TYPE = TableFilterType::IN_FILTER; - -public: - explicit InFilter(vector values); - InFilter(vector values, bool origin_is_hash_join); - - vector values; - bool origin_is_hash_join; - -public: - FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; - string ToString(const string &column_name) override; - bool Equals(const TableFilter &other) const override; - unique_ptr Copy() const override; - unique_ptr ToExpression(const Expression &column) const override; - void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &deserializer); -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp b/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp deleted file mode 100644 index d694674d8..000000000 --- a/src/duckdb/src/include/duckdb/planner/filter/optional_filter.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/planner/filter/optional_filter.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/planner/table_filter.hpp" - -namespace duckdb { - -class OptionalFilter : public TableFilter { -public: - static constexpr const TableFilterType TYPE = TableFilterType::OPTIONAL_FILTER; - -public: - explicit OptionalFilter(unique_ptr filter = nullptr); - - string ToString(const string &column_name) override; - unique_ptr Copy() const override; - unique_ptr ToExpression(const Expression &column) const override; - FilterPropagateResult CheckStatistics(BaseStatistics &stats) override; - void Serialize(Serializer &serializer) const override; - static unique_ptr Deserialize(Deserializer &deserializer); - -public: - // optional child filters - unique_ptr child_filter; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/logical_operator.hpp b/src/duckdb/src/include/duckdb/planner/logical_operator.hpp index e7f533bdd..b0611f7e3 100644 --- a/src/duckdb/src/include/duckdb/planner/logical_operator.hpp +++ b/src/duckdb/src/include/duckdb/planner/logical_operator.hpp @@ -80,10 +80,6 @@ class LogicalOperator { return true; }; - virtual bool HasProjectionMap() const { - return false; - } - //! Returns the set of table indexes of this operator virtual vector GetTableIndex() const; diff --git a/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp b/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp index b11065f67..ff0fd75de 100644 --- a/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp +++ b/src/duckdb/src/include/duckdb/planner/logical_operator_visitor.hpp @@ -35,9 +35,6 @@ class LogicalOperatorVisitor { //! Automatically calls the Visit method for Expression children of the current operator. Can be overloaded to //! change this behavior. void VisitOperatorExpressions(LogicalOperator &op); - //! Alternatives for VisitOperatorChildren for operators that have a projection map - void VisitOperatorWithProjectionMapChildren(LogicalOperator &op); - void VisitChildOfOperatorWithProjectionMap(LogicalOperator &child, vector &projection_map); // The VisitExpressionChildren method is called at the end of every call to VisitExpression to recursively visit all // expressions in an expression tree. It can be overloaded to prevent automatically visiting the entire tree. diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp index e361a2a6e..fd095f534 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_comparison_join.hpp @@ -70,8 +70,6 @@ class LogicalComparisonJoin : public LogicalJoin { const unordered_set &right_bindings, vector> &expressions, vector &conditions, vector> &arbitrary_expressions); - - bool HasEquality(idx_t &range_count) const; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp index 2f04c7ee4..e9925cb40 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_create_index.hpp @@ -20,15 +20,15 @@ class LogicalCreateIndex : public LogicalOperator { public: LogicalCreateIndex(unique_ptr info_p, vector> expressions_p, - TableCatalogEntry &table_p, unique_ptr alter_table_info = nullptr); + TableCatalogEntry &table_p); - //! Index creation information. + // Info for index creation unique_ptr info; - //! The table to create the index for. + + //! The table to create the index for TableCatalogEntry &table; - // Alter table information. - unique_ptr alter_table_info; - //! Unbound expressions of the indexed columns. + + //! Unbound expressions to be used in the optimizer vector> unbound_expressions; public: @@ -39,8 +39,8 @@ class LogicalCreateIndex : public LogicalOperator { void ResolveTypes() override; private: - LogicalCreateIndex(ClientContext &context, unique_ptr info, vector> expressions, - unique_ptr alter_info); - TableCatalogEntry &BindTable(ClientContext &context, CreateIndexInfo &info_p); + LogicalCreateIndex(ClientContext &context, unique_ptr info, vector> expressions); + + TableCatalogEntry &BindTable(ClientContext &context, CreateIndexInfo &info); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp index b6f8323a6..acd5771b9 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_filter.hpp @@ -26,10 +26,6 @@ class LogicalFilter : public LogicalOperator { public: vector GetColumnBindings() override; - bool HasProjectionMap() const override { - return !projection_map.empty(); - } - void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp index 0a73d12cb..07af9e2ea 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_get.hpp @@ -23,8 +23,7 @@ class LogicalGet : public LogicalOperator { public: LogicalGet(idx_t table_index, TableFunction function, unique_ptr bind_data, - vector returned_types, vector returned_names, - LogicalType rowid_type = LogicalType(LogicalType::ROW_TYPE)); + vector returned_types, vector returned_names); //! The table index in the current bind context idx_t table_index; @@ -50,9 +49,8 @@ class LogicalGet : public LogicalOperator { vector input_table_names; //! For a table-in-out function, the set of projected input columns vector projected_input; - //! Currently stores File Filters (as strings) applied by hive partitioning/complex filter pushdown and sample rate - //! pushed down into the table scan - //! Stored so the can be included in explain output + //! Currently stores File Filters (as strings) applied by hive partitioning/complex filter pushdown + //! Stored so they can be included in explain output ExtraOperatorInfo extra_info; //! Contains a reference to dynamically generated table filters (through e.g. a join up in the tree) shared_ptr dynamic_filters; @@ -63,11 +61,11 @@ class LogicalGet : public LogicalOperator { optional_ptr GetTable() const; public: - void SetColumnIds(vector &&column_ids); + void SetColumnIds(vector &&column_ids); void AddColumnId(column_t column_id); void ClearColumnIds(); - const vector &GetColumnIds() const; - vector &GetMutableColumnIds(); + const vector &GetColumnIds() const; + vector &GetMutableColumnIds(); vector GetColumnBindings() override; idx_t EstimateCardinality(ClientContext &context) override; @@ -80,10 +78,6 @@ class LogicalGet : public LogicalOperator { void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); - LogicalType GetRowIdType() const { - return rowid_type; - } - protected: void ResolveTypes() override; @@ -92,9 +86,6 @@ class LogicalGet : public LogicalOperator { private: //! Bound column IDs - vector column_ids; - - //! The type of the rowid column - LogicalType rowid_type = LogicalType(LogicalType::ROW_TYPE); + vector column_ids; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_insert.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_insert.hpp index c20c33a54..c8eb3997f 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_insert.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_insert.hpp @@ -60,8 +60,6 @@ class LogicalInsert : public LogicalOperator { vector columns_to_fetch; // The columns to fetch from the 'source' table vector source_columns; - //! True, if the INSERT OR REPLACE requires delete + insert. - bool update_is_del_and_insert; public: void Serialize(Serializer &serializer) const override; diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp index 9e278886c..a6a63de66 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_join.hpp @@ -27,10 +27,6 @@ class LogicalJoin : public LogicalOperator { static void GetTableReferences(LogicalOperator &op, unordered_set &bindings); static void GetExpressionBindings(Expression &expr, unordered_set &bindings); - bool HasProjectionMap() const override { - return !left_projection_map.empty() || !right_projection_map.empty(); - } - //! The type of the join (INNER, OUTER, etc...) JoinType join_type; //! Table index used to refer to the MARK column (in case of a MARK join) diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp index a7bdf50d8..c16193ff8 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_order.hpp @@ -24,15 +24,11 @@ class LogicalOrder : public LogicalOperator { explicit LogicalOrder(vector orders); vector orders; - vector projection_map; + vector projections; public: vector GetColumnBindings() override; - bool HasProjectionMap() const override { - return !projection_map.empty(); - } - void Serialize(Serializer &serializer) const override; static unique_ptr Deserialize(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/planner/operator/logical_top_n.hpp b/src/duckdb/src/include/duckdb/planner/operator/logical_top_n.hpp index 6a2f38ab6..cc19ea6b7 100644 --- a/src/duckdb/src/include/duckdb/planner/operator/logical_top_n.hpp +++ b/src/duckdb/src/include/duckdb/planner/operator/logical_top_n.hpp @@ -12,7 +12,6 @@ #include "duckdb/planner/logical_operator.hpp" namespace duckdb { -struct DynamicFilterData; //! LogicalTopN represents a comibination of ORDER BY and LIMIT clause, using Min/Max Heap class LogicalTopN : public LogicalOperator { @@ -20,16 +19,15 @@ class LogicalTopN : public LogicalOperator { static constexpr const LogicalOperatorType TYPE = LogicalOperatorType::LOGICAL_TOP_N; public: - LogicalTopN(vector orders, idx_t limit, idx_t offset); - ~LogicalTopN() override; + LogicalTopN(vector orders, idx_t limit, idx_t offset) + : LogicalOperator(LogicalOperatorType::LOGICAL_TOP_N), orders(std::move(orders)), limit(limit), offset(offset) { + } vector orders; //! The maximum amount of elements to emit idx_t limit; //! The offset from the start to begin emitting elements idx_t offset; - //! Dynamic table filter (if any) - shared_ptr dynamic_filter; public: vector GetColumnBindings() override { diff --git a/src/duckdb/src/include/duckdb/planner/table_binding.hpp b/src/duckdb/src/include/duckdb/planner/table_binding.hpp index 50631f57a..551ab9b00 100644 --- a/src/duckdb/src/include/duckdb/planner/table_binding.hpp +++ b/src/duckdb/src/include/duckdb/planner/table_binding.hpp @@ -14,8 +14,6 @@ #include "duckdb/parser/parsed_expression.hpp" #include "duckdb/planner/expression_binder.hpp" #include "duckdb/catalog/catalog_entry/table_column_type.hpp" -#include "duckdb/planner/binding_alias.hpp" -#include "duckdb/common/column_index.hpp" namespace duckdb { class BindContext; @@ -33,14 +31,14 @@ enum class BindingType { BASE, TABLE, DUMMY, CATALOG_ENTRY }; //! A Binding represents a binding to a table, table-producing function or subquery with a specified table index. struct Binding { - Binding(BindingType binding_type, BindingAlias alias, vector types, vector names, idx_t index, - LogicalType rowid_type = LogicalType(LogicalType::ROW_TYPE)); + Binding(BindingType binding_type, const string &alias, vector types, vector names, + idx_t index); virtual ~Binding() = default; //! The type of Binding BindingType binding_type; //! The alias of the binding - BindingAlias alias; + string alias; //! The table index of the binding idx_t index; //! The types of the bound columns @@ -50,8 +48,6 @@ struct Binding { //! Name -> index for the names case_insensitive_map_t name_map; - LogicalType rowid_type; - public: bool TryGetBindingIndex(const string &column_name, column_t &column_index); column_t GetBindingIndex(const string &column_name); @@ -59,10 +55,6 @@ struct Binding { virtual ErrorData ColumnNotFoundError(const string &column_name) const; virtual BindResult Bind(ColumnRefExpression &colref, idx_t depth); virtual optional_ptr GetStandardEntry(); - string GetAlias() const; - - static BindingAlias GetAlias(const string &explicit_alias, const StandardEntry &entry); - static BindingAlias GetAlias(const string &explicit_alias, optional_ptr entry); public: template @@ -103,11 +95,11 @@ struct TableBinding : public Binding { public: TableBinding(const string &alias, vector types, vector names, - vector &bound_column_ids, optional_ptr entry, idx_t index, + vector &bound_column_ids, optional_ptr entry, idx_t index, bool add_row_id = false); //! A reference to the set of bound column ids - vector &bound_column_ids; + vector &bound_column_ids; //! The underlying catalog entry (if any) optional_ptr entry; @@ -117,7 +109,7 @@ struct TableBinding : public Binding { optional_ptr GetStandardEntry() override; ErrorData ColumnNotFoundError(const string &column_name) const override; // These are columns that are present in the name_map, appearing in the order that they're bound - const vector &GetBoundColumnIds() const; + const vector &GetBoundColumnIds() const; protected: ColumnBinding GetColumnBinding(column_t column_index); diff --git a/src/duckdb/src/include/duckdb/planner/table_filter.hpp b/src/duckdb/src/include/duckdb/planner/table_filter.hpp index b39d529b0..edcb975cd 100644 --- a/src/duckdb/src/include/duckdb/planner/table_filter.hpp +++ b/src/duckdb/src/include/duckdb/planner/table_filter.hpp @@ -15,7 +15,6 @@ #include "duckdb/common/types.hpp" #include "duckdb/common/unordered_map.hpp" #include "duckdb/planner/column_binding.hpp" -#include "duckdb/common/column_index.hpp" namespace duckdb { class BaseStatistics; @@ -25,14 +24,11 @@ class PhysicalTableScan; enum class TableFilterType : uint8_t { CONSTANT_COMPARISON = 0, // constant comparison (e.g. =C, >C, >=C, TARGET &Cast() { if (filter_type != TARGET::TYPE) { - throw InternalException("Failed to cast to type - table filter type mismatch"); + throw InternalException("Failed to cast table to type - table filter type mismatch"); } return reinterpret_cast(*this); } @@ -71,7 +67,7 @@ class TableFilter { template const TARGET &Cast() const { if (filter_type != TARGET::TYPE) { - throw InternalException("Failed to cast to type - table filter type mismatch"); + throw InternalException("Failed to cast table to type - table filter type mismatch"); } return reinterpret_cast(*this); } @@ -82,7 +78,7 @@ class TableFilterSet { unordered_map> filters; public: - void PushFilter(const ColumnIndex &col_idx, unique_ptr filter); + void PushFilter(idx_t column_index, unique_ptr filter); bool Equals(TableFilterSet &other) { if (filters.size() != other.filters.size()) { diff --git a/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp b/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp index d76aeccb6..dc778907d 100644 --- a/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp +++ b/src/duckdb/src/include/duckdb/storage/arena_allocator.hpp @@ -25,7 +25,6 @@ struct ArenaChunk { }; class ArenaAllocator { -public: static constexpr const idx_t ARENA_ALLOCATOR_INITIAL_CAPACITY = 2048; static constexpr const idx_t ARENA_ALLOCATOR_MAX_CAPACITY = 1ULL << 24ULL; // 16MB diff --git a/src/duckdb/src/include/duckdb/storage/block_manager.hpp b/src/duckdb/src/include/duckdb/storage/block_manager.hpp index d93f417d1..7e73f037a 100644 --- a/src/duckdb/src/include/duckdb/storage/block_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/block_manager.hpp @@ -17,7 +17,6 @@ namespace duckdb { class BlockHandle; -class BufferHandle; class BufferManager; class ClientContext; class DatabaseInstance; @@ -87,8 +86,6 @@ class BlockManager { //! Register a block with the given block id in the base file shared_ptr RegisterBlock(block_id_t block_id); //! Convert an existing in-memory buffer into a persistent disk-backed block - shared_ptr ConvertToPersistent(block_id_t block_id, shared_ptr old_block, - BufferHandle old_handle); shared_ptr ConvertToPersistent(block_id_t block_id, shared_ptr old_block); void UnregisterBlock(BlockHandle &block); diff --git a/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp b/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp index 1f7970d5d..be1128fae 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp @@ -15,7 +15,6 @@ #include "duckdb/common/file_buffer.hpp" #include "duckdb/common/mutex.hpp" #include "duckdb/common/numeric_utils.hpp" -#include "duckdb/common/optional_idx.hpp" #include "duckdb/storage/storage_info.hpp" namespace duckdb { @@ -55,9 +54,15 @@ struct TempBufferPoolReservation : BufferPoolReservation { } }; -using BlockLock = unique_lock; - class BlockHandle : public enable_shared_from_this { + friend class BlockManager; + friend struct BufferEvictionNode; + friend class BufferHandle; + friend class BufferManager; + friend class StandardBufferManager; + friend class BufferPool; + friend struct EvictionQueue; + public: BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag); BlockHandle(BlockManager &block_manager, block_id_t block_id, MemoryTag tag, unique_ptr buffer, @@ -67,24 +72,21 @@ class BlockHandle : public enable_shared_from_this { BlockManager &block_manager; public: - block_id_t BlockId() const { + block_id_t BlockId() { return block_id; } - idx_t EvictionSequenceNumber() const { - return eviction_seq_num; - } - - idx_t NextEvictionSequenceNumber() { - return ++eviction_seq_num; + void ResizeBuffer(idx_t block_size, int64_t memory_delta) { + D_ASSERT(buffer); + // resize and adjust current memory + buffer->Resize(block_size); + memory_usage = NumericCast(NumericCast(memory_usage) + memory_delta); + D_ASSERT(memory_usage == buffer->AllocSize()); } int32_t Readers() const { return readers; } - int32_t DecrementReaders() { - return --readers; - } inline bool IsSwizzled() const { return !unswizzled; @@ -99,6 +101,7 @@ class BlockHandle : public enable_shared_from_this { } inline void SetDestroyBufferUpon(DestroyBufferUpon destroy_buffer_upon_p) { + lock_guard guard(lock); destroy_buffer_upon = destroy_buffer_upon_p; } @@ -110,75 +113,20 @@ class BlockHandle : public enable_shared_from_this { return destroy_buffer_upon == DestroyBufferUpon::BLOCK; } - inline idx_t GetMemoryUsage() const { + inline const idx_t &GetMemoryUsage() const { return memory_usage; } - - bool IsUnloaded() const { + bool IsUnloaded() { return state == BlockState::BLOCK_UNLOADED; } - void SetEvictionQueueIndex(const idx_t index) { - // can only be set once - D_ASSERT(eviction_queue_idx == DConstants::INVALID_INDEX); - // MANAGED_BUFFER only (at least, for now) - D_ASSERT(GetBufferType() == FileBufferType::MANAGED_BUFFER); - eviction_queue_idx = index; - } - - idx_t GetEvictionQueueIndex() const { - return eviction_queue_idx; - } - - FileBufferType GetBufferType() const { - return buffer_type; - } - - BlockState GetState() const { - return state; - } - - int64_t GetLRUTimestamp() const { - return lru_timestamp_msec; - } - - void SetLRUTimestamp(int64_t timestamp_msec) { - lru_timestamp_msec = timestamp_msec; - } - - BlockLock GetLock() { - return BlockLock(lock); - } - - //! Gets a reference to the buffer - the lock must be held - unique_ptr &GetBuffer(BlockLock &l); - - void ChangeMemoryUsage(BlockLock &l, int64_t delta); - BufferPoolReservation &GetMemoryCharge(BlockLock &l); - //! Merge a new memory reservation - void MergeMemoryReservation(BlockLock &, BufferPoolReservation reservation); - //! Resize the memory allocation - void ResizeMemory(BlockLock &, idx_t alloc_size); - - //! Resize the actual buffer - void ResizeBuffer(BlockLock &, idx_t block_size, int64_t memory_delta); - BufferHandle Load(unique_ptr buffer = nullptr); - BufferHandle LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, - BufferPoolReservation reservation); - unique_ptr UnloadAndTakeBlock(BlockLock &); - void Unload(BlockLock &); - - //! Returns whether or not the block can be unloaded - //! Note that while this method does not require a lock, whether or not a block can be unloaded can change if the - //! lock is not held - bool CanUnload() const; - - void ConvertToPersistent(BlockLock &, BlockHandle &new_block, unique_ptr new_buffer); - private: - void VerifyMutex(unique_lock &l) const; + BufferHandle Load(unique_ptr buffer = nullptr); + BufferHandle LoadFromBuffer(data_ptr_t data, unique_ptr reusable_buffer); + unique_ptr UnloadAndTakeBlock(); + void Unload(); + bool CanUnload(); -private: //! The block-level lock mutex lock; //! Whether or not the block is loaded/unloaded @@ -188,9 +136,7 @@ class BlockHandle : public enable_shared_from_this { //! The block id of the block const block_id_t block_id; //! Memory tag - const MemoryTag tag; - //! File buffer type - const FileBufferType buffer_type; + MemoryTag tag; //! Pointer to loaded data (if any) unique_ptr buffer; //! Internal eviction sequence number @@ -198,16 +144,14 @@ class BlockHandle : public enable_shared_from_this { //! LRU timestamp (for age-based eviction) atomic lru_timestamp_msec; //! When to destroy the data buffer - atomic destroy_buffer_upon; + DestroyBufferUpon destroy_buffer_upon; //! The memory usage of the block (when loaded). If we are pinning/loading //! an unloaded block, this tells us how much memory to reserve. - atomic memory_usage; + idx_t memory_usage; //! Current memory reservation / usage BufferPoolReservation memory_charge; //! Does the block contain any memory pointers? const char *unswizzled; - //! Index for eviction queue (FileBufferType::MANAGED_BUFFER only, for now) - atomic eviction_queue_idx; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/buffer/buffer_handle.hpp b/src/duckdb/src/include/duckdb/storage/buffer/buffer_handle.hpp index 32ae0ee5f..8895cff47 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/buffer_handle.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/buffer_handle.hpp @@ -18,7 +18,7 @@ class FileBuffer; class BufferHandle { public: DUCKDB_API BufferHandle(); - DUCKDB_API explicit BufferHandle(shared_ptr handle, optional_ptr node); + DUCKDB_API explicit BufferHandle(shared_ptr handle); DUCKDB_API ~BufferHandle(); // disable copy constructors BufferHandle(const BufferHandle &other) = delete; diff --git a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp index f4548e430..50166a51f 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer/buffer_pool.hpp @@ -82,21 +82,14 @@ class BufferPool { idx_t PurgeAgedBlocks(uint32_t max_age_sec); idx_t PurgeAgedBlocksInternal(EvictionQueue &queue, uint32_t max_age_sec, int64_t now, int64_t limit); //! Garbage collect dead nodes in the eviction queue. - void PurgeQueue(const BlockHandle &handle); + void PurgeQueue(FileBufferType type); //! Add a buffer handle to the eviction queue. Returns true, if the queue is //! ready to be purged, and false otherwise. bool AddToEvictionQueue(shared_ptr &handle); //! Gets the eviction queue for the specified type - EvictionQueue &GetEvictionQueueForBlockHandle(const BlockHandle &handle); + EvictionQueue &GetEvictionQueueForType(FileBufferType type); //! Increments the dead nodes for the queue with specified type - void IncrementDeadNodes(const BlockHandle &handle); - - //! How many eviction queues we have for the different FileBufferTypes - static constexpr idx_t BLOCK_QUEUE_SIZE = 1; - static constexpr idx_t MANAGED_BUFFER_QUEUE_SIZE = 6; - static constexpr idx_t TINY_BUFFER_QUEUE_SIZE = 1; - //! Mapping and priority order for the eviction queues - const array eviction_queue_sizes; + void IncrementDeadNodes(FileBufferType type); protected: enum class MemoryUsageCaches { diff --git a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp index f497aa1db..e2a3b95e0 100644 --- a/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp @@ -59,7 +59,6 @@ class BufferManager { virtual shared_ptr RegisterTransientMemory(const idx_t size, const idx_t block_size); //! Returns a new block of memory that is smaller than the block size setting. virtual shared_ptr RegisterSmallMemory(const idx_t size); - virtual shared_ptr RegisterSmallMemory(MemoryTag tag, const idx_t size); virtual DUCKDB_API Allocator &GetBufferAllocator(); virtual DUCKDB_API void ReserveMemory(idx_t size); @@ -99,7 +98,7 @@ class BufferManager { virtual TemporaryMemoryManager &GetTemporaryMemoryManager(); protected: - virtual void PurgeQueue(const BlockHandle &handle) = 0; + virtual void PurgeQueue(FileBufferType type) = 0; virtual void AddToEvictionQueue(shared_ptr &handle); virtual void WriteTemporaryBuffer(MemoryTag tag, block_id_t block_id, FileBuffer &buffer); virtual unique_ptr ReadTemporaryBuffer(MemoryTag tag, BlockHandle &block, diff --git a/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp b/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp index 2b49a4cbc..59eb2efd4 100644 --- a/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/checkpoint/string_checkpoint_state.hpp @@ -33,6 +33,19 @@ struct StringBlock { unique_ptr next; }; +struct string_location_t { // NOLINT + string_location_t(block_id_t block_id, int32_t offset) : block_id(block_id), offset(offset) { + } + string_location_t() { + } + bool IsValid(const idx_t block_size) { + auto cast_block_size = NumericCast(block_size); + return offset < cast_block_size && (block_id == INVALID_BLOCK || block_id >= MAXIMUM_BLOCK); + } + block_id_t block_id; + int32_t offset; +}; + struct UncompressedStringSegmentState : public CompressedSegmentState { ~UncompressedStringSegmentState() override; @@ -60,10 +73,6 @@ struct UncompressedStringSegmentState : public CompressedSegmentState { return "Overflow String Block Ids: " + result; } - vector GetAdditionalBlocks() const override { - return on_disk_blocks; - } - private: mutex block_lock; unordered_map> handles; diff --git a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_compress.hpp b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_compress.hpp index 5ba58dcf6..e22c52ee9 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_compress.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_compress.hpp @@ -32,16 +32,16 @@ struct AlpCompressionState : public CompressionState { public: using EXACT_TYPE = typename FloatingToExact::TYPE; - AlpCompressionState(ColumnDataCheckpointData &checkpoint_data, AlpAnalyzeState *analyze_state) - : CompressionState(analyze_state->info), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ALP)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); + AlpCompressionState(ColumnDataCheckpointer &checkpointer, AlpAnalyzeState *analyze_state) + : CompressionState(analyze_state->info), checkpointer(checkpointer), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_ALP)) { + CreateEmptySegment(checkpointer.GetRowGroup().start); //! Combinations found on the analyze step are needed for compression state.best_k_combinations = analyze_state->state.best_k_combinations; } - ColumnDataCheckpointData &checkpoint_data; + ColumnDataCheckpointer &checkpointer; CompressionFunction &function; unique_ptr current_segment; BufferHandle handle; @@ -90,12 +90,13 @@ struct AlpCompressionState : public CompressionState { } void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); + auto compressed_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); current_segment = std::move(compressed_segment); + current_segment->function = function; auto &buffer_manager = BufferManager::GetBufferManager(current_segment->db); handle = buffer_manager.Pin(current_segment->block); @@ -176,7 +177,7 @@ struct AlpCompressionState : public CompressionState { } void FlushSegment() { - auto &checkpoint_state = checkpoint_data.GetCheckpointState(); + auto &checkpoint_state = checkpointer.GetCheckpointState(); auto dataptr = handle.Ptr(); idx_t metadata_offset = AlignValue(UsedSpace()); @@ -209,7 +210,8 @@ struct AlpCompressionState : public CompressionState { // Store the offset to the end of metadata (to be used as a backwards pointer in decoding) Store(NumericCast(total_segment_size), dataptr); - checkpoint_state.FlushSegment(std::move(current_segment), std::move(handle), total_segment_size); + handle.Destroy(); + checkpoint_state.FlushSegment(std::move(current_segment), total_segment_size); data_bytes_used = 0; vectors_flushed = 0; } @@ -262,9 +264,8 @@ struct AlpCompressionState : public CompressionState { }; template -unique_ptr AlpInitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr state) { - return make_uniq>(checkpoint_data, (AlpAnalyzeState *)state.get()); +unique_ptr AlpInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { + return make_uniq>(checkpointer, (AlpAnalyzeState *)state.get()); } template diff --git a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp index cf9766177..e4763d762 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alp/alp_constants.hpp @@ -19,7 +19,7 @@ class AlpConstants { static constexpr uint32_t RG_SAMPLES = 8; static constexpr uint16_t SAMPLES_PER_VECTOR = 32; // We calculate how many equidistant vector we must jump within a rowgroup - static constexpr uint32_t RG_SAMPLES_DUCKDB_JUMP = (DEFAULT_ROW_GROUP_SIZE / RG_SAMPLES) / STANDARD_VECTOR_SIZE; + static constexpr uint32_t RG_SAMPLES_DUCKDB_JUMP = (STANDARD_ROW_GROUPS_SIZE / RG_SAMPLES) / STANDARD_VECTOR_SIZE; static constexpr uint8_t HEADER_SIZE = sizeof(uint32_t); static constexpr uint8_t EXPONENT_SIZE = sizeof(uint8_t); diff --git a/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_compress.hpp b/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_compress.hpp index 6b732e664..4bf2cdb85 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_compress.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/alprd/alprd_compress.hpp @@ -34,9 +34,9 @@ struct AlpRDCompressionState : public CompressionState { public: using EXACT_TYPE = typename FloatingToExact::TYPE; - AlpRDCompressionState(ColumnDataCheckpointData &checkpoint_data, AlpRDAnalyzeState *analyze_state) - : CompressionState(analyze_state->info), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ALPRD)) { + AlpRDCompressionState(ColumnDataCheckpointer &checkpointer, AlpRDAnalyzeState *analyze_state) + : CompressionState(analyze_state->info), checkpointer(checkpointer), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_ALPRD)) { //! State variables from the analyze step that are needed for compression state.left_parts_dict_map = std::move(analyze_state->state.left_parts_dict_map); state.left_bit_width = analyze_state->state.left_bit_width; @@ -46,10 +46,10 @@ struct AlpRDCompressionState : public CompressionState { next_vector_byte_index_start = AlpRDConstants::HEADER_SIZE + actual_dictionary_size_bytes; memcpy((void *)state.left_parts_dict, (void *)analyze_state->state.left_parts_dict, actual_dictionary_size_bytes); - CreateEmptySegment(checkpoint_data.GetRowGroup().start); + CreateEmptySegment(checkpointer.GetRowGroup().start); } - ColumnDataCheckpointData &checkpoint_data; + ColumnDataCheckpointer &checkpointer; CompressionFunction &function; unique_ptr current_segment; BufferHandle handle; @@ -100,11 +100,12 @@ struct AlpRDCompressionState : public CompressionState { } void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); + auto compressed_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); + compressed_segment->function = function; current_segment = std::move(compressed_segment); auto &buffer_manager = BufferManager::GetBufferManager(db); @@ -176,7 +177,7 @@ struct AlpRDCompressionState : public CompressionState { } void FlushSegment() { - auto &checkpoint_state = checkpoint_data.GetCheckpointState(); + auto &checkpoint_state = checkpointer.GetCheckpointState(); auto dataptr = handle.Ptr(); idx_t metadata_offset = AlignValue(UsedSpace()); @@ -225,7 +226,8 @@ struct AlpRDCompressionState : public CompressionState { // Store the Dictionary memcpy((void *)dataptr, (void *)state.left_parts_dict, actual_dictionary_size_bytes); - checkpoint_state.FlushSegment(std::move(current_segment), std::move(handle), total_segment_size); + handle.Destroy(); + checkpoint_state.FlushSegment(std::move(current_segment), total_segment_size); data_bytes_used = 0; vectors_flushed = 0; } @@ -277,9 +279,9 @@ struct AlpRDCompressionState : public CompressionState { }; template -unique_ptr AlpRDInitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr AlpRDInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { - return make_uniq>(checkpoint_data, (AlpRDAnalyzeState *)state.get()); + return make_uniq>(checkpointer, (AlpRDAnalyzeState *)state.get()); } template diff --git a/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_compress.hpp b/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_compress.hpp index ae120027c..a233246f3 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_compress.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_compress.hpp @@ -33,7 +33,7 @@ struct ChimpCompressionState : public CompressionState {}; // Compression Functions template -unique_ptr ChimpInitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr ChimpInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { throw InternalException("Chimp has been deprecated, can no longer be used to compress data"); return nullptr; diff --git a/src/duckdb/src/include/duckdb/storage/compression/dictionary/analyze.hpp b/src/duckdb/src/include/duckdb/storage/compression/dictionary/analyze.hpp deleted file mode 100644 index 99eb72156..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/dictionary/analyze.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "duckdb/storage/compression/dictionary/common.hpp" -#include "duckdb/common/string_map_set.hpp" -#include "duckdb/storage/table/column_data.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// Analyze -//===--------------------------------------------------------------------===// -struct DictionaryAnalyzeState : public DictionaryCompressionState { -public: - explicit DictionaryAnalyzeState(const CompressionInfo &info); - -public: - bool LookupString(string_t str) override; - void AddNewString(string_t str) override; - void AddLastLookup() override; - void AddNull() override; - bool CalculateSpaceRequirements(bool new_string, idx_t string_size) override; - void Flush(bool final = false) override; - void Verify() override; - -public: - idx_t segment_count; - idx_t current_tuple_count; - idx_t current_unique_count; - idx_t current_dict_size; - StringHeap heap; - string_set_t current_set; - bitpacking_width_t current_width; - bitpacking_width_t next_width; -}; - -struct DictionaryCompressionAnalyzeState : public AnalyzeState { -public: - explicit DictionaryCompressionAnalyzeState(const CompressionInfo &info) - : AnalyzeState(info), analyze_state(make_uniq(info)) { - } - -public: - unique_ptr analyze_state; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/dictionary/common.hpp b/src/duckdb/src/include/duckdb/storage/compression/dictionary/common.hpp deleted file mode 100644 index 79bd094bf..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/dictionary/common.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/common/bitpacking.hpp" -#include "duckdb/storage/string_uncompressed.hpp" - -namespace duckdb { - -typedef struct { - uint32_t dict_size; - uint32_t dict_end; - uint32_t index_buffer_offset; - uint32_t index_buffer_count; - uint32_t bitpacking_width; -} dictionary_compression_header_t; - -struct DictionaryCompression { -public: - static constexpr float MINIMUM_COMPRESSION_RATIO = 1.2F; - //! Dictionary header size at the beginning of the string segment (offset + length) - static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(dictionary_compression_header_t); - -public: - static bool HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size, - bitpacking_width_t packing_width, const idx_t block_size); - static idx_t RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size, - bitpacking_width_t packing_width); - - static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle); - static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer container); -}; - -//! Abstract class managing the compression state for size analysis or compression. -class DictionaryCompressionState : public CompressionState { -public: - explicit DictionaryCompressionState(const CompressionInfo &info); - ~DictionaryCompressionState() override; - -public: - bool UpdateState(Vector &scan_vector, idx_t count); - -protected: - // Should verify the State - virtual void Verify() = 0; - // Performs a lookup of str, storing the result internally - virtual bool LookupString(string_t str) = 0; - // Add the most recently looked up str to compression state - virtual void AddLastLookup() = 0; - // Add string to the state that is known to not be seen yet - virtual void AddNewString(string_t str) = 0; - // Add a null value to the compression state - virtual void AddNull() = 0; - // Needs to be called before adding a value. Will return false if a flush is required first. - virtual bool CalculateSpaceRequirements(bool new_string, idx_t string_size) = 0; - // Flush the segment to disk if compressing or reset the counters if analyzing - virtual void Flush(bool final = false) = 0; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/dictionary/compression.hpp b/src/duckdb/src/include/duckdb/storage/compression/dictionary/compression.hpp deleted file mode 100644 index 09f1f44bd..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/dictionary/compression.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/storage/compression/dictionary/common.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/common/string_map_set.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" - -namespace duckdb { - -// Dictionary compression uses a combination of bitpacking and a dictionary to compress string segments. The data is -// stored across three buffers: the index buffer, the selection buffer and the dictionary. Firstly the Index buffer -// contains the offsets into the dictionary which are also used to determine the string lengths. Each value in the -// dictionary gets a single unique index in the index buffer. Secondly, the selection buffer maps the tuples to an index -// in the index buffer. The selection buffer is compressed with bitpacking. Finally, the dictionary contains simply all -// the unique strings without lengths or null termination as we can deduce the lengths from the index buffer. The -// addition of the selection buffer is done for two reasons: firstly, to allow the scan to emit dictionary vectors by -// scanning the whole dictionary at once and then scanning the selection buffer for each emitted vector. Secondly, it -// allows for efficient bitpacking compression as the selection values should remain relatively small. - -//===--------------------------------------------------------------------===// -// Compress -//===--------------------------------------------------------------------===// -struct DictionaryCompressionCompressState : public DictionaryCompressionState { -public: - DictionaryCompressionCompressState(ColumnDataCheckpointData &checkpoint_data_p, const CompressionInfo &info); - -public: - void CreateEmptySegment(idx_t row_start); - void Verify() override; - bool LookupString(string_t str) override; - void AddNewString(string_t str) override; - void AddNull() override; - void AddLastLookup() override; - bool CalculateSpaceRequirements(bool new_string, idx_t string_size) override; - void Flush(bool final = false) override; - idx_t Finalize(); - -public: - ColumnDataCheckpointData &checkpoint_data; - CompressionFunction &function; - - // State regarding current segment - unique_ptr current_segment; - BufferHandle current_handle; - StringDictionaryContainer current_dictionary; - data_ptr_t current_end_ptr; - - // Buffers and map for current segment - string_map_t current_string_map; - vector index_buffer; - vector selection_buffer; - - bitpacking_width_t current_width = 0; - bitpacking_width_t next_width = 0; - - // Result of latest LookupString call - uint32_t latest_lookup_result; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/dictionary/decompression.hpp b/src/duckdb/src/include/duckdb/storage/compression/dictionary/decompression.hpp deleted file mode 100644 index 1656ec718..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/dictionary/decompression.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "duckdb/storage/compression/dictionary/common.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// Scan -//===--------------------------------------------------------------------===// -// FIXME: why is this StringScanState when we also define: `BufferHandle handle` ??? -struct CompressedStringScanState : public StringScanState { -public: - explicit CompressedStringScanState(BufferHandle &&handle_p) - : StringScanState(), owned_handle(std::move(handle_p)), handle(owned_handle) { - } - explicit CompressedStringScanState(BufferHandle &handle_p) : StringScanState(), owned_handle(), handle(handle_p) { - } - -public: - void Initialize(ColumnSegment &segment, bool initialize_dictionary = true); - void ScanToFlatVector(Vector &result, idx_t result_offset, idx_t start, idx_t scan_count); - void ScanToDictionaryVector(ColumnSegment &segment, Vector &result, idx_t result_offset, idx_t start, - idx_t scan_count); - -private: - string_t FetchStringFromDict(int32_t dict_offset, uint16_t string_len); - uint16_t GetStringLength(sel_t index); - -public: - BufferHandle owned_handle; - optional_ptr handle; - - bitpacking_width_t current_width; - buffer_ptr sel_vec; - idx_t sel_vec_size = 0; - - //! Start of the block (pointing to the dictionary_header) - data_ptr_t baseptr; - //! Start of the data (pointing to the start of the selection buffer) - data_ptr_t base_data; - uint32_t *index_buffer_ptr; - uint32_t index_buffer_count; - - buffer_ptr dictionary; - idx_t dictionary_size; - StringDictionaryContainer dict; - idx_t block_size; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/empty_validity.hpp b/src/duckdb/src/include/duckdb/storage/compression/empty_validity.hpp deleted file mode 100644 index 89abe1ce7..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/empty_validity.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include "duckdb/function/compression_function.hpp" -#include "duckdb/storage/table/column_data.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" - -namespace duckdb { - -class EmptyValidityCompression { -public: - struct EmptyValidityCompressionState : public CompressionState { - public: - explicit EmptyValidityCompressionState(ColumnDataCheckpointData &checkpoint_data, const CompressionInfo &info) - : CompressionState(info), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_EMPTY)), - checkpoint_data(checkpoint_data) { - } - ~EmptyValidityCompressionState() override { - } - - public: - optional_ptr function; - ColumnDataCheckpointData &checkpoint_data; - idx_t count = 0; - idx_t non_nulls = 0; - }; - struct EmptyValiditySegmentScanState : public SegmentScanState { - EmptyValiditySegmentScanState() { - } - }; - -public: - static CompressionFunction CreateFunction() { - return CompressionFunction(CompressionType::COMPRESSION_EMPTY, PhysicalType::BIT, nullptr, nullptr, nullptr, - InitCompression, Compress, FinalizeCompress, InitScan, Scan, ScanPartial, FetchRow, - Skip, InitSegment); - } - -public: - static unique_ptr InitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr state_p) { - return make_uniq(checkpoint_data, state_p->info); - } - static void Compress(CompressionState &state_p, Vector &scan_vector, idx_t count) { - auto &state = state_p.Cast(); - UnifiedVectorFormat format; - scan_vector.ToUnifiedFormat(count, format); - state.non_nulls += format.validity.CountValid(count); - state.count += count; - } - static void FinalizeCompress(CompressionState &state_p) { - auto &state = state_p.Cast(); - auto &checkpoint_data = state.checkpoint_data; - - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); - auto row_start = checkpoint_data.GetRowGroup().start; - - auto &info = state.info; - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, *state.function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); - compressed_segment->count = state.count; - if (state.non_nulls != state.count) { - compressed_segment->stats.statistics.SetHasNullFast(); - } - if (state.non_nulls != 0) { - compressed_segment->stats.statistics.SetHasNoNullFast(); - } - - auto &buffer_manager = BufferManager::GetBufferManager(checkpoint_data.GetDatabase()); - auto handle = buffer_manager.Pin(compressed_segment->block); - - auto &checkpoint_state = checkpoint_data.GetCheckpointState(); - checkpoint_state.FlushSegment(std::move(compressed_segment), std::move(handle), 0); - } - static unique_ptr InitScan(ColumnSegment &segment) { - return make_uniq(); - } - static void ScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, - idx_t result_offset) { - return; - } - static void Scan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result) { - return; - } - static void FetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, - idx_t result_idx) { - return; - } - static void Skip(ColumnSegment &segment, ColumnScanState &state, idx_t skip_count) { - return; - } - static unique_ptr InitSegment(ColumnSegment &segment, block_id_t block_id, - optional_ptr segment_state) { - return nullptr; - } -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/patas/patas_compress.hpp b/src/duckdb/src/include/duckdb/storage/compression/patas/patas_compress.hpp index b33e1a6a0..2931e9168 100644 --- a/src/duckdb/src/include/duckdb/storage/compression/patas/patas_compress.hpp +++ b/src/duckdb/src/include/duckdb/storage/compression/patas/patas_compress.hpp @@ -35,7 +35,7 @@ struct PatasCompressionState : public CompressionState {}; // Compression Functions template -unique_ptr PatasInitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr PatasInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { throw InternalException("Patas has been deprecated, can no longer be used to compress data"); return nullptr; diff --git a/src/duckdb/src/include/duckdb/storage/compression/roaring/appender.hpp b/src/duckdb/src/include/duckdb/storage/compression/roaring/appender.hpp deleted file mode 100644 index 31972d4c8..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/roaring/appender.hpp +++ /dev/null @@ -1,150 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/storage/compression/roaring/appender.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/common/helper.hpp" -#include "duckdb/common/types/validity_mask.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/storage/compression/roaring/roaring.hpp" - -namespace duckdb { - -namespace roaring { - -template -struct RoaringStateAppender { -public: - RoaringStateAppender() = delete; - -public: - static void AppendBytes(STATE_TYPE &state, validity_t entry, idx_t bits) { - D_ASSERT(bits <= ValidityMask::BITS_PER_VALUE); - - idx_t full_bytes = bits / 8; - idx_t last_bits = bits % 8; - for (idx_t i = 0; i < full_bytes; i++) { - // Create a mask for the byte we care about (least to most significant byte) - auto bitmask = ValidityUncompressed::UPPER_MASKS[8] >> ((7 - i) * 8); - // Shift to the least significant bits so we can use it to index our bitmask table - auto array_index = static_cast((entry & bitmask) >> (i * 8)); - STATE_TYPE::HandleByte(state, array_index); - } - - if (DUCKDB_UNLIKELY(last_bits != 0)) { - auto bitmask = ValidityUncompressed::UPPER_MASKS[8] >> ((7 - full_bytes) * 8); - auto array_index = static_cast((entry & bitmask) >> (full_bytes * 8)); - STATE_TYPE::HandleRaggedByte(state, array_index, last_bits); - } - } - - static void AppendVector(STATE_TYPE &state, Vector &input, idx_t input_size) { - UnifiedVectorFormat unified; - input.ToUnifiedFormat(input_size, unified); - auto &validity = unified.validity; - - if (validity.AllValid()) { - // All bits are set implicitly - idx_t appended = 0; - while (appended < input_size) { - idx_t to_append = - MinValue(ROARING_CONTAINER_SIZE - STATE_TYPE::Count(state), input_size - appended); - STATE_TYPE::HandleAllValid(state, to_append); - if (STATE_TYPE::Count(state) == ROARING_CONTAINER_SIZE) { - STATE_TYPE::Flush(state); - } - appended += to_append; - } - } else { - // There is a validity mask - idx_t appended = 0; - while (appended < input_size) { - idx_t to_append = - MinValue(ROARING_CONTAINER_SIZE - STATE_TYPE::Count(state), input_size - appended); - - // Deal with a ragged start, when 'appended' isn't a multiple of ValidityMask::BITS_PER_VALUE - // then we need to process the remainder of the entry - idx_t entry_offset = appended / ValidityMask::BITS_PER_VALUE; - auto previous_entry_remainder = appended % ValidityMask::BITS_PER_VALUE; - if (DUCKDB_UNLIKELY(previous_entry_remainder != 0)) { - auto validity_entry = validity.GetValidityEntry(entry_offset); - - idx_t to_process = ValidityMask::BITS_PER_VALUE - previous_entry_remainder; - validity_t mask; - if (to_append < to_process) { - // Limit the amount of bits to set - auto left_bits = to_process - to_append; - to_process = to_append; - mask = ValidityUncompressed::UPPER_MASKS[to_process] >> left_bits; - } else { - mask = ValidityUncompressed::UPPER_MASKS[to_process]; - } - - auto masked_entry = (validity_entry & mask) >> previous_entry_remainder; - if (masked_entry == ValidityUncompressed::LOWER_MASKS[to_process]) { - // All bits are set - STATE_TYPE::HandleAllValid(state, to_process); - } else if (masked_entry == 0) { - // None of the bits are set - STATE_TYPE::HandleNoneValid(state, to_process); - } else { - // Mixed set/unset bits - AppendBytes(state, masked_entry, to_process); - } - - to_append -= to_process; - appended += to_process; - entry_offset++; - } - - auto entry_count = to_append / ValidityMask::BITS_PER_VALUE; - for (idx_t entry_index = 0; entry_index < entry_count; entry_index++) { - // get the validity entry at this index - auto validity_entry = validity.GetValidityEntry(entry_offset + entry_index); - if (ValidityMask::AllValid(validity_entry)) { - // All bits are set - STATE_TYPE::HandleAllValid(state, ValidityMask::BITS_PER_VALUE); - } else if (ValidityMask::NoneValid(validity_entry)) { - // None of the bits are set - STATE_TYPE::HandleNoneValid(state, ValidityMask::BITS_PER_VALUE); - } else { - // Mixed set/unset bits - AppendBytes(state, validity_entry, ValidityMask::BITS_PER_VALUE); - } - } - - // Deal with a ragged end, when the validity entry isn't entirely used - idx_t remainder = to_append % ValidityMask::BITS_PER_VALUE; - if (DUCKDB_UNLIKELY(remainder != 0)) { - auto validity_entry = validity.GetValidityEntry(entry_offset + entry_count); - auto masked = validity_entry & ValidityUncompressed::LOWER_MASKS[remainder]; - if (masked == ValidityUncompressed::LOWER_MASKS[remainder]) { - // All bits are set - STATE_TYPE::HandleAllValid(state, remainder); - } else if (masked == 0) { - // None of the bits are set - STATE_TYPE::HandleNoneValid(state, remainder); - } else { - AppendBytes(state, validity_entry, remainder); - } - } - - if (STATE_TYPE::Count(state) == ROARING_CONTAINER_SIZE) { - STATE_TYPE::Flush(state); - } - appended += to_append; - } - } - } -}; - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/compression/roaring/roaring.hpp b/src/duckdb/src/include/duckdb/storage/compression/roaring/roaring.hpp deleted file mode 100644 index 7a2d1ddaa..000000000 --- a/src/duckdb/src/include/duckdb/storage/compression/roaring/roaring.hpp +++ /dev/null @@ -1,616 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/storage/compression/roaring/roaring.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/typedefs.hpp" -#include "duckdb/common/helper.hpp" -#include "duckdb/common/types/validity_mask.hpp" -#include "duckdb/common/types/vector.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/storage/table/scan_state.hpp" - -namespace duckdb { -namespace roaring { - -//! Used for compressed runs/arrays -static constexpr uint16_t COMPRESSED_SEGMENT_SIZE = 256; -//! compresed segment size is 256, instead of division we can make use of shifting -static constexpr uint16_t COMPRESSED_SEGMENT_SHIFT_AMOUNT = 8; -//! The amount of values that are encoded per container -static constexpr idx_t ROARING_CONTAINER_SIZE = 2048; -static constexpr bool NULLS = true; -static constexpr bool NON_NULLS = false; -static constexpr uint16_t UNCOMPRESSED_SIZE = (ROARING_CONTAINER_SIZE / sizeof(validity_t)); -static constexpr uint16_t COMPRESSED_SEGMENT_COUNT = (ROARING_CONTAINER_SIZE / COMPRESSED_SEGMENT_SIZE); - -static constexpr uint16_t MAX_RUN_IDX = (UNCOMPRESSED_SIZE - COMPRESSED_SEGMENT_COUNT) / (sizeof(uint8_t) * 2); -static constexpr uint16_t MAX_ARRAY_IDX = (UNCOMPRESSED_SIZE - COMPRESSED_SEGMENT_COUNT) / (sizeof(uint8_t) * 1); -//! The value used to indicate that a container is a bitset container -static constexpr uint16_t BITSET_CONTAINER_SENTINEL_VALUE = MAX_ARRAY_IDX + 1; -static constexpr uint16_t COMPRESSED_ARRAY_THRESHOLD = 8; -static constexpr uint16_t COMPRESSED_RUN_THRESHOLD = 4; - -static constexpr uint16_t CONTAINER_TYPE_BITWIDTH = 2; -static constexpr uint16_t RUN_CONTAINER_SIZE_BITWIDTH = 7; -static constexpr uint16_t ARRAY_CONTAINER_SIZE_BITWIDTH = 8; - -//! This can be increased, but requires additional changes beyond just changing the constant -static_assert(MAX_RUN_IDX < NumericLimits::Maximum(), "The run size is encoded in a maximum of 8 bits"); - -//! This can be increased, but requires additional changes beyond just changing the constant -static_assert(BITSET_CONTAINER_SENTINEL_VALUE < NumericLimits::Maximum(), - "The array/bitset size is encoded in a maximum of 8 bits"); - -static_assert(ROARING_CONTAINER_SIZE % COMPRESSED_SEGMENT_SIZE == 0, - "The (maximum) container size has to be cleanly divisable by the segment size"); - -static_assert((1 << RUN_CONTAINER_SIZE_BITWIDTH) - 1 >= MAX_RUN_IDX, - "The bitwidth used to store the size of a run container has to be big enough to store the maximum size"); -static_assert( - (1 << ARRAY_CONTAINER_SIZE_BITWIDTH) - 1 >= MAX_ARRAY_IDX + 1, - "The bitwidth used to store the size of an array/bitset container has to be big enough to store the maximum size"); - -void SetInvalidRange(ValidityMask &result, idx_t start, idx_t end); - -struct RunContainerRLEPair { - uint16_t start; - uint16_t length; -}; - -enum class ContainerType : uint8_t { RUN_CONTAINER, ARRAY_CONTAINER, BITSET_CONTAINER }; - -struct ContainerMetadata { -public: - bool operator==(const ContainerMetadata &other) const { - if (container_type != other.container_type) { - return false; - } - if (count != other.count) { - return false; - } - if (nulls != other.nulls) { - return false; - } - return true; - } - - static ContainerMetadata CreateMetadata(uint16_t count, uint16_t array_null, uint16_t array_non_null, - uint16_t runs); - - static ContainerMetadata RunContainer(uint16_t runs) { - auto res = ContainerMetadata(); - res.container_type = ContainerType::RUN_CONTAINER; - res.nulls = true; - res.count = runs; - return res; - } - - static ContainerMetadata ArrayContainer(uint16_t array_size, bool nulls) { - auto res = ContainerMetadata(); - res.container_type = ContainerType::ARRAY_CONTAINER; - res.nulls = nulls; - res.count = array_size; - return res; - } - - static ContainerMetadata BitsetContainer(uint16_t container_size) { - auto res = ContainerMetadata(); - res.container_type = ContainerType::BITSET_CONTAINER; - res.nulls = true; - res.count = container_size; - return res; - } - -public: - idx_t GetDataSizeInBytes(idx_t container_size) const; - bool IsUncompressed() const { - return container_type == ContainerType::BITSET_CONTAINER; - } - bool IsRun() const { - return container_type == ContainerType::RUN_CONTAINER; - } - bool IsInverted() const { - return nulls; - } - bool IsArray() const { - return container_type == ContainerType::ARRAY_CONTAINER; - } - idx_t NumberOfRuns() const { - D_ASSERT(IsRun()); - return count; - } - idx_t Cardinality() const { - D_ASSERT(IsArray()); - return count; - } - -public: - ContainerType container_type; - //! Whether nulls are being encoded or non-nulls - bool nulls; - //! The amount (meaning depends on container_type) - uint16_t count; - -private: - ContainerMetadata() { - } -}; - -struct ContainerMetadataCollection { - static constexpr uint8_t IS_RUN_FLAG = 1 << 1; - static constexpr uint8_t IS_INVERTED_FLAG = 1 << 0; - -public: - ContainerMetadataCollection(); - -public: - void AddMetadata(ContainerMetadata metadata); - idx_t GetMetadataSizeForSegment() const; - idx_t GetMetadataSize(idx_t container_count, idx_t run_containers, idx_t array_containers) const; - idx_t GetRunContainerCount() const; - idx_t GetArrayAndBitsetContainerCount() const; - void FlushSegment(); - void Reset(); - // Write the metadata for the current segment - idx_t Serialize(data_ptr_t dest) const; - void Deserialize(data_ptr_t src, idx_t container_count); - -private: - void AddBitsetContainer(); - void AddArrayContainer(idx_t amount, bool is_inverted); - void AddRunContainer(idx_t amount, bool is_inverted); - void AddContainerType(bool is_run, bool is_inverted); - -public: - //! Encode for each container in the lower 2 bits if the container 'is_run' and 'is_inverted' - vector container_type; - //! Encode for each run container the length - vector number_of_runs; - //! Encode for each array/bitset container the length - vector cardinality; - - idx_t count_in_segment = 0; - idx_t runs_in_segment = 0; - idx_t arrays_in_segment = 0; -}; - -struct ContainerMetadataCollectionScanner { -public: - explicit ContainerMetadataCollectionScanner(ContainerMetadataCollection &collection); - -public: - ContainerMetadata GetNext(); - -public: - const ContainerMetadataCollection &collection; - idx_t array_idx = 0; - idx_t run_idx = 0; - idx_t idx = 0; -}; - -struct BitmaskTableEntry { - uint8_t first_bit_set : 1; - uint8_t last_bit_set : 1; - uint8_t valid_count : 6; - uint8_t run_count; -}; - -//===--------------------------------------------------------------------===// -// Analyze -//===--------------------------------------------------------------------===// -struct RoaringAnalyzeState : public AnalyzeState { -public: - explicit RoaringAnalyzeState(const CompressionInfo &info); - -public: - // RoaringStateAppender interface: - - static void HandleByte(RoaringAnalyzeState &state, uint8_t array_index); - static void HandleRaggedByte(RoaringAnalyzeState &state, uint8_t array_index, idx_t relevant_bits); - static void HandleAllValid(RoaringAnalyzeState &state, idx_t amount); - static void HandleNoneValid(RoaringAnalyzeState &state, idx_t amount); - static idx_t Count(RoaringAnalyzeState &state); - static void Flush(RoaringAnalyzeState &state); - -public: - ContainerMetadata GetResult(); - bool HasEnoughSpaceInSegment(idx_t required_space); - void FlushSegment(); - void FlushContainer(); - void Analyze(Vector &input, idx_t count); - -public: - unsafe_unique_array bitmask_table; - - //! Analyze phase - - //! The amount of set bits found - uint16_t one_count = 0; - //! The amount of unset bits found - uint16_t zero_count = 0; - //! The amount of runs (of 0's) so far - uint16_t run_count = 0; - //! Whether the last bit was set or not - bool last_bit_set; - //! The total amount of bits covered (one_count + zero_count) - uint16_t count = 0; - - //! Flushed analyze data - - //! The space used by the current segment - idx_t space_used = 0; - //! The total amount of segments to write - idx_t segment_count = 0; - //! The amount of values in the current segment; - idx_t current_count = 0; - //! The total amount of data to serialize - idx_t total_count = 0; - - //! The total amount of bytes used to compress the whole segment - idx_t total_size = 0; - //! The container metadata, determining the type of each container to use during compression - ContainerMetadataCollection metadata_collection; - vector container_metadata; -}; - -//===--------------------------------------------------------------------===// -// Compress -//===--------------------------------------------------------------------===// - -struct ContainerCompressionState { - using append_func_t = void (*)(ContainerCompressionState &, bool, uint16_t); - -public: - ContainerCompressionState(); - -public: - void Append(bool null, uint16_t amount = 1); - void OverrideArray(data_ptr_t destination, bool nulls, idx_t count); - void OverrideRun(data_ptr_t destination, idx_t count); - void OverrideUncompressed(data_ptr_t destination); - void Finalize(); - ContainerMetadata GetResult(); - void Reset(); - -public: - //! Buffered append state (we don't want to append every bit separately) - uint16_t length = 0; - bool last_bit_set; - - //! Total amount of values covered by the container - uint16_t appended_count = 0; - //! How many of the total are null - uint16_t null_count = 0; - bool last_is_null = false; - - RunContainerRLEPair *runs; - uint8_t *compressed_runs; - uint8_t *compressed_arrays[2]; - uint16_t *arrays[2]; - - //! The runs (for sequential nulls) - RunContainerRLEPair base_runs[COMPRESSED_RUN_THRESHOLD]; - //! The indices (for nulls | non-nulls) - uint16_t base_arrays[2][COMPRESSED_ARRAY_THRESHOLD]; - - uint16_t run_idx; - uint16_t array_idx[2]; - - uint8_t *array_counts[2]; - uint8_t *run_counts; - - uint8_t base_compressed_arrays[2][MAX_ARRAY_IDX]; - uint8_t base_compressed_runs[MAX_RUN_IDX * 2]; - uint8_t base_array_counts[2][COMPRESSED_SEGMENT_COUNT]; - uint8_t base_run_counts[COMPRESSED_SEGMENT_COUNT]; - - validity_t *uncompressed = nullptr; - //! Whether the state has been finalized - bool finalized = false; - //! The function called to append to the state - append_func_t append_function; -}; - -struct RoaringCompressState : public CompressionState { -public: - explicit RoaringCompressState(ColumnDataCheckpointData &checkpoint_data, unique_ptr analyze_state_p); - -public: - //! RoaringStateAppender interface - static void HandleByte(RoaringCompressState &state, uint8_t array_index); - static void HandleRaggedByte(RoaringCompressState &state, uint8_t array_index, idx_t relevant_bits); - static void HandleAllValid(RoaringCompressState &state, idx_t amount); - static void HandleNoneValid(RoaringCompressState &state, idx_t amount); - static idx_t Count(RoaringCompressState &state); - static void Flush(RoaringCompressState &state); - -public: - idx_t GetContainerIndex(); - idx_t GetRemainingSpace(); - bool CanStore(idx_t container_size, const ContainerMetadata &metadata); - void InitializeContainer(); - void CreateEmptySegment(idx_t row_start); - void FlushSegment(); - void Finalize(); - void FlushContainer(); - void NextContainer(); - void Compress(Vector &input, idx_t count); - -public: - unique_ptr owned_analyze_state; - RoaringAnalyzeState &analyze_state; - - ContainerCompressionState container_state; - ContainerMetadataCollection metadata_collection; - vector &container_metadata; - - ColumnDataCheckpointData &checkpoint_data; - CompressionFunction &function; - unique_ptr current_segment; - BufferHandle handle; - - // Ptr to next free spot in segment; - data_ptr_t data_ptr; - // Ptr to next free spot for storing - data_ptr_t metadata_ptr; - //! The amount of values already compressed - idx_t total_count = 0; -}; - -//===--------------------------------------------------------------------===// -// Scan -//===--------------------------------------------------------------------===// - -struct ContainerScanState { -public: - ContainerScanState(idx_t container_index_p, idx_t container_size) - : container_index(container_index_p), container_size(container_size) { - } - virtual ~ContainerScanState() { - } - -public: - virtual void ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) = 0; - virtual void Skip(idx_t count) = 0; - virtual void Verify() const = 0; - -public: - //! The index of the container - idx_t container_index; - //! The size of the container (how many values does it hold) - idx_t container_size; - //! How much of the container is already consumed - idx_t scanned_count = 0; -}; - -struct ContainerSegmentScan { -public: - explicit ContainerSegmentScan(data_ptr_t data); - ContainerSegmentScan(const ContainerSegmentScan &other) = delete; - ContainerSegmentScan(ContainerSegmentScan &&other) = delete; - ContainerSegmentScan &operator=(const ContainerSegmentScan &other) = delete; - ContainerSegmentScan &operator=(ContainerSegmentScan &&other) = delete; - -public: - // Returns the base of the current segment, forwarding the index if the segment is depleted of values - uint16_t operator++(int); - -private: - //! The COMPRESSED_SEGMENT_COUNT unsigned bytes indicating for each segment (256 bytes) of the container how many - //! values are in the segment - uint8_t *segments; - uint8_t index; - uint8_t count; -}; - -//! RUN Container - -struct RunContainerScanState : public ContainerScanState { -public: - RunContainerScanState(idx_t container_index, idx_t container_size, idx_t count, data_ptr_t data_p); - -public: - void ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) override; - void Skip(idx_t to_skip) override; - void Verify() const override; - -protected: - virtual void LoadNextRun(); - -protected: - RunContainerRLEPair run; - bool finished = false; - idx_t run_index = 0; - idx_t count; - data_ptr_t data; -}; - -struct CompressedRunContainerScanState : public RunContainerScanState { -public: - CompressedRunContainerScanState(idx_t container_index, idx_t container_size, idx_t count, data_ptr_t segments, - data_ptr_t data); - -protected: - void LoadNextRun() override; - void Verify() const override; - -private: - data_ptr_t segments; - ContainerSegmentScan segment; -}; - -//! ARRAY Container - -template -struct ArrayContainerScanState : public ContainerScanState { -public: - ArrayContainerScanState(idx_t container_index, idx_t container_size, idx_t count, data_ptr_t data_p) - : ContainerScanState(container_index, container_size), data(data_p), count(count) { - } - -public: - virtual void LoadNextValue() { - if (array_index >= count) { - finished = true; - return; - } - value = reinterpret_cast(data)[array_index]; - array_index++; - } - -public: - void ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) override { - auto &result_mask = FlatVector::Validity(result); - - // This method assumes that the validity mask starts off as having all bits set for the entries that are being - // scanned. - - if (!INVERTED) { - // If we are mapping valid entries, that means the majority of the bits are invalid - // so we set everything to invalid and only flip the bits that are present in the array - SetInvalidRange(result_mask, result_offset, result_offset + to_scan); - } - - if (!array_index) { - LoadNextValue(); - } - // At least one of the entries to scan is set - while (!finished) { - if (value >= scanned_count + to_scan) { - break; - } - if (value < scanned_count) { - LoadNextValue(); - continue; - } - auto index = value - scanned_count; - if (INVERTED) { - result_mask.SetInvalid(result_offset + index); - } else { - result_mask.SetValid(result_offset + index); - } - LoadNextValue(); - } - scanned_count += to_scan; - } - - void Skip(idx_t to_skip) override { - idx_t end = scanned_count + to_skip; - if (!array_index) { - LoadNextValue(); - } - while (!finished && value < end) { - LoadNextValue(); - } - // In case array_index has already reached count - scanned_count = end; - } - - void Verify() const override { -#ifdef DEBUG - uint16_t index = 0; - auto array = reinterpret_cast(data); - for (uint16_t i = 0; i < count; i++) { - D_ASSERT(!i || array[i] > index); - index = array[i]; - } -#endif - } - -protected: - uint16_t value; - data_ptr_t data; - bool finished = false; - const idx_t count; - idx_t array_index = 0; -}; - -template -struct CompressedArrayContainerScanState : public ArrayContainerScanState { -public: - CompressedArrayContainerScanState(idx_t container_index, idx_t container_size, idx_t count, data_ptr_t segments, - data_ptr_t data) - : ArrayContainerScanState(container_index, container_size, count, data), segments(segments), - segment(segments) { - D_ASSERT(count >= COMPRESSED_ARRAY_THRESHOLD); - } - -public: - void LoadNextValue() override { - if (this->array_index >= this->count) { - this->finished = true; - return; - } - this->value = segment++; - this->value += reinterpret_cast(this->data)[this->array_index]; - this->array_index++; - } - void Verify() const override { -#ifdef DEBUG - uint16_t index = 0; - ContainerSegmentScan verify_segment(segments); - for (uint16_t i = 0; i < this->count; i++) { - // Get the value - uint16_t new_index = verify_segment++; - new_index += reinterpret_cast(this->data)[i]; - - D_ASSERT(!i || new_index > index); - index = new_index; - } -#endif - } - -private: - data_ptr_t segments; - ContainerSegmentScan segment; -}; - -//! BITSET Container - -struct BitsetContainerScanState : public ContainerScanState { -public: - BitsetContainerScanState(idx_t container_index, idx_t count, validity_t *bitset); - -public: - void ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) override; - void Skip(idx_t to_skip) override; - void Verify() const override; - -public: - validity_t *bitset; -}; - -struct RoaringScanState : public SegmentScanState { -public: - explicit RoaringScanState(ColumnSegment &segment); - -public: - idx_t SkipVector(const ContainerMetadata &metadata); - bool UseContainerStateCache(idx_t container_index, idx_t internal_offset); - ContainerMetadata GetContainerMetadata(idx_t container_index); - data_ptr_t GetStartOfContainerData(idx_t container_index); - ContainerScanState &LoadContainer(idx_t container_index, idx_t internal_offset); - void ScanInternal(ContainerScanState &scan_state, idx_t to_scan, Vector &result, idx_t offset); - idx_t GetContainerIndex(idx_t start_index, idx_t &offset); - void ScanPartial(idx_t start_idx, Vector &result, idx_t offset, idx_t count); - void Skip(ContainerScanState &scan_state, idx_t skip_count); - -public: - BufferHandle handle; - ColumnSegment &segment; - unique_ptr current_container; - data_ptr_t data_ptr; - ContainerMetadataCollection metadata_collection; - vector container_metadata; - vector data_start_position; -}; - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/data_table.hpp b/src/duckdb/src/include/duckdb/storage/data_table.hpp index 39795ed1b..313cb4b74 100644 --- a/src/duckdb/src/include/duckdb/storage/data_table.hpp +++ b/src/duckdb/src/include/duckdb/storage/data_table.hpp @@ -9,8 +9,11 @@ #pragma once #include "duckdb/common/enums/index_constraint_type.hpp" +#include "duckdb/common/enums/scan_options.hpp" +#include "duckdb/common/mutex.hpp" #include "duckdb/common/types/data_chunk.hpp" #include "duckdb/common/unique_ptr.hpp" +#include "duckdb/storage/block.hpp" #include "duckdb/storage/index.hpp" #include "duckdb/storage/statistics/column_statistics.hpp" #include "duckdb/storage/table/column_segment.hpp" @@ -22,7 +25,6 @@ #include "duckdb/transaction/local_storage.hpp" namespace duckdb { - class BoundForeignKeyConstraint; class ClientContext; class ColumnDataCollection; @@ -57,9 +59,9 @@ class DataTable { DataTable(ClientContext &context, DataTable &parent, idx_t removed_column); //! Constructs a DataTable as a delta on an existing data table but with one column changed type DataTable(ClientContext &context, DataTable &parent, idx_t changed_idx, const LogicalType &target_type, - const vector &bound_columns, Expression &cast_expr); + const vector &bound_columns, Expression &cast_expr); //! Constructs a DataTable as a delta on an existing data table but with one column added new constraint - DataTable(ClientContext &context, DataTable &parent, BoundConstraint &constraint); + explicit DataTable(ClientContext &context, DataTable &parent, unique_ptr constraint); //! A reference to the database instance AttachedDatabase &db; @@ -74,11 +76,13 @@ class DataTable { vector GetTypes(); const vector &Columns() const; - void InitializeScan(DuckTransaction &transaction, TableScanState &state, const vector &column_ids, + void InitializeScan(TableScanState &state, const vector &column_ids, + TableFilterSet *table_filter = nullptr); + void InitializeScan(DuckTransaction &transaction, TableScanState &state, const vector &column_ids, TableFilterSet *table_filters = nullptr); //! Returns the maximum amount of threads that should be assigned to scan this data table - idx_t MaxThreads(ClientContext &context) const; + idx_t MaxThreads(ClientContext &context); void InitializeParallelScan(ClientContext &context, ParallelTableScanState &state); bool NextParallelScan(ClientContext &context, ParallelTableScanState &state, TableScanState &scan_state); @@ -89,30 +93,23 @@ class DataTable { void Scan(DuckTransaction &transaction, DataChunk &result, TableScanState &state); //! Fetch data from the specific row identifiers from the base table - void Fetch(DuckTransaction &transaction, DataChunk &result, const vector &column_ids, + void Fetch(DuckTransaction &transaction, DataChunk &result, const vector &column_ids, const Vector &row_ids, idx_t fetch_count, ColumnFetchState &state); - //! Initializes appending to transaction-local storage + //! Initializes an append to transaction-local storage void InitializeLocalAppend(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context, const vector> &bound_constraints); - //! Initializes only the delete-indexes of the transaction-local storage - void InitializeLocalStorage(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context, - const vector> &bound_constraints); //! Append a DataChunk to the transaction-local storage of the table. - void LocalAppend(LocalAppendState &state, ClientContext &context, DataChunk &chunk, bool unsafe); + void LocalAppend(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context, DataChunk &chunk, + bool unsafe = false); //! Finalizes a transaction-local append void FinalizeLocalAppend(LocalAppendState &state); - //! Append a chunk to the transaction-local storage of this table and update the delete indexes. - void LocalAppend(TableCatalogEntry &table, ClientContext &context, DataChunk &chunk, - const vector> &bound_constraints, Vector &row_ids, - DataChunk &delete_chunk); - //! Append a chunk to the transaction-local storage of this table. + //! Append a chunk to the transaction-local storage of this table void LocalAppend(TableCatalogEntry &table, ClientContext &context, DataChunk &chunk, const vector> &bound_constraints); - //! Append a column data collection with default values to the transaction-local storage of this table. + //! Append a column data collection to the transaction-local storage of this table void LocalAppend(TableCatalogEntry &table, ClientContext &context, ColumnDataCollection &collection, - const vector> &bound_constraints, - optional_ptr> column_ids); + const vector> &bound_constraints); //! Merge a row group collection into the transaction-local storage void LocalMerge(ClientContext &context, RowGroupCollection &collection); //! Creates an optimistic writer for this table - used for optimistically writing parallel appends @@ -152,24 +149,21 @@ class DataTable { //! Commit the append void CommitAppend(transaction_t commit_id, idx_t row_start, idx_t count); //! Write a segment of the table to the WAL - void WriteToLog(DuckTransaction &transaction, WriteAheadLog &log, idx_t row_start, idx_t count, - optional_ptr commit_state); + void WriteToLog(WriteAheadLog &log, idx_t row_start, idx_t count, optional_ptr commit_state); //! Revert a set of appends made by the given AppendState, used to revert appends in the event of an error during //! commit (e.g. because of an I/O exception) - void RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_t count); + void RevertAppend(idx_t start_row, idx_t count); void RevertAppendInternal(idx_t start_row); - void ScanTableSegment(DuckTransaction &transaction, idx_t start_row, idx_t count, - const std::function &function); + void ScanTableSegment(idx_t start_row, idx_t count, const std::function &function); //! Merge a row group collection directly into this table - appending it to the end of the table without copying void MergeStorage(RowGroupCollection &data, TableIndexList &indexes, optional_ptr commit_state); - //! Append a chunk with the row ids [row_start, ..., row_start + chunk.size()] to all indexes of the table. - //! Returns empty ErrorData, if the append was successful. - ErrorData AppendToIndexes(optional_ptr delete_indexes, DataChunk &chunk, row_t row_start); - static ErrorData AppendToIndexes(TableIndexList &indexes, optional_ptr delete_indexes, - DataChunk &chunk, row_t row_start); + //! Append a chunk with the row ids [row_start, ..., row_start + chunk.size()] to all indexes of the table, returns + //! whether or not the append succeeded + ErrorData AppendToIndexes(DataChunk &chunk, row_t row_start); + static ErrorData AppendToIndexes(TableIndexList &indexes, DataChunk &chunk, row_t row_start); //! Remove a chunk with the row ids [row_start, ..., row_start + chunk.size()] from all indexes of the table void RemoveFromIndexes(TableAppendState &state, DataChunk &chunk, row_t row_start); //! Remove the chunk with the specified set of row identifiers from all indexes of the table @@ -180,16 +174,12 @@ class DataTable { void SetAsRoot() { this->is_root = true; } - bool IsRoot() { return this->is_root; } //! Get statistics of a physical column within the table unique_ptr GetStatistics(ClientContext &context, column_t column_id); - - //! Get table sample - unique_ptr GetSample(); //! Sets statistics of a physical column within the table void SetDistinct(column_t column_id, unique_ptr distinct_stats); @@ -218,14 +208,14 @@ class DataTable { unique_ptr InitializeConstraintState(TableCatalogEntry &table, const vector> &bound_constraints); //! Verify constraints with a chunk from the Append containing all columns of the table - void VerifyAppendConstraints(ConstraintState &constraint_state, ClientContext &context, DataChunk &chunk, - optional_ptr local_storage, optional_ptr manager); + void VerifyAppendConstraints(ConstraintState &state, ClientContext &context, DataChunk &chunk, + optional_ptr conflict_manager = nullptr); shared_ptr &GetDataTableInfo(); void InitializeIndexes(ClientContext &context); bool HasIndexes() const; - bool HasUniqueIndexes() const; + void AddIndex(unique_ptr index); bool HasForeignKeyIndex(const vector &keys, ForeignKeyType type); void SetIndexStorageInfo(vector index_storage_info); void VacuumIndexes(); @@ -236,33 +226,21 @@ class DataTable { TableStorageInfo GetStorageInfo(); - idx_t GetRowGroupSize() const; - - static void VerifyUniqueIndexes(TableIndexList &indexes, optional_ptr storage, DataChunk &chunk, - optional_ptr manager); - - //! AddIndex initializes an index and adds it to the table's index list. - //! It is either empty, or initialized via its index storage information. - void AddIndex(const ColumnList &columns, const vector &column_indexes, const IndexConstraintType type, - const IndexStorageInfo &info); - //! AddIndex moves an index to this table's index list. - void AddIndex(unique_ptr index); - - //! Returns a list of the partition stats - vector GetPartitionStats(ClientContext &context); +public: + static void VerifyUniqueIndexes(TableIndexList &indexes, ClientContext &context, DataChunk &chunk, + optional_ptr conflict_manager); private: //! Verify the new added constraints against current persistent&local data void VerifyNewConstraint(LocalStorage &local_storage, DataTable &parent, const BoundConstraint &constraint); - //! Verify constraints with a chunk from the Update containing only the specified column_ids void VerifyUpdateConstraints(ConstraintState &state, ClientContext &context, DataChunk &chunk, const vector &column_ids); //! Verify constraints with a chunk from the Delete containing all columns of the table void VerifyDeleteConstraints(TableDeleteState &state, ClientContext &context, DataChunk &chunk); - void InitializeScanWithOffset(DuckTransaction &transaction, TableScanState &state, - const vector &column_ids, idx_t start_row, idx_t end_row); + void InitializeScanWithOffset(TableScanState &state, const vector &column_ids, idx_t start_row, + idx_t end_row); void VerifyForeignKeyConstraint(const BoundForeignKeyConstraint &bfk, ClientContext &context, DataChunk &chunk, VerifyExistenceType verify_type); diff --git a/src/duckdb/src/include/duckdb/storage/index.hpp b/src/duckdb/src/include/duckdb/storage/index.hpp index 2b624c2c1..d838f60a3 100644 --- a/src/duckdb/src/include/duckdb/storage/index.hpp +++ b/src/duckdb/src/include/duckdb/storage/index.hpp @@ -59,8 +59,9 @@ class Index { //! Returns unique flag bool IsUnique() const { - auto type = GetConstraintType(); - return type == IndexConstraintType::UNIQUE || type == IndexConstraintType::PRIMARY; + auto index_constraint_type = GetConstraintType(); + return (index_constraint_type == IndexConstraintType::UNIQUE || + index_constraint_type == IndexConstraintType::PRIMARY); } //! Returns primary key flag diff --git a/src/duckdb/src/include/duckdb/storage/object_cache.hpp b/src/duckdb/src/include/duckdb/storage/object_cache.hpp index 96c3bf718..5ef1a6733 100644 --- a/src/duckdb/src/include/duckdb/storage/object_cache.hpp +++ b/src/duckdb/src/include/duckdb/storage/object_cache.hpp @@ -74,6 +74,7 @@ class ObjectCache { } DUCKDB_API static ObjectCache &GetObjectCache(ClientContext &context); + DUCKDB_API static bool ObjectCacheEnabled(ClientContext &context); private: //! Object Cache diff --git a/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp b/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp index fb6dd6c0e..57dd4d8d6 100644 --- a/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp +++ b/src/duckdb/src/include/duckdb/storage/segment/uncompressed.hpp @@ -14,7 +14,7 @@ namespace duckdb { class DatabaseInstance; struct UncompressedFunctions { - static unique_ptr InitCompression(ColumnDataCheckpointData &checkpoint_data, + static unique_ptr InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state); static void Compress(CompressionState &state_p, Vector &data, idx_t count); static void FinalizeCompress(CompressionState &state_p); @@ -29,9 +29,6 @@ struct FixedSizeUncompressed { struct ValidityUncompressed { public: static CompressionFunction GetFunction(PhysicalType data_type); - static void AlignedScan(data_ptr_t input, idx_t input_start, Vector &result, idx_t scan_count); - static void UnalignedScan(data_ptr_t input, idx_t input_size, idx_t input_start, Vector &result, - idx_t result_offset, idx_t scan_count); public: static const validity_t LOWER_MASKS[65]; diff --git a/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp b/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp index 93c348a6a..383882bef 100644 --- a/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/standard_buffer_manager.hpp @@ -49,7 +49,7 @@ class StandardBufferManager : public BufferManager { //! Registers an in-memory buffer that cannot be unloaded until it is destroyed. //! This buffer can be small (smaller than the block size of the temporary block manager). //! Unpin and Pin are NOPs on this block of memory. - shared_ptr RegisterSmallMemory(MemoryTag tag, const idx_t size) final; + shared_ptr RegisterSmallMemory(const idx_t size) final; idx_t GetUsedMemory() const final; idx_t GetMaxMemory() const final; @@ -120,7 +120,7 @@ class StandardBufferManager : public BufferManager { shared_ptr RegisterMemory(MemoryTag tag, idx_t block_size, bool can_destroy); //! Garbage collect eviction queue - void PurgeQueue(const BlockHandle &handle) final; + void PurgeQueue(FileBufferType type) final; BufferPool &GetBufferPool() const final; TemporaryMemoryManager &GetTemporaryMemoryManager() final; @@ -148,7 +148,7 @@ class StandardBufferManager : public BufferManager { //! When the BlockHandle reaches 0 readers, this creates a new FileBuffer for this BlockHandle and //! overwrites the data within with garbage. Any readers that do not hold the pin will notice - void VerifyZeroReaders(BlockLock &l, shared_ptr &handle); + void VerifyZeroReaders(shared_ptr &handle); void BatchRead(vector> &handles, const map &load_map, block_id_t first_block, block_id_t last_block); diff --git a/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp b/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp index 12f8d5672..0cc4c69a5 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp @@ -24,7 +24,7 @@ class ColumnStatistics { void Merge(ColumnStatistics &other); - void UpdateDistinctStatistics(Vector &v, idx_t count, Vector &hashes); + void UpdateDistinctStatistics(Vector &v, idx_t count); BaseStatistics &Statistics(); diff --git a/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp b/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp index aaa4acb0e..5bfe6e200 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp @@ -34,8 +34,8 @@ class DistinctStatistics { unique_ptr Copy() const; - void UpdateSample(Vector &new_data, idx_t count, Vector &hashes); - void Update(Vector &new_data, idx_t count, Vector &hashes); + void Update(Vector &update, idx_t count, bool sample = true); + void Update(UnifiedVectorFormat &update_data, const LogicalType &ptype, idx_t count, bool sample = true); string ToString() const; idx_t GetCount() const; @@ -45,14 +45,13 @@ class DistinctStatistics { void Serialize(Serializer &serializer) const; static unique_ptr Deserialize(Deserializer &deserializer); -private: - void UpdateInternal(Vector &update, idx_t count, Vector &hashes); - private: //! For distinct statistics we sample the input to speed up insertions static constexpr double BASE_SAMPLE_RATE = 0.1; //! For integers, we sample more: likely to be join keys (and hashing is cheaper than, e.g., strings) static constexpr double INTEGRAL_SAMPLE_RATE = 0.3; + //! For concurrent access + mutable mutex lock; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/statistics/numeric_stats.hpp b/src/duckdb/src/include/duckdb/storage/statistics/numeric_stats.hpp index 342a6f30b..9515acbec 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/numeric_stats.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/numeric_stats.hpp @@ -13,7 +13,6 @@ #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/types/value.hpp" #include "duckdb/storage/statistics/numeric_stats_union.hpp" -#include "duckdb/common/array_ptr.hpp" namespace duckdb { class BaseStatistics; @@ -54,23 +53,9 @@ struct NumericStats { //! Sets the max value of the statistics DUCKDB_API static void SetMax(BaseStatistics &stats, const Value &val); - template - static void SetMax(BaseStatistics &stats, T val) { - auto &nstats = GetDataUnsafe(stats); - nstats.has_max = true; - nstats.max.GetReferenceUnsafe() = val; - } - - template - static void SetMin(BaseStatistics &stats, T val) { - auto &nstats = GetDataUnsafe(stats); - nstats.has_min = true; - nstats.min.GetReferenceUnsafe() = val; - } - //! Check whether or not a given comparison with a constant could possibly be satisfied by rows given the statistics DUCKDB_API static FilterPropagateResult CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type, - array_ptr constants); + const Value &constant); DUCKDB_API static void Merge(BaseStatistics &stats, const BaseStatistics &other_p); diff --git a/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp b/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp index 6ae410bea..f069ecc45 100644 --- a/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp +++ b/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp @@ -14,7 +14,6 @@ #include "duckdb/common/exception.hpp" #include "duckdb/common/operator/comparison_operators.hpp" #include "duckdb/common/types/hugeint.hpp" -#include "duckdb/common/array_ptr.hpp" namespace duckdb { class BaseStatistics; @@ -63,7 +62,7 @@ struct StringStats { DUCKDB_API static string ToString(const BaseStatistics &stats); DUCKDB_API static FilterPropagateResult CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type, - array_ptr constants); + const string &value); DUCKDB_API static FilterPropagateResult CheckZonemap(const_data_ptr_t min_data, idx_t min_len, const_data_ptr_t max_data, idx_t max_len, ExpressionType comparison_type, const string &value); diff --git a/src/duckdb/src/include/duckdb/storage/storage_index.hpp b/src/duckdb/src/include/duckdb/storage/storage_index.hpp deleted file mode 100644 index 38ba99976..000000000 --- a/src/duckdb/src/include/duckdb/storage/storage_index.hpp +++ /dev/null @@ -1,70 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/storage/storage_index.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/constants.hpp" -#include "duckdb/common/vector.hpp" - -namespace duckdb { - -struct StorageIndex { - StorageIndex() : index(DConstants::INVALID_INDEX) { - } - explicit StorageIndex(idx_t index) : index(index) { - } - StorageIndex(idx_t index, vector child_indexes_p) - : index(index), child_indexes(std::move(child_indexes_p)) { - } - - inline bool operator==(const StorageIndex &rhs) const { - return index == rhs.index; - } - inline bool operator!=(const StorageIndex &rhs) const { - return index != rhs.index; - } - inline bool operator<(const StorageIndex &rhs) const { - return index < rhs.index; - } - idx_t GetPrimaryIndex() const { - return index; - } - PhysicalIndex ToPhysical() const { - return PhysicalIndex(index); - } - bool HasChildren() const { - return !child_indexes.empty(); - } - idx_t ChildIndexCount() const { - return child_indexes.size(); - } - const StorageIndex &GetChildIndex(idx_t idx) const { - return child_indexes[idx]; - } - StorageIndex &GetChildIndex(idx_t idx) { - return child_indexes[idx]; - } - const vector &GetChildIndexes() const { - return child_indexes; - } - void AddChildIndex(StorageIndex new_index) { - this->child_indexes.push_back(std::move(new_index)); - } - void SetIndex(idx_t new_index) { - index = new_index; - } - bool IsRowIdColumn() const { - return index == DConstants::INVALID_INDEX; - } - -private: - idx_t index; - vector child_indexes; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/storage_info.hpp b/src/duckdb/src/include/duckdb/storage/storage_info.hpp index a2047d720..17fb6c288 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_info.hpp @@ -17,7 +17,7 @@ namespace duckdb { struct FileHandle; //! The standard row group size -#define DEFAULT_ROW_GROUP_SIZE 122880ULL +#define STANDARD_ROW_GROUPS_SIZE 122880 //! The definition of an invalid block #define INVALID_BLOCK (-1) //! The maximum block id is 2^62 @@ -38,8 +38,10 @@ struct Storage { //! The size of the headers. This should be small and written more or less atomically by the hard disk. We default //! to the page size, which is 4KB. (1 << 12) constexpr static idx_t FILE_HEADER_SIZE = 4096U; - //! The maximum row group size - constexpr static const idx_t MAX_ROW_GROUP_SIZE = 1ULL << 30ULL; + //! The number of rows per row group (must be a multiple of the vector size) + constexpr static const idx_t ROW_GROUP_SIZE = STANDARD_ROW_GROUPS_SIZE; + //! The number of vectors per row group + constexpr static const idx_t ROW_GROUP_VECTOR_COUNT = ROW_GROUP_SIZE / STANDARD_VECTOR_SIZE; //! The minimum block allocation size. This is the minimum size we test in our nightly tests. constexpr static idx_t MIN_BLOCK_ALLOC_SIZE = 16384ULL; @@ -116,10 +118,10 @@ struct DatabaseHeader { //! Detect mismatching constant values when compiling -#if (DEFAULT_ROW_GROUP_SIZE % STANDARD_VECTOR_SIZE != 0) +#if (STANDARD_ROW_GROUPS_SIZE % STANDARD_VECTOR_SIZE != 0) #error The row group size must be a multiple of the vector size #endif -#if (DEFAULT_ROW_GROUP_SIZE < STANDARD_VECTOR_SIZE) +#if (STANDARD_ROW_GROUPS_SIZE < STANDARD_VECTOR_SIZE) #error Row groups must be able to hold at least one vector #endif #if (DEFAULT_BLOCK_ALLOC_SIZE & (DEFAULT_BLOCK_ALLOC_SIZE - 1) != 0) diff --git a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp index b72d3972d..1820805ff 100644 --- a/src/duckdb/src/include/duckdb/storage/storage_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/storage_manager.hpp @@ -15,7 +15,6 @@ #include "duckdb/storage/write_ahead_log.hpp" #include "duckdb/storage/database_size.hpp" #include "duckdb/common/enums/checkpoint_type.hpp" -#include "duckdb/storage/storage_options.hpp" namespace duckdb { class BlockManager; @@ -72,7 +71,7 @@ class StorageManager { //! Initialize a database or load an existing database from the database file path. The block_alloc_size is //! either set, or invalid. If invalid, then DuckDB defaults to the default_block_alloc_size (DBConfig), //! or the file's block allocation size, if it is an existing database. - void Initialize(StorageOptions options); + void Initialize(const optional_idx block_alloc_size); DatabaseInstance &GetDatabase(); AttachedDatabase &GetAttached() { @@ -107,7 +106,7 @@ class StorageManager { virtual BlockManager &GetBlockManager() = 0; protected: - virtual void LoadDatabase(StorageOptions options) = 0; + virtual void LoadDatabase(const optional_idx block_alloc_size) = 0; protected: //! The database this storage manager belongs to @@ -157,6 +156,6 @@ class SingleFileStorageManager : public StorageManager { BlockManager &GetBlockManager() override; protected: - void LoadDatabase(StorageOptions options) override; + void LoadDatabase(const optional_idx block_alloc_size) override; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/storage_options.hpp b/src/duckdb/src/include/duckdb/storage/storage_options.hpp deleted file mode 100644 index 8935f09a5..000000000 --- a/src/duckdb/src/include/duckdb/storage/storage_options.hpp +++ /dev/null @@ -1,23 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/storage/storage_options.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/common/optional_idx.hpp" - -namespace duckdb { - -struct StorageOptions { - //! The allocation size of blocks for this attached database file (if any) - optional_idx block_alloc_size; - //! The row group size for this attached database (if any) - optional_idx row_group_size; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp b/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp index 981d4e4ef..9d8233597 100644 --- a/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp +++ b/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp @@ -41,18 +41,6 @@ struct StringScanState : public SegmentScanState { BufferHandle handle; }; -//===--------------------------------------------------------------------===// -// Append -//===--------------------------------------------------------------------===// -struct SerializedStringSegmentState : public ColumnSegmentState { -public: - SerializedStringSegmentState(); - explicit SerializedStringSegmentState(vector blocks_p); - -public: - void Serialize(Serializer &serializer) const override; -}; - struct UncompressedStringStorage { public: //! Dictionary header size at the beginning of the string segment (offset + length) @@ -72,9 +60,6 @@ struct UncompressedStringStorage { static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset); static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result); - static void Select(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count); - static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx); static unique_ptr StringInitSegment(ColumnSegment &segment, block_id_t block_id, @@ -217,25 +202,12 @@ struct UncompressedStringStorage { static void WriteStringMarker(data_ptr_t target, block_id_t block_id, int32_t offset); static void ReadStringMarker(data_ptr_t target, block_id_t &block_id, int32_t &offset); - inline static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result, - data_ptr_t base_ptr, int32_t dict_offset, uint32_t string_length) { - D_ASSERT(dict_offset <= NumericCast(segment.GetBlockManager().GetBlockSize())); - if (DUCKDB_LIKELY(dict_offset >= 0)) { - // regular string - fetch from dictionary - auto dict_end = base_ptr + dict.end; - auto dict_pos = dict_end - dict_offset; - - auto str_ptr = char_ptr_cast(dict_pos); - return string_t(str_ptr, string_length); - } else { - // read overflow string - block_id_t block_id; - int32_t offset; - ReadStringMarker(base_ptr + dict.end - AbsValue(dict_offset), block_id, offset); - - return ReadOverflowString(segment, result, block_id, offset); - } - } + static string_location_t FetchStringLocation(StringDictionaryContainer dict, data_ptr_t base_ptr, + int32_t dict_offset, const idx_t block_size); + static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result, + data_ptr_t base_ptr, int32_t dict_offset, uint32_t string_length); + static string_t FetchString(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result, + data_ptr_t baseptr, string_location_t location, uint32_t string_length); static unique_ptr SerializeState(ColumnSegment &segment); static unique_ptr DeserializeState(Deserializer &deserializer); diff --git a/src/duckdb/src/include/duckdb/storage/table/append_state.hpp b/src/duckdb/src/include/duckdb/storage/table/append_state.hpp index 0a5c7b170..d7d2d37d8 100644 --- a/src/duckdb/src/include/duckdb/storage/table/append_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/append_state.hpp @@ -72,8 +72,6 @@ struct TableAppendState { TransactionData transaction; //! Table statistics TableStatistics stats; - //! Cached hash vector - Vector hashes; }; struct ConstraintState { diff --git a/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp index 2a0ec1d07..447324ee3 100644 --- a/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/array_column_data.hpp @@ -1,7 +1,7 @@ //===----------------------------------------------------------------------===// // DuckDB // -// duckdb/storage/table/array_column_data.hpp +// duckdb/storage/table/list_column_data.hpp // // //===----------------------------------------------------------------------===// @@ -21,7 +21,7 @@ class ArrayColumnData : public ColumnData { //! The child-column of the list unique_ptr child_column; - //! The validity column data of the array + //! The validity column data of the struct ValidityColumnData validity; public: diff --git a/src/duckdb/src/include/duckdb/storage/table/column_checkpoint_state.hpp b/src/duckdb/src/include/duckdb/storage/table/column_checkpoint_state.hpp index 09c8985f2..5830496bc 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_checkpoint_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_checkpoint_state.hpp @@ -40,8 +40,7 @@ struct ColumnCheckpointState { public: virtual unique_ptr GetStatistics(); - virtual void FlushSegmentInternal(unique_ptr segment, idx_t segment_size); - virtual void FlushSegment(unique_ptr segment, BufferHandle handle, idx_t segment_size); + virtual void FlushSegment(unique_ptr segment, idx_t segment_size); virtual PersistentColumnData ToPersistentData(); PartialBlockManager &GetPartialBlockManager() { diff --git a/src/duckdb/src/include/duckdb/storage/table/column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/column_data.hpp index adb3ed056..c3e214948 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_data.hpp @@ -18,7 +18,6 @@ #include "duckdb/common/mutex.hpp" #include "duckdb/common/enums/scan_vector_type.hpp" #include "duckdb/common/serializer/serialization_traits.hpp" -#include "duckdb/common/atomic_ptr.hpp" namespace duckdb { class ColumnData; @@ -35,8 +34,6 @@ struct TableScanOptions; struct TransactionData; struct PersistentColumnData; -using column_segment_vector_t = vector>; - struct ColumnCheckpointInfo { ColumnCheckpointInfo(RowGroupWriteInfo &info, idx_t column_idx) : info(info), column_idx(column_idx) { } @@ -68,6 +65,8 @@ class ColumnData { idx_t column_index; //! The type of the column LogicalType type; + //! The parent column (if any) + optional_ptr parent; public: virtual FilterPropagateResult CheckZonemap(ColumnScanState &state, TableFilter &filter); @@ -82,24 +81,12 @@ class ColumnData { idx_t GetAllocationSize() const { return allocation_size; } - optional_ptr GetCompressionFunction() const { - return compression.get(); - } - - bool HasParent() const { - return parent != nullptr; - } - const ColumnData &Parent() const { - D_ASSERT(HasParent()); - return *parent; - } virtual void SetStart(idx_t new_start); //! The root type of the column const LogicalType &RootType() const; //! Whether or not the column has any updates bool HasUpdates() const; - bool HasChanges(idx_t start_row, idx_t end_row) const; //! Whether or not we can scan an entire vector virtual ScanVectorType GetVectorScanType(ColumnScanState &state, idx_t scan_count, Vector &result); @@ -121,12 +108,12 @@ class ColumnData { virtual idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count); //! Select - virtual void Filter(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t &count, const TableFilter &filter); virtual void Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t count); - virtual void SelectCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel, - idx_t count, bool allow_updates); + SelectionVector &sel, idx_t &count, const TableFilter &filter); + virtual void FilterScan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, + SelectionVector &sel, idx_t count); + virtual void FilterScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel, + idx_t count, bool allow_updates); //! Skip the scan forward by "count" rows virtual void Skip(ColumnScanState &state, idx_t count = STANDARD_VECTOR_SIZE); @@ -190,20 +177,14 @@ class ColumnData { protected: //! Append a transient segment void AppendTransientSegment(SegmentLock &l, idx_t start_row); - void AppendSegment(SegmentLock &l, unique_ptr segment); - void BeginScanVectorInternal(ColumnScanState &state); //! Scans a base vector from the column idx_t ScanVector(ColumnScanState &state, Vector &result, idx_t remaining, ScanVectorType scan_type); //! Scans a vector from the column merged with any potential updates + //! If ALLOW_UPDATES is set to false, the function will instead throw an exception if any updates are found + template idx_t ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - idx_t target_scan, ScanVectorType scan_type, ScanVectorMode mode); - idx_t ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - idx_t target_scan, ScanVectorMode mode); - void SelectVector(ColumnScanState &state, Vector &result, idx_t target_count, const SelectionVector &sel, - idx_t sel_count); - void FilterVector(ColumnScanState &state, Vector &result, idx_t target_count, SelectionVector &sel, - idx_t &sel_count, const TableFilter &filter); + idx_t target_scan); void ClearUpdates(); void FetchUpdates(TransactionData transaction, idx_t vector_index, Vector &result, idx_t scan_count, @@ -214,9 +195,6 @@ class ColumnData { idx_t GetVectorCount(idx_t vector_index) const; -private: - void UpdateCompressionFunction(SegmentLock &l, const CompressionFunction &function); - protected: //! The segments holding the data of this column segment ColumnSegmentTree data; @@ -230,13 +208,6 @@ class ColumnData { unique_ptr stats; //! Total transient allocation size idx_t allocation_size; - -private: - //! The parent column (if any) - optional_ptr parent; - //! The compression function used by the ColumnData - //! This is empty if the segments have mixed compression or the ColumnData is empty - atomic_ptr compression; }; struct PersistentColumnData { diff --git a/src/duckdb/src/include/duckdb/storage/table/column_data_checkpointer.hpp b/src/duckdb/src/include/duckdb/storage/table/column_data_checkpointer.hpp index 0db0e6fbc..eb105e55a 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_data_checkpointer.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_data_checkpointer.hpp @@ -15,79 +15,37 @@ namespace duckdb { struct TableScanOptions; -//! Holds state related to a single column during compression -struct ColumnDataCheckpointData { +class ColumnDataCheckpointer { public: - //! Default constructor used when column data does not need to be checkpointed - ColumnDataCheckpointData() { - } - ColumnDataCheckpointData(ColumnCheckpointState &checkpoint_state, ColumnData &col_data, DatabaseInstance &db, - RowGroup &row_group, ColumnCheckpointInfo &checkpoint_info) - : checkpoint_state(checkpoint_state), col_data(col_data), db(db), row_group(row_group), - checkpoint_info(checkpoint_info) { - } + ColumnDataCheckpointer(ColumnData &col_data_p, RowGroup &row_group_p, ColumnCheckpointState &state_p, + ColumnCheckpointInfo &checkpoint_info); public: - CompressionFunction &GetCompressionFunction(CompressionType type); + DatabaseInstance &GetDatabase(); const LogicalType &GetType() const; ColumnData &GetColumnData(); RowGroup &GetRowGroup(); ColumnCheckpointState &GetCheckpointState(); - DatabaseInstance &GetDatabase(); - -private: - optional_ptr checkpoint_state; - optional_ptr col_data; - optional_ptr db; - optional_ptr row_group; - optional_ptr checkpoint_info; -}; - -struct CheckpointAnalyzeResult { -public: - //! Default constructor, returned when the column data doesn't require checkpoint - CheckpointAnalyzeResult() { - } - CheckpointAnalyzeResult(unique_ptr &&analyze_state, CompressionFunction &function) - : analyze_state(std::move(analyze_state)), function(function) { - } -public: - unique_ptr analyze_state; - optional_ptr function; -}; - -class ColumnDataCheckpointer { -public: - ColumnDataCheckpointer(vector> &states, DatabaseInstance &db, RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info); - -public: - void Checkpoint(); - void FinalizeCheckpoint(); + void Checkpoint(vector> nodes); + CompressionFunction &GetCompressionFunction(CompressionType type); private: void ScanSegments(const std::function &callback); - vector DetectBestCompressionMethod(); + unique_ptr DetectBestCompressionMethod(idx_t &compression_idx); void WriteToDisk(); - bool HasChanges(ColumnData &col_data); - void WritePersistentSegments(ColumnCheckpointState &state); - void InitAnalyze(); - void DropSegments(); - bool ValidityCoveredByBasedata(vector &result); + bool HasChanges(); + void WritePersistentSegments(); private: - vector> &checkpoint_states; - DatabaseInstance &db; + ColumnData &col_data; RowGroup &row_group; + ColumnCheckpointState &state; + bool is_validity; Vector intermediate; + vector> nodes; + vector> compression_functions; ColumnCheckpointInfo &checkpoint_info; - - vector has_changes; - //! For every column data that is being checkpointed, the applicable functions - vector>> compression_functions; - //! For every column data that is being checkpointed, the analyze state of functions being tried - vector>> analyze_states; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp b/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp index 45d2db0c0..2b1e70706 100644 --- a/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp @@ -38,37 +38,37 @@ enum class ColumnSegmentType : uint8_t { TRANSIENT, PERSISTENT }; class ColumnSegment : public SegmentBase { public: - //! Construct a column segment. - ColumnSegment(DatabaseInstance &db, shared_ptr block, const LogicalType &type, - const ColumnSegmentType segment_type, const idx_t start, const idx_t count, - CompressionFunction &function_p, BaseStatistics statistics, const block_id_t block_id_p, - const idx_t offset, const idx_t segment_size_p, - unique_ptr segment_state_p = nullptr); - //! Construct a column segment from another column segment. - //! The other column segment becomes invalid (std::move). - ColumnSegment(ColumnSegment &other, const idx_t start); ~ColumnSegment(); -public: + //! The database instance + DatabaseInstance &db; + //! The type stored in the column + LogicalType type; + //! The size of the type + idx_t type_size; + //! The column segment type (transient or persistent) + ColumnSegmentType segment_type; + //! The compression function + reference function; + //! The statistics for the segment + SegmentStatistics stats; + //! The block that this segment relates to + shared_ptr block; + static unique_ptr CreatePersistentSegment(DatabaseInstance &db, BlockManager &block_manager, block_id_t id, idx_t offset, const LogicalType &type_p, idx_t start, idx_t count, CompressionType compression_type, BaseStatistics statistics, unique_ptr segment_state); - static unique_ptr CreateTransientSegment(DatabaseInstance &db, CompressionFunction &function, - const LogicalType &type, const idx_t start, - const idx_t segment_size, const idx_t block_size); + static unique_ptr CreateTransientSegment(DatabaseInstance &db, const LogicalType &type, + const idx_t start, const idx_t segment_size, + const idx_t block_size); public: void InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state); void InitializeScan(ColumnScanState &state); //! Scan one vector from this segment void Scan(ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset, ScanVectorType scan_type); - //! Scan a subset of a vector (defined by the selection vector) - void Select(ColumnScanState &state, idx_t scan_count, Vector &result, const SelectionVector &sel, idx_t sel_count); - //! Scan one vector while applying a filter to the vector, returning only the matching elements - void Filter(ColumnScanState &state, idx_t scan_count, Vector &result, SelectionVector &sel, idx_t &sel_count, - const TableFilter &filter); //! Fetch a value of the specific row id and append it to the result void FetchRow(ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx); @@ -82,7 +82,6 @@ class ColumnSegment : public SegmentBase { idx_t SegmentSize() const; //! Resize the block void Resize(idx_t segment_size); - const CompressionFunction &GetCompressionFunction(); //! Initialize an append of this segment. Appends are only supported on transient segments. void InitializeAppend(ColumnAppendState &state); @@ -133,27 +132,22 @@ class ColumnSegment : public SegmentBase { void CommitDropSegment(); +public: + //! Construct a column segment. + ColumnSegment(DatabaseInstance &db, shared_ptr block, const LogicalType &type, + const ColumnSegmentType segment_type, const idx_t start, const idx_t count, + CompressionFunction &function_p, BaseStatistics statistics, const block_id_t block_id_p, + const idx_t offset, const idx_t segment_size_p, + unique_ptr segment_state_p = nullptr); + //! Construct a column segment from another column segment. + //! The other column segment becomes invalid (std::move). + ColumnSegment(ColumnSegment &other, const idx_t start); + private: void Scan(ColumnScanState &state, idx_t scan_count, Vector &result); void ScanPartial(ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset); -public: - //! The database instance - DatabaseInstance &db; - //! The type stored in the column - LogicalType type; - //! The size of the type - idx_t type_size; - //! The column segment type (transient or persistent) - ColumnSegmentType segment_type; - //! The statistics for the segment - SegmentStatistics stats; - //! The block that this segment relates to - shared_ptr block; - private: - //! The compression function - reference function; //! The block id that this segment relates to (persistent segment only) block_id_t block_id; //! The offset into the block (persistent segment only) diff --git a/src/duckdb/src/include/duckdb/storage/table/delete_state.hpp b/src/duckdb/src/include/duckdb/storage/table/delete_state.hpp index d3a05eeeb..6d25df4a5 100644 --- a/src/duckdb/src/include/duckdb/storage/table/delete_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/delete_state.hpp @@ -17,7 +17,7 @@ struct TableDeleteState { unique_ptr constraint_state; bool has_delete_constraints = false; DataChunk verify_chunk; - vector col_ids; + vector col_ids; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp index c4ec56740..57b9f2358 100644 --- a/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp @@ -21,7 +21,7 @@ class ListColumnData : public ColumnData { //! The child-column of the list unique_ptr child_column; - //! The validity column data of the list + //! The validity column data of the struct ValidityColumnData validity; public: diff --git a/src/duckdb/src/include/duckdb/storage/table/row_group.hpp b/src/duckdb/src/include/duckdb/storage/table/row_group.hpp index 16a535a4e..e3f2e3dbd 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_group.hpp @@ -18,8 +18,6 @@ #include "duckdb/storage/table/segment_base.hpp" #include "duckdb/storage/block.hpp" #include "duckdb/common/enums/checkpoint_type.hpp" -#include "duckdb/storage/storage_index.hpp" -#include "duckdb/function/partition_stats.hpp" namespace duckdb { class AttachedDatabase; @@ -125,7 +123,7 @@ class RowGroup : public SegmentBase { //! For a specific row, returns true if it should be used for the transaction and false otherwise. bool Fetch(TransactionData transaction, idx_t row); //! Fetch a specific row from the row_group and insert it into the result at the specified index - void FetchRow(TransactionData transaction, ColumnFetchState &state, const vector &column_ids, + void FetchRow(TransactionData transaction, ColumnFetchState &state, const vector &column_ids, row_t row_id, DataChunk &result, idx_t result_idx); //! Append count rows to the version info @@ -164,7 +162,6 @@ class RowGroup : public SegmentBase { unique_ptr GetStatistics(idx_t column_idx); void GetColumnSegmentInfo(idx_t row_group_index, vector &result); - PartitionStatistics GetPartitionStats() const; idx_t GetAllocationSize() const { return allocation_size; @@ -181,8 +178,6 @@ class RowGroup : public SegmentBase { static void Serialize(RowGroupPointer &pointer, Serializer &serializer); static RowGroupPointer Deserialize(Deserializer &deserializer); - idx_t GetRowGroupSize() const; - private: optional_ptr GetVersionInfo(); shared_ptr GetOrCreateVersionInfoPtr(); @@ -190,7 +185,6 @@ class RowGroup : public SegmentBase { void SetVersionInfo(shared_ptr version); ColumnData &GetColumn(storage_t c); - ColumnData &GetColumn(const StorageIndex &c); idx_t GetColumnCount() const; vector> &GetColumns(); diff --git a/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp b/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp index 19aa64520..9184abf50 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp @@ -12,7 +12,6 @@ #include "duckdb/storage/table/segment_tree.hpp" #include "duckdb/storage/statistics/column_statistics.hpp" #include "duckdb/storage/table/table_statistics.hpp" -#include "duckdb/storage/storage_index.hpp" namespace duckdb { @@ -35,14 +34,11 @@ struct VacuumState; struct CollectionCheckpointState; struct PersistentCollectionData; class CheckpointTask; -class TableIOManager; class RowGroupCollection { public: - RowGroupCollection(shared_ptr info, TableIOManager &io_manager, vector types, - idx_t row_start, idx_t total_rows = 0); RowGroupCollection(shared_ptr info, BlockManager &block_manager, vector types, - idx_t row_start, idx_t total_rows, idx_t row_group_size); + idx_t row_start, idx_t total_rows = 0); public: idx_t GetTotalRows() const; @@ -59,21 +55,20 @@ class RowGroupCollection { RowGroup *GetRowGroup(int64_t index); void Verify(); - void InitializeScan(CollectionScanState &state, const vector &column_ids, - TableFilterSet *table_filters); + void InitializeScan(CollectionScanState &state, const vector &column_ids, TableFilterSet *table_filters); void InitializeCreateIndexScan(CreateIndexScanState &state); - void InitializeScanWithOffset(CollectionScanState &state, const vector &column_ids, idx_t start_row, + void InitializeScanWithOffset(CollectionScanState &state, const vector &column_ids, idx_t start_row, idx_t end_row); static bool InitializeScanInRowGroup(CollectionScanState &state, RowGroupCollection &collection, RowGroup &row_group, idx_t vector_index, idx_t max_row); void InitializeParallelScan(ParallelCollectionScanState &state); bool NextParallelScan(ClientContext &context, ParallelCollectionScanState &state, CollectionScanState &scan_state); - bool Scan(DuckTransaction &transaction, const vector &column_ids, + bool Scan(DuckTransaction &transaction, const vector &column_ids, const std::function &fun); bool Scan(DuckTransaction &transaction, const std::function &fun); - void Fetch(TransactionData transaction, DataChunk &result, const vector &column_ids, + void Fetch(TransactionData transaction, DataChunk &result, const vector &column_ids, const Vector &row_identifiers, idx_t fetch_count, ColumnFetchState &state); //! Initialize an append of a variable number of rows. FinalizeAppend must be called after appending is done. @@ -111,7 +106,6 @@ class RowGroupCollection { void CommitDropColumn(idx_t index); void CommitDropTable(); - vector GetPartitionStats() const; vector GetColumnSegmentInfo(); const vector &GetTypes() const; @@ -119,12 +113,11 @@ class RowGroupCollection { ExpressionExecutor &default_executor); shared_ptr RemoveColumn(idx_t col_idx); shared_ptr AlterType(ClientContext &context, idx_t changed_idx, const LogicalType &target_type, - vector bound_columns, Expression &cast_expr); + vector bound_columns, Expression &cast_expr); void VerifyNewConstraint(DataTable &parent, const BoundConstraint &constraint); void CopyStats(TableStatistics &stats); unique_ptr CopyStats(column_t column_id); - unique_ptr GetSample(); void SetDistinct(column_t column_id, unique_ptr distinct_stats); AttachedDatabase &GetAttached(); @@ -140,18 +133,12 @@ class RowGroupCollection { return allocation_size; } - idx_t GetRowGroupSize() const { - return row_group_size; - } - private: bool IsEmpty(SegmentLock &) const; private: //! BlockManager BlockManager &block_manager; - //! The row group size of the row group collection - const idx_t row_group_size; //! The number of rows in the table atomic total_rows; //! The data table info diff --git a/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp b/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp index bb0d0056b..25bd70dd6 100644 --- a/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/row_version_manager.hpp @@ -49,14 +49,13 @@ class RowVersionManager { private: mutex version_lock; idx_t start; - vector> vector_info; + unique_ptr vector_info[Storage::ROW_GROUP_VECTOR_COUNT]; bool has_changes; vector storage_pointers; private: optional_ptr GetChunkInfo(idx_t vector_idx); ChunkVectorInfo &GetVectorInfo(idx_t vector_idx); - void FillVectorInfo(idx_t vector_idx); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp b/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp index e94381a65..bd7d03771 100644 --- a/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp @@ -13,11 +13,8 @@ #include "duckdb/storage/buffer/buffer_handle.hpp" #include "duckdb/storage/storage_lock.hpp" #include "duckdb/common/enums/scan_options.hpp" -#include "duckdb/common/random_engine.hpp" #include "duckdb/storage/table/segment_lock.hpp" #include "duckdb/common/types/data_chunk.hpp" -#include "duckdb/parser/parsed_data/sample_options.hpp" -#include "duckdb/storage/storage_index.hpp" namespace duckdb { class AdaptiveFilter; @@ -39,7 +36,6 @@ class RowGroupSegmentTree; class TableFilter; struct AdaptiveFilterState; struct TableScanOptions; -struct ScanSamplingInfo; struct SegmentScanState { virtual ~SegmentScanState() { @@ -97,14 +93,10 @@ struct ColumnScanState { vector> previous_states; //! The last read offset in the child state (used for LIST columns only) idx_t last_offset = 0; - //! Whether or not we should scan a specific child column - vector scan_child_column; //! Contains TableScan level config for scanning optional_ptr scan_options; public: - void Initialize(const LogicalType &type, const vector &children, - optional_ptr options); void Initialize(const LogicalType &type, optional_ptr options); //! Move the scan state forward by "count" rows (including all child states) void Next(idx_t count); @@ -122,7 +114,7 @@ struct ColumnFetchState { }; struct ScanFilter { - ScanFilter(idx_t index, const vector &column_ids, TableFilter &filter); + ScanFilter(idx_t index, const vector &column_ids, TableFilter &filter); idx_t scan_column_index; idx_t table_column_index; @@ -138,7 +130,7 @@ class ScanFilterInfo { public: ~ScanFilterInfo(); - void Initialize(TableFilterSet &filters, const vector &column_ids); + void Initialize(TableFilterSet &filters, const vector &column_ids); const vector &GetFilterList() const { return filter_list; @@ -196,13 +188,10 @@ class CollectionScanState { //! The valid selection SelectionVector valid_sel; - RandomEngine random; - public: void Initialize(const vector &types); - const vector &GetColumnIds(); + const vector &GetColumnIds(); ScanFilterInfo &GetFilterInfo(); - ScanSamplingInfo &GetSamplingInfo(); TableScanOptions &GetOptions(); bool Scan(DuckTransaction &transaction, DataChunk &result); bool ScanCommitted(DataChunk &result, TableScanType type); @@ -212,13 +201,6 @@ class CollectionScanState { TableScanState &parent; }; -struct ScanSamplingInfo { - //! Whether or not to do a system sample during scanning - bool do_system_sample = false; - //! The sampling rate to use - double sample_rate; -}; - struct TableScanOptions { //! Fetch rows one-at-a-time instead of using the regular scans. bool force_fetch_row = false; @@ -248,22 +230,17 @@ class TableScanState { shared_ptr checkpoint_lock; //! Filter info ScanFilterInfo filters; - //! Sampling info - ScanSamplingInfo sampling_info; public: - void Initialize(vector column_ids, optional_ptr table_filters = nullptr, - optional_ptr table_sampling = nullptr); + void Initialize(vector column_ids, optional_ptr table_filters = nullptr); - const vector &GetColumnIds(); + const vector &GetColumnIds(); ScanFilterInfo &GetFilterInfo(); - ScanSamplingInfo &GetSamplingInfo(); - private: //! The column identifiers of the scan - vector column_ids; + vector column_ids; }; struct ParallelCollectionScanState { diff --git a/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp b/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp index 1a461ac37..218cdac9b 100644 --- a/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/segment_tree.hpp @@ -67,16 +67,6 @@ class SegmentTree { auto l = Lock(); return MoveSegments(l); } - - const vector> &ReferenceSegments(SegmentLock &l) { - LoadAllSegments(l); - return nodes; - } - const vector> &ReferenceSegments() { - auto l = Lock(); - return ReferenceSegments(l); - } - idx_t GetSegmentCount() { auto l = Lock(); return GetSegmentCount(l); @@ -177,6 +167,16 @@ class SegmentTree { return segment->index < nodes.size() && nodes[segment->index].node.get() == segment; } + //! Replace this tree with another tree, taking over its nodes in-place + void Replace(SegmentTree &other) { + auto l = Lock(); + Replace(l, other); + } + void Replace(SegmentLock &l, SegmentTree &other) { + other.LoadAllSegments(l); + nodes = std::move(other.nodes); + } + //! Erase all segments after a specific segment void EraseSegments(SegmentLock &l, idx_t segment_start) { LoadAllSegments(l); diff --git a/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp index 97fbc889c..b4b337301 100644 --- a/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/standard_column_data.hpp @@ -36,11 +36,6 @@ class StandardColumnData : public ColumnData { idx_t target_count) override; idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count) override; - void Filter(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t &count, const TableFilter &filter) override; - void Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t sel_count) override; - void InitializeAppend(ColumnAppendState &state) override; void AppendData(BaseStatistics &stats, ColumnAppendState &state, UnifiedVectorFormat &vdata, idx_t count) override; void RevertAppend(row_t start_row) override; diff --git a/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp b/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp index 6ae66836e..4f1f681f3 100644 --- a/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/table_index_list.hpp @@ -9,20 +9,18 @@ #pragma once #include "duckdb/common/mutex.hpp" -#include "duckdb/execution/index/bound_index.hpp" -#include "duckdb/parser/constraint.hpp" #include "duckdb/storage/index.hpp" +#include "duckdb/parser/constraint.hpp" namespace duckdb { class ConflictManager; - struct IndexStorageInfo; struct DataTableInfo; class TableIndexList { public: - //! Scan the indexes, invoking the callback method for every entry. + //! Scan the indexes, invoking the callback method for every entry template void Scan(T &&callback) { lock_guard lock(indexes_lock); @@ -33,7 +31,7 @@ class TableIndexList { } } - //! Scan the indexes, invoking the callback method for every bound entry of type T. + //! Scan the indexes, invoking the callback method for every bound entry of a specific type template void ScanBound(FUNC &&callback) { lock_guard lock(indexes_lock); @@ -46,50 +44,45 @@ class TableIndexList { } } - // Bind any unbound indexes of type T and invoke the callback method. + // Bind any unbound indexes of the specified type and invoke the callback method for every bound entry of the + // specified type, regardless if it was bound before or not template void BindAndScan(ClientContext &context, DataTableInfo &table_info, FUNC &&callback) { - // FIXME: optimize this by only looping through the indexes once without re-acquiring the lock. + // FIXME: optimize this by only looping through the indexes once without re-acquiring the lock InitializeIndexes(context, table_info, T::TYPE_NAME); ScanBound(callback); } - //! Returns a reference to the indexes. + //! Returns a reference to the indexes of this table const vector> &Indexes() const { return indexes; } - //! Adds an index to the list of indexes. + //! Adds an index to the list of indexes of this table void AddIndex(unique_ptr index); - //! Removes an index from the list of indexes. + //! Removes an index from the list of indexes of this table void RemoveIndex(const string &name); - //! Removes all remaining memory of an index after dropping the catalog entry. + //! Completely removes all remaining memory of an index after dropping the catalog entry void CommitDrop(const string &name); - //! Returns true, if the index name does not exist. + //! Returns true, if the index name does not exist bool NameIsUnique(const string &name); - //! Returns an optional pointer to the index matching the name. - optional_ptr Find(const string &name); - //! Initializes unknown indexes that are possibly present after an extension load, optionally throwing an exception - //! on failure. + //! Initializes unknown indexes that might now be present after an extension load, optionally throwing an exception + //! if a index cant be initialized void InitializeIndexes(ClientContext &context, DataTableInfo &table_info, const char *index_type = nullptr); - //! Returns true, if there are no indexes in this list. bool Empty(); - //! Returns the number of indexes in this list. idx_t Count(); - //! Overwrite this list with the other list. void Move(TableIndexList &other); - //! Find the foreign key matching the keys. - Index *FindForeignKeyIndex(const vector &fk_keys, const ForeignKeyType fk_type); - //! Verify a foreign key constraint. + + Index *FindForeignKeyIndex(const vector &fk_keys, ForeignKeyType fk_type); void VerifyForeignKey(const vector &fk_keys, DataChunk &chunk, ConflictManager &conflict_manager); - //! Get the combined column ids of the indexes in this list. - unordered_set GetRequiredColumns(); + //! Serialize all indexes of this table. vector GetStorageInfos(const case_insensitive_map_t &options); + vector GetRequiredColumns(); + private: + //! Indexes associated with the current table mutex indexes_lock; - // Indexes associated with the table. vector> indexes; }; - } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp b/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp index 628023dfd..633d46946 100644 --- a/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp @@ -48,14 +48,6 @@ class TableStatistics { //! Get a reference to the stats - this requires us to hold the lock. //! The reference can only be safely accessed while the lock is held ColumnStatistics &GetStats(TableStatisticsLock &lock, idx_t i); - //! Get a reference to the table sample - this requires us to hold the lock. - BlockingSample &GetTableSampleRef(TableStatisticsLock &lock); - //! Take ownership of the sample, needed for merging. Requires the lock - unique_ptr GetTableSample(TableStatisticsLock &lock); - void SetTableSample(TableStatisticsLock &lock, unique_ptr sample); - - void DestroyTableSample(TableStatisticsLock &lock) const; - void AppendToTableSample(TableStatisticsLock &lock, unique_ptr sample); bool Empty(); @@ -70,6 +62,7 @@ class TableStatistics { //! Column statistics vector> column_stats; //! The table sample + //! Sample for table unique_ptr table_sample; }; diff --git a/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp b/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp index a0e325c31..71fba059c 100644 --- a/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/update_segment.hpp @@ -12,7 +12,6 @@ #include "duckdb/storage/storage_lock.hpp" #include "duckdb/storage/statistics/segment_statistics.hpp" #include "duckdb/common/types/string_heap.hpp" -#include "duckdb/transaction/undo_buffer_allocator.hpp" namespace duckdb { class ColumnData; @@ -20,7 +19,6 @@ class DataTable; class Vector; struct UpdateInfo; struct UpdateNode; -struct UndoBufferAllocator; class UpdateSegment { public: @@ -53,7 +51,7 @@ class UpdateSegment { private: //! The lock for the update segment - mutable StorageLock lock; + StorageLock lock; //! The root node (if any) unique_ptr root; //! Update statistics @@ -66,16 +64,16 @@ class UpdateSegment { StringHeap heap; public: - typedef void (*initialize_update_function_t)(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, + typedef void (*initialize_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, const SelectionVector &sel); - typedef void (*merge_update_function_t)(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, + typedef void (*merge_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel); - typedef void (*fetch_update_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, + typedef void (*fetch_update_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, Vector &result); - typedef void (*fetch_committed_function_t)(UpdateInfo &info, Vector &result); - typedef void (*fetch_committed_range_function_t)(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, + typedef void (*fetch_committed_function_t)(UpdateInfo *info, Vector &result); + typedef void (*fetch_committed_range_function_t)(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, Vector &result); - typedef void (*fetch_row_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, + typedef void (*fetch_row_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, idx_t row_idx, Vector &result, idx_t result_idx); typedef void (*rollback_update_function_t)(UpdateInfo &base_info, UpdateInfo &rollback_info); typedef idx_t (*statistics_update_function_t)(UpdateSegment *segment, SegmentStatistics &stats, Vector &update, @@ -92,18 +90,18 @@ class UpdateSegment { statistics_update_function_t statistics_update_function; private: - UndoBufferPointer GetUpdateNode(idx_t vector_idx) const; - void InitializeUpdateInfo(idx_t vector_idx); void InitializeUpdateInfo(UpdateInfo &info, row_t *ids, const SelectionVector &sel, idx_t count, idx_t vector_index, idx_t vector_offset); }; -struct UpdateNode { - explicit UpdateNode(BufferManager &manager); - ~UpdateNode(); +struct UpdateNodeData { + unique_ptr info; + unsafe_unique_array tuples; + unsafe_unique_array tuple_data; +}; - UndoBufferAllocator allocator; - vector info; +struct UpdateNode { + unique_ptr info[Storage::ROW_GROUP_VECTOR_COUNT]; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table/validity_column_data.hpp b/src/duckdb/src/include/duckdb/storage/table/validity_column_data.hpp index 286a5343b..dcabc739c 100644 --- a/src/duckdb/src/include/duckdb/storage/table/validity_column_data.hpp +++ b/src/duckdb/src/include/duckdb/storage/table/validity_column_data.hpp @@ -14,8 +14,6 @@ namespace duckdb { //! Validity column data represents the validity data (i.e. which values are null) class ValidityColumnData : public ColumnData { - friend class StandardColumnData; - public: ValidityColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, idx_t start_row, ColumnData &parent); diff --git a/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp b/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp index babe17274..eff63da03 100644 --- a/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/table_io_manager.hpp @@ -30,9 +30,6 @@ class TableIOManager { virtual BlockManager &GetBlockManagerForRowData() = 0; virtual MetadataManager &GetMetadataManager() = 0; - - //! Returns the target row group size for the table - virtual idx_t GetRowGroupSize() const = 0; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/table_storage_info.hpp b/src/duckdb/src/include/duckdb/storage/table_storage_info.hpp index 493dd320a..49b3089c6 100644 --- a/src/duckdb/src/include/duckdb/storage/table_storage_info.hpp +++ b/src/duckdb/src/include/duckdb/storage/table_storage_info.hpp @@ -31,7 +31,6 @@ struct ColumnSegmentInfo { bool has_updates; bool persistent; block_id_t block_id; - vector additional_blocks; idx_t block_offset; string segment_info; }; diff --git a/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp b/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp index 780b113ee..e5587547e 100644 --- a/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp +++ b/src/duckdb/src/include/duckdb/storage/temporary_file_manager.hpp @@ -9,113 +9,73 @@ #pragma once #include "duckdb/common/allocator.hpp" -#include "duckdb/common/array.hpp" #include "duckdb/common/atomic.hpp" -#include "duckdb/common/enum_class_hash.hpp" #include "duckdb/common/file_system.hpp" #include "duckdb/common/mutex.hpp" -#include "duckdb/common/random_engine.hpp" -#include "duckdb/common/unordered_map.hpp" +#include "duckdb/storage/block_manager.hpp" +#include "duckdb/storage/buffer/block_handle.hpp" +#include "duckdb/storage/buffer/buffer_pool.hpp" #include "duckdb/storage/buffer_manager.hpp" namespace duckdb { -class TemporaryFileManager; - //===--------------------------------------------------------------------===// -// TemporaryBufferSize +// BlockIndexManager //===--------------------------------------------------------------------===// -static constexpr uint64_t TEMPORARY_BUFFER_SIZE_GRANULARITY = 32ULL * 1024ULL; - -enum class TemporaryBufferSize : uint64_t { - INVALID = 0, - S32K = 32768, - S64K = 65536, - S96K = 98304, - S128K = 131072, - S160K = 163840, - S192K = 196608, - S224K = 229376, - DEFAULT = DEFAULT_BLOCK_ALLOC_SIZE, -}; -//===--------------------------------------------------------------------===// -// TemporaryFileIdentifier/TemporaryFileIndex -//===--------------------------------------------------------------------===// -struct TemporaryFileIdentifier { -public: - TemporaryFileIdentifier(); - TemporaryFileIdentifier(TemporaryBufferSize size, idx_t file_index); - -public: - //! Whether this temporary file identifier is valid (fields have been set) - bool IsValid() const; - -public: - //! The size of the buffers within the temp file - TemporaryBufferSize size; - //! The index of the temp file - optional_idx file_index; -}; - -struct TemporaryFileIndex { -public: - TemporaryFileIndex(); - TemporaryFileIndex(TemporaryFileIdentifier identifier, idx_t block_index); - -public: - //! Whether this temporary file index is valid (fields have been set) - bool IsValid() const; - -public: - //! The identifier for the temporary file - TemporaryFileIdentifier identifier; - //! The block index within the temporary file - optional_idx block_index; -}; +class TemporaryFileManager; -//===--------------------------------------------------------------------===// -// BlockIndexManager -//===--------------------------------------------------------------------===// struct BlockIndexManager { public: - BlockIndexManager(); explicit BlockIndexManager(TemporaryFileManager &manager); + BlockIndexManager(); public: //! Obtains a new block index from the index manager - idx_t GetNewBlockIndex(TemporaryBufferSize size); - //! Removes an index from the block manager (returns true if the max_index has been altered) - bool RemoveIndex(idx_t index, TemporaryBufferSize size); - //! Get the maximum block index - idx_t GetMaxIndex() const; - //! Whether there are free blocks available within the file - bool HasFreeBlocks() const; + idx_t GetNewBlockIndex(); + //! Removes an index from the block manager + //! Returns true if the max_index has been altered + bool RemoveIndex(idx_t index); + idx_t GetMaxIndex(); + bool HasFreeBlocks(); private: - //! Get/set max block index - idx_t GetNewBlockIndexInternal(TemporaryBufferSize size); - void SetMaxIndex(idx_t new_index, TemporaryBufferSize size); + void SetMaxIndex(idx_t blocks); + idx_t GetNewBlockIndexInternal(); private: - //! The maximum block index idx_t max_index; - //! Free indexes within the file set free_indexes; - //! Used indexes within the file set indexes_in_use; - //! The TemporaryFileManager that "owns" this BlockIndexManager optional_ptr manager; }; +//===--------------------------------------------------------------------===// +// TemporaryFileIndex +//===--------------------------------------------------------------------===// + +// FIXME: should be optional_idx +struct TemporaryFileIndex { + explicit TemporaryFileIndex(idx_t file_index = DConstants::INVALID_INDEX, + idx_t block_index = DConstants::INVALID_INDEX); + + idx_t file_index; + idx_t block_index; + +public: + bool IsValid() const; +}; + //===--------------------------------------------------------------------===// // TemporaryFileHandle //===--------------------------------------------------------------------===// + class TemporaryFileHandle { constexpr static idx_t MAX_ALLOWED_INDEX_BASE = 4000; public: - TemporaryFileHandle(TemporaryFileManager &manager, TemporaryFileIdentifier identifier, idx_t temp_file_count); + TemporaryFileHandle(idx_t temp_file_count, DatabaseInstance &db, const string &temp_directory, idx_t index, + TemporaryFileManager &manager); public: struct TemporaryFileLock { @@ -127,226 +87,99 @@ class TemporaryFileHandle { }; public: - //! Try to get an index of where to write in this file. Returns an invalid index if full TemporaryFileIndex TryGetBlockIndex(); - //! Remove block index from this TemporaryFileHandle + void WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index); + unique_ptr ReadTemporaryBuffer(idx_t block_index, unique_ptr reusable_buffer); void EraseBlockIndex(block_id_t block_index); - - //! Read/Write temporary buffers at given positions in this file (potentially compressed) - unique_ptr ReadTemporaryBuffer(idx_t block_index, unique_ptr reusable_buffer) const; - void WriteTemporaryBuffer(FileBuffer &buffer, idx_t block_index, AllocatedData &compressed_buffer) const; - - //! Deletes the file if there are no more blocks bool DeleteIfEmpty(); - //! Get information about this temporary file TemporaryFileInformation GetTemporaryFile(); private: - //! Create temporary file if it did not exist yet void CreateFileIfNotExists(TemporaryFileLock &); - //! Remove block index from this file void RemoveTempBlockIndex(TemporaryFileLock &, idx_t index); - //! Get the position of a block in the file - idx_t GetPositionInFile(idx_t index) const; + idx_t GetPositionInFile(idx_t index); private: - //! Reference to the DB instance - DatabaseInstance &db; - //! The identifier (size/file index) of this TemporaryFileHandle - const TemporaryFileIdentifier identifier; - //! The maximum allowed index const idx_t max_allowed_index; - //! File path/handle - const string path; + DatabaseInstance &db; unique_ptr handle; - //! Lock for concurrent access and block index manager + idx_t file_index; + string path; mutex file_lock; BlockIndexManager index_manager; }; //===--------------------------------------------------------------------===// -// TemporaryFileMap -//===--------------------------------------------------------------------===// -class TemporaryFileMap { -private: - template - using temporary_buffer_size_map_t = unordered_map; - using temporary_file_map_t = unordered_map>; - -public: - explicit TemporaryFileMap(TemporaryFileManager &manager); - void Clear(); - -public: - //! Gets the map for the given size - temporary_file_map_t &GetMapForSize(TemporaryBufferSize size); - - //! Get/create/erase a TemporaryFileHandle for a size/index - optional_ptr GetFile(const TemporaryFileIdentifier &identifier); - TemporaryFileHandle &CreateFile(const TemporaryFileIdentifier &identifier); - void EraseFile(const TemporaryFileIdentifier &identifier); - -private: - TemporaryFileManager &manager; - temporary_buffer_size_map_t files; -}; - -//===--------------------------------------------------------------------===// -// TemporaryFileCompressionLevel/TemporaryFileCompressionAdaptivity +// TemporaryDirectoryHandle //===--------------------------------------------------------------------===// -enum class TemporaryCompressionLevel : int { - ZSTD_MINUS_FIVE = -5, - ZSTD_MINUS_THREE = -3, - ZSTD_MINUS_ONE = -1, - UNCOMPRESSED = 0, - ZSTD_ONE = 1, - ZSTD_THREE = 3, - ZSTD_FIVE = 5, -}; -class TemporaryFileCompressionAdaptivity { +class TemporaryDirectoryHandle { public: - TemporaryFileCompressionAdaptivity(); + TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space); + ~TemporaryDirectoryHandle(); -public: - //! Get current time in nanoseconds to measure write times - static int64_t GetCurrentTimeNanos(); - //! Get the compression level to use based on current write times - TemporaryCompressionLevel GetCompressionLevel(); - //! Update write time for given compression level - void Update(TemporaryCompressionLevel level, int64_t time_before_ns); + TemporaryFileManager &GetTempFile(); private: - //! Convert from level to index into write time array and back - static TemporaryCompressionLevel IndexToLevel(idx_t index); - static idx_t LevelToIndex(TemporaryCompressionLevel level); - //! Min/max compression levels - static TemporaryCompressionLevel MinimumCompressionLevel(); - static TemporaryCompressionLevel MaximumCompressionLevel(); - -private: - //! The value to initialize the atomic write counters to - static constexpr int64_t INITIAL_NS = 50000; - //! How many compression levels we adapt between - static constexpr idx_t LEVELS = 6; - //! Bias towards compressed writes: we only choose uncompressed if it is more than 2x faster than compressed - static constexpr double DURATION_RATIO_THRESHOLD = 2.0; - //! Probability to deviate from the current best write behavior (1 in 20) - static constexpr double COMPRESSION_DEVIATION = 0.5; - //! Weight to use for moving weighted average - static constexpr int64_t WEIGHT = 16; - - //! Random engine to (sometimes) randomize compression - RandomEngine random_engine; - //! Duration of the last uncompressed write - int64_t last_uncompressed_write_ns; - //! Duration of the last compressed writes - int64_t last_compressed_writes_ns[LEVELS]; + DatabaseInstance &db; + string temp_directory; + bool created_directory = false; + unique_ptr temp_file; }; //===--------------------------------------------------------------------===// // TemporaryFileManager //===--------------------------------------------------------------------===// -class TemporaryFileManager { - friend struct BlockIndexManager; - friend class TemporaryFileHandle; +class TemporaryFileManager { public: TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p); ~TemporaryFileManager(); -private: - struct CompressionResult { - TemporaryBufferSize size; - TemporaryCompressionLevel level; - }; - public: - struct TemporaryFileManagerLock { + struct TemporaryManagerLock { public: - explicit TemporaryFileManagerLock(mutex &mutex); + explicit TemporaryManagerLock(mutex &mutex); public: lock_guard lock; }; - //! Create/Read/Update/Delete operations for temporary buffers void WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer); bool HasTemporaryBuffer(block_id_t block_id); unique_ptr ReadTemporaryBuffer(block_id_t id, unique_ptr reusable_buffer); void DeleteTemporaryBuffer(block_id_t id); - - //! Get the list of temporary files and their sizes vector GetTemporaryFiles(); - - //! Get/set maximum swap space + idx_t GetTotalUsedSpaceInBytes(); optional_idx GetMaxSwapSpace() const; void SetMaxSwapSpace(optional_idx limit); - - //! Get temporary file size - idx_t GetTotalUsedSpaceInBytes() const; //! Register temporary file size growth void IncreaseSizeOnDisk(idx_t amount); //! Register temporary file size decrease void DecreaseSizeOnDisk(idx_t amount); private: - //! Compress buffer, write it in compressed_buffer and return the size/level - CompressionResult CompressBuffer(TemporaryFileCompressionAdaptivity &compression_adaptivity, FileBuffer &buffer, - AllocatedData &compressed_buffer); - - //! Create file name for given size/index - string CreateTemporaryFileName(const TemporaryFileIdentifier &identifier) const; - - //! Get/erase a temporary block - TemporaryFileIndex GetTempBlockIndex(TemporaryFileManagerLock &, block_id_t id); - void EraseUsedBlock(TemporaryFileManagerLock &lock, block_id_t id, TemporaryFileHandle &handle, + void EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle, TemporaryFileIndex index); - - //! Get/erase a temporary file handle - optional_ptr GetFileHandle(TemporaryFileManagerLock &, - const TemporaryFileIdentifier &identifier); - void EraseFileHandle(TemporaryFileManagerLock &, const TemporaryFileIdentifier &identifier); + TemporaryFileHandle *GetFileHandle(TemporaryManagerLock &, idx_t index); + TemporaryFileIndex GetTempBlockIndex(TemporaryManagerLock &, block_id_t id); + void EraseFileHandle(TemporaryManagerLock &, idx_t file_index); private: - //! Reference to the DB instance DatabaseInstance &db; + mutex manager_lock; //! The temporary directory string temp_directory; - //! Lock for parallel access - mutex manager_lock; //! The set of active temporary file handles - TemporaryFileMap files; - //! Map of block_id -> temporary file position + unordered_map> files; + //! map of block_id -> temporary file position unordered_map used_blocks; - //! Map of TemporaryBufferSize -> manager of in-use temporary file indexes - unordered_map index_managers; + //! Manager of in-use temporary file indexes + BlockIndexManager index_manager; //! The size in bytes of the temporary files that are currently alive atomic size_on_disk; //! The max amount of disk space that can be used idx_t max_swap_space; - //! How many compression adaptivities we have so that threads don't all share the same one - static constexpr idx_t COMPRESSION_ADAPTIVITIES = 64; - //! Class that oversees when/how much to compress - array compression_adaptivities; -}; - -//===--------------------------------------------------------------------===// -// TemporaryDirectoryHandle -//===--------------------------------------------------------------------===// -class TemporaryDirectoryHandle { -public: - TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space); - ~TemporaryDirectoryHandle(); - -public: - TemporaryFileManager &GetTempFile() const; - -private: - DatabaseInstance &db; - string temp_directory; - bool created_directory = false; - unique_ptr temp_file; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp b/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp index 8b2acc112..a5e295f2f 100644 --- a/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +++ b/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp @@ -38,8 +38,6 @@ class TransactionManager; class WriteAheadLogDeserializer; struct PersistentCollectionData; -enum class WALInitState { NO_WAL, UNINITIALIZED, UNINITIALIZED_REQUIRES_TRUNCATE, INITIALIZED }; - //! The WriteAheadLog (WAL) is a log that is used to provide durability. Prior //! to committing a transaction it writes the changes the transaction made to //! the database to the log, which can then be replayed upon startup in case the @@ -47,21 +45,22 @@ enum class WALInitState { NO_WAL, UNINITIALIZED, UNINITIALIZED_REQUIRES_TRUNCATE class WriteAheadLog { public: //! Initialize the WAL in the specified directory - explicit WriteAheadLog(AttachedDatabase &database, const string &wal_path, idx_t wal_size = 0ULL, - WALInitState state = WALInitState::NO_WAL); + explicit WriteAheadLog(AttachedDatabase &database, const string &wal_path); virtual ~WriteAheadLog(); public: - //! Replay and initialize the WAL - static unique_ptr Replay(FileSystem &fs, AttachedDatabase &database, const string &wal_path); + //! Replay the WAL + static bool Replay(AttachedDatabase &database, unique_ptr handle); //! Gets the total bytes written to the WAL since startup - idx_t GetWALSize() const; + idx_t GetWALSize(); //! Gets the total bytes written to the WAL since startup - idx_t GetTotalWritten() const; + idx_t GetTotalWritten(); //! A WAL is initialized, if a writer to a file exists. - bool Initialized() const; + bool Initialized() { + return initialized; + } //! Initializes the file of the WAL by creating the file writer. BufferedFileWriter &Initialize(); @@ -94,7 +93,7 @@ class WriteAheadLog { //! Sets the table used for subsequent insert/delete/update commands void WriteSetTable(const string &schema, const string &table); - void WriteAlter(CatalogEntry &entry, const AlterInfo &info); + void WriteAlter(const AlterInfo &info); void WriteInsert(DataChunk &chunk); void WriteRowGroupData(const PersistentCollectionData &data); @@ -117,16 +116,13 @@ class WriteAheadLog { void WriteCheckpoint(MetaBlockPointer meta_block); -protected: - static unique_ptr ReplayInternal(AttachedDatabase &database, unique_ptr handle); - protected: AttachedDatabase &database; mutex wal_lock; unique_ptr writer; string wal_path; atomic wal_size; - atomic init_state; + atomic initialized; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/commit_state.hpp b/src/duckdb/src/include/duckdb/transaction/commit_state.hpp index 382de7296..d92056d36 100644 --- a/src/duckdb/src/include/duckdb/transaction/commit_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/commit_state.hpp @@ -14,7 +14,6 @@ namespace duckdb { class CatalogEntry; class DataChunk; -class DuckTransaction; class WriteAheadLog; class ClientContext; @@ -24,7 +23,7 @@ struct UpdateInfo; class CommitState { public: - explicit CommitState(DuckTransaction &transaction, transaction_t commit_id); + explicit CommitState(transaction_t commit_id); public: void CommitEntry(UndoFlags type, data_ptr_t data); @@ -34,7 +33,6 @@ class CommitState { void CommitEntryDrop(CatalogEntry &entry, data_ptr_t extra_data); private: - DuckTransaction &transaction; transaction_t commit_id; }; diff --git a/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp b/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp index e17c048be..5399b2ef0 100644 --- a/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp +++ b/src/duckdb/src/include/duckdb/transaction/duck_transaction.hpp @@ -11,7 +11,6 @@ #include "duckdb/transaction/transaction.hpp" #include "duckdb/common/reference_map.hpp" #include "duckdb/common/error_data.hpp" -#include "duckdb/transaction/undo_buffer.hpp" namespace duckdb { class CheckpointLock; @@ -59,7 +58,7 @@ class DuckTransaction : public Transaction { bool AutomaticCheckpoint(AttachedDatabase &db, const UndoBufferProperties &properties); //! Rollback - ErrorData Rollback(); + void Rollback() noexcept; //! Cleanup the undo buffer void Cleanup(transaction_t lowest_active_transaction); @@ -70,7 +69,7 @@ class DuckTransaction : public Transaction { idx_t base_row); void PushSequenceUsage(SequenceCatalogEntry &entry, const SequenceData &data); void PushAppend(DataTable &table, idx_t row_start, idx_t row_count); - UndoBufferReference CreateUpdateInfo(idx_t type_size, idx_t entries); + UpdateInfo *CreateUpdateInfo(idx_t type_size, idx_t entries); bool IsDuckTransaction() const override { return true; diff --git a/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp b/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp index deaaf0b4d..0371d4e97 100644 --- a/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp +++ b/src/duckdb/src/include/duckdb/transaction/duck_transaction_manager.hpp @@ -14,7 +14,6 @@ namespace duckdb { class DuckTransaction; -struct UndoBufferProperties; //! The Transaction Manager is responsible for creating and managing //! transactions diff --git a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp index 453a7ce44..aa345b1ef 100644 --- a/src/duckdb/src/include/duckdb/transaction/local_storage.hpp +++ b/src/duckdb/src/include/duckdb/transaction/local_storage.hpp @@ -31,7 +31,7 @@ class LocalTableStorage : public enable_shared_from_this { explicit LocalTableStorage(ClientContext &context, DataTable &table); // Create a LocalTableStorage from an ALTER TYPE LocalTableStorage(ClientContext &context, DataTable &table, LocalTableStorage &parent, idx_t changed_idx, - const LogicalType &target_type, const vector &bound_columns, Expression &cast_expr); + const LogicalType &target_type, const vector &bound_columns, Expression &cast_expr); // Create a LocalTableStorage from a DROP COLUMN LocalTableStorage(DataTable &table, LocalTableStorage &parent, idx_t drop_idx); // Create a LocalTableStorage from an ADD COLUMN @@ -44,10 +44,8 @@ class LocalTableStorage : public enable_shared_from_this { Allocator &allocator; //! The main chunk collection holding the data shared_ptr row_groups; - //! The set of unique append indexes. - TableIndexList append_indexes; - //! The set of delete indexes. - TableIndexList delete_indexes; + //! The set of unique indexes + TableIndexList indexes; //! The number of deleted rows idx_t deleted_rows; //! The main optimistic data writer @@ -67,10 +65,10 @@ class LocalTableStorage : public enable_shared_from_this { void Rollback(); idx_t EstimatedSize(); - void AppendToIndexes(DuckTransaction &transaction, TableAppendState &append_state, bool append_to_table); + void AppendToIndexes(DuckTransaction &transaction, TableAppendState &append_state, idx_t append_count, + bool append_to_table); ErrorData AppendToIndexes(DuckTransaction &transaction, RowGroupCollection &source, TableIndexList &index_list, const vector &table_types, row_t &start_row); - void AppendToDeleteIndexes(Vector &row_ids, DataChunk &delete_chunk); //! Creates an optimistic writer for this table OptimisticDataWriter &CreateOptimisticWriter(); @@ -81,19 +79,23 @@ class LocalTableManager { public: shared_ptr MoveEntry(DataTable &table); reference_map_t> MoveEntries(); - optional_ptr GetStorage(DataTable &table) const; + optional_ptr GetStorage(DataTable &table); LocalTableStorage &GetOrCreateStorage(ClientContext &context, DataTable &table); - idx_t EstimatedSize() const; - bool IsEmpty() const; + idx_t EstimatedSize(); + bool IsEmpty(); void InsertEntry(DataTable &table, shared_ptr entry); private: - mutable mutex table_storage_lock; + mutex table_storage_lock; reference_map_t> table_storage; }; //! The LocalStorage class holds appends that have not been committed yet class LocalStorage { +public: + // Threshold to merge row groups instead of appending + static constexpr const idx_t MERGE_THRESHOLD = Storage::ROW_GROUP_SIZE; + public: struct CommitState { CommitState(); @@ -112,7 +114,7 @@ class LocalStorage { //! Initialize a scan of the local storage void InitializeScan(DataTable &table, CollectionScanState &state, optional_ptr table_filters); //! Scan - void Scan(CollectionScanState &state, const vector &column_ids, DataChunk &result); + void Scan(CollectionScanState &state, const vector &column_ids, DataChunk &result); void InitializeParallelScan(DataTable &table, ParallelCollectionScanState &state); bool NextParallelScan(ClientContext &context, DataTable &table, ParallelCollectionScanState &state, @@ -120,8 +122,6 @@ class LocalStorage { //! Begin appending to the local storage void InitializeAppend(LocalAppendState &state, DataTable &table); - //! Initialize the storage and its indexes, but no row groups. - void InitializeStorage(LocalAppendState &state, DataTable &table); //! Append a chunk to the local storage static void Append(LocalAppendState &state, DataChunk &chunk); //! Finish appending to the local storage @@ -149,19 +149,17 @@ class LocalStorage { bool Find(DataTable &table); idx_t AddedRows(DataTable &table); - vector GetPartitionStats(DataTable &table) const; void AddColumn(DataTable &old_dt, DataTable &new_dt, ColumnDefinition &new_column, ExpressionExecutor &default_executor); void DropColumn(DataTable &old_dt, DataTable &new_dt, idx_t removed_column); void ChangeType(DataTable &old_dt, DataTable &new_dt, idx_t changed_idx, const LogicalType &target_type, - const vector &bound_columns, Expression &cast_expr); + const vector &bound_columns, Expression &cast_expr); void MoveStorage(DataTable &old_dt, DataTable &new_dt); - void FetchChunk(DataTable &table, Vector &row_ids, idx_t count, const vector &col_ids, - DataChunk &chunk, ColumnFetchState &fetch_state); + void FetchChunk(DataTable &table, Vector &row_ids, idx_t count, const vector &col_ids, DataChunk &chunk, + ColumnFetchState &fetch_state); TableIndexList &GetIndexes(DataTable &table); - optional_ptr GetStorage(DataTable &table); void VerifyNewConstraint(DataTable &parent, const BoundConstraint &constraint); diff --git a/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp b/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp index 3195c2a6a..19d6cdad4 100644 --- a/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/rollback_state.hpp @@ -13,18 +13,15 @@ namespace duckdb { class DataChunk; class DataTable; -class DuckTransaction; class WriteAheadLog; class RollbackState { public: - explicit RollbackState(DuckTransaction &transaction); + RollbackState() { + } public: void RollbackEntry(UndoFlags type, data_ptr_t data); - -private: - DuckTransaction &transaction; }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/transaction.hpp b/src/duckdb/src/include/duckdb/transaction/transaction.hpp index db0a90eee..a2122a68f 100644 --- a/src/duckdb/src/include/duckdb/transaction/transaction.hpp +++ b/src/duckdb/src/include/duckdb/transaction/transaction.hpp @@ -10,9 +10,10 @@ #include "duckdb/catalog/catalog_entry/sequence_catalog_entry.hpp" #include "duckdb/common/types/data_chunk.hpp" +#include "duckdb/transaction/undo_buffer.hpp" +#include "duckdb/common/atomic.hpp" #include "duckdb/transaction/transaction_data.hpp" #include "duckdb/common/shared_ptr.hpp" -#include "duckdb/common/atomic.hpp" namespace duckdb { class SequenceCatalogEntry; diff --git a/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp b/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp index 7218bb876..0eb865222 100644 --- a/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp +++ b/src/duckdb/src/include/duckdb/transaction/undo_buffer.hpp @@ -10,20 +10,16 @@ #include "duckdb/common/common.hpp" #include "duckdb/common/enums/undo_flags.hpp" -#include "duckdb/transaction/undo_buffer_allocator.hpp" +#include "duckdb/storage/arena_allocator.hpp" namespace duckdb { -class BufferManager; -class DuckTransaction; class StorageCommitState; class WriteAheadLog; -struct UndoBufferPointer; struct UndoBufferProperties { idx_t estimated_size = 0; bool has_updates = false; bool has_deletes = false; - bool has_index_deletes = false; bool has_catalog_changes = false; bool has_dropped_entries = false; }; @@ -34,17 +30,17 @@ struct UndoBufferProperties { class UndoBuffer { public: struct IteratorState { - BufferHandle handle; - optional_ptr current; + ArenaChunk *current; data_ptr_t start; data_ptr_t end; }; public: - explicit UndoBuffer(DuckTransaction &transaction, ClientContext &context); + explicit UndoBuffer(ClientContext &context); - //! Write a specified entry to the undo buffer - UndoBufferReference CreateEntry(UndoFlags type, idx_t len); + //! Reserve space for an entry of the specified type and length in the undo + //! buffer + data_ptr_t CreateEntry(UndoFlags type, idx_t len); bool ChangesMade(); UndoBufferProperties GetProperties(); @@ -59,11 +55,10 @@ class UndoBuffer { void RevertCommit(UndoBuffer::IteratorState &iterator_state, transaction_t transaction_id); //! Rollback the changes made in this UndoBuffer: should be called on //! rollback - void Rollback(); + void Rollback() noexcept; private: - DuckTransaction &transaction; - UndoBufferAllocator allocator; + ArenaAllocator allocator; private: template diff --git a/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp b/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp deleted file mode 100644 index a318fe8ff..000000000 --- a/src/duckdb/src/include/duckdb/transaction/undo_buffer_allocator.hpp +++ /dev/null @@ -1,79 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// -// duckdb/transaction/undo_buffer_allocator.hpp -// -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include "duckdb/common/common.hpp" -#include "duckdb/storage/buffer/buffer_handle.hpp" - -namespace duckdb { -class BufferManager; -class BlockHandle; -struct UndoBufferEntry; -struct UndoBufferPointer; - -struct UndoBufferEntry { - explicit UndoBufferEntry(BufferManager &buffer_manager) : buffer_manager(buffer_manager) { - } - ~UndoBufferEntry(); - - BufferManager &buffer_manager; - shared_ptr block; - idx_t position = 0; - idx_t capacity = 0; - unique_ptr next; - optional_ptr prev; -}; - -struct UndoBufferReference { - UndoBufferReference() : entry(nullptr), position(0) { - } - UndoBufferReference(UndoBufferEntry &entry_p, BufferHandle handle_p, idx_t position) - : entry(&entry_p), handle(std::move(handle_p)), position(position) { - } - - optional_ptr entry; - BufferHandle handle; - idx_t position; - - data_ptr_t Ptr() { - return handle.Ptr() + position; - } - bool IsSet() const { - return entry; - } - - UndoBufferPointer GetBufferPointer(); -}; - -struct UndoBufferPointer { - UndoBufferPointer() : entry(nullptr), position(0) { - } - UndoBufferPointer(UndoBufferEntry &entry_p, idx_t position) : entry(&entry_p), position(position) { - } - - UndoBufferEntry *entry; - idx_t position; - - UndoBufferReference Pin() const; - bool IsSet() const { - return entry; - } -}; - -struct UndoBufferAllocator { - explicit UndoBufferAllocator(BufferManager &buffer_manager); - - UndoBufferReference Allocate(idx_t alloc_len); - - BufferManager &buffer_manager; - unique_ptr head; - optional_ptr tail; -}; - -} // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/update_info.hpp b/src/duckdb/src/include/duckdb/transaction/update_info.hpp index 7cccd923e..e7dc7dfcb 100644 --- a/src/duckdb/src/include/duckdb/transaction/update_info.hpp +++ b/src/duckdb/src/include/duckdb/transaction/update_info.hpp @@ -11,18 +11,12 @@ #include "duckdb/common/constants.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/common/types/validity_mask.hpp" -#include "duckdb/transaction/undo_buffer_allocator.hpp" #include "duckdb/common/atomic.hpp" namespace duckdb { class UpdateSegment; struct DataTableInfo; -//! UpdateInfo is a class that represents a set of updates applied to a single vector. -//! The UpdateInfo struct contains metadata associated with the update. -//! After the UpdateInfo, we must ALWAYS allocate the list of tuples and the data as contiguous arrays: -//! [UpdateInfo][TUPLES (sel_t[max])][DATA (T[max])] -//! The required allocation size can be obtained using UpdateInfo::GetAllocSize struct UpdateInfo { //! The update segment that this update info affects UpdateSegment *segment; @@ -36,44 +30,27 @@ struct UpdateInfo { sel_t N; // NOLINT //! The maximum amount of tuples that can fit into this UpdateInfo sel_t max; + //! The row ids of the tuples that have been updated. This should always be kept sorted! + sel_t *tuples; + //! The data of the tuples + data_ptr_t tuple_data; //! The previous update info (or nullptr if it is the base) - UndoBufferPointer prev; + UpdateInfo *prev; //! The next update info in the chain (or nullptr if it is the last) - UndoBufferPointer next; - - //! The row ids of the tuples that have been updated. This should always be kept sorted! - sel_t *GetTuples(); - - //! The update values - data_ptr_t GetValues(); - - template - T *GetData() { - return reinterpret_cast(GetValues()); - } - - bool AppliesToTransaction(transaction_t start_time, transaction_t transaction_id) { - // these tuples were either committed AFTER this transaction started or are not committed yet, use - // tuples stored in this version - return version_number > start_time && version_number != transaction_id; - } + UpdateInfo *next; //! Loop over the update chain and execute the specified callback on all UpdateInfo's that are relevant for that //! transaction in-order of newest to oldest template - static void UpdatesForTransaction(UpdateInfo ¤t, transaction_t start_time, transaction_t transaction_id, + static void UpdatesForTransaction(UpdateInfo *current, transaction_t start_time, transaction_t transaction_id, T &&callback) { - if (current.AppliesToTransaction(start_time, transaction_id)) { - callback(current); - } - auto update_ptr = current.next; - while (update_ptr.IsSet()) { - auto pin = update_ptr.Pin(); - auto &info = Get(pin); - if (info.AppliesToTransaction(start_time, transaction_id)) { - callback(info); + while (current) { + if (current->version_number > start_time && current->version_number != transaction_id) { + // these tuples were either committed AFTER this transaction started or are not committed yet, use + // tuples stored in this version + callback(current); } - update_ptr = info.next; + current = current->next; } } @@ -81,13 +58,6 @@ struct UpdateInfo { string ToString(); void Print(); void Verify(); - bool HasPrev() const; - bool HasNext() const; - static UpdateInfo &Get(UndoBufferReference &entry); - //! Returns the total allocation size for an UpdateInfo entry, together with space for the tuple data - static idx_t GetAllocSize(idx_t type_size); - //! Initialize an UpdateInfo struct that has been allocated using GetAllocSize (i.e. has extra space after it) - static void Initialize(UpdateInfo &info, transaction_t transaction_id); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp b/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp index aad1a672c..0a4b1e1c1 100644 --- a/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp +++ b/src/duckdb/src/include/duckdb/transaction/wal_write_state.hpp @@ -14,7 +14,6 @@ namespace duckdb { class CatalogEntry; class DataChunk; -class DuckTransaction; class WriteAheadLog; class ClientContext; @@ -24,8 +23,7 @@ struct UpdateInfo; class WALWriteState { public: - explicit WALWriteState(DuckTransaction &transaction, WriteAheadLog &log, - optional_ptr commit_state); + explicit WALWriteState(WriteAheadLog &log, optional_ptr commit_state); public: void CommitEntry(UndoFlags type, data_ptr_t data); @@ -38,7 +36,6 @@ class WALWriteState { void WriteUpdate(UpdateInfo &info); private: - DuckTransaction &transaction; WriteAheadLog &log; optional_ptr commit_state; diff --git a/src/duckdb/src/include/duckdb/verification/copied_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/copied_statement_verifier.hpp index 0e1d021c4..1df929c6c 100644 --- a/src/duckdb/src/include/duckdb/verification/copied_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/copied_statement_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class CopiedStatementVerifier : public StatementVerifier { public: - explicit CopiedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement_p, - optional_ptr> parameters); + explicit CopiedStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement_p); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/verification/deserialized_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/deserialized_statement_verifier.hpp index af21d57d8..78b2ff1ef 100644 --- a/src/duckdb/src/include/duckdb/verification/deserialized_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/deserialized_statement_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class DeserializedStatementVerifier : public StatementVerifier { public: - explicit DeserializedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement, - optional_ptr> parameters); + explicit DeserializedStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement); }; } // namespace duckdb diff --git a/src/duckdb/src/include/duckdb/verification/external_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/external_statement_verifier.hpp index a46d97661..91d551f00 100644 --- a/src/duckdb/src/include/duckdb/verification/external_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/external_statement_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class ExternalStatementVerifier : public StatementVerifier { public: - explicit ExternalStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement, - optional_ptr> parameters); + explicit ExternalStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement); bool ForceExternal() const override { return true; diff --git a/src/duckdb/src/include/duckdb/verification/fetch_row_verifier.hpp b/src/duckdb/src/include/duckdb/verification/fetch_row_verifier.hpp index f4b75761d..007e98657 100644 --- a/src/duckdb/src/include/duckdb/verification/fetch_row_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/fetch_row_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class FetchRowVerifier : public StatementVerifier { public: - explicit FetchRowVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement_p, - optional_ptr> parameters); + explicit FetchRowVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement_p); bool ForceFetchRow() const override { return true; diff --git a/src/duckdb/src/include/duckdb/verification/no_operator_caching_verifier.hpp b/src/duckdb/src/include/duckdb/verification/no_operator_caching_verifier.hpp index 66b99db29..51a97d359 100644 --- a/src/duckdb/src/include/duckdb/verification/no_operator_caching_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/no_operator_caching_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class NoOperatorCachingVerifier : public StatementVerifier { public: - explicit NoOperatorCachingVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement_p, - optional_ptr> parameters); + explicit NoOperatorCachingVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement_p); bool DisableOperatorCaching() const override { return true; diff --git a/src/duckdb/src/include/duckdb/verification/parsed_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/parsed_statement_verifier.hpp index d689eecb3..5448d5f8f 100644 --- a/src/duckdb/src/include/duckdb/verification/parsed_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/parsed_statement_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class ParsedStatementVerifier : public StatementVerifier { public: - explicit ParsedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement, - optional_ptr> parameters); + explicit ParsedStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement); bool RequireEquality() const override { return false; diff --git a/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp index c34598c9b..23c7593ab 100644 --- a/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp @@ -14,15 +14,11 @@ namespace duckdb { class PreparedStatementVerifier : public StatementVerifier { public: - explicit PreparedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement_p, - optional_ptr> parameters); + explicit PreparedStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement_p); bool Run(ClientContext &context, const string &query, - const std::function(const string &, unique_ptr, - optional_ptr>)> - &run) override; + const std::function(const string &, unique_ptr)> &run) override; private: case_insensitive_map_t> values; diff --git a/src/duckdb/src/include/duckdb/verification/statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/statement_verifier.hpp index 63d52393e..27ce92a3a 100644 --- a/src/duckdb/src/include/duckdb/verification/statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/statement_verifier.hpp @@ -30,12 +30,9 @@ enum class VerificationType : uint8_t { class StatementVerifier { public: - StatementVerifier(VerificationType type, string name, unique_ptr statement_p, - optional_ptr> values); - explicit StatementVerifier(unique_ptr statement_p, - optional_ptr> values); - static unique_ptr Create(VerificationType type, const SQLStatement &statement_p, - optional_ptr> values); + StatementVerifier(VerificationType type, string name, unique_ptr statement_p); + explicit StatementVerifier(unique_ptr statement_p); + static unique_ptr Create(VerificationType type, const SQLStatement &statement_p); virtual ~StatementVerifier() noexcept; //! Check whether expressions in this verifier and the other verifier match @@ -44,10 +41,8 @@ class StatementVerifier { void CheckExpressions() const; //! Run the select statement and store the result - virtual bool - Run(ClientContext &context, const string &query, - const std::function(const string &, unique_ptr, - optional_ptr>)> &run); + virtual bool Run(ClientContext &context, const string &query, + const std::function(const string &, unique_ptr)> &run); //! Compare this verifier's results with another verifier string CompareResults(const StatementVerifier &other); @@ -55,7 +50,6 @@ class StatementVerifier { const VerificationType type; const string name; unique_ptr statement; - optional_ptr> parameters; const vector> &select_list; unique_ptr materialized_result; diff --git a/src/duckdb/src/include/duckdb/verification/unoptimized_statement_verifier.hpp b/src/duckdb/src/include/duckdb/verification/unoptimized_statement_verifier.hpp index 6521bb9c6..4d71b2e71 100644 --- a/src/duckdb/src/include/duckdb/verification/unoptimized_statement_verifier.hpp +++ b/src/duckdb/src/include/duckdb/verification/unoptimized_statement_verifier.hpp @@ -14,10 +14,8 @@ namespace duckdb { class UnoptimizedStatementVerifier : public StatementVerifier { public: - explicit UnoptimizedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters); - static unique_ptr Create(const SQLStatement &statement_p, - optional_ptr> parameters); + explicit UnoptimizedStatementVerifier(unique_ptr statement_p); + static unique_ptr Create(const SQLStatement &statement_p); bool DisableOptimizer() const override { return true; diff --git a/src/duckdb/src/include/duckdb_extension.h b/src/duckdb/src/include/duckdb_extension.h index 47c6a7f87..c70eb8a80 100644 --- a/src/duckdb/src/include/duckdb_extension.h +++ b/src/duckdb/src/include/duckdb_extension.h @@ -11,7 +11,8 @@ // WARNING: this file is autogenerated by scripts/generate_c_api.py, manual changes will be overwritten // !!!!!!! -// WARNING: this API is not yet stable, meaning it is only guaranteed to work for this specific DuckDB version. +// WARNING: this API is not yet stable, this means that this API is only guaranteed to work for this specific DuckDB +// version #pragma once @@ -40,36 +41,34 @@ // Versioning //===--------------------------------------------------------------------===// //! Set version to latest if no explicit version is defined - #if !defined(DUCKDB_EXTENSION_API_VERSION_MAJOR) && !defined(DUCKDB_EXTENSION_API_VERSION_MINOR) && \ !defined(DUCKDB_EXTENSION_API_VERSION_PATCH) -#define DUCKDB_EXTENSION_API_VERSION_MAJOR 1 -#define DUCKDB_EXTENSION_API_VERSION_MINOR 2 -#define DUCKDB_EXTENSION_API_VERSION_PATCH 0 +#define DUCKDB_EXTENSION_API_VERSION_MAJOR 0 +#define DUCKDB_EXTENSION_API_VERSION_MINOR 0 +#define DUCKDB_EXTENSION_API_VERSION_PATCH 1 #elif !(defined(DUCKDB_EXTENSION_API_VERSION_MAJOR) && defined(DUCKDB_EXTENSION_API_VERSION_MINOR) && \ defined(DUCKDB_EXTENSION_API_VERSION_PATCH)) #error "either all or none of the DUCKDB_EXTENSION_API_VERSION_ defines should be defined" #endif //! Set the DUCKDB_EXTENSION_API_VERSION_STRING which is passed to DuckDB on extension load -#ifdef DUCKDB_EXTENSION_API_UNSTABLE_VERSION -#define DUCKDB_EXTENSION_API_VERSION_STRING DUCKDB_EXTENSION_API_UNSTABLE_VERSION +#if DUCKDB_EXTENSION_API_VERSION_DEV +#define DUCKDB_EXTENSION_API_VERSION_STRING "dev" #else #define DUCKDB_EXTENSION_API_VERSION_STRING \ DUCKDB_EXTENSION_SEMVER_STRING(DUCKDB_EXTENSION_API_VERSION_MAJOR, DUCKDB_EXTENSION_API_VERSION_MINOR, \ DUCKDB_EXTENSION_API_VERSION_PATCH) #endif -#if DUCKDB_EXTENSION_API_VERSION_MAJOR != 1 -#error "This version of the extension API header only supports API VERSION v1.x.x" +#if DUCKDB_EXTENSION_API_VERSION_MAJOR != 0 +#error "This version of the extension API header only supports API VERSION v0.x.x" #endif //===--------------------------------------------------------------------===// // Function pointer struct //===--------------------------------------------------------------------===// typedef struct { -#if DUCKDB_EXTENSION_API_VERSION_MINOR > 2 || \ - (DUCKDB_EXTENSION_API_VERSION_MINOR == 2 && DUCKDB_EXTENSION_API_VERSION_PATCH >= 0) // v1.2.0 +#if DUCKDB_EXTENSION_API_VERSION_MINOR >= 0 && DUCKDB_EXTENSION_API_VERSION_PATCH >= 1 // v0.0.1 duckdb_state (*duckdb_open)(const char *path, duckdb_database *out_database); duckdb_state (*duckdb_open_ext)(const char *path, duckdb_database *out_database, duckdb_config config, char **out_error); @@ -93,14 +92,10 @@ typedef struct { idx_t (*duckdb_column_count)(duckdb_result *result); idx_t (*duckdb_rows_changed)(duckdb_result *result); const char *(*duckdb_result_error)(duckdb_result *result); - duckdb_error_type (*duckdb_result_error_type)(duckdb_result *result); - duckdb_result_type (*duckdb_result_return_type)(duckdb_result result); void *(*duckdb_malloc)(size_t size); void (*duckdb_free)(void *ptr); idx_t (*duckdb_vector_size)(); bool (*duckdb_string_is_inlined)(duckdb_string_t string); - uint32_t (*duckdb_string_t_length)(duckdb_string_t string); - const char *(*duckdb_string_t_data)(duckdb_string_t *string); duckdb_date_struct (*duckdb_from_date)(duckdb_date date); duckdb_date (*duckdb_to_date)(duckdb_date_struct date); bool (*duckdb_is_finite_date)(duckdb_date date); @@ -124,7 +119,6 @@ typedef struct { idx_t (*duckdb_nparams)(duckdb_prepared_statement prepared_statement); const char *(*duckdb_parameter_name)(duckdb_prepared_statement prepared_statement, idx_t index); duckdb_type (*duckdb_param_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); - duckdb_logical_type (*duckdb_param_logical_type)(duckdb_prepared_statement prepared_statement, idx_t param_idx); duckdb_state (*duckdb_clear_bindings)(duckdb_prepared_statement prepared_statement); duckdb_statement_type (*duckdb_prepared_statement_type)(duckdb_prepared_statement statement); duckdb_state (*duckdb_bind_value)(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_value val); @@ -180,70 +174,14 @@ typedef struct { void (*duckdb_destroy_value)(duckdb_value *value); duckdb_value (*duckdb_create_varchar)(const char *text); duckdb_value (*duckdb_create_varchar_length)(const char *text, idx_t length); - duckdb_value (*duckdb_create_bool)(bool input); - duckdb_value (*duckdb_create_int8)(int8_t input); - duckdb_value (*duckdb_create_uint8)(uint8_t input); - duckdb_value (*duckdb_create_int16)(int16_t input); - duckdb_value (*duckdb_create_uint16)(uint16_t input); - duckdb_value (*duckdb_create_int32)(int32_t input); - duckdb_value (*duckdb_create_uint32)(uint32_t input); - duckdb_value (*duckdb_create_uint64)(uint64_t input); duckdb_value (*duckdb_create_int64)(int64_t val); - duckdb_value (*duckdb_create_hugeint)(duckdb_hugeint input); - duckdb_value (*duckdb_create_uhugeint)(duckdb_uhugeint input); - duckdb_value (*duckdb_create_float)(float input); - duckdb_value (*duckdb_create_double)(double input); - duckdb_value (*duckdb_create_date)(duckdb_date input); - duckdb_value (*duckdb_create_time)(duckdb_time input); - duckdb_value (*duckdb_create_time_tz_value)(duckdb_time_tz value); - duckdb_value (*duckdb_create_timestamp)(duckdb_timestamp input); - duckdb_value (*duckdb_create_interval)(duckdb_interval input); - duckdb_value (*duckdb_create_blob)(const uint8_t *data, idx_t length); - duckdb_value (*duckdb_create_varint)(duckdb_varint input); - duckdb_value (*duckdb_create_decimal)(duckdb_decimal input); - duckdb_value (*duckdb_create_bit)(duckdb_bit input); - duckdb_value (*duckdb_create_uuid)(duckdb_uhugeint input); - bool (*duckdb_get_bool)(duckdb_value val); - int8_t (*duckdb_get_int8)(duckdb_value val); - uint8_t (*duckdb_get_uint8)(duckdb_value val); - int16_t (*duckdb_get_int16)(duckdb_value val); - uint16_t (*duckdb_get_uint16)(duckdb_value val); - int32_t (*duckdb_get_int32)(duckdb_value val); - uint32_t (*duckdb_get_uint32)(duckdb_value val); - int64_t (*duckdb_get_int64)(duckdb_value val); - uint64_t (*duckdb_get_uint64)(duckdb_value val); - duckdb_hugeint (*duckdb_get_hugeint)(duckdb_value val); - duckdb_uhugeint (*duckdb_get_uhugeint)(duckdb_value val); - float (*duckdb_get_float)(duckdb_value val); - double (*duckdb_get_double)(duckdb_value val); - duckdb_date (*duckdb_get_date)(duckdb_value val); - duckdb_time (*duckdb_get_time)(duckdb_value val); - duckdb_time_tz (*duckdb_get_time_tz)(duckdb_value val); - duckdb_timestamp (*duckdb_get_timestamp)(duckdb_value val); - duckdb_interval (*duckdb_get_interval)(duckdb_value val); - duckdb_logical_type (*duckdb_get_value_type)(duckdb_value val); - duckdb_blob (*duckdb_get_blob)(duckdb_value val); - duckdb_varint (*duckdb_get_varint)(duckdb_value val); - duckdb_decimal (*duckdb_get_decimal)(duckdb_value val); - duckdb_bit (*duckdb_get_bit)(duckdb_value val); - duckdb_uhugeint (*duckdb_get_uuid)(duckdb_value val); - char *(*duckdb_get_varchar)(duckdb_value value); duckdb_value (*duckdb_create_struct_value)(duckdb_logical_type type, duckdb_value *values); duckdb_value (*duckdb_create_list_value)(duckdb_logical_type type, duckdb_value *values, idx_t value_count); duckdb_value (*duckdb_create_array_value)(duckdb_logical_type type, duckdb_value *values, idx_t value_count); - idx_t (*duckdb_get_map_size)(duckdb_value value); - duckdb_value (*duckdb_get_map_key)(duckdb_value value, idx_t index); - duckdb_value (*duckdb_get_map_value)(duckdb_value value, idx_t index); - bool (*duckdb_is_null_value)(duckdb_value value); - duckdb_value (*duckdb_create_null_value)(); - idx_t (*duckdb_get_list_size)(duckdb_value value); - duckdb_value (*duckdb_get_list_child)(duckdb_value value, idx_t index); - duckdb_value (*duckdb_create_enum_value)(duckdb_logical_type type, uint64_t value); - uint64_t (*duckdb_get_enum_value)(duckdb_value value); - duckdb_value (*duckdb_get_struct_child)(duckdb_value value, idx_t index); + char *(*duckdb_get_varchar)(duckdb_value value); + int64_t (*duckdb_get_int64)(duckdb_value val); duckdb_logical_type (*duckdb_create_logical_type)(duckdb_type type); char *(*duckdb_logical_type_get_alias)(duckdb_logical_type type); - void (*duckdb_logical_type_set_alias)(duckdb_logical_type type, const char *alias); duckdb_logical_type (*duckdb_create_list_type)(duckdb_logical_type type); duckdb_logical_type (*duckdb_create_array_type)(duckdb_logical_type type, idx_t array_size); duckdb_logical_type (*duckdb_create_map_type)(duckdb_logical_type key_type, duckdb_logical_type value_type); @@ -272,8 +210,7 @@ typedef struct { char *(*duckdb_union_type_member_name)(duckdb_logical_type type, idx_t index); duckdb_logical_type (*duckdb_union_type_member_type)(duckdb_logical_type type, idx_t index); void (*duckdb_destroy_logical_type)(duckdb_logical_type *type); - duckdb_state (*duckdb_register_logical_type)(duckdb_connection con, duckdb_logical_type type, - duckdb_create_type_info info); + duckdb_data_chunk (*duckdb_fetch_chunk)(duckdb_result result); duckdb_data_chunk (*duckdb_create_data_chunk)(duckdb_logical_type *types, idx_t column_count); void (*duckdb_destroy_data_chunk)(duckdb_data_chunk *chunk); void (*duckdb_data_chunk_reset)(duckdb_data_chunk chunk); @@ -300,9 +237,6 @@ typedef struct { duckdb_scalar_function (*duckdb_create_scalar_function)(); void (*duckdb_destroy_scalar_function)(duckdb_scalar_function *scalar_function); void (*duckdb_scalar_function_set_name)(duckdb_scalar_function scalar_function, const char *name); - void (*duckdb_scalar_function_set_varargs)(duckdb_scalar_function scalar_function, duckdb_logical_type type); - void (*duckdb_scalar_function_set_special_handling)(duckdb_scalar_function scalar_function); - void (*duckdb_scalar_function_set_volatile)(duckdb_scalar_function scalar_function); void (*duckdb_scalar_function_add_parameter)(duckdb_scalar_function scalar_function, duckdb_logical_type type); void (*duckdb_scalar_function_set_return_type)(duckdb_scalar_function scalar_function, duckdb_logical_type type); void (*duckdb_scalar_function_set_extra_info)(duckdb_scalar_function scalar_function, void *extra_info, @@ -310,39 +244,6 @@ typedef struct { void (*duckdb_scalar_function_set_function)(duckdb_scalar_function scalar_function, duckdb_scalar_function_t function); duckdb_state (*duckdb_register_scalar_function)(duckdb_connection con, duckdb_scalar_function scalar_function); - void *(*duckdb_scalar_function_get_extra_info)(duckdb_function_info info); - void (*duckdb_scalar_function_set_error)(duckdb_function_info info, const char *error); - duckdb_scalar_function_set (*duckdb_create_scalar_function_set)(const char *name); - void (*duckdb_destroy_scalar_function_set)(duckdb_scalar_function_set *scalar_function_set); - duckdb_state (*duckdb_add_scalar_function_to_set)(duckdb_scalar_function_set set, duckdb_scalar_function function); - duckdb_state (*duckdb_register_scalar_function_set)(duckdb_connection con, duckdb_scalar_function_set set); - duckdb_aggregate_function (*duckdb_create_aggregate_function)(); - void (*duckdb_destroy_aggregate_function)(duckdb_aggregate_function *aggregate_function); - void (*duckdb_aggregate_function_set_name)(duckdb_aggregate_function aggregate_function, const char *name); - void (*duckdb_aggregate_function_add_parameter)(duckdb_aggregate_function aggregate_function, - duckdb_logical_type type); - void (*duckdb_aggregate_function_set_return_type)(duckdb_aggregate_function aggregate_function, - duckdb_logical_type type); - void (*duckdb_aggregate_function_set_functions)(duckdb_aggregate_function aggregate_function, - duckdb_aggregate_state_size state_size, - duckdb_aggregate_init_t state_init, - duckdb_aggregate_update_t update, - duckdb_aggregate_combine_t combine, - duckdb_aggregate_finalize_t finalize); - void (*duckdb_aggregate_function_set_destructor)(duckdb_aggregate_function aggregate_function, - duckdb_aggregate_destroy_t destroy); - duckdb_state (*duckdb_register_aggregate_function)(duckdb_connection con, - duckdb_aggregate_function aggregate_function); - void (*duckdb_aggregate_function_set_special_handling)(duckdb_aggregate_function aggregate_function); - void (*duckdb_aggregate_function_set_extra_info)(duckdb_aggregate_function aggregate_function, void *extra_info, - duckdb_delete_callback_t destroy); - void *(*duckdb_aggregate_function_get_extra_info)(duckdb_function_info info); - void (*duckdb_aggregate_function_set_error)(duckdb_function_info info, const char *error); - duckdb_aggregate_function_set (*duckdb_create_aggregate_function_set)(const char *name); - void (*duckdb_destroy_aggregate_function_set)(duckdb_aggregate_function_set *aggregate_function_set); - duckdb_state (*duckdb_add_aggregate_function_to_set)(duckdb_aggregate_function_set set, - duckdb_aggregate_function function); - duckdb_state (*duckdb_register_aggregate_function_set)(duckdb_connection con, duckdb_aggregate_function_set set); duckdb_table_function (*duckdb_create_table_function)(); void (*duckdb_destroy_table_function)(duckdb_table_function *table_function); void (*duckdb_table_function_set_name)(duckdb_table_function table_function, const char *name); @@ -383,68 +284,14 @@ typedef struct { void (*duckdb_replacement_scan_set_function_name)(duckdb_replacement_scan_info info, const char *function_name); void (*duckdb_replacement_scan_add_parameter)(duckdb_replacement_scan_info info, duckdb_value parameter); void (*duckdb_replacement_scan_set_error)(duckdb_replacement_scan_info info, const char *error); - duckdb_value (*duckdb_profiling_info_get_metrics)(duckdb_profiling_info info); - idx_t (*duckdb_profiling_info_get_child_count)(duckdb_profiling_info info); - duckdb_profiling_info (*duckdb_profiling_info_get_child)(duckdb_profiling_info info, idx_t index); duckdb_state (*duckdb_appender_create)(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender); - duckdb_state (*duckdb_appender_create_ext)(duckdb_connection connection, const char *catalog, const char *schema, - const char *table, duckdb_appender *out_appender); idx_t (*duckdb_appender_column_count)(duckdb_appender appender); duckdb_logical_type (*duckdb_appender_column_type)(duckdb_appender appender, idx_t col_idx); const char *(*duckdb_appender_error)(duckdb_appender appender); duckdb_state (*duckdb_appender_flush)(duckdb_appender appender); duckdb_state (*duckdb_appender_close)(duckdb_appender appender); duckdb_state (*duckdb_appender_destroy)(duckdb_appender *appender); - duckdb_state (*duckdb_appender_add_column)(duckdb_appender appender, const char *name); - duckdb_state (*duckdb_appender_clear_columns)(duckdb_appender appender); - duckdb_state (*duckdb_append_data_chunk)(duckdb_appender appender, duckdb_data_chunk chunk); - duckdb_state (*duckdb_table_description_create)(duckdb_connection connection, const char *schema, const char *table, - duckdb_table_description *out); - duckdb_state (*duckdb_table_description_create_ext)(duckdb_connection connection, const char *catalog, - const char *schema, const char *table, - duckdb_table_description *out); - void (*duckdb_table_description_destroy)(duckdb_table_description *table_description); - const char *(*duckdb_table_description_error)(duckdb_table_description table_description); - duckdb_state (*duckdb_column_has_default)(duckdb_table_description table_description, idx_t index, bool *out); - char *(*duckdb_table_description_get_column_name)(duckdb_table_description table_description, idx_t index); - void (*duckdb_execute_tasks)(duckdb_database database, idx_t max_tasks); - duckdb_task_state (*duckdb_create_task_state)(duckdb_database database); - void (*duckdb_execute_tasks_state)(duckdb_task_state state); - idx_t (*duckdb_execute_n_tasks_state)(duckdb_task_state state, idx_t max_tasks); - void (*duckdb_finish_execution)(duckdb_task_state state); - bool (*duckdb_task_state_is_finished)(duckdb_task_state state); - void (*duckdb_destroy_task_state)(duckdb_task_state state); - bool (*duckdb_execution_is_finished)(duckdb_connection con); - duckdb_data_chunk (*duckdb_fetch_chunk)(duckdb_result result); - duckdb_cast_function (*duckdb_create_cast_function)(); - void (*duckdb_cast_function_set_source_type)(duckdb_cast_function cast_function, duckdb_logical_type source_type); - void (*duckdb_cast_function_set_target_type)(duckdb_cast_function cast_function, duckdb_logical_type target_type); - void (*duckdb_cast_function_set_implicit_cast_cost)(duckdb_cast_function cast_function, int64_t cost); - void (*duckdb_cast_function_set_function)(duckdb_cast_function cast_function, duckdb_cast_function_t function); - void (*duckdb_cast_function_set_extra_info)(duckdb_cast_function cast_function, void *extra_info, - duckdb_delete_callback_t destroy); - void *(*duckdb_cast_function_get_extra_info)(duckdb_function_info info); - duckdb_cast_mode (*duckdb_cast_function_get_cast_mode)(duckdb_function_info info); - void (*duckdb_cast_function_set_error)(duckdb_function_info info, const char *error); - void (*duckdb_cast_function_set_row_error)(duckdb_function_info info, const char *error, idx_t row, - duckdb_vector output); - duckdb_state (*duckdb_register_cast_function)(duckdb_connection con, duckdb_cast_function cast_function); - void (*duckdb_destroy_cast_function)(duckdb_cast_function *cast_function); - bool (*duckdb_is_finite_timestamp_s)(duckdb_timestamp_s ts); - bool (*duckdb_is_finite_timestamp_ms)(duckdb_timestamp_ms ts); - bool (*duckdb_is_finite_timestamp_ns)(duckdb_timestamp_ns ts); - duckdb_value (*duckdb_create_timestamp_tz)(duckdb_timestamp input); - duckdb_value (*duckdb_create_timestamp_s)(duckdb_timestamp_s input); - duckdb_value (*duckdb_create_timestamp_ms)(duckdb_timestamp_ms input); - duckdb_value (*duckdb_create_timestamp_ns)(duckdb_timestamp_ns input); - duckdb_timestamp (*duckdb_get_timestamp_tz)(duckdb_value val); - duckdb_timestamp_s (*duckdb_get_timestamp_s)(duckdb_value val); - duckdb_timestamp_ms (*duckdb_get_timestamp_ms)(duckdb_value val); - duckdb_timestamp_ns (*duckdb_get_timestamp_ns)(duckdb_value val); - duckdb_state (*duckdb_append_value)(duckdb_appender appender, duckdb_value value); - duckdb_profiling_info (*duckdb_get_profiling_info)(duckdb_connection connection); - duckdb_value (*duckdb_profiling_info_get_value)(duckdb_profiling_info info, const char *key); duckdb_state (*duckdb_appender_begin_row)(duckdb_appender appender); duckdb_state (*duckdb_appender_end_row)(duckdb_appender appender); duckdb_state (*duckdb_append_default)(duckdb_appender appender); @@ -469,16 +316,127 @@ typedef struct { duckdb_state (*duckdb_append_varchar_length)(duckdb_appender appender, const char *val, idx_t length); duckdb_state (*duckdb_append_blob)(duckdb_appender appender, const void *data, idx_t length); duckdb_state (*duckdb_append_null)(duckdb_appender appender); -#endif - -// These functions have been deprecated and may be removed in future versions of DuckDB -#ifdef DUCKDB_EXTENSION_API_VERSION_UNSTABLE + duckdb_state (*duckdb_append_data_chunk)(duckdb_appender appender, duckdb_data_chunk chunk); + void (*duckdb_execute_tasks)(duckdb_database database, idx_t max_tasks); + duckdb_task_state (*duckdb_create_task_state)(duckdb_database database); + void (*duckdb_execute_tasks_state)(duckdb_task_state state); + idx_t (*duckdb_execute_n_tasks_state)(duckdb_task_state state, idx_t max_tasks); + void (*duckdb_finish_execution)(duckdb_task_state state); + bool (*duckdb_task_state_is_finished)(duckdb_task_state state); + void (*duckdb_destroy_task_state)(duckdb_task_state state); + bool (*duckdb_execution_is_finished)(duckdb_connection con); + duckdb_profiling_info (*duckdb_get_profiling_info)(duckdb_connection connection); + duckdb_value (*duckdb_profiling_info_get_value)(duckdb_profiling_info info, const char *key); + idx_t (*duckdb_profiling_info_get_child_count)(duckdb_profiling_info info); + duckdb_profiling_info (*duckdb_profiling_info_get_child)(duckdb_profiling_info info, idx_t index); + duckdb_value (*duckdb_profiling_info_get_metrics)(duckdb_profiling_info info); + void (*duckdb_scalar_function_set_varargs)(duckdb_scalar_function scalar_function, duckdb_logical_type type); + void (*duckdb_scalar_function_set_special_handling)(duckdb_scalar_function scalar_function); + void (*duckdb_scalar_function_set_volatile)(duckdb_scalar_function scalar_function); + void *(*duckdb_scalar_function_get_extra_info)(duckdb_function_info info); + void (*duckdb_scalar_function_set_error)(duckdb_function_info info, const char *error); + duckdb_state (*duckdb_table_description_create)(duckdb_connection connection, const char *schema, const char *table, + duckdb_table_description *out); + void (*duckdb_table_description_destroy)(duckdb_table_description *table_description); + const char *(*duckdb_table_description_error)(duckdb_table_description table_description); + duckdb_error_type (*duckdb_result_error_type)(duckdb_result *result); + uint32_t (*duckdb_string_t_length)(duckdb_string_t string); + const char *(*duckdb_string_t_data)(duckdb_string_t *string); + duckdb_value (*duckdb_create_bool)(bool input); + duckdb_value (*duckdb_create_int8)(int8_t input); + duckdb_value (*duckdb_create_uint8)(uint8_t input); + duckdb_value (*duckdb_create_int16)(int16_t input); + duckdb_value (*duckdb_create_uint16)(uint16_t input); + duckdb_value (*duckdb_create_int32)(int32_t input); + duckdb_value (*duckdb_create_uint32)(uint32_t input); + duckdb_value (*duckdb_create_uint64)(uint64_t input); + duckdb_value (*duckdb_create_hugeint)(duckdb_hugeint input); + duckdb_value (*duckdb_create_uhugeint)(duckdb_uhugeint input); + duckdb_value (*duckdb_create_float)(float input); + duckdb_value (*duckdb_create_double)(double input); + duckdb_value (*duckdb_create_date)(duckdb_date input); + duckdb_value (*duckdb_create_time)(duckdb_time input); + duckdb_value (*duckdb_create_time_tz_value)(duckdb_time_tz value); + duckdb_value (*duckdb_create_timestamp)(duckdb_timestamp input); + duckdb_value (*duckdb_create_interval)(duckdb_interval input); + duckdb_value (*duckdb_create_blob)(const uint8_t *data, idx_t length); + bool (*duckdb_get_bool)(duckdb_value val); + int8_t (*duckdb_get_int8)(duckdb_value val); + uint8_t (*duckdb_get_uint8)(duckdb_value val); + int16_t (*duckdb_get_int16)(duckdb_value val); + uint16_t (*duckdb_get_uint16)(duckdb_value val); + int32_t (*duckdb_get_int32)(duckdb_value val); + uint32_t (*duckdb_get_uint32)(duckdb_value val); + uint64_t (*duckdb_get_uint64)(duckdb_value val); + duckdb_hugeint (*duckdb_get_hugeint)(duckdb_value val); + duckdb_uhugeint (*duckdb_get_uhugeint)(duckdb_value val); + float (*duckdb_get_float)(duckdb_value val); + double (*duckdb_get_double)(duckdb_value val); + duckdb_date (*duckdb_get_date)(duckdb_value val); + duckdb_time (*duckdb_get_time)(duckdb_value val); + duckdb_time_tz (*duckdb_get_time_tz)(duckdb_value val); + duckdb_timestamp (*duckdb_get_timestamp)(duckdb_value val); + duckdb_interval (*duckdb_get_interval)(duckdb_value val); + duckdb_logical_type (*duckdb_get_value_type)(duckdb_value val); + duckdb_blob (*duckdb_get_blob)(duckdb_value val); + duckdb_scalar_function_set (*duckdb_create_scalar_function_set)(const char *name); + void (*duckdb_destroy_scalar_function_set)(duckdb_scalar_function_set *scalar_function_set); + duckdb_state (*duckdb_add_scalar_function_to_set)(duckdb_scalar_function_set set, duckdb_scalar_function function); + duckdb_state (*duckdb_register_scalar_function_set)(duckdb_connection con, duckdb_scalar_function_set set); + duckdb_aggregate_function_set (*duckdb_create_aggregate_function_set)(const char *name); + void (*duckdb_destroy_aggregate_function_set)(duckdb_aggregate_function_set *aggregate_function_set); + duckdb_state (*duckdb_add_aggregate_function_to_set)(duckdb_aggregate_function_set set, + duckdb_aggregate_function function); + duckdb_state (*duckdb_register_aggregate_function_set)(duckdb_connection con, duckdb_aggregate_function_set set); + idx_t (*duckdb_get_map_size)(duckdb_value value); + duckdb_value (*duckdb_get_map_key)(duckdb_value value, idx_t index); + duckdb_value (*duckdb_get_map_value)(duckdb_value value, idx_t index); + duckdb_aggregate_function (*duckdb_create_aggregate_function)(); + void (*duckdb_destroy_aggregate_function)(duckdb_aggregate_function *aggregate_function); + void (*duckdb_aggregate_function_set_name)(duckdb_aggregate_function aggregate_function, const char *name); + void (*duckdb_aggregate_function_add_parameter)(duckdb_aggregate_function aggregate_function, + duckdb_logical_type type); + void (*duckdb_aggregate_function_set_return_type)(duckdb_aggregate_function aggregate_function, + duckdb_logical_type type); + void (*duckdb_aggregate_function_set_functions)(duckdb_aggregate_function aggregate_function, + duckdb_aggregate_state_size state_size, + duckdb_aggregate_init_t state_init, + duckdb_aggregate_update_t update, + duckdb_aggregate_combine_t combine, + duckdb_aggregate_finalize_t finalize); + void (*duckdb_aggregate_function_set_destructor)(duckdb_aggregate_function aggregate_function, + duckdb_aggregate_destroy_t destroy); + duckdb_state (*duckdb_register_aggregate_function)(duckdb_connection con, + duckdb_aggregate_function aggregate_function); + void (*duckdb_aggregate_function_set_special_handling)(duckdb_aggregate_function aggregate_function); + void (*duckdb_aggregate_function_set_extra_info)(duckdb_aggregate_function aggregate_function, void *extra_info, + duckdb_delete_callback_t destroy); + void *(*duckdb_aggregate_function_get_extra_info)(duckdb_function_info info); + void (*duckdb_aggregate_function_set_error)(duckdb_function_info info, const char *error); + void (*duckdb_logical_type_set_alias)(duckdb_logical_type type, const char *alias); + duckdb_state (*duckdb_register_logical_type)(duckdb_connection con, duckdb_logical_type type, + duckdb_create_type_info info); + duckdb_cast_function (*duckdb_create_cast_function)(); + void (*duckdb_cast_function_set_source_type)(duckdb_cast_function cast_function, duckdb_logical_type source_type); + void (*duckdb_cast_function_set_target_type)(duckdb_cast_function cast_function, duckdb_logical_type target_type); + void (*duckdb_cast_function_set_implicit_cast_cost)(duckdb_cast_function cast_function, int64_t cost); + void (*duckdb_cast_function_set_function)(duckdb_cast_function cast_function, duckdb_cast_function_t function); + void (*duckdb_cast_function_set_extra_info)(duckdb_cast_function cast_function, void *extra_info, + duckdb_delete_callback_t destroy); + void *(*duckdb_cast_function_get_extra_info)(duckdb_function_info info); + duckdb_cast_mode (*duckdb_cast_function_get_cast_mode)(duckdb_function_info info); + void (*duckdb_cast_function_set_error)(duckdb_function_info info, const char *error); + void (*duckdb_cast_function_set_row_error)(duckdb_function_info info, const char *error, idx_t row, + duckdb_vector output); + duckdb_state (*duckdb_register_cast_function)(duckdb_connection con, duckdb_cast_function cast_function); + void (*duckdb_destroy_cast_function)(duckdb_cast_function *cast_function); idx_t (*duckdb_row_count)(duckdb_result *result); void *(*duckdb_column_data)(duckdb_result *result, idx_t col); bool *(*duckdb_nullmask_data)(duckdb_result *result, idx_t col); duckdb_data_chunk (*duckdb_result_get_chunk)(duckdb_result result, idx_t chunk_index); bool (*duckdb_result_is_streaming)(duckdb_result result); idx_t (*duckdb_result_chunk_count)(duckdb_result result); + duckdb_result_type (*duckdb_result_return_type)(duckdb_result result); bool (*duckdb_value_boolean)(duckdb_result *result, idx_t col, idx_t row); int8_t (*duckdb_value_int8)(duckdb_result *result, idx_t col, idx_t row); int16_t (*duckdb_value_int16)(duckdb_result *result, idx_t col, idx_t row); @@ -507,6 +465,7 @@ typedef struct { duckdb_result *out_result); duckdb_state (*duckdb_pending_prepared_streaming)(duckdb_prepared_statement prepared_statement, duckdb_pending_result *out_result); + duckdb_state (*duckdb_column_has_default)(duckdb_table_description table_description, idx_t index, bool *out); duckdb_state (*duckdb_query_arrow)(duckdb_connection connection, const char *query, duckdb_arrow *out_result); duckdb_state (*duckdb_query_arrow_schema)(duckdb_arrow result, duckdb_arrow_schema *out_schema); duckdb_state (*duckdb_prepared_arrow_schema)(duckdb_prepared_statement prepared, duckdb_arrow_schema *out_schema); @@ -527,27 +486,12 @@ typedef struct { duckdb_data_chunk (*duckdb_stream_fetch_chunk)(duckdb_result result); #endif -// Exposing the instance cache -#ifdef DUCKDB_EXTENSION_API_VERSION_UNSTABLE - duckdb_instance_cache (*duckdb_create_instance_cache)(); - duckdb_state (*duckdb_get_or_create_from_cache)(duckdb_instance_cache instance_cache, const char *path, - duckdb_database *out_database, duckdb_config config, - char **out_error); - void (*duckdb_destroy_instance_cache)(duckdb_instance_cache *instance_cache); -#endif - -// New append functions that are added -#ifdef DUCKDB_EXTENSION_API_VERSION_UNSTABLE - duckdb_state (*duckdb_append_default_to_chunk)(duckdb_appender appender, duckdb_data_chunk chunk, idx_t col, - idx_t row); -#endif - -} duckdb_ext_api_v1; +} duckdb_ext_api_v0; //===--------------------------------------------------------------------===// // Typedefs mapping functions to struct entries //===--------------------------------------------------------------------===// -// Version v1.2.0 +// Version v0.0.1 #define duckdb_open duckdb_ext_api.duckdb_open #define duckdb_open_ext duckdb_ext_api.duckdb_open_ext #define duckdb_close duckdb_ext_api.duckdb_close @@ -568,10 +512,40 @@ typedef struct { #define duckdb_result_statement_type duckdb_ext_api.duckdb_result_statement_type #define duckdb_column_logical_type duckdb_ext_api.duckdb_column_logical_type #define duckdb_column_count duckdb_ext_api.duckdb_column_count +#define duckdb_row_count duckdb_ext_api.duckdb_row_count #define duckdb_rows_changed duckdb_ext_api.duckdb_rows_changed +#define duckdb_column_data duckdb_ext_api.duckdb_column_data +#define duckdb_nullmask_data duckdb_ext_api.duckdb_nullmask_data #define duckdb_result_error duckdb_ext_api.duckdb_result_error #define duckdb_result_error_type duckdb_ext_api.duckdb_result_error_type +#define duckdb_result_get_chunk duckdb_ext_api.duckdb_result_get_chunk +#define duckdb_result_is_streaming duckdb_ext_api.duckdb_result_is_streaming +#define duckdb_result_chunk_count duckdb_ext_api.duckdb_result_chunk_count #define duckdb_result_return_type duckdb_ext_api.duckdb_result_return_type +#define duckdb_value_boolean duckdb_ext_api.duckdb_value_boolean +#define duckdb_value_int8 duckdb_ext_api.duckdb_value_int8 +#define duckdb_value_int16 duckdb_ext_api.duckdb_value_int16 +#define duckdb_value_int32 duckdb_ext_api.duckdb_value_int32 +#define duckdb_value_int64 duckdb_ext_api.duckdb_value_int64 +#define duckdb_value_hugeint duckdb_ext_api.duckdb_value_hugeint +#define duckdb_value_uhugeint duckdb_ext_api.duckdb_value_uhugeint +#define duckdb_value_decimal duckdb_ext_api.duckdb_value_decimal +#define duckdb_value_uint8 duckdb_ext_api.duckdb_value_uint8 +#define duckdb_value_uint16 duckdb_ext_api.duckdb_value_uint16 +#define duckdb_value_uint32 duckdb_ext_api.duckdb_value_uint32 +#define duckdb_value_uint64 duckdb_ext_api.duckdb_value_uint64 +#define duckdb_value_float duckdb_ext_api.duckdb_value_float +#define duckdb_value_double duckdb_ext_api.duckdb_value_double +#define duckdb_value_date duckdb_ext_api.duckdb_value_date +#define duckdb_value_time duckdb_ext_api.duckdb_value_time +#define duckdb_value_timestamp duckdb_ext_api.duckdb_value_timestamp +#define duckdb_value_interval duckdb_ext_api.duckdb_value_interval +#define duckdb_value_varchar duckdb_ext_api.duckdb_value_varchar +#define duckdb_value_string duckdb_ext_api.duckdb_value_string +#define duckdb_value_varchar_internal duckdb_ext_api.duckdb_value_varchar_internal +#define duckdb_value_string_internal duckdb_ext_api.duckdb_value_string_internal +#define duckdb_value_blob duckdb_ext_api.duckdb_value_blob +#define duckdb_value_is_null duckdb_ext_api.duckdb_value_is_null #define duckdb_malloc duckdb_ext_api.duckdb_malloc #define duckdb_free duckdb_ext_api.duckdb_free #define duckdb_vector_size duckdb_ext_api.duckdb_vector_size @@ -588,9 +562,6 @@ typedef struct { #define duckdb_from_timestamp duckdb_ext_api.duckdb_from_timestamp #define duckdb_to_timestamp duckdb_ext_api.duckdb_to_timestamp #define duckdb_is_finite_timestamp duckdb_ext_api.duckdb_is_finite_timestamp -#define duckdb_is_finite_timestamp_s duckdb_ext_api.duckdb_is_finite_timestamp_s -#define duckdb_is_finite_timestamp_ms duckdb_ext_api.duckdb_is_finite_timestamp_ms -#define duckdb_is_finite_timestamp_ns duckdb_ext_api.duckdb_is_finite_timestamp_ns #define duckdb_hugeint_to_double duckdb_ext_api.duckdb_hugeint_to_double #define duckdb_double_to_hugeint duckdb_ext_api.duckdb_double_to_hugeint #define duckdb_uhugeint_to_double duckdb_ext_api.duckdb_uhugeint_to_double @@ -603,7 +574,6 @@ typedef struct { #define duckdb_nparams duckdb_ext_api.duckdb_nparams #define duckdb_parameter_name duckdb_ext_api.duckdb_parameter_name #define duckdb_param_type duckdb_ext_api.duckdb_param_type -#define duckdb_param_logical_type duckdb_ext_api.duckdb_param_logical_type #define duckdb_clear_bindings duckdb_ext_api.duckdb_clear_bindings #define duckdb_prepared_statement_type duckdb_ext_api.duckdb_prepared_statement_type #define duckdb_bind_value duckdb_ext_api.duckdb_bind_value @@ -632,11 +602,13 @@ typedef struct { #define duckdb_bind_blob duckdb_ext_api.duckdb_bind_blob #define duckdb_bind_null duckdb_ext_api.duckdb_bind_null #define duckdb_execute_prepared duckdb_ext_api.duckdb_execute_prepared +#define duckdb_execute_prepared_streaming duckdb_ext_api.duckdb_execute_prepared_streaming #define duckdb_extract_statements duckdb_ext_api.duckdb_extract_statements #define duckdb_prepare_extracted_statement duckdb_ext_api.duckdb_prepare_extracted_statement #define duckdb_extract_statements_error duckdb_ext_api.duckdb_extract_statements_error #define duckdb_destroy_extracted duckdb_ext_api.duckdb_destroy_extracted #define duckdb_pending_prepared duckdb_ext_api.duckdb_pending_prepared +#define duckdb_pending_prepared_streaming duckdb_ext_api.duckdb_pending_prepared_streaming #define duckdb_destroy_pending duckdb_ext_api.duckdb_destroy_pending #define duckdb_pending_error duckdb_ext_api.duckdb_pending_error #define duckdb_pending_execute_task duckdb_ext_api.duckdb_pending_execute_task @@ -657,22 +629,14 @@ typedef struct { #define duckdb_create_int64 duckdb_ext_api.duckdb_create_int64 #define duckdb_create_hugeint duckdb_ext_api.duckdb_create_hugeint #define duckdb_create_uhugeint duckdb_ext_api.duckdb_create_uhugeint -#define duckdb_create_varint duckdb_ext_api.duckdb_create_varint -#define duckdb_create_decimal duckdb_ext_api.duckdb_create_decimal #define duckdb_create_float duckdb_ext_api.duckdb_create_float #define duckdb_create_double duckdb_ext_api.duckdb_create_double #define duckdb_create_date duckdb_ext_api.duckdb_create_date #define duckdb_create_time duckdb_ext_api.duckdb_create_time #define duckdb_create_time_tz_value duckdb_ext_api.duckdb_create_time_tz_value #define duckdb_create_timestamp duckdb_ext_api.duckdb_create_timestamp -#define duckdb_create_timestamp_tz duckdb_ext_api.duckdb_create_timestamp_tz -#define duckdb_create_timestamp_s duckdb_ext_api.duckdb_create_timestamp_s -#define duckdb_create_timestamp_ms duckdb_ext_api.duckdb_create_timestamp_ms -#define duckdb_create_timestamp_ns duckdb_ext_api.duckdb_create_timestamp_ns #define duckdb_create_interval duckdb_ext_api.duckdb_create_interval #define duckdb_create_blob duckdb_ext_api.duckdb_create_blob -#define duckdb_create_bit duckdb_ext_api.duckdb_create_bit -#define duckdb_create_uuid duckdb_ext_api.duckdb_create_uuid #define duckdb_get_bool duckdb_ext_api.duckdb_get_bool #define duckdb_get_int8 duckdb_ext_api.duckdb_get_int8 #define duckdb_get_uint8 duckdb_ext_api.duckdb_get_uint8 @@ -684,23 +648,15 @@ typedef struct { #define duckdb_get_uint64 duckdb_ext_api.duckdb_get_uint64 #define duckdb_get_hugeint duckdb_ext_api.duckdb_get_hugeint #define duckdb_get_uhugeint duckdb_ext_api.duckdb_get_uhugeint -#define duckdb_get_varint duckdb_ext_api.duckdb_get_varint -#define duckdb_get_decimal duckdb_ext_api.duckdb_get_decimal #define duckdb_get_float duckdb_ext_api.duckdb_get_float #define duckdb_get_double duckdb_ext_api.duckdb_get_double #define duckdb_get_date duckdb_ext_api.duckdb_get_date #define duckdb_get_time duckdb_ext_api.duckdb_get_time #define duckdb_get_time_tz duckdb_ext_api.duckdb_get_time_tz #define duckdb_get_timestamp duckdb_ext_api.duckdb_get_timestamp -#define duckdb_get_timestamp_tz duckdb_ext_api.duckdb_get_timestamp_tz -#define duckdb_get_timestamp_s duckdb_ext_api.duckdb_get_timestamp_s -#define duckdb_get_timestamp_ms duckdb_ext_api.duckdb_get_timestamp_ms -#define duckdb_get_timestamp_ns duckdb_ext_api.duckdb_get_timestamp_ns #define duckdb_get_interval duckdb_ext_api.duckdb_get_interval #define duckdb_get_value_type duckdb_ext_api.duckdb_get_value_type #define duckdb_get_blob duckdb_ext_api.duckdb_get_blob -#define duckdb_get_bit duckdb_ext_api.duckdb_get_bit -#define duckdb_get_uuid duckdb_ext_api.duckdb_get_uuid #define duckdb_get_varchar duckdb_ext_api.duckdb_get_varchar #define duckdb_create_struct_value duckdb_ext_api.duckdb_create_struct_value #define duckdb_create_list_value duckdb_ext_api.duckdb_create_list_value @@ -708,13 +664,6 @@ typedef struct { #define duckdb_get_map_size duckdb_ext_api.duckdb_get_map_size #define duckdb_get_map_key duckdb_ext_api.duckdb_get_map_key #define duckdb_get_map_value duckdb_ext_api.duckdb_get_map_value -#define duckdb_is_null_value duckdb_ext_api.duckdb_is_null_value -#define duckdb_create_null_value duckdb_ext_api.duckdb_create_null_value -#define duckdb_get_list_size duckdb_ext_api.duckdb_get_list_size -#define duckdb_get_list_child duckdb_ext_api.duckdb_get_list_child -#define duckdb_create_enum_value duckdb_ext_api.duckdb_create_enum_value -#define duckdb_get_enum_value duckdb_ext_api.duckdb_get_enum_value -#define duckdb_get_struct_child duckdb_ext_api.duckdb_get_struct_child #define duckdb_create_logical_type duckdb_ext_api.duckdb_create_logical_type #define duckdb_logical_type_get_alias duckdb_ext_api.duckdb_logical_type_get_alias #define duckdb_logical_type_set_alias duckdb_ext_api.duckdb_logical_type_set_alias @@ -844,15 +793,12 @@ typedef struct { #define duckdb_profiling_info_get_child_count duckdb_ext_api.duckdb_profiling_info_get_child_count #define duckdb_profiling_info_get_child duckdb_ext_api.duckdb_profiling_info_get_child #define duckdb_appender_create duckdb_ext_api.duckdb_appender_create -#define duckdb_appender_create_ext duckdb_ext_api.duckdb_appender_create_ext #define duckdb_appender_column_count duckdb_ext_api.duckdb_appender_column_count #define duckdb_appender_column_type duckdb_ext_api.duckdb_appender_column_type #define duckdb_appender_error duckdb_ext_api.duckdb_appender_error #define duckdb_appender_flush duckdb_ext_api.duckdb_appender_flush #define duckdb_appender_close duckdb_ext_api.duckdb_appender_close #define duckdb_appender_destroy duckdb_ext_api.duckdb_appender_destroy -#define duckdb_appender_add_column duckdb_ext_api.duckdb_appender_add_column -#define duckdb_appender_clear_columns duckdb_ext_api.duckdb_appender_clear_columns #define duckdb_appender_begin_row duckdb_ext_api.duckdb_appender_begin_row #define duckdb_appender_end_row duckdb_ext_api.duckdb_appender_end_row #define duckdb_append_default duckdb_ext_api.duckdb_append_default @@ -877,14 +823,25 @@ typedef struct { #define duckdb_append_varchar_length duckdb_ext_api.duckdb_append_varchar_length #define duckdb_append_blob duckdb_ext_api.duckdb_append_blob #define duckdb_append_null duckdb_ext_api.duckdb_append_null -#define duckdb_append_value duckdb_ext_api.duckdb_append_value #define duckdb_append_data_chunk duckdb_ext_api.duckdb_append_data_chunk #define duckdb_table_description_create duckdb_ext_api.duckdb_table_description_create -#define duckdb_table_description_create_ext duckdb_ext_api.duckdb_table_description_create_ext #define duckdb_table_description_destroy duckdb_ext_api.duckdb_table_description_destroy #define duckdb_table_description_error duckdb_ext_api.duckdb_table_description_error #define duckdb_column_has_default duckdb_ext_api.duckdb_column_has_default -#define duckdb_table_description_get_column_name duckdb_ext_api.duckdb_table_description_get_column_name +#define duckdb_query_arrow duckdb_ext_api.duckdb_query_arrow +#define duckdb_query_arrow_schema duckdb_ext_api.duckdb_query_arrow_schema +#define duckdb_prepared_arrow_schema duckdb_ext_api.duckdb_prepared_arrow_schema +#define duckdb_result_arrow_array duckdb_ext_api.duckdb_result_arrow_array +#define duckdb_query_arrow_array duckdb_ext_api.duckdb_query_arrow_array +#define duckdb_arrow_column_count duckdb_ext_api.duckdb_arrow_column_count +#define duckdb_arrow_row_count duckdb_ext_api.duckdb_arrow_row_count +#define duckdb_arrow_rows_changed duckdb_ext_api.duckdb_arrow_rows_changed +#define duckdb_query_arrow_error duckdb_ext_api.duckdb_query_arrow_error +#define duckdb_destroy_arrow duckdb_ext_api.duckdb_destroy_arrow +#define duckdb_destroy_arrow_stream duckdb_ext_api.duckdb_destroy_arrow_stream +#define duckdb_execute_prepared_arrow duckdb_ext_api.duckdb_execute_prepared_arrow +#define duckdb_arrow_scan duckdb_ext_api.duckdb_arrow_scan +#define duckdb_arrow_array_scan duckdb_ext_api.duckdb_arrow_array_scan #define duckdb_execute_tasks duckdb_ext_api.duckdb_execute_tasks #define duckdb_create_task_state duckdb_ext_api.duckdb_create_task_state #define duckdb_execute_tasks_state duckdb_ext_api.duckdb_execute_tasks_state @@ -893,6 +850,7 @@ typedef struct { #define duckdb_task_state_is_finished duckdb_ext_api.duckdb_task_state_is_finished #define duckdb_destroy_task_state duckdb_ext_api.duckdb_destroy_task_state #define duckdb_execution_is_finished duckdb_ext_api.duckdb_execution_is_finished +#define duckdb_stream_fetch_chunk duckdb_ext_api.duckdb_stream_fetch_chunk #define duckdb_fetch_chunk duckdb_ext_api.duckdb_fetch_chunk #define duckdb_create_cast_function duckdb_ext_api.duckdb_create_cast_function #define duckdb_cast_function_set_source_type duckdb_ext_api.duckdb_cast_function_set_source_type @@ -907,84 +865,21 @@ typedef struct { #define duckdb_register_cast_function duckdb_ext_api.duckdb_register_cast_function #define duckdb_destroy_cast_function duckdb_ext_api.duckdb_destroy_cast_function -// Version unstable_deprecated -#define duckdb_row_count duckdb_ext_api.duckdb_row_count -#define duckdb_column_data duckdb_ext_api.duckdb_column_data -#define duckdb_nullmask_data duckdb_ext_api.duckdb_nullmask_data -#define duckdb_result_get_chunk duckdb_ext_api.duckdb_result_get_chunk -#define duckdb_result_is_streaming duckdb_ext_api.duckdb_result_is_streaming -#define duckdb_result_chunk_count duckdb_ext_api.duckdb_result_chunk_count -#define duckdb_value_boolean duckdb_ext_api.duckdb_value_boolean -#define duckdb_value_int8 duckdb_ext_api.duckdb_value_int8 -#define duckdb_value_int16 duckdb_ext_api.duckdb_value_int16 -#define duckdb_value_int32 duckdb_ext_api.duckdb_value_int32 -#define duckdb_value_int64 duckdb_ext_api.duckdb_value_int64 -#define duckdb_value_hugeint duckdb_ext_api.duckdb_value_hugeint -#define duckdb_value_uhugeint duckdb_ext_api.duckdb_value_uhugeint -#define duckdb_value_decimal duckdb_ext_api.duckdb_value_decimal -#define duckdb_value_uint8 duckdb_ext_api.duckdb_value_uint8 -#define duckdb_value_uint16 duckdb_ext_api.duckdb_value_uint16 -#define duckdb_value_uint32 duckdb_ext_api.duckdb_value_uint32 -#define duckdb_value_uint64 duckdb_ext_api.duckdb_value_uint64 -#define duckdb_value_float duckdb_ext_api.duckdb_value_float -#define duckdb_value_double duckdb_ext_api.duckdb_value_double -#define duckdb_value_date duckdb_ext_api.duckdb_value_date -#define duckdb_value_time duckdb_ext_api.duckdb_value_time -#define duckdb_value_timestamp duckdb_ext_api.duckdb_value_timestamp -#define duckdb_value_interval duckdb_ext_api.duckdb_value_interval -#define duckdb_value_varchar duckdb_ext_api.duckdb_value_varchar -#define duckdb_value_string duckdb_ext_api.duckdb_value_string -#define duckdb_value_varchar_internal duckdb_ext_api.duckdb_value_varchar_internal -#define duckdb_value_string_internal duckdb_ext_api.duckdb_value_string_internal -#define duckdb_value_blob duckdb_ext_api.duckdb_value_blob -#define duckdb_value_is_null duckdb_ext_api.duckdb_value_is_null -#define duckdb_execute_prepared_streaming duckdb_ext_api.duckdb_execute_prepared_streaming -#define duckdb_pending_prepared_streaming duckdb_ext_api.duckdb_pending_prepared_streaming -#define duckdb_query_arrow duckdb_ext_api.duckdb_query_arrow -#define duckdb_query_arrow_schema duckdb_ext_api.duckdb_query_arrow_schema -#define duckdb_prepared_arrow_schema duckdb_ext_api.duckdb_prepared_arrow_schema -#define duckdb_result_arrow_array duckdb_ext_api.duckdb_result_arrow_array -#define duckdb_query_arrow_array duckdb_ext_api.duckdb_query_arrow_array -#define duckdb_arrow_column_count duckdb_ext_api.duckdb_arrow_column_count -#define duckdb_arrow_row_count duckdb_ext_api.duckdb_arrow_row_count -#define duckdb_arrow_rows_changed duckdb_ext_api.duckdb_arrow_rows_changed -#define duckdb_query_arrow_error duckdb_ext_api.duckdb_query_arrow_error -#define duckdb_destroy_arrow duckdb_ext_api.duckdb_destroy_arrow -#define duckdb_destroy_arrow_stream duckdb_ext_api.duckdb_destroy_arrow_stream -#define duckdb_execute_prepared_arrow duckdb_ext_api.duckdb_execute_prepared_arrow -#define duckdb_arrow_scan duckdb_ext_api.duckdb_arrow_scan -#define duckdb_arrow_array_scan duckdb_ext_api.duckdb_arrow_array_scan -#define duckdb_stream_fetch_chunk duckdb_ext_api.duckdb_stream_fetch_chunk - -// Version unstable_instance_cache -#define duckdb_create_instance_cache duckdb_ext_api.duckdb_create_instance_cache -#define duckdb_get_or_create_from_cache duckdb_ext_api.duckdb_get_or_create_from_cache -#define duckdb_destroy_instance_cache duckdb_ext_api.duckdb_destroy_instance_cache - -// Version unstable_new_append_functions -#define duckdb_append_default_to_chunk duckdb_ext_api.duckdb_append_default_to_chunk - //===--------------------------------------------------------------------===// // Struct Global Macros //===--------------------------------------------------------------------===// // This goes in the c/c++ file containing the entrypoint (handle -#define DUCKDB_EXTENSION_GLOBAL duckdb_ext_api_v1 duckdb_ext_api = {0}; +#define DUCKDB_EXTENSION_GLOBAL duckdb_ext_api_v0 duckdb_ext_api = {0}; // Initializes the C Extension API: First thing to call in the extension entrypoint #define DUCKDB_EXTENSION_API_INIT(info, access, minimum_api_version) \ - duckdb_ext_api_v1 *res = (duckdb_ext_api_v1 *)access->get_api(info, minimum_api_version); \ + duckdb_ext_api_v0 *res = (duckdb_ext_api_v0 *)access->get_api(info, minimum_api_version); \ if (!res) { \ - return false; \ + return; \ }; \ duckdb_ext_api = *res; // Place in global scope of any C/C++ file that needs to access the extension API -#define DUCKDB_EXTENSION_EXTERN extern duckdb_ext_api_v1 duckdb_ext_api; - -#ifdef _WIN32 -#define DUCKDB_CAPI_ENTRY_VISIBILITY __declspec(dllexport) -#else -#define DUCKDB_CAPI_ENTRY_VISIBILITY __attribute__((visibility("default"))) -#endif +#define DUCKDB_EXTENSION_EXTERN extern duckdb_ext_api_v0 duckdb_ext_api; //===--------------------------------------------------------------------===// // Entrypoint Macros @@ -997,31 +892,30 @@ typedef struct { // Main entrypoint: opens (and closes) a connection automatically for the extension to register its functionality // through #define DUCKDB_EXTENSION_ENTRYPOINT \ - DUCKDB_EXTENSION_GLOBAL static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ - duckdb_connection connection, duckdb_extension_info info, struct duckdb_extension_access * access); \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_CAPI_ENTRY_VISIBILITY DUCKDB_EXTENSION_API bool DUCKDB_EXTENSION_GLUE( \ - DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, struct duckdb_extension_access * access) { \ + DUCKDB_EXTENSION_GLOBAL static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ + duckdb_connection connection, duckdb_extension_info info, duckdb_extension_access * access); \ + DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API void DUCKDB_EXTENSION_GLUE( \ + DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, duckdb_extension_access * access) { \ DUCKDB_EXTENSION_API_INIT(info, access, DUCKDB_EXTENSION_API_VERSION_STRING); \ duckdb_database *db = access->get_database(info); \ duckdb_connection conn; \ if (duckdb_connect(*db, &conn) == DuckDBError) { \ access->set_error(info, "Failed to open connection to database"); \ - return false; \ + return; \ } \ - bool init_result = DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(conn, info, access); \ + DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(conn, info, access); \ duckdb_disconnect(&conn); \ - return init_result; \ } \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) + DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) // Custom entrypoint: just forwards the info and access #define DUCKDB_EXTENSION_ENTRYPOINT_CUSTOM \ - DUCKDB_EXTENSION_GLOBAL static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ - duckdb_extension_info info, struct duckdb_extension_access * access); \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_CAPI_ENTRY_VISIBILITY DUCKDB_EXTENSION_API bool DUCKDB_EXTENSION_GLUE( \ - DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, struct duckdb_extension_access * access) { \ + DUCKDB_EXTENSION_GLOBAL static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)( \ + duckdb_extension_info info, duckdb_extension_access * access); \ + DUCKDB_EXTENSION_EXTERN_C_GUARD_OPEN DUCKDB_EXTENSION_API void DUCKDB_EXTENSION_GLUE( \ + DUCKDB_EXTENSION_NAME, _init_c_api)(duckdb_extension_info info, duckdb_extension_access * access) { \ DUCKDB_EXTENSION_API_INIT(info, access, DUCKDB_EXTENSION_API_VERSION_STRING); \ - return DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(info, access); \ + DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal)(info, access); \ } \ - DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static bool DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) + DUCKDB_EXTENSION_EXTERN_C_GUARD_CLOSE static void DUCKDB_EXTENSION_GLUE(DUCKDB_EXTENSION_NAME, _init_c_api_internal) #endif diff --git a/src/duckdb/src/main/appender.cpp b/src/duckdb/src/main/appender.cpp index 11a5753a6..33ef17bf4 100644 --- a/src/duckdb/src/main/appender.cpp +++ b/src/duckdb/src/main/appender.cpp @@ -18,12 +18,12 @@ namespace duckdb { -BaseAppender::BaseAppender(Allocator &allocator, const AppenderType type_p) +BaseAppender::BaseAppender(Allocator &allocator, AppenderType type_p) : allocator(allocator), column(0), appender_type(type_p) { } -BaseAppender::BaseAppender(Allocator &allocator_p, vector types_p, const AppenderType type_p, - const idx_t flush_count_p) +BaseAppender::BaseAppender(Allocator &allocator_p, vector types_p, AppenderType type_p, + idx_t flush_count_p) : allocator(allocator_p), types(std::move(types_p)), collection(make_uniq(allocator, types)), column(0), appender_type(type_p), flush_count(flush_count_p) { InitializeChunk(); @@ -36,22 +36,15 @@ void BaseAppender::Destructor() { if (Exception::UncaughtException()) { return; } - // Flush any remaining chunks, if we are not cleaning up as part of an exception stack unwind wrapped in a - // try/catch. Close() can throw if the table was dropped in the meantime. + // flush any remaining chunks, but only if we are not cleaning up the appender as part of an exception stack unwind + // wrapped in a try/catch because Close() can throw if the table was dropped in the meantime try { Close(); } catch (...) { // NOLINT } } -const vector &BaseAppender::GetActiveTypes() const { - if (active_types.empty()) { - return types; - } - return active_types; -} - -InternalAppender::InternalAppender(ClientContext &context_p, TableCatalogEntry &table_p, const idx_t flush_count_p) +InternalAppender::InternalAppender(ClientContext &context_p, TableCatalogEntry &table_p, idx_t flush_count_p) : BaseAppender(Allocator::DefaultAllocator(), table_p.GetTypes(), AppenderType::PHYSICAL, flush_count_p), context(context_p), table(table_p) { } @@ -60,17 +53,13 @@ InternalAppender::~InternalAppender() { Destructor(); } -Appender::Appender(Connection &con, const string &database_name, const string &schema_name, const string &table_name) +Appender::Appender(Connection &con, const string &schema_name, const string &table_name) : BaseAppender(Allocator::DefaultAllocator(), AppenderType::LOGICAL), context(con.context) { - - description = con.TableInfo(database_name, schema_name, table_name); + description = con.TableInfo(schema_name, table_name); if (!description) { + // table could not be found throw CatalogException(StringUtil::Format("Table \"%s.%s\" could not be found", schema_name, table_name)); } - if (description->readonly) { - throw InvalidInputException("Cannot append to a readonly database."); - } - vector> defaults; for (auto &column : description->columns) { if (column.Generated()) { @@ -79,50 +68,39 @@ Appender::Appender(Connection &con, const string &database_name, const string &s types.push_back(column.Type()); defaults.push_back(column.HasDefaultValue() ? &column.DefaultValue() : nullptr); } - auto binder = Binder::CreateBinder(*context); + context->RunFunctionInTransaction([&]() { for (idx_t i = 0; i < types.size(); i++) { auto &type = types[i]; auto &expr = defaults[i]; if (!expr) { - // The default value is NULL. + // Insert NULL default_values[i] = Value(type); continue; } - auto default_copy = expr->Copy(); D_ASSERT(!default_copy->HasParameter()); - ConstantBinder default_binder(*binder, *context, "DEFAULT value"); default_binder.target_type = type; auto bound_default = default_binder.Bind(default_copy); - - if (!bound_default->IsFoldable()) { - // Not supported yet. - continue; - } - Value result_value; - auto eval_success = ExpressionExecutor::TryEvaluateScalar(*context, *bound_default, result_value); - // Insert the default Value. - if (eval_success) { + if (bound_default->IsFoldable() && + ExpressionExecutor::TryEvaluateScalar(*context, *bound_default, result_value)) { + // Insert the evaluated Value default_values[i] = result_value; + } else { + // These are not supported currently, we don't add them to the 'default_values' map } } }); InitializeChunk(); - collection = make_uniq(allocator, GetActiveTypes()); + collection = make_uniq(allocator, types); } -Appender::Appender(Connection &con, const string &schema_name, const string &table_name) - : Appender(con, INVALID_CATALOG, schema_name, table_name) { -} - -Appender::Appender(Connection &con, const string &table_name) - : Appender(con, INVALID_CATALOG, DEFAULT_SCHEMA, table_name) { +Appender::Appender(Connection &con, const string &table_name) : Appender(con, DEFAULT_SCHEMA, table_name) { } Appender::~Appender() { @@ -130,15 +108,14 @@ Appender::~Appender() { } void BaseAppender::InitializeChunk() { - chunk.Destroy(); - chunk.Initialize(allocator, GetActiveTypes()); + chunk.Initialize(allocator, types); } void BaseAppender::BeginRow() { } void BaseAppender::EndRow() { - // Ensure that all columns have been appended to. + // check that all rows have been appended to if (column != chunk.ColumnCount()) { throw InvalidInputException("Call to EndRow before all columns have been appended to!"); } @@ -163,8 +140,8 @@ void BaseAppender::AppendDecimalValueInternal(Vector &col, SRC input) { auto width = DecimalType::GetWidth(type); auto scale = DecimalType::GetScale(type); CastParameters parameters; - auto &result = FlatVector::GetData(col)[chunk.size()]; - TryCastToDecimal::Operation(input, result, parameters, width, scale); + TryCastToDecimal::Operation(input, FlatVector::GetData(col)[chunk.size()], parameters, width, + scale); return; } case AppenderType::PHYSICAL: { @@ -178,7 +155,7 @@ void BaseAppender::AppendDecimalValueInternal(Vector &col, SRC input) { template void BaseAppender::AppendValueInternal(T input) { - if (column >= GetActiveTypes().size()) { + if (column >= types.size()) { throw InvalidInputException("Too many appends for chunk!"); } auto &col = chunk.data[column]; @@ -366,35 +343,13 @@ void BaseAppender::Append(interval_t value) { } template <> -void BaseAppender::Append(Value value) { // NOLINT: template stuff +void BaseAppender::Append(Value value) { // NOLINT: template shtuff if (column >= chunk.ColumnCount()) { throw InvalidInputException("Too many appends for chunk!"); } AppendValue(value); } -void duckdb::BaseAppender::Append(DataChunk &target, const Value &value, idx_t col, idx_t row) { - if (col >= target.ColumnCount()) { - throw InvalidInputException("Too many appends for chunk!"); - } - if (row >= target.GetCapacity()) { - throw InvalidInputException("Too many rows for chunk!"); - } - - if (value.type() == target.GetTypes()[col]) { - target.SetValue(col, row, value); - } else { - Value new_value; - string error_msg; - if (value.DefaultTryCastAs(target.GetTypes()[col], new_value, &error_msg)) { - target.SetValue(col, row, new_value); - } else { - throw InvalidInputException("type mismatch in Append, expected %s, got %s for column %d", - target.GetTypes()[col], value.type(), col); - } - } -} - template <> void BaseAppender::Append(std::nullptr_t value) { if (column >= chunk.ColumnCount()) { @@ -409,46 +364,18 @@ void BaseAppender::AppendValue(const Value &value) { column++; } -void BaseAppender::AppendDataChunk(DataChunk &chunk_p) { - auto chunk_types = chunk_p.GetTypes(); - auto &appender_types = GetActiveTypes(); - - // Early-out, if types match. - if (chunk_types == appender_types) { - collection->Append(chunk_p); - if (collection->Count() >= flush_count) { - Flush(); - } - return; - } - - auto count = chunk_p.ColumnCount(); - if (count != appender_types.size()) { - throw InvalidInputException("incorrect column count in AppendDataChunk, expected %d, got %d", - appender_types.size(), count); - } - - // We try to cast the chunk. - auto size = chunk_p.size(); - DataChunk cast_chunk; - cast_chunk.Initialize(allocator, appender_types); - cast_chunk.SetCardinality(size); - - for (idx_t i = 0; i < count; i++) { - if (chunk_p.data[i].GetType() == appender_types[i]) { - cast_chunk.data[i].Reference(chunk_p.data[i]); - continue; - } - - string error_msg; - auto success = VectorOperations::DefaultTryCast(chunk_p.data[i], cast_chunk.data[i], size, &error_msg); - if (!success) { - throw InvalidInputException("type mismatch in AppendDataChunk, expected %s, got %s for column %d", - appender_types[i].ToString(), chunk_p.data[i].GetType().ToString(), i); +void BaseAppender::AppendDataChunk(DataChunk &chunk) { + auto chunk_types = chunk.GetTypes(); + if (chunk_types != types) { + for (idx_t i = 0; i < chunk.ColumnCount(); i++) { + if (chunk.data[i].GetType() != types[i]) { + throw InvalidInputException("Type mismatch in Append DataChunk and the types required for appender, " + "expected %s but got %s for column %d", + types[i].ToString(), chunk.data[i].GetType().ToString(), i + 1); + } } } - - collection->Append(cast_chunk); + collection->Append(chunk); if (collection->Count() >= flush_count) { Flush(); } @@ -466,7 +393,7 @@ void BaseAppender::FlushChunk() { } void BaseAppender::Flush() { - // Check that all vectors have the same length before appending. + // check that all vectors have the same length before appending if (column != 0) { throw InvalidInputException("Failed to Flush appender: incomplete append to row!"); } @@ -475,105 +402,36 @@ void BaseAppender::Flush() { if (collection->Count() == 0) { return; } - FlushInternal(*collection); + collection->Reset(); column = 0; } void Appender::FlushInternal(ColumnDataCollection &collection) { - context->Append(*description, collection, &column_ids); + context->Append(*description, collection); } void Appender::AppendDefault() { - auto value = GetDefaultValue(column); - Append(value); -} - -void duckdb::Appender::AppendDefault(DataChunk &chunk, idx_t col, idx_t row) { - auto value = GetDefaultValue(col); - Append(chunk, value, col, row); -} - -Value Appender::GetDefaultValue(idx_t column) { - auto index = column; - - if (!column_ids.empty()) { - if (column >= column_ids.size()) { - throw InvalidInputException("Column index out of bounds"); - } - index = column_ids[column].index; - } - - auto it = default_values.find(index); + auto it = default_values.find(column); + auto &column_def = description->columns[column]; if (it == default_values.end()) { - auto &name = description->columns[index].Name(); throw NotImplementedException( - "AppendDefault is not supported for column \"%s\": not a foldable default expressions.", name); + "AppendDefault is currently not supported for column \"%s\" because default expression is not foldable.", + column_def.Name()); } - return it->second; -} - -void Appender::AddColumn(const string &name) { - Flush(); - - auto exists = false; - for (idx_t col_idx = 0; col_idx < description->columns.size(); col_idx++) { - auto &col_def = description->columns[col_idx]; - if (col_def.Name() != name) { - continue; - } - - // Ensure that we are not adding a generated column. - if (col_def.Generated()) { - throw InvalidInputException("cannot add a generated column to the appender"); - } - - // Ensure that we haven't added this column before. - for (const auto &column_id : column_ids) { - if (column_id == col_def.Logical()) { - throw InvalidInputException("cannot add the same column twice"); - } - } - - active_types.push_back(col_def.Type()); - column_ids.push_back(col_def.Logical()); - exists = true; - break; - } - if (!exists) { - throw InvalidInputException("the column must exist in the table"); - } - - InitializeChunk(); - collection = make_uniq(allocator, GetActiveTypes()); -} - -void Appender::ClearColumns() { - Flush(); - column_ids.clear(); - active_types.clear(); - - InitializeChunk(); - collection = make_uniq(allocator, GetActiveTypes()); + auto &default_value = it->second; + Append(default_value); } void InternalAppender::FlushInternal(ColumnDataCollection &collection) { auto binder = Binder::CreateBinder(context); auto bound_constraints = binder->BindConstraints(table); - table.GetStorage().LocalAppend(table, context, collection, bound_constraints, nullptr); -} - -void InternalAppender::AddColumn(const string &name) { - throw InternalException("AddColumn not implemented for InternalAppender"); -} - -void InternalAppender::ClearColumns() { - throw InternalException("ClearColumns not implemented for InternalAppender"); + table.GetStorage().LocalAppend(table, context, collection, bound_constraints); } void BaseAppender::Close() { - if (column == 0 || column == GetActiveTypes().size()) { + if (column == 0 || column == types.size()) { Flush(); } } diff --git a/src/duckdb/src/main/attached_database.cpp b/src/duckdb/src/main/attached_database.cpp index 51546d6c3..5a435b1dd 100644 --- a/src/duckdb/src/main/attached_database.cpp +++ b/src/duckdb/src/main/attached_database.cpp @@ -25,6 +25,7 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod : access_mode(default_access_mode) { for (auto &entry : info->options) { + if (entry.first == "readonly" || entry.first == "read_only") { // Extract the read access mode. @@ -39,6 +40,7 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod if (entry.first == "readwrite" || entry.first == "read_write") { // Extract the write access mode. + auto read_write = BooleanValue::Get(entry.second.DefaultCastAs(LogicalType::BOOLEAN)); if (!read_write) { access_mode = AccessMode::READ_ONLY; @@ -54,12 +56,11 @@ AttachOptions::AttachOptions(const unique_ptr &info, const AccessMod continue; } - if (entry.first == "default_table") { - default_table = QualifiedName::Parse(StringValue::Get(entry.second.DefaultCastAs(LogicalType::VARCHAR))); - continue; + // We allow unrecognized options in storage extensions. To track that we saw an unrecognized option, + // we set unrecognized_option. + if (unrecognized_option.empty()) { + unrecognized_option = entry.first; } - - options[entry.first] = entry.second; } } @@ -92,15 +93,6 @@ AttachedDatabase::AttachedDatabase(DatabaseInstance &db, Catalog &catalog_p, str } else { type = AttachedDatabaseType::READ_WRITE_DATABASE; } - for (auto &entry : options.options) { - if (StringUtil::CIEquals(entry.first, "block_size")) { - continue; - } - if (StringUtil::CIEquals(entry.first, "row_group_size")) { - continue; - } - throw BinderException("Unrecognized option for attach \"%s\"", entry.first); - } // We create the storage after the catalog to guarantee we allow extensions to instantiate the DuckCatalog. catalog = make_uniq(*this); @@ -171,14 +163,14 @@ string AttachedDatabase::ExtractDatabaseName(const string &dbpath, FileSystem &f return name; } -void AttachedDatabase::Initialize(StorageOptions options) { +void AttachedDatabase::Initialize(const optional_idx block_alloc_size) { if (IsSystem()) { catalog->Initialize(true); } else { catalog->Initialize(false); } if (storage) { - storage->Initialize(options); + storage->Initialize(block_alloc_size); } } diff --git a/src/duckdb/src/main/capi/appender-c.cpp b/src/duckdb/src/main/capi/appender-c.cpp index cab3291f2..eed34fb97 100644 --- a/src/duckdb/src/main/capi/appender-c.cpp +++ b/src/duckdb/src/main/capi/appender-c.cpp @@ -15,27 +15,18 @@ using duckdb::uhugeint_t; duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender) { - return duckdb_appender_create_ext(connection, INVALID_CATALOG, schema, table, out_appender); -} - -duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, const char *schema, - const char *table, duckdb_appender *out_appender) { Connection *conn = reinterpret_cast(connection); if (!connection || !table || !out_appender) { return DuckDBError; } - if (catalog == nullptr) { - catalog = INVALID_CATALOG; - } if (schema == nullptr) { schema = DEFAULT_SCHEMA; } - auto wrapper = new AppenderWrapper(); *out_appender = (duckdb_appender)wrapper; try { - wrapper->appender = duckdb::make_uniq(*conn, catalog, schema, table); + wrapper->appender = duckdb::make_uniq(*conn, schema, table); } catch (std::exception &ex) { ErrorData error(ex); wrapper->error = error.RawMessage(); @@ -82,14 +73,6 @@ duckdb_state duckdb_appender_run_function(duckdb_appender appender, FUN &&functi return DuckDBSuccess; } -duckdb_state duckdb_appender_add_column(duckdb_appender appender, const char *name) { - return duckdb_appender_run_function(appender, [&](Appender &appender) { appender.AddColumn(name); }); -} - -duckdb_state duckdb_appender_clear_columns(duckdb_appender appender) { - return duckdb_appender_run_function(appender, [&](Appender &appender) { appender.ClearColumns(); }); -} - const char *duckdb_appender_error(duckdb_appender appender) { if (!appender) { return nullptr; @@ -145,27 +128,6 @@ duckdb_state duckdb_append_default(duckdb_appender appender) { return DuckDBSuccess; } -duckdb_state duckdb_append_default_to_chunk(duckdb_appender appender, duckdb_data_chunk chunk, idx_t col, idx_t row) { - if (!appender || !chunk) { - return DuckDBError; - } - - auto *appender_instance = reinterpret_cast(appender); - - auto data_chunk = reinterpret_cast(chunk); - - try { - appender_instance->appender->AppendDefault(*data_chunk, col, row); - } catch (std::exception &ex) { - ErrorData error(ex); - appender_instance->error = error.RawMessage(); - return DuckDBError; - } catch (...) { - return DuckDBError; - } - return DuckDBSuccess; -} - duckdb_state duckdb_append_bool(duckdb_appender appender, bool value) { return duckdb_append_internal(appender, value); } @@ -279,7 +241,7 @@ idx_t duckdb_appender_column_count(duckdb_appender appender) { return 0; } - return wrapper->appender->GetActiveTypes().size(); + return wrapper->appender->GetTypes().size(); } duckdb_logical_type duckdb_appender_column_type(duckdb_appender appender, idx_t col_idx) { @@ -292,18 +254,13 @@ duckdb_logical_type duckdb_appender_column_type(duckdb_appender appender, idx_t return nullptr; } - auto &logical_type = wrapper->appender->GetActiveTypes()[col_idx]; - return reinterpret_cast(new duckdb::LogicalType(logical_type)); -} - -duckdb_state duckdb_append_value(duckdb_appender appender, duckdb_value value) { - return duckdb_append_internal(appender, *(reinterpret_cast(value))); + return reinterpret_cast(new duckdb::LogicalType(wrapper->appender->GetTypes()[col_idx])); } duckdb_state duckdb_append_data_chunk(duckdb_appender appender, duckdb_data_chunk chunk) { if (!chunk) { return DuckDBError; } - auto data_chunk = reinterpret_cast(chunk); + auto data_chunk = (duckdb::DataChunk *)chunk; return duckdb_appender_run_function(appender, [&](Appender &appender) { appender.AppendDataChunk(*data_chunk); }); } diff --git a/src/duckdb/src/main/capi/config-c.cpp b/src/duckdb/src/main/capi/config-c.cpp index 68605056d..daa4bcb0a 100644 --- a/src/duckdb/src/main/capi/config-c.cpp +++ b/src/duckdb/src/main/capi/config-c.cpp @@ -1,7 +1,6 @@ #include "duckdb/main/capi/capi_internal.hpp" #include "duckdb/main/config.hpp" #include "duckdb/common/types/value.hpp" -#include "duckdb/main/extension_helper.hpp" using duckdb::DBConfig; using duckdb::Value; @@ -23,31 +22,19 @@ duckdb_state duckdb_create_config(duckdb_config *out_config) { } size_t duckdb_config_count() { - return DBConfig::GetOptionCount() + duckdb::ExtensionHelper::ArraySize(duckdb::EXTENSION_SETTINGS); + return DBConfig::GetOptionCount(); } duckdb_state duckdb_get_config_flag(size_t index, const char **out_name, const char **out_description) { auto option = DBConfig::GetOptionByIndex(index); - if (option) { - if (out_name) { - *out_name = option->name; - } - if (out_description) { - *out_description = option->description; - } - return DuckDBSuccess; - } - - // extension index? - auto entry = duckdb::ExtensionHelper::GetArrayEntry(duckdb::EXTENSION_SETTINGS, index - DBConfig::GetOptionCount()); - if (!entry) { + if (!option) { return DuckDBError; } if (out_name) { - *out_name = entry->name; + *out_name = option->name; } if (out_description) { - *out_description = entry->extension; + *out_description = option->description; } return DuckDBSuccess; } diff --git a/src/duckdb/src/main/capi/datetime-c.cpp b/src/duckdb/src/main/capi/datetime-c.cpp index 9e19128a8..de92c8dad 100644 --- a/src/duckdb/src/main/capi/datetime-c.cpp +++ b/src/duckdb/src/main/capi/datetime-c.cpp @@ -10,9 +10,6 @@ using duckdb::Timestamp; using duckdb::date_t; using duckdb::dtime_t; -using duckdb::timestamp_ms_t; -using duckdb::timestamp_ns_t; -using duckdb::timestamp_sec_t; using duckdb::timestamp_t; duckdb_date_struct duckdb_from_date(duckdb_date date) { @@ -102,15 +99,3 @@ duckdb_timestamp duckdb_to_timestamp(duckdb_timestamp_struct ts) { bool duckdb_is_finite_timestamp(duckdb_timestamp ts) { return Timestamp::IsFinite(timestamp_t(ts.micros)); } - -bool duckdb_is_finite_timestamp_s(duckdb_timestamp_s ts) { - return Timestamp::IsFinite(timestamp_sec_t(ts.seconds)); -} - -bool duckdb_is_finite_timestamp_ms(duckdb_timestamp_ms ts) { - return Timestamp::IsFinite(timestamp_ms_t(ts.millis)); -} - -bool duckdb_is_finite_timestamp_ns(duckdb_timestamp_ns ts) { - return Timestamp::IsFinite(timestamp_ns_t(ts.nanos)); -} diff --git a/src/duckdb/src/main/capi/duckdb-c.cpp b/src/duckdb/src/main/capi/duckdb-c.cpp index ad47d7448..ac944578c 100644 --- a/src/duckdb/src/main/capi/duckdb-c.cpp +++ b/src/duckdb/src/main/capi/duckdb-c.cpp @@ -1,88 +1,49 @@ #include "duckdb/main/capi/capi_internal.hpp" using duckdb::Connection; -using duckdb::DatabaseWrapper; +using duckdb::DatabaseData; using duckdb::DBConfig; -using duckdb::DBInstanceCacheWrapper; using duckdb::DuckDB; using duckdb::ErrorData; -duckdb_instance_cache duckdb_create_instance_cache() { - auto wrapper = new DBInstanceCacheWrapper(); - wrapper->instance_cache = duckdb::make_uniq(); - return reinterpret_cast(wrapper); -} - -void duckdb_destroy_instance_cache(duckdb_instance_cache *instance_cache) { - if (instance_cache && *instance_cache) { - auto wrapper = reinterpret_cast(*instance_cache); - delete wrapper; - *instance_cache = nullptr; - } -} - -duckdb_state duckdb_open_internal(DBInstanceCacheWrapper *cache, const char *path, duckdb_database *out, - duckdb_config config, char **out_error) { - auto wrapper = new DatabaseWrapper(); +duckdb_state duckdb_open_ext(const char *path, duckdb_database *out, duckdb_config config, char **error) { + auto wrapper = new DatabaseData(); try { DBConfig default_config; default_config.SetOptionByName("duckdb_api", "capi"); DBConfig *db_config = &default_config; - DBConfig *user_config = reinterpret_cast(config); + DBConfig *user_config = (DBConfig *)config; if (user_config) { db_config = user_config; } - if (cache) { - wrapper->database = cache->instance_cache->GetOrCreateInstance(path, *db_config, true); - } else { - wrapper->database = duckdb::make_shared_ptr(path, db_config); - } - + wrapper->database = duckdb::make_uniq(path, db_config); } catch (std::exception &ex) { - if (out_error) { + if (error) { ErrorData parsed_error(ex); - *out_error = strdup(parsed_error.Message().c_str()); + *error = strdup(parsed_error.Message().c_str()); } delete wrapper; return DuckDBError; - } catch (...) { // LCOV_EXCL_START - if (out_error) { - *out_error = strdup("Unknown error"); + if (error) { + *error = strdup("Unknown error"); } delete wrapper; return DuckDBError; } // LCOV_EXCL_STOP - - *out = reinterpret_cast(wrapper); + *out = (duckdb_database)wrapper; return DuckDBSuccess; } -duckdb_state duckdb_get_or_create_from_cache(duckdb_instance_cache instance_cache, const char *path, - duckdb_database *out_database, duckdb_config config, char **out_error) { - if (!instance_cache) { - if (out_error) { - *out_error = strdup("instance cache cannot be nullptr"); - } - return DuckDBError; - } - auto cache = reinterpret_cast(instance_cache); - return duckdb_open_internal(cache, path, out_database, config, out_error); -} - -duckdb_state duckdb_open_ext(const char *path, duckdb_database *out, duckdb_config config, char **error) { - return duckdb_open_internal(nullptr, path, out, config, error); -} - duckdb_state duckdb_open(const char *path, duckdb_database *out) { return duckdb_open_ext(path, out, nullptr, nullptr); } void duckdb_close(duckdb_database *database) { if (database && *database) { - auto wrapper = reinterpret_cast(*database); + auto wrapper = reinterpret_cast(*database); delete wrapper; *database = nullptr; } @@ -92,16 +53,14 @@ duckdb_state duckdb_connect(duckdb_database database, duckdb_connection *out) { if (!database || !out) { return DuckDBError; } - - auto wrapper = reinterpret_cast(database); + auto wrapper = reinterpret_cast(database); Connection *connection; try { connection = new Connection(*wrapper->database); } catch (...) { // LCOV_EXCL_START return DuckDBError; } // LCOV_EXCL_STOP - - *out = reinterpret_cast(connection); + *out = (duckdb_connection)connection; return DuckDBSuccess; } diff --git a/src/duckdb/src/main/capi/duckdb_value-c.cpp b/src/duckdb/src/main/capi/duckdb_value-c.cpp index 7f75691bc..defdf6a3b 100644 --- a/src/duckdb/src/main/capi/duckdb_value-c.cpp +++ b/src/duckdb/src/main/capi/duckdb_value-c.cpp @@ -1,11 +1,7 @@ -#include "duckdb/common/hugeint.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types.hpp" #include "duckdb/common/types/null_value.hpp" -#include "duckdb/common/types/string_type.hpp" -#include "duckdb/common/types/uuid.hpp" #include "duckdb/common/types/value.hpp" -#include "duckdb/common/types/varint.hpp" #include "duckdb/main/capi/capi_internal.hpp" using duckdb::LogicalTypeId; @@ -119,43 +115,6 @@ duckdb_uhugeint duckdb_get_uhugeint(duckdb_value val) { auto res = CAPIGetValue(val); return {res.lower, res.upper}; } -duckdb_value duckdb_create_varint(duckdb_varint input) { - return WrapValue(new duckdb::Value( - duckdb::Value::VARINT(duckdb::Varint::FromByteArray(input.data, input.size, input.is_negative)))); -} -duckdb_varint duckdb_get_varint(duckdb_value val) { - auto v = UnwrapValue(val).DefaultCastAs(duckdb::LogicalType::VARINT); - auto &str = duckdb::StringValue::Get(v); - duckdb::vector byte_array; - bool is_negative; - duckdb::Varint::GetByteArray(byte_array, is_negative, duckdb::string_t(str)); - auto size = byte_array.size(); - auto data = reinterpret_cast(malloc(size)); - memcpy(data, byte_array.data(), size); - return {data, size, is_negative}; -} -duckdb_value duckdb_create_decimal(duckdb_decimal input) { - duckdb::hugeint_t hugeint(input.value.upper, input.value.lower); - int64_t int64; - if (duckdb::Hugeint::TryCast(hugeint, int64)) { - // The int64 DECIMAL value constructor will select the appropriate physical type based on width. - return WrapValue(new duckdb::Value(duckdb::Value::DECIMAL(int64, input.width, input.scale))); - } else { - // The hugeint DECIMAL value constructor always uses a physical hugeint, and requires width >= MAX_WIDTH_INT64. - return WrapValue(new duckdb::Value(duckdb::Value::DECIMAL(hugeint, input.width, input.scale))); - } -} -duckdb_decimal duckdb_get_decimal(duckdb_value val) { - auto &v = UnwrapValue(val); - auto &type = v.type(); - if (type.id() != LogicalTypeId::DECIMAL) { - return {0, 0, {0, 0}}; - } - auto width = duckdb::DecimalType::GetWidth(type); - auto scale = duckdb::DecimalType::GetScale(type); - duckdb::hugeint_t hugeint = duckdb::IntegralValue::Get(v); - return {width, scale, {hugeint.lower, hugeint.upper}}; -} duckdb_value duckdb_create_float(float input) { return CAPICreateValue(input); } @@ -186,67 +145,12 @@ duckdb_value duckdb_create_time_tz_value(duckdb_time_tz input) { duckdb_time_tz duckdb_get_time_tz(duckdb_value val) { return {CAPIGetValue(val).bits}; } - duckdb_value duckdb_create_timestamp(duckdb_timestamp input) { - duckdb::timestamp_t ts(input.micros); - return CAPICreateValue(ts); + return CAPICreateValue(duckdb::timestamp_t(input.micros)); } - duckdb_timestamp duckdb_get_timestamp(duckdb_value val) { - if (!val) { - return {0}; - } return {CAPIGetValue(val).value}; } - -duckdb_value duckdb_create_timestamp_tz(duckdb_timestamp input) { - duckdb::timestamp_tz_t ts(input.micros); - return CAPICreateValue(ts); -} - -duckdb_timestamp duckdb_get_timestamp_tz(duckdb_value val) { - if (!val) { - return {0}; - } - return {CAPIGetValue(val).value}; -} - -duckdb_value duckdb_create_timestamp_s(duckdb_timestamp_s input) { - duckdb::timestamp_sec_t ts(input.seconds); - return CAPICreateValue(ts); -} - -duckdb_timestamp_s duckdb_get_timestamp_s(duckdb_value val) { - if (!val) { - return {0}; - } - return {CAPIGetValue(val).value}; -} - -duckdb_value duckdb_create_timestamp_ms(duckdb_timestamp_ms input) { - duckdb::timestamp_ms_t ts(input.millis); - return CAPICreateValue(ts); -} - -duckdb_timestamp_ms duckdb_get_timestamp_ms(duckdb_value val) { - if (!val) { - return {0}; - } - return {CAPIGetValue(val).value}; -} - -duckdb_value duckdb_create_timestamp_ns(duckdb_timestamp_ns input) { - duckdb::timestamp_ns_t ts(input.nanos); - return CAPICreateValue(ts); -} - -duckdb_timestamp_ns duckdb_get_timestamp_ns(duckdb_value val) { - if (!val) { - return {0}; - } - return {CAPIGetValue(val).value}; -} - duckdb_value duckdb_create_interval(duckdb_interval input) { return WrapValue(new duckdb::Value(duckdb::Value::INTERVAL(input.months, input.days, input.micros))); } @@ -265,27 +169,6 @@ duckdb_blob duckdb_get_blob(duckdb_value val) { memcpy(result, str.c_str(), str.size()); return {result, str.size()}; } -duckdb_value duckdb_create_bit(duckdb_bit input) { - return WrapValue(new duckdb::Value(duckdb::Value::BIT(input.data, input.size))); -} -duckdb_bit duckdb_get_bit(duckdb_value val) { - auto v = UnwrapValue(val).DefaultCastAs(duckdb::LogicalType::BIT); - auto &str = duckdb::StringValue::Get(v); - auto size = str.size(); - auto data = reinterpret_cast(malloc(size)); - memcpy(data, str.c_str(), size); - return {data, size}; -} -duckdb_value duckdb_create_uuid(duckdb_uhugeint input) { - // uhugeint_t has a constexpr ctor with upper first - return WrapValue(new duckdb::Value(duckdb::Value::UUID(duckdb::UUID::FromUHugeint({input.upper, input.lower})))); -} -duckdb_uhugeint duckdb_get_uuid(duckdb_value val) { - auto hugeint = CAPIGetValue(val); - auto uhugeint = duckdb::UUID::ToUHugeint(hugeint); - // duckdb_uhugeint has no constexpr ctor; struct is lower first - return {uhugeint.lower, uhugeint.upper}; -} duckdb_logical_type duckdb_get_value_type(duckdb_value val) { auto &type = UnwrapValue(val).type(); @@ -399,7 +282,7 @@ idx_t duckdb_get_map_size(duckdb_value value) { } auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::MAP || val.IsNull()) { + if (val.type().id() != LogicalTypeId::MAP) { return 0; } @@ -413,7 +296,7 @@ duckdb_value duckdb_get_map_key(duckdb_value value, idx_t index) { } auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::MAP || val.IsNull()) { + if (val.type().id() != LogicalTypeId::MAP) { return nullptr; } @@ -433,7 +316,7 @@ duckdb_value duckdb_get_map_value(duckdb_value value, idx_t index) { } auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::MAP || val.IsNull()) { + if (val.type().id() != LogicalTypeId::MAP) { return nullptr; } @@ -446,94 +329,3 @@ duckdb_value duckdb_get_map_value(duckdb_value value, idx_t index) { auto &child_struct = duckdb::StructValue::GetChildren(child); return WrapValue(new duckdb::Value(child_struct[1])); } - -bool duckdb_is_null_value(duckdb_value value) { - if (!value) { - return false; - } - return UnwrapValue(value).IsNull(); -} - -duckdb_value duckdb_create_null_value() { - return WrapValue(new duckdb::Value()); -} - -idx_t duckdb_get_list_size(duckdb_value value) { - if (!value) { - return 0; - } - - auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::LIST || val.IsNull()) { - return 0; - } - - auto &children = duckdb::ListValue::GetChildren(val); - return children.size(); -} - -duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index) { - if (!value) { - return nullptr; - } - - auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::LIST || val.IsNull()) { - return nullptr; - } - - auto &children = duckdb::ListValue::GetChildren(val); - if (index >= children.size()) { - return nullptr; - } - - return WrapValue(new duckdb::Value(children[index])); -} - -duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value) { - if (!type) { - return nullptr; - } - - auto &logical_type = UnwrapType(type); - if (logical_type.id() != LogicalTypeId::ENUM) { - return nullptr; - } - - if (value >= duckdb::EnumType::GetSize(logical_type)) { - return nullptr; - } - - return WrapValue(new duckdb::Value(duckdb::Value::ENUM(value, logical_type))); -} - -uint64_t duckdb_get_enum_value(duckdb_value value) { - if (!value) { - return 0; - } - - auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::ENUM || val.IsNull()) { - return 0; - } - - return val.GetValue(); -} - -duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index) { - if (!value) { - return nullptr; - } - - auto val = UnwrapValue(value); - if (val.type().id() != LogicalTypeId::STRUCT || val.IsNull()) { - return nullptr; - } - - auto &children = duckdb::StructValue::GetChildren(val); - if (index >= children.size()) { - return nullptr; - } - - return WrapValue(new duckdb::Value(children[index])); -} diff --git a/src/duckdb/src/main/capi/helper-c.cpp b/src/duckdb/src/main/capi/helper-c.cpp index 710996537..c6c1f455b 100644 --- a/src/duckdb/src/main/capi/helper-c.cpp +++ b/src/duckdb/src/main/capi/helper-c.cpp @@ -197,7 +197,6 @@ idx_t GetCTypeSize(duckdb_type type) { case DUCKDB_TYPE_TIME: return sizeof(duckdb_time); case DUCKDB_TYPE_TIMESTAMP: - case DUCKDB_TYPE_TIMESTAMP_TZ: case DUCKDB_TYPE_TIMESTAMP_S: case DUCKDB_TYPE_TIMESTAMP_MS: case DUCKDB_TYPE_TIMESTAMP_NS: diff --git a/src/duckdb/src/main/capi/prepared-c.cpp b/src/duckdb/src/main/capi/prepared-c.cpp index d033083d0..a0df37a21 100644 --- a/src/duckdb/src/main/capi/prepared-c.cpp +++ b/src/duckdb/src/main/capi/prepared-c.cpp @@ -73,7 +73,7 @@ duckdb_state duckdb_prepare(duckdb_connection connection, const char *query, auto wrapper = new PreparedStatementWrapper(); Connection *conn = reinterpret_cast(connection); wrapper->statement = conn->Prepare(query); - *out_prepared_statement = reinterpret_cast(wrapper); + *out_prepared_statement = (duckdb_prepared_statement)wrapper; return !wrapper->statement->HasError() ? DuckDBSuccess : DuckDBError; } @@ -122,41 +122,22 @@ const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, } duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) { - auto logical_type = duckdb_param_logical_type(prepared_statement, param_idx); - if (!logical_type) { - return DUCKDB_TYPE_INVALID; - } - - auto type = duckdb_get_type_id(logical_type); - - duckdb_destroy_logical_type(&logical_type); - - return type; -} - -duckdb_logical_type duckdb_param_logical_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) { auto wrapper = reinterpret_cast(prepared_statement); if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { - return nullptr; - } - - auto identifier = duckdb_parameter_name_internal(prepared_statement, param_idx); - if (identifier == duckdb::string()) { - return nullptr; + return DUCKDB_TYPE_INVALID; } - LogicalType param_type; - + auto identifier = std::to_string(param_idx); if (wrapper->statement->data->TryGetType(identifier, param_type)) { - return reinterpret_cast(new LogicalType(param_type)); + return ConvertCPPTypeToC(param_type); } // The value_map is gone after executing the prepared statement // See if this is the case and we still have a value registered for it auto it = wrapper->values.find(identifier); if (it != wrapper->values.end()) { - return reinterpret_cast(new LogicalType(it->second.return_type)); + return ConvertCPPTypeToC(it->second.return_type.id()); } - return nullptr; + return DUCKDB_TYPE_INVALID; } duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement) { @@ -301,7 +282,7 @@ duckdb_state duckdb_bind_timestamp(duckdb_prepared_statement prepared_statement, duckdb_state duckdb_bind_timestamp_tz(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_timestamp val) { - auto value = Value::TIMESTAMPTZ(duckdb::timestamp_tz_t(val.micros)); + auto value = Value::TIMESTAMPTZ(timestamp_t(val.micros)); return duckdb_bind_value(prepared_statement, param_idx, (duckdb_value)&value); } diff --git a/src/duckdb/src/main/capi/replacement_scan-c.cpp b/src/duckdb/src/main/capi/replacement_scan-c.cpp index 5f23a3169..ff3eae4ff 100644 --- a/src/duckdb/src/main/capi/replacement_scan-c.cpp +++ b/src/duckdb/src/main/capi/replacement_scan-c.cpp @@ -58,7 +58,7 @@ void duckdb_add_replacement_scan(duckdb_database db, duckdb_replacement_callback if (!db || !replacement) { return; } - auto wrapper = reinterpret_cast(db); + auto wrapper = reinterpret_cast(db); auto scan_info = duckdb::make_uniq(); scan_info->callback = replacement; scan_info->extra_data = extra_data; diff --git a/src/duckdb/src/main/capi/result-c.cpp b/src/duckdb/src/main/capi/result-c.cpp index cc5c6e471..217e2bb05 100644 --- a/src/duckdb/src/main/capi/result-c.cpp +++ b/src/duckdb/src/main/capi/result-c.cpp @@ -538,9 +538,6 @@ idx_t duckdb_column_count(duckdb_result *result) { if (!result) { return 0; } - if (result->internal_data == NULL) { - return 0; - } auto &result_data = *(reinterpret_cast(result->internal_data)); return result_data.result->ColumnCount(); } diff --git a/src/duckdb/src/main/capi/table_description-c.cpp b/src/duckdb/src/main/capi/table_description-c.cpp index 26624bbfc..495267f98 100644 --- a/src/duckdb/src/main/capi/table_description-c.cpp +++ b/src/duckdb/src/main/capi/table_description-c.cpp @@ -8,31 +8,24 @@ using duckdb::TableDescriptionWrapper; duckdb_state duckdb_table_description_create(duckdb_connection connection, const char *schema, const char *table, duckdb_table_description *out) { - return duckdb_table_description_create_ext(connection, INVALID_CATALOG, schema, table, out); -} - -duckdb_state duckdb_table_description_create_ext(duckdb_connection connection, const char *catalog, const char *schema, - const char *table, duckdb_table_description *out) { Connection *conn = reinterpret_cast(connection); if (!out) { return DuckDBError; } auto wrapper = new TableDescriptionWrapper(); - *out = reinterpret_cast(wrapper); + *out = (duckdb_table_description)wrapper; if (!connection || !table) { return DuckDBError; } - if (catalog == nullptr) { - catalog = INVALID_CATALOG; - } + if (schema == nullptr) { schema = DEFAULT_SCHEMA; } try { - wrapper->description = conn->TableInfo(catalog, schema, table); + wrapper->description = conn->TableInfo(schema, table); } catch (std::exception &ex) { ErrorData error(ex); wrapper->error = error.RawMessage(); @@ -68,48 +61,22 @@ const char *duckdb_table_description_error(duckdb_table_description table) { return wrapper->error.c_str(); } -duckdb_state GetTableDescription(TableDescriptionWrapper *wrapper, idx_t index) { - if (!wrapper) { +duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out) { + auto wrapper = reinterpret_cast(table_description); + if (!wrapper || !out) { + if (wrapper) { + wrapper->error = "Please provide a valid (non-null) 'out' variable"; + } return DuckDBError; } + auto &table = wrapper->description; if (index >= table->columns.size()) { wrapper->error = duckdb::StringUtil::Format("Column index %d is out of range, table only has %d columns", index, table->columns.size()); return DuckDBError; } - return DuckDBSuccess; -} - -duckdb_state duckdb_column_has_default(duckdb_table_description table_description, idx_t index, bool *out) { - auto wrapper = reinterpret_cast(table_description); - if (GetTableDescription(wrapper, index) == DuckDBError) { - return DuckDBError; - } - if (!out) { - wrapper->error = "Please provide a valid (non-null) 'out' variable"; - return DuckDBError; - } - - auto &table = wrapper->description; auto &column = table->columns[index]; *out = column.HasDefaultValue(); return DuckDBSuccess; } - -char *duckdb_table_description_get_column_name(duckdb_table_description table_description, idx_t index) { - auto wrapper = reinterpret_cast(table_description); - if (GetTableDescription(wrapper, index) == DuckDBError) { - return nullptr; - } - - auto &table = wrapper->description; - auto &column = table->columns[index]; - - auto name = column.GetName(); - auto result = reinterpret_cast(malloc(sizeof(char) * (name.size() + 1))); - memcpy(result, name.c_str(), name.size()); - result[name.size()] = '\0'; - - return result; -} diff --git a/src/duckdb/src/main/capi/threading-c.cpp b/src/duckdb/src/main/capi/threading-c.cpp index 575f22c3c..b0a002f18 100644 --- a/src/duckdb/src/main/capi/threading-c.cpp +++ b/src/duckdb/src/main/capi/threading-c.cpp @@ -1,10 +1,10 @@ #include "duckdb/main/capi/capi_internal.hpp" #include "duckdb/parallel/task_scheduler.hpp" -using duckdb::DatabaseWrapper; +using duckdb::DatabaseData; struct CAPITaskState { - explicit CAPITaskState(duckdb::DatabaseInstance &db) + CAPITaskState(duckdb::DatabaseInstance &db) : db(db), marker(duckdb::make_uniq>(true)), execute_count(0) { } @@ -17,7 +17,7 @@ void duckdb_execute_tasks(duckdb_database database, idx_t max_tasks) { if (!database) { return; } - auto wrapper = reinterpret_cast(database); + auto wrapper = (DatabaseData *)database; auto &scheduler = duckdb::TaskScheduler::GetScheduler(*wrapper->database->instance); scheduler.ExecuteTasks(max_tasks); } @@ -26,7 +26,7 @@ duckdb_task_state duckdb_create_task_state(duckdb_database database) { if (!database) { return nullptr; } - auto wrapper = reinterpret_cast(database); + auto wrapper = (DatabaseData *)database; auto state = new CAPITaskState(*wrapper->database->instance); return state; } diff --git a/src/duckdb/src/main/client_context.cpp b/src/duckdb/src/main/client_context.cpp index 53234bdb9..90c029ab4 100644 --- a/src/duckdb/src/main/client_context.cpp +++ b/src/duckdb/src/main/client_context.cpp @@ -41,7 +41,6 @@ #include "duckdb/planner/pragma_handler.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/transaction/meta_transaction.hpp" -#include "duckdb/transaction/transaction_context.hpp" #include "duckdb/transaction/transaction_manager.hpp" namespace duckdb { @@ -76,9 +75,6 @@ struct ActiveQueryContext { #ifdef DEBUG struct DebugClientContextState : public ClientContextState { ~DebugClientContextState() override { - if (Exception::UncaughtException()) { - return; - } D_ASSERT(!active_transaction); D_ASSERT(!active_query); } @@ -170,10 +166,9 @@ void ClientContext::Destroy() { } void ClientContext::ProcessError(ErrorData &error, const string &query) const { - error.FinalizeError(); if (config.errors_as_json) { error.ConvertErrorToJSON(); - } else { + } else if (!query.empty()) { error.AddErrorLocation(query); } } @@ -195,7 +190,6 @@ void ClientContext::BeginQueryInternal(ClientContextLock &lock, const string &qu if (transaction.IsAutoCommit()) { transaction.BeginTransaction(); } - transaction.SetActiveQuery(db->GetDatabaseManager().GetNewQueryNumber()); LogQueryInternal(lock, query); active_query->query = query; @@ -236,7 +230,7 @@ ErrorData ClientContext::EndQueryInternal(ClientContextLock &lock, bool success, } } catch (std::exception &ex) { error = ErrorData(ex); - if (Exception::InvalidatesDatabase(error.Type()) || error.Type() == ExceptionType::INTERNAL) { + if (Exception::InvalidatesDatabase(error.Type())) { auto &db_inst = DatabaseInstance::GetDatabase(*this); ValidChecker::Invalidate(db_inst, error.RawMessage()); } @@ -546,7 +540,6 @@ unique_ptr ClientContext::PendingPreparedStatement(ClientCon } if (rebind == RebindQueryInfo::ATTEMPT_TO_REBIND) { RebindPreparedStatement(lock, query, prepared, parameters); - CheckIfPreparedStatementIsExecutable(*prepared); // rerun this too as modified_databases might have changed } return PendingPreparedStatementInternal(lock, prepared, parameters); } @@ -584,7 +577,7 @@ PendingExecutionResult ClientContext::ExecuteTaskInternal(ClientContextLock &loc } } else if (!Exception::InvalidatesTransaction(error.Type())) { invalidate_transaction = false; - } else if (Exception::InvalidatesDatabase(error.Type()) || error.Type() == ExceptionType::INTERNAL) { + } else if (Exception::InvalidatesDatabase(error.Type())) { // fatal exceptions invalidate the entire database auto &db_instance = DatabaseInstance::GetDatabase(*this); ValidChecker::Invalidate(db_instance, error.RawMessage()); @@ -742,13 +735,8 @@ unique_ptr ClientContext::PendingStatementInternal(ClientCon unique_ptr statement, const PendingQueryParameters ¶meters) { // prepare the query for execution - if (parameters.parameters) { - PreparedStatement::VerifyParameters(*parameters.parameters, statement->named_param_map); - } - auto prepared = CreatePreparedStatement(lock, query, std::move(statement), parameters.parameters, PreparedStatementMode::PREPARE_AND_EXECUTE); - idx_t parameter_count = !parameters.parameters ? 0 : parameters.parameters->size(); if (prepared->properties.parameter_count > 0 && parameter_count == 0) { string error_message = StringUtil::Format("Expected %lld parameters, but none were supplied", @@ -763,13 +751,11 @@ unique_ptr ClientContext::PendingStatementInternal(ClientCon return PendingPreparedStatementInternal(lock, std::move(prepared), parameters); } -unique_ptr -ClientContext::RunStatementInternal(ClientContextLock &lock, const string &query, unique_ptr statement, - bool allow_stream_result, - optional_ptr> params, bool verify) { +unique_ptr ClientContext::RunStatementInternal(ClientContextLock &lock, const string &query, + unique_ptr statement, + bool allow_stream_result, bool verify) { PendingQueryParameters parameters; parameters.allow_stream_result = allow_stream_result; - parameters.parameters = params; auto pending = PendingQueryInternal(lock, std::move(statement), parameters, verify); if (pending->HasError()) { return ErrorResult(pending->GetErrorObject()); @@ -803,7 +789,7 @@ unique_ptr ClientContext::PendingStatementOrPreparedStatemen // in case this is a select query, we verify the original statement ErrorData error; try { - error = VerifyQuery(lock, query, std::move(statement), parameters.parameters); + error = VerifyQuery(lock, query, std::move(statement)); } catch (std::exception &ex) { error = ErrorData(ex); } @@ -940,7 +926,7 @@ unique_ptr ClientContext::Query(const string &query, bool allow_str } unique_ptr result; - optional_ptr last_result; + QueryResult *last_result = nullptr; bool last_had_result = false; for (idx_t i = 0; i < statements.size(); i++) { auto &statement = statements[i]; @@ -975,7 +961,6 @@ unique_ptr ClientContext::Query(const string &query, bool allow_str // Reset the interrupted flag, this was set by the task that found the error // Next statements should not be bothered by that interruption interrupted = false; - break; } } return result; @@ -995,57 +980,34 @@ bool ClientContext::ParseStatements(ClientContextLock &lock, const string &query } unique_ptr ClientContext::PendingQuery(const string &query, bool allow_stream_result) { - case_insensitive_map_t empty_param_list; - return PendingQuery(query, empty_param_list, allow_stream_result); -} - -unique_ptr ClientContext::PendingQuery(unique_ptr statement, - bool allow_stream_result) { - case_insensitive_map_t empty_param_list; - return PendingQuery(std::move(statement), empty_param_list, allow_stream_result); -} - -unique_ptr ClientContext::PendingQuery(const string &query, - case_insensitive_map_t &values, - bool allow_stream_result) { auto lock = LockContext(); - try { - InitialCleanup(*lock); - auto statements = ParseStatementsInternal(*lock, query); - if (statements.empty()) { - throw InvalidInputException("No statement to prepare!"); - } - if (statements.size() > 1) { - throw InvalidInputException("Cannot prepare multiple statements at once!"); - } - - PendingQueryParameters params; - params.allow_stream_result = allow_stream_result; - params.parameters = values; - - return PendingQueryInternal(*lock, std::move(statements[0]), params, true); - } catch (std::exception &ex) { - return make_uniq(ErrorData(ex)); + ErrorData error; + vector> statements; + if (!ParseStatements(*lock, query, statements, error)) { + return ErrorResult(std::move(error), query); } + if (statements.size() != 1) { + return ErrorResult(ErrorData("PendingQuery can only take a single statement"), query); + } + PendingQueryParameters parameters; + parameters.allow_stream_result = allow_stream_result; + return PendingQueryInternal(*lock, std::move(statements[0]), parameters); } unique_ptr ClientContext::PendingQuery(unique_ptr statement, - case_insensitive_map_t &values, bool allow_stream_result) { auto lock = LockContext(); - auto query = statement->query; + try { InitialCleanup(*lock); - - PendingQueryParameters params; - params.allow_stream_result = allow_stream_result; - params.parameters = values; - - return PendingQueryInternal(*lock, std::move(statement), params, true); } catch (std::exception &ex) { - return make_uniq(ErrorData(ex)); + return ErrorResult(ErrorData(ex)); } + + PendingQueryParameters parameters; + parameters.allow_stream_result = allow_stream_result; + return PendingQueryInternal(*lock, std::move(statement), parameters); } unique_ptr ClientContext::PendingQueryInternal(ClientContextLock &lock, @@ -1145,20 +1107,19 @@ void ClientContext::RunFunctionInTransaction(const std::function &fu RunFunctionInTransactionInternal(*lock, fun, requires_valid_transaction); } -unique_ptr ClientContext::TableInfo(const string &database_name, const string &schema_name, - const string &table_name) { +unique_ptr ClientContext::TableInfo(const string &schema_name, const string &table_name) { unique_ptr result; RunFunctionInTransaction([&]() { - // Obtain the table from the catalog. - auto table = Catalog::GetEntry(*this, database_name, schema_name, table_name, + // obtain the table info + auto table = Catalog::GetEntry(*this, INVALID_CATALOG, schema_name, table_name, OnEntryNotFound::RETURN_NULL); if (!table) { return; } - // Create the table description. - result = make_uniq(database_name, schema_name, table_name); - auto &catalog = Catalog::GetCatalog(*this, database_name); - result->readonly = catalog.GetAttached().IsReadOnly(); + // write the table info to the result + result = make_uniq(); + result->schema = schema_name; + result->table = table_name; for (auto &column : table->GetColumns().Logical()) { result->columns.emplace_back(column.Copy()); } @@ -1166,16 +1127,10 @@ unique_ptr ClientContext::TableInfo(const string &database_nam return result; } -unique_ptr ClientContext::TableInfo(const string &schema_name, const string &table_name) { - return TableInfo(INVALID_CATALOG, schema_name, table_name); -} - -void ClientContext::Append(TableDescription &description, ColumnDataCollection &collection, - optional_ptr> column_ids) { - +void ClientContext::Append(TableDescription &description, ColumnDataCollection &collection) { RunFunctionInTransaction([&]() { auto &table_entry = - Catalog::GetEntry(*this, description.database, description.schema, description.table); + Catalog::GetEntry(*this, INVALID_CATALOG, description.schema, description.table); // verify that the table columns and types match up if (description.PhysicalColumnCount() != table_entry.GetColumns().PhysicalColumnCount()) { throw InvalidInputException("Failed to append: table entry has different number of columns!"); @@ -1194,28 +1149,26 @@ void ClientContext::Append(TableDescription &description, ColumnDataCollection & auto binder = Binder::CreateBinder(*this); auto bound_constraints = binder->BindConstraints(table_entry); MetaTransaction::Get(*this).ModifyDatabase(table_entry.ParentCatalog().GetAttached()); - table_entry.GetStorage().LocalAppend(table_entry, *this, collection, bound_constraints, column_ids); + table_entry.GetStorage().LocalAppend(table_entry, *this, collection, bound_constraints); }); } -void ClientContext::InternalTryBindRelation(Relation &relation, vector &result_columns) { - // bind the expressions - auto binder = Binder::CreateBinder(*this); - auto result = relation.Bind(*binder); - D_ASSERT(result.names.size() == result.types.size()); - - result_columns.reserve(result_columns.size() + result.names.size()); - for (idx_t i = 0; i < result.names.size(); i++) { - result_columns.emplace_back(result.names[i], result.types[i]); - } -} - void ClientContext::TryBindRelation(Relation &relation, vector &result_columns) { #ifdef DEBUG D_ASSERT(!relation.GetAlias().empty()); D_ASSERT(!relation.ToString().empty()); #endif - RunFunctionInTransaction([&]() { InternalTryBindRelation(relation, result_columns); }); + RunFunctionInTransaction([&]() { + // bind the expressions + auto binder = Binder::CreateBinder(*this); + auto result = relation.Bind(*binder); + D_ASSERT(result.names.size() == result.types.size()); + + result_columns.reserve(result_columns.size() + result.names.size()); + for (idx_t i = 0; i < result.names.size(); i++) { + result_columns.emplace_back(result.names[i], result.types[i]); + } + }); } unordered_set ClientContext::GetTableNames(const string &query) { @@ -1251,7 +1204,7 @@ unique_ptr ClientContext::PendingQueryInternal(ClientContext // verify read only statements by running a select statement auto select = make_uniq(); select->node = relation->GetQueryNode(); - RunStatementInternal(lock, query, std::move(select), false, nullptr); + RunStatementInternal(lock, query, std::move(select), false); } } @@ -1351,7 +1304,7 @@ ClientProperties ClientContext::GetClientProperties() const { timezone = result.ToString(); } return {timezone, db->config.options.arrow_offset_size, db->config.options.arrow_use_list_view, - db->config.options.produce_arrow_string_views, db->config.options.arrow_lossless_conversion}; + db->config.options.produce_arrow_string_views, db->config.options.arrow_arrow_lossless_conversion}; } bool ClientContext::ExecutionIsFinished() { diff --git a/src/duckdb/src/main/client_context_wrapper.cpp b/src/duckdb/src/main/client_context_wrapper.cpp index 74783c79d..d79b09300 100644 --- a/src/duckdb/src/main/client_context_wrapper.cpp +++ b/src/duckdb/src/main/client_context_wrapper.cpp @@ -19,8 +19,4 @@ shared_ptr ClientContextWrapper::GetContext() { return actual_context; } -void ClientContextWrapper::TryBindRelation(Relation &relation, vector &columns) { - GetContext()->TryBindRelation(relation, columns); -} - } // namespace duckdb diff --git a/src/duckdb/src/main/client_data.cpp b/src/duckdb/src/main/client_data.cpp index fb07894c4..50e460b60 100644 --- a/src/duckdb/src/main/client_data.cpp +++ b/src/duckdb/src/main/client_data.cpp @@ -42,7 +42,7 @@ ClientData::ClientData(ClientContext &context) : catalog_search_path(make_uniq(); file_opener = make_uniq(context); client_file_system = make_uniq(context); - temporary_objects->Initialize(); + temporary_objects->Initialize(DEFAULT_BLOCK_ALLOC_SIZE); } ClientData::~ClientData() { diff --git a/src/duckdb/src/main/client_verify.cpp b/src/duckdb/src/main/client_verify.cpp index d3fb4f380..f31a6fc52 100644 --- a/src/duckdb/src/main/client_verify.cpp +++ b/src/duckdb/src/main/client_verify.cpp @@ -21,8 +21,7 @@ static void ThrowIfExceptionIsInternal(StatementVerifier &verifier) { } } -ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr statement, - optional_ptr> parameters) { +ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr statement) { D_ASSERT(statement->type == StatementType::SELECT_STATEMENT); // Aggressive query verification @@ -46,36 +45,30 @@ ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &quer // Base Statement verifiers: these are the verifiers we enable for regular builds if (config.query_verification_enabled) { - statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::COPIED, stmt, parameters)); - statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::DESERIALIZED, stmt, parameters)); - statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::UNOPTIMIZED, stmt, parameters)); - - // FIXME: Prepared parameter verifier is broken for queries with parameters - if (!parameters || parameters->empty()) { - prepared_statement_verifier = StatementVerifier::Create(VerificationType::PREPARED, stmt, parameters); - } + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::COPIED, stmt)); + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::DESERIALIZED, stmt)); + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::UNOPTIMIZED, stmt)); + prepared_statement_verifier = StatementVerifier::Create(VerificationType::PREPARED, stmt); } // This verifier is enabled explicitly OR by enabling run_slow_verifiers if (config.verify_fetch_row || (run_slow_verifiers && config.query_verification_enabled)) { - statement_verifiers.emplace_back( - StatementVerifier::Create(VerificationType::FETCH_ROW_AS_SCAN, stmt, parameters)); + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::FETCH_ROW_AS_SCAN, stmt)); } // For the DEBUG_ASYNC build we enable this extra verifier #ifdef DUCKDB_DEBUG_ASYNC_SINK_SOURCE if (config.query_verification_enabled) { - statement_verifiers.emplace_back( - StatementVerifier::Create(VerificationType::NO_OPERATOR_CACHING, stmt, parameters)); + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::NO_OPERATOR_CACHING, stmt)); } #endif // Verify external always needs to be explicitly enabled and is never part of default verifier set if (config.verify_external) { - statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::EXTERNAL, stmt, parameters)); + statement_verifiers.emplace_back(StatementVerifier::Create(VerificationType::EXTERNAL, stmt)); } - auto original = make_uniq(std::move(statement), parameters); + auto original = make_uniq(std::move(statement)); for (auto &verifier : statement_verifiers) { original->CheckExpressions(*verifier); } @@ -95,33 +88,26 @@ ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &quer } // Execute the original statement - bool any_failed = original->Run(*this, query, - [&](const string &q, unique_ptr s, - optional_ptr> params) { - return RunStatementInternal(lock, q, std::move(s), false, params, false); - }); + bool any_failed = original->Run(*this, query, [&](const string &q, unique_ptr s) { + return RunStatementInternal(lock, q, std::move(s), false, false); + }); if (!any_failed) { statement_verifiers.emplace_back( - StatementVerifier::Create(VerificationType::PARSED, *statement_copy_for_explain, parameters)); + StatementVerifier::Create(VerificationType::PARSED, *statement_copy_for_explain)); } // Execute the verifiers for (auto &verifier : statement_verifiers) { - bool failed = verifier->Run(*this, query, - [&](const string &q, unique_ptr s, - optional_ptr> params) { - return RunStatementInternal(lock, q, std::move(s), false, params, false); - }); + bool failed = verifier->Run(*this, query, [&](const string &q, unique_ptr s) { + return RunStatementInternal(lock, q, std::move(s), false, false); + }); any_failed = any_failed || failed; } if (!any_failed && prepared_statement_verifier) { // If none failed, we execute the prepared statement verifier - bool failed = prepared_statement_verifier->Run( - *this, query, - [&](const string &q, unique_ptr s, - optional_ptr> params) { - return RunStatementInternal(lock, q, std::move(s), false, params, false); - }); + bool failed = prepared_statement_verifier->Run(*this, query, [&](const string &q, unique_ptr s) { + return RunStatementInternal(lock, q, std::move(s), false, false); + }); if (!failed) { // PreparedStatementVerifier fails if it runs into a ParameterNotAllowedException, which is OK statement_verifiers.push_back(std::move(prepared_statement_verifier)); @@ -133,9 +119,6 @@ ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &quer if (ValidChecker::IsInvalidated(*db)) { return original->materialized_result->GetErrorObject(); } - if (transaction.HasActiveTransaction() && ValidChecker::IsInvalidated(ActiveTransaction())) { - return original->materialized_result->GetErrorObject(); - } } // Restore config setting @@ -145,11 +128,9 @@ ErrorData ClientContext::VerifyQuery(ClientContextLock &lock, const string &quer // Check explain, only if q does not already contain EXPLAIN if (original->materialized_result->success) { auto explain_q = "EXPLAIN " + query; - auto original_named_param_map = statement_copy_for_explain->named_param_map; auto explain_stmt = make_uniq(std::move(statement_copy_for_explain)); - explain_stmt->named_param_map = original_named_param_map; try { - RunStatementInternal(lock, explain_q, std::move(explain_stmt), false, parameters, false); + RunStatementInternal(lock, explain_q, std::move(explain_stmt), false, false); } catch (std::exception &ex) { // LCOV_EXCL_START ErrorData error(ex); interrupted = false; diff --git a/src/duckdb/src/main/config.cpp b/src/duckdb/src/main/config.cpp index 2c604cec3..6921cb497 100644 --- a/src/duckdb/src/main/config.cpp +++ b/src/duckdb/src/main/config.cpp @@ -54,113 +54,109 @@ bool DBConfigOptions::debug_print_bindings = false; _PARAM::ResetLocal, _PARAM::GetSetting \ } #define FINAL_SETTING \ - { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } + { nullptr, nullptr, LogicalTypeId::INVALID, nullptr, nullptr, nullptr, nullptr, nullptr } static const ConfigurationOption internal_options[] = { DUCKDB_GLOBAL(AccessModeSetting), - DUCKDB_GLOBAL(AllocatorBackgroundThreadsSetting), - DUCKDB_GLOBAL(AllocatorBulkDeallocationFlushThresholdSetting), - DUCKDB_GLOBAL(AllocatorFlushThresholdSetting), - DUCKDB_GLOBAL(AllowCommunityExtensionsSetting), - DUCKDB_GLOBAL(AllowExtensionsMetadataMismatchSetting), - DUCKDB_GLOBAL(AllowPersistentSecretsSetting), - DUCKDB_GLOBAL(AllowUnredactedSecretsSetting), - DUCKDB_GLOBAL(AllowUnsignedExtensionsSetting), - DUCKDB_GLOBAL(AllowedDirectoriesSetting), - DUCKDB_GLOBAL(AllowedPathsSetting), - DUCKDB_GLOBAL(ArrowLargeBufferSizeSetting), - DUCKDB_GLOBAL(ArrowLosslessConversionSetting), - DUCKDB_GLOBAL(ArrowOutputListViewSetting), - DUCKDB_GLOBAL(AutoinstallExtensionRepositorySetting), - DUCKDB_GLOBAL(AutoinstallKnownExtensionsSetting), - DUCKDB_GLOBAL(AutoloadKnownExtensionsSetting), - DUCKDB_GLOBAL(CatalogErrorMaxSchemasSetting), + DUCKDB_GLOBAL(AllowPersistentSecrets), + DUCKDB_GLOBAL(CatalogErrorMaxSchema), DUCKDB_GLOBAL(CheckpointThresholdSetting), - DUCKDB_GLOBAL_ALIAS("wal_autocheckpoint", CheckpointThresholdSetting), - DUCKDB_GLOBAL(CustomExtensionRepositorySetting), - DUCKDB_LOCAL(CustomProfilingSettingsSetting), - DUCKDB_GLOBAL(CustomUserAgentSetting), - DUCKDB_LOCAL(DebugAsofIejoinSetting), - DUCKDB_GLOBAL(DebugCheckpointAbortSetting), - DUCKDB_LOCAL(DebugForceExternalSetting), - DUCKDB_LOCAL(DebugForceNoCrossProductSetting), - DUCKDB_GLOBAL(DebugSkipCheckpointOnCommitSetting), - DUCKDB_GLOBAL(DebugWindowModeSetting), - DUCKDB_GLOBAL(DefaultBlockSizeSetting), + DUCKDB_GLOBAL(DebugCheckpointAbort), + DUCKDB_GLOBAL(DebugSkipCheckpointOnCommit), + DUCKDB_GLOBAL(StorageCompatibilityVersion), + DUCKDB_LOCAL(DebugForceExternal), + DUCKDB_LOCAL(DebugForceNoCrossProduct), + DUCKDB_LOCAL(DebugAsOfIEJoin), + DUCKDB_LOCAL(PreferRangeJoins), + DUCKDB_GLOBAL(DebugWindowMode), DUCKDB_GLOBAL_LOCAL(DefaultCollationSetting), - DUCKDB_GLOBAL(DefaultNullOrderSetting), - DUCKDB_GLOBAL_ALIAS("null_order", DefaultNullOrderSetting), DUCKDB_GLOBAL(DefaultOrderSetting), - DUCKDB_GLOBAL(DefaultSecretStorageSetting), - DUCKDB_GLOBAL(DisabledFilesystemsSetting), + DUCKDB_GLOBAL(DefaultNullOrderSetting), + DUCKDB_GLOBAL(DisabledFileSystemsSetting), DUCKDB_GLOBAL(DisabledOptimizersSetting), - DUCKDB_GLOBAL(DuckDBAPISetting), - DUCKDB_LOCAL(DynamicOrFilterThresholdSetting), DUCKDB_GLOBAL(EnableExternalAccessSetting), - DUCKDB_GLOBAL(EnableFSSTVectorsSetting), - DUCKDB_LOCAL(EnableHTTPLoggingSetting), - DUCKDB_GLOBAL(EnableHTTPMetadataCacheSetting), - DUCKDB_GLOBAL(EnableMacroDependenciesSetting), + DUCKDB_GLOBAL(EnableFSSTVectors), + DUCKDB_GLOBAL(AllowUnsignedExtensionsSetting), + DUCKDB_GLOBAL(AllowCommunityExtensionsSetting), + DUCKDB_GLOBAL(AllowExtensionsMetadataMismatchSetting), + DUCKDB_GLOBAL(AllowUnredactedSecretsSetting), + DUCKDB_GLOBAL(CustomExtensionRepository), + DUCKDB_GLOBAL(AutoloadExtensionRepository), + DUCKDB_GLOBAL(AutoinstallKnownExtensions), + DUCKDB_GLOBAL(AutoloadKnownExtensions), DUCKDB_GLOBAL(EnableObjectCacheSetting), + DUCKDB_GLOBAL(EnableHTTPMetadataCacheSetting), DUCKDB_LOCAL(EnableProfilingSetting), DUCKDB_LOCAL(EnableProgressBarSetting), DUCKDB_LOCAL(EnableProgressBarPrintSetting), - DUCKDB_GLOBAL(EnableViewDependenciesSetting), - DUCKDB_LOCAL(ErrorsAsJSONSetting), + DUCKDB_LOCAL(ErrorsAsJsonSetting), DUCKDB_LOCAL(ExplainOutputSetting), DUCKDB_GLOBAL(ExtensionDirectorySetting), DUCKDB_GLOBAL(ExternalThreadsSetting), DUCKDB_LOCAL(FileSearchPathSetting), - DUCKDB_GLOBAL(ForceBitpackingModeSetting), DUCKDB_GLOBAL(ForceCompressionSetting), + DUCKDB_GLOBAL(ForceBitpackingModeSetting), DUCKDB_LOCAL(HomeDirectorySetting), - DUCKDB_LOCAL(HTTPLoggingOutputSetting), - DUCKDB_GLOBAL(HTTPProxySetting), - DUCKDB_GLOBAL(HTTPProxyPasswordSetting), - DUCKDB_GLOBAL(HTTPProxyUsernameSetting), + DUCKDB_GLOBAL(HTTPProxy), + DUCKDB_GLOBAL(HTTPProxyUsername), + DUCKDB_GLOBAL(HTTPProxyPassword), + DUCKDB_LOCAL(LogQueryPathSetting), + DUCKDB_GLOBAL(EnableMacrosDependencies), + DUCKDB_GLOBAL(EnableViewDependencies), + DUCKDB_GLOBAL(LockConfigurationSetting), DUCKDB_LOCAL(IEEEFloatingPointOpsSetting), DUCKDB_GLOBAL(ImmediateTransactionModeSetting), - DUCKDB_GLOBAL(IndexScanMaxCountSetting), - DUCKDB_GLOBAL(IndexScanPercentageSetting), DUCKDB_LOCAL(IntegerDivisionSetting), - DUCKDB_GLOBAL(LockConfigurationSetting), - DUCKDB_LOCAL(LogQueryPathSetting), - DUCKDB_LOCAL(MaxExpressionDepthSetting), - DUCKDB_GLOBAL(MaxMemorySetting), - DUCKDB_GLOBAL_ALIAS("memory_limit", MaxMemorySetting), - DUCKDB_GLOBAL(MaxTempDirectorySizeSetting), - DUCKDB_GLOBAL(MaxVacuumTasksSetting), - DUCKDB_LOCAL(MergeJoinThresholdSetting), - DUCKDB_LOCAL(NestedLoopJoinThresholdSetting), - DUCKDB_GLOBAL(OldImplicitCastingSetting), - DUCKDB_LOCAL(OrderByNonIntegerLiteralSetting), - DUCKDB_LOCAL(OrderedAggregateThresholdSetting), - DUCKDB_LOCAL(PartitionedWriteFlushThresholdSetting), - DUCKDB_LOCAL(PartitionedWriteMaxOpenFilesSetting), + DUCKDB_LOCAL(MaximumExpressionDepthSetting), + DUCKDB_LOCAL(StreamingBufferSize), + DUCKDB_GLOBAL(MaximumMemorySetting), + DUCKDB_GLOBAL(MaximumTempDirectorySize), + DUCKDB_GLOBAL(MaximumVacuumTasks), + DUCKDB_LOCAL(MergeJoinThreshold), + DUCKDB_LOCAL(NestedLoopJoinThreshold), + DUCKDB_GLOBAL(OldImplicitCasting), + DUCKDB_GLOBAL_ALIAS("memory_limit", MaximumMemorySetting), + DUCKDB_GLOBAL_ALIAS("null_order", DefaultNullOrderSetting), + DUCKDB_LOCAL(OrderByNonIntegerLiteral), + DUCKDB_LOCAL(OrderedAggregateThreshold), DUCKDB_GLOBAL(PasswordSetting), - DUCKDB_LOCAL(PerfectHtThresholdSetting), - DUCKDB_LOCAL(PivotFilterThresholdSetting), + DUCKDB_LOCAL(PerfectHashThresholdSetting), + DUCKDB_LOCAL(PivotFilterThreshold), DUCKDB_LOCAL(PivotLimitSetting), - DUCKDB_LOCAL(PreferRangeJoinsSetting), - DUCKDB_LOCAL(PreserveIdentifierCaseSetting), - DUCKDB_GLOBAL(PreserveInsertionOrderSetting), - DUCKDB_GLOBAL(ProduceArrowStringViewSetting), + DUCKDB_LOCAL(PreserveIdentifierCase), + DUCKDB_GLOBAL(PreserveInsertionOrder), DUCKDB_LOCAL(ProfileOutputSetting), - DUCKDB_LOCAL_ALIAS("profiling_output", ProfileOutputSetting), DUCKDB_LOCAL(ProfilingModeSetting), + DUCKDB_LOCAL_ALIAS("profiling_output", ProfileOutputSetting), + DUCKDB_LOCAL(CustomProfilingSettings), DUCKDB_LOCAL(ProgressBarTimeSetting), - DUCKDB_LOCAL(ScalarSubqueryErrorOnMultipleRowsSetting), DUCKDB_LOCAL(SchemaSetting), DUCKDB_LOCAL(SearchPathSetting), + DUCKDB_LOCAL(ScalarSubqueryErrorOnMultipleRows), DUCKDB_GLOBAL(SecretDirectorySetting), - DUCKDB_GLOBAL(StorageCompatibilityVersionSetting), - DUCKDB_LOCAL(StreamingBufferSizeSetting), + DUCKDB_GLOBAL(DefaultSecretStorage), DUCKDB_GLOBAL(TempDirectorySetting), DUCKDB_GLOBAL(ThreadsSetting), - DUCKDB_GLOBAL_ALIAS("worker_threads", ThreadsSetting), DUCKDB_GLOBAL(UsernameSetting), + DUCKDB_GLOBAL(ExportLargeBufferArrow), + DUCKDB_GLOBAL(ArrowOutputListView), + DUCKDB_GLOBAL(LosslessConversionArrow), + DUCKDB_GLOBAL(ProduceArrowStringView), DUCKDB_GLOBAL_ALIAS("user", UsernameSetting), - DUCKDB_GLOBAL(ZstdMinStringLengthSetting), + DUCKDB_GLOBAL_ALIAS("wal_autocheckpoint", CheckpointThresholdSetting), + DUCKDB_GLOBAL_ALIAS("worker_threads", ThreadsSetting), + DUCKDB_GLOBAL(AllocatorFlushThreshold), + DUCKDB_GLOBAL(AllocatorBulkDeallocationFlushThreshold), + DUCKDB_GLOBAL(AllocatorBackgroundThreadsSetting), + DUCKDB_GLOBAL(DuckDBApiSetting), + DUCKDB_GLOBAL(CustomUserAgentSetting), + DUCKDB_LOCAL(PartitionedWriteFlushThreshold), + DUCKDB_LOCAL(PartitionedWriteMaxOpenFiles), + DUCKDB_GLOBAL(DefaultBlockAllocSize), + DUCKDB_GLOBAL(IndexScanPercentage), + DUCKDB_GLOBAL(IndexScanMaxCount), + DUCKDB_LOCAL(EnableHTTPLoggingSetting), + DUCKDB_LOCAL(HTTPLoggingOutputSetting), FINAL_SETTING}; vector DBConfig::GetOptions() { @@ -245,7 +241,7 @@ void DBConfig::SetOption(DatabaseInstance *db, const ConfigurationOption &option throw InvalidInputException("Could not set option \"%s\" as a global option", option.name); } D_ASSERT(option.reset_global); - Value input = value.DefaultCastAs(ParseLogicalType(option.parameter_type)); + Value input = value.DefaultCastAs(option.parameter_type); option.set_global(db, *this, input); } @@ -277,96 +273,6 @@ void DBConfig::ResetOption(const string &name) { } } -LogicalType DBConfig::ParseLogicalType(const string &type) { - if (StringUtil::EndsWith(type, "[]")) { - // list - recurse - auto child_type = ParseLogicalType(type.substr(0, type.size() - 2)); - return LogicalType::LIST(child_type); - } - - if (StringUtil::EndsWith(type, "]")) { - // array - recurse - auto bracket_open_idx = type.rfind('['); - if (bracket_open_idx == DConstants::INVALID_INDEX || bracket_open_idx == 0) { - throw InternalException("Ill formatted type: '%s'", type); - } - idx_t array_size = 0; - for (auto length_idx = bracket_open_idx + 1; length_idx < type.size() - 1; length_idx++) { - if (!isdigit(type[length_idx])) { - throw InternalException("Ill formatted array type: '%s'", type); - } - array_size = array_size * 10 + static_cast(type[length_idx] - '0'); - } - if (array_size == 0 || array_size > ArrayType::MAX_ARRAY_SIZE) { - throw InternalException("Invalid array size: '%s'", type); - } - auto child_type = ParseLogicalType(type.substr(0, bracket_open_idx)); - return LogicalType::ARRAY(child_type, array_size); - } - - if (StringUtil::StartsWith(type, "MAP(") && StringUtil::EndsWith(type, ")")) { - // map - recurse - string map_args = type.substr(4, type.size() - 5); - vector map_args_vect = StringUtil::SplitWithParentheses(map_args); - if (map_args_vect.size() != 2) { - throw InternalException("Ill formatted map type: '%s'", type); - } - StringUtil::Trim(map_args_vect[0]); - StringUtil::Trim(map_args_vect[1]); - auto key_type = ParseLogicalType(map_args_vect[0]); - auto value_type = ParseLogicalType(map_args_vect[1]); - return LogicalType::MAP(key_type, value_type); - } - - if (StringUtil::StartsWith(type, "UNION(") && StringUtil::EndsWith(type, ")")) { - // union - recurse - string union_members_str = type.substr(6, type.size() - 7); - vector union_members_vect = StringUtil::SplitWithParentheses(union_members_str); - child_list_t union_members; - for (idx_t member_idx = 0; member_idx < union_members_vect.size(); member_idx++) { - StringUtil::Trim(union_members_vect[member_idx]); - vector union_member_parts = StringUtil::SplitWithParentheses(union_members_vect[member_idx], ' '); - if (union_member_parts.size() != 2) { - throw InternalException("Ill formatted union type: %s", type); - } - StringUtil::Trim(union_member_parts[0]); - StringUtil::Trim(union_member_parts[1]); - auto value_type = ParseLogicalType(union_member_parts[1]); - union_members.emplace_back(make_pair(union_member_parts[0], value_type)); - } - if (union_members.empty() || union_members.size() > UnionType::MAX_UNION_MEMBERS) { - throw InternalException("Invalid number of union members: '%s'", type); - } - return LogicalType::UNION(union_members); - } - - if (StringUtil::StartsWith(type, "STRUCT(") && StringUtil::EndsWith(type, ")")) { - // struct - recurse - string struct_members_str = type.substr(7, type.size() - 8); - vector struct_members_vect = StringUtil::SplitWithParentheses(struct_members_str); - child_list_t struct_members; - for (idx_t member_idx = 0; member_idx < struct_members_vect.size(); member_idx++) { - StringUtil::Trim(struct_members_vect[member_idx]); - vector struct_member_parts = StringUtil::SplitWithParentheses(struct_members_vect[member_idx], ' '); - if (struct_member_parts.size() != 2) { - throw InternalException("Ill formatted struct type: %s", type); - } - StringUtil::Trim(struct_member_parts[0]); - StringUtil::Trim(struct_member_parts[1]); - auto value_type = ParseLogicalType(struct_member_parts[1]); - struct_members.emplace_back(make_pair(struct_member_parts[0], value_type)); - } - return LogicalType::STRUCT(struct_members); - } - - LogicalType type_id = StringUtil::CIEquals(type, "ANY") ? LogicalType::ANY : TransformStringToLogicalTypeId(type); - if (type_id == LogicalTypeId::USER) { - throw InternalException("Error while generating extension function overloads - unrecognized logical type %s", - type); - } - return type_id; -} - void DBConfig::AddExtensionOption(const string &name, string description, LogicalType parameter, const Value &default_value, set_option_callback_t function) { extension_parameters.insert( @@ -416,9 +322,7 @@ void DBConfig::SetDefaultMaxMemory() { } void DBConfig::SetDefaultTempDirectory() { - if (!options.use_temporary_directory) { - options.temporary_directory = string(); - } else if (DBConfig::IsInMemoryDatabase(options.database_path.c_str())) { + if (DBConfig::IsInMemoryDatabase(options.database_path.c_str())) { options.temporary_directory = ".tmp"; } else { options.temporary_directory = options.database_path + ".tmp"; @@ -548,9 +452,8 @@ idx_t DBConfig::ParseMemoryLimit(const string &arg) { } else if (unit == "tib") { multiplier = 1024LL * 1024LL * 1024LL * 1024LL; } else { - throw ParserException("Unknown unit for memory_limit: '%s' (expected: KB, MB, GB, TB for 1000^i units or KiB, " - "MiB, GiB, TiB for 1024^i units)", - unit); + throw ParserException("Unknown unit for memory_limit: %s (expected: KB, MB, GB, TB for 1000^i units or KiB, " + "MiB, GiB, TiB for 1024^i unites)"); } return LossyNumericCast(static_cast(multiplier) * limit); } @@ -645,94 +548,6 @@ const string DBConfig::UserAgent() const { return user_agent; } -string DBConfig::SanitizeAllowedPath(const string &path) const { - auto path_sep = file_system->PathSeparator(path); - if (path_sep != "/") { - // allowed_directories/allowed_path always uses forward slashes regardless of the OS - return StringUtil::Replace(path, path_sep, "/"); - } - return path; -} - -void DBConfig::AddAllowedDirectory(const string &path) { - auto allowed_directory = SanitizeAllowedPath(path); - if (allowed_directory.empty()) { - throw InvalidInputException("Cannot provide an empty string for allowed_directory"); - } - // ensure the directory ends with a path separator - if (!StringUtil::EndsWith(allowed_directory, "/")) { - allowed_directory += "/"; - } - options.allowed_directories.insert(allowed_directory); -} - -void DBConfig::AddAllowedPath(const string &path) { - auto allowed_path = SanitizeAllowedPath(path); - options.allowed_paths.insert(allowed_path); -} - -bool DBConfig::CanAccessFile(const string &input_path, FileType type) { - if (options.enable_external_access) { - // all external access is allowed - return true; - } - string path = SanitizeAllowedPath(input_path); - if (options.allowed_paths.count(path) > 0) { - // path is explicitly allowed - return true; - } - if (options.allowed_directories.empty()) { - // no prefix directories specified - return false; - } - if (type == FileType::FILE_TYPE_DIR) { - // make sure directories end with a / - if (!StringUtil::EndsWith(path, "/")) { - path += "/"; - } - } - auto start_bound = options.allowed_directories.lower_bound(path); - if (start_bound != options.allowed_directories.begin()) { - --start_bound; - } - auto end_bound = options.allowed_directories.upper_bound(path); - - string prefix; - for (auto it = start_bound; it != end_bound; ++it) { - if (StringUtil::StartsWith(path, *it)) { - prefix = *it; - break; - } - } - if (prefix.empty()) { - // no common prefix found - path is not inside an allowed directory - return false; - } - D_ASSERT(StringUtil::EndsWith(prefix, "/")); - // path is inside an allowed directory - HOWEVER, we could still exit the allowed directory using ".." - // we check if we ever exit the allowed directory using ".." by looking at the path fragments - idx_t directory_level = 0; - idx_t current_pos = prefix.size(); - for (; current_pos < path.size(); current_pos++) { - idx_t dir_begin = current_pos; - // find either the end of the path or the directory separator - for (; path[current_pos] != '/' && current_pos < path.size(); current_pos++) { - } - idx_t path_length = current_pos - dir_begin; - if (path_length == 2 && path[dir_begin] == '.' && path[dir_begin + 1] == '.') { - // go up a directory - if (directory_level == 0) { - // we cannot go up past the prefix - return false; - } - --directory_level; - } else if (path_length > 0) { - directory_level++; - } - } - return true; -} - SerializationCompatibility SerializationCompatibility::FromString(const string &input) { if (input.empty()) { throw InvalidInputException("Version string can not be empty"); diff --git a/src/duckdb/src/main/connection.cpp b/src/duckdb/src/main/connection.cpp index 10dddcd4f..fe6fd7247 100644 --- a/src/duckdb/src/main/connection.cpp +++ b/src/duckdb/src/main/connection.cpp @@ -28,10 +28,10 @@ Connection::Connection(DatabaseInstance &database) } Connection::Connection(DuckDB &database) : Connection(*database.instance) { - warning_cb = nullptr; + // Initialization of warning_cb happens in the other constructor } -Connection::Connection(Connection &&other) noexcept { +Connection::Connection(Connection &&other) noexcept : warning_cb(nullptr) { std::swap(context, other.context); std::swap(warning_cb, other.warning_cb); } @@ -51,7 +51,11 @@ Connection::~Connection() { string Connection::GetProfilingInformation(ProfilerPrintFormat format) { auto &profiler = QueryProfiler::Get(*context); - return profiler.ToString(format); + if (format == ProfilerPrintFormat::JSON) { + return profiler.ToJSON(); + } else { + return profiler.QueryTreeToString(); + } } optional_ptr Connection::GetProfilingTree() { @@ -141,39 +145,6 @@ unique_ptr Connection::PendingQuery(unique_ptr return context->PendingQuery(std::move(statement), allow_stream_result); } -unique_ptr Connection::PendingQuery(const string &query, - case_insensitive_map_t &named_values, - bool allow_stream_result) { - return context->PendingQuery(query, named_values, allow_stream_result); -} - -unique_ptr Connection::PendingQuery(unique_ptr statement, - case_insensitive_map_t &named_values, - bool allow_stream_result) { - return context->PendingQuery(std::move(statement), named_values, allow_stream_result); -} - -static case_insensitive_map_t ConvertParamListToMap(vector ¶m_list) { - case_insensitive_map_t named_values; - for (idx_t i = 0; i < param_list.size(); i++) { - auto &val = param_list[i]; - named_values[std::to_string(i + 1)] = BoundParameterData(val); - } - return named_values; -} - -unique_ptr Connection::PendingQuery(const string &query, vector &values, - bool allow_stream_result) { - auto named_params = ConvertParamListToMap(values); - return context->PendingQuery(query, named_params, allow_stream_result); -} - -unique_ptr Connection::PendingQuery(unique_ptr statement, vector &values, - bool allow_stream_result) { - auto named_params = ConvertParamListToMap(values); - return context->PendingQuery(std::move(statement), named_params, allow_stream_result); -} - unique_ptr Connection::Prepare(const string &query) { return context->Prepare(query); } @@ -183,25 +154,19 @@ unique_ptr Connection::Prepare(unique_ptr state } unique_ptr Connection::QueryParamsRecursive(const string &query, vector &values) { - auto named_params = ConvertParamListToMap(values); - auto pending = PendingQuery(query, named_params, false); - if (pending->HasError()) { - return make_uniq(pending->GetErrorObject()); + auto statement = Prepare(query); + if (statement->HasError()) { + return make_uniq(statement->error); } - return pending->Execute(); + return statement->Execute(values, false); } -unique_ptr Connection::TableInfo(const string &database_name, const string &schema_name, - const string &table_name) { - return context->TableInfo(database_name, schema_name, table_name); +unique_ptr Connection::TableInfo(const string &table_name) { + return TableInfo(INVALID_SCHEMA, table_name); } unique_ptr Connection::TableInfo(const string &schema_name, const string &table_name) { - return TableInfo(INVALID_CATALOG, schema_name, table_name); -} - -unique_ptr Connection::TableInfo(const string &table_name) { - return TableInfo(INVALID_CATALOG, DEFAULT_SCHEMA, table_name); + return context->TableInfo(schema_name, table_name); } vector> Connection::ExtractStatements(const string &query) { @@ -230,7 +195,7 @@ shared_ptr Connection::Table(const string &table_name) { } shared_ptr Connection::Table(const string &schema_name, const string &table_name) { - auto table_info = TableInfo(INVALID_CATALOG, schema_name, table_name); + auto table_info = TableInfo(schema_name, table_name); if (!table_info) { throw CatalogException("Table '%s' does not exist!", table_name); } @@ -265,11 +230,6 @@ shared_ptr Connection::Values(const vector> &values) { return Values(values, column_names); } -shared_ptr Connection::Values(vector>> &&expressions) { - vector column_names; - return make_shared_ptr(context, std::move(expressions), column_names); -} - shared_ptr Connection::Values(const vector> &values, const vector &column_names, const string &alias) { return make_shared_ptr(context, values, column_names, alias); diff --git a/src/duckdb/src/main/database.cpp b/src/duckdb/src/main/database.cpp index 3bd387f84..0a82e4598 100644 --- a/src/duckdb/src/main/database.cpp +++ b/src/duckdb/src/main/database.cpp @@ -26,7 +26,6 @@ #include "duckdb/storage/storage_manager.hpp" #include "duckdb/transaction/transaction_manager.hpp" #include "duckdb/main/capi/extension_api.hpp" -#include "duckdb/storage/compression/empty_validity.hpp" #ifndef DUCKDB_NO_THREADS #include "duckdb/common/thread.hpp" @@ -36,8 +35,6 @@ namespace duckdb { DBConfig::DBConfig() { compression_functions = make_uniq(); - encoding_functions = make_uniq(); - encoding_functions->Initialize(*this); cast_functions = make_uniq(*this); collation_bindings = make_uniq(); index_types = make_uniq(); @@ -60,7 +57,7 @@ DBConfig::~DBConfig() { DatabaseInstance::DatabaseInstance() { config.is_user_config = false; - create_api_v1 = nullptr; + create_api_v0 = nullptr; } DatabaseInstance::~DatabaseInstance() { @@ -263,8 +260,8 @@ void DatabaseInstance::LoadExtensionSettings() { } } -static duckdb_ext_api_v1 CreateAPIv1Wrapper() { - return CreateAPIv1(); +static duckdb_ext_api_v0 CreateAPIv0Wrapper() { + return CreateAPIv0(); } void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_config) { @@ -276,7 +273,12 @@ void DatabaseInstance::Initialize(const char *database_path, DBConfig *user_conf Configure(*config_ptr, database_path); - create_api_v1 = CreateAPIv1Wrapper; + create_api_v0 = CreateAPIv0Wrapper; + + if (user_config && !user_config->options.use_temporary_directory) { + // temporary directories explicitly disabled + config.options.temporary_directory = string(); + } db_file_system = make_uniq(*this); db_manager = make_uniq(*this); @@ -416,13 +418,6 @@ void DatabaseInstance::Configure(DBConfig &new_config, const char *database_path } else { config.file_system = make_uniq(); } - if (database_path && !config.options.enable_external_access) { - config.AddAllowedPath(database_path); - config.AddAllowedPath(database_path + string(".wal")); - if (!config.options.temporary_directory.empty()) { - config.AddAllowedDirectory(config.options.temporary_directory); - } - } if (new_config.secret_manager) { config.secret_manager = std::move(new_config.secret_manager); } @@ -517,9 +512,9 @@ ValidChecker &DatabaseInstance::GetValidChecker() { return db_validity; } -const duckdb_ext_api_v1 DatabaseInstance::GetExtensionAPIV1() { - D_ASSERT(create_api_v1); - return create_api_v1(); +const duckdb_ext_api_v0 DatabaseInstance::GetExtensionAPIV0() { + D_ASSERT(create_api_v0); + return create_api_v0(); } ValidChecker &ValidChecker::Get(DatabaseInstance &db) { diff --git a/src/duckdb/src/main/database_manager.cpp b/src/duckdb/src/main/database_manager.cpp index b20394027..5750ab9f9 100644 --- a/src/duckdb/src/main/database_manager.cpp +++ b/src/duckdb/src/main/database_manager.cpp @@ -134,21 +134,17 @@ void DatabaseManager::EraseDatabasePath(const string &path) { } } -vector DatabaseManager::GetAttachedDatabasePaths() { - lock_guard path_lock(db_paths_lock); - vector paths; - for (auto &path : db_paths) { - paths.push_back(path); - } - return paths; -} - void DatabaseManager::GetDatabaseType(ClientContext &context, AttachInfo &info, const DBConfig &config, AttachOptions &options) { // Test if the database is a DuckDB database file. if (StringUtil::CIEquals(options.db_type, "DUCKDB")) { options.db_type = ""; + + // The DuckDB format does not allow unrecognized options. + if (!options.unrecognized_option.empty()) { + throw BinderException("Unrecognized option for attach \"%s\"", options.unrecognized_option); + } return; } @@ -170,6 +166,12 @@ void DatabaseManager::GetDatabaseType(ClientContext &context, AttachInfo &info, } return; } + + // The DuckDB file format does not allow unrecognized options, except for the block_size option, + // which is specific to DuckDB files. + if (!options.unrecognized_option.empty() && options.unrecognized_option != "block_size") { + throw BinderException("Unrecognized option for attach \"%s\"", options.unrecognized_option); + } } const string &DatabaseManager::GetDefaultDatabase(ClientContext &context) { diff --git a/src/duckdb/src/main/extension.cpp b/src/duckdb/src/main/extension.cpp index c13971b0c..7eba4e482 100644 --- a/src/duckdb/src/main/extension.cpp +++ b/src/duckdb/src/main/extension.cpp @@ -1,9 +1,8 @@ #include "duckdb/main/extension.hpp" - -#include "duckdb/common/operator/cast_operators.hpp" #include "duckdb/common/string_util.hpp" -#include "duckdb/main/capi/extension_api.hpp" #include "duckdb/main/extension_helper.hpp" +#include "duckdb/main/capi/extension_api.hpp" +#include "duckdb/common/operator/cast_operators.hpp" namespace duckdb { @@ -45,8 +44,7 @@ string ParsedExtensionMetaData::GetInvalidMetadataError() { string result; - // CPP or C_STRUCT_UNSTABLE ABI versioning needs to match the DuckDB version exactly - if (abi_type == ExtensionABIType::CPP || abi_type == ExtensionABIType::C_STRUCT_UNSTABLE) { + if (abi_type == ExtensionABIType::CPP) { const string engine_version = string(ExtensionHelper::GetVersionDirectoryName()); if (engine_version != duckdb_version) { @@ -54,14 +52,14 @@ string ParsedExtensionMetaData::GetInvalidMetadataError() { "built for DuckDB version '%s'.", PrettyPrintString(duckdb_version), engine_version); } - // C_STRUCT ABI versioning works when current duckdb version >= required version } else if (abi_type == ExtensionABIType::C_STRUCT) { if (!VersioningUtils::IsSupportedCAPIVersion(duckdb_capi_version)) { - result += StringUtil::Format("The file was built for DuckDB version '%s', but we can only load extensions " - "built for DuckDB C API 'v%lld.%lld.%lld' and lower.", - duckdb_capi_version, DUCKDB_EXTENSION_API_VERSION_MAJOR, - DUCKDB_EXTENSION_API_VERSION_MINOR, DUCKDB_EXTENSION_API_VERSION_PATCH); + result += + StringUtil::Format("The file was built for DuckDB C API version '%s', but we can only load extensions " + "built for DuckDB C API 'v%lld.%lld.%lld' and lower.", + duckdb_capi_version, DUCKDB_EXTENSION_API_VERSION_MAJOR, + DUCKDB_EXTENSION_API_VERSION_MINOR, DUCKDB_EXTENSION_API_VERSION_PATCH); } } else { throw InternalException("Unknown ABI type for extension: " + extension_abi_metadata); @@ -91,18 +89,11 @@ bool VersioningUtils::IsSupportedCAPIVersion(string &capi_version_string) { } bool VersioningUtils::IsSupportedCAPIVersion(idx_t major, idx_t minor, idx_t patch) { - if (major != DUCKDB_EXTENSION_API_VERSION_MAJOR) { - return false; - } - if (minor > DUCKDB_EXTENSION_API_VERSION_MINOR) { - return false; - } - if (minor < DUCKDB_EXTENSION_API_VERSION_MINOR) { - return true; - } - if (patch > DUCKDB_EXTENSION_API_VERSION_PATCH) { + if (major > DUCKDB_EXTENSION_API_VERSION_MAJOR || minor > DUCKDB_EXTENSION_API_VERSION_MINOR || + patch > DUCKDB_EXTENSION_API_VERSION_PATCH) { return false; } + return true; } diff --git a/src/duckdb/src/main/extension/extension_helper.cpp b/src/duckdb/src/main/extension/extension_helper.cpp index 2eb5e419b..0742b503b 100644 --- a/src/duckdb/src/main/extension/extension_helper.cpp +++ b/src/duckdb/src/main/extension/extension_helper.cpp @@ -12,10 +12,6 @@ // Note that c++ preprocessor doesn't have a nice way to clean this up so we need to set the defines we use to false // explicitly when they are undefined -#ifndef DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED -#define DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED false -#endif - #ifndef DUCKDB_EXTENSION_ICU_LINKED #define DUCKDB_EXTENSION_ICU_LINKED false #endif @@ -36,6 +32,10 @@ #define DUCKDB_EXTENSION_TPCDS_LINKED false #endif +#ifndef DUCKDB_EXTENSION_FTS_LINKED +#define DUCKDB_EXTENSION_FTS_LINKED false +#endif + #ifndef DUCKDB_EXTENSION_HTTPFS_LINKED #define DUCKDB_EXTENSION_HTTPFS_LINKED false #endif @@ -58,10 +58,6 @@ #else // TODO: rewrite package_build.py to allow also loading out-of-tree extensions in non-cmake builds, after that // these can be removed -#if DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED -#include "core_functions_extension.hpp" -#endif - #if DUCKDB_EXTENSION_ICU_LINKED #include "icu_extension.hpp" #endif @@ -78,6 +74,14 @@ #include "tpcds_extension.hpp" #endif +#if DUCKDB_EXTENSION_FTS_LINKED +#include "fts_extension.hpp" +#endif + +#if DUCKDB_EXTENSION_HTTPFS_LINKED +#include "httpfs_extension.hpp" +#endif + #if DUCKDB_EXTENSION_JSON_LINKED #include "json_extension.hpp" #endif @@ -89,7 +93,6 @@ #if DUCKDB_EXTENSION_AUTOCOMPLETE_LINKED #include "autocomplete_extension.hpp" #endif - #endif namespace duckdb { @@ -98,12 +101,12 @@ namespace duckdb { // Default Extensions //===--------------------------------------------------------------------===// static const DefaultExtension internal_extensions[] = { - {"core_functions", "Core function library", DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED}, {"icu", "Adds support for time zones and collations using the ICU library", DUCKDB_EXTENSION_ICU_LINKED}, {"excel", "Adds support for Excel-like format strings", DUCKDB_EXTENSION_EXCEL_LINKED}, {"parquet", "Adds support for reading and writing parquet files", DUCKDB_EXTENSION_PARQUET_LINKED}, {"tpch", "Adds TPC-H data generation and query support", DUCKDB_EXTENSION_TPCH_LINKED}, {"tpcds", "Adds TPC-DS data generation and query support", DUCKDB_EXTENSION_TPCDS_LINKED}, + {"fts", "Adds support for Full-Text Search Indexes", DUCKDB_EXTENSION_FTS_LINKED}, {"httpfs", "Adds support for reading and writing files over a HTTP(S) connection", DUCKDB_EXTENSION_HTTPFS_LINKED}, {"json", "Adds support for JSON operations", DUCKDB_EXTENSION_JSON_LINKED}, {"jemalloc", "Overwrites system allocator with JEMalloc", DUCKDB_EXTENSION_JEMALLOC_LINKED}, @@ -121,7 +124,6 @@ static const DefaultExtension internal_extensions[] = { {"iceberg", "Adds support for Apache Iceberg", false}, {"vss", "Adds indexing support to accelerate Vector Similarity Search", false}, {"delta", "Adds support for Delta Lake", false}, - {"fts", "Adds support for Full-Text Search Indexes", false}, {nullptr, nullptr, false}}; idx_t ExtensionHelper::DefaultExtensionCount() { @@ -210,8 +212,7 @@ bool ExtensionHelper::TryAutoLoadExtension(ClientContext &context, const string try { if (dbconfig.options.autoinstall_known_extensions) { auto &config = DBConfig::GetConfig(context); - auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl( - StringValue::Get(config.GetSetting(context))); + auto autoinstall_repo = ExtensionRepository::GetRepositoryByUrl(config.options.autoinstall_extension_repo); ExtensionInstallOptions options; options.repository = autoinstall_repo; ExtensionHelper::InstallExtension(context, extension_name, options); @@ -402,8 +403,8 @@ void ExtensionHelper::LoadAllExtensions(DuckDB &db) { // The in-tree extensions that we check. Non-cmake builds are currently limited to these for static linking // TODO: rewrite package_build.py to allow also loading out-of-tree extensions in non-cmake builds, after that // these can be removed - vector extensions {"parquet", "icu", "tpch", "tpcds", "httpfs", "json", - "excel", "inet", "jemalloc", "autocomplete", "core_functions"}; + unordered_set extensions {"parquet", "icu", "tpch", "tpcds", "fts", "httpfs", + "json", "excel", "inet", "jemalloc", "autocomplete"}; for (auto &ext : extensions) { LoadExtensionInternal(db, ext, true); } @@ -490,6 +491,13 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std #else // icu extension required but not build: skip this test return ExtensionLoadResult::NOT_LOADED; +#endif + } else if (extension == "fts") { +#if DUCKDB_EXTENSION_FTS_LINKED +// db.LoadStaticExtension(); +#else + // fts extension required but not build: skip this test + return ExtensionLoadResult::NOT_LOADED; #endif } else if (extension == "httpfs") { #if DUCKDB_EXTENSION_HTTPFS_LINKED @@ -531,13 +539,6 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std #else // inet extension required but not build: skip this test return ExtensionLoadResult::NOT_LOADED; -#endif - } else if (extension == "core_functions") { -#if DUCKDB_EXTENSION_CORE_FUNCTIONS_LINKED - db.LoadStaticExtension(); -#else - // core_functions extension required but not build: skip this test - return ExtensionLoadResult::NOT_LOADED; #endif } diff --git a/src/duckdb/src/main/extension/extension_install.cpp b/src/duckdb/src/main/extension/extension_install.cpp index 5675bb9ac..1258d95ea 100644 --- a/src/duckdb/src/main/extension/extension_install.cpp +++ b/src/duckdb/src/main/extension/extension_install.cpp @@ -70,13 +70,10 @@ duckdb::string ExtensionHelper::DefaultExtensionFolder(FileSystem &fs) { return res; } -string ExtensionHelper::GetExtensionDirectoryPath(ClientContext &context) { - auto &db = DatabaseInstance::GetDatabase(context); - auto &fs = FileSystem::GetFileSystem(context); - return GetExtensionDirectoryPath(db, fs); -} - -string ExtensionHelper::GetExtensionDirectoryPath(DatabaseInstance &db, FileSystem &fs) { +string ExtensionHelper::ExtensionDirectory(DatabaseInstance &db, FileSystem &fs) { +#ifdef WASM_LOADABLE_EXTENSIONS + throw PermissionException("ExtensionDirectory functionality is not supported in duckdb-wasm"); +#endif string extension_directory; auto &config = db.config; if (!config.options.extension_directory.empty()) { // create the extension directory if not present @@ -86,19 +83,10 @@ string ExtensionHelper::GetExtensionDirectoryPath(DatabaseInstance &db, FileSyst } else { // otherwise default to home extension_directory = DefaultExtensionFolder(fs); } - - extension_directory = fs.ConvertSeparators(extension_directory); - // expand ~ in extension directory - extension_directory = fs.ExpandPath(extension_directory); - return extension_directory; -} - -string ExtensionHelper::ExtensionDirectory(DatabaseInstance &db, FileSystem &fs) { -#ifdef WASM_LOADABLE_EXTENSIONS - throw PermissionException("ExtensionDirectory functionality is not supported in duckdb-wasm"); -#endif - string extension_directory = GetExtensionDirectoryPath(db, fs); { + extension_directory = fs.ConvertSeparators(extension_directory); + // expand ~ in extension directory + extension_directory = fs.ExpandPath(extension_directory); if (!fs.DirectoryExists(extension_directory)) { auto sep = fs.PathSeparator(extension_directory); auto splits = StringUtil::Split(extension_directory, sep); diff --git a/src/duckdb/src/main/extension/extension_load.cpp b/src/duckdb/src/main/extension/extension_load.cpp index 23101f722..b0282a710 100644 --- a/src/duckdb/src/main/extension/extension_load.cpp +++ b/src/duckdb/src/main/extension/extension_load.cpp @@ -25,8 +25,7 @@ namespace duckdb { //! State that is kept during the load phase of a C API extension struct DuckDBExtensionLoadState { - explicit DuckDBExtensionLoadState(DatabaseInstance &db_p, ExtensionInitResult &init_result_p) - : db(db_p), init_result(init_result_p), database_data(nullptr) { + explicit DuckDBExtensionLoadState(DatabaseInstance &db_p) : db(db_p), database_data(nullptr) { } //! Create a DuckDBExtensionLoadState reference from a C API opaque pointer @@ -43,16 +42,13 @@ struct DuckDBExtensionLoadState { //! Ref to the database being loaded DatabaseInstance &db; - //! The init result from initializing the extension - ExtensionInitResult &init_result; - //! This is the duckdb_database struct that will be passed to the extension during initialization. Note that the //! extension does not need to free it. - unique_ptr database_data; + unique_ptr database_data; //! The function pointer struct passed to the extension. The extension is expected to copy this struct during //! initialization - duckdb_ext_api_v1 api_struct; + duckdb_ext_api_v0 api_struct; //! Error handling bool has_error = false; @@ -71,15 +67,8 @@ struct ExtensionAccess { static void SetError(duckdb_extension_info info, const char *error) { auto &load_state = DuckDBExtensionLoadState::Get(info); - if (error) { - load_state.has_error = true; - load_state.error_data = ErrorData(error); - } else { - load_state.has_error = true; - load_state.error_data = ErrorData( - ExceptionType::UNKNOWN_TYPE, - "Extension has indicated an error occured during initialization, but did not set an error message."); - } + load_state.has_error = true; + load_state.error_data = ErrorData(ExceptionType::UNKNOWN_TYPE, error); } //! Called by the extension get a pointer to the database that is loading it @@ -88,8 +77,8 @@ struct ExtensionAccess { try { // Create the duckdb_database - load_state.database_data = make_uniq(); - load_state.database_data->database = make_shared_ptr(load_state.db); + load_state.database_data = make_uniq(); + load_state.database_data->database = make_uniq(load_state.db); return reinterpret_cast(load_state.database_data.get()); } catch (std::exception &ex) { load_state.error_data = ErrorData(ex); @@ -103,34 +92,22 @@ struct ExtensionAccess { //! Called by the extension get a pointer the correctly versioned extension C API struct. static const void *GetAPI(duckdb_extension_info info, const char *version) { + string version_string = version; + idx_t major, minor, patch; + auto parsed = VersioningUtils::ParseSemver(version_string, major, minor, patch); + auto &load_state = DuckDBExtensionLoadState::Get(info); - if (load_state.init_result.abi_type == ExtensionABIType::C_STRUCT) { - idx_t major, minor, patch; - auto parsed = VersioningUtils::ParseSemver(version_string, major, minor, patch); - - if (!parsed || !VersioningUtils::IsSupportedCAPIVersion(major, minor, patch)) { - load_state.has_error = true; - load_state.error_data = ErrorData( - ExceptionType::UNKNOWN_TYPE, - "Unsupported C CAPI version detected during extension initialization: " + string(version)); - return nullptr; - } - } else if (load_state.init_result.abi_type == ExtensionABIType::C_STRUCT_UNSTABLE) { - // NOTE: we currently don't check anything here: the version of extensions of ABI type C_STRUCT_UNSTABLE is - // ignored because C_STRUCT_UNSTABLE extensions are tied 1:1 to duckdb verions meaning they will always - // receive the whole function pointer struct - } else { + if (!parsed || !VersioningUtils::IsSupportedCAPIVersion(major, minor, patch)) { load_state.has_error = true; load_state.error_data = ErrorData(ExceptionType::UNKNOWN_TYPE, - StringUtil::Format("Unknown ABI Type '%s' found when loading extension '%s'", - load_state.init_result.abi_type, load_state.init_result.filename)); + "Unsupported C CAPI version detected during extension initialization: " + string(version)); return nullptr; } - load_state.api_struct = load_state.db.GetExtensionAPIV1(); + load_state.api_struct = load_state.db.GetExtensionAPIV0(); return &load_state.api_struct; } }; @@ -142,7 +119,7 @@ struct ExtensionAccess { // The C++ init function typedef void (*ext_init_fun_t)(DatabaseInstance &); // The C init function -typedef bool (*ext_init_c_api_fun_t)(duckdb_extension_info info, duckdb_extension_access *access); +typedef void (*ext_init_c_api_fun_t)(duckdb_extension_info info, duckdb_extension_access *access); typedef const char *(*ext_version_fun_t)(void); typedef bool (*ext_is_storage_t)(void); @@ -223,9 +200,6 @@ ParsedExtensionMetaData ExtensionHelper::ParseExtensionMetaData(const char *meta if (extension_abi_metadata == "C_STRUCT") { result.abi_type = ExtensionABIType::C_STRUCT; result.duckdb_capi_version = FilterZeroAtEnd(metadata_field[2]); - } else if (extension_abi_metadata == "C_STRUCT_UNSTABLE") { - result.abi_type = ExtensionABIType::C_STRUCT_UNSTABLE; - result.duckdb_version = FilterZeroAtEnd(metadata_field[2]); } else if (extension_abi_metadata == "CPP" || extension_abi_metadata.empty()) { result.abi_type = ExtensionABIType::CPP; result.duckdb_version = FilterZeroAtEnd(metadata_field[2]); @@ -451,7 +425,6 @@ bool ExtensionHelper::TryInitialLoad(DatabaseInstance &db, FileSystem &fs, const result.filebase = lowercase_extension_name; result.filename = filename; result.lib_hdl = lib_hdl; - result.abi_type = parsed_metadata.abi_type; if (!direct_load) { auto info_file_name = filename + ".info"; @@ -525,73 +498,50 @@ void ExtensionHelper::LoadExternalExtension(DatabaseInstance &db, FileSystem &fs #ifdef DUCKDB_DISABLE_EXTENSION_LOAD throw PermissionException("Loading external extensions is disabled through a compile time flag"); #else - auto extension_init_result = InitialLoad(db, fs, extension); - - // C++ ABI - if (extension_init_result.abi_type == ExtensionABIType::CPP) { - auto init_fun_name = extension_init_result.filebase + "_init"; - ext_init_fun_t init_fun = TryLoadFunctionFromDLL(extension_init_result.lib_hdl, init_fun_name, - extension_init_result.filename); - if (!init_fun) { - throw IOException("Extension '%s' did not contain the expected entrypoint function '%s'", extension, - init_fun_name); - } + auto res = InitialLoad(db, fs, extension); + auto init_fun_name = res.filebase + "_init"; + // "OLD WAY" of loading extensions. If the _init exists, we choose that + ext_init_fun_t init_fun = TryLoadFunctionFromDLL(res.lib_hdl, init_fun_name, res.filename); + if (init_fun) { try { (*init_fun)(db); } catch (std::exception &e) { ErrorData error(e); throw InvalidInputException("Initialization function \"%s\" from file \"%s\" threw an exception: \"%s\"", - init_fun_name, extension_init_result.filename, error.RawMessage()); + init_fun_name, res.filename, error.RawMessage()); } - D_ASSERT(extension_init_result.install_info); + D_ASSERT(res.install_info); - db.SetExtensionLoaded(extension, *extension_init_result.install_info); + db.SetExtensionLoaded(extension, *res.install_info); return; } - // C ABI - if (extension_init_result.abi_type == ExtensionABIType::C_STRUCT || - extension_init_result.abi_type == ExtensionABIType::C_STRUCT_UNSTABLE) { - auto init_fun_name = extension_init_result.filebase + "_init_c_api"; - ext_init_c_api_fun_t init_fun_capi = TryLoadFunctionFromDLL( - extension_init_result.lib_hdl, init_fun_name, extension_init_result.filename); - - if (!init_fun_capi) { - throw IOException("File \"%s\" did not contain function \"%s\": %s", extension_init_result.filename, - init_fun_name, GetDLError()); - } - // Create the load state - DuckDBExtensionLoadState load_state(db, extension_init_result); + // TODO: make this the only way of calling extensions? + // "NEW WAY" of loading extensions enabling C API only + init_fun_name = res.filebase + "_init_c_api"; + ext_init_c_api_fun_t init_fun_capi = + TryLoadFunctionFromDLL(res.lib_hdl, init_fun_name, res.filename); - auto access = ExtensionAccess::CreateAccessStruct(); - auto result = (*init_fun_capi)(load_state.ToCStruct(), &access); - - // Throw any error that the extension might have encountered - if (load_state.has_error) { - load_state.error_data.Throw("An error was thrown during initialization of the extension '" + extension + - "': "); - } + if (!init_fun_capi) { + throw IOException("File \"%s\" did not contain function \"%s\": %s", res.filename, init_fun_name, GetDLError()); + } - // Extensions are expected to either set an error or return true indicating successful initialization - if (result == false) { - throw FatalException( - "Extension '%s' failed to initialize but did not return an error. This indicates an " - "error in the extension: C API extensions should return a boolean `true` to indicate succesful " - "initialization. " - "This means that the Extension may be partially initialized resulting in an inconsistent state of " - "DuckDB.", - extension); - } + // Create the load state + DuckDBExtensionLoadState load_state(db); - D_ASSERT(extension_init_result.install_info); + auto access = ExtensionAccess::CreateAccessStruct(); + (*init_fun_capi)(load_state.ToCStruct(), &access); - db.SetExtensionLoaded(extension, *extension_init_result.install_info); - return; + // Throw any error that the extension might have encountered + if (load_state.has_error) { + load_state.error_data.Throw("An error was thrown during initialization of the extension '" + extension + "': "); } - throw IOException("Unknown ABI type '%s' for extension '%s'", extension_init_result.abi_type, extension); + D_ASSERT(res.install_info); + + db.SetExtensionLoaded(extension, *res.install_info); #endif } diff --git a/src/duckdb/src/main/extension/extension_util.cpp b/src/duckdb/src/main/extension/extension_util.cpp index 65e099d7e..bcad31464 100644 --- a/src/duckdb/src/main/extension/extension_util.cpp +++ b/src/duckdb/src/main/extension/extension_util.cpp @@ -24,39 +24,31 @@ void ExtensionUtil::RegisterExtension(DatabaseInstance &db, const string &name, db.AddExtensionInfo(name, description); } -void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunction function) { - ScalarFunctionSet set(function.name); - set.AddFunction(std::move(function)); - RegisterFunction(db, std::move(set)); -} - void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunctionSet set) { + D_ASSERT(!set.name.empty()); CreateScalarFunctionInfo info(std::move(set)); - info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; - RegisterFunction(db, std::move(info)); -} - -void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateScalarFunctionInfo info) { - D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); } +void ExtensionUtil::RegisterFunction(DatabaseInstance &db, ScalarFunction function) { + D_ASSERT(!function.name.empty()); + ScalarFunctionSet set(function.name); + set.AddFunction(std::move(function)); + RegisterFunction(db, std::move(set)); +} + void ExtensionUtil::RegisterFunction(DatabaseInstance &db, AggregateFunction function) { + D_ASSERT(!function.name.empty()); AggregateFunctionSet set(function.name); set.AddFunction(std::move(function)); RegisterFunction(db, std::move(set)); } void ExtensionUtil::RegisterFunction(DatabaseInstance &db, AggregateFunctionSet set) { + D_ASSERT(!set.name.empty()); CreateAggregateFunctionInfo info(std::move(set)); - info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; - RegisterFunction(db, std::move(info)); -} - -void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateAggregateFunctionInfo info) { - D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); @@ -69,6 +61,7 @@ void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateSecretFunction } void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunction function) { + D_ASSERT(!function.name.empty()); TableFunctionSet set(function.name); set.AddFunction(std::move(function)); RegisterFunction(db, std::move(set)); @@ -77,12 +70,6 @@ void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunction functio void ExtensionUtil::RegisterFunction(DatabaseInstance &db, TableFunctionSet function) { D_ASSERT(!function.name.empty()); CreateTableFunctionInfo info(std::move(function)); - info.on_conflict = OnCreateConflict::ALTER_ON_CONFLICT; - RegisterFunction(db, std::move(info)); -} - -void ExtensionUtil::RegisterFunction(DatabaseInstance &db, CreateTableFunctionInfo info) { - D_ASSERT(!info.functions.name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); system_catalog.CreateFunction(data, info); @@ -151,32 +138,24 @@ void ExtensionUtil::AddFunctionOverload(DatabaseInstance &db, TableFunctionSet f } } -optional_ptr TryGetEntry(DatabaseInstance &db, const string &name, CatalogType type) { +ScalarFunctionCatalogEntry &ExtensionUtil::GetFunction(DatabaseInstance &db, const string &name) { D_ASSERT(!name.empty()); auto &system_catalog = Catalog::GetSystemCatalog(db); auto data = CatalogTransaction::GetSystemTransaction(db); auto &schema = system_catalog.GetSchema(data, DEFAULT_SCHEMA); - return schema.GetEntry(data, type, name); -} - -optional_ptr ExtensionUtil::TryGetFunction(DatabaseInstance &db, const string &name) { - return TryGetEntry(db, name, CatalogType::SCALAR_FUNCTION_ENTRY); -} - -ScalarFunctionCatalogEntry &ExtensionUtil::GetFunction(DatabaseInstance &db, const string &name) { - auto catalog_entry = TryGetFunction(db, name); + auto catalog_entry = schema.GetEntry(data, CatalogType::SCALAR_FUNCTION_ENTRY, name); if (!catalog_entry) { throw InvalidInputException("Function with name \"%s\" not found in ExtensionUtil::GetFunction", name); } return catalog_entry->Cast(); } -optional_ptr ExtensionUtil::TryGetTableFunction(DatabaseInstance &db, const string &name) { - return TryGetEntry(db, name, CatalogType::TABLE_FUNCTION_ENTRY); -} - TableFunctionCatalogEntry &ExtensionUtil::GetTableFunction(DatabaseInstance &db, const string &name) { - auto catalog_entry = TryGetTableFunction(db, name); + D_ASSERT(!name.empty()); + auto &system_catalog = Catalog::GetSystemCatalog(db); + auto data = CatalogTransaction::GetSystemTransaction(db); + auto &schema = system_catalog.GetSchema(data, DEFAULT_SCHEMA); + auto catalog_entry = schema.GetEntry(data, CatalogType::TABLE_FUNCTION_ENTRY, name); if (!catalog_entry) { throw InvalidInputException("Function with name \"%s\" not found in ExtensionUtil::GetTableFunction", name); } @@ -184,7 +163,7 @@ TableFunctionCatalogEntry &ExtensionUtil::GetTableFunction(DatabaseInstance &db, } void ExtensionUtil::RegisterType(DatabaseInstance &db, string type_name, LogicalType type, - bind_logical_type_function_t bind_modifiers) { + bind_type_modifiers_function_t bind_modifiers) { D_ASSERT(!type_name.empty()); CreateTypeInfo info(std::move(type_name), std::move(type), bind_modifiers); info.temporary = true; diff --git a/src/duckdb/src/main/profiling_info.cpp b/src/duckdb/src/main/profiling_info.cpp index 4ce68b76d..0614747a9 100644 --- a/src/duckdb/src/main/profiling_info.cpp +++ b/src/duckdb/src/main/profiling_info.cpp @@ -14,7 +14,6 @@ ProfilingInfo::ProfilingInfo(const profiler_settings_t &n_settings, const idx_t if (depth == 0) { settings.insert(MetricsType::QUERY_NAME); } else { - settings.insert(MetricsType::OPERATOR_NAME); settings.insert(MetricsType::OPERATOR_TYPE); } for (const auto &metric : settings) { @@ -37,19 +36,10 @@ ProfilingInfo::ProfilingInfo(const profiler_settings_t &n_settings, const idx_t } profiler_settings_t ProfilingInfo::DefaultSettings() { - return {MetricsType::QUERY_NAME, - MetricsType::BLOCKED_THREAD_TIME, - MetricsType::CPU_TIME, - MetricsType::EXTRA_INFO, - MetricsType::CUMULATIVE_CARDINALITY, - MetricsType::OPERATOR_NAME, - MetricsType::OPERATOR_TYPE, - MetricsType::OPERATOR_CARDINALITY, - MetricsType::CUMULATIVE_ROWS_SCANNED, - MetricsType::OPERATOR_ROWS_SCANNED, - MetricsType::OPERATOR_TIMING, - MetricsType::RESULT_SET_SIZE, - MetricsType::LATENCY, + return {MetricsType::QUERY_NAME, MetricsType::BLOCKED_THREAD_TIME, MetricsType::CPU_TIME, + MetricsType::EXTRA_INFO, MetricsType::CUMULATIVE_CARDINALITY, MetricsType::OPERATOR_TYPE, + MetricsType::OPERATOR_CARDINALITY, MetricsType::CUMULATIVE_ROWS_SCANNED, MetricsType::OPERATOR_ROWS_SCANNED, + MetricsType::OPERATOR_TIMING, MetricsType::RESULT_SET_SIZE, MetricsType::LATENCY, MetricsType::ROWS_RETURNED}; } @@ -60,7 +50,7 @@ profiler_settings_t ProfilingInfo::DefaultRootSettings() { profiler_settings_t ProfilingInfo::DefaultOperatorSettings() { return {MetricsType::OPERATOR_CARDINALITY, MetricsType::OPERATOR_ROWS_SCANNED, MetricsType::OPERATOR_TIMING, - MetricsType::OPERATOR_NAME, MetricsType::OPERATOR_TYPE}; + MetricsType::OPERATOR_TYPE}; } void ProfilingInfo::ResetMetrics() { @@ -81,9 +71,6 @@ void ProfilingInfo::ResetMetrics() { case MetricsType::OPERATOR_TIMING: metrics[metric] = Value::CreateValue(0.0); break; - case MetricsType::OPERATOR_NAME: - metrics[metric] = Value::CreateValue(""); - break; case MetricsType::OPERATOR_TYPE: metrics[metric] = Value::CreateValue(0); break; @@ -198,7 +185,6 @@ void ProfilingInfo::WriteMetricsToJSON(yyjson_mut_doc *doc, yyjson_mut_val *dest switch (metric) { case MetricsType::QUERY_NAME: - case MetricsType::OPERATOR_NAME: yyjson_mut_obj_add_strcpy(doc, dest, key_ptr, metrics[metric].GetValue().c_str()); break; case MetricsType::LATENCY: diff --git a/src/duckdb/src/main/query_profiler.cpp b/src/duckdb/src/main/query_profiler.cpp index 03889af52..4f91d46d5 100644 --- a/src/duckdb/src/main/query_profiler.cpp +++ b/src/duckdb/src/main/query_profiler.cpp @@ -8,12 +8,13 @@ #include "duckdb/common/tree_renderer/text_tree_renderer.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/operator/helper/physical_execute.hpp" -#include "duckdb/execution/operator/scan/physical_table_scan.hpp" #include "duckdb/execution/physical_operator.hpp" #include "duckdb/main/client_config.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/client_data.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/execution/operator/scan/physical_table_scan.hpp" + #include "yyjson.hpp" #include @@ -45,35 +46,12 @@ ProfilerPrintFormat QueryProfiler::GetPrintFormat(ExplainFormat format) const { return ProfilerPrintFormat::QUERY_TREE; case ExplainFormat::JSON: return ProfilerPrintFormat::JSON; - case ExplainFormat::HTML: - return ProfilerPrintFormat::HTML; - case ExplainFormat::GRAPHVIZ: - return ProfilerPrintFormat::GRAPHVIZ; default: throw NotImplementedException("No mapping from ExplainFormat::%s to ProfilerPrintFormat", EnumUtil::ToString(format)); } } -ExplainFormat QueryProfiler::GetExplainFormat(ProfilerPrintFormat format) const { - switch (format) { - case ProfilerPrintFormat::QUERY_TREE: - case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: - return ExplainFormat::TEXT; - case ProfilerPrintFormat::JSON: - return ExplainFormat::JSON; - case ProfilerPrintFormat::HTML: - return ExplainFormat::HTML; - case ProfilerPrintFormat::GRAPHVIZ: - return ExplainFormat::GRAPHVIZ; - case ProfilerPrintFormat::NO_OUTPUT: - throw InternalException("Should not attempt to get ExplainFormat for ProfilerPrintFormat::NO_OUTPUT"); - default: - throw NotImplementedException("No mapping from ProfilePrintFormat::%s to ExplainFormat", - EnumUtil::ToString(format)); - } -} - bool QueryProfiler::PrintOptimizerOutput() const { return GetPrintFormat() == ProfilerPrintFormat::QUERY_TREE_OPTIMIZER || IsDetailedEnabled(); } @@ -87,7 +65,6 @@ QueryProfiler &QueryProfiler::Get(ClientContext &context) { } void QueryProfiler::StartQuery(string query, bool is_explain_analyze_p, bool start_at_optimizer) { - lock_guard guard(lock); if (is_explain_analyze_p) { StartExplainAnalyze(); } @@ -197,7 +174,7 @@ Value GetCumulativeOptimizers(ProfilingNode &node) { } void QueryProfiler::EndQuery() { - unique_lock guard(lock); + lock_guard guard(flush_lock); if (!IsEnabled() || !running) { return; } @@ -211,8 +188,6 @@ void QueryProfiler::EndQuery() { } running = false; - bool emit_output = false; - // Print or output the query profiling after query termination. // EXPLAIN ANALYZE output is not written by the profiler. if (IsEnabled() && !is_explain_analyze) { @@ -253,36 +228,24 @@ void QueryProfiler::EndQuery() { } } - if (ClientConfig::GetConfig(context).emit_profiler_output) { - emit_output = true; - } - } - - is_explain_analyze = false; - - guard.unlock(); - - if (emit_output) { string tree = ToString(); auto save_location = GetSaveLocation(); - if (save_location.empty()) { + if (!ClientConfig::GetConfig(context).emit_profiler_output) { + // disable output + } else if (save_location.empty()) { Printer::Print(tree); Printer::Print("\n"); } else { WriteToFile(save_location.c_str(), tree); } } -} -string QueryProfiler::ToString(ExplainFormat explain_format) const { - return ToString(GetPrintFormat(explain_format)); + is_explain_analyze = false; } -string QueryProfiler::ToString(ProfilerPrintFormat format) const { - if (!IsEnabled()) { - return RenderDisabledMessage(format); - } +string QueryProfiler::ToString(ExplainFormat explain_format) const { + const auto format = GetPrintFormat(explain_format); switch (format) { case ProfilerPrintFormat::QUERY_TREE: case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: @@ -291,30 +254,12 @@ string QueryProfiler::ToString(ProfilerPrintFormat format) const { return ToJSON(); case ProfilerPrintFormat::NO_OUTPUT: return ""; - case ProfilerPrintFormat::HTML: - case ProfilerPrintFormat::GRAPHVIZ: { - lock_guard guard(lock); - // checking the tree to ensure the query is really empty - // the query string is empty when a logical plan is deserialized - if (query_info.query_name.empty() && !root) { - return ""; - } - auto renderer = TreeRenderer::CreateRenderer(GetExplainFormat(format)); - std::stringstream str; - auto &info = root->GetProfilingInfo(); - if (info.Enabled(info.expanded_settings, MetricsType::OPERATOR_TIMING)) { - info.metrics[MetricsType::OPERATOR_TIMING] = main_query.Elapsed(); - } - renderer->Render(*root, str); - return str.str(); - } default: throw InternalException("Unknown ProfilerPrintFormat \"%s\"", EnumUtil::ToString(format)); } } void QueryProfiler::StartPhase(MetricsType phase_metric) { - lock_guard guard(lock); if (!IsEnabled() || !running) { return; } @@ -326,7 +271,6 @@ void QueryProfiler::StartPhase(MetricsType phase_metric) { } void QueryProfiler::EndPhase() { - lock_guard guard(lock); if (!IsEnabled() || !running) { return; } @@ -372,17 +316,9 @@ void OperatorProfiler::StartOperator(optional_ptr phys_o } active_operator = phys_op; - if (!settings.empty()) { - if (ProfilingInfo::Enabled(settings, MetricsType::EXTRA_INFO)) { - auto &info = GetOperatorInfo(*active_operator); - auto params = active_operator->ParamsToString(); - info.extra_info = params; - } - - // Start the timing of the current operator. - if (ProfilingInfo::Enabled(settings, MetricsType::OPERATOR_TIMING)) { - op.Start(); - } + // Start the timing of the current operator. + if (ProfilingInfo::Enabled(settings, MetricsType::OPERATOR_TIMING)) { + op.Start(); } } @@ -412,32 +348,30 @@ void OperatorProfiler::EndOperator(optional_ptr chunk) { } OperatorInformation &OperatorProfiler::GetOperatorInfo(const PhysicalOperator &phys_op) { - auto entry = operator_infos.find(phys_op); - if (entry != operator_infos.end()) { + auto entry = timings.find(phys_op); + if (entry != timings.end()) { return entry->second; } - // Add a new entry. - operator_infos[phys_op] = OperatorInformation(); - return operator_infos[phys_op]; + timings[phys_op] = OperatorInformation(); + return timings[phys_op]; } void OperatorProfiler::Flush(const PhysicalOperator &phys_op) { - auto entry = operator_infos.find(phys_op); - if (entry == operator_infos.end()) { + auto entry = timings.find(phys_op); + if (entry == timings.end()) { return; } - - auto &info = operator_infos.find(phys_op)->second; - info.name = phys_op.GetName(); + auto &operator_timing = timings.find(phys_op)->second; + operator_timing.name = phys_op.GetName(); } void QueryProfiler::Flush(OperatorProfiler &profiler) { - lock_guard guard(lock); + lock_guard guard(flush_lock); if (!IsEnabled() || !running) { return; } - for (auto &node : profiler.operator_infos) { + for (auto &node : profiler.timings) { auto &op = node.first.get(); auto entry = tree_map.find(op); D_ASSERT(entry != tree_map.end()); @@ -467,15 +401,12 @@ void QueryProfiler::Flush(OperatorProfiler &profiler) { if (ProfilingInfo::Enabled(profiler.settings, MetricsType::RESULT_SET_SIZE)) { info.AddToMetric(MetricsType::RESULT_SET_SIZE, node.second.result_set_size); } - if (ProfilingInfo::Enabled(profiler.settings, MetricsType::EXTRA_INFO)) { - info.extra_info = node.second.extra_info; - } } - profiler.operator_infos.clear(); + profiler.timings.clear(); } void QueryProfiler::SetInfo(const double &blocked_thread_time) { - lock_guard guard(lock); + lock_guard guard(flush_lock); if (!IsEnabled() || !running) { return; } @@ -591,7 +522,10 @@ void PrintPhaseTimingsToStream(std::ostream &ss, const ProfilingInfo &info, idx_ } void QueryProfiler::QueryTreeToStream(std::ostream &ss) const { - lock_guard guard(lock); + if (!IsEnabled()) { + ss << "Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"; + return; + } ss << "┌─────────────────────────────────────┐\n"; ss << "│┌───────────────────────────────────┐│\n"; ss << "││ Query Profiling Information ││\n"; @@ -616,12 +550,12 @@ void QueryProfiler::QueryTreeToStream(std::ostream &ss) const { ss << "││" + DrawPadded(total_time, TOTAL_BOX_WIDTH - 4) + "││\n"; ss << "│└──────────────────────────────────────────────┘│\n"; ss << "└────────────────────────────────────────────────┘\n"; + // print phase timings + if (PrintOptimizerOutput()) { + PrintPhaseTimingsToStream(ss, root->GetProfilingInfo(), TOTAL_BOX_WIDTH); + } // render the main operator tree if (root) { - // print phase timings - if (PrintOptimizerOutput()) { - PrintPhaseTimingsToStream(ss, root->GetProfilingInfo(), TOTAL_BOX_WIDTH); - } Render(*root, ss); } } @@ -703,11 +637,14 @@ static string StringifyAndFree(yyjson_mut_doc *doc, yyjson_mut_val *object) { } string QueryProfiler::ToJSON() const { - lock_guard guard(lock); auto doc = yyjson_mut_doc_new(nullptr); auto result_obj = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, result_obj); + if (!IsEnabled()) { + yyjson_mut_obj_add_str(doc, result_obj, "result", "disabled"); + return StringifyAndFree(doc, result_obj); + } if (query_info.query_name.empty() && !root) { yyjson_mut_obj_add_str(doc, result_obj, "result", "empty"); return StringifyAndFree(doc, result_obj); @@ -772,7 +709,6 @@ unique_ptr QueryProfiler::CreateTree(const PhysicalOperator &root node->depth = depth; if (depth != 0) { - info.metrics[MetricsType::OPERATOR_NAME] = root_p.GetName(); info.AddToMetric(MetricsType::OPERATOR_TYPE, static_cast(root_p.type)); } if (info.Enabled(info.settings, MetricsType::EXTRA_INFO)) { @@ -788,42 +724,7 @@ unique_ptr QueryProfiler::CreateTree(const PhysicalOperator &root return node; } -string QueryProfiler::RenderDisabledMessage(ProfilerPrintFormat format) const { - switch (format) { - case ProfilerPrintFormat::NO_OUTPUT: - return ""; - case ProfilerPrintFormat::QUERY_TREE: - case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: - return "Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"; - case ProfilerPrintFormat::HTML: - return R"( - - - Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling! - - )"; - case ProfilerPrintFormat::GRAPHVIZ: - return R"( - digraph G { - node [shape=box, style=rounded, fontname="Courier New", fontsize=10]; - node_0_0 [label="Query profiling is disabled. Use 'PRAGMA enable_profiling;' to enable profiling!"]; - } - )"; - case ProfilerPrintFormat::JSON: { - auto doc = yyjson_mut_doc_new(nullptr); - auto result_obj = yyjson_mut_obj(doc); - yyjson_mut_doc_set_root(doc, result_obj); - - yyjson_mut_obj_add_str(doc, result_obj, "result", "disabled"); - return StringifyAndFree(doc, result_obj); - } - default: - throw InternalException("Unknown ProfilerPrintFormat \"%s\"", EnumUtil::ToString(format)); - } -} - void QueryProfiler::Initialize(const PhysicalOperator &root_op) { - lock_guard guard(lock); if (!IsEnabled() || !running) { return; } diff --git a/src/duckdb/src/main/relation.cpp b/src/duckdb/src/main/relation.cpp index 9154822f9..95a4c6bbd 100644 --- a/src/duckdb/src/main/relation.cpp +++ b/src/duckdb/src/main/relation.cpp @@ -38,7 +38,7 @@ shared_ptr Relation::Project(const string &expression, const string &a } shared_ptr Relation::Project(const string &select_list, const vector &aliases) { - auto expressions = Parser::ParseExpressionList(select_list, context->GetContext()->GetParserOptions()); + auto expressions = Parser::ParseExpressionList(select_list, context.GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); } @@ -52,7 +52,7 @@ shared_ptr Relation::Project(vector> expr return make_shared_ptr(shared_from_this(), std::move(expressions), aliases); } -static vector> StringListToExpressionList(const ClientContext &context, +static vector> StringListToExpressionList(ClientContext &context, const vector &expressions) { if (expressions.empty()) { throw ParserException("Zero expressions provided"); @@ -69,12 +69,12 @@ static vector> StringListToExpressionList(const Cli } shared_ptr Relation::Project(const vector &expressions, const vector &aliases) { - auto result_list = StringListToExpressionList(*context->GetContext(), expressions); + auto result_list = StringListToExpressionList(*context.GetContext(), expressions); return make_shared_ptr(shared_from_this(), std::move(result_list), aliases); } shared_ptr Relation::Filter(const string &expression) { - auto expression_list = Parser::ParseExpressionList(expression, context->GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(expression, context.GetContext()->GetParserOptions()); if (expression_list.size() != 1) { throw ParserException("Expected a single expression as filter condition"); } @@ -87,7 +87,7 @@ shared_ptr Relation::Filter(unique_ptr expression) { shared_ptr Relation::Filter(const vector &expressions) { // if there are multiple expressions, we AND them together - auto expression_list = StringListToExpressionList(*context->GetContext(), expressions); + auto expression_list = StringListToExpressionList(*context.GetContext(), expressions); D_ASSERT(!expression_list.empty()); auto expr = std::move(expression_list[0]); @@ -103,7 +103,7 @@ shared_ptr Relation::Limit(int64_t limit, int64_t offset) { } shared_ptr Relation::Order(const string &expression) { - auto order_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); + auto order_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions()); return Order(std::move(order_list)); } @@ -117,7 +117,7 @@ shared_ptr Relation::Order(const vector &expressions) { } vector order_list; for (auto &expression : expressions) { - auto inner_list = Parser::ParseOrderList(expression, context->GetContext()->GetParserOptions()); + auto inner_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions()); if (inner_list.size() != 1) { throw ParserException("Expected a single ORDER BY expression in the expression list"); } @@ -128,7 +128,7 @@ shared_ptr Relation::Order(const vector &expressions) { shared_ptr Relation::Join(const shared_ptr &other, const string &condition, JoinType type, JoinRefType ref_type) { - auto expression_list = Parser::ParseExpressionList(condition, context->GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(condition, context.GetContext()->GetParserOptions()); D_ASSERT(!expression_list.empty()); return Join(other, std::move(expression_list), type, ref_type); } @@ -136,11 +136,11 @@ shared_ptr Relation::Join(const shared_ptr &other, const str shared_ptr Relation::Join(const shared_ptr &other, vector> expression_list, JoinType type, JoinRefType ref_type) { - if (expression_list.size() > 1 || expression_list[0]->GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expression_list.size() > 1 || expression_list[0]->type == ExpressionType::COLUMN_REF) { // multiple columns or single column ref: the condition is a USING list vector using_columns; for (auto &expr : expression_list) { - if (expr->GetExpressionType() != ExpressionType::COLUMN_REF) { + if (expr->type != ExpressionType::COLUMN_REF) { throw ParserException("Expected a single expression as join condition"); } auto &colref = expr->Cast(); @@ -181,7 +181,7 @@ shared_ptr Relation::Alias(const string &alias) { } shared_ptr Relation::Aggregate(const string &aggregate_list) { - auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expression_list)); } @@ -190,13 +190,13 @@ shared_ptr Relation::Aggregate(vector> ex } shared_ptr Relation::Aggregate(const string &aggregate_list, const string &group_list) { - auto expression_list = Parser::ParseExpressionList(aggregate_list, context->GetContext()->GetParserOptions()); - auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); + auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions()); + auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expression_list), std::move(groups)); } shared_ptr Relation::Aggregate(const vector &aggregates) { - auto aggregate_list = StringListToExpressionList(*context->GetContext(), aggregates); + auto aggregate_list = StringListToExpressionList(*context.GetContext(), aggregates); return make_shared_ptr(shared_from_this(), std::move(aggregate_list)); } @@ -207,12 +207,12 @@ shared_ptr Relation::Aggregate(const vector &aggregates, const } shared_ptr Relation::Aggregate(vector> expressions, const string &group_list) { - auto groups = Parser::ParseGroupByList(group_list, context->GetContext()->GetParserOptions()); + auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions()); return make_shared_ptr(shared_from_this(), std::move(expressions), std::move(groups)); } string Relation::GetAlias() { - return alias; + return "relation"; } unique_ptr Relation::GetTableRef() { @@ -222,7 +222,7 @@ unique_ptr Relation::GetTableRef() { } unique_ptr Relation::Execute() { - return context->GetContext()->Execute(shared_from_this()); + return context.GetContext()->Execute(shared_from_this()); } unique_ptr Relation::ExecuteOrThrow() { @@ -259,29 +259,20 @@ void Relation::Insert(const string &schema_name, const string &table_name) { void Relation::Insert(const vector> &values) { vector column_names; - auto rel = make_shared_ptr(context->GetContext(), values, std::move(column_names), "values"); + auto rel = make_shared_ptr(context.GetContext(), values, std::move(column_names), "values"); rel->Insert(GetAlias()); } -void Relation::Insert(vector>> &&expressions) { - vector column_names; - auto rel = make_shared_ptr(context->GetContext(), std::move(expressions), std::move(column_names), - "values"); - rel->Insert(GetAlias()); +shared_ptr Relation::CreateRel(const string &schema_name, const string &table_name, bool temporary) { + return make_shared_ptr(shared_from_this(), schema_name, table_name, temporary); } -shared_ptr Relation::CreateRel(const string &schema_name, const string &table_name, bool temporary, - OnCreateConflict on_conflict) { - return make_shared_ptr(shared_from_this(), schema_name, table_name, temporary, on_conflict); +void Relation::Create(const string &table_name, bool temporary) { + Create(INVALID_SCHEMA, table_name, temporary); } -void Relation::Create(const string &table_name, bool temporary, OnCreateConflict on_conflict) { - Create(INVALID_SCHEMA, table_name, temporary, on_conflict); -} - -void Relation::Create(const string &schema_name, const string &table_name, bool temporary, - OnCreateConflict on_conflict) { - auto create = CreateRel(schema_name, table_name, temporary, on_conflict); +void Relation::Create(const string &schema_name, const string &table_name, bool temporary) { + auto create = CreateRel(schema_name, table_name, temporary); auto res = create->Execute(); if (res->HasError()) { const string prepended_message = "Failed to create table '" + table_name + "': "; @@ -332,8 +323,8 @@ shared_ptr Relation::CreateView(const string &schema_name, const strin return shared_from_this(); } -unique_ptr Relation::Query(const string &sql) const { - return context->GetContext()->Query(sql, false); +unique_ptr Relation::Query(const string &sql) { + return context.GetContext()->Query(sql, false); } unique_ptr Relation::Query(const string &name, const string &sql) { @@ -348,34 +339,22 @@ unique_ptr Relation::Explain(ExplainType type, ExplainFormat format return explain->Execute(); } -void Relation::TryBindRelation(vector &columns) { - context->TryBindRelation(*this, columns); -} - void Relation::Update(const string &update, const string &condition) { throw InvalidInputException("UPDATE can only be used on base tables!"); } -void Relation::Update(vector, // NOLINT: unused variable / copied on every invocation ... - vector> &&update, // NOLINT: unused variable - unique_ptr condition) { // NOLINT: unused variable - (void)std::move(update); - (void)std::move(condition); - throw InvalidInputException("UPDATE can only be used on base tables!"); -} - void Relation::Delete(const string &condition) { throw InvalidInputException("DELETE can only be used on base tables!"); } shared_ptr Relation::TableFunction(const std::string &fname, const vector &values, const named_parameter_map_t &named_parameters) { - return make_shared_ptr(context->GetContext(), fname, values, named_parameters, + return make_shared_ptr(context.GetContext(), fname, values, named_parameters, shared_from_this()); } shared_ptr Relation::TableFunction(const std::string &fname, const vector &values) { - return make_shared_ptr(context->GetContext(), fname, values, shared_from_this()); + return make_shared_ptr(context.GetContext(), fname, values, shared_from_this()); } string Relation::ToString() { diff --git a/src/duckdb/src/main/relation/aggregate_relation.cpp b/src/duckdb/src/main/relation/aggregate_relation.cpp index daf663e3b..c84036ad4 100644 --- a/src/duckdb/src/main/relation/aggregate_relation.cpp +++ b/src/duckdb/src/main/relation/aggregate_relation.cpp @@ -10,7 +10,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, : Relation(child_p->context, RelationType::AGGREGATE_RELATION), expressions(std::move(parsed_expressions)), child(std::move(child_p)) { // bind the expressions - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } AggregateRelation::AggregateRelation(shared_ptr child_p, @@ -18,7 +18,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, : Relation(child_p->context, RelationType::AGGREGATE_RELATION), expressions(std::move(parsed_expressions)), groups(std::move(groups_p)), child(std::move(child_p)) { // bind the expressions - Relation::TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } AggregateRelation::AggregateRelation(shared_ptr child_p, @@ -36,7 +36,7 @@ AggregateRelation::AggregateRelation(shared_ptr child_p, groups.grouping_sets.push_back(std::move(grouping_set)); } // bind the expressions - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr AggregateRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/create_table_relation.cpp b/src/duckdb/src/main/relation/create_table_relation.cpp index 2492f244b..bff69e3aa 100644 --- a/src/duckdb/src/main/relation/create_table_relation.cpp +++ b/src/duckdb/src/main/relation/create_table_relation.cpp @@ -7,11 +7,10 @@ namespace duckdb { CreateTableRelation::CreateTableRelation(shared_ptr child_p, string schema_name, string table_name, - bool temporary_p, OnCreateConflict on_conflict) + bool temporary_p) : Relation(child_p->context, RelationType::CREATE_TABLE_RELATION), child(std::move(child_p)), - schema_name(std::move(schema_name)), table_name(std::move(table_name)), temporary(temporary_p), - on_conflict(on_conflict) { - TryBindRelation(columns); + schema_name(std::move(schema_name)), table_name(std::move(table_name)), temporary(temporary_p) { + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement CreateTableRelation::Bind(Binder &binder) { @@ -23,7 +22,7 @@ BoundStatement CreateTableRelation::Bind(Binder &binder) { info->schema = schema_name; info->table = table_name; info->query = std::move(select); - info->on_conflict = on_conflict; + info->on_conflict = OnCreateConflict::ERROR_ON_CONFLICT; info->temporary = temporary; stmt.info = std::move(info); return binder.Bind(stmt.Cast()); diff --git a/src/duckdb/src/main/relation/create_view_relation.cpp b/src/duckdb/src/main/relation/create_view_relation.cpp index c00deef38..b9c80c074 100644 --- a/src/duckdb/src/main/relation/create_view_relation.cpp +++ b/src/duckdb/src/main/relation/create_view_relation.cpp @@ -9,7 +9,7 @@ CreateViewRelation::CreateViewRelation(shared_ptr child_p, string view bool temporary_p) : Relation(child_p->context, RelationType::CREATE_VIEW_RELATION), child(std::move(child_p)), view_name(std::move(view_name_p)), replace(replace_p), temporary(temporary_p) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } CreateViewRelation::CreateViewRelation(shared_ptr child_p, string schema_name_p, string view_name_p, @@ -17,7 +17,7 @@ CreateViewRelation::CreateViewRelation(shared_ptr child_p, string sche : Relation(child_p->context, RelationType::CREATE_VIEW_RELATION), child(std::move(child_p)), schema_name(std::move(schema_name_p)), view_name(std::move(view_name_p)), replace(replace_p), temporary(temporary_p) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement CreateViewRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/cross_product_relation.cpp b/src/duckdb/src/main/relation/cross_product_relation.cpp index e0645fae1..ca3abfbed 100644 --- a/src/duckdb/src/main/relation/cross_product_relation.cpp +++ b/src/duckdb/src/main/relation/cross_product_relation.cpp @@ -10,10 +10,10 @@ CrossProductRelation::CrossProductRelation(shared_ptr left_p, shared_p JoinRefType ref_type) : Relation(left_p->context, RelationType::CROSS_PRODUCT_RELATION), left(std::move(left_p)), right(std::move(right_p)), ref_type(ref_type) { - if (left->context->GetContext() != right->context->GetContext()) { + if (left->context.GetContext() != right->context.GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr CrossProductRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/delete_relation.cpp b/src/duckdb/src/main/relation/delete_relation.cpp index bbc0d58ef..8afc8226e 100644 --- a/src/duckdb/src/main/relation/delete_relation.cpp +++ b/src/duckdb/src/main/relation/delete_relation.cpp @@ -6,11 +6,11 @@ namespace duckdb { -DeleteRelation::DeleteRelation(shared_ptr &context, unique_ptr condition_p, +DeleteRelation::DeleteRelation(ClientContextWrapper &context, unique_ptr condition_p, string schema_name_p, string table_name_p) : Relation(context, RelationType::DELETE_RELATION), condition(std::move(condition_p)), schema_name(std::move(schema_name_p)), table_name(std::move(table_name_p)) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement DeleteRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/delim_get_relation.cpp b/src/duckdb/src/main/relation/delim_get_relation.cpp index 3f1b9cbc8..6613c60d8 100644 --- a/src/duckdb/src/main/relation/delim_get_relation.cpp +++ b/src/duckdb/src/main/relation/delim_get_relation.cpp @@ -8,7 +8,7 @@ namespace duckdb { DelimGetRelation::DelimGetRelation(const shared_ptr &context, vector chunk_types_p) : Relation(context, RelationType::DELIM_GET_RELATION), chunk_types(std::move(chunk_types_p)) { - TryBindRelation(columns); + context->TryBindRelation(*this, this->columns); } unique_ptr DelimGetRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/distinct_relation.cpp b/src/duckdb/src/main/relation/distinct_relation.cpp index 16bb53822..0f96d4580 100644 --- a/src/duckdb/src/main/relation/distinct_relation.cpp +++ b/src/duckdb/src/main/relation/distinct_relation.cpp @@ -8,7 +8,7 @@ DistinctRelation::DistinctRelation(shared_ptr child_p) : Relation(child_p->context, RelationType::DISTINCT_RELATION), child(std::move(child_p)) { D_ASSERT(child.get() != this); vector dummy_columns; - TryBindRelation(dummy_columns); + context.GetContext()->TryBindRelation(*this, dummy_columns); } unique_ptr DistinctRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/explain_relation.cpp b/src/duckdb/src/main/relation/explain_relation.cpp index f91e1d29f..9b8ed1edb 100644 --- a/src/duckdb/src/main/relation/explain_relation.cpp +++ b/src/duckdb/src/main/relation/explain_relation.cpp @@ -10,7 +10,7 @@ namespace duckdb { ExplainRelation::ExplainRelation(shared_ptr child_p, ExplainType type, ExplainFormat format) : Relation(child_p->context, RelationType::EXPLAIN_RELATION), child(std::move(child_p)), type(type), format(format) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement ExplainRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/filter_relation.cpp b/src/duckdb/src/main/relation/filter_relation.cpp index 738e83577..2abaa41aa 100644 --- a/src/duckdb/src/main/relation/filter_relation.cpp +++ b/src/duckdb/src/main/relation/filter_relation.cpp @@ -12,7 +12,7 @@ FilterRelation::FilterRelation(shared_ptr child_p, unique_ptr dummy_columns; - TryBindRelation(dummy_columns); + context.GetContext()->TryBindRelation(*this, dummy_columns); } unique_ptr FilterRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/insert_relation.cpp b/src/duckdb/src/main/relation/insert_relation.cpp index 9728570a0..c6738d486 100644 --- a/src/duckdb/src/main/relation/insert_relation.cpp +++ b/src/duckdb/src/main/relation/insert_relation.cpp @@ -10,7 +10,7 @@ namespace duckdb { InsertRelation::InsertRelation(shared_ptr child_p, string schema_name, string table_name) : Relation(child_p->context, RelationType::INSERT_RELATION), child(std::move(child_p)), schema_name(std::move(schema_name)), table_name(std::move(table_name)) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement InsertRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/join_relation.cpp b/src/duckdb/src/main/relation/join_relation.cpp index b3701ea39..3d9572f76 100644 --- a/src/duckdb/src/main/relation/join_relation.cpp +++ b/src/duckdb/src/main/relation/join_relation.cpp @@ -4,7 +4,6 @@ #include "duckdb/parser/expression/star_expression.hpp" #include "duckdb/parser/tableref/joinref.hpp" #include "duckdb/common/enum_util.hpp" -#include "duckdb/main/client_context_wrapper.hpp" namespace duckdb { @@ -12,20 +11,20 @@ JoinRelation::JoinRelation(shared_ptr left_p, shared_ptr rig unique_ptr condition_p, JoinType type, JoinRefType join_ref_type) : Relation(left_p->context, RelationType::JOIN_RELATION), left(std::move(left_p)), right(std::move(right_p)), condition(std::move(condition_p)), join_type(type), join_ref_type(join_ref_type) { - if (left->context->GetContext() != right->context->GetContext()) { + if (left->context.GetContext() != right->context.GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } JoinRelation::JoinRelation(shared_ptr left_p, shared_ptr right_p, vector using_columns_p, JoinType type, JoinRefType join_ref_type) : Relation(left_p->context, RelationType::JOIN_RELATION), left(std::move(left_p)), right(std::move(right_p)), using_columns(std::move(using_columns_p)), join_type(type), join_ref_type(join_ref_type) { - if (left->context->GetContext() != right->context->GetContext()) { + if (left->context.GetContext() != right->context.GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr JoinRelation::GetQueryNode() { @@ -48,6 +47,7 @@ unique_ptr JoinRelation::GetTableRef() { for (auto &col : duplicate_eliminated_columns) { join_ref->duplicate_eliminated_columns.emplace_back(col->Copy()); } + return std::move(join_ref); } diff --git a/src/duckdb/src/main/relation/order_relation.cpp b/src/duckdb/src/main/relation/order_relation.cpp index ac97d1c52..7a9c16dc5 100644 --- a/src/duckdb/src/main/relation/order_relation.cpp +++ b/src/duckdb/src/main/relation/order_relation.cpp @@ -10,7 +10,7 @@ OrderRelation::OrderRelation(shared_ptr child_p, vector o : Relation(child_p->context, RelationType::ORDER_RELATION), orders(std::move(orders)), child(std::move(child_p)) { D_ASSERT(child.get() != this); // bind the expressions - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr OrderRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/projection_relation.cpp b/src/duckdb/src/main/relation/projection_relation.cpp index 0577ce73d..eb1f57fd3 100644 --- a/src/duckdb/src/main/relation/projection_relation.cpp +++ b/src/duckdb/src/main/relation/projection_relation.cpp @@ -14,11 +14,11 @@ ProjectionRelation::ProjectionRelation(shared_ptr child_p, throw ParserException("Aliases list length must match expression list length!"); } for (idx_t i = 0; i < aliases.size(); i++) { - expressions[i]->SetAlias(aliases[i]); + expressions[i]->alias = aliases[i]; } } // bind the expressions - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr ProjectionRelation::GetQueryNode() { @@ -60,7 +60,7 @@ string ProjectionRelation::ToString(idx_t depth) { if (i != 0) { str += ", "; } - str += expressions[i]->ToString() + " as " + expressions[i]->GetAlias(); + str += expressions[i]->ToString() + " as " + expressions[i]->alias; } str += "]\n"; return str + child->ToString(depth + 1); diff --git a/src/duckdb/src/main/relation/query_relation.cpp b/src/duckdb/src/main/relation/query_relation.cpp index bc0bfd4e5..bc0b51502 100644 --- a/src/duckdb/src/main/relation/query_relation.cpp +++ b/src/duckdb/src/main/relation/query_relation.cpp @@ -20,7 +20,7 @@ QueryRelation::QueryRelation(const shared_ptr &context, unique_pt if (query.empty()) { query = select_stmt->ToString(); } - TryBindRelation(columns); + context->TryBindRelation(*this, this->columns); } QueryRelation::~QueryRelation() { diff --git a/src/duckdb/src/main/relation/read_csv_relation.cpp b/src/duckdb/src/main/relation/read_csv_relation.cpp index 4720a8e52..56eb0d6f5 100644 --- a/src/duckdb/src/main/relation/read_csv_relation.cpp +++ b/src/duckdb/src/main/relation/read_csv_relation.cpp @@ -13,7 +13,7 @@ #include "duckdb/parser/query_node/select_node.hpp" #include "duckdb/parser/tableref/basetableref.hpp" #include "duckdb/parser/tableref/table_function_ref.hpp" -#include "duckdb/function/table/read_csv.hpp" + namespace duckdb { void ReadCSVRelation::InitializeAlias(const vector &input) { @@ -46,63 +46,27 @@ ReadCSVRelation::ReadCSVRelation(const shared_ptr &context, const // Run the auto-detect, populating the options with the detected settings - if (csv_options.file_options.union_by_name) { - SimpleMultiFileList multi_file_list(files); - vector types; - vector names; - auto result = make_uniq(); - - multi_file_reader->BindUnionReader(*context, types, names, multi_file_list, *result, csv_options); - if (result->union_readers.size() > 1) { - for (idx_t i = 0; i < result->union_readers.size(); i++) { - result->column_info.emplace_back(result->union_readers[i]->names, result->union_readers[i]->types); - } - } - if (!csv_options.sql_types_per_column.empty()) { - const auto exception = CSVError::ColumnTypesError(csv_options.sql_types_per_column, names); - if (!exception.error_message.empty()) { - throw BinderException(exception.error_message); - } - for (idx_t i = 0; i < names.size(); i++) { - auto it = csv_options.sql_types_per_column.find(names[i]); - if (it != csv_options.sql_types_per_column.end()) { - types[i] = csv_options.sql_type_list[it->second]; - } - } - } - D_ASSERT(names.size() == types.size()); - for (idx_t i = 0; i < names.size(); i++) { + shared_ptr buffer_manager; + context->RunFunctionInTransaction([&]() { + buffer_manager = make_shared_ptr(*context, csv_options, files[0], 0); + CSVSniffer sniffer(csv_options, buffer_manager, CSVStateMachineCache::Get(*context)); + auto sniffer_result = sniffer.SniffCSV(); + auto &types = sniffer_result.return_types; + auto &names = sniffer_result.names; + for (idx_t i = 0; i < types.size(); i++) { columns.emplace_back(names[i], types[i]); } - } else { - if (csv_options.auto_detect) { - shared_ptr buffer_manager; - context->RunFunctionInTransaction([&]() { - buffer_manager = make_shared_ptr(*context, csv_options, files[0], 0); - CSVSniffer sniffer(csv_options, buffer_manager, CSVStateMachineCache::Get(*context)); - auto sniffer_result = sniffer.SniffCSV(); - auto &types = sniffer_result.return_types; - auto &names = sniffer_result.names; - for (idx_t i = 0; i < types.size(); i++) { - columns.emplace_back(names[i], types[i]); - } - }); - } else { - for (idx_t i = 0; i < csv_options.sql_type_list.size(); i++) { - D_ASSERT(csv_options.name_list.size() == csv_options.sql_type_list.size()); - columns.emplace_back(csv_options.name_list[i], csv_options.sql_type_list[i]); - } - } - // After sniffing we can consider these set, so they are exported as named parameters - // FIXME: This is horribly hacky, should be refactored at some point - csv_options.dialect_options.state_machine_options.escape.ChangeSetByUserTrue(); - csv_options.dialect_options.state_machine_options.delimiter.ChangeSetByUserTrue(); - csv_options.dialect_options.state_machine_options.quote.ChangeSetByUserTrue(); - csv_options.dialect_options.header.ChangeSetByUserTrue(); - csv_options.dialect_options.skip_rows.ChangeSetByUserTrue(); - } + }); + + // After sniffing we can consider these set, so they are exported as named parameters + // FIXME: This is horribly hacky, should be refactored at some point + csv_options.dialect_options.state_machine_options.escape.ChangeSetByUserTrue(); + csv_options.dialect_options.state_machine_options.delimiter.ChangeSetByUserTrue(); + csv_options.dialect_options.state_machine_options.quote.ChangeSetByUserTrue(); + csv_options.dialect_options.header.ChangeSetByUserTrue(); + csv_options.dialect_options.skip_rows.ChangeSetByUserTrue(); - // Capture the options potentially set/altered by the auto-detection phase + // Capture the options potentially set/altered by the auto detection phase csv_options.ToNamedParameters(options); // No need to auto-detect again @@ -114,9 +78,7 @@ ReadCSVRelation::ReadCSVRelation(const shared_ptr &context, const column_names.push_back(make_pair(columns[i].Name(), Value(columns[i].Type().ToString()))); } - if (!csv_options.file_options.union_by_name) { - AddNamedParameter("columns", Value::STRUCT(std::move(column_names))); - } + AddNamedParameter("columns", Value::STRUCT(std::move(column_names))); RemoveNamedParameterIfExists("names"); RemoveNamedParameterIfExists("types"); RemoveNamedParameterIfExists("dtypes"); diff --git a/src/duckdb/src/main/relation/setop_relation.cpp b/src/duckdb/src/main/relation/setop_relation.cpp index a0253df37..4023099c6 100644 --- a/src/duckdb/src/main/relation/setop_relation.cpp +++ b/src/duckdb/src/main/relation/setop_relation.cpp @@ -9,10 +9,10 @@ SetOpRelation::SetOpRelation(shared_ptr left_p, shared_ptr r bool setop_all) : Relation(left_p->context, RelationType::SET_OPERATION_RELATION), left(std::move(left_p)), right(std::move(right_p)), setop_type(setop_type_p), setop_all(setop_all) { - if (left->context->GetContext() != right->context->GetContext()) { + if (left->context.GetContext() != right->context.GetContext()) { throw InvalidInputException("Cannot combine LEFT and RIGHT relations of different connections!"); } - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr SetOpRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/subquery_relation.cpp b/src/duckdb/src/main/relation/subquery_relation.cpp index 2e83ed124..5ee1e0329 100644 --- a/src/duckdb/src/main/relation/subquery_relation.cpp +++ b/src/duckdb/src/main/relation/subquery_relation.cpp @@ -4,17 +4,22 @@ namespace duckdb { -SubqueryRelation::SubqueryRelation(shared_ptr child_p, const string &alias_p) - : Relation(child_p->context, RelationType::SUBQUERY_RELATION, alias_p), child(std::move(child_p)) { +SubqueryRelation::SubqueryRelation(shared_ptr child_p, string alias_p) + : Relation(child_p->context, RelationType::SUBQUERY_RELATION), child(std::move(child_p)), + alias(std::move(alias_p)) { D_ASSERT(child.get() != this); vector dummy_columns; - Relation::TryBindRelation(dummy_columns); + context.GetContext()->TryBindRelation(*this, dummy_columns); } unique_ptr SubqueryRelation::GetQueryNode() { return child->GetQueryNode(); } +string SubqueryRelation::GetAlias() { + return alias; +} + const vector &SubqueryRelation::Columns() { return child->Columns(); } diff --git a/src/duckdb/src/main/relation/table_function_relation.cpp b/src/duckdb/src/main/relation/table_function_relation.cpp index 5111752e2..7d0b2d9b1 100644 --- a/src/duckdb/src/main/relation/table_function_relation.cpp +++ b/src/duckdb/src/main/relation/table_function_relation.cpp @@ -37,15 +37,6 @@ TableFunctionRelation::TableFunctionRelation(const shared_ptr &co InitializeColumns(); } -TableFunctionRelation::TableFunctionRelation(const shared_ptr &context, string name_p, - vector parameters_p, named_parameter_map_t named_parameters, - shared_ptr input_relation_p, bool auto_init) - : Relation(context, RelationType::TABLE_FUNCTION_RELATION), name(std::move(name_p)), - parameters(std::move(parameters_p)), named_parameters(std::move(named_parameters)), - input_relation(std::move(input_relation_p)), auto_initialize(auto_init) { - InitializeColumns(); -} - TableFunctionRelation::TableFunctionRelation(const shared_ptr &context, string name_p, vector parameters_p, shared_ptr input_relation_p, bool auto_init) @@ -58,7 +49,7 @@ void TableFunctionRelation::InitializeColumns() { if (!auto_initialize) { return; } - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } unique_ptr TableFunctionRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/table_relation.cpp b/src/duckdb/src/main/relation/table_relation.cpp index 1b790a698..4a0ff6e0e 100644 --- a/src/duckdb/src/main/relation/table_relation.cpp +++ b/src/duckdb/src/main/relation/table_relation.cpp @@ -13,11 +13,6 @@ TableRelation::TableRelation(const shared_ptr &context, unique_pt : Relation(context, RelationType::TABLE_RELATION), description(std::move(description)) { } -TableRelation::TableRelation(const shared_ptr &context, - unique_ptr description) - : Relation(context, RelationType::TABLE_RELATION), description(std::move(description)) { -} - unique_ptr TableRelation::GetQueryNode() { auto result = make_uniq(); result->select_list.push_back(make_uniq()); @@ -56,29 +51,18 @@ static unique_ptr ParseCondition(ClientContext &context, const } } -void TableRelation::Update(vector names, vector> &&update, - unique_ptr condition) { - vector update_columns = std::move(names); - vector> expressions = std::move(update); - - auto update_relation = - make_shared_ptr(context, std::move(condition), description->schema, description->table, - std::move(update_columns), std::move(expressions)); - update_relation->Execute(); -} - void TableRelation::Update(const string &update_list, const string &condition) { vector update_columns; vector> expressions; - auto cond = ParseCondition(*context->GetContext(), condition); - Parser::ParseUpdateList(update_list, update_columns, expressions, context->GetContext()->GetParserOptions()); + auto cond = ParseCondition(*context.GetContext(), condition); + Parser::ParseUpdateList(update_list, update_columns, expressions, context.GetContext()->GetParserOptions()); auto update = make_shared_ptr(context, std::move(cond), description->schema, description->table, std::move(update_columns), std::move(expressions)); update->Execute(); } void TableRelation::Delete(const string &condition) { - auto cond = ParseCondition(*context->GetContext(), condition); + auto cond = ParseCondition(*context.GetContext(), condition); auto del = make_shared_ptr(context, std::move(cond), description->schema, description->table); del->Execute(); } diff --git a/src/duckdb/src/main/relation/update_relation.cpp b/src/duckdb/src/main/relation/update_relation.cpp index 6dd34dfc5..152d04af3 100644 --- a/src/duckdb/src/main/relation/update_relation.cpp +++ b/src/duckdb/src/main/relation/update_relation.cpp @@ -6,14 +6,14 @@ namespace duckdb { -UpdateRelation::UpdateRelation(shared_ptr &context, unique_ptr condition_p, +UpdateRelation::UpdateRelation(ClientContextWrapper &context, unique_ptr condition_p, string schema_name_p, string table_name_p, vector update_columns_p, vector> expressions_p) : Relation(context, RelationType::UPDATE_RELATION), condition(std::move(condition_p)), schema_name(std::move(schema_name_p)), table_name(std::move(table_name_p)), update_columns(std::move(update_columns_p)), expressions(std::move(expressions_p)) { D_ASSERT(update_columns.size() == expressions.size()); - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement UpdateRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/value_relation.cpp b/src/duckdb/src/main/relation/value_relation.cpp index bd9adf991..3e11ed6bb 100644 --- a/src/duckdb/src/main/relation/value_relation.cpp +++ b/src/duckdb/src/main/relation/value_relation.cpp @@ -21,14 +21,7 @@ ValueRelation::ValueRelation(const shared_ptr &context, const vec this->expressions.push_back(std::move(expressions)); } QueryResult::DeduplicateColumns(names); - TryBindRelation(columns); -} - -ValueRelation::ValueRelation(const shared_ptr &context, - vector>> &&expressions_p, vector names_p, - string alias_p) - : ValueRelation(make_shared_ptr(context), std::move(expressions_p), std::move(names_p), - std::move(alias_p)) { + context->TryBindRelation(*this, this->columns); } ValueRelation::ValueRelation(const shared_ptr &context, const string &values_list, @@ -36,40 +29,7 @@ ValueRelation::ValueRelation(const shared_ptr &context, const str : Relation(context, RelationType::VALUE_LIST_RELATION), names(std::move(names_p)), alias(std::move(alias_p)) { this->expressions = Parser::ParseValuesList(values_list, context->GetParserOptions()); QueryResult::DeduplicateColumns(names); - TryBindRelation(columns); -} - -ValueRelation::ValueRelation(const shared_ptr &context, const vector> &values, - vector names_p, string alias_p) - : Relation(context, RelationType::VALUE_LIST_RELATION), names(std::move(names_p)), alias(std::move(alias_p)) { - // create constant expressions for the values - for (idx_t row_idx = 0; row_idx < values.size(); row_idx++) { - auto &list = values[row_idx]; - vector> expressions; - for (idx_t col_idx = 0; col_idx < list.size(); col_idx++) { - expressions.push_back(make_uniq(list[col_idx])); - } - this->expressions.push_back(std::move(expressions)); - } - QueryResult::DeduplicateColumns(names); - TryBindRelation(columns); -} - -ValueRelation::ValueRelation(const shared_ptr &context, - vector>> &&expressions_p, vector names_p, - string alias_p) - : Relation(context, RelationType::VALUE_LIST_RELATION), alias(std::move(alias_p)) { - D_ASSERT(!expressions_p.empty()); - if (names_p.empty()) { - auto &first_list = expressions_p[0]; - for (auto &expr : first_list) { - names_p.push_back(expr->GetName()); - } - } - names = std::move(names_p); - expressions = std::move(expressions_p); - QueryResult::DeduplicateColumns(names); - TryBindRelation(columns); + context->TryBindRelation(*this, this->columns); } unique_ptr ValueRelation::GetQueryNode() { diff --git a/src/duckdb/src/main/relation/view_relation.cpp b/src/duckdb/src/main/relation/view_relation.cpp index 16c1bdc37..7b6b73c56 100644 --- a/src/duckdb/src/main/relation/view_relation.cpp +++ b/src/duckdb/src/main/relation/view_relation.cpp @@ -10,18 +10,12 @@ namespace duckdb { ViewRelation::ViewRelation(const shared_ptr &context, string schema_name_p, string view_name_p) : Relation(context, RelationType::VIEW_RELATION), schema_name(std::move(schema_name_p)), view_name(std::move(view_name_p)) { - TryBindRelation(columns); -} - -ViewRelation::ViewRelation(const shared_ptr &context, string schema_name_p, string view_name_p) - : Relation(context, RelationType::VIEW_RELATION), schema_name(std::move(schema_name_p)), - view_name(std::move(view_name_p)) { - TryBindRelation(columns); + context->TryBindRelation(*this, this->columns); } ViewRelation::ViewRelation(const shared_ptr &context, unique_ptr ref, const string &view_name) : Relation(context, RelationType::VIEW_RELATION), view_name(view_name), premade_tableref(std::move(ref)) { - TryBindRelation(columns); + context->TryBindRelation(*this, this->columns); premade_tableref->alias = view_name; } diff --git a/src/duckdb/src/main/relation/write_csv_relation.cpp b/src/duckdb/src/main/relation/write_csv_relation.cpp index 4795c7a51..a521f8cae 100644 --- a/src/duckdb/src/main/relation/write_csv_relation.cpp +++ b/src/duckdb/src/main/relation/write_csv_relation.cpp @@ -10,7 +10,7 @@ WriteCSVRelation::WriteCSVRelation(shared_ptr child_p, string csv_file case_insensitive_map_t> options_p) : Relation(child_p->context, RelationType::WRITE_CSV_RELATION), child(std::move(child_p)), csv_file(std::move(csv_file_p)), options(std::move(options_p)) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement WriteCSVRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/relation/write_parquet_relation.cpp b/src/duckdb/src/main/relation/write_parquet_relation.cpp index d6e403618..c2d937a2f 100644 --- a/src/duckdb/src/main/relation/write_parquet_relation.cpp +++ b/src/duckdb/src/main/relation/write_parquet_relation.cpp @@ -10,7 +10,7 @@ WriteParquetRelation::WriteParquetRelation(shared_ptr child_p, string case_insensitive_map_t> options_p) : Relation(child_p->context, RelationType::WRITE_PARQUET_RELATION), child(std::move(child_p)), parquet_file(std::move(parquet_file_p)), options(std::move(options_p)) { - TryBindRelation(columns); + context.GetContext()->TryBindRelation(*this, this->columns); } BoundStatement WriteParquetRelation::Bind(Binder &binder) { diff --git a/src/duckdb/src/main/secret/secret_manager.cpp b/src/duckdb/src/main/secret/secret_manager.cpp index 191cf1f56..045d1efe8 100644 --- a/src/duckdb/src/main/secret/secret_manager.cpp +++ b/src/duckdb/src/main/secret/secret_manager.cpp @@ -80,7 +80,7 @@ void SecretManager::LoadSecretStorageInternal(unique_ptr storage) // Check for tie-break offset collisions to ensure we can always tie-break cleanly for (const auto &storage_ptr : secret_storages) { - if (storage_ptr.second->tie_break_offset == storage->tie_break_offset) { + if (storage_ptr.second->GetTieBreakOffset() == storage->GetTieBreakOffset()) { throw InternalException("Failed to load secret storage '%s', tie break score collides with '%s'", storage->GetName(), storage_ptr.second->GetName()); } diff --git a/src/duckdb/src/main/secret/secret_storage.cpp b/src/duckdb/src/main/secret/secret_storage.cpp index 0b543f8b3..ef35f419e 100644 --- a/src/duckdb/src/main/secret/secret_storage.cpp +++ b/src/duckdb/src/main/secret/secret_storage.cpp @@ -14,8 +14,7 @@ namespace duckdb { -SecretMatch SecretStorage::SelectBestMatch(SecretEntry &secret_entry, const string &path, int64_t offset, - SecretMatch ¤t_best) { +SecretMatch SecretStorage::SelectBestMatch(SecretEntry &secret_entry, const string &path, SecretMatch ¤t_best) { // Get secret match score auto match_score = secret_entry.secret->MatchScore(path); @@ -28,7 +27,7 @@ SecretMatch SecretStorage::SelectBestMatch(SecretEntry &secret_entry, const stri D_ASSERT(match_score >= 0); // Apply storage tie-break offset - match_score = 100 * match_score - offset; + match_score = OffsetMatchScore(match_score); // Choose the best matching score, tie-breaking on secret name when necessary if (match_score > current_best.score) { @@ -106,7 +105,7 @@ SecretMatch CatalogSetSecretStorage::LookupSecret(const string &path, const stri const std::function callback = [&](CatalogEntry &entry) { auto &cast_entry = entry.Cast(); if (StringUtil::CIEquals(cast_entry.secret->secret->GetType(), type)) { - best_match = SelectBestMatch(*cast_entry.secret, path, tie_break_offset, best_match); + best_match = SelectBestMatch(*cast_entry.secret, path, best_match); } }; secrets->Scan(GetTransactionOrDefault(transaction), callback); @@ -132,8 +131,7 @@ unique_ptr CatalogSetSecretStorage::GetSecretByName(const string &n LocalFileSecretStorage::LocalFileSecretStorage(SecretManager &manager, DatabaseInstance &db_p, const string &name_p, const string &secret_path_p) - : CatalogSetSecretStorage(db_p, name_p, LOCAL_FILE_STORAGE_OFFSET), - secret_path(FileSystem::ExpandPath(secret_path_p, nullptr)) { + : CatalogSetSecretStorage(db_p, name_p), secret_path(FileSystem::ExpandPath(secret_path_p, nullptr)) { persistent = true; // Check existence of persistent secret dir diff --git a/src/duckdb/src/main/settings/autogenerated_settings.cpp b/src/duckdb/src/main/settings/autogenerated_settings.cpp deleted file mode 100644 index 6a7106963..000000000 --- a/src/duckdb/src/main/settings/autogenerated_settings.cpp +++ /dev/null @@ -1,1085 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// This code is autogenerated from 'scripts/settings_scripts/update_settings_src_code.py'. -// Please do not make any changes directly here, as they will be overwritten. -// If you need to implement a custom function for a new setting, enable the -// 'custom_implementation' in 'src/common/settings.json' for this setting. -// -//===----------------------------------------------------------------------===// - -#include "duckdb/main/settings.hpp" -#include "duckdb/common/enum_util.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/config.hpp" - -namespace duckdb { - -//===----------------------------------------------------------------------===// -// Access Mode -//===----------------------------------------------------------------------===// -void AccessModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - auto str_input = StringUtil::Upper(input.GetValue()); - config.options.access_mode = EnumUtil::FromString(str_input); -} - -void AccessModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.access_mode = DBConfig().options.access_mode; -} - -Value AccessModeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.options.access_mode))); -} - -//===----------------------------------------------------------------------===// -// Allocator Background Threads -//===----------------------------------------------------------------------===// -void AllocatorBackgroundThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allocator_background_threads = input.GetValue(); -} - -void AllocatorBackgroundThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allocator_background_threads = DBConfig().options.allocator_background_threads; -} - -Value AllocatorBackgroundThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allocator_background_threads); -} - -//===----------------------------------------------------------------------===// -// Allow Community Extensions -//===----------------------------------------------------------------------===// -void AllowCommunityExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_community_extensions = input.GetValue(); -} - -void AllowCommunityExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_community_extensions = DBConfig().options.allow_community_extensions; -} - -Value AllowCommunityExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_community_extensions); -} - -//===----------------------------------------------------------------------===// -// Allow Extensions Metadata Mismatch -//===----------------------------------------------------------------------===// -void AllowExtensionsMetadataMismatchSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.allow_extensions_metadata_mismatch = input.GetValue(); -} - -void AllowExtensionsMetadataMismatchSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allow_extensions_metadata_mismatch = DBConfig().options.allow_extensions_metadata_mismatch; -} - -Value AllowExtensionsMetadataMismatchSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_extensions_metadata_mismatch); -} - -//===----------------------------------------------------------------------===// -// Allow Unredacted Secrets -//===----------------------------------------------------------------------===// -void AllowUnredactedSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_unredacted_secrets = input.GetValue(); -} - -void AllowUnredactedSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_unredacted_secrets = DBConfig().options.allow_unredacted_secrets; -} - -Value AllowUnredactedSecretsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unredacted_secrets); -} - -//===----------------------------------------------------------------------===// -// Allow Unsigned Extensions -//===----------------------------------------------------------------------===// -void AllowUnsignedExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.allow_unsigned_extensions = input.GetValue(); -} - -void AllowUnsignedExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.allow_unsigned_extensions = DBConfig().options.allow_unsigned_extensions; -} - -Value AllowUnsignedExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.allow_unsigned_extensions); -} - -//===----------------------------------------------------------------------===// -// Arrow Large Buffer Size -//===----------------------------------------------------------------------===// -void ArrowLargeBufferSizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_offset_size = DBConfig().options.arrow_offset_size; -} - -//===----------------------------------------------------------------------===// -// Arrow Lossless Conversion -//===----------------------------------------------------------------------===// -void ArrowLosslessConversionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.arrow_lossless_conversion = input.GetValue(); -} - -void ArrowLosslessConversionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_lossless_conversion = DBConfig().options.arrow_lossless_conversion; -} - -Value ArrowLosslessConversionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.arrow_lossless_conversion); -} - -//===----------------------------------------------------------------------===// -// Arrow Output List View -//===----------------------------------------------------------------------===// -void ArrowOutputListViewSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.arrow_use_list_view = input.GetValue(); -} - -void ArrowOutputListViewSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.arrow_use_list_view = DBConfig().options.arrow_use_list_view; -} - -Value ArrowOutputListViewSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.arrow_use_list_view); -} - -//===----------------------------------------------------------------------===// -// Autoinstall Extension Repository -//===----------------------------------------------------------------------===// -void AutoinstallExtensionRepositorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_extension_repo = input.GetValue(); -} - -void AutoinstallExtensionRepositorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_extension_repo = DBConfig().options.autoinstall_extension_repo; -} - -Value AutoinstallExtensionRepositorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.autoinstall_extension_repo); -} - -//===----------------------------------------------------------------------===// -// Autoinstall Known Extensions -//===----------------------------------------------------------------------===// -void AutoinstallKnownExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoinstall_known_extensions = input.GetValue(); -} - -void AutoinstallKnownExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoinstall_known_extensions = DBConfig().options.autoinstall_known_extensions; -} - -Value AutoinstallKnownExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoinstall_known_extensions); -} - -//===----------------------------------------------------------------------===// -// Autoload Known Extensions -//===----------------------------------------------------------------------===// -void AutoloadKnownExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.autoload_known_extensions = input.GetValue(); -} - -void AutoloadKnownExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.autoload_known_extensions = DBConfig().options.autoload_known_extensions; -} - -Value AutoloadKnownExtensionsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.autoload_known_extensions); -} - -//===----------------------------------------------------------------------===// -// Catalog Error Max Schemas -//===----------------------------------------------------------------------===// -void CatalogErrorMaxSchemasSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.catalog_error_max_schemas = input.GetValue(); -} - -void CatalogErrorMaxSchemasSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.catalog_error_max_schemas = DBConfig().options.catalog_error_max_schemas; -} - -Value CatalogErrorMaxSchemasSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.catalog_error_max_schemas); -} - -//===----------------------------------------------------------------------===// -// Checkpoint Threshold -//===----------------------------------------------------------------------===// -void CheckpointThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.checkpoint_wal_size = DBConfig().options.checkpoint_wal_size; -} - -//===----------------------------------------------------------------------===// -// Custom Extension Repository -//===----------------------------------------------------------------------===// -void CustomExtensionRepositorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.custom_extension_repo = input.GetValue(); -} - -void CustomExtensionRepositorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.custom_extension_repo = DBConfig().options.custom_extension_repo; -} - -Value CustomExtensionRepositorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.custom_extension_repo); -} - -//===----------------------------------------------------------------------===// -// Custom User Agent -//===----------------------------------------------------------------------===// -Value CustomUserAgentSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.custom_user_agent); -} - -//===----------------------------------------------------------------------===// -// Debug Asof Iejoin -//===----------------------------------------------------------------------===// -void DebugAsofIejoinSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.force_asof_iejoin = input.GetValue(); -} - -void DebugAsofIejoinSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_asof_iejoin = ClientConfig().force_asof_iejoin; -} - -Value DebugAsofIejoinSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.force_asof_iejoin); -} - -//===----------------------------------------------------------------------===// -// Debug Checkpoint Abort -//===----------------------------------------------------------------------===// -void DebugCheckpointAbortSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto str_input = StringUtil::Upper(input.GetValue()); - config.options.checkpoint_abort = EnumUtil::FromString(str_input); -} - -void DebugCheckpointAbortSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.checkpoint_abort = DBConfig().options.checkpoint_abort; -} - -Value DebugCheckpointAbortSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.options.checkpoint_abort))); -} - -//===----------------------------------------------------------------------===// -// Debug Force External -//===----------------------------------------------------------------------===// -void DebugForceExternalSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.force_external = input.GetValue(); -} - -void DebugForceExternalSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_external = ClientConfig().force_external; -} - -Value DebugForceExternalSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.force_external); -} - -//===----------------------------------------------------------------------===// -// Debug Force No Cross Product -//===----------------------------------------------------------------------===// -void DebugForceNoCrossProductSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.force_no_cross_product = input.GetValue(); -} - -void DebugForceNoCrossProductSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).force_no_cross_product = ClientConfig().force_no_cross_product; -} - -Value DebugForceNoCrossProductSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.force_no_cross_product); -} - -//===----------------------------------------------------------------------===// -// Debug Skip Checkpoint On Commit -//===----------------------------------------------------------------------===// -void DebugSkipCheckpointOnCommitSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.debug_skip_checkpoint_on_commit = input.GetValue(); -} - -void DebugSkipCheckpointOnCommitSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.debug_skip_checkpoint_on_commit = DBConfig().options.debug_skip_checkpoint_on_commit; -} - -Value DebugSkipCheckpointOnCommitSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.debug_skip_checkpoint_on_commit); -} - -//===----------------------------------------------------------------------===// -// Debug Window Mode -//===----------------------------------------------------------------------===// -void DebugWindowModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto str_input = StringUtil::Upper(input.GetValue()); - config.options.window_mode = EnumUtil::FromString(str_input); -} - -void DebugWindowModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.window_mode = DBConfig().options.window_mode; -} - -Value DebugWindowModeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.options.window_mode))); -} - -//===----------------------------------------------------------------------===// -// Default Null Order -//===----------------------------------------------------------------------===// -void DefaultNullOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_null_order = DBConfig().options.default_null_order; -} - -Value DefaultNullOrderSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.options.default_null_order))); -} - -//===----------------------------------------------------------------------===// -// Default Order -//===----------------------------------------------------------------------===// -void DefaultOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_order_type = DBConfig().options.default_order_type; -} - -//===----------------------------------------------------------------------===// -// Dynamic Or Filter Threshold -//===----------------------------------------------------------------------===// -void DynamicOrFilterThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.dynamic_or_filter_threshold = input.GetValue(); -} - -void DynamicOrFilterThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).dynamic_or_filter_threshold = ClientConfig().dynamic_or_filter_threshold; -} - -Value DynamicOrFilterThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.dynamic_or_filter_threshold); -} - -//===----------------------------------------------------------------------===// -// Enable External Access -//===----------------------------------------------------------------------===// -void EnableExternalAccessSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.enable_external_access = input.GetValue(); -} - -void EnableExternalAccessSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.enable_external_access = DBConfig().options.enable_external_access; -} - -Value EnableExternalAccessSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_external_access); -} - -//===----------------------------------------------------------------------===// -// Enable F S S T Vectors -//===----------------------------------------------------------------------===// -void EnableFSSTVectorsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_fsst_vectors = input.GetValue(); -} - -void EnableFSSTVectorsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_fsst_vectors = DBConfig().options.enable_fsst_vectors; -} - -Value EnableFSSTVectorsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_fsst_vectors); -} - -//===----------------------------------------------------------------------===// -// Enable H T T P Logging -//===----------------------------------------------------------------------===// -void EnableHTTPLoggingSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.enable_http_logging = input.GetValue(); -} - -void EnableHTTPLoggingSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).enable_http_logging = ClientConfig().enable_http_logging; -} - -Value EnableHTTPLoggingSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.enable_http_logging); -} - -//===----------------------------------------------------------------------===// -// Enable H T T P Metadata Cache -//===----------------------------------------------------------------------===// -void EnableHTTPMetadataCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_metadata_cache_enable = input.GetValue(); -} - -void EnableHTTPMetadataCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_metadata_cache_enable = DBConfig().options.http_metadata_cache_enable; -} - -Value EnableHTTPMetadataCacheSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.http_metadata_cache_enable); -} - -//===----------------------------------------------------------------------===// -// Enable Macro Dependencies -//===----------------------------------------------------------------------===// -void EnableMacroDependenciesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_macro_dependencies = input.GetValue(); -} - -void EnableMacroDependenciesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_macro_dependencies = DBConfig().options.enable_macro_dependencies; -} - -Value EnableMacroDependenciesSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_macro_dependencies); -} - -//===----------------------------------------------------------------------===// -// Enable Progress Bar -//===----------------------------------------------------------------------===// -void EnableProgressBarSetting::SetLocal(ClientContext &context, const Value &input) { - if (!OnLocalSet(context, input)) { - return; - } - auto &config = ClientConfig::GetConfig(context); - config.enable_progress_bar = input.GetValue(); -} - -void EnableProgressBarSetting::ResetLocal(ClientContext &context) { - if (!OnLocalReset(context)) { - return; - } - ClientConfig::GetConfig(context).enable_progress_bar = ClientConfig().enable_progress_bar; -} - -Value EnableProgressBarSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.enable_progress_bar); -} - -//===----------------------------------------------------------------------===// -// Enable View Dependencies -//===----------------------------------------------------------------------===// -void EnableViewDependenciesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.enable_view_dependencies = input.GetValue(); -} - -void EnableViewDependenciesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.enable_view_dependencies = DBConfig().options.enable_view_dependencies; -} - -Value EnableViewDependenciesSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.enable_view_dependencies); -} - -//===----------------------------------------------------------------------===// -// Errors As J S O N -//===----------------------------------------------------------------------===// -void ErrorsAsJSONSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.errors_as_json = input.GetValue(); -} - -void ErrorsAsJSONSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).errors_as_json = ClientConfig().errors_as_json; -} - -Value ErrorsAsJSONSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.errors_as_json); -} - -//===----------------------------------------------------------------------===// -// Explain Output -//===----------------------------------------------------------------------===// -void ExplainOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - auto str_input = StringUtil::Upper(input.GetValue()); - config.explain_output_type = EnumUtil::FromString(str_input); -} - -void ExplainOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).explain_output_type = ClientConfig().explain_output_type; -} - -Value ExplainOutputSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(StringUtil::Lower(EnumUtil::ToString(config.explain_output_type))); -} - -//===----------------------------------------------------------------------===// -// Extension Directory -//===----------------------------------------------------------------------===// -void ExtensionDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.extension_directory = input.GetValue(); -} - -void ExtensionDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.extension_directory = DBConfig().options.extension_directory; -} - -Value ExtensionDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.extension_directory); -} - -//===----------------------------------------------------------------------===// -// External Threads -//===----------------------------------------------------------------------===// -void ExternalThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.external_threads = input.GetValue(); -} - -void ExternalThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!OnGlobalReset(db, config)) { - return; - } - config.options.external_threads = DBConfig().options.external_threads; -} - -Value ExternalThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.external_threads); -} - -//===----------------------------------------------------------------------===// -// Home Directory -//===----------------------------------------------------------------------===// -void HomeDirectorySetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).home_directory = ClientConfig().home_directory; -} - -Value HomeDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.home_directory); -} - -//===----------------------------------------------------------------------===// -// H T T P Logging Output -//===----------------------------------------------------------------------===// -void HTTPLoggingOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.http_logging_output = input.GetValue(); -} - -void HTTPLoggingOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).http_logging_output = ClientConfig().http_logging_output; -} - -Value HTTPLoggingOutputSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.http_logging_output); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy -//===----------------------------------------------------------------------===// -void HTTPProxySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy = input.GetValue(); -} - -void HTTPProxySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy = DBConfig().options.http_proxy; -} - -Value HTTPProxySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy Password -//===----------------------------------------------------------------------===// -void HTTPProxyPasswordSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy_password = input.GetValue(); -} - -void HTTPProxyPasswordSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_password = DBConfig().options.http_proxy_password; -} - -Value HTTPProxyPasswordSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy_password); -} - -//===----------------------------------------------------------------------===// -// H T T P Proxy Username -//===----------------------------------------------------------------------===// -void HTTPProxyUsernameSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.http_proxy_username = input.GetValue(); -} - -void HTTPProxyUsernameSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.http_proxy_username = DBConfig().options.http_proxy_username; -} - -Value HTTPProxyUsernameSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.http_proxy_username); -} - -//===----------------------------------------------------------------------===// -// I E E E Floating Point Ops -//===----------------------------------------------------------------------===// -void IEEEFloatingPointOpsSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.ieee_floating_point_ops = input.GetValue(); -} - -void IEEEFloatingPointOpsSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).ieee_floating_point_ops = ClientConfig().ieee_floating_point_ops; -} - -Value IEEEFloatingPointOpsSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.ieee_floating_point_ops); -} - -//===----------------------------------------------------------------------===// -// Immediate Transaction Mode -//===----------------------------------------------------------------------===// -void ImmediateTransactionModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.immediate_transaction_mode = input.GetValue(); -} - -void ImmediateTransactionModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.immediate_transaction_mode = DBConfig().options.immediate_transaction_mode; -} - -Value ImmediateTransactionModeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.immediate_transaction_mode); -} - -//===----------------------------------------------------------------------===// -// Index Scan Max Count -//===----------------------------------------------------------------------===// -void IndexScanMaxCountSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.index_scan_max_count = input.GetValue(); -} - -void IndexScanMaxCountSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.index_scan_max_count = DBConfig().options.index_scan_max_count; -} - -Value IndexScanMaxCountSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.index_scan_max_count); -} - -//===----------------------------------------------------------------------===// -// Index Scan Percentage -//===----------------------------------------------------------------------===// -void IndexScanPercentageSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!OnGlobalSet(db, config, input)) { - return; - } - config.options.index_scan_percentage = input.GetValue(); -} - -void IndexScanPercentageSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.index_scan_percentage = DBConfig().options.index_scan_percentage; -} - -Value IndexScanPercentageSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::DOUBLE(config.options.index_scan_percentage); -} - -//===----------------------------------------------------------------------===// -// Integer Division -//===----------------------------------------------------------------------===// -void IntegerDivisionSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.integer_division = input.GetValue(); -} - -void IntegerDivisionSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).integer_division = ClientConfig().integer_division; -} - -Value IntegerDivisionSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.integer_division); -} - -//===----------------------------------------------------------------------===// -// Lock Configuration -//===----------------------------------------------------------------------===// -void LockConfigurationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.lock_configuration = input.GetValue(); -} - -void LockConfigurationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.lock_configuration = DBConfig().options.lock_configuration; -} - -Value LockConfigurationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.lock_configuration); -} - -//===----------------------------------------------------------------------===// -// Max Expression Depth -//===----------------------------------------------------------------------===// -void MaxExpressionDepthSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.max_expression_depth = input.GetValue(); -} - -void MaxExpressionDepthSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).max_expression_depth = ClientConfig().max_expression_depth; -} - -Value MaxExpressionDepthSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.max_expression_depth); -} - -//===----------------------------------------------------------------------===// -// Max Vacuum Tasks -//===----------------------------------------------------------------------===// -void MaxVacuumTasksSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.max_vacuum_tasks = input.GetValue(); -} - -void MaxVacuumTasksSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.max_vacuum_tasks = DBConfig().options.max_vacuum_tasks; -} - -Value MaxVacuumTasksSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.max_vacuum_tasks); -} - -//===----------------------------------------------------------------------===// -// Merge Join Threshold -//===----------------------------------------------------------------------===// -void MergeJoinThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.merge_join_threshold = input.GetValue(); -} - -void MergeJoinThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).merge_join_threshold = ClientConfig().merge_join_threshold; -} - -Value MergeJoinThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.merge_join_threshold); -} - -//===----------------------------------------------------------------------===// -// Nested Loop Join Threshold -//===----------------------------------------------------------------------===// -void NestedLoopJoinThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.nested_loop_join_threshold = input.GetValue(); -} - -void NestedLoopJoinThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).nested_loop_join_threshold = ClientConfig().nested_loop_join_threshold; -} - -Value NestedLoopJoinThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.nested_loop_join_threshold); -} - -//===----------------------------------------------------------------------===// -// Old Implicit Casting -//===----------------------------------------------------------------------===// -void OldImplicitCastingSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.old_implicit_casting = input.GetValue(); -} - -void OldImplicitCastingSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.old_implicit_casting = DBConfig().options.old_implicit_casting; -} - -Value OldImplicitCastingSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.old_implicit_casting); -} - -//===----------------------------------------------------------------------===// -// Order By Non Integer Literal -//===----------------------------------------------------------------------===// -void OrderByNonIntegerLiteralSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.order_by_non_integer_literal = input.GetValue(); -} - -void OrderByNonIntegerLiteralSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).order_by_non_integer_literal = ClientConfig().order_by_non_integer_literal; -} - -Value OrderByNonIntegerLiteralSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.order_by_non_integer_literal); -} - -//===----------------------------------------------------------------------===// -// Ordered Aggregate Threshold -//===----------------------------------------------------------------------===// -void OrderedAggregateThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - if (!OnLocalSet(context, input)) { - return; - } - auto &config = ClientConfig::GetConfig(context); - config.ordered_aggregate_threshold = input.GetValue(); -} - -void OrderedAggregateThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).ordered_aggregate_threshold = ClientConfig().ordered_aggregate_threshold; -} - -Value OrderedAggregateThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.ordered_aggregate_threshold); -} - -//===----------------------------------------------------------------------===// -// Partitioned Write Flush Threshold -//===----------------------------------------------------------------------===// -void PartitionedWriteFlushThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.partitioned_write_flush_threshold = input.GetValue(); -} - -void PartitionedWriteFlushThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).partitioned_write_flush_threshold = - ClientConfig().partitioned_write_flush_threshold; -} - -Value PartitionedWriteFlushThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.partitioned_write_flush_threshold); -} - -//===----------------------------------------------------------------------===// -// Partitioned Write Max Open Files -//===----------------------------------------------------------------------===// -void PartitionedWriteMaxOpenFilesSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.partitioned_write_max_open_files = input.GetValue(); -} - -void PartitionedWriteMaxOpenFilesSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).partitioned_write_max_open_files = ClientConfig().partitioned_write_max_open_files; -} - -Value PartitionedWriteMaxOpenFilesSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.partitioned_write_max_open_files); -} - -//===----------------------------------------------------------------------===// -// Perfect Ht Threshold -//===----------------------------------------------------------------------===// -void PerfectHtThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).perfect_ht_threshold = ClientConfig().perfect_ht_threshold; -} - -//===----------------------------------------------------------------------===// -// Pivot Filter Threshold -//===----------------------------------------------------------------------===// -void PivotFilterThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.pivot_filter_threshold = input.GetValue(); -} - -void PivotFilterThresholdSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).pivot_filter_threshold = ClientConfig().pivot_filter_threshold; -} - -Value PivotFilterThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.pivot_filter_threshold); -} - -//===----------------------------------------------------------------------===// -// Pivot Limit -//===----------------------------------------------------------------------===// -void PivotLimitSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.pivot_limit = input.GetValue(); -} - -void PivotLimitSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).pivot_limit = ClientConfig().pivot_limit; -} - -Value PivotLimitSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::UBIGINT(config.pivot_limit); -} - -//===----------------------------------------------------------------------===// -// Prefer Range Joins -//===----------------------------------------------------------------------===// -void PreferRangeJoinsSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.prefer_range_joins = input.GetValue(); -} - -void PreferRangeJoinsSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).prefer_range_joins = ClientConfig().prefer_range_joins; -} - -Value PreferRangeJoinsSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.prefer_range_joins); -} - -//===----------------------------------------------------------------------===// -// Preserve Identifier Case -//===----------------------------------------------------------------------===// -void PreserveIdentifierCaseSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.preserve_identifier_case = input.GetValue(); -} - -void PreserveIdentifierCaseSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).preserve_identifier_case = ClientConfig().preserve_identifier_case; -} - -Value PreserveIdentifierCaseSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.preserve_identifier_case); -} - -//===----------------------------------------------------------------------===// -// Preserve Insertion Order -//===----------------------------------------------------------------------===// -void PreserveInsertionOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.preserve_insertion_order = input.GetValue(); -} - -void PreserveInsertionOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.preserve_insertion_order = DBConfig().options.preserve_insertion_order; -} - -Value PreserveInsertionOrderSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.preserve_insertion_order); -} - -//===----------------------------------------------------------------------===// -// Produce Arrow String View -//===----------------------------------------------------------------------===// -void ProduceArrowStringViewSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.produce_arrow_string_views = input.GetValue(); -} - -void ProduceArrowStringViewSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.produce_arrow_string_views = DBConfig().options.produce_arrow_string_views; -} - -Value ProduceArrowStringViewSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.options.produce_arrow_string_views); -} - -//===----------------------------------------------------------------------===// -// Scalar Subquery Error On Multiple Rows -//===----------------------------------------------------------------------===// -void ScalarSubqueryErrorOnMultipleRowsSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.scalar_subquery_error_on_multiple_rows = input.GetValue(); -} - -void ScalarSubqueryErrorOnMultipleRowsSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = - ClientConfig().scalar_subquery_error_on_multiple_rows; -} - -Value ScalarSubqueryErrorOnMultipleRowsSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value::BOOLEAN(config.scalar_subquery_error_on_multiple_rows); -} - -//===----------------------------------------------------------------------===// -// Zstd Min String Length -//===----------------------------------------------------------------------===// -void ZstdMinStringLengthSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.zstd_min_string_length = input.GetValue(); -} - -void ZstdMinStringLengthSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.zstd_min_string_length = DBConfig().options.zstd_min_string_length; -} - -Value ZstdMinStringLengthSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.zstd_min_string_length); -} - -} // namespace duckdb diff --git a/src/duckdb/src/main/settings/custom_settings.cpp b/src/duckdb/src/main/settings/custom_settings.cpp deleted file mode 100644 index 57e961a22..000000000 --- a/src/duckdb/src/main/settings/custom_settings.cpp +++ /dev/null @@ -1,1237 +0,0 @@ -//===----------------------------------------------------------------------===// -// DuckDB -// This file will not be overwritten. To implement a custom function for -// a new setting, enable 'custom_implementation' in 'src/common/settings.json' -// for this setting. The 'update_settings_definitions.py' may include new -// setting methods' signatures that need to be implemented in this file. You -// can check the functions declaration in 'settings.hpp' and what is -// autogenerated in 'autogenerated_settings.cpp'. -// -//===----------------------------------------------------------------------===// - -#include "duckdb/main/settings.hpp" - -#include "duckdb/common/enums/access_mode.hpp" -#include "duckdb/catalog/catalog_search_path.hpp" -#include "duckdb/common/string_util.hpp" -#include "duckdb/main/attached_database.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/main/client_data.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/main/database.hpp" -#include "duckdb/main/database_manager.hpp" -#include "duckdb/main/query_profiler.hpp" -#include "duckdb/main/secret/secret_manager.hpp" -#include "duckdb/parallel/task_scheduler.hpp" -#include "duckdb/parser/parser.hpp" -#include "duckdb/planner/expression_binder.hpp" -#include "duckdb/storage/buffer/buffer_pool.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/storage_manager.hpp" - -namespace duckdb { - -const string GetDefaultUserAgent() { - return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); -} - -//===----------------------------------------------------------------------===// -// Access Mode -//===----------------------------------------------------------------------===// -bool AccessModeSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db) { - throw InvalidInputException("Cannot change access_mode setting while database is running - it must be set when " - "opening or attaching the database"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allocator Background Threads -//===----------------------------------------------------------------------===// -bool AllocatorBackgroundThreadsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(input.GetValue()); - } - return true; -} - -bool AllocatorBackgroundThreadsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(DBConfig().options.allocator_background_threads); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allocator Bulk Deallocation Flush Threshold -//===----------------------------------------------------------------------===// -void AllocatorBulkDeallocationFlushThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, - const Value &input) { - config.options.allocator_bulk_deallocation_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( - config.options.allocator_bulk_deallocation_flush_threshold); - } -} - -void AllocatorBulkDeallocationFlushThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allocator_bulk_deallocation_flush_threshold = - DBConfig().options.allocator_bulk_deallocation_flush_threshold; - if (db) { - BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( - config.options.allocator_bulk_deallocation_flush_threshold); - } -} - -Value AllocatorBulkDeallocationFlushThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_bulk_deallocation_flush_threshold)); -} - -//===----------------------------------------------------------------------===// -// Allocator Flush Threshold -//===----------------------------------------------------------------------===// -void AllocatorFlushThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.allocator_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); - } -} - -void AllocatorFlushThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.allocator_flush_threshold = DBConfig().options.allocator_flush_threshold; - if (db) { - TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); - } -} - -Value AllocatorFlushThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_flush_threshold)); -} - -//===----------------------------------------------------------------------===// -// Allow Community Extensions -//===----------------------------------------------------------------------===// -bool AllowCommunityExtensionsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && !config.options.allow_community_extensions) { - auto new_value = input.GetValue(); - if (new_value) { - throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); - } - return false; - } - return true; -} - -bool AllowCommunityExtensionsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db && !config.options.allow_community_extensions) { - if (DBConfig().options.allow_community_extensions) { - throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); - } - return false; - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allow Persistent Secrets -//===----------------------------------------------------------------------===// -void AllowPersistentSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto value = input.DefaultCastAs(LogicalType::BOOLEAN); - config.secret_manager->SetEnablePersistentSecrets(value.GetValue()); -} - -void AllowPersistentSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetEnablePersistentSecrets(); -} - -Value AllowPersistentSecretsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BOOLEAN(config.secret_manager->PersistentSecretsEnabled()); -} - -//===----------------------------------------------------------------------===// -// Allow Unredacted Secrets -//===----------------------------------------------------------------------===// -bool AllowUnredactedSecretsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && input.GetValue()) { - throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); - } - return true; -} - -bool AllowUnredactedSecretsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allow Unsigned Extensions -//===----------------------------------------------------------------------===// -bool AllowUnsignedExtensionsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (db && input.GetValue()) { - throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); - } - return true; -} - -bool AllowUnsignedExtensionsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Allowed Directories -//===----------------------------------------------------------------------===// -void AllowedDirectoriesSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { - throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); - } - config.options.allowed_directories.clear(); - auto &list = ListValue::GetChildren(input); - for (auto &val : list) { - config.AddAllowedDirectory(val.GetValue()); - } -} - -void AllowedDirectoriesSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { - throw InvalidInputException("Cannot change allowed_directories when enable_external_access is disabled"); - } - config.options.allowed_directories = DBConfig().options.allowed_directories; -} - -Value AllowedDirectoriesSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - vector allowed_directories; - for (auto &dir : config.options.allowed_directories) { - allowed_directories.emplace_back(dir); - } - return Value::LIST(LogicalType::VARCHAR, std::move(allowed_directories)); -} - -//===----------------------------------------------------------------------===// -// Allowed Paths -//===----------------------------------------------------------------------===//void -void AllowedPathsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { - throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); - } - config.options.allowed_paths.clear(); - auto &list = ListValue::GetChildren(input); - for (auto &val : list) { - config.AddAllowedPath(val.GetValue()); - } -} - -void AllowedPathsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { - throw InvalidInputException("Cannot change allowed_paths when enable_external_access is disabled"); - } - config.options.allowed_paths = DBConfig().options.allowed_paths; -} - -Value AllowedPathsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - vector allowed_paths; - for (auto &dir : config.options.allowed_paths) { - allowed_paths.emplace_back(dir); - } - return Value::LIST(LogicalType::VARCHAR, std::move(allowed_paths)); -} - -//===----------------------------------------------------------------------===// -// Arrow Large Buffer Size -//===----------------------------------------------------------------------===// -void ArrowLargeBufferSizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto export_large_buffers_arrow = input.GetValue(); - config.options.arrow_offset_size = export_large_buffers_arrow ? ArrowOffsetSize::LARGE : ArrowOffsetSize::REGULAR; -} - -Value ArrowLargeBufferSizeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - bool export_large_buffers_arrow = config.options.arrow_offset_size == ArrowOffsetSize::LARGE; - return Value::BOOLEAN(export_large_buffers_arrow); -} - -//===----------------------------------------------------------------------===// -// Checkpoint Threshold -//===----------------------------------------------------------------------===// -void CheckpointThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - idx_t new_limit = DBConfig::ParseMemoryLimit(input.ToString()); - config.options.checkpoint_wal_size = new_limit; -} - -Value CheckpointThresholdSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.checkpoint_wal_size)); -} - -//===----------------------------------------------------------------------===// -// Custom Profiling Settings -//===----------------------------------------------------------------------===// -bool IsEnabledOptimizer(MetricsType metric, const set &disabled_optimizers) { - auto matching_optimizer_type = MetricsUtils::GetOptimizerTypeByMetric(metric); - if (matching_optimizer_type != OptimizerType::INVALID && - disabled_optimizers.find(matching_optimizer_type) == disabled_optimizers.end()) { - return true; - } - return false; -} - -static profiler_settings_t FillTreeNodeSettings(unordered_map &json, - const set &disabled_optimizers) { - profiler_settings_t metrics; - - string invalid_settings; - for (auto &entry : json) { - MetricsType setting; - try { - setting = EnumUtil::FromString(StringUtil::Upper(entry.first)); - } catch (std::exception &ex) { - if (!invalid_settings.empty()) { - invalid_settings += ", "; - } - invalid_settings += entry.first; - continue; - } - if (StringUtil::Lower(entry.second) == "true" && - (!MetricsUtils::IsOptimizerMetric(setting) || IsEnabledOptimizer(setting, disabled_optimizers))) { - metrics.insert(setting); - } - } - - if (!invalid_settings.empty()) { - throw IOException("Invalid custom profiler settings: \"%s\"", invalid_settings); - } - return metrics; -} - -void AddOptimizerMetrics(profiler_settings_t &settings, const set &disabled_optimizers) { - if (settings.find(MetricsType::ALL_OPTIMIZERS) != settings.end()) { - auto optimizer_metrics = MetricsUtils::GetOptimizerMetrics(); - for (auto &metric : optimizer_metrics) { - if (IsEnabledOptimizer(metric, disabled_optimizers)) { - settings.insert(metric); - } - } - } -} - -void CustomProfilingSettingsSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - - // parse the file content - unordered_map json; - try { - json = StringUtil::ParseJSONMap(input.ToString()); - } catch (std::exception &ex) { - throw IOException("Could not parse the custom profiler settings file due to incorrect JSON: \"%s\". Make sure " - "all the keys and values start with a quote. ", - input.ToString()); - } - - config.enable_profiler = true; - auto &db_config = DBConfig::GetConfig(context); - auto &disabled_optimizers = db_config.options.disabled_optimizers; - - auto settings = FillTreeNodeSettings(json, disabled_optimizers); - AddOptimizerMetrics(settings, disabled_optimizers); - config.profiler_settings = settings; -} - -void CustomProfilingSettingsSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.enable_profiler = ClientConfig().enable_profiler; - config.profiler_settings = ProfilingInfo::DefaultSettings(); -} - -Value CustomProfilingSettingsSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - - string profiling_settings_str; - for (auto &entry : config.profiler_settings) { - if (!profiling_settings_str.empty()) { - profiling_settings_str += ", "; - } - profiling_settings_str += StringUtil::Format("\"%s\": \"true\"", EnumUtil::ToString(entry)); - } - return Value(StringUtil::Format("{%s}", profiling_settings_str)); -} - -//===----------------------------------------------------------------------===// -// Custom User Agent -//===----------------------------------------------------------------------===// -void CustomUserAgentSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db) { - throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); - } - config.options.custom_user_agent = - config.options.custom_user_agent.empty() ? new_value : config.options.custom_user_agent + " " + new_value; -} - -void CustomUserAgentSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); - } - config.options.custom_user_agent = DBConfig().options.custom_user_agent; -} - -//===----------------------------------------------------------------------===// -// Default Block Size -//===----------------------------------------------------------------------===// -void DefaultBlockSizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto block_alloc_size = input.GetValue(); - Storage::VerifyBlockAllocSize(block_alloc_size); - config.options.default_block_alloc_size = block_alloc_size; -} - -void DefaultBlockSizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.default_block_alloc_size = DBConfig().options.default_block_alloc_size; -} - -Value DefaultBlockSizeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::UBIGINT(config.options.default_block_alloc_size); -} - -//===----------------------------------------------------------------------===// -// Default Collation -//===----------------------------------------------------------------------===// -void DefaultCollationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - config.options.collation = parameter; -} - -void DefaultCollationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.collation = DBConfig().options.collation; -} - -void DefaultCollationSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - // bind the collation to verify that it exists - ExpressionBinder::TestCollation(context, parameter); - auto &config = DBConfig::GetConfig(context); - config.options.collation = parameter; -} - -void DefaultCollationSetting::ResetLocal(ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - config.options.collation = DBConfig().options.collation; -} - -Value DefaultCollationSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.collation); -} - -//===----------------------------------------------------------------------===// -// Default Null Order -//===----------------------------------------------------------------------===// -void DefaultNullOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - - if (parameter == "nulls_first" || parameter == "nulls first" || parameter == "null first" || parameter == "first") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST; - } else if (parameter == "nulls_last" || parameter == "nulls last" || parameter == "null last" || - parameter == "last") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST; - } else if (parameter == "nulls_first_on_asc_last_on_desc" || parameter == "sqlite" || parameter == "mysql") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; - } else if (parameter == "nulls_last_on_asc_first_on_desc" || parameter == "postgres") { - config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; - } else { - throw ParserException("Unrecognized parameter for option NULL_ORDER \"%s\", expected either NULLS FIRST, NULLS " - "LAST, SQLite, MySQL or Postgres", - parameter); - } -} - -//===----------------------------------------------------------------------===// -// Default Order -//===----------------------------------------------------------------------===// -void DefaultOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - if (parameter == "ascending" || parameter == "asc") { - config.options.default_order_type = OrderType::ASCENDING; - } else if (parameter == "descending" || parameter == "desc") { - config.options.default_order_type = OrderType::DESCENDING; - } else { - throw InvalidInputException("Unrecognized parameter for option DEFAULT_ORDER \"%s\". Expected ASC or DESC.", - parameter); - } -} - -Value DefaultOrderSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - switch (config.options.default_order_type) { - case OrderType::ASCENDING: - return "asc"; - case OrderType::DESCENDING: - return "desc"; - default: - throw InternalException("Unknown order type setting"); - } -} - -//===----------------------------------------------------------------------===// -// Default Secret Storage -//===----------------------------------------------------------------------===// -void DefaultSecretStorageSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.secret_manager->SetDefaultStorage(input.ToString()); -} - -void DefaultSecretStorageSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetDefaultStorage(); -} - -Value DefaultSecretStorageSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.secret_manager->DefaultStorage(); -} - -//===----------------------------------------------------------------------===// -// Disabled Filesystems -//===----------------------------------------------------------------------===// -void DisabledFilesystemsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!db) { - throw InternalException("disabled_filesystems can only be set in an active database"); - } - auto &fs = FileSystem::GetFileSystem(*db); - auto list = StringUtil::Split(input.ToString(), ","); - fs.SetDisabledFileSystems(list); -} - -void DisabledFilesystemsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!db) { - throw InternalException("disabled_filesystems can only be set in an active database"); - } - auto &fs = FileSystem::GetFileSystem(*db); - fs.SetDisabledFileSystems(vector()); -} - -Value DisabledFilesystemsSetting::GetSetting(const ClientContext &context) { - return Value(""); -} - -//===----------------------------------------------------------------------===// -// Disabled Optimizers -//===----------------------------------------------------------------------===// -void DisabledOptimizersSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto list = StringUtil::Split(input.ToString(), ","); - set disabled_optimizers; - for (auto &entry : list) { - auto param = StringUtil::Lower(entry); - StringUtil::Trim(param); - if (param.empty()) { - continue; - } - disabled_optimizers.insert(OptimizerTypeFromString(param)); - } - config.options.disabled_optimizers = std::move(disabled_optimizers); -} - -void DisabledOptimizersSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.disabled_optimizers = DBConfig().options.disabled_optimizers; -} - -Value DisabledOptimizersSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - string result; - for (auto &optimizer : config.options.disabled_optimizers) { - if (!result.empty()) { - result += ","; - } - result += OptimizerTypeToString(optimizer); - } - return Value(result); -} - -//===----------------------------------------------------------------------===// -// Duckdb Api -//===----------------------------------------------------------------------===// -void DuckDBAPISetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_value = input.GetValue(); - if (db) { - throw InvalidInputException("Cannot change duckdb_api setting while database is running"); - } - config.options.duckdb_api = new_value; -} - -void DuckDBAPISetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change duckdb_api setting while database is running"); - } - config.options.duckdb_api = GetDefaultUserAgent(); -} - -Value DuckDBAPISetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(config.options.duckdb_api); -} - -//===----------------------------------------------------------------------===// -// Enable External Access -//===----------------------------------------------------------------------===// -bool EnableExternalAccessSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!db) { - return true; - } - if (input.GetValue()) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); - } - if (db && config.options.enable_external_access) { - // we are turning off external access - add any already attached databases to the list of accepted paths - auto &db_manager = DatabaseManager::Get(*db); - auto attached_paths = db_manager.GetAttachedDatabasePaths(); - for (auto &path : attached_paths) { - config.AddAllowedPath(path); - config.AddAllowedPath(path + ".wal"); - } - } - if (config.options.use_temporary_directory && !config.options.temporary_directory.empty()) { - // if temp directory is enabled we can also write there - config.AddAllowedDirectory(config.options.temporary_directory); - } - return true; -} - -bool EnableExternalAccessSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - if (db) { - throw InvalidInputException("Cannot change enable_external_access setting while database is running"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Enable Object Cache -//===----------------------------------------------------------------------===// -void EnableObjectCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { -} - -void EnableObjectCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { -} - -Value EnableObjectCacheSetting::GetSetting(const ClientContext &context) { - return Value(); -} - -//===----------------------------------------------------------------------===// -// Enable Profiling -//===----------------------------------------------------------------------===// -void EnableProfilingSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - - auto &config = ClientConfig::GetConfig(context); - config.enable_profiler = true; - config.emit_profiler_output = true; - config.profiler_settings = ClientConfig().profiler_settings; - - if (parameter == "json") { - config.profiler_print_format = ProfilerPrintFormat::JSON; - } else if (parameter == "query_tree") { - config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE; - } else if (parameter == "query_tree_optimizer") { - config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; - - // add optimizer settings to the profiler settings - auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); - for (auto &setting : optimizer_settings) { - config.profiler_settings.insert(setting); - } - - // add the phase timing settings to the profiler settings - auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); - for (auto &setting : phase_timing_settings) { - config.profiler_settings.insert(setting); - } - } else if (parameter == "no_output") { - config.profiler_print_format = ProfilerPrintFormat::NO_OUTPUT; - config.emit_profiler_output = false; - } else if (parameter == "html") { - config.profiler_print_format = ProfilerPrintFormat::HTML; - } else if (parameter == "graphviz") { - config.profiler_print_format = ProfilerPrintFormat::GRAPHVIZ; - } else { - throw ParserException( - "Unrecognized print format %s, supported formats: [json, query_tree, query_tree_optimizer, no_output]", - parameter); - } -} - -void EnableProfilingSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.profiler_print_format = ClientConfig().profiler_print_format; - config.enable_profiler = ClientConfig().enable_profiler; - config.emit_profiler_output = ClientConfig().emit_profiler_output; - config.profiler_settings = ClientConfig().profiler_settings; -} - -Value EnableProfilingSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - if (!config.enable_profiler) { - return Value(); - } - switch (config.profiler_print_format) { - case ProfilerPrintFormat::JSON: - return Value("json"); - case ProfilerPrintFormat::QUERY_TREE: - return Value("query_tree"); - case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: - return Value("query_tree_optimizer"); - case ProfilerPrintFormat::NO_OUTPUT: - return Value("no_output"); - case ProfilerPrintFormat::HTML: - return Value("html"); - case ProfilerPrintFormat::GRAPHVIZ: - return Value("graphviz"); - default: - throw InternalException("Unsupported profiler print format"); - } -} - -//===----------------------------------------------------------------------===// -// Enable Progress Bar Print -//===----------------------------------------------------------------------===// -void EnableProgressBarPrintSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.print_progress_bar = input.GetValue(); -} - -void EnableProgressBarPrintSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.print_progress_bar = ClientConfig().print_progress_bar; -} - -Value EnableProgressBarPrintSetting::GetSetting(const ClientContext &context) { - return Value::BOOLEAN(ClientConfig::GetConfig(context).print_progress_bar); -} - -//===----------------------------------------------------------------------===// -// Enable Progress Bar -//===----------------------------------------------------------------------===// -bool EnableProgressBarSetting::OnLocalSet(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - return true; -} - -bool EnableProgressBarSetting::OnLocalReset(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - return true; -} - -//===----------------------------------------------------------------------===// -// External Threads -//===----------------------------------------------------------------------===// -bool ExternalThreadsSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_val = input.GetValue(); - if (new_val < 0) { - throw SyntaxException("Must have a non-negative number of external threads!"); - } - auto new_external_threads = NumericCast(new_val); - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); - } - return true; -} - -bool ExternalThreadsSetting::OnGlobalReset(DatabaseInstance *db, DBConfig &config) { - idx_t new_external_threads = DBConfig().options.external_threads; - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); - } - return true; -} - -//===----------------------------------------------------------------------===// -// File Search Path -//===----------------------------------------------------------------------===// -void FileSearchPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.file_search_path = parameter; -} - -void FileSearchPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - client_data.file_search_path.clear(); -} - -Value FileSearchPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return Value(client_data.file_search_path); -} - -//===----------------------------------------------------------------------===// -// Force Bitpacking Mode -//===----------------------------------------------------------------------===// -void ForceBitpackingModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto mode_str = StringUtil::Lower(input.ToString()); - auto mode = BitpackingModeFromString(mode_str); - if (mode == BitpackingMode::INVALID) { - throw ParserException("Unrecognized option for force_bitpacking_mode, expected none, constant, constant_delta, " - "delta_for, or for"); - } - config.options.force_bitpacking_mode = mode; -} - -void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.force_bitpacking_mode = DBConfig().options.force_bitpacking_mode; -} - -Value ForceBitpackingModeSetting::GetSetting(const ClientContext &context) { - return Value(BitpackingModeToString(context.db->config.options.force_bitpacking_mode)); -} - -//===----------------------------------------------------------------------===// -// Force Compression -//===----------------------------------------------------------------------===// -void ForceCompressionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto compression = StringUtil::Lower(input.ToString()); - if (compression == "none" || compression == "auto") { - config.options.force_compression = CompressionType::COMPRESSION_AUTO; - } else { - auto compression_type = CompressionTypeFromString(compression); - if (CompressionTypeIsDeprecated(compression_type)) { - throw ParserException("Attempted to force a deprecated compression type (%s)", - CompressionTypeToString(compression_type)); - } - if (compression_type == CompressionType::COMPRESSION_AUTO) { - auto compression_types = StringUtil::Join(ListCompressionTypes(), ", "); - throw ParserException("Unrecognized option for PRAGMA force_compression, expected %s", compression_types); - } - config.options.force_compression = compression_type; - } -} - -void ForceCompressionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.force_compression = DBConfig().options.force_compression; -} - -Value ForceCompressionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(*context.db); - return CompressionTypeToString(config.options.force_compression); -} - -//===----------------------------------------------------------------------===// -// Home Directory -//===----------------------------------------------------------------------===// -void HomeDirectorySetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - if (!input.IsNull() && FileSystem::GetFileSystem(context).IsRemoteFile(input.ToString())) { - throw InvalidInputException("Cannot set the home directory to a remote path"); - } - config.home_directory = input.IsNull() ? string() : input.ToString(); -} - -//===----------------------------------------------------------------------===// -// Index Scan Percentage -//===----------------------------------------------------------------------===// -bool IndexScanPercentageSetting::OnGlobalSet(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto index_scan_percentage = input.GetValue(); - if (index_scan_percentage < 0 || index_scan_percentage > 1.0) { - throw InvalidInputException("the index scan percentage must be within [0, 1]"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Log Query Path -//===----------------------------------------------------------------------===// -void LogQueryPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto &client_data = ClientData::Get(context); - auto path = input.ToString(); - if (path.empty()) { - // empty path: clean up query writer - client_data.log_query_writer = nullptr; - } else { - client_data.log_query_writer = make_uniq(FileSystem::GetFileSystem(context), path, - BufferedFileWriter::DEFAULT_OPEN_FLAGS); - } -} - -void LogQueryPathSetting::ResetLocal(ClientContext &context) { - auto &client_data = ClientData::Get(context); - // TODO: verify that this does the right thing - client_data.log_query_writer = std::move(ClientData(context).log_query_writer); -} - -Value LogQueryPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return client_data.log_query_writer ? Value(client_data.log_query_writer->path) : Value(); -} - -//===----------------------------------------------------------------------===// -// Max Memory -//===----------------------------------------------------------------------===// -void MaxMemorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.options.maximum_memory = DBConfig::ParseMemoryLimit(input.ToString()); - if (db) { - BufferManager::GetBufferManager(*db).SetMemoryLimit(config.options.maximum_memory); - } -} - -void MaxMemorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.SetDefaultMaxMemory(); -} - -Value MaxMemorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_memory)); -} - -//===----------------------------------------------------------------------===// -// Max Temp Directory Size -//===----------------------------------------------------------------------===// -void MaxTempDirectorySizeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (input == "90% of available disk space") { - ResetGlobal(db, config); - return; - } - auto maximum_swap_space = DBConfig::ParseMemoryLimit(input.ToString()); - if (maximum_swap_space == DConstants::INVALID_INDEX) { - // We use INVALID_INDEX to indicate that the value is not set by the user - // use one lower to indicate 'unlimited' - maximum_swap_space--; - } - if (!db) { - config.options.maximum_swap_space = maximum_swap_space; - return; - } - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetSwapLimit(maximum_swap_space); - config.options.maximum_swap_space = maximum_swap_space; -} - -void MaxTempDirectorySizeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.maximum_swap_space = DConstants::INVALID_INDEX; - if (!db) { - return; - } - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetSwapLimit(); -} - -Value MaxTempDirectorySizeSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - if (config.options.maximum_swap_space != DConstants::INVALID_INDEX) { - // Explicitly set by the user - return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_swap_space)); - } - auto &buffer_manager = BufferManager::GetBufferManager(context); - // Database is initialized, use the setting from the temporary directory - auto max_swap = buffer_manager.GetMaxSwap(); - if (max_swap.IsValid()) { - return Value(StringUtil::BytesToHumanReadableString(max_swap.GetIndex())); - } else { - // The temp directory has not been used yet - return Value("90% of available disk space"); - } -} - -//===----------------------------------------------------------------------===// -// Ordered Aggregate Threshold -//===----------------------------------------------------------------------===// -bool OrderedAggregateThresholdSetting::OnLocalSet(ClientContext &context, const Value &input) { - const auto param = input.GetValue(); - if (param <= 0) { - throw ParserException("Invalid option for PRAGMA ordered_aggregate_threshold, value must be positive"); - } - return true; -} - -//===----------------------------------------------------------------------===// -// Password -//===----------------------------------------------------------------------===// -void PasswordSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - // nop -} - -void PasswordSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - // nop -} - -Value PasswordSetting::GetSetting(const ClientContext &context) { - return Value(); -} - -//===----------------------------------------------------------------------===// -// Perfect Ht Threshold -//===----------------------------------------------------------------------===// -void PerfectHtThresholdSetting::SetLocal(ClientContext &context, const Value &input) { - auto bits = input.GetValue(); - if (bits < 0 || bits > 32) { - throw ParserException("Perfect HT threshold out of range: should be within range 0 - 32"); - } - ClientConfig::GetConfig(context).perfect_ht_threshold = NumericCast(bits); -} - -Value PerfectHtThresholdSetting::GetSetting(const ClientContext &context) { - return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).perfect_ht_threshold)); -} - -//===----------------------------------------------------------------------===// -// Profile Output -//===----------------------------------------------------------------------===// -void ProfileOutputSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - auto parameter = input.ToString(); - config.profiler_save_location = parameter; -} - -void ProfileOutputSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).profiler_save_location = ClientConfig().profiler_save_location; -} - -Value ProfileOutputSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(config.profiler_save_location); -} - -//===----------------------------------------------------------------------===// -// Profiling Mode -//===----------------------------------------------------------------------===// -void ProfilingModeSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = StringUtil::Lower(input.ToString()); - auto &config = ClientConfig::GetConfig(context); - if (parameter == "standard") { - config.enable_profiler = true; - config.enable_detailed_profiling = false; - } else if (parameter == "detailed") { - config.enable_profiler = true; - config.enable_detailed_profiling = true; - - // add optimizer settings to the profiler settings - auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); - for (auto &setting : optimizer_settings) { - config.profiler_settings.insert(setting); - } - - // add the phase timing settings to the profiler settings - auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); - for (auto &setting : phase_timing_settings) { - config.profiler_settings.insert(setting); - } - } else { - throw ParserException("Unrecognized profiling mode \"%s\", supported formats: [standard, detailed]", parameter); - } -} - -void ProfilingModeSetting::ResetLocal(ClientContext &context) { - ClientConfig::GetConfig(context).enable_profiler = ClientConfig().enable_profiler; - ClientConfig::GetConfig(context).enable_detailed_profiling = ClientConfig().enable_detailed_profiling; - ClientConfig::GetConfig(context).emit_profiler_output = ClientConfig().emit_profiler_output; - ClientConfig::GetConfig(context).profiler_settings = ClientConfig().profiler_settings; -} - -Value ProfilingModeSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - if (!config.enable_profiler) { - return Value(); - } - return Value(config.enable_detailed_profiling ? "detailed" : "standard"); -} - -//===----------------------------------------------------------------------===// -// Progress Bar Time -//===----------------------------------------------------------------------===// -void ProgressBarTimeSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.wait_time = input.GetValue(); - config.enable_progress_bar = true; -} - -void ProgressBarTimeSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - ProgressBar::SystemOverrideCheck(config); - config.wait_time = ClientConfig().wait_time; - config.enable_progress_bar = ClientConfig().enable_progress_bar; -} - -Value ProgressBarTimeSetting::GetSetting(const ClientContext &context) { - return Value::BIGINT(ClientConfig::GetConfig(context).wait_time); -} - -//===----------------------------------------------------------------------===// -// Schema -//===----------------------------------------------------------------------===// -void SchemaSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), CatalogSetPathType::SET_SCHEMA); -} - -void SchemaSetting::ResetLocal(ClientContext &context) { - // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Reset(); -} - -Value SchemaSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - return client_data.catalog_search_path->GetDefault().schema; -} - -//===----------------------------------------------------------------------===// -// Search Path -//===----------------------------------------------------------------------===// -void SearchPathSetting::SetLocal(ClientContext &context, const Value &input) { - auto parameter = input.ToString(); - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), CatalogSetPathType::SET_SCHEMAS); -} - -void SearchPathSetting::ResetLocal(ClientContext &context) { - // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting - auto &client_data = ClientData::Get(context); - client_data.catalog_search_path->Reset(); -} - -Value SearchPathSetting::GetSetting(const ClientContext &context) { - auto &client_data = ClientData::Get(context); - auto &set_paths = client_data.catalog_search_path->GetSetPaths(); - return Value(CatalogSearchEntry::ListToString(set_paths)); -} - -//===----------------------------------------------------------------------===// -// Secret Directory -//===----------------------------------------------------------------------===// -void SecretDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - config.secret_manager->SetPersistentSecretPath(input.ToString()); -} - -void SecretDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.secret_manager->ResetPersistentSecretPath(); -} - -Value SecretDirectorySetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return config.secret_manager->PersistentSecretPath(); -} - -//===----------------------------------------------------------------------===// -// Storage Compatibility Version -//===----------------------------------------------------------------------===// -void StorageCompatibilityVersionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto version_string = input.GetValue(); - auto serialization_compatibility = SerializationCompatibility::FromString(version_string); - config.options.serialization_compatibility = serialization_compatibility; -} - -void StorageCompatibilityVersionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - config.options.serialization_compatibility = DBConfig().options.serialization_compatibility; -} - -Value StorageCompatibilityVersionSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - - auto &version_name = config.options.serialization_compatibility.duckdb_version; - return Value(version_name); -} - -//===----------------------------------------------------------------------===// -// Streaming Buffer Size -//===----------------------------------------------------------------------===// -void StreamingBufferSizeSetting::SetLocal(ClientContext &context, const Value &input) { - auto &config = ClientConfig::GetConfig(context); - config.streaming_buffer_size = DBConfig::ParseMemoryLimit(input.ToString()); -} - -void StreamingBufferSizeSetting::ResetLocal(ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - config.SetDefaultStreamingBufferSize(); -} - -Value StreamingBufferSizeSetting::GetSetting(const ClientContext &context) { - auto &config = ClientConfig::GetConfig(context); - return Value(StringUtil::BytesToHumanReadableString(config.streaming_buffer_size)); -} - -//===----------------------------------------------------------------------===// -// Temp Directory -//===----------------------------------------------------------------------===// -void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - if (!config.options.enable_external_access) { - throw PermissionException("Modifying the temp_directory has been disabled by configuration"); - } - config.options.temporary_directory = input.IsNull() ? "" : input.ToString(); - config.options.use_temporary_directory = !config.options.temporary_directory.empty(); - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); - } -} - -void TempDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - if (!config.options.enable_external_access) { - throw PermissionException("Modifying the temp_directory has been disabled by configuration"); - } - config.SetDefaultTempDirectory(); - config.options.use_temporary_directory = DBConfig().options.use_temporary_directory; - if (db) { - auto &buffer_manager = BufferManager::GetBufferManager(*db); - buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); - } -} - -Value TempDirectorySetting::GetSetting(const ClientContext &context) { - auto &buffer_manager = BufferManager::GetBufferManager(context); - return Value(buffer_manager.GetTemporaryDirectory()); -} - -//===----------------------------------------------------------------------===// -// Threads -//===----------------------------------------------------------------------===// -void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - auto new_val = input.GetValue(); - if (new_val < 1) { - throw SyntaxException("Must have at least 1 thread!"); - } - auto new_maximum_threads = NumericCast(new_val); - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); - } - config.options.maximum_threads = new_maximum_threads; -} - -void ThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - idx_t new_maximum_threads = config.GetSystemMaxThreads(*config.file_system); - if (db) { - TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); - } - config.options.maximum_threads = new_maximum_threads; -} - -Value ThreadsSetting::GetSetting(const ClientContext &context) { - auto &config = DBConfig::GetConfig(context); - return Value::BIGINT(NumericCast(config.options.maximum_threads)); -} - -//===----------------------------------------------------------------------===// -// Username -//===----------------------------------------------------------------------===// -void UsernameSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { - // nop -} - -void UsernameSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { - // nop -} - -Value UsernameSetting::GetSetting(const ClientContext &context) { - return Value(); -} - -} // namespace duckdb diff --git a/src/duckdb/src/main/settings/settings.cpp b/src/duckdb/src/main/settings/settings.cpp new file mode 100644 index 000000000..8cdcf42ef --- /dev/null +++ b/src/duckdb/src/main/settings/settings.cpp @@ -0,0 +1,2056 @@ +#include "duckdb/main/settings.hpp" + +#include "duckdb/catalog/catalog_search_path.hpp" +#include "duckdb/common/string_util.hpp" +#include "duckdb/main/attached_database.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/main/client_data.hpp" +#include "duckdb/main/config.hpp" +#include "duckdb/main/database.hpp" +#include "duckdb/main/database_manager.hpp" +#include "duckdb/main/query_profiler.hpp" +#include "duckdb/main/secret/secret_manager.hpp" +#include "duckdb/parallel/task_scheduler.hpp" +#include "duckdb/parser/parser.hpp" +#include "duckdb/planner/expression_binder.hpp" +#include "duckdb/storage/buffer/buffer_pool.hpp" +#include "duckdb/storage/buffer_manager.hpp" +#include "duckdb/storage/storage_manager.hpp" + +namespace duckdb { + +const string GetDefaultUserAgent() { + return StringUtil::Format("duckdb/%s(%s)", DuckDB::LibraryVersion(), DuckDB::Platform()); +} + +//===--------------------------------------------------------------------===// +// Access Mode +//===--------------------------------------------------------------------===// +void AccessModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (db) { + throw InvalidInputException("Cannot change access_mode setting while database is running - it must be set when " + "opening or attaching the database"); + } + auto parameter = StringUtil::Lower(input.ToString()); + if (parameter == "automatic") { + config.options.access_mode = AccessMode::AUTOMATIC; + } else if (parameter == "read_only") { + config.options.access_mode = AccessMode::READ_ONLY; + } else if (parameter == "read_write") { + config.options.access_mode = AccessMode::READ_WRITE; + } else { + throw InvalidInputException( + "Unrecognized parameter for option ACCESS_MODE \"%s\". Expected READ_ONLY or READ_WRITE.", parameter); + } +} + +void AccessModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.access_mode = DBConfig().options.access_mode; +} + +Value AccessModeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + switch (config.options.access_mode) { + case AccessMode::AUTOMATIC: + return "automatic"; + case AccessMode::READ_ONLY: + return "read_only"; + case AccessMode::READ_WRITE: + return "read_write"; + default: + throw InternalException("Unknown access mode setting"); + } +} + +//===--------------------------------------------------------------------===// +// Allow Persistent Secrets +//===--------------------------------------------------------------------===// +void AllowPersistentSecrets::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto value = input.DefaultCastAs(LogicalType::BOOLEAN); + config.secret_manager->SetEnablePersistentSecrets(value.GetValue()); +} + +void AllowPersistentSecrets::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetEnablePersistentSecrets(); +} + +Value AllowPersistentSecrets::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.secret_manager->PersistentSecretsEnabled()); +} + +//===--------------------------------------------------------------------===// +// Access Mode +//===--------------------------------------------------------------------===// +void CatalogErrorMaxSchema::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.catalog_error_max_schemas = UBigIntValue::Get(input); +} + +void CatalogErrorMaxSchema::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.catalog_error_max_schemas = DBConfig().options.catalog_error_max_schemas; +} + +Value CatalogErrorMaxSchema::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.catalog_error_max_schemas); +} + +//===--------------------------------------------------------------------===// +// Checkpoint Threshold +//===--------------------------------------------------------------------===// +void CheckpointThresholdSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + idx_t new_limit = DBConfig::ParseMemoryLimit(input.ToString()); + config.options.checkpoint_wal_size = new_limit; +} + +void CheckpointThresholdSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.checkpoint_wal_size = DBConfig().options.checkpoint_wal_size; +} + +Value CheckpointThresholdSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.checkpoint_wal_size)); +} + +//===--------------------------------------------------------------------===// +// Debug Checkpoint Abort +//===--------------------------------------------------------------------===// +void DebugCheckpointAbort::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto checkpoint_abort = StringUtil::Lower(input.ToString()); + if (checkpoint_abort == "none") { + config.options.checkpoint_abort = CheckpointAbort::NO_ABORT; + } else if (checkpoint_abort == "before_truncate") { + config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE; + } else if (checkpoint_abort == "before_header") { + config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER; + } else if (checkpoint_abort == "after_free_list_write") { + config.options.checkpoint_abort = CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE; + } else { + throw ParserException( + "Unrecognized option for PRAGMA debug_checkpoint_abort, expected none, before_truncate or before_header"); + } +} + +void DebugCheckpointAbort::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.checkpoint_abort = DBConfig().options.checkpoint_abort; +} + +Value DebugCheckpointAbort::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(*context.db); + auto setting = config.options.checkpoint_abort; + switch (setting) { + case CheckpointAbort::NO_ABORT: + return "none"; + case CheckpointAbort::DEBUG_ABORT_BEFORE_TRUNCATE: + return "before_truncate"; + case CheckpointAbort::DEBUG_ABORT_BEFORE_HEADER: + return "before_header"; + case CheckpointAbort::DEBUG_ABORT_AFTER_FREE_LIST_WRITE: + return "after_free_list_write"; + default: + throw InternalException("Type not implemented for CheckpointAbort"); + } +} + +//===--------------------------------------------------------------------===// +// Debug Force External +//===--------------------------------------------------------------------===// +void DebugForceExternal::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_external = ClientConfig().force_external; +} + +void DebugForceExternal::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).force_external = input.GetValue(); +} + +Value DebugForceExternal::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).force_external); +} + +//===--------------------------------------------------------------------===// +// Debug Force NoCrossProduct +//===--------------------------------------------------------------------===// +void DebugForceNoCrossProduct::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_no_cross_product = ClientConfig().force_no_cross_product; +} + +void DebugForceNoCrossProduct::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).force_no_cross_product = input.GetValue(); +} + +Value DebugForceNoCrossProduct::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).force_no_cross_product); +} + +//===--------------------------------------------------------------------===// +// Debug Skip Checkpoint On Commit +//===--------------------------------------------------------------------===// +void DebugSkipCheckpointOnCommit::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { + config.options.debug_skip_checkpoint_on_commit = BooleanValue::Get(parameter); +} + +void DebugSkipCheckpointOnCommit::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.debug_skip_checkpoint_on_commit = DBConfig().options.debug_skip_checkpoint_on_commit; +} + +Value DebugSkipCheckpointOnCommit::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(*context.db); + return Value::BOOLEAN(config.options.debug_skip_checkpoint_on_commit); +} + +//===--------------------------------------------------------------------===// +// Ordered Aggregate Threshold +//===--------------------------------------------------------------------===// +void OrderedAggregateThreshold::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).ordered_aggregate_threshold = ClientConfig().ordered_aggregate_threshold; +} + +void OrderedAggregateThreshold::SetLocal(ClientContext &context, const Value &input) { + const auto param = input.GetValue(); + if (param <= 0) { + throw ParserException("Invalid option for PRAGMA ordered_aggregate_threshold, value must be positive"); + } + ClientConfig::GetConfig(context).ordered_aggregate_threshold = param; +} + +Value OrderedAggregateThreshold::GetSetting(const ClientContext &context) { + return Value::UBIGINT(ClientConfig::GetConfig(context).ordered_aggregate_threshold); +} + +//===--------------------------------------------------------------------===// +// Debug Window Mode +//===--------------------------------------------------------------------===// +void DebugWindowMode::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto param = StringUtil::Lower(input.ToString()); + if (param == "window") { + config.options.window_mode = WindowAggregationMode::WINDOW; + } else if (param == "combine") { + config.options.window_mode = WindowAggregationMode::COMBINE; + } else if (param == "separate") { + config.options.window_mode = WindowAggregationMode::SEPARATE; + } else { + throw ParserException("Unrecognized option for PRAGMA debug_window_mode, expected window, combine or separate"); + } +} + +void DebugWindowMode::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.window_mode = DBConfig().options.window_mode; +} + +Value DebugWindowMode::GetSetting(const ClientContext &context) { + return Value(); +} + +//===--------------------------------------------------------------------===// +// Debug AsOf Join +//===--------------------------------------------------------------------===// +void DebugAsOfIEJoin::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).force_asof_iejoin = ClientConfig().force_asof_iejoin; +} + +void DebugAsOfIEJoin::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).force_asof_iejoin = input.GetValue(); +} + +Value DebugAsOfIEJoin::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).force_asof_iejoin); +} + +//===--------------------------------------------------------------------===// +// Prefer Range Joins +//===--------------------------------------------------------------------===// +void PreferRangeJoins::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).prefer_range_joins = ClientConfig().prefer_range_joins; +} + +void PreferRangeJoins::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).prefer_range_joins = input.GetValue(); +} + +Value PreferRangeJoins::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).prefer_range_joins); +} + +//===--------------------------------------------------------------------===// +// Default Collation +//===--------------------------------------------------------------------===// +void DefaultCollationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + config.options.collation = parameter; +} + +void DefaultCollationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.collation = DBConfig().options.collation; +} + +void DefaultCollationSetting::ResetLocal(ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + config.options.collation = DBConfig().options.collation; +} + +void DefaultCollationSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + // bind the collation to verify that it exists + ExpressionBinder::TestCollation(context, parameter); + auto &config = DBConfig::GetConfig(context); + config.options.collation = parameter; +} + +Value DefaultCollationSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.collation); +} + +//===--------------------------------------------------------------------===// +// Default Order +//===--------------------------------------------------------------------===// +void DefaultOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + if (parameter == "ascending" || parameter == "asc") { + config.options.default_order_type = OrderType::ASCENDING; + } else if (parameter == "descending" || parameter == "desc") { + config.options.default_order_type = OrderType::DESCENDING; + } else { + throw InvalidInputException("Unrecognized parameter for option DEFAULT_ORDER \"%s\". Expected ASC or DESC.", + parameter); + } +} + +void DefaultOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.default_order_type = DBConfig().options.default_order_type; +} + +Value DefaultOrderSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + switch (config.options.default_order_type) { + case OrderType::ASCENDING: + return "asc"; + case OrderType::DESCENDING: + return "desc"; + default: + throw InternalException("Unknown order type setting"); + } +} + +//===--------------------------------------------------------------------===// +// Default Null Order +//===--------------------------------------------------------------------===// +void DefaultNullOrderSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + + if (parameter == "nulls_first" || parameter == "nulls first" || parameter == "null first" || parameter == "first") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST; + } else if (parameter == "nulls_last" || parameter == "nulls last" || parameter == "null last" || + parameter == "last") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST; + } else if (parameter == "nulls_first_on_asc_last_on_desc" || parameter == "sqlite" || parameter == "mysql") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC; + } else if (parameter == "nulls_last_on_asc_first_on_desc" || parameter == "postgres") { + config.options.default_null_order = DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC; + } else { + throw ParserException("Unrecognized parameter for option NULL_ORDER \"%s\", expected either NULLS FIRST, NULLS " + "LAST, SQLite, MySQL or Postgres", + parameter); + } +} + +void DefaultNullOrderSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.default_null_order = DBConfig().options.default_null_order; +} + +Value DefaultNullOrderSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + switch (config.options.default_null_order) { + case DefaultOrderByNullType::NULLS_FIRST: + return "nulls_first"; + case DefaultOrderByNullType::NULLS_LAST: + return "nulls_last"; + case DefaultOrderByNullType::NULLS_FIRST_ON_ASC_LAST_ON_DESC: + return "nulls_first_on_asc_last_on_desc"; + case DefaultOrderByNullType::NULLS_LAST_ON_ASC_FIRST_ON_DESC: + return "nulls_last_on_asc_first_on_desc"; + default: + throw InternalException("Unknown null order setting"); + } +} + +//===--------------------------------------------------------------------===// +// Default Secret Storage +//===--------------------------------------------------------------------===// +void DefaultSecretStorage::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.secret_manager->SetDefaultStorage(input.ToString()); +} + +void DefaultSecretStorage::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetDefaultStorage(); +} + +Value DefaultSecretStorage::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.secret_manager->DefaultStorage(); +} + +//===--------------------------------------------------------------------===// +// Disabled File Systems +//===--------------------------------------------------------------------===// +void DisabledFileSystemsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (!db) { + throw InternalException("disabled_filesystems can only be set in an active database"); + } + auto &fs = FileSystem::GetFileSystem(*db); + auto list = StringUtil::Split(input.ToString(), ","); + fs.SetDisabledFileSystems(list); +} + +void DisabledFileSystemsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (!db) { + throw InternalException("disabled_filesystems can only be set in an active database"); + } + auto &fs = FileSystem::GetFileSystem(*db); + fs.SetDisabledFileSystems(vector()); +} + +Value DisabledFileSystemsSetting::GetSetting(const ClientContext &context) { + return Value(""); +} + +//===--------------------------------------------------------------------===// +// Disabled Optimizer +//===--------------------------------------------------------------------===// +void DisabledOptimizersSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto list = StringUtil::Split(input.ToString(), ","); + set disabled_optimizers; + for (auto &entry : list) { + auto param = StringUtil::Lower(entry); + StringUtil::Trim(param); + if (param.empty()) { + continue; + } + disabled_optimizers.insert(OptimizerTypeFromString(param)); + } + config.options.disabled_optimizers = std::move(disabled_optimizers); +} + +void DisabledOptimizersSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.disabled_optimizers = DBConfig().options.disabled_optimizers; +} + +Value DisabledOptimizersSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + string result; + for (auto &optimizer : config.options.disabled_optimizers) { + if (!result.empty()) { + result += ","; + } + result += OptimizerTypeToString(optimizer); + } + return Value(result); +} + +//===--------------------------------------------------------------------===// +// Enable External Access +//===--------------------------------------------------------------------===// +void EnableExternalAccessSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db && new_value) { + throw InvalidInputException("Cannot change enable_external_access setting while database is running"); + } + config.options.enable_external_access = new_value; +} + +void EnableExternalAccessSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change enable_external_access setting while database is running"); + } + config.options.enable_external_access = DBConfig().options.enable_external_access; +} + +Value EnableExternalAccessSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_external_access); +} + +//===--------------------------------------------------------------------===// +// Enable Macro Dependencies +//===--------------------------------------------------------------------===// +void EnableMacrosDependencies::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_macro_dependencies = input.GetValue(); +} + +void EnableMacrosDependencies::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_macro_dependencies = DBConfig().options.enable_macro_dependencies; +} + +Value EnableMacrosDependencies::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_macro_dependencies); +} + +//===--------------------------------------------------------------------===// +// Enable View Dependencies +//===--------------------------------------------------------------------===// +void EnableViewDependencies::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_view_dependencies = input.GetValue(); +} + +void EnableViewDependencies::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_view_dependencies = DBConfig().options.enable_view_dependencies; +} + +Value EnableViewDependencies::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_view_dependencies); +} + +//===--------------------------------------------------------------------===// +// Enable FSST Vectors +//===--------------------------------------------------------------------===// +void EnableFSSTVectors::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.enable_fsst_vectors = input.GetValue(); +} + +void EnableFSSTVectors::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.enable_fsst_vectors = DBConfig().options.enable_fsst_vectors; +} + +Value EnableFSSTVectors::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.enable_fsst_vectors); +} + +//===--------------------------------------------------------------------===// +// Allow Unsigned Extensions +//===--------------------------------------------------------------------===// +void AllowUnsignedExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db && new_value) { + throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); + } + config.options.allow_unsigned_extensions = new_value; +} + +void AllowUnsignedExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change allow_unsigned_extensions setting while database is running"); + } + config.options.allow_unsigned_extensions = DBConfig().options.allow_unsigned_extensions; +} + +Value AllowUnsignedExtensionsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_unsigned_extensions); +} + +//===--------------------------------------------------------------------===// +// Allow Community Extensions +//===--------------------------------------------------------------------===// +void AllowCommunityExtensionsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + if (db && !config.options.allow_community_extensions) { + auto new_value = input.GetValue(); + if (new_value) { + throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); + } + return; + } + auto new_value = input.GetValue(); + config.options.allow_community_extensions = new_value; +} + +void AllowCommunityExtensionsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db && !config.options.allow_community_extensions) { + if (DBConfig().options.allow_community_extensions) { + throw InvalidInputException("Cannot upgrade allow_community_extensions setting while database is running"); + } + return; + } + config.options.allow_community_extensions = DBConfig().options.allow_community_extensions; +} + +Value AllowCommunityExtensionsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_community_extensions); +} + +//===--------------------------------------------------------------------===// +// Allow Extensions Metadata Mismatch +//===--------------------------------------------------------------------===// +void AllowExtensionsMetadataMismatchSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + config.options.allow_extensions_metadata_mismatch = new_value; +} + +void AllowExtensionsMetadataMismatchSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allow_extensions_metadata_mismatch = DBConfig().options.allow_extensions_metadata_mismatch; +} + +Value AllowExtensionsMetadataMismatchSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_extensions_metadata_mismatch); +} + +//===--------------------------------------------------------------------===// +// Allow Unredacted Secrets +//===--------------------------------------------------------------------===// +void AllowUnredactedSecretsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db && new_value) { + throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); + } + config.options.allow_unredacted_secrets = new_value; +} + +void AllowUnredactedSecretsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change allow_unredacted_secrets setting while database is running"); + } + config.options.allow_unredacted_secrets = DBConfig().options.allow_unredacted_secrets; +} + +Value AllowUnredactedSecretsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.allow_unredacted_secrets); +} + +//===--------------------------------------------------------------------===// +// Enable Object Cache +//===--------------------------------------------------------------------===// +void EnableObjectCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.object_cache_enable = input.GetValue(); +} + +void EnableObjectCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.object_cache_enable = DBConfig().options.object_cache_enable; +} + +Value EnableObjectCacheSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.object_cache_enable); +} + +//===--------------------------------------------------------------------===// +// Storage Compatibility Version (for serialization) +//===--------------------------------------------------------------------===// +void StorageCompatibilityVersion::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto version_string = input.GetValue(); + auto serialization_compatibility = SerializationCompatibility::FromString(version_string); + config.options.serialization_compatibility = serialization_compatibility; +} + +void StorageCompatibilityVersion::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.serialization_compatibility = DBConfig().options.serialization_compatibility; +} + +Value StorageCompatibilityVersion::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + + auto &version_name = config.options.serialization_compatibility.duckdb_version; + return Value(version_name); +} + +//===--------------------------------------------------------------------===// +// Enable HTTP Metadata Cache +//===--------------------------------------------------------------------===// +void EnableHTTPMetadataCacheSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.http_metadata_cache_enable = input.GetValue(); +} + +void EnableHTTPMetadataCacheSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.http_metadata_cache_enable = DBConfig().options.http_metadata_cache_enable; +} + +Value EnableHTTPMetadataCacheSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.http_metadata_cache_enable); +} + +//===--------------------------------------------------------------------===// +// Enable Profiling +//===--------------------------------------------------------------------===// +void EnableProfilingSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.profiler_print_format = ClientConfig().profiler_print_format; + config.enable_profiler = ClientConfig().enable_profiler; + config.emit_profiler_output = ClientConfig().emit_profiler_output; + config.profiler_settings = ClientConfig().profiler_settings; +} + +void EnableProfilingSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + + auto &config = ClientConfig::GetConfig(context); + config.enable_profiler = true; + config.emit_profiler_output = true; + config.profiler_settings = ClientConfig().profiler_settings; + + if (parameter == "json") { + config.profiler_print_format = ProfilerPrintFormat::JSON; + } else if (parameter == "query_tree") { + config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE; + } else if (parameter == "query_tree_optimizer") { + config.profiler_print_format = ProfilerPrintFormat::QUERY_TREE_OPTIMIZER; + + // add optimizer settings to the profiler settings + auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); + for (auto &setting : optimizer_settings) { + config.profiler_settings.insert(setting); + } + + // add the phase timing settings to the profiler settings + auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); + for (auto &setting : phase_timing_settings) { + config.profiler_settings.insert(setting); + } + } else if (parameter == "no_output") { + config.profiler_print_format = ProfilerPrintFormat::NO_OUTPUT; + config.emit_profiler_output = false; + } else { + throw ParserException( + "Unrecognized print format %s, supported formats: [json, query_tree, query_tree_optimizer, no_output]", + parameter); + } +} + +Value EnableProfilingSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + if (!config.enable_profiler) { + return Value(); + } + switch (config.profiler_print_format) { + case ProfilerPrintFormat::JSON: + return Value("json"); + case ProfilerPrintFormat::QUERY_TREE: + return Value("query_tree"); + case ProfilerPrintFormat::QUERY_TREE_OPTIMIZER: + return Value("query_tree_optimizer"); + case ProfilerPrintFormat::NO_OUTPUT: + return Value("no_output"); + default: + throw InternalException("Unsupported profiler print format"); + } +} + +//===--------------------------------------------------------------------===// +// Custom Profiling Settings +//===--------------------------------------------------------------------===// + +bool IsEnabledOptimizer(MetricsType metric, const set &disabled_optimizers) { + auto matching_optimizer_type = MetricsUtils::GetOptimizerTypeByMetric(metric); + if (matching_optimizer_type != OptimizerType::INVALID && + disabled_optimizers.find(matching_optimizer_type) == disabled_optimizers.end()) { + return true; + } + return false; +} + +static profiler_settings_t FillTreeNodeSettings(unordered_map &json, + const set &disabled_optimizers) { + profiler_settings_t metrics; + + string invalid_settings; + for (auto &entry : json) { + MetricsType setting; + try { + setting = EnumUtil::FromString(StringUtil::Upper(entry.first)); + } catch (std::exception &ex) { + if (!invalid_settings.empty()) { + invalid_settings += ", "; + } + invalid_settings += entry.first; + continue; + } + if (StringUtil::Lower(entry.second) == "true" && + (!MetricsUtils::IsOptimizerMetric(setting) || IsEnabledOptimizer(setting, disabled_optimizers))) { + metrics.insert(setting); + } + } + + if (!invalid_settings.empty()) { + throw IOException("Invalid custom profiler settings: \"%s\"", invalid_settings); + } + return metrics; +} + +void AddOptimizerMetrics(profiler_settings_t &settings, const set &disabled_optimizers) { + if (settings.find(MetricsType::ALL_OPTIMIZERS) != settings.end()) { + auto optimizer_metrics = MetricsUtils::GetOptimizerMetrics(); + for (auto &metric : optimizer_metrics) { + if (IsEnabledOptimizer(metric, disabled_optimizers)) { + settings.insert(metric); + } + } + } +} + +void CustomProfilingSettings::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + + // parse the file content + unordered_map json; + try { + json = StringUtil::ParseJSONMap(input.ToString()); + } catch (std::exception &ex) { + throw IOException("Could not parse the custom profiler settings file due to incorrect JSON: \"%s\". Make sure " + "all the keys and values start with a quote. ", + input.ToString()); + } + + config.enable_profiler = true; + auto &db_config = DBConfig::GetConfig(context); + auto &disabled_optimizers = db_config.options.disabled_optimizers; + + auto settings = FillTreeNodeSettings(json, disabled_optimizers); + AddOptimizerMetrics(settings, disabled_optimizers); + config.profiler_settings = settings; +} + +void CustomProfilingSettings::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.enable_profiler = ClientConfig().enable_profiler; + config.profiler_settings = ProfilingInfo::DefaultSettings(); +} + +Value CustomProfilingSettings::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + + string profiling_settings_str; + for (auto &entry : config.profiler_settings) { + if (!profiling_settings_str.empty()) { + profiling_settings_str += ", "; + } + profiling_settings_str += StringUtil::Format("\"%s\": \"true\"", EnumUtil::ToString(entry)); + } + return Value(StringUtil::Format("{%s}", profiling_settings_str)); +} + +//===--------------------------------------------------------------------===// +// Custom Extension Repository +//===--------------------------------------------------------------------===// +void CustomExtensionRepository::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.custom_extension_repo = DBConfig().options.custom_extension_repo; +} + +void CustomExtensionRepository::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.custom_extension_repo = input.ToString(); +} + +Value CustomExtensionRepository::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.custom_extension_repo); +} + +//===--------------------------------------------------------------------===// +// Autoload Extension Repository +//===--------------------------------------------------------------------===// +void AutoloadExtensionRepository::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.autoinstall_extension_repo = DBConfig().options.autoinstall_extension_repo; +} + +void AutoloadExtensionRepository::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.autoinstall_extension_repo = input.ToString(); +} + +Value AutoloadExtensionRepository::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.autoinstall_extension_repo); +} + +//===--------------------------------------------------------------------===// +// Autoinstall Known Extensions +//===--------------------------------------------------------------------===// +void AutoinstallKnownExtensions::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.autoinstall_known_extensions = input.GetValue(); +} + +void AutoinstallKnownExtensions::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.autoinstall_known_extensions = DBConfig().options.autoinstall_known_extensions; +} + +Value AutoinstallKnownExtensions::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.autoinstall_known_extensions); +} +//===--------------------------------------------------------------------===// +// Autoload Known Extensions +//===--------------------------------------------------------------------===// +void AutoloadKnownExtensions::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.autoload_known_extensions = input.GetValue(); +} + +void AutoloadKnownExtensions::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.autoload_known_extensions = DBConfig().options.autoload_known_extensions; +} + +Value AutoloadKnownExtensions::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.autoload_known_extensions); +} + +//===--------------------------------------------------------------------===// +// Enable Progress Bar +//===--------------------------------------------------------------------===// +void EnableProgressBarSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.enable_progress_bar = ClientConfig().enable_progress_bar; +} + +void EnableProgressBarSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.enable_progress_bar = input.GetValue(); +} + +Value EnableProgressBarSetting::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).enable_progress_bar); +} + +//===--------------------------------------------------------------------===// +// Enable Progress Bar Print +//===--------------------------------------------------------------------===// +void EnableProgressBarPrintSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.print_progress_bar = input.GetValue(); +} + +void EnableProgressBarPrintSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.print_progress_bar = ClientConfig().print_progress_bar; +} + +Value EnableProgressBarPrintSetting::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).print_progress_bar); +} + +//===--------------------------------------------------------------------===// +// Errors As JSON +//===--------------------------------------------------------------------===// +void ErrorsAsJsonSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).errors_as_json = ClientConfig().errors_as_json; +} + +void ErrorsAsJsonSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).errors_as_json = BooleanValue::Get(input); +} + +Value ErrorsAsJsonSetting::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).errors_as_json); +} + +//===--------------------------------------------------------------------===// +// Explain Output +//===--------------------------------------------------------------------===// +void ExplainOutputSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).explain_output_type = ClientConfig().explain_output_type; +} + +void ExplainOutputSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + if (parameter == "all") { + ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::ALL; + } else if (parameter == "optimized_only") { + ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::OPTIMIZED_ONLY; + } else if (parameter == "physical_only") { + ClientConfig::GetConfig(context).explain_output_type = ExplainOutputType::PHYSICAL_ONLY; + } else { + throw ParserException("Unrecognized output type \"%s\", expected either ALL, OPTIMIZED_ONLY or PHYSICAL_ONLY", + parameter); + } +} + +Value ExplainOutputSetting::GetSetting(const ClientContext &context) { + switch (ClientConfig::GetConfig(context).explain_output_type) { + case ExplainOutputType::ALL: + return "all"; + case ExplainOutputType::OPTIMIZED_ONLY: + return "optimized_only"; + case ExplainOutputType::PHYSICAL_ONLY: + return "physical_only"; + default: + throw InternalException("Unrecognized explain output type"); + } +} + +//===--------------------------------------------------------------------===// +// Extension Directory Setting +//===--------------------------------------------------------------------===// +void ExtensionDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.extension_directory = input.ToString(); +} + +void ExtensionDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.extension_directory = DBConfig().options.extension_directory; +} + +Value ExtensionDirectorySetting::GetSetting(const ClientContext &context) { + return Value(DBConfig::GetConfig(context).options.extension_directory); +} + +//===--------------------------------------------------------------------===// +// External Threads Setting +//===--------------------------------------------------------------------===// +void ExternalThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_val = input.GetValue(); + if (new_val < 0) { + throw SyntaxException("Must have a non-negative number of external threads!"); + } + auto new_external_threads = NumericCast(new_val); + if (db) { + TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); + } + config.options.external_threads = new_external_threads; +} + +void ExternalThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + idx_t new_external_threads = DBConfig().options.external_threads; + if (db) { + TaskScheduler::GetScheduler(*db).SetThreads(config.options.maximum_threads, new_external_threads); + } + config.options.external_threads = new_external_threads; +} + +Value ExternalThreadsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BIGINT(NumericCast(config.options.external_threads)); +} + +//===--------------------------------------------------------------------===// +// File Search Path +//===--------------------------------------------------------------------===// +void FileSearchPathSetting::ResetLocal(ClientContext &context) { + auto &client_data = ClientData::Get(context); + client_data.file_search_path.clear(); +} + +void FileSearchPathSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + auto &client_data = ClientData::Get(context); + client_data.file_search_path = parameter; +} + +Value FileSearchPathSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + return Value(client_data.file_search_path); +} + +//===--------------------------------------------------------------------===// +// Force Compression +//===--------------------------------------------------------------------===// +void ForceCompressionSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto compression = StringUtil::Lower(input.ToString()); + if (compression == "none" || compression == "auto") { + config.options.force_compression = CompressionType::COMPRESSION_AUTO; + } else { + auto compression_type = CompressionTypeFromString(compression); + if (CompressionTypeIsDeprecated(compression_type)) { + throw ParserException("Attempted to force a deprecated compression type (%s)", + CompressionTypeToString(compression_type)); + } + if (compression_type == CompressionType::COMPRESSION_AUTO) { + auto compression_types = StringUtil::Join(ListCompressionTypes(), ", "); + throw ParserException("Unrecognized option for PRAGMA force_compression, expected %s", compression_types); + } + config.options.force_compression = compression_type; + } +} + +void ForceCompressionSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.force_compression = DBConfig().options.force_compression; +} + +Value ForceCompressionSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(*context.db); + return CompressionTypeToString(config.options.force_compression); +} + +//===--------------------------------------------------------------------===// +// Force Bitpacking mode +//===--------------------------------------------------------------------===// +void ForceBitpackingModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto mode_str = StringUtil::Lower(input.ToString()); + auto mode = BitpackingModeFromString(mode_str); + if (mode == BitpackingMode::INVALID) { + throw ParserException("Unrecognized option for force_bitpacking_mode, expected none, constant, constant_delta, " + "delta_for, or for"); + } + config.options.force_bitpacking_mode = mode; +} + +void ForceBitpackingModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.force_bitpacking_mode = DBConfig().options.force_bitpacking_mode; +} + +Value ForceBitpackingModeSetting::GetSetting(const ClientContext &context) { + return Value(BitpackingModeToString(context.db->config.options.force_bitpacking_mode)); +} + +//===--------------------------------------------------------------------===// +// Home Directory +//===--------------------------------------------------------------------===// +void HomeDirectorySetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).home_directory = ClientConfig().home_directory; +} + +void HomeDirectorySetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + + if (!input.IsNull() && FileSystem::GetFileSystem(context).IsRemoteFile(input.ToString())) { + throw InvalidInputException("Cannot set the home directory to a remote path"); + } + + config.home_directory = input.IsNull() ? string() : input.ToString(); +} + +Value HomeDirectorySetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(config.home_directory); +} + +//===--------------------------------------------------------------------===// +// HTTP Proxy +//===--------------------------------------------------------------------===// +void HTTPProxy::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.http_proxy = DBConfig().options.http_proxy; +} + +void HTTPProxy::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { + config.options.http_proxy = parameter.GetValue(); +} + +Value HTTPProxy::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.options.http_proxy; +} + +//===--------------------------------------------------------------------===// +// HTTP Proxy Username +//===--------------------------------------------------------------------===// +void HTTPProxyUsername::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.http_proxy_username = DBConfig().options.http_proxy_username; +} + +void HTTPProxyUsername::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { + config.options.http_proxy_username = parameter.GetValue(); +} + +Value HTTPProxyUsername::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.options.http_proxy_username; +} + +//===--------------------------------------------------------------------===// +// HTTP Proxy Password +//===--------------------------------------------------------------------===// +void HTTPProxyPassword::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.http_proxy_password = DBConfig().options.http_proxy_password; +} + +void HTTPProxyPassword::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value ¶meter) { + config.options.http_proxy_password = parameter.GetValue(); +} + +Value HTTPProxyPassword::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.options.http_proxy_password; +} + +//===--------------------------------------------------------------------===// +// Integer Division +//===--------------------------------------------------------------------===// +void IntegerDivisionSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).integer_division = ClientConfig().integer_division; +} + +void IntegerDivisionSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.integer_division = input.GetValue(); +} + +Value IntegerDivisionSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(config.integer_division); +} + +//===--------------------------------------------------------------------===// +// Log Query Path +//===--------------------------------------------------------------------===// +void LogQueryPathSetting::ResetLocal(ClientContext &context) { + auto &client_data = ClientData::Get(context); + // TODO: verify that this does the right thing + client_data.log_query_writer = std::move(ClientData(context).log_query_writer); +} + +void LogQueryPathSetting::SetLocal(ClientContext &context, const Value &input) { + auto &client_data = ClientData::Get(context); + auto path = input.ToString(); + if (path.empty()) { + // empty path: clean up query writer + client_data.log_query_writer = nullptr; + } else { + client_data.log_query_writer = make_uniq(FileSystem::GetFileSystem(context), path, + BufferedFileWriter::DEFAULT_OPEN_FLAGS); + } +} + +Value LogQueryPathSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + return client_data.log_query_writer ? Value(client_data.log_query_writer->path) : Value(); +} + +//===--------------------------------------------------------------------===// +// Lock Configuration +//===--------------------------------------------------------------------===// +void LockConfigurationSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + config.options.lock_configuration = new_value; +} + +void LockConfigurationSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.lock_configuration = DBConfig().options.lock_configuration; +} + +Value LockConfigurationSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.lock_configuration); +} + +//===--------------------------------------------------------------------===// +// IEEE Floating Points +//===--------------------------------------------------------------------===// +void IEEEFloatingPointOpsSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).ieee_floating_point_ops = ClientConfig().ieee_floating_point_ops; +} + +void IEEEFloatingPointOpsSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).ieee_floating_point_ops = input.GetValue(); +} + +Value IEEEFloatingPointOpsSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.ieee_floating_point_ops); +} + +//===--------------------------------------------------------------------===// +// Immediate Transaction Mode +//===--------------------------------------------------------------------===// +void ImmediateTransactionModeSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.immediate_transaction_mode = BooleanValue::Get(input); +} + +void ImmediateTransactionModeSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.immediate_transaction_mode = DBConfig().options.immediate_transaction_mode; +} + +Value ImmediateTransactionModeSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.immediate_transaction_mode); +} + +//===--------------------------------------------------------------------===// +// Maximum Expression Depth +//===--------------------------------------------------------------------===// +void MaximumExpressionDepthSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).max_expression_depth = ClientConfig().max_expression_depth; +} + +void MaximumExpressionDepthSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).max_expression_depth = input.GetValue(); +} + +Value MaximumExpressionDepthSetting::GetSetting(const ClientContext &context) { + return Value::UBIGINT(ClientConfig::GetConfig(context).max_expression_depth); +} + +//===--------------------------------------------------------------------===// +// Maximum Memory +//===--------------------------------------------------------------------===// +void MaximumMemorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.maximum_memory = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + BufferManager::GetBufferManager(*db).SetMemoryLimit(config.options.maximum_memory); + } +} + +void MaximumMemorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.SetDefaultMaxMemory(); +} + +Value MaximumMemorySetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_memory)); +} + +//===--------------------------------------------------------------------===// +// Streaming Buffer Size +//===--------------------------------------------------------------------===// +void StreamingBufferSize::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.streaming_buffer_size = DBConfig::ParseMemoryLimit(input.ToString()); +} + +void StreamingBufferSize::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + config.SetDefaultStreamingBufferSize(); +} + +Value StreamingBufferSize::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.streaming_buffer_size)); +} + +//===--------------------------------------------------------------------===// +// Maximum Temp Directory Size +//===--------------------------------------------------------------------===// +void MaximumTempDirectorySize::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto maximum_swap_space = DBConfig::ParseMemoryLimit(input.ToString()); + if (maximum_swap_space == DConstants::INVALID_INDEX) { + // We use INVALID_INDEX to indicate that the value is not set by the user + // use one lower to indicate 'unlimited' + maximum_swap_space--; + } + if (!db) { + config.options.maximum_swap_space = maximum_swap_space; + return; + } + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetSwapLimit(maximum_swap_space); + config.options.maximum_swap_space = maximum_swap_space; +} + +void MaximumTempDirectorySize::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.maximum_swap_space = DConstants::INVALID_INDEX; + if (!db) { + return; + } + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetSwapLimit(); +} + +Value MaximumTempDirectorySize::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + if (config.options.maximum_swap_space != DConstants::INVALID_INDEX) { + // Explicitly set by the user + return Value(StringUtil::BytesToHumanReadableString(config.options.maximum_swap_space)); + } + auto &buffer_manager = BufferManager::GetBufferManager(context); + // Database is initialized, use the setting from the temporary directory + auto max_swap = buffer_manager.GetMaxSwap(); + if (max_swap.IsValid()) { + return Value(StringUtil::BytesToHumanReadableString(max_swap.GetIndex())); + } else { + // The temp directory has not been used yet + return Value(StringUtil::BytesToHumanReadableString(0)); + } +} + +//===--------------------------------------------------------------------===// +// Maximum Vacuum Size +//===--------------------------------------------------------------------===// +void MaximumVacuumTasks::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.max_vacuum_tasks = input.GetValue(); +} + +void MaximumVacuumTasks::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.max_vacuum_tasks = DBConfig().options.max_vacuum_tasks; +} + +Value MaximumVacuumTasks::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.max_vacuum_tasks); +} + +//===--------------------------------------------------------------------===// +// Merge Join Threshold +//===--------------------------------------------------------------------===// +void MergeJoinThreshold::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.merge_join_threshold = input.GetValue(); +} + +void MergeJoinThreshold::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).merge_join_threshold = ClientConfig().merge_join_threshold; +} + +Value MergeJoinThreshold::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.merge_join_threshold); +} + +//===--------------------------------------------------------------------===// +// Nested Loop Join Threshold +//===--------------------------------------------------------------------===// +void NestedLoopJoinThreshold::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + config.nested_loop_join_threshold = input.GetValue(); +} + +void NestedLoopJoinThreshold::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).nested_loop_join_threshold = ClientConfig().nested_loop_join_threshold; +} + +Value NestedLoopJoinThreshold::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::UBIGINT(config.nested_loop_join_threshold); +} + +//===--------------------------------------------------------------------===// +// Old Implicit Casting +//===--------------------------------------------------------------------===// +void OldImplicitCasting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.old_implicit_casting = input.GetValue(); +} + +void OldImplicitCasting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.old_implicit_casting = DBConfig().options.old_implicit_casting; +} + +Value OldImplicitCasting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.old_implicit_casting); +} + +//===--------------------------------------------------------------------===// +// Old Implicit Casting +//===--------------------------------------------------------------------===// +void OrderByNonIntegerLiteral::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).order_by_non_integer_literal = ClientConfig().order_by_non_integer_literal; +} + +void OrderByNonIntegerLiteral::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).order_by_non_integer_literal = input.GetValue(); +} + +Value OrderByNonIntegerLiteral::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value::BOOLEAN(config.order_by_non_integer_literal); +} + +//===--------------------------------------------------------------------===// +// Partitioned Write Flush Threshold +//===--------------------------------------------------------------------===// +void PartitionedWriteFlushThreshold::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).partitioned_write_flush_threshold = + ClientConfig().partitioned_write_flush_threshold; +} + +void PartitionedWriteFlushThreshold::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).partitioned_write_flush_threshold = input.GetValue(); +} + +Value PartitionedWriteFlushThreshold::GetSetting(const ClientContext &context) { + return Value::UBIGINT(ClientConfig::GetConfig(context).partitioned_write_flush_threshold); +} + +//===--------------------------------------------------------------------===// +// Partitioned Write Flush Threshold +//===--------------------------------------------------------------------===// +void PartitionedWriteMaxOpenFiles::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).partitioned_write_max_open_files = ClientConfig().partitioned_write_max_open_files; +} + +void PartitionedWriteMaxOpenFiles::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).partitioned_write_max_open_files = input.GetValue(); +} + +Value PartitionedWriteMaxOpenFiles::GetSetting(const ClientContext &context) { + return Value::UBIGINT(ClientConfig::GetConfig(context).partitioned_write_max_open_files); +} + +//===--------------------------------------------------------------------===// +// Preferred block allocation size +//===--------------------------------------------------------------------===// +void DefaultBlockAllocSize::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto block_alloc_size = input.GetValue(); + Storage::VerifyBlockAllocSize(block_alloc_size); + config.options.default_block_alloc_size = block_alloc_size; +} + +void DefaultBlockAllocSize::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.default_block_alloc_size = DBConfig().options.default_block_alloc_size; +} + +Value DefaultBlockAllocSize::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.default_block_alloc_size); +} + +//===--------------------------------------------------------------------===// +// Index scan percentage +//===--------------------------------------------------------------------===// +void IndexScanPercentage::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto index_scan_percentage = input.GetValue(); + if (index_scan_percentage < 0 || index_scan_percentage > 1.0) { + throw InvalidInputException("the index scan percentage must be within [0, 1]"); + } + config.options.index_scan_percentage = index_scan_percentage; +} + +void IndexScanPercentage::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.index_scan_percentage = DBConfig().options.index_scan_percentage; +} + +Value IndexScanPercentage::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::DOUBLE(config.options.index_scan_percentage); +} + +//===--------------------------------------------------------------------===// +// Index scan max count +//===--------------------------------------------------------------------===// +void IndexScanMaxCount::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto index_scan_max_count = input.GetValue(); + config.options.index_scan_max_count = index_scan_max_count; +} + +void IndexScanMaxCount::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.index_scan_max_count = DBConfig().options.index_scan_max_count; +} + +Value IndexScanMaxCount::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::UBIGINT(config.options.index_scan_max_count); +} + +//===--------------------------------------------------------------------===// +// Password Setting +//===--------------------------------------------------------------------===// +void PasswordSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + // nop +} + +void PasswordSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + // nop +} + +Value PasswordSetting::GetSetting(const ClientContext &context) { + return Value(); +} + +//===--------------------------------------------------------------------===// +// Perfect Hash Threshold +//===--------------------------------------------------------------------===// +void PerfectHashThresholdSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).perfect_ht_threshold = ClientConfig().perfect_ht_threshold; +} + +void PerfectHashThresholdSetting::SetLocal(ClientContext &context, const Value &input) { + auto bits = input.GetValue(); + if (bits < 0 || bits > 32) { + throw ParserException("Perfect HT threshold out of range: should be within range 0 - 32"); + } + ClientConfig::GetConfig(context).perfect_ht_threshold = NumericCast(bits); +} + +Value PerfectHashThresholdSetting::GetSetting(const ClientContext &context) { + return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).perfect_ht_threshold)); +} + +//===--------------------------------------------------------------------===// +// Pivot Filter Threshold +//===--------------------------------------------------------------------===// +void PivotFilterThreshold::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).pivot_filter_threshold = ClientConfig().pivot_filter_threshold; +} + +void PivotFilterThreshold::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).pivot_filter_threshold = input.GetValue(); +} + +Value PivotFilterThreshold::GetSetting(const ClientContext &context) { + return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).pivot_filter_threshold)); +} + +//===--------------------------------------------------------------------===// +// Pivot Limit +//===--------------------------------------------------------------------===// +void PivotLimitSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).pivot_limit = ClientConfig().pivot_limit; +} + +void PivotLimitSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).pivot_limit = input.GetValue(); +} + +Value PivotLimitSetting::GetSetting(const ClientContext &context) { + return Value::BIGINT(NumericCast(ClientConfig::GetConfig(context).pivot_limit)); +} + +//===--------------------------------------------------------------------===// +// PreserveIdentifierCase +//===--------------------------------------------------------------------===// +void PreserveIdentifierCase::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).preserve_identifier_case = ClientConfig().preserve_identifier_case; +} + +void PreserveIdentifierCase::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).preserve_identifier_case = input.GetValue(); +} + +Value PreserveIdentifierCase::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).preserve_identifier_case); +} + +//===--------------------------------------------------------------------===// +// PreserveInsertionOrder +//===--------------------------------------------------------------------===// +void PreserveInsertionOrder::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.preserve_insertion_order = input.GetValue(); +} + +void PreserveInsertionOrder::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.preserve_insertion_order = DBConfig().options.preserve_insertion_order; +} + +Value PreserveInsertionOrder::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BOOLEAN(config.options.preserve_insertion_order); +} + +//===--------------------------------------------------------------------===// +// ExportLargeBufferArrow +//===--------------------------------------------------------------------===// +void ExportLargeBufferArrow::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto export_large_buffers_arrow = input.GetValue(); + + config.options.arrow_offset_size = export_large_buffers_arrow ? ArrowOffsetSize::LARGE : ArrowOffsetSize::REGULAR; +} + +void ExportLargeBufferArrow::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_offset_size = DBConfig().options.arrow_offset_size; +} + +Value ExportLargeBufferArrow::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + bool export_large_buffers_arrow = config.options.arrow_offset_size == ArrowOffsetSize::LARGE; + return Value::BOOLEAN(export_large_buffers_arrow); +} + +//===--------------------------------------------------------------------===// +// ArrowOutputListView +//===--------------------------------------------------------------------===// +void ArrowOutputListView::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto arrow_output_list_view = input.GetValue(); + + config.options.arrow_use_list_view = arrow_output_list_view; +} + +void ArrowOutputListView::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_use_list_view = DBConfig().options.arrow_use_list_view; +} + +Value ArrowOutputListView::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + bool arrow_output_list_view = config.options.arrow_use_list_view; + return Value::BOOLEAN(arrow_output_list_view); +} + +//===--------------------------------------------------------------------===// +// LosslessConversionArrow +//===--------------------------------------------------------------------===// +void LosslessConversionArrow::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto arrow_arrow_lossless_conversion = input.GetValue(); + + config.options.arrow_arrow_lossless_conversion = arrow_arrow_lossless_conversion; +} + +void LosslessConversionArrow::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.arrow_arrow_lossless_conversion = DBConfig().options.arrow_arrow_lossless_conversion; +} + +Value LosslessConversionArrow::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + bool arrow_arrow_lossless_conversion = config.options.arrow_arrow_lossless_conversion; + return Value::BOOLEAN(arrow_arrow_lossless_conversion); +} + +//===--------------------------------------------------------------------===// +// ProduceArrowStringView +//===--------------------------------------------------------------------===// +void ProduceArrowStringView::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.produce_arrow_string_views = input.GetValue(); +} + +void ProduceArrowStringView::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.produce_arrow_string_views = DBConfig().options.produce_arrow_string_views; +} + +Value ProduceArrowStringView::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(DBConfig::GetConfig(context).options.produce_arrow_string_views); +} + +//===--------------------------------------------------------------------===// +// ScalarSubqueryErrorOnMultipleRows +//===--------------------------------------------------------------------===// +void ScalarSubqueryErrorOnMultipleRows::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = + ClientConfig().scalar_subquery_error_on_multiple_rows; +} + +void ScalarSubqueryErrorOnMultipleRows::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows = input.GetValue(); +} + +Value ScalarSubqueryErrorOnMultipleRows::GetSetting(const ClientContext &context) { + return Value::BOOLEAN(ClientConfig::GetConfig(context).scalar_subquery_error_on_multiple_rows); +} + +//===--------------------------------------------------------------------===// +// Profile Output +//===--------------------------------------------------------------------===// +void ProfileOutputSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).profiler_save_location = ClientConfig().profiler_save_location; +} + +void ProfileOutputSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + auto parameter = input.ToString(); + config.profiler_save_location = parameter; +} + +Value ProfileOutputSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + return Value(config.profiler_save_location); +} + +//===--------------------------------------------------------------------===// +// Profiling Mode +//===--------------------------------------------------------------------===// +void ProfilingModeSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).enable_profiler = ClientConfig().enable_profiler; + ClientConfig::GetConfig(context).enable_detailed_profiling = ClientConfig().enable_detailed_profiling; + ClientConfig::GetConfig(context).emit_profiler_output = ClientConfig().emit_profiler_output; + ClientConfig::GetConfig(context).profiler_settings = ClientConfig().profiler_settings; +} + +void ProfilingModeSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = StringUtil::Lower(input.ToString()); + auto &config = ClientConfig::GetConfig(context); + if (parameter == "standard") { + config.enable_profiler = true; + config.enable_detailed_profiling = false; + } else if (parameter == "detailed") { + config.enable_profiler = true; + config.enable_detailed_profiling = true; + + // add optimizer settings to the profiler settings + auto optimizer_settings = MetricsUtils::GetOptimizerMetrics(); + for (auto &setting : optimizer_settings) { + config.profiler_settings.insert(setting); + } + + // add the phase timing settings to the profiler settings + auto phase_timing_settings = MetricsUtils::GetPhaseTimingMetrics(); + for (auto &setting : phase_timing_settings) { + config.profiler_settings.insert(setting); + } + } else { + throw ParserException("Unrecognized profiling mode \"%s\", supported formats: [standard, detailed]", parameter); + } +} + +Value ProfilingModeSetting::GetSetting(const ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + if (!config.enable_profiler) { + return Value(); + } + return Value(config.enable_detailed_profiling ? "detailed" : "standard"); +} + +//===--------------------------------------------------------------------===// +// Progress Bar Time +//===--------------------------------------------------------------------===// +void ProgressBarTimeSetting::ResetLocal(ClientContext &context) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.wait_time = ClientConfig().wait_time; + config.enable_progress_bar = ClientConfig().enable_progress_bar; +} + +void ProgressBarTimeSetting::SetLocal(ClientContext &context, const Value &input) { + auto &config = ClientConfig::GetConfig(context); + ProgressBar::SystemOverrideCheck(config); + config.wait_time = input.GetValue(); + config.enable_progress_bar = true; +} + +Value ProgressBarTimeSetting::GetSetting(const ClientContext &context) { + return Value::BIGINT(ClientConfig::GetConfig(context).wait_time); +} + +//===--------------------------------------------------------------------===// +// Schema +//===--------------------------------------------------------------------===// +void SchemaSetting::ResetLocal(ClientContext &context) { + // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Reset(); +} + +void SchemaSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Set(CatalogSearchEntry::Parse(parameter), CatalogSetPathType::SET_SCHEMA); +} + +Value SchemaSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + return client_data.catalog_search_path->GetDefault().schema; +} + +//===--------------------------------------------------------------------===// +// Search Path +//===--------------------------------------------------------------------===// +void SearchPathSetting::ResetLocal(ClientContext &context) { + // FIXME: catalog_search_path is controlled by both SchemaSetting and SearchPathSetting + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Reset(); +} + +void SearchPathSetting::SetLocal(ClientContext &context, const Value &input) { + auto parameter = input.ToString(); + auto &client_data = ClientData::Get(context); + client_data.catalog_search_path->Set(CatalogSearchEntry::ParseList(parameter), CatalogSetPathType::SET_SCHEMAS); +} + +Value SearchPathSetting::GetSetting(const ClientContext &context) { + auto &client_data = ClientData::Get(context); + auto &set_paths = client_data.catalog_search_path->GetSetPaths(); + return Value(CatalogSearchEntry::ListToString(set_paths)); +} + +//===--------------------------------------------------------------------===// +// Secret Directory +//===--------------------------------------------------------------------===// +void SecretDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.secret_manager->SetPersistentSecretPath(input.ToString()); +} + +void SecretDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.secret_manager->ResetPersistentSecretPath(); +} + +Value SecretDirectorySetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return config.secret_manager->PersistentSecretPath(); +} + +//===--------------------------------------------------------------------===// +// Temp Directory +//===--------------------------------------------------------------------===// +void TempDirectorySetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.temporary_directory = input.ToString(); + config.options.use_temporary_directory = !config.options.temporary_directory.empty(); + if (db) { + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); + } +} + +void TempDirectorySetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.SetDefaultTempDirectory(); + + config.options.use_temporary_directory = DBConfig().options.use_temporary_directory; + if (db) { + auto &buffer_manager = BufferManager::GetBufferManager(*db); + buffer_manager.SetTemporaryDirectory(config.options.temporary_directory); + } +} + +Value TempDirectorySetting::GetSetting(const ClientContext &context) { + auto &buffer_manager = BufferManager::GetBufferManager(context); + return Value(buffer_manager.GetTemporaryDirectory()); +} + +//===--------------------------------------------------------------------===// +// Threads Setting +//===--------------------------------------------------------------------===// +void ThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_val = input.GetValue(); + if (new_val < 1) { + throw SyntaxException("Must have at least 1 thread!"); + } + auto new_maximum_threads = NumericCast(new_val); + if (db) { + TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); + } + config.options.maximum_threads = new_maximum_threads; +} + +void ThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + idx_t new_maximum_threads = config.GetSystemMaxThreads(*config.file_system); + if (db) { + TaskScheduler::GetScheduler(*db).SetThreads(new_maximum_threads, config.options.external_threads); + } + config.options.maximum_threads = new_maximum_threads; +} + +Value ThreadsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value::BIGINT(NumericCast(config.options.maximum_threads)); +} + +//===--------------------------------------------------------------------===// +// Username Setting +//===--------------------------------------------------------------------===// +void UsernameSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + // nop +} + +void UsernameSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + // nop +} + +Value UsernameSetting::GetSetting(const ClientContext &context) { + return Value(); +} + +//===--------------------------------------------------------------------===// +// Allocator Flush Threshold +//===--------------------------------------------------------------------===// +void AllocatorFlushThreshold::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.allocator_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); + } +} + +void AllocatorFlushThreshold::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allocator_flush_threshold = DBConfig().options.allocator_flush_threshold; + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorFlushTreshold(config.options.allocator_flush_threshold); + } +} + +Value AllocatorFlushThreshold::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_flush_threshold)); +} + +//===--------------------------------------------------------------------===// +// Allocator Bulk Deallocation Flush Threshold +//===--------------------------------------------------------------------===// +void AllocatorBulkDeallocationFlushThreshold::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.allocator_bulk_deallocation_flush_threshold = DBConfig::ParseMemoryLimit(input.ToString()); + if (db) { + BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( + config.options.allocator_bulk_deallocation_flush_threshold); + } +} + +void AllocatorBulkDeallocationFlushThreshold::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allocator_bulk_deallocation_flush_threshold = + DBConfig().options.allocator_bulk_deallocation_flush_threshold; + if (db) { + BufferManager::GetBufferManager(*db).GetBufferPool().SetAllocatorBulkDeallocationFlushThreshold( + config.options.allocator_bulk_deallocation_flush_threshold); + } +} + +Value AllocatorBulkDeallocationFlushThreshold::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(StringUtil::BytesToHumanReadableString(config.options.allocator_bulk_deallocation_flush_threshold)); +} + +//===--------------------------------------------------------------------===// +// Allocator Background Threads +//===--------------------------------------------------------------------===// +void AllocatorBackgroundThreadsSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + config.options.allocator_background_threads = input.GetValue(); + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(config.options.allocator_background_threads); + } +} + +void AllocatorBackgroundThreadsSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + config.options.allocator_background_threads = DBConfig().options.allocator_background_threads; + if (db) { + TaskScheduler::GetScheduler(*db).SetAllocatorBackgroundThreads(config.options.allocator_background_threads); + } +} + +Value AllocatorBackgroundThreadsSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.allocator_background_threads); +} + +//===--------------------------------------------------------------------===// +// DuckDBApi Setting +//===--------------------------------------------------------------------===// + +void DuckDBApiSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db) { + throw InvalidInputException("Cannot change duckdb_api setting while database is running"); + } + config.options.duckdb_api = new_value; +} + +void DuckDBApiSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change duckdb_api setting while database is running"); + } + config.options.duckdb_api = GetDefaultUserAgent(); +} + +Value DuckDBApiSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.duckdb_api); +} + +//===--------------------------------------------------------------------===// +// CustomUserAgent Setting +//===--------------------------------------------------------------------===// + +void CustomUserAgentSetting::SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &input) { + auto new_value = input.GetValue(); + if (db) { + throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); + } + config.options.custom_user_agent = + config.options.custom_user_agent.empty() ? new_value : config.options.custom_user_agent + " " + new_value; +} + +void CustomUserAgentSetting::ResetGlobal(DatabaseInstance *db, DBConfig &config) { + if (db) { + throw InvalidInputException("Cannot change custom_user_agent setting while database is running"); + } + config.options.custom_user_agent = DBConfig().options.custom_user_agent; +} + +Value CustomUserAgentSetting::GetSetting(const ClientContext &context) { + auto &config = DBConfig::GetConfig(context); + return Value(config.options.custom_user_agent); +} + +//===--------------------------------------------------------------------===// +// EnableHTTPLogging Setting +//===--------------------------------------------------------------------===// +void EnableHTTPLoggingSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).enable_http_logging = ClientConfig().enable_http_logging; +} + +void EnableHTTPLoggingSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).enable_http_logging = input.GetValue(); +} + +Value EnableHTTPLoggingSetting::GetSetting(const ClientContext &context) { + return Value(ClientConfig::GetConfig(context).enable_http_logging); +} + +//===--------------------------------------------------------------------===// +// HTTPLoggingOutput Setting +//===--------------------------------------------------------------------===// +void HTTPLoggingOutputSetting::ResetLocal(ClientContext &context) { + ClientConfig::GetConfig(context).http_logging_output = ClientConfig().http_logging_output; +} + +void HTTPLoggingOutputSetting::SetLocal(ClientContext &context, const Value &input) { + ClientConfig::GetConfig(context).http_logging_output = input.GetValue(); +} + +Value HTTPLoggingOutputSetting::GetSetting(const ClientContext &context) { + return Value(ClientConfig::GetConfig(context).http_logging_output); +} + +} // namespace duckdb diff --git a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp index 384760594..91ba551a9 100644 --- a/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp +++ b/src/duckdb/src/optimizer/build_probe_side_optimizer.cpp @@ -3,15 +3,11 @@ #include "duckdb/common/enums/join_type.hpp" #include "duckdb/common/type_visitor.hpp" #include "duckdb/common/types/row/tuple_data_layout.hpp" +#include "duckdb/execution/physical_plan_generator.hpp" #include "duckdb/planner/operator/logical_any_join.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_join.hpp" -#include "duckdb/planner/operator/logical_order.hpp" -#include "duckdb/optimizer/column_binding_replacer.hpp" -#include "duckdb/optimizer/optimizer.hpp" -#include "duckdb/planner/operator/logical_cross_product.hpp" -#include "duckdb/planner/operator/logical_projection.hpp" namespace duckdb { @@ -20,14 +16,7 @@ static void GetRowidBindings(LogicalOperator &op, vector &binding auto &get = op.Cast(); auto get_bindings = get.GetColumnBindings(); auto &column_ids = get.GetColumnIds(); - bool has_row_id = false; - for (auto &col_id : column_ids) { - if (col_id.IsRowIdColumn()) { - has_row_id = true; - break; - } - } - if (has_row_id) { + if (std::find(column_ids.begin(), column_ids.end(), DConstants::INVALID_INDEX) != column_ids.end()) { for (auto &binding : get_bindings) { bindings.push_back(binding); } @@ -49,12 +38,9 @@ BuildProbeSideOptimizer::BuildProbeSideOptimizer(ClientContext &context, Logical GetRowidBindings(op, preferred_on_probe_side); op.ResolveOperatorTypes(); } - static void FlipChildren(LogicalOperator &op) { std::swap(op.children[0], op.children[1]); - switch (op.type) { - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - case LogicalOperatorType::LOGICAL_DELIM_JOIN: { + if (op.type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN || op.type == LogicalOperatorType::LOGICAL_DELIM_JOIN) { auto &join = op.Cast(); join.join_type = InverseJoinType(join.join_type); for (auto &cond : join.conditions) { @@ -62,20 +48,11 @@ static void FlipChildren(LogicalOperator &op) { cond.comparison = FlipComparisonExpression(cond.comparison); } std::swap(join.left_projection_map, join.right_projection_map); - return; } - case LogicalOperatorType::LOGICAL_ANY_JOIN: { + if (op.type == LogicalOperatorType::LOGICAL_ANY_JOIN) { auto &join = op.Cast(); join.join_type = InverseJoinType(join.join_type); std::swap(join.left_projection_map, join.right_projection_map); - return; - } - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { - // don't need to do anything here - return; - } - default: - throw InternalException("Flipping children, but children were not flipped"); } } @@ -155,7 +132,7 @@ idx_t BuildProbeSideOptimizer::ChildHasJoins(LogicalOperator &op) { return ChildHasJoins(*op.children[0]); } -void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) const { +void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) { auto &left_child = *op.children[0]; auto &right_child = *op.children[1]; const auto lhs_cardinality = left_child.has_estimated_cardinality ? left_child.estimated_cardinality @@ -210,61 +187,61 @@ void BuildProbeSideOptimizer::TryFlipJoinChildren(LogicalOperator &op) const { } void BuildProbeSideOptimizer::VisitOperator(LogicalOperator &op) { - // then the currentoperator switch (op.type) { - case LogicalOperatorType::LOGICAL_DELIM_JOIN: { - auto &join = op.Cast(); - if (HasInverseJoinType(join.join_type)) { - FlipChildren(join); - join.delim_flipped = true; - } - break; - } case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { auto &join = op.Cast(); + switch (join.join_type) { + case JoinType::INNER: + case JoinType::OUTER: + TryFlipJoinChildren(join); + break; + case JoinType::LEFT: + case JoinType::RIGHT: + if (join.right_projection_map.empty()) { + TryFlipJoinChildren(join); + } + break; case JoinType::SEMI: case JoinType::ANTI: { - // if the conditions have no equality, do not flip the children. - // There is no physical join operator (yet) that can do an inequality right_semi/anti join. idx_t has_range = 0; - if (op.type == LogicalOperatorType::LOGICAL_ANY_JOIN || - (op.Cast().HasEquality(has_range) && !context.config.prefer_range_joins)) { - TryFlipJoinChildren(join); + if (!PhysicalPlanGenerator::HasEquality(join.conditions, has_range)) { + // if the conditions have no equality, do not flip the children. + // There is no physical join operator (yet) that can do a right_semi/anti join. + break; } + TryFlipJoinChildren(join); break; } default: - if (HasInverseJoinType(join.join_type)) { - TryFlipJoinChildren(op); - } + break; } break; } + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { + TryFlipJoinChildren(op); + break; + } case LogicalOperatorType::LOGICAL_ANY_JOIN: { - auto &join = op.Cast(); - // We do not yet support the RIGHT_SEMI or RIGHT_ANTI join types for these, so don't try to flip - switch (join.join_type) { - case JoinType::SEMI: - case JoinType::ANTI: - break; // RIGHT_SEMI/RIGHT_ANTI not supported yet for ANY/ASOF - default: - // We cannot flip projection maps are set (YET), but not flipping is worse than just clearing them - // They will be set in the 2nd round of ColumnLifetimeAnalyzer - join.left_projection_map.clear(); - join.right_projection_map.clear(); - TryFlipJoinChildren(op); + auto &join = op.Cast(); + if (join.join_type == JoinType::LEFT && join.right_projection_map.empty()) { + TryFlipJoinChildren(join); + } else if (join.join_type == JoinType::INNER) { + TryFlipJoinChildren(join); } break; } - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { - TryFlipJoinChildren(op); + case LogicalOperatorType::LOGICAL_DELIM_JOIN: { + auto &join = op.Cast(); + if (HasInverseJoinType(join.join_type) && join.right_projection_map.empty()) { + FlipChildren(join); + join.delim_flipped = true; + } break; } default: break; } - VisitOperatorChildren(op); } diff --git a/src/duckdb/src/optimizer/column_binding_replacer.cpp b/src/duckdb/src/optimizer/column_binding_replacer.cpp index f5652ad2a..2450b9267 100644 --- a/src/duckdb/src/optimizer/column_binding_replacer.cpp +++ b/src/duckdb/src/optimizer/column_binding_replacer.cpp @@ -25,7 +25,7 @@ void ColumnBindingReplacer::VisitOperator(LogicalOperator &op) { void ColumnBindingReplacer::VisitExpression(unique_ptr *expression) { auto &expr = *expression; - if (expr->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + if (expr->expression_class == ExpressionClass::BOUND_COLUMN_REF) { auto &bound_column_ref = expr->Cast(); for (const auto &replace_binding : replacement_bindings) { if (bound_column_ref.binding == replace_binding.old_binding) { diff --git a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp index efb3e684d..4df51ba75 100644 --- a/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp +++ b/src/duckdb/src/optimizer/column_lifetime_analyzer.cpp @@ -1,20 +1,14 @@ #include "duckdb/optimizer/column_lifetime_analyzer.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/optimizer/column_binding_replacer.hpp" -#include "duckdb/optimizer/optimizer.hpp" -#include "duckdb/optimizer/topn_optimizer.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/planner/operator/logical_order.hpp" -#include "duckdb/planner/operator/logical_projection.hpp" +#include "duckdb/planner/operator/logical_filter.hpp" +#include "duckdb/planner/expression_iterator.hpp" namespace duckdb { -void ColumnLifetimeAnalyzer::ExtractUnusedColumnBindings(const vector &bindings, +void ColumnLifetimeAnalyzer::ExtractUnusedColumnBindings(vector bindings, column_binding_set_t &unused_bindings) { for (idx_t i = 0; i < bindings.size(); i++) { if (column_references.find(bindings[i]) == column_references.end()) { @@ -43,96 +37,108 @@ void ColumnLifetimeAnalyzer::GenerateProjectionMap(vector binding } void ColumnLifetimeAnalyzer::StandardVisitOperator(LogicalOperator &op) { - VisitOperatorExpressions(op); - VisitOperatorChildren(op); + LogicalOperatorVisitor::VisitOperatorExpressions(op); + if (op.type == LogicalOperatorType::LOGICAL_DELIM_JOIN) { + // visit the duplicate eliminated columns on the LHS, if any + auto &delim_join = op.Cast(); + for (auto &expr : delim_join.duplicate_eliminated_columns) { + VisitExpression(&expr); + } + } + LogicalOperatorVisitor::VisitOperatorChildren(op); } void ExtractColumnBindings(Expression &expr, vector &bindings) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_ref = expr.Cast(); bindings.push_back(bound_ref.binding); } - ExpressionIterator::EnumerateChildren(expr, [&](Expression &child) { ExtractColumnBindings(child, bindings); }); + ExpressionIterator::EnumerateChildren(expr, [&](Expression &expr) { ExtractColumnBindings(expr, bindings); }); } void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { - Verify(op); - if (TopN::CanOptimize(op) && op.children[0]->type == LogicalOperatorType::LOGICAL_ORDER_BY) { - // Let's not mess with this, TopN is more important than projection maps - // TopN does not support a projection map like Order does - VisitOperatorExpressions(op); // Visit LIMIT - VisitOperatorExpressions(*op.children[0]); // Visit ORDER - StandardVisitOperator(*op.children[0]->children[0]); // Recurse into child of ORDER - return; - } switch (op.type) { case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { // FIXME: groups that are not referenced can be removed from projection // recurse into the children of the aggregate - ColumnLifetimeAnalyzer analyzer(optimizer, root); - analyzer.StandardVisitOperator(op); + ColumnLifetimeAnalyzer analyzer; + analyzer.VisitOperatorExpressions(op); + analyzer.VisitOperator(*op.children[0]); return; } case LogicalOperatorType::LOGICAL_ASOF_JOIN: case LogicalOperatorType::LOGICAL_DELIM_JOIN: case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { - auto &comp_join = op.Cast(); if (everything_referenced) { break; } - - // FIXME: for now, we only push into the projection map for equality (hash) joins - idx_t has_range = 0; - if (!comp_join.HasEquality(has_range) || optimizer.context.config.prefer_range_joins) { - return; + auto &comp_join = op.Cast(); + // FIXME for now, we only push into the projection map for equality (hash) joins + // FIXME: add projection to LHS as well + bool has_equality = false; + for (auto &cond : comp_join.conditions) { + if (cond.comparison == ExpressionType::COMPARE_EQUAL) { + has_equality = true; + break; + } } + if (!has_equality) { + break; + } + // visit current operator expressions so they are added to the referenced_columns + LogicalOperatorVisitor::VisitOperatorExpressions(op); - column_binding_set_t lhs_unused; - column_binding_set_t rhs_unused; - ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), lhs_unused); - ExtractUnusedColumnBindings(op.children[1]->GetColumnBindings(), rhs_unused); + column_binding_set_t unused_bindings; + auto old_bindings = op.GetColumnBindings(); + ExtractUnusedColumnBindings(op.children[1]->GetColumnBindings(), unused_bindings); - StandardVisitOperator(op); + // now recurse into the filter and its children + LogicalOperatorVisitor::VisitOperatorChildren(op); // then generate the projection map - if (op.type != LogicalOperatorType::LOGICAL_ASOF_JOIN) { - // FIXME: left_projection_map in ASOF join - GenerateProjectionMap(op.children[0]->GetColumnBindings(), lhs_unused, comp_join.left_projection_map); - } - GenerateProjectionMap(op.children[1]->GetColumnBindings(), rhs_unused, comp_join.right_projection_map); + GenerateProjectionMap(op.children[1]->GetColumnBindings(), unused_bindings, comp_join.right_projection_map); + auto new_bindings = op.GetColumnBindings(); return; } case LogicalOperatorType::LOGICAL_UNION: case LogicalOperatorType::LOGICAL_EXCEPT: case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: { + case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: // for set operations/materialized CTEs we don't remove anything, just recursively visit the children // FIXME: for UNION we can remove unreferenced columns as long as everything_referenced is false (i.e. we // encounter a UNION node that is not preceded by a DISTINCT) - ColumnLifetimeAnalyzer analyzer(optimizer, root, true); - analyzer.StandardVisitOperator(op); + for (auto &child : op.children) { + ColumnLifetimeAnalyzer analyzer(true); + analyzer.VisitOperator(*child); + } return; - } case LogicalOperatorType::LOGICAL_PROJECTION: { // then recurse into the children of this projection - ColumnLifetimeAnalyzer analyzer(optimizer, root); - analyzer.StandardVisitOperator(op); + ColumnLifetimeAnalyzer analyzer; + analyzer.VisitOperatorExpressions(op); + analyzer.VisitOperator(*op.children[0]); return; } - case LogicalOperatorType::LOGICAL_ORDER_BY: { - auto &order = op.Cast(); - if (everything_referenced) { - break; - } + case LogicalOperatorType::LOGICAL_ORDER_BY: + if (!everything_referenced) { + auto &order = op.Cast(); - column_binding_set_t unused_bindings; - ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); + column_binding_set_t unused_bindings; + ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); - StandardVisitOperator(op); + // now recurse into the order and its children + LogicalOperatorVisitor::VisitOperatorExpressions(op); + LogicalOperatorVisitor::VisitOperatorChildren(op); - GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, order.projection_map); - return; - } + // then generate the projection map + GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, order.projections); + return; + } + // order by, for now reference all columns + // FIXME: for ORDER BY we remove columns below an ORDER BY, we just need to make sure that the projections are + // updated + everything_referenced = true; + break; case LogicalOperatorType::LOGICAL_DISTINCT: { // distinct, all projected columns are used for the DISTINCT computation // mark all columns as used and continue to the children @@ -145,89 +151,29 @@ void ColumnLifetimeAnalyzer::VisitOperator(LogicalOperator &op) { if (everything_referenced) { break; } - + // first visit operator expressions to populate referenced columns + LogicalOperatorVisitor::VisitOperatorExpressions(op); // filter, figure out which columns are not needed after the filter column_binding_set_t unused_bindings; ExtractUnusedColumnBindings(op.children[0]->GetColumnBindings(), unused_bindings); - StandardVisitOperator(op); + // now recurse into the filter and its children + LogicalOperatorVisitor::VisitOperatorChildren(op); // then generate the projection map GenerateProjectionMap(op.children[0]->GetColumnBindings(), unused_bindings, filter.projection_map); + auto bindings = filter.GetColumnBindings(); - return; - } - default: - break; - } - StandardVisitOperator(op); -} + if (bindings.empty()) { + return; + } -void ColumnLifetimeAnalyzer::Verify(LogicalOperator &op) { -#ifdef DEBUG - if (everything_referenced) { return; } - switch (op.type) { - case LogicalOperatorType::LOGICAL_ASOF_JOIN: - case LogicalOperatorType::LOGICAL_DELIM_JOIN: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - AddVerificationProjection(op.children[0]); - if (op.Cast().join_type != JoinType::MARK) { // Can't mess up the mark_index - AddVerificationProjection(op.children[1]); - } - break; - case LogicalOperatorType::LOGICAL_ORDER_BY: - case LogicalOperatorType::LOGICAL_FILTER: - AddVerificationProjection(op.children[0]); - break; default: break; } -#endif -} - -void ColumnLifetimeAnalyzer::AddVerificationProjection(unique_ptr &child) { - child->ResolveOperatorTypes(); - const auto child_types = child->types; - const auto child_bindings = child->GetColumnBindings(); - const auto column_count = child_bindings.size(); - - // If our child has columns [i, j], we will generate a projection like so [NULL, j, NULL, i, NULL] - const auto projection_column_count = column_count * 2 + 1; - vector> expressions; - expressions.reserve(projection_column_count); - - // First fill with all NULLs - for (idx_t col_idx = 0; col_idx < projection_column_count; col_idx++) { - expressions.emplace_back(make_uniq(Value(LogicalType::UTINYINT))); - } - - // Now place the "real" columns in their respective positions, while keeping track of which column becomes which - const auto table_index = optimizer.binder.GenerateTableIndex(); - ColumnBindingReplacer replacer; - for (idx_t col_idx = 0; col_idx < column_count; col_idx++) { - const auto &old_binding = child_bindings[col_idx]; - const auto new_col_idx = projection_column_count - 2 - col_idx * 2; - expressions[new_col_idx] = make_uniq(child_types[col_idx], old_binding); - replacer.replacement_bindings.emplace_back(old_binding, ColumnBinding(table_index, new_col_idx)); - } - - // Create a projection and swap the operators accordingly - auto projection = make_uniq(table_index, std::move(expressions)); - projection->children.emplace_back(std::move(child)); - child = std::move(projection); - - // Replace references to the old binding (higher up in the plan) with references to the new binding - replacer.stop_operator = child.get(); - replacer.VisitOperator(root); - - // Add new bindings to column_references, else they are considered "unused" - for (const auto &replacement_binding : replacer.replacement_bindings) { - if (column_references.find(replacement_binding.old_binding) != column_references.end()) { - column_references.insert(replacement_binding.new_binding); - } - } + StandardVisitOperator(op); } unique_ptr ColumnLifetimeAnalyzer::VisitReplace(BoundColumnRefExpression &expr, diff --git a/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp b/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp index 991c12d83..435b94cd3 100644 --- a/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp +++ b/src/duckdb/src/optimizer/common_aggregate_optimizer.cpp @@ -1,37 +1,21 @@ #include "duckdb/optimizer/common_aggregate_optimizer.hpp" -#include "duckdb/parser/expression_map.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/operator/logical_aggregate.hpp" +#include "duckdb/parser/expression_map.hpp" +#include "duckdb/planner/column_binding_map.hpp" namespace duckdb { -void CommonAggregateOptimizer::StandardVisitOperator(LogicalOperator &op) { - VisitOperatorChildren(op); - if (!aggregate_map.empty()) { - VisitOperatorExpressions(op); - } -} - void CommonAggregateOptimizer::VisitOperator(LogicalOperator &op) { + LogicalOperatorVisitor::VisitOperator(op); switch (op.type) { - case LogicalOperatorType::LOGICAL_UNION: - case LogicalOperatorType::LOGICAL_EXCEPT: - case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: - case LogicalOperatorType::LOGICAL_PROJECTION: { - CommonAggregateOptimizer common_aggregate; - common_aggregate.StandardVisitOperator(op); - return; - } + case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: + ExtractCommonAggregates(op.Cast()); + break; default: break; } - - StandardVisitOperator(op); - if (op.type == LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY) { - ExtractCommonAggregates(op.Cast()); - } } unique_ptr CommonAggregateOptimizer::VisitReplace(BoundColumnRefExpression &expr, diff --git a/src/duckdb/src/optimizer/compressed_materialization.cpp b/src/duckdb/src/optimizer/compressed_materialization.cpp index 5e6c30760..3a8198077 100644 --- a/src/duckdb/src/optimizer/compressed_materialization.cpp +++ b/src/duckdb/src/optimizer/compressed_materialization.cpp @@ -1,7 +1,7 @@ #include "duckdb/optimizer/compressed_materialization.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/compressed_materialization_utils.hpp" +#include "duckdb/function/scalar/compressed_materialization_functions.hpp" #include "duckdb/function/scalar/operators.hpp" #include "duckdb/optimizer/column_binding_replacer.hpp" #include "duckdb/optimizer/optimizer.hpp" @@ -333,7 +333,7 @@ static Value GetIntegralRangeValue(ClientContext &context, const LogicalType &ty vector> arguments; arguments.emplace_back(make_uniq(max)); arguments.emplace_back(make_uniq(min)); - BoundFunctionExpression sub(type, SubtractFunction::GetFunction(type, type), std::move(arguments), nullptr); + BoundFunctionExpression sub(type, SubtractFun::GetFunction(type, type), std::move(arguments), nullptr); Value result; if (ExpressionExecutor::TryEvaluateScalar(context, sub, result)) { @@ -401,7 +401,7 @@ unique_ptr CompressedMaterialization::GetStringCompress(uniq const auto max_string_length = StringStats::MaxStringLength(stats); LogicalType cast_type = LogicalType::INVALID; - for (const auto &compressed_type : CMUtils::StringTypes()) { + for (const auto &compressed_type : CompressedMaterializationFunctions::StringTypes()) { if (max_string_length < GetTypeIdSize(compressed_type.InternalType())) { cast_type = compressed_type; break; diff --git a/src/duckdb/src/optimizer/compressed_materialization/compress_aggregate.cpp b/src/duckdb/src/optimizer/compressed_materialization/compress_aggregate.cpp index ae4a7e8f1..beea67d49 100644 --- a/src/duckdb/src/optimizer/compressed_materialization/compress_aggregate.cpp +++ b/src/duckdb/src/optimizer/compressed_materialization/compress_aggregate.cpp @@ -13,7 +13,7 @@ void CompressedMaterialization::CompressAggregate(unique_ptr &o auto &groups = aggregate.groups; column_binding_set_t group_binding_set; for (const auto &group : groups) { - if (group->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (group->type != ExpressionType::BOUND_COLUMN_REF) { continue; } auto &colref = group->Cast(); @@ -67,7 +67,7 @@ void CompressedMaterialization::CompressAggregate(unique_ptr &o // Anything referenced in the aggregate functions is also excluded for (idx_t expr_idx = 0; expr_idx < aggregate.expressions.size(); expr_idx++) { const auto &expr = *aggregate.expressions[expr_idx]; - D_ASSERT(expr.GetExpressionType() == ExpressionType::BOUND_AGGREGATE); + D_ASSERT(expr.type == ExpressionType::BOUND_AGGREGATE); const auto &aggr_expr = expr.Cast(); for (const auto &child : aggr_expr.children) { GetReferencedBindings(*child, referenced_bindings); @@ -78,7 +78,7 @@ void CompressedMaterialization::CompressAggregate(unique_ptr &o if (aggr_expr.order_bys) { for (const auto &order : aggr_expr.order_bys->orders) { const auto &order_expr = *order.expression; - if (order_expr.GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (order_expr.type != ExpressionType::BOUND_COLUMN_REF) { GetReferencedBindings(order_expr, referenced_bindings); } } diff --git a/src/duckdb/src/optimizer/compressed_materialization/compress_distinct.cpp b/src/duckdb/src/optimizer/compressed_materialization/compress_distinct.cpp index e533bfaac..3dd1f5367 100644 --- a/src/duckdb/src/optimizer/compressed_materialization/compress_distinct.cpp +++ b/src/duckdb/src/optimizer/compressed_materialization/compress_distinct.cpp @@ -10,14 +10,14 @@ void CompressedMaterialization::CompressDistinct(unique_ptr &op column_binding_set_t referenced_bindings; for (auto &target : distinct_targets) { - if (target->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { // LCOV_EXCL_START + if (target->type != ExpressionType::BOUND_COLUMN_REF) { // LCOV_EXCL_START GetReferencedBindings(*target, referenced_bindings); } // LCOV_EXCL_STOP } if (distinct.order_by) { for (auto &order : distinct.order_by->orders) { - if (order.expression->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { // LCOV_EXCL_START + if (order.expression->type != ExpressionType::BOUND_COLUMN_REF) { // LCOV_EXCL_START GetReferencedBindings(*order.expression, referenced_bindings); } // LCOV_EXCL_STOP } diff --git a/src/duckdb/src/optimizer/cse_optimizer.cpp b/src/duckdb/src/optimizer/cse_optimizer.cpp index cde7aeb4c..12034f07f 100644 --- a/src/duckdb/src/optimizer/cse_optimizer.cpp +++ b/src/duckdb/src/optimizer/cse_optimizer.cpp @@ -47,7 +47,7 @@ void CommonSubExpressionOptimizer::VisitOperator(LogicalOperator &op) { void CommonSubExpressionOptimizer::CountExpressions(Expression &expr, CSEReplacementState &state) { // we only consider expressions with children for CSE elimination - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BOUND_COLUMN_REF: case ExpressionClass::BOUND_CONSTANT: case ExpressionClass::BOUND_PARAMETER: @@ -58,7 +58,7 @@ void CommonSubExpressionOptimizer::CountExpressions(Expression &expr, CSEReplace default: break; } - if (expr.GetExpressionClass() != ExpressionClass::BOUND_AGGREGATE && !expr.IsVolatile()) { + if (expr.expression_class != ExpressionClass::BOUND_AGGREGATE && !expr.IsVolatile()) { // we can't move aggregates to a projection, so we only consider the children of the aggregate auto node = state.expression_count.find(expr); if (node == state.expression_count.end()) { @@ -75,7 +75,7 @@ void CommonSubExpressionOptimizer::CountExpressions(Expression &expr, CSEReplace void CommonSubExpressionOptimizer::PerformCSEReplacement(unique_ptr &expr_ptr, CSEReplacementState &state) { Expression &expr = *expr_ptr; - if (expr.GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + if (expr.expression_class == ExpressionClass::BOUND_COLUMN_REF) { auto &bound_column_ref = expr.Cast(); // bound column ref, check if this one has already been recorded in the expression list auto column_entry = state.column_map.find(bound_column_ref.binding); @@ -84,7 +84,7 @@ void CommonSubExpressionOptimizer::PerformCSEReplacement(unique_ptr idx_t new_column_index = state.expressions.size(); state.column_map[bound_column_ref.binding] = new_column_index; state.expressions.push_back(make_uniq( - bound_column_ref.GetAlias(), bound_column_ref.return_type, bound_column_ref.binding)); + bound_column_ref.alias, bound_column_ref.return_type, bound_column_ref.binding)); bound_column_ref.binding = ColumnBinding(state.projection_index, new_column_index); } else { // else: just update the column binding! @@ -93,14 +93,14 @@ void CommonSubExpressionOptimizer::PerformCSEReplacement(unique_ptr return; } // check if this child is eligible for CSE elimination - bool can_cse = expr.GetExpressionClass() != ExpressionClass::BOUND_CONJUNCTION && - expr.GetExpressionClass() != ExpressionClass::BOUND_CASE; + bool can_cse = expr.expression_class != ExpressionClass::BOUND_CONJUNCTION && + expr.expression_class != ExpressionClass::BOUND_CASE; if (can_cse && state.expression_count.find(expr) != state.expression_count.end()) { auto &node = state.expression_count[expr]; if (node.count > 1) { // this expression occurs more than once! push it into the projection // check if it has already been pushed into the projection - auto alias = expr.GetAlias(); + auto alias = expr.alias; auto type = expr.return_type; if (!node.column_index.IsValid()) { // has not been pushed yet: push it diff --git a/src/duckdb/src/optimizer/deliminator.cpp b/src/duckdb/src/optimizer/deliminator.cpp index 254a57026..805e56609 100644 --- a/src/duckdb/src/optimizer/deliminator.cpp +++ b/src/duckdb/src/optimizer/deliminator.cpp @@ -206,8 +206,8 @@ bool Deliminator::RemoveJoinWithDelimGet(LogicalComparisonJoin &delim_join, cons all_equality_conditions = all_equality_conditions && IsEqualityJoinCondition(cond); auto &delim_side = delim_idx == 0 ? *cond.left : *cond.right; auto &other_side = delim_idx == 0 ? *cond.right : *cond.left; - if (delim_side.GetExpressionType() != ExpressionType::BOUND_COLUMN_REF || - other_side.GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (delim_side.type != ExpressionType::BOUND_COLUMN_REF || + other_side.type != ExpressionType::BOUND_COLUMN_REF) { return false; } auto &delim_colref = delim_side.Cast(); @@ -257,8 +257,7 @@ bool FindAndReplaceBindings(vector &traced_bindings, const vector } } - if (current_idx == expressions.size() || - expressions[current_idx]->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (current_idx == expressions.size() || expressions[current_idx]->type != ExpressionType::BOUND_COLUMN_REF) { return false; // Didn't find / can't deal with non-colref } @@ -294,7 +293,7 @@ bool Deliminator::RemoveInequalityJoinWithDelimGet(LogicalComparisonJoin &delim_ // We only support colref's vector traced_bindings; for (const auto &cond : delim_conditions) { - if (cond.right->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (cond.right->type != ExpressionType::BOUND_COLUMN_REF) { return false; } auto &colref = cond.right->Cast(); @@ -368,7 +367,7 @@ void Deliminator::TrySwitchSingleToLeft(LogicalComparisonJoin &delim_join) { if (!IsEqualityJoinCondition(cond)) { return; } - if (cond.right->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (cond.right->type != ExpressionType::BOUND_COLUMN_REF) { return; } auto &colref = cond.right->Cast(); diff --git a/src/duckdb/src/optimizer/empty_result_pullup.cpp b/src/duckdb/src/optimizer/empty_result_pullup.cpp deleted file mode 100644 index 12b809634..000000000 --- a/src/duckdb/src/optimizer/empty_result_pullup.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "duckdb/optimizer/empty_result_pullup.hpp" -#include "duckdb/common/enums/logical_operator_type.hpp" -#include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/planner/operator/logical_empty_result.hpp" -#include "duckdb/planner/operator/logical_any_join.hpp" - -namespace duckdb { - -unique_ptr EmptyResultPullup::PullUpEmptyJoinChildren(unique_ptr op) { - JoinType join_type = JoinType::INVALID; - D_ASSERT(op->type == LogicalOperatorType::LOGICAL_COMPARISON_JOIN || - op->type == LogicalOperatorType::LOGICAL_ANY_JOIN || op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN || - op->type == LogicalOperatorType::LOGICAL_EXCEPT); - switch (op->type) { - case LogicalOperatorType::LOGICAL_DELIM_JOIN: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - join_type = op->Cast().join_type; - break; - case LogicalOperatorType::LOGICAL_ANY_JOIN: - join_type = op->Cast().join_type; - break; - case LogicalOperatorType::LOGICAL_EXCEPT: - join_type = JoinType::ANTI; - break; - case LogicalOperatorType::LOGICAL_INTERSECT: - join_type = JoinType::SEMI; - break; - default: - break; - } - - switch (join_type) { - case JoinType::SEMI: - case JoinType::INNER: { - for (auto &child : op->children) { - if (child->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { - op = make_uniq(std::move(op)); - break; - } - } - break; - } - // TODO: For ANTI joins, if the right child is empty, you can replace the whole join with - // the left child - case JoinType::ANTI: - case JoinType::MARK: - case JoinType::SINGLE: - case JoinType::LEFT: { - if (op->children[0]->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { - op = make_uniq(std::move(op)); - } - break; - } - default: - break; - } - return op; -} - -unique_ptr EmptyResultPullup::Optimize(unique_ptr op) { - for (idx_t i = 0; i < op->children.size(); i++) { - op->children[i] = Optimize(std::move(op->children[i])); - } - switch (op->type) { - case LogicalOperatorType::LOGICAL_PROJECTION: - case LogicalOperatorType::LOGICAL_FILTER: - case LogicalOperatorType::LOGICAL_DISTINCT: - case LogicalOperatorType::LOGICAL_WINDOW: - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: - case LogicalOperatorType::LOGICAL_GET: - case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_PIVOT: - case LogicalOperatorType::LOGICAL_ASOF_JOIN: - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: { - for (auto &child : op->children) { - if (child->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { - op = make_uniq(std::move(op)); - break; - } - } - return op; - } - case LogicalOperatorType::LOGICAL_EXCEPT: - case LogicalOperatorType::LOGICAL_ANY_JOIN: - case LogicalOperatorType::LOGICAL_DELIM_JOIN: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { - op = PullUpEmptyJoinChildren(std::move(op)); - break; - } - default: - break; - } - return op; -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/expression_heuristics.cpp b/src/duckdb/src/optimizer/expression_heuristics.cpp index e6103b6d3..e334db4b0 100644 --- a/src/duckdb/src/optimizer/expression_heuristics.cpp +++ b/src/duckdb/src/optimizer/expression_heuristics.cpp @@ -1,5 +1,4 @@ #include "duckdb/optimizer/expression_heuristics.hpp" - #include "duckdb/planner/expression/list.hpp" namespace duckdb { @@ -42,13 +41,6 @@ void ExpressionHeuristics::ReorderExpressions(vector> &ex } }; - for (idx_t i = 0; i < expressions.size(); i++) { - if (expressions[i]->CanThrow()) { - // do not allow reordering if an expression can throw - return; - } - } - vector expression_costs; expression_costs.reserve(expressions.size()); // iterate expressions, get cost for each one @@ -125,7 +117,7 @@ idx_t ExpressionHeuristics::ExpressionCost(BoundFunctionExpression &expr) { } } -idx_t ExpressionHeuristics::ExpressionCost(BoundOperatorExpression &expr, ExpressionType expr_type) { +idx_t ExpressionHeuristics::ExpressionCost(BoundOperatorExpression &expr, ExpressionType &expr_type) { idx_t sum = 0; for (auto &child : expr.children) { sum += Cost(*child); @@ -159,7 +151,7 @@ idx_t ExpressionHeuristics::ExpressionCost(PhysicalType return_type, idx_t multi } idx_t ExpressionHeuristics::Cost(Expression &expr) { - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BOUND_CASE: { auto &case_expr = expr.Cast(); return ExpressionCost(case_expr); @@ -186,7 +178,7 @@ idx_t ExpressionHeuristics::Cost(Expression &expr) { } case ExpressionClass::BOUND_OPERATOR: { auto &op_expr = expr.Cast(); - return ExpressionCost(op_expr, expr.GetExpressionType()); + return ExpressionCost(op_expr, expr.type); } case ExpressionClass::BOUND_COLUMN_REF: { auto &col_expr = expr.Cast(); diff --git a/src/duckdb/src/optimizer/expression_rewriter.cpp b/src/duckdb/src/optimizer/expression_rewriter.cpp index a8ab28358..fea861e9d 100644 --- a/src/duckdb/src/optimizer/expression_rewriter.cpp +++ b/src/duckdb/src/optimizer/expression_rewriter.cpp @@ -4,7 +4,6 @@ #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/function/scalar/generic_functions.hpp" -#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" @@ -49,11 +48,9 @@ unique_ptr ExpressionRewriter::ConstantOrNull(unique_ptr unique_ptr ExpressionRewriter::ConstantOrNull(vector> children, Value value) { auto type = value.type(); - auto func = ConstantOrNullFun::GetFunction(); - func.arguments[0] = type; - func.return_type = type; children.insert(children.begin(), make_uniq(value)); - return make_uniq(type, func, std::move(children), ConstantOrNull::Bind(std::move(value))); + return make_uniq(type, ConstantOrNull::GetFunction(type), std::move(children), + ConstantOrNull::Bind(std::move(value))); } void ExpressionRewriter::VisitOperator(LogicalOperator &op) { diff --git a/src/duckdb/src/optimizer/filter_combiner.cpp b/src/duckdb/src/optimizer/filter_combiner.cpp index a72354d7d..91b512f8c 100644 --- a/src/duckdb/src/optimizer/filter_combiner.cpp +++ b/src/duckdb/src/optimizer/filter_combiner.cpp @@ -1,7 +1,6 @@ #include "duckdb/optimizer/filter_combiner.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/optimizer/optimizer.hpp" #include "duckdb/planner/expression.hpp" #include "duckdb/planner/expression/bound_between_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" @@ -11,13 +10,11 @@ #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" +#include "duckdb/planner/table_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" -#include "duckdb/planner/filter/in_filter.hpp" #include "duckdb/planner/filter/null_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" -#include "duckdb/planner/table_filter.hpp" -#include "duckdb/common/operator/subtract.hpp" +#include "duckdb/optimizer/optimizer.hpp" namespace duckdb { @@ -401,8 +398,8 @@ bool FilterCombiner::HasFilters() { // Try to extract a column index from a bound column ref expression, or a column ref recursively nested // inside of a struct_extract call. If the expression is not a column ref (or nested column ref), return false. -static bool TryGetBoundColumnIndex(const vector &column_ids, const Expression &expr, ColumnIndex &result) { - switch (expr.GetExpressionType()) { +static bool TryGetBoundColumnIndex(const vector &column_ids, const Expression &expr, idx_t &result) { + switch (expr.type) { case ExpressionType::BOUND_COLUMN_REF: { auto &ref = expr.Cast(); result = column_ids[ref.binding.column_index]; @@ -410,7 +407,7 @@ static bool TryGetBoundColumnIndex(const vector &column_ids, const } case ExpressionType::BOUND_FUNCTION: { auto &func = expr.Cast(); - if (func.function.name == "struct_extract" || func.function.name == "struct_extract_at") { + if (func.function.name == "struct_extract") { auto &child_expr = func.children[0]; return TryGetBoundColumnIndex(column_ids, *child_expr, result); } @@ -424,62 +421,21 @@ static bool TryGetBoundColumnIndex(const vector &column_ids, const // Try to push down a filter into a expression by recursively wrapping any nested expressions in StructFilters. // If the expression is not a struct_extract, return the inner_filter unchanged. static unique_ptr PushDownFilterIntoExpr(const Expression &expr, unique_ptr inner_filter) { - if (expr.GetExpressionType() == ExpressionType::BOUND_FUNCTION) { + if (expr.type == ExpressionType::BOUND_FUNCTION) { auto &func = expr.Cast(); - auto &child_expr = func.children[0]; - auto child_value = func.children[1]->Cast().value; if (func.function.name == "struct_extract") { - string child_name = child_value.GetValue(); + auto &child_expr = func.children[0]; + auto child_name = func.children[1]->Cast().value.GetValue(); auto child_index = StructType::GetChildIndexUnsafe(func.children[0]->return_type, child_name); + inner_filter = make_uniq(child_index, child_name, std::move(inner_filter)); return PushDownFilterIntoExpr(*child_expr, std::move(inner_filter)); - } else if (func.function.name == "struct_extract_at") { - inner_filter = make_uniq(child_value.GetValue() - 1, "", std::move(inner_filter)); - return PushDownFilterIntoExpr(*child_expr, std::move(inner_filter)); } } return inner_filter; } -bool FilterCombiner::ContainsNull(vector &in_list) { - for (idx_t i = 0; i < in_list.size(); i++) { - if (in_list[i].IsNull()) { - return true; - } - } - return false; -} - -bool FilterCombiner::IsDenseRange(vector &in_list) { - if (in_list.empty()) { - return true; - } - if (!in_list[0].type().IsIntegral()) { - return false; - } - // sort the input list - sort(in_list.begin(), in_list.end()); - - // check if the gap between each value is exactly one - hugeint_t prev_value = in_list[0].GetValue(); - for (idx_t i = 1; i < in_list.size(); i++) { - hugeint_t current_value = in_list[i].GetValue(); - hugeint_t diff; - if (!TrySubtractOperator::Operation(current_value, prev_value, diff)) { - // if subtract would overflow then it's certainly not 1 - return false; - } - if (diff != 1) { - // gap is not 1 - this is not a dense range - return false; - } - prev_value = current_value; - } - // dense range - return true; -} - -TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector &column_ids) { +TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector &column_ids) { TableFilterSet table_filters; //! First, we figure the filters that have constant expressions that we can push down to the table scan for (auto &constant_value : constant_values) { @@ -489,8 +445,7 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vectorsecond; for (auto &constant_cmp : constant_list) { @@ -517,6 +475,10 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(constant_cmp.comparison_type, constant_cmp.constant); table_filters.PushFilter(column_index, PushDownFilterIntoExpr(expr, std::move(constant_filter))); } + // We need to apply a IS NOT NULL filter to the column expression because any comparison with NULL + // is always false. + table_filters.PushFilter(column_index, PushDownFilterIntoExpr(expr, make_uniq())); + equivalence_map.erase(filter_exp); } } @@ -524,11 +486,11 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vectorGetExpressionClass() == ExpressionClass::BOUND_FUNCTION) { + if (remaining_filter->expression_class == ExpressionClass::BOUND_FUNCTION) { auto &func = remaining_filter->Cast(); if (func.function.name == "prefix" && - func.children[0]->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF && - func.children[1]->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + func.children[0]->expression_class == ExpressionClass::BOUND_COLUMN_REF && + func.children[1]->type == ExpressionType::VALUE_CONSTANT) { //! This is a like function. auto &column_ref = func.children[0]->Cast(); auto &constant_value_expr = func.children[1]->Cast(); @@ -536,7 +498,7 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(ExpressionType::COMPARE_GREATERTHANOREQUALTO, Value(like_string)); @@ -544,14 +506,14 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(ExpressionType::COMPARE_LESSTHAN, Value(like_string)); table_filters.PushFilter(column_index, std::move(lower_bound)); table_filters.PushFilter(column_index, std::move(upper_bound)); + table_filters.PushFilter(column_index, make_uniq()); } - if (func.function.name == "~~" && - func.children[0]->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF && - func.children[1]->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (func.function.name == "~~" && func.children[0]->expression_class == ExpressionClass::BOUND_COLUMN_REF && + func.children[1]->type == ExpressionType::VALUE_CONSTANT) { //! This is a like function. auto &column_ref = func.children[0]->Cast(); auto &constant_value_expr = func.children[1]->Cast(); - auto &column_index = column_ids[column_ref.binding.column_index]; + auto column_index = column_ids[column_ref.binding.column_index]; // constant value expr can sometimes be null. if so, push is not null filter, which will // make the filter unsatisfiable and return no results. if (constant_value_expr.value.IsNull()) { @@ -577,6 +539,7 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(ExpressionType::COMPARE_EQUAL, Value(prefix)); table_filters.PushFilter(column_index, std::move(equal_filter)); + table_filters.PushFilter(column_index, make_uniq()); } else { //! Here the like must be transformed to a BOUND COMPARISON geq le auto lower_bound = @@ -585,23 +548,25 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(ExpressionType::COMPARE_LESSTHAN, Value(prefix)); table_filters.PushFilter(column_index, std::move(lower_bound)); table_filters.PushFilter(column_index, std::move(upper_bound)); + table_filters.PushFilter(column_index, make_uniq()); } } - } else if (remaining_filter->GetExpressionType() == ExpressionType::COMPARE_IN) { + } else if (remaining_filter->type == ExpressionType::COMPARE_IN) { auto &func = remaining_filter->Cast(); + vector in_values; D_ASSERT(func.children.size() > 1); - if (func.children[0]->GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { + if (func.children[0]->expression_class != ExpressionClass::BOUND_COLUMN_REF) { continue; } auto &column_ref = func.children[0]->Cast(); - auto &column_index = column_ids[column_ref.binding.column_index]; - if (column_index.IsRowIdColumn()) { + auto column_index = column_ids[column_ref.binding.column_index]; + if (column_index == COLUMN_IDENTIFIER_ROW_ID) { break; } //! check if all children are const expr bool children_constant = true; for (size_t i {1}; i < func.children.size(); i++) { - if (func.children[i]->GetExpressionType() != ExpressionType::VALUE_CONSTANT) { + if (func.children[i]->type != ExpressionType::VALUE_CONSTANT) { children_constant = false; break; } @@ -623,117 +588,52 @@ TableFilterSet FilterCombiner::GenerateTableScanFilters(const vector(ExpressionType::COMPARE_EQUAL, fst_const_value_expr.value); table_filters.PushFilter(column_index, std::move(bound_eq_comparison)); - remaining_filters.erase_at(rem_fil_idx--); // decrement to stay on the same idx next iteration + table_filters.PushFilter(column_index, make_uniq()); + remaining_filters.erase_at(rem_fil_idx); continue; } //! Check if values are consecutive, if yes transform them to >= <= (only for integers) // e.g. if we have x IN (1, 2, 3, 4, 5) we transform this into x >= 1 AND x <= 5 - vector in_list; + if (!type.IsIntegral()) { + continue; + } + for (idx_t i = 1; i < func.children.size(); i++) { auto &const_value_expr = func.children[i]->Cast(); D_ASSERT(!const_value_expr.value.IsNull()); - in_list.push_back(const_value_expr.value); + in_values.push_back(const_value_expr.value.GetValue()); } - if (type.IsIntegral() && IsDenseRange(in_list)) { - // dense range! turn this into x >= min AND x <= max - // IsDenseRange sorts in_list, so the front element is the min and the back element is the max - auto lower_bound = - make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, std::move(in_list.front())); - auto upper_bound = - make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, std::move(in_list.back())); - table_filters.PushFilter(column_index, std::move(lower_bound)); - table_filters.PushFilter(column_index, std::move(upper_bound)); - - remaining_filters.erase_at(rem_fil_idx--); // decrement to stay on the same idx next iteration - } else { - // if this is not a dense range we can push a zone-map filter - auto optional_filter = make_uniq(); - auto in_filter = make_uniq(std::move(in_list)); - optional_filter->child_filter = std::move(in_filter); - table_filters.PushFilter(column_index, std::move(optional_filter)); + if (in_values.empty()) { + continue; } - } - } - for (idx_t rem_fil_idx = 0; rem_fil_idx < remaining_filters.size(); rem_fil_idx++) { - auto &remaining_filter = remaining_filters[rem_fil_idx]; - if (remaining_filter->GetExpressionClass() == ExpressionClass::BOUND_CONJUNCTION) { - auto &conj = remaining_filter->Cast(); - if (conj.GetExpressionType() == ExpressionType::CONJUNCTION_OR) { - optional_idx column_id; - auto optional_filter = make_uniq(); - auto conj_filter = make_uniq(); - for (auto &child : conj.children) { - if (child->GetExpressionClass() != ExpressionClass::BOUND_COMPARISON) { - column_id.SetInvalid(); - break; - } - optional_ptr column_ref; - optional_ptr const_val; - auto &comp = child->Cast(); - bool invert = false; - if (comp.left->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF && - comp.right->GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { - column_ref = comp.left->Cast(); - const_val = comp.right->Cast(); - } else if (comp.left->GetExpressionClass() == ExpressionClass::BOUND_CONSTANT && - comp.right->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { - column_ref = comp.right->Cast(); - const_val = comp.left->Cast(); - invert = true; - } else { - // child of OR filter is not simple so we do not push the or filter down at all - column_id.SetInvalid(); - break; - } - - if (!column_id.IsValid()) { - auto &col_id = column_ids[column_ref->binding.column_index]; - if (col_id.IsRowIdColumn()) { - break; - } - column_id = col_id.GetPrimaryIndex(); - } else if (column_id.GetIndex() != column_ids[column_ref->binding.column_index].GetPrimaryIndex()) { - column_id.SetInvalid(); - break; - } + sort(in_values.begin(), in_values.end()); - if (const_val->value.type().IsTemporal()) { - column_id.SetInvalid(); - break; - } - auto comparison_type = - invert ? FlipComparisonExpression(comp.GetExpressionType()) : comp.GetExpressionType(); - if (const_val->value.IsNull()) { - switch (comparison_type) { - case ExpressionType::COMPARE_DISTINCT_FROM: { - auto null_filter = make_uniq(); - conj_filter->child_filters.push_back(std::move(null_filter)); - break; - } - case ExpressionType::COMPARE_NOT_DISTINCT_FROM: { - auto null_filter = make_uniq(); - conj_filter->child_filters.push_back(std::move(null_filter)); - break; - } - // if any other comparison type (i.e EQUAL, NOT_EQUAL) do not push a table filter - default: - break; - } - } else { - auto const_filter = make_uniq(comparison_type, const_val->value); - conj_filter->child_filters.push_back(std::move(const_filter)); - } - } - if (column_id.IsValid()) { - optional_filter->child_filter = std::move(conj_filter); - table_filters.PushFilter(ColumnIndex(column_id.GetIndex()), std::move(optional_filter)); + bool can_simplify_in_clause = true; + for (idx_t in_val_idx = 1; in_val_idx < in_values.size(); in_val_idx++) { + if (in_values[in_val_idx] - in_values[in_val_idx - 1] > 1) { + can_simplify_in_clause = false; + break; } } + if (!can_simplify_in_clause) { + continue; + } + auto lower_bound = make_uniq(ExpressionType::COMPARE_GREATERTHANOREQUALTO, + Value::Numeric(type, in_values.front())); + auto upper_bound = make_uniq(ExpressionType::COMPARE_LESSTHANOREQUALTO, + Value::Numeric(type, in_values.back())); + table_filters.PushFilter(column_index, std::move(lower_bound)); + table_filters.PushFilter(column_index, std::move(upper_bound)); + table_filters.PushFilter(column_index, make_uniq()); + + remaining_filters.erase_at(rem_fil_idx); } } + // GenerateORFilters(table_filters, column_ids); + return table_filters; } @@ -747,12 +647,11 @@ static bool IsLessThan(ExpressionType type) { FilterResult FilterCombiner::AddBoundComparisonFilter(Expression &expr) { auto &comparison = expr.Cast(); - if (comparison.GetExpressionType() != ExpressionType::COMPARE_LESSTHAN && - comparison.GetExpressionType() != ExpressionType::COMPARE_LESSTHANOREQUALTO && - comparison.GetExpressionType() != ExpressionType::COMPARE_GREATERTHAN && - comparison.GetExpressionType() != ExpressionType::COMPARE_GREATERTHANOREQUALTO && - comparison.GetExpressionType() != ExpressionType::COMPARE_EQUAL && - comparison.GetExpressionType() != ExpressionType::COMPARE_NOTEQUAL) { + if (comparison.type != ExpressionType::COMPARE_LESSTHAN && + comparison.type != ExpressionType::COMPARE_LESSTHANOREQUALTO && + comparison.type != ExpressionType::COMPARE_GREATERTHAN && + comparison.type != ExpressionType::COMPARE_GREATERTHANOREQUALTO && + comparison.type != ExpressionType::COMPARE_EQUAL && comparison.type != ExpressionType::COMPARE_NOTEQUAL) { // only support [>, >=, <, <=, ==, !=] expressions return FilterResult::UNSUPPORTED; } @@ -775,8 +674,7 @@ FilterResult FilterCombiner::AddBoundComparisonFilter(Expression &expr) { // create the ExpressionValueInformation ExpressionValueInformation info; - info.comparison_type = - left_is_scalar ? FlipComparisonExpression(comparison.GetExpressionType()) : comparison.GetExpressionType(); + info.comparison_type = left_is_scalar ? FlipComparisonExpression(comparison.type) : comparison.type; info.constant = constant_value; // get the current bucket of constant values @@ -802,7 +700,7 @@ FilterResult FilterCombiner::AddBoundComparisonFilter(Expression &expr) { } else { // comparison between two non-scalars // only handle comparisons for now - if (expr.GetExpressionType() != ExpressionType::COMPARE_EQUAL) { + if (expr.type != ExpressionType::COMPARE_EQUAL) { return FilterResult::UNSUPPORTED; } // get the LHS and RHS nodes @@ -956,7 +854,7 @@ FilterResult FilterCombiner::AddFilter(Expression &expr) { * It's missing to create another method to add transitive filters from scalar filters, e.g, i > 10 */ FilterResult FilterCombiner::AddTransitiveFilters(BoundComparisonExpression &comparison, bool is_root) { - if (!IsGreaterThan(comparison.GetExpressionType()) && !IsLessThan(comparison.GetExpressionType())) { + if (!IsGreaterThan(comparison.type) && !IsLessThan(comparison.type)) { return FilterResult::UNSUPPORTED; } // get the LHS and RHS nodes @@ -964,20 +862,20 @@ FilterResult FilterCombiner::AddTransitiveFilters(BoundComparisonExpression &com reference right_node = GetNode(*comparison.right); // In case with filters like CAST(i) = j and i = 5 we replace the COLUMN_REF i with the constant 5 do { - if (right_node.get().GetExpressionType() != ExpressionType::OPERATOR_CAST) { + if (right_node.get().type != ExpressionType::OPERATOR_CAST) { break; } auto &bound_cast_expr = right_node.get().Cast(); - if (bound_cast_expr.child->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (bound_cast_expr.child->type != ExpressionType::BOUND_COLUMN_REF) { break; } auto &col_ref = bound_cast_expr.child->Cast(); for (auto &stored_exp : stored_expressions) { reference expr = stored_exp.first; - if (expr.get().GetExpressionType() == ExpressionType::OPERATOR_CAST) { + if (expr.get().type == ExpressionType::OPERATOR_CAST) { expr = *(right_node.get().Cast().child); } - if (expr.get().GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (expr.get().type != ExpressionType::BOUND_COLUMN_REF) { continue; } auto &st_col_ref = expr.get().Cast(); @@ -1020,33 +918,33 @@ FilterResult FilterCombiner::AddTransitiveFilters(BoundComparisonExpression &com // suppose the new comparison is j >= i and we have already a filter i = 10, // then we create a new filter j >= 10 // and the filter j >= i can be pruned by not adding it into the remaining filters - info.comparison_type = comparison.GetExpressionType(); - } else if ((comparison.GetExpressionType() == ExpressionType::COMPARE_GREATERTHANOREQUALTO && + info.comparison_type = comparison.type; + } else if ((comparison.type == ExpressionType::COMPARE_GREATERTHANOREQUALTO && IsGreaterThan(right_constant.comparison_type)) || - (comparison.GetExpressionType() == ExpressionType::COMPARE_LESSTHANOREQUALTO && + (comparison.type == ExpressionType::COMPARE_LESSTHANOREQUALTO && IsLessThan(right_constant.comparison_type))) { // filters (j >= i AND i [>, >=] 10) OR (j <= i AND i [<, <=] 10) // create filter j [>, >=] 10 and add the filter j [>=, <=] i into the remaining filters info.comparison_type = right_constant.comparison_type; // create filter j [>, >=, <, <=] 10 if (!is_inserted) { // Add the filter j >= i in the remaing filters - auto filter = make_uniq(comparison.GetExpressionType(), - comparison.left->Copy(), comparison.right->Copy()); + auto filter = make_uniq(comparison.type, comparison.left->Copy(), + comparison.right->Copy()); remaining_filters.push_back(std::move(filter)); is_inserted = true; } - } else if ((comparison.GetExpressionType() == ExpressionType::COMPARE_GREATERTHAN && + } else if ((comparison.type == ExpressionType::COMPARE_GREATERTHAN && IsGreaterThan(right_constant.comparison_type)) || - (comparison.GetExpressionType() == ExpressionType::COMPARE_LESSTHAN && + (comparison.type == ExpressionType::COMPARE_LESSTHAN && IsLessThan(right_constant.comparison_type))) { // filters (j > i AND i [>, >=] 10) OR j < i AND i [<, <=] 10 // create filter j [>, <] 10 and add the filter j [>, <] i into the remaining filters // the comparisons j > i and j < i are more restrictive - info.comparison_type = comparison.GetExpressionType(); + info.comparison_type = comparison.type; if (!is_inserted) { // Add the filter j [>, <] i - auto filter = make_uniq(comparison.GetExpressionType(), - comparison.left->Copy(), comparison.right->Copy()); + auto filter = make_uniq(comparison.type, comparison.left->Copy(), + comparison.right->Copy()); remaining_filters.push_back(std::move(filter)); is_inserted = true; } @@ -1086,13 +984,13 @@ FilterResult FilterCombiner::AddTransitiveFilters(BoundComparisonExpression &com */ unique_ptr FilterCombiner::FindTransitiveFilter(Expression &expr) { // We only check for bound column ref - if (expr.GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (expr.type != ExpressionType::BOUND_COLUMN_REF) { return nullptr; } for (idx_t i = 0; i < remaining_filters.size(); i++) { if (remaining_filters[i]->GetExpressionClass() == ExpressionClass::BOUND_COMPARISON) { auto &comparison = remaining_filters[i]->Cast(); - if (expr.Equals(*comparison.right) && comparison.GetExpressionType() != ExpressionType::COMPARE_NOTEQUAL) { + if (expr.Equals(*comparison.right) && comparison.type != ExpressionType::COMPARE_NOTEQUAL) { auto filter = std::move(remaining_filters[i]); remaining_filters.erase_at(i); return filter; diff --git a/src/duckdb/src/optimizer/filter_pushdown.cpp b/src/duckdb/src/optimizer/filter_pushdown.cpp index c7962b714..f5a7b405f 100644 --- a/src/duckdb/src/optimizer/filter_pushdown.cpp +++ b/src/duckdb/src/optimizer/filter_pushdown.cpp @@ -1,4 +1,5 @@ #include "duckdb/optimizer/filter_pushdown.hpp" + #include "duckdb/optimizer/filter_combiner.hpp" #include "duckdb/optimizer/optimizer.hpp" #include "duckdb/planner/expression_iterator.hpp" @@ -14,7 +15,6 @@ using Filter = FilterPushdown::Filter; void FilterPushdown::CheckMarkToSemi(LogicalOperator &op, unordered_set &table_bindings) { switch (op.type) { - case LogicalOperatorType::LOGICAL_DELIM_JOIN: case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: { auto &join = op.Cast(); if (join.join_type != JoinType::MARK) { @@ -32,6 +32,7 @@ void FilterPushdown::CheckMarkToSemi(LogicalOperator &op, unordered_set & case LogicalOperatorType::LOGICAL_PROJECTION: { // when we encounter a projection, replace the table_bindings with // the tables in the projection + auto plan_bindings = op.GetColumnBindings(); auto &proj = op.Cast(); auto proj_bindings = proj.GetColumnBindings(); unordered_set new_table_bindings; @@ -40,8 +41,8 @@ void FilterPushdown::CheckMarkToSemi(LogicalOperator &op, unordered_set & auto &expr = proj.expressions.at(col_index); vector bindings_to_keep; ExpressionIterator::EnumerateExpression(expr, [&](Expression &child) { - if (child.GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { - auto &col_ref = child.Cast(); + if (expr->expression_class == ExpressionClass::BOUND_COLUMN_REF) { + auto &col_ref = expr->Cast(); bindings_to_keep.push_back(col_ref.binding); } }); @@ -106,8 +107,6 @@ unique_ptr FilterPushdown::Rewrite(unique_ptr return PushdownLimit(std::move(op)); case LogicalOperatorType::LOGICAL_WINDOW: return PushdownWindow(std::move(op)); - case LogicalOperatorType::LOGICAL_UNNEST: - return PushdownUnnest(std::move(op)); default: return FinishPushdown(std::move(op)); } @@ -122,7 +121,7 @@ unique_ptr FilterPushdown::PushdownJoin(unique_ptrtype == LogicalOperatorType::LOGICAL_ASOF_JOIN || op->type == LogicalOperatorType::LOGICAL_ANY_JOIN || op->type == LogicalOperatorType::LOGICAL_DELIM_JOIN); auto &join = op->Cast(); - if (join.HasProjectionMap()) { + if (!join.left_projection_map.empty() || !join.right_projection_map.empty()) { // cannot push down further otherwise the projection maps won't be preserved return FinishPushdown(std::move(op)); } diff --git a/src/duckdb/src/optimizer/in_clause_rewriter.cpp b/src/duckdb/src/optimizer/in_clause_rewriter.cpp index 62f34c1a9..880964f5f 100644 --- a/src/duckdb/src/optimizer/in_clause_rewriter.cpp +++ b/src/duckdb/src/optimizer/in_clause_rewriter.cpp @@ -6,24 +6,22 @@ #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/operator/logical_column_data_get.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" -#include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/execution/expression_executor.hpp" namespace duckdb { unique_ptr InClauseRewriter::Rewrite(unique_ptr op) { - switch (op->type) { - case LogicalOperatorType::LOGICAL_PROJECTION: - case LogicalOperatorType::LOGICAL_FILTER: { - current_op = op.get(); + if (op->children.size() == 1) { + if (op->children[0]->type == LogicalOperatorType::LOGICAL_GET) { + auto &get = op->children[0]->Cast(); + if (get.function.to_string && get.function.to_string(get.bind_data.get()) == "REMOTE") { + return op; + } + } root = std::move(op->children[0]); VisitOperatorExpressions(*op); op->children[0] = std::move(root); - break; - } - default: - break; } for (auto &child : op->children) { @@ -33,13 +31,12 @@ unique_ptr InClauseRewriter::Rewrite(unique_ptr InClauseRewriter::VisitReplace(BoundOperatorExpression &expr, unique_ptr *expr_ptr) { - if (expr.GetExpressionType() != ExpressionType::COMPARE_IN && - expr.GetExpressionType() != ExpressionType::COMPARE_NOT_IN) { + if (expr.type != ExpressionType::COMPARE_IN && expr.type != ExpressionType::COMPARE_NOT_IN) { return nullptr; } D_ASSERT(root); auto in_type = expr.children[0]->return_type; - bool is_regular_in = expr.GetExpressionType() == ExpressionType::COMPARE_IN; + bool is_regular_in = expr.type == ExpressionType::COMPARE_IN; bool all_scalar = true; // IN clause with many children: try to generate a mark join that replaces this IN expression // we can only do this if the expressions in the expression list are scalar @@ -114,19 +111,6 @@ unique_ptr InClauseRewriter::VisitReplace(BoundOperatorExpression &e join->conditions.push_back(std::move(cond)); root = std::move(join); - if (current_op->type == LogicalOperatorType::LOGICAL_FILTER) { - // project out the mark index again - auto &filter = current_op->Cast(); - if (filter.projection_map.empty()) { - auto child_bindings = root->GetColumnBindings(); - for (idx_t i = 0; i < child_bindings.size(); i++) { - if (child_bindings[i].table_index != chunk_index) { - filter.projection_map.push_back(i); - } - } - } - } - // we replace the original subquery with a BoundColumnRefExpression referring to the mark column unique_ptr result = make_uniq("IN (...)", LogicalType::BOOLEAN, ColumnBinding(chunk_index, 0)); diff --git a/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp b/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp index 6187d3f8d..60b8c83af 100644 --- a/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp +++ b/src/duckdb/src/optimizer/join_filter_pushdown_optimizer.cpp @@ -1,151 +1,20 @@ #include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" - -#include "duckdb/execution/operator/join/join_filter_pushdown.hpp" -#include "duckdb/execution/operator/join/physical_comparison_join.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" -#include "duckdb/function/function_binder.hpp" -#include "duckdb/optimizer/optimizer.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" -#include "duckdb/planner/operator/logical_aggregate.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_projection.hpp" -#include "duckdb/planner/operator/logical_set_operation.hpp" -#include "duckdb/planner/operator/logical_unnest.hpp" +#include "duckdb/execution/operator/join/join_filter_pushdown.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/optimizer/optimizer.hpp" +#include "duckdb/function/function_binder.hpp" +#include "duckdb/execution/operator/join/physical_comparison_join.hpp" +#include "duckdb/planner/expression/bound_aggregate_expression.hpp" namespace duckdb { JoinFilterPushdownOptimizer::JoinFilterPushdownOptimizer(Optimizer &optimizer) : optimizer(optimizer) { } -bool PushdownJoinFilterExpression(Expression &expr, JoinFilterPushdownColumn &filter) { - if (expr.GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { - // not a simple column ref - bail-out - return false; - } - // column-ref - pass through the new column binding - auto &colref = expr.Cast(); - filter.probe_column_index = colref.binding; - return true; -} - -void JoinFilterPushdownOptimizer::GetPushdownFilterTargets(LogicalOperator &op, - vector columns, - vector &targets) { - auto &probe_child = op; - switch (probe_child.type) { - case LogicalOperatorType::LOGICAL_LIMIT: - case LogicalOperatorType::LOGICAL_FILTER: - case LogicalOperatorType::LOGICAL_ORDER_BY: - case LogicalOperatorType::LOGICAL_TOP_N: - case LogicalOperatorType::LOGICAL_DISTINCT: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: - // does not affect probe side - recurse into left child - // FIXME: we can probably recurse into more operators here (e.g. window, unnest) - GetPushdownFilterTargets(*probe_child.children[0], std::move(columns), targets); - break; - case LogicalOperatorType::LOGICAL_UNNEST: { - auto &unnest = probe_child.Cast(); - // check if the filters apply to the unnest index - for (auto &filter : columns) { - if (filter.probe_column_index.table_index == unnest.unnest_index) { - // the filter applies to the unnest index - bail out - return; - } - } - GetPushdownFilterTargets(*probe_child.children[0], std::move(columns), targets); - break; - } - case LogicalOperatorType::LOGICAL_EXCEPT: - case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_UNION: { - auto &setop = probe_child.Cast(); - // union - // check if the filters apply to this table index - for (auto &filter : columns) { - if (filter.probe_column_index.table_index != setop.table_index) { - // the filter does not apply to the union - bail-out - return; - } - } - for (auto &child : probe_child.children) { - // rewrite the filters for each of the children of the union - vector child_columns; - auto child_bindings = child->GetColumnBindings(); - child_columns.reserve(columns.size()); - for (auto &child_column : columns) { - JoinFilterPushdownColumn new_col; - new_col.probe_column_index = child_bindings[child_column.probe_column_index.column_index]; - child_columns.push_back(new_col); - } - // then recurse into the child - GetPushdownFilterTargets(*child, std::move(child_columns), targets); - - // for EXCEPT we can only recurse into the first (left) child - if (probe_child.type == LogicalOperatorType::LOGICAL_EXCEPT) { - break; - } - } - break; - } - case LogicalOperatorType::LOGICAL_GET: { - // found LogicalGet - auto &get = probe_child.Cast(); - if (!get.function.filter_pushdown) { - // filter pushdown is not supported - no need to consider this node - return; - } - for (auto &filter : columns) { - if (filter.probe_column_index.table_index != get.table_index) { - // the filter does not apply to the probe side here - bail-out - return; - } - } - targets.emplace_back(get, std::move(columns)); - break; - } - case LogicalOperatorType::LOGICAL_PROJECTION: { - // projection - check if we all of the expressions are only column references - auto &proj = probe_child.Cast(); - for (auto &filter : columns) { - if (filter.probe_column_index.table_index != proj.table_index) { - // index does not belong to this projection - bail-out - return; - } - auto &expr = *proj.expressions[filter.probe_column_index.column_index]; - if (!PushdownJoinFilterExpression(expr, filter)) { - // cannot push through this expression - bail-out - return; - } - } - GetPushdownFilterTargets(*probe_child.children[0], std::move(columns), targets); - break; - } - case LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY: { - // we can push filters through aggregates IF they all point to groups - auto &aggr = probe_child.Cast(); - for (auto &filter : columns) { - if (filter.probe_column_index.table_index != aggr.group_index) { - // index does not refer to a group - bail-out - return; - } - auto &expr = *aggr.groups[filter.probe_column_index.column_index]; - if (!PushdownJoinFilterExpression(expr, filter)) { - // cannot push through this expression - bail-out - return; - } - } - GetPushdownFilterTargets(*probe_child.children[0], std::move(columns), targets); - break; - } - default: - // unsupported child type - break; - } -} - void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &join) { switch (join.join_type) { case JoinType::MARK: @@ -166,15 +35,13 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi // re-order conditions here - otherwise this will happen later on and invalidate the indexes we generate PhysicalComparisonJoin::ReorderConditions(join.conditions); auto pushdown_info = make_uniq(); - - vector pushdown_columns; for (idx_t cond_idx = 0; cond_idx < join.conditions.size(); cond_idx++) { auto &cond = join.conditions[cond_idx]; if (cond.comparison != ExpressionType::COMPARE_EQUAL) { // only equality supported for now continue; } - if (cond.left->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (cond.left->type != ExpressionType::BOUND_COLUMN_REF) { // only bound column ref supported for now continue; } @@ -187,51 +54,80 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi continue; } JoinFilterPushdownColumn pushdown_col; + pushdown_col.join_condition = cond_idx; + auto &colref = cond.left->Cast(); pushdown_col.probe_column_index = colref.binding; - pushdown_columns.push_back(pushdown_col); - - pushdown_info->join_condition.push_back(cond_idx); + pushdown_info->filters.push_back(pushdown_col); } - if (pushdown_columns.empty()) { + if (pushdown_info->filters.empty()) { // could not generate any filters - bail-out return; } - // recurse the query tree to find the LogicalGets in which we can push the filter info - vector pushdown_filter_targets; - GetPushdownFilterTargets(*join.children[0], pushdown_columns, pushdown_filter_targets); - for (auto &target : pushdown_filter_targets) { - auto &get = target.get; - // pushdown info can be applied to this LogicalGet - push the dynamic table filter set - if (!get.dynamic_filters) { - get.dynamic_filters = make_shared_ptr(); + // find the child LogicalGet (if possible) + reference probe_source(*join.children[0]); + while (probe_source.get().type != LogicalOperatorType::LOGICAL_GET) { + auto &probe_child = probe_source.get(); + switch (probe_child.type) { + case LogicalOperatorType::LOGICAL_LIMIT: + case LogicalOperatorType::LOGICAL_FILTER: + case LogicalOperatorType::LOGICAL_ORDER_BY: + case LogicalOperatorType::LOGICAL_TOP_N: + case LogicalOperatorType::LOGICAL_DISTINCT: + case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: + case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: + // does not affect probe side - continue into left child + // FIXME: we can probably recurse into more operators here (e.g. window, set operation, unnest) + probe_source = *probe_child.children[0]; + break; + case LogicalOperatorType::LOGICAL_PROJECTION: { + // projection - check if we all of the expressions are only column references + auto &proj = probe_source.get().Cast(); + for (auto &filter : pushdown_info->filters) { + if (filter.probe_column_index.table_index != proj.table_index) { + // index does not belong to this projection - bail-out + return; + } + auto &expr = *proj.expressions[filter.probe_column_index.column_index]; + if (expr.type != ExpressionType::BOUND_COLUMN_REF) { + // not a simple column ref - bail-out + return; + } + // column-ref - pass through the new column binding + auto &colref = expr.Cast(); + filter.probe_column_index = colref.binding; + } + probe_source = *probe_child.children[0]; + break; + } + default: + // unsupported child type + return; } - - JoinFilterPushdownFilter get_filter; - get_filter.dynamic_filters = get.dynamic_filters; - get_filter.columns = std::move(target.columns); - pushdown_info->probe_info.push_back(std::move(get_filter)); } - - // Even if we cannot find any table sources in which we can push down filters, - // we still initialize the aggregate states so that we have the possibility of doing a perfect hash join - const auto compute_aggregates_anyway = join.join_type == JoinType::INNER && join.conditions.size() == 1 && - pushdown_info->join_condition.size() == 1 && - TypeIsIntegral(join.conditions[0].right->return_type.InternalType()); - if (pushdown_info->probe_info.empty() && !compute_aggregates_anyway) { - // no table sources found in which we can push down filters + // found the LogicalGet + auto &get = probe_source.get().Cast(); + if (!get.function.filter_pushdown) { + // filter pushdown is not supported - bail-out return; } + for (auto &filter : pushdown_info->filters) { + if (filter.probe_column_index.table_index != get.table_index) { + // the filter does not apply to the probe side here - bail-out + return; + } + } + // pushdown can be performed // set up the min/max aggregates for each of the filters vector aggr_functions; - aggr_functions.push_back(MinFunction::GetFunction()); - aggr_functions.push_back(MaxFunction::GetFunction()); - for (auto &join_condition : pushdown_info->join_condition) { + aggr_functions.push_back(MinFun::GetFunction()); + aggr_functions.push_back(MaxFun::GetFunction()); + for (auto &filter : pushdown_info->filters) { for (auto &aggr : aggr_functions) { FunctionBinder function_binder(optimizer.GetContext()); vector> aggr_children; - aggr_children.push_back(join.conditions[join_condition].right->Copy()); + aggr_children.push_back(join.conditions[filter.join_condition].right->Copy()); auto aggr_expr = function_binder.BindAggregateFunction(aggr, std::move(aggr_children), nullptr, AggregateType::NON_DISTINCT); if (aggr_expr->children.size() != 1) { @@ -241,6 +137,12 @@ void JoinFilterPushdownOptimizer::GenerateJoinFilters(LogicalComparisonJoin &joi pushdown_info->min_max_aggregates.push_back(std::move(aggr_expr)); } } + // set up the dynamic filters (if we don't have any yet) + if (!get.dynamic_filters) { + get.dynamic_filters = make_shared_ptr(); + } + pushdown_info->dynamic_filters = get.dynamic_filters; + // set up the filter pushdown in the join itself join.filter_pushdown = std::move(pushdown_info); } diff --git a/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp b/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp index 4b5e22ada..fb65c0baf 100644 --- a/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +++ b/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp @@ -219,15 +219,14 @@ double CardinalityEstimator::CalculateUpdatedDenom(Subgraph2Denominator left, Su bool set = false; ExpressionType comparison_type = ExpressionType::COMPARE_EQUAL; ExpressionIterator::EnumerateExpression(filter.filter_info->filter, [&](Expression &expr) { - if (expr.GetExpressionClass() == ExpressionClass::BOUND_COMPARISON) { - comparison_type = expr.GetExpressionType(); + if (expr.expression_class == ExpressionClass::BOUND_COMPARISON) { + comparison_type = expr.type; set = true; return; } }); if (!set) { - new_denom *= - filter.has_tdom_hll ? static_cast(filter.tdom_hll) : static_cast(filter.tdom_no_hll); + new_denom *= filter.has_tdom_hll ? (double)filter.tdom_hll : (double)filter.tdom_no_hll; // no comparison is taking place, so the denominator is just the product of the left and right return new_denom; } @@ -345,8 +344,8 @@ DenomInfo CardinalityEstimator::GetDenominator(JoinRelationSet &set) { &set_manager.Union(*subgraph_to_merge_into->relations, *subgraph_to_delete->relations); subgraph_to_merge_into->numerator_relations = &UpdateNumeratorRelations(*subgraph_to_merge_into, *subgraph_to_delete, edge); - subgraph_to_merge_into->denom = CalculateUpdatedDenom(*subgraph_to_merge_into, *subgraph_to_delete, edge); subgraph_to_delete->relations = nullptr; + subgraph_to_merge_into->denom = CalculateUpdatedDenom(*subgraph_to_merge_into, *subgraph_to_delete, edge); auto remove_start = std::remove_if(subgraphs.begin(), subgraphs.end(), [](Subgraph2Denominator &s) { return !s.relations; }); subgraphs.erase(remove_start, subgraphs.end()); diff --git a/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp b/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp index 04b396b97..014181b27 100644 --- a/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp +++ b/src/duckdb/src/optimizer/join_order/plan_enumerator.cpp @@ -472,9 +472,7 @@ void PlanEnumerator::InitLeafPlans() { void PlanEnumerator::SolveJoinOrder() { bool force_no_cross_product = query_graph_manager.context.config.force_no_cross_product; // first try to solve the join order exactly - if (query_graph_manager.relation_manager.NumRelations() >= THRESHOLD_TO_SWAP_TO_APPROXIMATE) { - SolveJoinOrderApproximately(); - } else if (!SolveJoinOrderExactly()) { + if (!SolveJoinOrderExactly()) { // otherwise, if that times out we resort to a greedy algorithm SolveJoinOrderApproximately(); } diff --git a/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp b/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp index 6850508a6..3a5214d2c 100644 --- a/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp +++ b/src/duckdb/src/optimizer/join_order/query_graph_manager.cpp @@ -36,7 +36,7 @@ bool QueryGraphManager::Build(JoinOrderOptimizer &optimizer, LogicalOperator &op } void QueryGraphManager::GetColumnBinding(Expression &expression, ColumnBinding &binding) { - if (expression.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression.type == ExpressionType::BOUND_COLUMN_REF) { // Here you have a filter on a single column in a table. Return a binding for the column // being filtered on so the filter estimator knows what HLL count to pull auto &colref = expression.Cast(); @@ -114,8 +114,8 @@ void QueryGraphManager::CreateHyperGraphEdges() { } } else if (filter->GetExpressionClass() == ExpressionClass::BOUND_CONJUNCTION) { auto &conjunction = filter->Cast(); - if (conjunction.GetExpressionType() == ExpressionType::CONJUNCTION_OR || - filter_info->join_type == JoinType::INNER || filter_info->join_type == JoinType::INVALID) { + if (conjunction.type == ExpressionType::CONJUNCTION_OR || filter_info->join_type == JoinType::INNER || + filter_info->join_type == JoinType::INVALID) { // Currently we do not interpret Conjunction expressions as INNER joins // for hyper graph edges. These are most likely OR conjunctions, and // will be pushed down into a join later in the optimizer. @@ -127,7 +127,7 @@ void QueryGraphManager::CreateHyperGraphEdges() { D_ASSERT(filter_info->right_set); D_ASSERT(filter_info->join_type == JoinType::SEMI || filter_info->join_type == JoinType::ANTI); for (auto &child_comp : conjunction.children) { - if (child_comp->GetExpressionClass() != ExpressionClass::BOUND_COMPARISON) { + if (child_comp->expression_class != ExpressionClass::BOUND_COMPARISON) { continue; } auto &comparison = child_comp->Cast(); @@ -226,7 +226,7 @@ static JoinCondition MaybeInvertConditions(unique_ptr condition, boo JoinCondition cond; cond.left = !invert ? std::move(comparison.left) : std::move(comparison.right); cond.right = !invert ? std::move(comparison.right) : std::move(comparison.left); - cond.comparison = condition->GetExpressionType(); + cond.comparison = condition->type; if (invert) { // reverse comparison expression if we reverse the order of the children cond.comparison = FlipComparisonExpression(cond.comparison); @@ -368,10 +368,10 @@ GenerateJoinRelation QueryGraphManager::GenerateJoins(vectorchildren[0], filter_operators, op); bool can_reorder_right = ExtractJoinRelations(optimizer, *op->children[1], filter_operators, op); + bool can_reorder_left = ExtractJoinRelations(optimizer, *op->children[0], filter_operators, op); return can_reorder_left && can_reorder_right; } case LogicalOperatorType::LOGICAL_DUMMY_SCAN: { @@ -446,12 +437,12 @@ bool RelationManager::ExtractJoinRelations(JoinOrderOptimizer &optimizer, Logica } bool RelationManager::ExtractBindings(Expression &expression, unordered_set &bindings) { - if (expression.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expression.Cast(); D_ASSERT(colref.depth == 0); D_ASSERT(colref.binding.table_index != DConstants::INVALID_INDEX); // map the base table index to the relation index used by the JoinOrderOptimizer - if (expression.GetAlias() == "SUBQUERY" && + if (expression.alias == "SUBQUERY" && relation_mapping.find(colref.binding.table_index) == relation_mapping.end()) { // most likely a BoundSubqueryExpression that was created from an uncorrelated subquery // Here we return true and don't fill the bindings, the expression can be reordered. @@ -463,12 +454,12 @@ bool RelationManager::ExtractBindings(Expression &expression, unordered_set(); @@ -79,15 +79,14 @@ RelationStats RelationStatisticsHelper::ExtractGetStats(LogicalGet &get, ClientC // first push back basic distinct counts for each column (if we have them). auto &column_ids = get.GetColumnIds(); for (idx_t i = 0; i < column_ids.size(); i++) { - auto column_id = column_ids[i].GetPrimaryIndex(); bool have_distinct_count_stats = false; if (get.function.statistics) { - column_statistics = get.function.statistics(context, get.bind_data.get(), column_id); + column_statistics = get.function.statistics(context, get.bind_data.get(), column_ids[i]); if (column_statistics && have_catalog_table_statistics) { - auto distinct_count = MaxValue(1, column_statistics->GetDistinctCount()); + auto distinct_count = MaxValue((idx_t)1, column_statistics->GetDistinctCount()); auto column_distinct_count = DistinctCount({distinct_count, true}); return_stats.column_distinct_count.push_back(column_distinct_count); - return_stats.column_names.push_back(name + "." + get.names.at(column_id)); + return_stats.column_names.push_back(name + "." + get.names.at(column_ids.at(i))); have_distinct_count_stats = true; } } @@ -98,8 +97,8 @@ RelationStats RelationStatisticsHelper::ExtractGetStats(LogicalGet &get, ClientC auto column_distinct_count = DistinctCount({cardinality_after_filters, false}); return_stats.column_distinct_count.push_back(column_distinct_count); auto column_name = string("column"); - if (column_id < get.names.size()) { - column_name = get.names.at(column_id); + if (column_ids.at(i) < get.names.size()) { + column_name = get.names.at(column_ids.at(i)); } return_stats.column_names.push_back(get.GetName() + "." + column_name); } @@ -107,26 +106,22 @@ RelationStats RelationStatisticsHelper::ExtractGetStats(LogicalGet &get, ClientC if (!get.table_filters.filters.empty()) { column_statistics = nullptr; - bool has_non_optional_filters = false; for (auto &it : get.table_filters.filters) { if (get.bind_data && get.function.statistics) { column_statistics = get.function.statistics(context, get.bind_data.get(), it.first); } - if (column_statistics) { - idx_t cardinality_with_filter = - InspectTableFilter(base_table_cardinality, it.first, *it.second, *column_statistics); - cardinality_after_filters = MinValue(cardinality_after_filters, cardinality_with_filter); - } - - if (it.second->filter_type != TableFilterType::OPTIONAL_FILTER) { - has_non_optional_filters = true; + if (column_statistics && it.second->filter_type == TableFilterType::CONJUNCTION_AND) { + auto &filter = it.second->Cast(); + idx_t cardinality_with_and_filter = RelationStatisticsHelper::InspectConjunctionAND( + base_table_cardinality, it.first, filter, *column_statistics); + cardinality_after_filters = MinValue(cardinality_after_filters, cardinality_with_and_filter); } } // if the above code didn't find an equality filter (i.e country_code = "[us]") // and there are other table filters (i.e cost > 50), use default selectivity. bool has_equality_filter = (cardinality_after_filters != base_table_cardinality); - if (!has_equality_filter && has_non_optional_filters) { + if (!has_equality_filter && !get.table_filters.filters.empty()) { cardinality_after_filters = MaxValue( LossyNumericCast(double(base_table_cardinality) * RelationStatisticsHelper::DEFAULT_SELECTIVITY), 1U); @@ -331,7 +326,7 @@ RelationStats RelationStatisticsHelper::ExtractAggregationStats(LogicalAggregate double new_card = -1; for (auto &g_set : aggr.grouping_sets) { for (auto &ind : g_set) { - if (aggr.groups[ind]->GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { + if (aggr.groups[ind]->expression_class != ExpressionClass::BOUND_COLUMN_REF) { continue; } auto bound_col = &aggr.groups[ind]->Cast(); @@ -354,8 +349,7 @@ RelationStats RelationStatisticsHelper::ExtractAggregationStats(LogicalAggregate // most likely we are running on parquet files. Therefore we divide by 2. new_card = (double)child_stats.cardinality / 2; } - // an ungrouped aggregate has 1 row - stats.cardinality = aggr.groups.empty() ? 1 : LossyNumericCast(new_card); + stats.cardinality = LossyNumericCast(new_card); stats.column_names = child_stats.column_names; stats.stats_initialized = true; auto num_child_columns = aggr.GetColumnBindings().size(); @@ -378,22 +372,16 @@ RelationStats RelationStatisticsHelper::ExtractEmptyResultStats(LogicalEmptyResu return stats; } -idx_t RelationStatisticsHelper::InspectTableFilter(idx_t cardinality, idx_t column_index, TableFilter &filter, - BaseStatistics &base_stats) { +idx_t RelationStatisticsHelper::InspectConjunctionAND(idx_t cardinality, idx_t column_index, + ConjunctionAndFilter &filter, BaseStatistics &base_stats) { auto cardinality_after_filters = cardinality; - switch (filter.filter_type) { - case TableFilterType::CONJUNCTION_AND: { - auto &and_filter = filter.Cast(); - for (auto &child_filter : and_filter.child_filters) { - cardinality_after_filters = MinValue( - cardinality_after_filters, InspectTableFilter(cardinality, column_index, *child_filter, base_stats)); + for (auto &child_filter : filter.child_filters) { + if (child_filter->filter_type != TableFilterType::CONSTANT_COMPARISON) { + continue; } - return cardinality_after_filters; - } - case TableFilterType::CONSTANT_COMPARISON: { - auto &comparison_filter = filter.Cast(); + auto &comparison_filter = child_filter->Cast(); if (comparison_filter.comparison_type != ExpressionType::COMPARE_EQUAL) { - return cardinality_after_filters; + continue; } auto column_count = base_stats.GetDistinctCount(); // column_count = 0 when there is no column count (i.e parquet scans) @@ -401,11 +389,8 @@ idx_t RelationStatisticsHelper::InspectTableFilter(idx_t cardinality, idx_t colu // we want the ceil of cardinality/column_count. We also want to avoid compiler errors cardinality_after_filters = (cardinality + column_count - 1) / column_count; } - return cardinality_after_filters; - } - default: - return cardinality_after_filters; } + return cardinality_after_filters; } // TODO: Currently only simple AND filters are pushed into table scans. diff --git a/src/duckdb/src/optimizer/limit_pushdown.cpp b/src/duckdb/src/optimizer/limit_pushdown.cpp index e47f00939..d6f2b66b6 100644 --- a/src/duckdb/src/optimizer/limit_pushdown.cpp +++ b/src/duckdb/src/optimizer/limit_pushdown.cpp @@ -30,7 +30,6 @@ unique_ptr LimitPushdown::Optimize(unique_ptr if (CanOptimize(*op)) { auto projection = std::move(op->children[0]); op->children[0] = std::move(projection->children[0]); - projection->SetEstimatedCardinality(op->estimated_cardinality); projection->children[0] = std::move(op); swap(projection, op); } diff --git a/src/duckdb/src/optimizer/matcher/expression_matcher.cpp b/src/duckdb/src/optimizer/matcher/expression_matcher.cpp index 499daa599..1d8ca93ca 100644 --- a/src/duckdb/src/optimizer/matcher/expression_matcher.cpp +++ b/src/duckdb/src/optimizer/matcher/expression_matcher.cpp @@ -8,7 +8,7 @@ bool ExpressionMatcher::Match(Expression &expr, vector> &b if (type && !type->Match(expr.return_type)) { return false; } - if (expr_type && !expr_type->Match(expr.GetExpressionType())) { + if (expr_type && !expr_type->Match(expr.type)) { return false; } if (expr_class != ExpressionClass::INVALID && expr_class != expr.GetExpressionClass()) { @@ -60,8 +60,7 @@ bool InClauseExpressionMatcher::Match(Expression &expr_p, vector(); - if (expr.GetExpressionType() != ExpressionType::COMPARE_IN || - expr.GetExpressionType() == ExpressionType::COMPARE_NOT_IN) { + if (expr.type != ExpressionType::COMPARE_IN || expr.type == ExpressionType::COMPARE_NOT_IN) { return false; } return SetMatcher::Match(matchers, expr.children, bindings, policy); @@ -92,24 +91,6 @@ bool FunctionExpressionMatcher::Match(Expression &expr_p, vector> &bindings) { - if (!ExpressionMatcher::Match(expr_p, bindings)) { - return false; - } - auto &expr = expr_p.Cast(); - if (!FunctionMatcher::Match(function, expr.function.name)) { - return false; - } - // we should create matchers for these in the future - if (expr.filter || expr.order_bys || expr.aggr_type != AggregateType::NON_DISTINCT) { - return false; - } - if (!SetMatcher::Match(matchers, expr.children, bindings, policy)) { - return false; - } - return true; -} - bool FoldableConstantMatcher::Match(Expression &expr, vector> &bindings) { // we match on ANY expression that is a scalar expression if (!expr.IsFoldable()) { @@ -119,13 +100,4 @@ bool FoldableConstantMatcher::Match(Expression &expr, vector> &bindings) { - // we match on ANY expression that is a stable expression - if (expr.IsVolatile()) { - return false; - } - bindings.push_back(expr); - return true; -} - } // namespace duckdb diff --git a/src/duckdb/src/optimizer/optimizer.cpp b/src/duckdb/src/optimizer/optimizer.cpp index d5c466211..9b5478ace 100644 --- a/src/duckdb/src/optimizer/optimizer.cpp +++ b/src/duckdb/src/optimizer/optimizer.cpp @@ -1,7 +1,6 @@ #include "duckdb/optimizer/optimizer.hpp" #include "duckdb/execution/column_binding_resolver.hpp" -#include "duckdb/function/function_binder.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/query_profiler.hpp" @@ -11,27 +10,23 @@ #include "duckdb/optimizer/cse_optimizer.hpp" #include "duckdb/optimizer/cte_filter_pusher.hpp" #include "duckdb/optimizer/deliminator.hpp" -#include "duckdb/optimizer/empty_result_pullup.hpp" #include "duckdb/optimizer/expression_heuristics.hpp" #include "duckdb/optimizer/filter_pullup.hpp" #include "duckdb/optimizer/filter_pushdown.hpp" #include "duckdb/optimizer/in_clause_rewriter.hpp" -#include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" #include "duckdb/optimizer/join_order/join_order_optimizer.hpp" #include "duckdb/optimizer/limit_pushdown.hpp" #include "duckdb/optimizer/regex_range_filter.hpp" #include "duckdb/optimizer/remove_duplicate_groups.hpp" #include "duckdb/optimizer/remove_unused_columns.hpp" -#include "duckdb/optimizer/rule/distinct_aggregate_optimizer.hpp" #include "duckdb/optimizer/rule/equal_or_null_simplification.hpp" #include "duckdb/optimizer/rule/in_clause_simplification.hpp" #include "duckdb/optimizer/rule/join_dependent_filter.hpp" #include "duckdb/optimizer/rule/list.hpp" -#include "duckdb/optimizer/sampling_pushdown.hpp" #include "duckdb/optimizer/statistics_propagator.hpp" -#include "duckdb/optimizer/sum_rewriter.hpp" #include "duckdb/optimizer/topn_optimizer.hpp" #include "duckdb/optimizer/unnest_rewriter.hpp" +#include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/planner.hpp" @@ -50,8 +45,6 @@ Optimizer::Optimizer(Binder &binder, ClientContext &context) : context(context), rewriter.rules.push_back(make_uniq(rewriter)); rewriter.rules.push_back(make_uniq(rewriter)); rewriter.rules.push_back(make_uniq(rewriter)); - rewriter.rules.push_back(make_uniq(rewriter)); - rewriter.rules.push_back(make_uniq(rewriter)); rewriter.rules.push_back(make_uniq(rewriter)); rewriter.rules.push_back(make_uniq(rewriter)); rewriter.rules.push_back(make_uniq(rewriter)); @@ -71,11 +64,7 @@ ClientContext &Optimizer::GetContext() { } bool Optimizer::OptimizerDisabled(OptimizerType type) { - return OptimizerDisabled(context, type); -} - -bool Optimizer::OptimizerDisabled(ClientContext &context_p, OptimizerType type) { - auto &config = DBConfig::GetConfig(context_p); + auto &config = DBConfig::GetConfig(context); return config.options.disabled_optimizers.find(type) != config.options.disabled_optimizers.end(); } @@ -117,12 +106,6 @@ void Optimizer::RunBuiltInOptimizers() { // this does not change the logical plan structure, but only simplifies the expression trees RunOptimizer(OptimizerType::EXPRESSION_REWRITER, [&]() { rewriter.VisitOperator(*plan); }); - // transform ORDER BY + LIMIT to TopN - RunOptimizer(OptimizerType::SUM_REWRITER, [&]() { - SumRewriterOptimizer optimizer(*this); - optimizer.Optimize(plan); - }); - // perform filter pullup RunOptimizer(OptimizerType::FILTER_PULLUP, [&]() { FilterPullup filter_pullup; @@ -159,12 +142,6 @@ void Optimizer::RunBuiltInOptimizers() { plan = deliminator.Optimize(std::move(plan)); }); - // Pulls up empty results - RunOptimizer(OptimizerType::EMPTY_RESULT_PULLUP, [&]() { - EmptyResultPullup empty_result_pullup; - plan = empty_result_pullup.Optimize(std::move(plan)); - }); - // then we perform the join ordering optimization // this also rewrites cross products + filters into joins and performs filter pushdowns RunOptimizer(OptimizerType::JOIN_ORDER, [&]() { @@ -196,12 +173,6 @@ void Optimizer::RunBuiltInOptimizers() { cse_optimizer.VisitOperator(*plan); }); - // creates projection maps so unused columns are projected out early - RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { - ColumnLifetimeAnalyzer column_lifetime(*this, *plan, true); - column_lifetime.VisitOperator(*plan); - }); - // Once we know the column lifetime, we have more information regarding // what relations should be the build side/probe side. RunOptimizer(OptimizerType::BUILD_SIDE_PROBE_SIDE, [&]() { @@ -215,18 +186,18 @@ void Optimizer::RunBuiltInOptimizers() { plan = limit_pushdown.Optimize(std::move(plan)); }); - // perform sampling pushdown - RunOptimizer(OptimizerType::SAMPLING_PUSHDOWN, [&]() { - SamplingPushdown sampling_pushdown; - plan = sampling_pushdown.Optimize(std::move(plan)); - }); - // transform ORDER BY + LIMIT to TopN RunOptimizer(OptimizerType::TOP_N, [&]() { TopN topn; plan = topn.Optimize(std::move(plan)); }); + // creates projection maps so unused columns are projected out early + RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { + ColumnLifetimeAnalyzer column_lifetime(true); + column_lifetime.VisitOperator(*plan); + }); + // perform statistics propagation column_binding_map_t> statistics_map; RunOptimizer(OptimizerType::STATISTICS_PROPAGATION, [&]() { @@ -243,7 +214,7 @@ void Optimizer::RunBuiltInOptimizers() { // creates projection maps so unused columns are projected out early RunOptimizer(OptimizerType::COLUMN_LIFETIME, [&]() { - ColumnLifetimeAnalyzer column_lifetime(*this, *plan, true); + ColumnLifetimeAnalyzer column_lifetime(true); column_lifetime.VisitOperator(*plan); }); @@ -279,28 +250,4 @@ unique_ptr Optimizer::Optimize(unique_ptr plan return std::move(plan); } -unique_ptr Optimizer::BindScalarFunction(const string &name, unique_ptr c1) { - vector> children; - children.push_back(std::move(c1)); - return BindScalarFunction(name, std::move(children)); -} - -unique_ptr Optimizer::BindScalarFunction(const string &name, unique_ptr c1, - unique_ptr c2) { - vector> children; - children.push_back(std::move(c1)); - children.push_back(std::move(c2)); - return BindScalarFunction(name, std::move(children)); -} - -unique_ptr Optimizer::BindScalarFunction(const string &name, vector> children) { - FunctionBinder binder(context); - ErrorData error; - auto expr = binder.BindScalarFunction(DEFAULT_SCHEMA, name, std::move(children), error); - if (error.HasError()) { - throw InternalException("Optimizer exception - failed to bind function %s: %s", name, error.Message()); - } - return expr; -} - } // namespace duckdb diff --git a/src/duckdb/src/optimizer/pullup/pullup_filter.cpp b/src/duckdb/src/optimizer/pullup/pullup_filter.cpp index 95fd7f7bb..96395a97c 100644 --- a/src/duckdb/src/optimizer/pullup/pullup_filter.cpp +++ b/src/duckdb/src/optimizer/pullup/pullup_filter.cpp @@ -1,8 +1,8 @@ #include "duckdb/optimizer/filter_pullup.hpp" -#include "duckdb/planner/expression/bound_between_expression.hpp" +#include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression_iterator.hpp" -#include "duckdb/planner/operator/logical_filter.hpp" +#include "duckdb/planner/expression/bound_between_expression.hpp" namespace duckdb { @@ -10,7 +10,7 @@ unique_ptr FilterPullup::PullupFilter(unique_ptrtype == LogicalOperatorType::LOGICAL_FILTER); auto &filter = op->Cast(); - if (can_pullup && !filter.HasProjectionMap()) { + if (can_pullup && filter.projection_map.empty()) { unique_ptr child = std::move(op->children[0]); child = Rewrite(std::move(child)); // moving filter's expressions diff --git a/src/duckdb/src/optimizer/pullup/pullup_projection.cpp b/src/duckdb/src/optimizer/pullup/pullup_projection.cpp index 0149fbcf2..f2fd71b70 100644 --- a/src/duckdb/src/optimizer/pullup/pullup_projection.cpp +++ b/src/duckdb/src/optimizer/pullup/pullup_projection.cpp @@ -19,13 +19,13 @@ static void RevertFilterPullup(LogicalProjection &proj, vector> &proj_expressions, Expression &expr, idx_t proj_table_idx) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { bool found_proj_col = false; BoundColumnRefExpression &colref = expr.Cast(); // find the corresponding column index in the projection expressions for (idx_t proj_idx = 0; proj_idx < proj_expressions.size(); proj_idx++) { auto &proj_expr = *proj_expressions[proj_idx]; - if (proj_expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (proj_expr.type == ExpressionType::BOUND_COLUMN_REF) { if (colref.Equals(proj_expr)) { colref.binding.table_index = proj_table_idx; colref.binding.column_index = proj_idx; diff --git a/src/duckdb/src/optimizer/pullup/pullup_set_operation.cpp b/src/duckdb/src/optimizer/pullup/pullup_set_operation.cpp index 00f642ca0..8d7b3c1d9 100644 --- a/src/duckdb/src/optimizer/pullup/pullup_set_operation.cpp +++ b/src/duckdb/src/optimizer/pullup/pullup_set_operation.cpp @@ -6,7 +6,7 @@ namespace duckdb { static void ReplaceFilterTableIndex(Expression &expr, LogicalSetOperation &setop) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(colref.depth == 0); diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp index eb5f803b6..bd664a26e 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_aggregate.cpp @@ -10,7 +10,7 @@ namespace duckdb { using Filter = FilterPushdown::Filter; static unique_ptr ReplaceGroupBindings(LogicalAggregate &proj, unique_ptr expr) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr->Cast(); D_ASSERT(colref.binding.table_index == proj.group_index); D_ASSERT(colref.binding.column_index < proj.groups.size()); @@ -24,7 +24,7 @@ static unique_ptr ReplaceGroupBindings(LogicalAggregate &proj, uniqu } void FilterPushdown::ExtractFilterBindings(Expression &expr, vector &bindings) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr.Cast(); bindings.push_back(colref.binding); } diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp index fdf6fbe6e..9f3a6b5a3 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_filter.cpp @@ -9,7 +9,7 @@ using Filter = FilterPushdown::Filter; unique_ptr FilterPushdown::PushdownFilter(unique_ptr op) { D_ASSERT(op->type == LogicalOperatorType::LOGICAL_FILTER); auto &filter = op->Cast(); - if (filter.HasProjectionMap()) { + if (!filter.projection_map.empty()) { return FinishPushdown(std::move(op)); } // filter: gather the filters and remove the filter from the set of operations diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp index 814adadc0..e142a1d71 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_left_join.cpp @@ -13,7 +13,7 @@ namespace duckdb { using Filter = FilterPushdown::Filter; static unique_ptr ReplaceColRefWithNull(unique_ptr expr, unordered_set &right_bindings) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_colref = expr->Cast(); if (right_bindings.find(bound_colref.binding.table_index) != right_bindings.end()) { // bound colref belongs to RHS diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp index 8958bb88a..172d84147 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_mark_join.cpp @@ -36,7 +36,7 @@ unique_ptr FilterPushdown::PushdownMarkJoin(unique_ptrfilter->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF && convert_mark_joins && + if (filters[i]->filter->type == ExpressionType::BOUND_COLUMN_REF && convert_mark_joins && comp_join.convert_mark_to_semi) { // filter just references the marker: turn into semi join #ifdef DEBUG @@ -51,9 +51,9 @@ unique_ptr FilterPushdown::PushdownMarkJoin(unique_ptrfilter->GetExpressionType() == ExpressionType::OPERATOR_NOT) { + if (filters[i]->filter->type == ExpressionType::OPERATOR_NOT) { auto &op_expr = filters[i]->filter->Cast(); - if (op_expr.children[0]->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (op_expr.children[0]->type == ExpressionType::BOUND_COLUMN_REF) { // the filter is NOT(marker), check the join conditions bool all_null_values_are_equal = true; for (auto &cond : comp_join.conditions) { diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp index b10b60ae4..ec82b39cd 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_projection.cpp @@ -3,13 +3,11 @@ #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_empty_result.hpp" #include "duckdb/planner/operator/logical_projection.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/common/types.hpp" namespace duckdb { static bool IsVolatile(LogicalProjection &proj, const unique_ptr &expr) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr->Cast(); D_ASSERT(colref.binding.table_index == proj.table_index); D_ASSERT(colref.binding.column_index < proj.expressions.size()); @@ -26,7 +24,7 @@ static bool IsVolatile(LogicalProjection &proj, const unique_ptr &ex } static unique_ptr ReplaceProjectionBindings(LogicalProjection &proj, unique_ptr expr) { - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr->Cast(); D_ASSERT(colref.binding.table_index == proj.table_index); D_ASSERT(colref.binding.column_index < proj.expressions.size()); @@ -53,7 +51,7 @@ unique_ptr FilterPushdown::PushdownProjection(unique_ptrCanThrow()) { + if (is_volatile) { // We can't push down related expressions if the column in the // expression is generated by the functions which have side effects remain_expressions.push_back(std::move(f.filter)); diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_set_operation.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_set_operation.cpp index 64f9fe18a..5d3dce97e 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_set_operation.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_set_operation.cpp @@ -13,7 +13,7 @@ using Filter = FilterPushdown::Filter; static void ReplaceSetOpBindings(vector &bindings, Filter &filter, Expression &expr, LogicalSetOperation &setop) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(colref.binding.table_index == setop.table_index); D_ASSERT(colref.depth == 0); diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp deleted file mode 100644 index 9bdeb2567..000000000 --- a/src/duckdb/src/optimizer/pushdown/pushdown_unnest.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "duckdb/optimizer/filter_pushdown.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" -#include "duckdb/planner/expression_iterator.hpp" -#include "duckdb/planner/operator/logical_empty_result.hpp" -#include "duckdb/planner/operator/logical_unnest.hpp" - -namespace duckdb { - -unique_ptr FilterPushdown::PushdownUnnest(unique_ptr op) { - D_ASSERT(op->type == LogicalOperatorType::LOGICAL_UNNEST); - auto &unnest = op->Cast(); - // push filter through logical projection - // all the BoundColumnRefExpressions in the filter should refer to the LogicalProjection - // we can rewrite them by replacing those references with the expression of the LogicalProjection node - FilterPushdown child_pushdown(optimizer, convert_mark_joins); - // There are some expressions can not be pushed down. We should keep them - // and add an extra filter operator. - vector> remain_expressions; - for (auto &filter : filters) { - auto &f = *filter; - auto can_push = true; - for (auto &binding : f.bindings) { - if (binding == unnest.unnest_index) { - can_push = false; - break; - } - } - // if the expression index table index is the unnest index, then the filter is on the - // unnest, and it should not be pushed down. - if (!can_push) { - // We can't push down related expressions if the column in the - // expression is generated by the functions which have side effects - remain_expressions.push_back(std::move(f.filter)); - } else { - // add the filter to the child pushdown - if (child_pushdown.AddFilter(std::move(f.filter)) == FilterResult::UNSATISFIABLE) { - // filter statically evaluates to false, strip tree - return make_uniq(std::move(op)); - } - } - } - child_pushdown.GenerateFilters(); - // now push into children - op->children[0] = child_pushdown.Rewrite(std::move(op->children[0])); - if (op->children[0]->type == LogicalOperatorType::LOGICAL_EMPTY_RESULT) { - // child returns an empty result: generate an empty result here too - return make_uniq(std::move(op)); - } - return AddLogicalFilter(std::move(op), std::move(remain_expressions)); -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/pushdown/pushdown_window.cpp b/src/duckdb/src/optimizer/pushdown/pushdown_window.cpp index a193b1e93..5b02983e8 100644 --- a/src/duckdb/src/optimizer/pushdown/pushdown_window.cpp +++ b/src/duckdb/src/optimizer/pushdown/pushdown_window.cpp @@ -39,7 +39,7 @@ unique_ptr FilterPushdown::PushdownWindow(unique_ptr window_exprs_partition_bindings; for (auto &expr : window.expressions) { - if (expr->GetExpressionClass() != ExpressionClass::BOUND_WINDOW) { + if (expr->expression_class != ExpressionClass::BOUND_WINDOW) { continue; } auto &window_expr = expr->Cast(); @@ -53,7 +53,7 @@ unique_ptr FilterPushdown::PushdownWindow(unique_ptrGetExpressionType()) { + switch (partition_expr->type) { // TODO: Add expressions for function expressions like FLOOR, CEIL etc. case ExpressionType::BOUND_COLUMN_REF: { auto &partition_col = partition_expr->Cast(); diff --git a/src/duckdb/src/optimizer/regex_range_filter.cpp b/src/duckdb/src/optimizer/regex_range_filter.cpp index fd9f98fe6..19d0e059e 100644 --- a/src/duckdb/src/optimizer/regex_range_filter.cpp +++ b/src/duckdb/src/optimizer/regex_range_filter.cpp @@ -28,7 +28,7 @@ unique_ptr RegexRangeFilter::Rewrite(unique_ptr(); for (auto &expr : op->expressions) { - if (expr->GetExpressionType() == ExpressionType::BOUND_FUNCTION) { + if (expr->type == ExpressionType::BOUND_FUNCTION) { auto &func = expr->Cast(); if (func.function.name != "regexp_full_match" || func.children.size() != 2) { continue; diff --git a/src/duckdb/src/optimizer/remove_duplicate_groups.cpp b/src/duckdb/src/optimizer/remove_duplicate_groups.cpp index dd09c2f3d..3ab3dca6c 100644 --- a/src/duckdb/src/optimizer/remove_duplicate_groups.cpp +++ b/src/duckdb/src/optimizer/remove_duplicate_groups.cpp @@ -29,7 +29,7 @@ void RemoveDuplicateGroups::VisitAggregate(LogicalAggregate &aggr) { vector> duplicates; for (idx_t group_idx = 0; group_idx < groups.size(); group_idx++) { const auto &group = groups[group_idx]; - if (group->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (group->type != ExpressionType::BOUND_COLUMN_REF) { continue; } const auto &colref = group->Cast(); diff --git a/src/duckdb/src/optimizer/remove_unused_columns.cpp b/src/duckdb/src/optimizer/remove_unused_columns.cpp index 3a867bdf2..8425050b1 100644 --- a/src/duckdb/src/optimizer/remove_unused_columns.cpp +++ b/src/duckdb/src/optimizer/remove_unused_columns.cpp @@ -8,7 +8,6 @@ #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression_iterator.hpp" #include "duckdb/planner/operator/logical_aggregate.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" @@ -19,17 +18,15 @@ #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/operator/logical_set_operation.hpp" #include "duckdb/planner/operator/logical_simple.hpp" -#include "duckdb/function/scalar/struct_utils.hpp" namespace duckdb { void RemoveUnusedColumns::ReplaceBinding(ColumnBinding current_binding, ColumnBinding new_binding) { auto colrefs = column_references.find(current_binding); if (colrefs != column_references.end()) { - for (auto &colref_p : colrefs->second.bindings) { - auto &colref = colref_p.get(); - D_ASSERT(colref.binding == current_binding); - colref.binding = new_binding; + for (auto &colref : colrefs->second) { + D_ASSERT(colref->binding == current_binding); + colref->binding = new_binding; } } } @@ -89,8 +86,8 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { // this reduces the amount of columns we need to extract from the join hash table for (auto &cond : comp_join.conditions) { if (cond.comparison == ExpressionType::COMPARE_EQUAL) { - if (cond.left->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF && - cond.right->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + if (cond.left->expression_class == ExpressionClass::BOUND_COLUMN_REF && + cond.right->expression_class == ExpressionClass::BOUND_COLUMN_REF) { // comparison join between two bound column refs // we can replace any reference to the RHS (build-side) with a reference to the LHS (probe-side) auto &lhs_col = cond.left->Cast(); @@ -98,10 +95,9 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { // if there are any columns that refer to the RHS, auto colrefs = column_references.find(rhs_col.binding); if (colrefs != column_references.end()) { - for (auto &entry : colrefs->second.bindings) { - auto &colref = entry.get(); - colref.binding = lhs_col.binding; - AddBinding(colref); + for (auto &entry : colrefs->second) { + entry->binding = lhs_col.binding; + column_references[lhs_col.binding].push_back(entry); } column_references.erase(rhs_col.binding); } @@ -213,7 +209,7 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { return; } - auto final_column_ids = get.GetColumnIds(); + auto &final_column_ids = get.GetColumnIds(); // Create "selection vector" of all column ids vector proj_sel; @@ -225,13 +221,12 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { // Clear unused ids, exclude filter columns that are projected out immediately ClearUnusedExpressions(proj_sel, get.table_index, false); - vector> filter_expressions; // for every table filter, push a column binding into the column references map to prevent the column from // being projected out for (auto &filter : get.table_filters.filters) { optional_idx index; for (idx_t i = 0; i < final_column_ids.size(); i++) { - if (final_column_ids[i].GetPrimaryIndex() == filter.first) { + if (final_column_ids[i] == filter.first) { index = i; break; } @@ -239,39 +234,20 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { if (!index.IsValid()) { throw InternalException("Could not find column index for table filter"); } - - auto column_type = - filter.first == COLUMN_IDENTIFIER_ROW_ID ? LogicalType::ROW_TYPE : get.returned_types[filter.first]; - ColumnBinding filter_binding(get.table_index, index.GetIndex()); - auto column_ref = make_uniq(std::move(column_type), filter_binding); - auto filter_expr = filter.second->ToExpression(*column_ref); - VisitExpression(&filter_expr); - filter_expressions.push_back(std::move(filter_expr)); + if (column_references.find(filter_binding) == column_references.end()) { + column_references.insert(make_pair(filter_binding, vector())); + } } // Clear unused ids, include filter columns that are projected out immediately ClearUnusedExpressions(col_sel, get.table_index); // Now set the column ids in the LogicalGet using the "selection vector" - vector column_ids; + vector column_ids; column_ids.reserve(col_sel.size()); for (auto col_sel_idx : col_sel) { - auto entry = column_references.find(ColumnBinding(get.table_index, col_sel_idx)); - if (entry == column_references.end()) { - throw InternalException("RemoveUnusedColumns - could not find referenced column"); - } - if (final_column_ids[col_sel_idx].HasChildren()) { - throw InternalException("RemoveUnusedColumns - LogicalGet::column_ids already has children"); - } - ColumnIndex new_index(final_column_ids[col_sel_idx].GetPrimaryIndex(), entry->second.child_columns); - column_ids.emplace_back(new_index); - } - if (column_ids.empty()) { - // this generally means we are only interested in whether or not anything exists in the table (e.g. - // EXISTS(SELECT * FROM tbl)) in this case, we just scan the row identifier column as it means we do not - // need to read any of the columns - column_ids.emplace_back(COLUMN_IDENTIFIER_ROW_ID); + column_ids.push_back(final_column_ids[col_sel_idx]); } get.SetColumnIds(std::move(column_ids)); @@ -288,8 +264,24 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { } } } + + if (final_column_ids.empty()) { + // this generally means we are only interested in whether or not anything exists in the table (e.g. + // EXISTS(SELECT * FROM tbl)) in this case, we just scan the row identifier column as it means we do not + // need to read any of the columns + get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); + } } return; + case LogicalOperatorType::LOGICAL_FILTER: { + auto &filter = op.Cast(); + if (!filter.projection_map.empty()) { + // if we have any entries in the filter projection map don't prune any columns + // FIXME: we can do something more clever here + everything_referenced = true; + } + break; + } case LogicalOperatorType::LOGICAL_DISTINCT: { auto &distinct = op.Cast(); if (distinct.distinct_type == DistinctType::DISTINCT_ON) { @@ -347,131 +339,10 @@ void RemoveUnusedColumns::VisitOperator(LogicalOperator &op) { } } -bool RemoveUnusedColumns::HandleStructExtractRecursive(Expression &expr, optional_ptr &colref, - vector &indexes) { - if (expr.GetExpressionClass() != ExpressionClass::BOUND_FUNCTION) { - return false; - } - auto &function = expr.Cast(); - if (function.function.name != "struct_extract_at" && function.function.name != "struct_extract" && - function.function.name != "array_extract") { - return false; - } - if (!function.bind_info) { - return false; - } - if (function.children[0]->return_type.id() != LogicalTypeId::STRUCT) { - return false; - } - auto &bind_data = function.bind_info->Cast(); - indexes.push_back(bind_data.index); - // struct extract, check if left child is a bound column ref - if (function.children[0]->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { - // column reference - check if it is a struct - auto &ref = function.children[0]->Cast(); - if (ref.return_type.id() != LogicalTypeId::STRUCT) { - return false; - } - colref = &ref; - return true; - } - // not a column reference - try to handle this recursively - if (!HandleStructExtractRecursive(*function.children[0], colref, indexes)) { - return false; - } - return true; -} - -bool RemoveUnusedColumns::HandleStructExtract(Expression &expr) { - optional_ptr colref; - vector indexes; - if (!HandleStructExtractRecursive(expr, colref, indexes)) { - return false; - } - D_ASSERT(!indexes.empty()); - // construct the ColumnIndex - ColumnIndex index = ColumnIndex(indexes[0]); - for (idx_t i = 1; i < indexes.size(); i++) { - ColumnIndex new_index(indexes[i]); - new_index.AddChildIndex(std::move(index)); - index = std::move(new_index); - } - AddBinding(*colref, std::move(index)); - return true; -} - -void MergeChildColumns(vector ¤t_child_columns, ColumnIndex &new_child_column) { - if (current_child_columns.empty()) { - // there's already a reference to the full column - we can't extract only a subfield - // skip struct projection pushdown - return; - } - // if we are already extract sub-fields, add it (if it is not there yet) - for (auto &binding : current_child_columns) { - if (binding.GetPrimaryIndex() != new_child_column.GetPrimaryIndex()) { - continue; - } - // found a match: sub-field is already projected - // check if we have child columns - auto &nested_child_columns = binding.GetChildIndexesMutable(); - if (!new_child_column.HasChildren()) { - // new child is a reference to a full column - clear any existing bindings (if any) - nested_child_columns.clear(); - } else { - // new child has a sub-reference - merge recursively - D_ASSERT(new_child_column.ChildIndexCount() == 1); - MergeChildColumns(nested_child_columns, new_child_column.GetChildIndex(0)); - } - return; - } - // this child column is not projected yet - add it in - current_child_columns.push_back(std::move(new_child_column)); -} - -void RemoveUnusedColumns::AddBinding(BoundColumnRefExpression &col, ColumnIndex child_column) { - auto entry = column_references.find(col.binding); - if (entry == column_references.end()) { - // column not referenced yet - add a binding to it entirely - ReferencedColumn column; - column.bindings.push_back(col); - column.child_columns.push_back(std::move(child_column)); - column_references.insert(make_pair(col.binding, std::move(column))); - } else { - // column reference already exists - check add the binding - auto &column = entry->second; - column.bindings.push_back(col); - - MergeChildColumns(column.child_columns, child_column); - } -} - -void RemoveUnusedColumns::AddBinding(BoundColumnRefExpression &col) { - auto entry = column_references.find(col.binding); - if (entry == column_references.end()) { - // column not referenced yet - add a binding to it entirely - column_references[col.binding].bindings.push_back(col); - } else { - // column reference already exists - add the binding and clear any sub-references - auto &column = entry->second; - column.bindings.push_back(col); - column.child_columns.clear(); - } -} - -void RemoveUnusedColumns::VisitExpression(unique_ptr *expression) { - auto &expr = **expression; - if (HandleStructExtract(expr)) { - // already handled - return; - } - // recurse - LogicalOperatorVisitor::VisitExpression(expression); -} - unique_ptr RemoveUnusedColumns::VisitReplace(BoundColumnRefExpression &expr, unique_ptr *expr_ptr) { - // add a reference to the entire column - AddBinding(expr); + // add a column reference + column_references[expr.binding].push_back(&expr); return nullptr; } diff --git a/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp b/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp index 367731fec..bd4e0821e 100644 --- a/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp +++ b/src/duckdb/src/optimizer/rule/arithmetic_simplification.cpp @@ -1,10 +1,9 @@ #include "duckdb/optimizer/rule/arithmetic_simplification.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/function/function_binder.hpp" -#include "duckdb/optimizer/expression_rewriter.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" +#include "duckdb/optimizer/expression_rewriter.hpp" namespace duckdb { diff --git a/src/duckdb/src/optimizer/rule/comparison_simplification.cpp b/src/duckdb/src/optimizer/rule/comparison_simplification.cpp index 1e377528d..467d235a2 100644 --- a/src/duckdb/src/optimizer/rule/comparison_simplification.cpp +++ b/src/duckdb/src/optimizer/rule/comparison_simplification.cpp @@ -3,7 +3,6 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/optimizer/expression_rewriter.hpp" namespace duckdb { @@ -29,12 +28,12 @@ unique_ptr ComparisonSimplificationRule::Apply(LogicalOperator &op, if (!ExpressionExecutor::TryEvaluateScalar(GetContext(), constant_expr, constant_value)) { return nullptr; } - if (constant_value.IsNull() && !(expr.GetExpressionType() == ExpressionType::COMPARE_NOT_DISTINCT_FROM || - expr.GetExpressionType() == ExpressionType::COMPARE_DISTINCT_FROM)) { + if (constant_value.IsNull() && !(expr.type == ExpressionType::COMPARE_NOT_DISTINCT_FROM || + expr.type == ExpressionType::COMPARE_DISTINCT_FROM)) { // comparison with constant NULL, return NULL return make_uniq(Value(LogicalType::BOOLEAN)); } - if (column_ref_expr->GetExpressionClass() == ExpressionClass::BOUND_CAST) { + if (column_ref_expr->expression_class == ExpressionClass::BOUND_CAST) { //! Here we check if we can apply the expression on the constant side //! We can do this if the cast itself is invertible and casting the constant is //! invertible in practice. @@ -47,8 +46,7 @@ unique_ptr ComparisonSimplificationRule::Apply(LogicalOperator &op, // Can we cast the constant at all? string error_message; Value cast_constant; - auto new_constant = - constant_value.TryCastAs(rewriter.context, target_type, cast_constant, &error_message, true); + auto new_constant = constant_value.DefaultTryCastAs(target_type, cast_constant, &error_message, true); if (!new_constant) { return nullptr; } @@ -58,8 +56,7 @@ unique_ptr ComparisonSimplificationRule::Apply(LogicalOperator &op, !BoundCastExpression::CastIsInvertible(cast_expression.return_type, target_type)) { // Is it actually invertible? Value uncast_constant; - if (!cast_constant.TryCastAs(rewriter.context, constant_value.type(), uncast_constant, &error_message, - true) || + if (!cast_constant.DefaultTryCastAs(constant_value.type(), uncast_constant, &error_message, true) || uncast_constant != constant_value) { return nullptr; } diff --git a/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp b/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp index f1d5838d0..14fd80a94 100644 --- a/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp +++ b/src/duckdb/src/optimizer/rule/conjunction_simplification.cpp @@ -48,7 +48,7 @@ unique_ptr ConjunctionSimplificationRule::Apply(LogicalOperator &op, // we can't simplify conjunctions with a constant NULL return nullptr; } - if (conjunction.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (conjunction.type == ExpressionType::CONJUNCTION_AND) { if (!BooleanValue::Get(constant_value)) { // FALSE in AND, result of expression is false return make_uniq(Value::BOOLEAN(false)); @@ -57,7 +57,7 @@ unique_ptr ConjunctionSimplificationRule::Apply(LogicalOperator &op, return RemoveExpression(conjunction, constant_expr); } } else { - D_ASSERT(conjunction.GetExpressionType() == ExpressionType::CONJUNCTION_OR); + D_ASSERT(conjunction.type == ExpressionType::CONJUNCTION_OR); if (!BooleanValue::Get(constant_value)) { // FALSE in OR, remove the expression from the set return RemoveExpression(conjunction, constant_expr); diff --git a/src/duckdb/src/optimizer/rule/constant_folding.cpp b/src/duckdb/src/optimizer/rule/constant_folding.cpp index 6dba91d2a..7702b4604 100644 --- a/src/duckdb/src/optimizer/rule/constant_folding.cpp +++ b/src/duckdb/src/optimizer/rule/constant_folding.cpp @@ -13,7 +13,7 @@ class ConstantFoldingExpressionMatcher : public FoldableConstantMatcher { public: bool Match(Expression &expr, vector> &bindings) override { // we also do not match on ConstantExpressions, because we cannot fold those any further - if (expr.GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (expr.type == ExpressionType::VALUE_CONSTANT) { return false; } return FoldableConstantMatcher::Match(expr, bindings); @@ -29,7 +29,7 @@ unique_ptr ConstantFoldingRule::Apply(LogicalOperator &op, vector(); - root->expr_class = ExpressionClass::BOUND_AGGREGATE; -} - -unique_ptr DistinctAggregateOptimizer::Apply(ClientContext &context, BoundAggregateExpression &aggr, - bool &changes_made) { - if (!aggr.IsDistinct()) { - // no DISTINCT defined - return nullptr; - } - if (aggr.function.distinct_dependent == AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT) { - // not a distinct-sensitive aggregate but we have an DISTINCT modifier - remove it - aggr.aggr_type = AggregateType::NON_DISTINCT; - changes_made = true; - return nullptr; - } - return nullptr; -} - -unique_ptr DistinctAggregateOptimizer::Apply(LogicalOperator &op, vector> &bindings, - bool &changes_made, bool is_root) { - auto &aggr = bindings[0].get().Cast(); - return Apply(rewriter.context, aggr, changes_made); -} - -DistinctWindowedOptimizer::DistinctWindowedOptimizer(ExpressionRewriter &rewriter) : Rule(rewriter) { - root = make_uniq(); - root->expr_class = ExpressionClass::BOUND_WINDOW; -} - -unique_ptr DistinctWindowedOptimizer::Apply(ClientContext &context, BoundWindowExpression &wexpr, - bool &changes_made) { - if (!wexpr.distinct) { - // no DISTINCT defined - return nullptr; - } - if (!wexpr.aggregate) { - // not an aggregate - return nullptr; - } - if (wexpr.aggregate->distinct_dependent == AggregateDistinctDependent::NOT_DISTINCT_DEPENDENT) { - // not a distinct-sensitive aggregate but we have an DISTINCT modifier - remove it - wexpr.distinct = false; - changes_made = true; - return nullptr; - } - return nullptr; -} - -unique_ptr DistinctWindowedOptimizer::Apply(LogicalOperator &op, vector> &bindings, - bool &changes_made, bool is_root) { - auto &wexpr = bindings[0].get().Cast(); - return Apply(rewriter.context, wexpr, changes_made); -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/rule/distributivity.cpp b/src/duckdb/src/optimizer/rule/distributivity.cpp index b1b18617c..b6a889af4 100644 --- a/src/duckdb/src/optimizer/rule/distributivity.cpp +++ b/src/duckdb/src/optimizer/rule/distributivity.cpp @@ -15,7 +15,7 @@ DistributivityRule::DistributivityRule(ExpressionRewriter &rewriter) : Rule(rewr } void DistributivityRule::AddExpressionSet(Expression &expr, expression_set_t &set) { - if (expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (expr.type == ExpressionType::CONJUNCTION_AND) { auto &and_expr = expr.Cast(); for (auto &child : and_expr.children) { set.insert(*child); @@ -29,7 +29,7 @@ unique_ptr DistributivityRule::ExtractExpression(BoundConjunctionExp Expression &expr) { auto &child = conj.children[idx]; unique_ptr result; - if (child->GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (child->type == ExpressionType::CONJUNCTION_AND) { // AND, remove expression from the list auto &and_expr = child->Cast(); for (idx_t i = 0; i < and_expr.children.size(); i++) { diff --git a/src/duckdb/src/optimizer/rule/enum_comparison.cpp b/src/duckdb/src/optimizer/rule/enum_comparison.cpp index 5dfcfaf30..aeb5e2248 100644 --- a/src/duckdb/src/optimizer/rule/enum_comparison.cpp +++ b/src/duckdb/src/optimizer/rule/enum_comparison.cpp @@ -65,8 +65,7 @@ unique_ptr EnumComparisonRule::Apply(LogicalOperator &op, vectorreturn_type, true); - return make_uniq(root.GetExpressionType(), std::move(cast_left_to_right), - std::move(right_child.child)); + return make_uniq(root.type, std::move(cast_left_to_right), std::move(right_child.child)); } } // namespace duckdb diff --git a/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp b/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp index c3053b382..7062dcd77 100644 --- a/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp +++ b/src/duckdb/src/optimizer/rule/equal_or_null_simplification.cpp @@ -38,8 +38,7 @@ EqualOrNullSimplification::EqualOrNullSimplification(ExpressionRewriter &rewrite // a=b OR (a IS NULL AND b IS NULL) to a IS NOT DISTINCT FROM b static unique_ptr TryRewriteEqualOrIsNull(Expression &equal_expr, Expression &and_expr) { - if (equal_expr.GetExpressionType() != ExpressionType::COMPARE_EQUAL || - and_expr.GetExpressionType() != ExpressionType::CONJUNCTION_AND) { + if (equal_expr.type != ExpressionType::COMPARE_EQUAL || and_expr.type != ExpressionType::CONJUNCTION_AND) { return nullptr; } @@ -59,7 +58,7 @@ static unique_ptr TryRewriteEqualOrIsNull(Expression &equal_expr, Ex for (const auto &item : and_cast.children) { auto &next_exp = *item; - if (next_exp.GetExpressionType() == ExpressionType::OPERATOR_IS_NULL) { + if (next_exp.type == ExpressionType::OPERATOR_IS_NULL) { auto &next_exp_cast = next_exp.Cast(); auto &child = *next_exp_cast.children[0]; @@ -86,7 +85,7 @@ unique_ptr EqualOrNullSimplification::Apply(LogicalOperator &op, vec bool &changes_made, bool is_root) { const Expression &or_exp = bindings[0].get(); - if (or_exp.GetExpressionType() != ExpressionType::CONJUNCTION_OR) { + if (or_exp.type != ExpressionType::CONJUNCTION_OR) { return nullptr; } diff --git a/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp b/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp index d54d98cc9..c17b0ea3b 100644 --- a/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp +++ b/src/duckdb/src/optimizer/rule/in_clause_simplification_rule.cpp @@ -16,11 +16,11 @@ InClauseSimplificationRule::InClauseSimplificationRule(ExpressionRewriter &rewri unique_ptr InClauseSimplificationRule::Apply(LogicalOperator &op, vector> &bindings, bool &changes_made, bool is_root) { auto &expr = bindings[0].get().Cast(); - if (expr.children[0]->GetExpressionClass() != ExpressionClass::BOUND_CAST) { + if (expr.children[0]->expression_class != ExpressionClass::BOUND_CAST) { return nullptr; } auto &cast_expression = expr.children[0]->Cast(); - if (cast_expression.child->GetExpressionClass() != ExpressionClass::BOUND_COLUMN_REF) { + if (cast_expression.child->expression_class != ExpressionClass::BOUND_COLUMN_REF) { return nullptr; } //! The goal here is to remove the cast from the probe expression @@ -34,7 +34,7 @@ unique_ptr InClauseSimplificationRule::Apply(LogicalOperator &op, ve vector> cast_list; //! First check if we can cast all children for (size_t i = 1; i < expr.children.size(); i++) { - if (expr.children[i]->GetExpressionClass() != ExpressionClass::BOUND_CONSTANT) { + if (expr.children[i]->expression_class != ExpressionClass::BOUND_CONSTANT) { return nullptr; } D_ASSERT(expr.children[i]->IsFoldable()); diff --git a/src/duckdb/src/optimizer/rule/like_optimizations.cpp b/src/duckdb/src/optimizer/rule/like_optimizations.cpp index a8398c99f..067dfd791 100644 --- a/src/duckdb/src/optimizer/rule/like_optimizations.cpp +++ b/src/duckdb/src/optimizer/rule/like_optimizations.cpp @@ -1,8 +1,6 @@ #include "duckdb/optimizer/rule/like_optimizations.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/string_functions.hpp" -#include "duckdb/function/scalar/string_common.hpp" #include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" @@ -134,7 +132,7 @@ unique_ptr LikeOptimizationRule::Apply(LogicalOperator &op, vector MoveConstantsRule::Apply(LogicalOperator &op, vectorreturn_type.IsIntegral()); if (inner_constant.value.IsNull() || outer_constant.value.IsNull()) { - if (comparison.GetExpressionType() == ExpressionType::COMPARE_DISTINCT_FROM || - comparison.GetExpressionType() == ExpressionType::COMPARE_NOT_DISTINCT_FROM) { + if (comparison.type == ExpressionType::COMPARE_DISTINCT_FROM || + comparison.type == ExpressionType::COMPARE_NOT_DISTINCT_FROM) { return nullptr; } return make_uniq(Value(comparison.return_type)); @@ -62,7 +62,7 @@ unique_ptr MoveConstantsRule::Apply(LogicalOperator &op, vector MoveConstantsRule::Apply(LogicalOperator &op, vector MoveConstantsRule::Apply(LogicalOperator &op, vector MoveConstantsRule::Apply(LogicalOperator &op, vector 2] - comparison.SetExpressionTypeUnsafe(FlipComparisonExpression(comparison.GetExpressionType())); + comparison.type = FlipComparisonExpression(comparison.type); } } else { D_ASSERT(op_type == "*"); @@ -126,8 +126,8 @@ unique_ptr MoveConstantsRule::Apply(LogicalOperator &op, vector::Minimum() && inner_value == -1) || outer_value % inner_value != 0) { - bool is_equality = comparison.GetExpressionType() == ExpressionType::COMPARE_EQUAL; - bool is_inequality = comparison.GetExpressionType() == ExpressionType::COMPARE_NOTEQUAL; + bool is_equality = comparison.type == ExpressionType::COMPARE_EQUAL; + bool is_inequality = comparison.type == ExpressionType::COMPARE_NOTEQUAL; if (is_equality || is_inequality) { // we know the values are not equal // the result will be either FALSE or NULL (if COMPARE_EQUAL) @@ -141,7 +141,7 @@ unique_ptr MoveConstantsRule::Apply(LogicalOperator &op, vector RegexOptimizationRule::Apply(LogicalOperator &op, vector< return nullptr; } auto parameter = make_uniq(Value(std::move(escaped_like_string.like_string))); - auto contains = make_uniq(root.return_type, GetStringContains(), + auto contains = make_uniq(root.return_type, ContainsFun::GetStringContains(), std::move(root.children), nullptr); contains->children[1] = std::move(parameter); @@ -206,8 +205,8 @@ unique_ptr RegexOptimizationRule::Apply(LogicalOperator &op, vector< D_ASSERT(root.children.size() == 2); } - auto like_expression = - make_uniq(root.return_type, LikeFun::GetFunction(), std::move(root.children), nullptr); + auto like_expression = make_uniq(root.return_type, LikeFun::GetLikeFunction(), + std::move(root.children), nullptr); auto parameter = make_uniq(Value(std::move(like_string.like_string))); like_expression->children[1] = std::move(parameter); return std::move(like_expression); diff --git a/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp b/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp index ee144e695..3b1d22eeb 100644 --- a/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp +++ b/src/duckdb/src/optimizer/rule/timestamp_comparison.cpp @@ -43,7 +43,7 @@ TimeStampComparison::TimeStampComparison(ClientContext &context, ExpressionRewri } static void ExpressionIsConstant(Expression &expr, bool &is_constant) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { is_constant = false; return; } diff --git a/src/duckdb/src/optimizer/sampling_pushdown.cpp b/src/duckdb/src/optimizer/sampling_pushdown.cpp deleted file mode 100644 index ca805e64e..000000000 --- a/src/duckdb/src/optimizer/sampling_pushdown.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "duckdb/optimizer/sampling_pushdown.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/planner/operator/logical_sample.hpp" -#include "duckdb/common/types/value.hpp" -namespace duckdb { - -unique_ptr SamplingPushdown::Optimize(unique_ptr op) { - if (op->type == LogicalOperatorType::LOGICAL_SAMPLE && - op->Cast().sample_options->method == SampleMethod::SYSTEM_SAMPLE && - op->Cast().sample_options->is_percentage && !op->children.empty() && - op->children[0]->type == LogicalOperatorType::LOGICAL_GET && - op->children[0]->Cast().function.sampling_pushdown && op->children[0]->children.empty()) { - auto &get = op->children[0]->Cast(); - // set sampling option - get.extra_info.sample_options = std::move(op->Cast().sample_options); - op = std::move(op->children[0]); - } - for (auto &child : op->children) { - child = Optimize(std::move(child)); - } - return op; -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/statistics/expression/propagate_comparison.cpp b/src/duckdb/src/optimizer/statistics/expression/propagate_comparison.cpp index bc1e116d6..3022d7c5d 100644 --- a/src/duckdb/src/optimizer/statistics/expression/propagate_comparison.cpp +++ b/src/duckdb/src/optimizer/statistics/expression/propagate_comparison.cpp @@ -99,7 +99,7 @@ unique_ptr StatisticsPropagator::PropagateExpression(BoundCompar return nullptr; } // propagate the statistics of the comparison operator - auto propagate_result = PropagateComparison(*left_stats, *right_stats, expr.GetExpressionType()); + auto propagate_result = PropagateComparison(*left_stats, *right_stats, expr.type); switch (propagate_result) { case FilterPropagateResult::FILTER_ALWAYS_TRUE: expr_ptr = make_uniq(Value::BOOLEAN(true)); diff --git a/src/duckdb/src/optimizer/statistics/expression/propagate_conjunction.cpp b/src/duckdb/src/optimizer/statistics/expression/propagate_conjunction.cpp index 31e415f19..d4431afaf 100644 --- a/src/duckdb/src/optimizer/statistics/expression/propagate_conjunction.cpp +++ b/src/duckdb/src/optimizer/statistics/expression/propagate_conjunction.cpp @@ -9,7 +9,7 @@ namespace duckdb { unique_ptr StatisticsPropagator::PropagateExpression(BoundConjunctionExpression &expr, unique_ptr &expr_ptr) { - auto is_and = expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND; + auto is_and = expr.type == ExpressionType::CONJUNCTION_AND; for (idx_t expr_idx = 0; expr_idx < expr.children.size(); expr_idx++) { auto &child = expr.children[expr_idx]; auto stats = PropagateExpression(child); diff --git a/src/duckdb/src/optimizer/statistics/expression/propagate_operator.cpp b/src/duckdb/src/optimizer/statistics/expression/propagate_operator.cpp index 234459478..0733fc740 100644 --- a/src/duckdb/src/optimizer/statistics/expression/propagate_operator.cpp +++ b/src/duckdb/src/optimizer/statistics/expression/propagate_operator.cpp @@ -19,7 +19,7 @@ unique_ptr StatisticsPropagator::PropagateExpression(BoundOperat if (!all_have_stats) { return nullptr; } - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::OPERATOR_COALESCE: // COALESCE, merge stats of all children for (idx_t i = 0; i < expr.children.size(); i++) { diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_aggregate.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_aggregate.cpp index 811d01c94..677b4835a 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_aggregate.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_aggregate.cpp @@ -1,78 +1,8 @@ #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/planner/operator/logical_aggregate.hpp" -#include "duckdb/planner/operator/logical_dummy_scan.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/planner/operator/logical_expression_get.hpp" -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" namespace duckdb { -void StatisticsPropagator::TryExecuteAggregates(LogicalAggregate &aggr, unique_ptr &node_ptr) { - if (!aggr.groups.empty()) { - // not possible with groups - return; - } - if (aggr.children[0]->type != LogicalOperatorType::LOGICAL_GET) { - // child must be a LOGICAL_GET - // FIXME: we could do this with projections as well - return; - } - auto &get = aggr.children[0]->Cast(); - if (!get.function.get_partition_stats) { - // GET does not support getting the partition stats - return; - } - if (!get.table_filters.filters.empty()) { - // we cannot do this if the GET has filters - return; - } - // check if all aggregates are COUNT(*) - for (auto &aggr_ref : aggr.expressions) { - if (aggr_ref->GetExpressionClass() != ExpressionClass::BOUND_AGGREGATE) { - // not an aggregate - return; - } - auto &aggr_expr = aggr_ref->Cast(); - if (aggr_expr.function.name != "count_star") { - // aggregate is not count star - bail - return; - } - if (aggr_expr.filter) { - // aggregate has a filter - bail - return; - } - } - // we can do the rewrite! get the stats - GetPartitionStatsInput input(get.function, get.bind_data.get()); - auto partition_stats = get.function.get_partition_stats(context, input); - idx_t count = 0; - for (auto &stats : partition_stats) { - if (stats.count_type == CountType::COUNT_APPROXIMATE) { - // we cannot get an exact count - return; - } - count += stats.count; - } - // we got an exact count - replace the entire aggregate with a scan of the result - vector types; - vector> count_results; - for (idx_t aggregate_index = 0; aggregate_index < aggr.expressions.size(); ++aggregate_index) { - auto count_result = make_uniq(Value::BIGINT(NumericCast(count))); - count_result->SetAlias(aggr.expressions[aggregate_index]->GetName()); - count_results.push_back(std::move(count_result)); - - types.push_back(LogicalType::BIGINT); - } - - vector>> expressions; - expressions.push_back(std::move(count_results)); - auto expression_get = - make_uniq(aggr.aggregate_index, std::move(types), std::move(expressions)); - expression_get->children.push_back(make_uniq(aggr.group_index)); - node_ptr = std::move(expression_get); -} - unique_ptr StatisticsPropagator::PropagateStatistics(LogicalAggregate &aggr, unique_ptr &node_ptr) { // first propagate statistics in the child node @@ -104,10 +34,6 @@ unique_ptr StatisticsPropagator::PropagateStatistics(LogicalAggr ColumnBinding aggregate_binding(aggr.aggregate_index, aggregate_idx); statistics_map[aggregate_binding] = std::move(stats); } - - // after we propagate statistics - try to directly execute aggregates using statistics - TryExecuteAggregates(aggr, node_ptr); - // the max cardinality of an aggregate is the max cardinality of the input (i.e. when every row is a unique group) return std::move(node_stats); } diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp index 1c555be4e..7dbdc6da7 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp @@ -1,5 +1,5 @@ #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/scalar/generic_common.hpp" +#include "duckdb/function/scalar/generic_functions.hpp" #include "duckdb/optimizer/statistics_propagator.hpp" #include "duckdb/planner/expression/bound_between_expression.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" @@ -161,26 +161,23 @@ void StatisticsPropagator::UpdateFilterStatistics(Expression &left, Expression & // first check if either side is a bound column ref // any column ref involved in a comparison will not be null after the comparison bool compare_distinct = IsCompareDistinct(comparison_type); - if (!compare_distinct && left.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (!compare_distinct && left.type == ExpressionType::BOUND_COLUMN_REF) { SetStatisticsNotNull((left.Cast()).binding); } - if (!compare_distinct && right.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (!compare_distinct && right.type == ExpressionType::BOUND_COLUMN_REF) { SetStatisticsNotNull((right.Cast()).binding); } // check if this is a comparison between a constant and a column ref optional_ptr constant; optional_ptr columnref; - if (left.GetExpressionType() == ExpressionType::VALUE_CONSTANT && - right.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (left.type == ExpressionType::VALUE_CONSTANT && right.type == ExpressionType::BOUND_COLUMN_REF) { constant = &left.Cast(); columnref = &right.Cast(); comparison_type = FlipComparisonExpression(comparison_type); - } else if (left.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF && - right.GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + } else if (left.type == ExpressionType::BOUND_COLUMN_REF && right.type == ExpressionType::VALUE_CONSTANT) { columnref = &left.Cast(); constant = &right.Cast(); - } else if (left.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF && - right.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + } else if (left.type == ExpressionType::BOUND_COLUMN_REF && right.type == ExpressionType::BOUND_COLUMN_REF) { // comparison between two column refs auto &left_column_ref = left.Cast(); auto &right_column_ref = right.Cast(); @@ -216,7 +213,7 @@ void StatisticsPropagator::UpdateFilterStatistics(Expression &condition) { } case ExpressionClass::BOUND_COMPARISON: { auto &comparison = condition.Cast(); - UpdateFilterStatistics(*comparison.left, *comparison.right, comparison.GetExpressionType()); + UpdateFilterStatistics(*comparison.left, *comparison.right, comparison.type); break; } default: diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp index dc2390db5..962ad8f9d 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_get.cpp @@ -41,7 +41,7 @@ unique_ptr StatisticsPropagator::PropagateStatistics(LogicalGet } auto &column_ids = get.GetColumnIds(); for (idx_t i = 0; i < column_ids.size(); i++) { - auto stats = get.function.statistics(context, get.bind_data.get(), column_ids[i].GetPrimaryIndex()); + auto stats = get.function.statistics(context, get.bind_data.get(), column_ids[i]); if (stats) { ColumnBinding binding(get.table_index, i); statistics_map.insert(make_pair(binding, std::move(stats))); @@ -57,12 +57,12 @@ unique_ptr StatisticsPropagator::PropagateStatistics(LogicalGet for (auto &table_filter_column : column_indexes) { idx_t column_index; for (column_index = 0; column_index < column_ids.size(); column_index++) { - if (column_ids[column_index].GetPrimaryIndex() == table_filter_column) { + if (column_ids[column_index] == table_filter_column) { break; } } D_ASSERT(column_index < column_ids.size()); - D_ASSERT(column_ids[column_index].GetPrimaryIndex() == table_filter_column); + D_ASSERT(column_ids[column_index] == table_filter_column); // find the stats ColumnBinding stats_binding(get.table_index, column_index); diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp index 1787a7f26..c3d0b0c65 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp @@ -157,8 +157,8 @@ void StatisticsPropagator::PropagateStatistics(LogicalComparisonJoin &join, uniq // Try to push lhs stats down rhs and vice versa if (stats_left && stats_right && updated_stats_left && updated_stats_right && - condition.left->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF && - condition.right->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + condition.left->type == ExpressionType::BOUND_COLUMN_REF && + condition.right->type == ExpressionType::BOUND_COLUMN_REF) { CreateFilterFromJoinStats(join.children[0], condition.left, *stats_left, *updated_stats_left); CreateFilterFromJoinStats(join.children[1], condition.right, *stats_right, *updated_stats_right); } @@ -324,7 +324,7 @@ void StatisticsPropagator::CreateFilterFromJoinStats(unique_ptr const BaseStatistics &stats_before, const BaseStatistics &stats_after) { // Only do this for integral colref's that have stats - if (expr->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF || !expr->return_type.IsIntegral() || + if (expr->type != ExpressionType::BOUND_COLUMN_REF || !expr->return_type.IsIntegral() || !NumericStats::HasMinMax(stats_before) || !NumericStats::HasMinMax(stats_after)) { return; } diff --git a/src/duckdb/src/optimizer/statistics/operator/propagate_window.cpp b/src/duckdb/src/optimizer/statistics/operator/propagate_window.cpp index 3f3d91731..55dd7af73 100644 --- a/src/duckdb/src/optimizer/statistics/operator/propagate_window.cpp +++ b/src/duckdb/src/optimizer/statistics/operator/propagate_window.cpp @@ -42,9 +42,6 @@ unique_ptr StatisticsPropagator::PropagateStatistics(LogicalWind } else { over_expr.expr_stats.push_back(nullptr); } - for (auto &bound_order : over_expr.arg_orders) { - bound_order.stats = PropagateExpression(bound_order.expression); - } } return std::move(node_stats); } diff --git a/src/duckdb/src/optimizer/sum_rewriter.cpp b/src/duckdb/src/optimizer/sum_rewriter.cpp deleted file mode 100644 index 587144110..000000000 --- a/src/duckdb/src/optimizer/sum_rewriter.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "duckdb/optimizer/sum_rewriter.hpp" - -#include "duckdb/planner/expression/bound_aggregate_expression.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" -#include "duckdb/planner/operator/logical_aggregate.hpp" -#include "duckdb/planner/operator/logical_projection.hpp" -#include "duckdb/optimizer/matcher/expression_matcher.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" -#include "duckdb/function/function_binder.hpp" -#include "duckdb/planner/binder.hpp" -#include "duckdb/optimizer/optimizer.hpp" - -namespace duckdb { - -unique_ptr GetSmallIntegerTypesMatcher() { - vector types {LogicalTypeId::TINYINT, LogicalTypeId::SMALLINT, LogicalTypeId::INTEGER, - LogicalTypeId::BIGINT, LogicalTypeId::UTINYINT, LogicalTypeId::USMALLINT, - LogicalTypeId::UINTEGER, LogicalTypeId::UBIGINT}; - return make_uniq(std::move(types)); -} - -SumRewriterOptimizer::SumRewriterOptimizer(Optimizer &optimizer) : optimizer(optimizer) { - // set up an expression matcher that detects SUM(x + C) or SUM(C + x) - auto op = make_uniq(); - op->function = make_uniq("sum"); - op->policy = SetMatcher::Policy::UNORDERED; - - auto arithmetic = make_uniq(); - // handle X + C where - arithmetic->function = make_uniq("+"); - // we match only on integral numeric types - arithmetic->type = make_uniq(); - auto child_constant_matcher = make_uniq(); - auto child_expression_matcher = make_uniq(); - child_constant_matcher->type = GetSmallIntegerTypesMatcher(); - child_expression_matcher->type = GetSmallIntegerTypesMatcher(); - arithmetic->matchers.push_back(std::move(child_constant_matcher)); - arithmetic->matchers.push_back(std::move(child_expression_matcher)); - arithmetic->policy = SetMatcher::Policy::SOME; - op->matchers.push_back(std::move(arithmetic)); - - sum_matcher = std::move(op); -} - -SumRewriterOptimizer::~SumRewriterOptimizer() { -} - -void SumRewriterOptimizer::Optimize(unique_ptr &op) { - if (op->type == LogicalOperatorType::LOGICAL_AGGREGATE_AND_GROUP_BY) { - RewriteSums(op); - } - VisitOperator(*op); -} - -void SumRewriterOptimizer::StandardVisitOperator(LogicalOperator &op) { - for (auto &child : op.children) { - Optimize(child); - } - if (!aggregate_map.empty()) { - VisitOperatorExpressions(op); - } -} - -void SumRewriterOptimizer::VisitOperator(LogicalOperator &op) { - switch (op.type) { - case LogicalOperatorType::LOGICAL_UNION: - case LogicalOperatorType::LOGICAL_EXCEPT: - case LogicalOperatorType::LOGICAL_INTERSECT: - case LogicalOperatorType::LOGICAL_MATERIALIZED_CTE: - case LogicalOperatorType::LOGICAL_PROJECTION: { - SumRewriterOptimizer sum_rewriter(optimizer); - sum_rewriter.StandardVisitOperator(op); - return; - } - default: - break; - } - - StandardVisitOperator(op); -} - -unique_ptr SumRewriterOptimizer::VisitReplace(BoundColumnRefExpression &expr, - unique_ptr *expr_ptr) { - // check if this column ref points to an aggregate that was remapped; if it does we remap it - auto entry = aggregate_map.find(expr.binding); - if (entry != aggregate_map.end()) { - expr.binding = entry->second; - } - return nullptr; -} - -void SumRewriterOptimizer::RewriteSums(unique_ptr &op) { - auto &aggr = op->Cast(); - if (!aggr.groups.empty()) { - return; - } - - unordered_set rewrote_map; - vector> constants; - idx_t aggr_count = aggr.expressions.size(); - for (idx_t i = 0; i < aggr_count; ++i) { - auto &expr = aggr.expressions[i]; - vector> bindings; - if (!sum_matcher->Match(*expr, bindings)) { - continue; - } - // found SUM(x + C) - auto &sum = bindings[0].get().Cast(); - auto &addition = bindings[1].get().Cast(); - idx_t const_idx = addition.children[0]->GetExpressionType() == ExpressionType::VALUE_CONSTANT ? 0 : 1; - auto const_expr = std::move(addition.children[const_idx]); - auto main_expr = std::move(addition.children[1 - const_idx]); - - // turn this into SUM(x) - sum.children[0] = main_expr->Copy(); - - // push a new aggregate - COUNT(x) - FunctionBinder function_binder(optimizer.context); - - auto count_fun = CountFunctionBase::GetFunction(); - vector> children; - children.push_back(std::move(main_expr)); - auto count_aggr = - function_binder.BindAggregateFunction(count_fun, std::move(children), nullptr, AggregateType::NON_DISTINCT); - aggr.expressions.push_back(std::move(count_aggr)); - constants.push_back(std::move(const_expr)); - rewrote_map.insert(i); - } - if (rewrote_map.empty()) { - return; - } - vector> projection_expressions; - // we rewrote aggregates - we need to push a projection in which we re-compute the original result - idx_t rewritten_index = 0; - auto proj_index = optimizer.binder.GenerateTableIndex(); - for (idx_t i = 0; i < aggr_count; i++) { - ColumnBinding aggregate_binding(aggr.aggregate_index, i); - aggregate_map[aggregate_binding] = ColumnBinding(proj_index, i); - auto &aggr_type = aggr.expressions[i]->return_type; - auto aggr_ref = make_uniq(aggr_type, aggregate_binding); - if (rewrote_map.find(i) == rewrote_map.end()) { - // not rewritten - just push a reference - projection_expressions.push_back(std::move(aggr_ref)); - continue; - } - // rewritten - need to compute the final result - idx_t count_idx = aggr_count + rewritten_index; - ColumnBinding count_binding(aggr.aggregate_index, count_idx); - auto count_ref = make_uniq(aggr.expressions[count_idx]->return_type, count_binding); - - // cast the count to the sum type - auto cast_count = BoundCastExpression::AddCastToType(optimizer.context, std::move(count_ref), aggr_type); - auto const_expr = - BoundCastExpression::AddCastToType(optimizer.context, std::move(constants[rewritten_index]), aggr_type); - - // bind the multiplication - auto multiply = optimizer.BindScalarFunction("*", std::move(cast_count), std::move(const_expr)); - - // add it to the sum - auto final_result = optimizer.BindScalarFunction("+", std::move(aggr_ref), std::move(multiply)); - projection_expressions.push_back(std::move(final_result)); - - rewritten_index++; - } - - // push the projection to replace the aggregate - auto proj = make_uniq(proj_index, std::move(projection_expressions)); - proj->children.push_back(std::move(op)); - op = std::move(proj); -} - -} // namespace duckdb diff --git a/src/duckdb/src/optimizer/topn_optimizer.cpp b/src/duckdb/src/optimizer/topn_optimizer.cpp index 0bfd81190..81b2aa09d 100644 --- a/src/duckdb/src/optimizer/topn_optimizer.cpp +++ b/src/duckdb/src/optimizer/topn_optimizer.cpp @@ -1,16 +1,9 @@ #include "duckdb/optimizer/topn_optimizer.hpp" #include "duckdb/common/limits.hpp" -#include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_limit.hpp" #include "duckdb/planner/operator/logical_order.hpp" #include "duckdb/planner/operator/logical_top_n.hpp" -#include "duckdb/planner/filter/constant_filter.hpp" -#include "duckdb/planner/filter/dynamic_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" -#include "duckdb/execution/operator/join/join_filter_pushdown.hpp" -#include "duckdb/optimizer/join_filter_pushdown_optimizer.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" namespace duckdb { @@ -39,69 +32,6 @@ bool TopN::CanOptimize(LogicalOperator &op) { return false; } -void TopN::PushdownDynamicFilters(LogicalTopN &op) { - // pushdown dynamic filters through the Top-N operator - if (op.orders[0].null_order == OrderByNullType::NULLS_FIRST) { - // FIXME: not supported for NULLS FIRST quite yet - // we can support NULLS FIRST by doing (x IS NULL) OR [boundary value] - return; - } - auto &type = op.orders[0].expression->return_type; - if (!TypeIsIntegral(type.InternalType()) && type.id() != LogicalTypeId::VARCHAR) { - // only supported for integral types currently - return; - } - if (op.orders[0].expression->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { - // we can only pushdown on ORDER BY [col] currently - return; - } - auto &colref = op.orders[0].expression->Cast(); - vector columns; - JoinFilterPushdownColumn column; - column.probe_column_index = colref.binding; - columns.emplace_back(column); - vector pushdown_targets; - JoinFilterPushdownOptimizer::GetPushdownFilterTargets(*op.children[0], std::move(columns), pushdown_targets); - if (pushdown_targets.empty()) { - // no pushdown targets - return; - } - // found pushdown targets! generate dynamic filters - ExpressionType comparison_type; - if (op.orders[0].type == OrderType::ASCENDING) { - // for ascending order, we want the lowest N elements, so we filter on C <= [boundary] - // if we only have a single order clause, we can filter on C < boundary - comparison_type = - op.orders.size() == 1 ? ExpressionType::COMPARE_LESSTHAN : ExpressionType::COMPARE_LESSTHANOREQUALTO; - } else { - // for descending order, we want the highest N elements, so we filter on C >= [boundary] - // if we only have a single order clause, we can filter on C > boundary - comparison_type = - op.orders.size() == 1 ? ExpressionType::COMPARE_GREATERTHAN : ExpressionType::COMPARE_GREATERTHANOREQUALTO; - } - Value minimum_value = type.InternalType() == PhysicalType::VARCHAR ? Value("") : Value::MinimumValue(type); - auto base_filter = make_uniq(comparison_type, std::move(minimum_value)); - auto filter_data = make_shared_ptr(); - filter_data->filter = std::move(base_filter); - - // put the filter into the Top-N clause - op.dynamic_filter = filter_data; - - for (auto &target : pushdown_targets) { - auto &get = target.get; - D_ASSERT(target.columns.size() == 1); - auto col_idx = target.columns[0].probe_column_index.column_index; - - // create the actual dynamic filter - auto dynamic_filter = make_uniq(filter_data); - auto optional_filter = make_uniq(std::move(dynamic_filter)); - - // push the filter into the table scan - auto &column_index = get.GetColumnIds()[col_idx]; - get.table_filters.PushFilter(column_index, std::move(optional_filter)); - } -} - unique_ptr TopN::Optimize(unique_ptr op) { if (CanOptimize(*op)) { @@ -136,7 +66,6 @@ unique_ptr TopN::Optimize(unique_ptr op) { if (topn->children[0]->has_estimated_cardinality && topn->children[0]->estimated_cardinality < limit_val) { cardinality = topn->children[0]->estimated_cardinality; } - PushdownDynamicFilters(*topn); topn->SetEstimatedCardinality(cardinality); op = std::move(topn); diff --git a/src/duckdb/src/optimizer/unnest_rewriter.cpp b/src/duckdb/src/optimizer/unnest_rewriter.cpp index 4c4207e2a..796a9338b 100644 --- a/src/duckdb/src/optimizer/unnest_rewriter.cpp +++ b/src/duckdb/src/optimizer/unnest_rewriter.cpp @@ -19,7 +19,7 @@ void UnnestRewriterPlanUpdater::VisitOperator(LogicalOperator &op) { void UnnestRewriterPlanUpdater::VisitExpression(unique_ptr *expression) { auto &expr = *expression; - if (expr->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + if (expr->expression_class == ExpressionClass::BOUND_COLUMN_REF) { auto &bound_column_ref = expr->Cast(); for (idx_t i = 0; i < replace_bindings.size(); i++) { if (bound_column_ref.binding == replace_bindings[i].old_binding) { @@ -122,7 +122,7 @@ bool UnnestRewriter::RewriteCandidate(unique_ptr &candidate) { D_ASSERT(delim_join.type == LogicalOperatorType::LOGICAL_DELIM_JOIN); GetDelimColumns(delim_join); - // LHS of the LOGICAL_DELIM_JOIN is a LOGICAL_WINDOW that contains a LOGICAL_PROJECTION/LOGICAL_CROSS_JOIN + // LHS of the LOGICAL_DELIM_JOIN is a LOGICAL_WINDOW that contains a LOGICAL_PROJECTION // this lhs_proj later becomes the child of the UNNEST idx_t delim_idx = delim_join.delim_flipped ? 1 : 0; @@ -279,7 +279,7 @@ void UnnestRewriter::UpdateBoundUnnestBindings(UnnestRewriterPlanUpdater &update if (delim_binding.table_index == unnest_binding.table_index) { unnest_binding.table_index = overwritten_tbl_idx; - unnest_binding.column_index = i; + unnest_binding.column_index++; updater.replace_bindings.emplace_back(unnest_binding, delim_binding); unnest_cols.erase(unnest_it); break; @@ -301,7 +301,7 @@ void UnnestRewriter::GetDelimColumns(LogicalOperator &op) { auto &delim_join = op.Cast(); for (idx_t i = 0; i < delim_join.duplicate_eliminated_columns.size(); i++) { auto &expr = *delim_join.duplicate_eliminated_columns[i]; - D_ASSERT(expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF); + D_ASSERT(expr.type == ExpressionType::BOUND_COLUMN_REF); auto &bound_colref_expr = expr.Cast(); delim_columns.push_back(bound_colref_expr.binding); } @@ -326,7 +326,7 @@ void UnnestRewriter::GetLHSExpressions(LogicalOperator &op) { lhs_bindings.emplace_back(col_bindings[i], op.types[i]); if (set_alias) { auto &proj = op.Cast(); - lhs_bindings.back().alias = proj.expressions[i]->GetAlias(); + lhs_bindings.back().alias = proj.expressions[i]->alias; } } } diff --git a/src/duckdb/src/parallel/executor.cpp b/src/duckdb/src/parallel/executor.cpp index 487a9c3d0..9655c33ac 100644 --- a/src/duckdb/src/parallel/executor.cpp +++ b/src/duckdb/src/parallel/executor.cpp @@ -27,7 +27,7 @@ Executor::Executor(ClientContext &context) : context(context), executor_tasks(0) } Executor::~Executor() { - D_ASSERT(Exception::UncaughtException() || executor_tasks == 0); + D_ASSERT(executor_tasks == 0); } Executor &Executor::Get(ClientContext &context) { @@ -684,21 +684,39 @@ void Executor::Flush(ThreadContext &thread_context) { } } -idx_t Executor::GetPipelinesProgress(ProgressData &progress) { // LCOV_EXCL_START +bool Executor::GetPipelinesProgress(double ¤t_progress, uint64_t ¤t_cardinality, + uint64_t &total_cardinality) { // LCOV_EXCL_START lock_guard elock(executor_lock); - progress.done = 0; - progress.total = 0; - idx_t count_invalid = 0; + vector progress; + vector cardinality; + total_cardinality = 0; + current_cardinality = 0; for (auto &pipeline : pipelines) { - ProgressData p; - if (!pipeline->GetProgress(p)) { - count_invalid++; - } else { - progress.Add(p); + double child_percentage; + idx_t child_cardinality; + + if (!pipeline->GetProgress(child_percentage, child_cardinality)) { + return false; } + progress.push_back(child_percentage); + cardinality.push_back(child_cardinality); + total_cardinality += child_cardinality; + } + if (total_cardinality == 0) { + return true; } - return count_invalid; + current_progress = 0; + + for (size_t i = 0; i < progress.size(); i++) { + progress[i] = MaxValue(0.0, MinValue(100.0, progress[i])); + current_cardinality = LossyNumericCast(static_cast( + static_cast(current_cardinality) + + static_cast(progress[i]) * static_cast(cardinality[i]) / static_cast(100))); + current_progress += progress[i] * double(cardinality[i]) / double(total_cardinality); + D_ASSERT(current_cardinality <= total_cardinality); + } + return true; } // LCOV_EXCL_STOP bool Executor::HasResultCollector() { diff --git a/src/duckdb/src/parallel/executor_task.cpp b/src/duckdb/src/parallel/executor_task.cpp index ebd462f93..a1395f2f4 100644 --- a/src/duckdb/src/parallel/executor_task.cpp +++ b/src/duckdb/src/parallel/executor_task.cpp @@ -36,14 +36,9 @@ void ExecutorTask::Reschedule() { TaskExecutionResult ExecutorTask::Execute(TaskExecutionMode mode) { try { if (thread_context) { - TaskExecutionResult result; - do { - thread_context->profiler.StartOperator(op); - // to allow continuous profiling, always execute in small steps - result = ExecuteTask(TaskExecutionMode::PROCESS_PARTIAL); - thread_context->profiler.EndOperator(nullptr); - executor.Flush(*thread_context); - } while (mode == TaskExecutionMode::PROCESS_ALL && result == TaskExecutionResult::TASK_NOT_FINISHED); + thread_context->profiler.StartOperator(op); + auto result = ExecuteTask(mode); + thread_context->profiler.EndOperator(nullptr); return result; } else { return ExecuteTask(mode); diff --git a/src/duckdb/src/parallel/pipeline.cpp b/src/duckdb/src/parallel/pipeline.cpp index 4e15068fb..ca0443b9d 100644 --- a/src/duckdb/src/parallel/pipeline.cpp +++ b/src/duckdb/src/parallel/pipeline.cpp @@ -72,23 +72,17 @@ ClientContext &Pipeline::GetClientContext() { return executor.context; } -bool Pipeline::GetProgress(ProgressData &progress) { +bool Pipeline::GetProgress(double ¤t_percentage, idx_t &source_cardinality) { D_ASSERT(source); - idx_t source_cardinality = MinValue(source->estimated_cardinality, 1ULL << 48ULL); - if (source_cardinality < 1) { - source_cardinality = 1; - } + source_cardinality = MinValue(source->estimated_cardinality, 1ULL << 48ULL); if (!initialized) { - progress.done = 0; - progress.total = double(source_cardinality); + current_percentage = 0; return true; } auto &client = executor.context; - - progress = source->GetProgress(client, *source_state); - progress.Normalize(double(source_cardinality)); - progress = sink->GetSinkProgress(client, *sink->sink_state, progress); - return progress.IsValid(); + current_percentage = source->GetProgress(client, *source_state); + current_percentage = sink->GetSinkProgress(client, *sink->sink_state, current_percentage); + return current_percentage >= 0; } void Pipeline::ScheduleSequentialTask(shared_ptr &event) { @@ -111,9 +105,8 @@ bool Pipeline::ScheduleParallel(shared_ptr &event) { return false; } } - auto partition_info = sink->RequiredPartitionInfo(); - if (partition_info.batch_index) { - if (!source->SupportsPartitioning(OperatorPartitionInfo::BatchIndex())) { + if (sink->RequiresBatchIndex()) { + if (!source->SupportsBatchIndex()) { throw InternalException( "Attempting to schedule a pipeline where the sink requires batch index but source does not support it"); } diff --git a/src/duckdb/src/parallel/pipeline_executor.cpp b/src/duckdb/src/parallel/pipeline_executor.cpp index 4b32c99d9..105d46299 100644 --- a/src/duckdb/src/parallel/pipeline_executor.cpp +++ b/src/duckdb/src/parallel/pipeline_executor.cpp @@ -15,9 +15,8 @@ PipelineExecutor::PipelineExecutor(ClientContext &context_p, Pipeline &pipeline_ D_ASSERT(pipeline.source_state); if (pipeline.sink) { local_sink_state = pipeline.sink->GetLocalSinkState(context); - required_partition_info = pipeline.sink->RequiredPartitionInfo(); - if (required_partition_info.AnyRequired()) { - D_ASSERT(pipeline.source->SupportsPartitioning(OperatorPartitionInfo::BatchIndex())); + requires_batch_index = pipeline.sink->RequiresBatchIndex() && pipeline.source->SupportsBatchIndex(); + if (requires_batch_index) { auto &partition_info = local_sink_state->partition_info; D_ASSERT(!partition_info.batch_index.IsValid()); // batch index is not set yet - initialize before fetching anything @@ -49,7 +48,7 @@ PipelineExecutor::PipelineExecutor(ClientContext &context_p, Pipeline &pipeline_ InitializeChunk(final_chunk); } -bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { +bool PipelineExecutor::TryFlushCachingOperators() { if (!started_flushing) { // Remainder of this method assumes any in process operators are from flushing D_ASSERT(in_process_operators.empty()); @@ -57,9 +56,7 @@ bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { flushing_idx = IsFinished() ? idx_t(finished_processing_idx) : 0; } - // For each operator that supports FinalExecute, - // extract every chunk from it and push it through the rest of the pipeline - // before moving onto the next operators' FinalExecute + // Go over each operator and keep flushing them using `FinalExecute` until empty while (flushing_idx < pipeline.operators.size()) { if (!pipeline.operators[flushing_idx].get().RequiresFinalExecute()) { flushing_idx++; @@ -79,6 +76,7 @@ bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { auto ¤t_operator = pipeline.operators[flushing_idx].get(); OperatorFinalizeResultType finalize_result; + OperatorResultType push_result; if (in_process_operators.empty()) { curr_chunk.Reset(); @@ -91,7 +89,7 @@ bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { finalize_result = OperatorFinalizeResultType::HAVE_MORE_OUTPUT; } - auto push_result = ExecutePushInternal(curr_chunk, chunk_budget, flushing_idx + 1); + push_result = ExecutePushInternal(curr_chunk, flushing_idx + 1); if (finalize_result == OperatorFinalizeResultType::HAVE_MORE_OUTPUT) { should_flush_current_idx = true; @@ -99,58 +97,43 @@ bool PipelineExecutor::TryFlushCachingOperators(ExecutionBudget &chunk_budget) { should_flush_current_idx = false; } - switch (push_result) { - case OperatorResultType::BLOCKED: { + if (push_result == OperatorResultType::BLOCKED) { remaining_sink_chunk = true; return false; - } - case OperatorResultType::HAVE_MORE_OUTPUT: { - D_ASSERT(chunk_budget.IsDepleted()); - // The chunk budget was used up, pushing the chunk through the pipeline created more chunks - // we need to continue this the next time Execute is called. - return false; - } - case OperatorResultType::NEED_MORE_INPUT: - continue; - case OperatorResultType::FINISHED: + } else if (push_result == OperatorResultType::FINISHED) { break; - default: - throw InternalException("Unexpected OperatorResultType (%s) in TryFlushCachingOperators", - EnumUtil::ToString(push_result)); } - break; } return true; } -SinkNextBatchType PipelineExecutor::NextBatch(DataChunk &source_chunk) { - D_ASSERT(required_partition_info.AnyRequired()); +SinkNextBatchType PipelineExecutor::NextBatch(duckdb::DataChunk &source_chunk) { + D_ASSERT(requires_batch_index); + idx_t next_batch_index; auto max_batch_index = pipeline.base_batch_index + PipelineBuildState::BATCH_INCREMENT - 1; - // by default set it to the maximum valid batch index value for the current pipeline - OperatorPartitionData next_data(max_batch_index); - if (source_chunk.size() > 0) { - // if we retrieved data - initialize the next batch index - auto partition_data = pipeline.source->GetPartitionData(context, source_chunk, *pipeline.source_state, - *local_source_state, required_partition_info); - auto batch_index = partition_data.batch_index; + if (source_chunk.size() == 0) { + // set it to the maximum valid batch index value for the current pipeline + next_batch_index = max_batch_index; + } else { + auto batch_index = + pipeline.source->GetBatchIndex(context, source_chunk, *pipeline.source_state, *local_source_state); // we start with the base_batch_index as a valid starting value. Make sure that next batch is called below - next_data = std::move(partition_data); - next_data.batch_index = pipeline.base_batch_index + batch_index + 1; - if (next_data.batch_index >= max_batch_index) { + next_batch_index = pipeline.base_batch_index + batch_index + 1; + if (next_batch_index >= max_batch_index) { throw InternalException("Pipeline batch index - invalid batch index %llu returned by source operator", batch_index); } } auto &partition_info = local_sink_state->partition_info; - if (next_data.batch_index == partition_info.batch_index.GetIndex()) { + if (next_batch_index == partition_info.batch_index.GetIndex()) { // no changes, return return SinkNextBatchType::READY; } // batch index has changed - update it - if (partition_info.batch_index.GetIndex() > next_data.batch_index) { + if (partition_info.batch_index.GetIndex() > next_batch_index) { throw InternalException( "Pipeline batch index - gotten lower batch index %llu (down from previous batch index of %llu)", - next_data.batch_index, partition_info.batch_index.GetIndex()); + next_batch_index, partition_info.batch_index.GetIndex()); } #ifdef DUCKDB_DEBUG_ASYNC_SINK_SOURCE if (debug_blocked_next_batch_count < debug_blocked_target_count) { @@ -167,8 +150,7 @@ SinkNextBatchType PipelineExecutor::NextBatch(DataChunk &source_chunk) { } #endif auto current_batch = partition_info.batch_index.GetIndex(); - partition_info.batch_index = next_data.batch_index; - partition_info.partition_data = std::move(next_data.partition_data); + partition_info.batch_index = next_batch_index; OperatorSinkNextBatchInput next_batch_input {*pipeline.sink->sink_state, *local_sink_state, interrupt_state}; // call NextBatch before updating min_batch_index to provide the opportunity to flush the previous batch auto next_batch_result = pipeline.sink->NextBatch(context, next_batch_input); @@ -178,7 +160,7 @@ SinkNextBatchType PipelineExecutor::NextBatch(DataChunk &source_chunk) { return SinkNextBatchType::BLOCKED; } - partition_info.min_batch_index = pipeline.UpdateBatchIndex(current_batch, next_data.batch_index); + partition_info.min_batch_index = pipeline.UpdateBatchIndex(current_batch, next_batch_index); return SinkNextBatchType::READY; } @@ -186,8 +168,7 @@ SinkNextBatchType PipelineExecutor::NextBatch(DataChunk &source_chunk) { PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { D_ASSERT(pipeline.sink); auto &source_chunk = pipeline.operators.empty() ? final_chunk : *intermediate_chunks[0]; - ExecutionBudget chunk_budget(max_chunks); - do { + for (idx_t i = 0; i < max_chunks; i++) { if (context.client.interrupted) { throw InterruptException(); } @@ -198,27 +179,22 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { break; } else if (remaining_sink_chunk) { // The pipeline was interrupted by the Sink. We should retry sinking the final chunk. - result = ExecutePushInternal(final_chunk, chunk_budget); - D_ASSERT(result != OperatorResultType::HAVE_MORE_OUTPUT); + result = ExecutePushInternal(final_chunk); remaining_sink_chunk = false; } else if (!in_process_operators.empty() && !started_flushing) { - // Operator(s) in the pipeline have returned `HAVE_MORE_OUTPUT` in the last Execute call - // the operators have to be called with the same input chunk to produce the rest of the output + // The pipeline was interrupted by the Sink when pushing a source chunk through the pipeline. We need to + // re-push the same source chunk through the pipeline because there are in_process operators, meaning that + // the result for the pipeline D_ASSERT(source_chunk.size() > 0); - result = ExecutePushInternal(source_chunk, chunk_budget); + result = ExecutePushInternal(source_chunk); } else if (exhausted_source && !next_batch_blocked && !done_flushing) { // The source was exhausted, try flushing all operators - auto flush_completed = TryFlushCachingOperators(chunk_budget); + auto flush_completed = TryFlushCachingOperators(); if (flush_completed) { done_flushing = true; break; } else { - if (remaining_sink_chunk) { - return PipelineExecuteResult::INTERRUPTED; - } else { - D_ASSERT(chunk_budget.IsDepleted()); - return PipelineExecuteResult::NOT_FINISHED; - } + return PipelineExecuteResult::INTERRUPTED; } } else if (!exhausted_source || next_batch_blocked) { SourceResultType source_result; @@ -234,7 +210,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { } } - if (required_partition_info.AnyRequired()) { + if (requires_batch_index) { auto next_batch_result = NextBatch(source_chunk); next_batch_blocked = next_batch_result == SinkNextBatchType::BLOCKED; if (next_batch_blocked) { @@ -247,7 +223,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { continue; } - result = ExecutePushInternal(source_chunk, chunk_budget); + result = ExecutePushInternal(source_chunk); } else { throw InternalException("Unexpected state reached in pipeline executor"); } @@ -261,7 +237,7 @@ PipelineExecuteResult PipelineExecutor::Execute(idx_t max_chunks) { if (result == OperatorResultType::FINISHED) { break; } - } while (chunk_budget.Next()); + } if ((!exhausted_source || !done_flushing) && !IsFinished()) { return PipelineExecuteResult::NOT_FINISHED; @@ -278,6 +254,10 @@ PipelineExecuteResult PipelineExecutor::Execute() { return Execute(NumericLimits::Maximum()); } +OperatorResultType PipelineExecutor::ExecutePush(DataChunk &input) { // LCOV_EXCL_START + return ExecutePushInternal(input); +} // LCOV_EXCL_STOP + void PipelineExecutor::FinishProcessing(int32_t operator_idx) { finished_processing_idx = operator_idx < 0 ? NumericLimits::Maximum() : operator_idx; in_process_operators = stack(); @@ -298,8 +278,7 @@ bool PipelineExecutor::IsFinished() { return finished_processing_idx >= 0; } -OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, ExecutionBudget &chunk_budget, - idx_t initial_idx) { +OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, idx_t initial_idx) { D_ASSERT(pipeline.sink); if (input.size() == 0) { // LCOV_EXCL_START return OperatorResultType::NEED_MORE_INPUT; @@ -308,13 +287,11 @@ OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, Execu // this loop will continuously push the input chunk through the pipeline as long as: // - the OperatorResultType for the Execute is HAVE_MORE_OUTPUT // - the Sink doesn't block - // - the ExecutionBudget has not been depleted - OperatorResultType result = OperatorResultType::HAVE_MORE_OUTPUT; - do { + while (true) { + OperatorResultType result; // Note: if input is the final_chunk, we don't do any executing, the chunk just needs to be sinked if (&input != &final_chunk) { final_chunk.Reset(); - // Execute and put the result into 'final_chunk' result = Execute(input, final_chunk, initial_idx); if (result == OperatorResultType::FINISHED) { return OperatorResultType::FINISHED; @@ -343,8 +320,7 @@ OperatorResultType PipelineExecutor::ExecutePushInternal(DataChunk &input, Execu if (result == OperatorResultType::NEED_MORE_INPUT) { return OperatorResultType::NEED_MORE_INPUT; } - } while (chunk_budget.Next()); - return result; + } } PipelineExecuteResult PipelineExecutor::PushFinalize() { diff --git a/src/duckdb/src/parser/column_definition.cpp b/src/duckdb/src/parser/column_definition.cpp index 4718c40c1..245bcd47d 100644 --- a/src/duckdb/src/parser/column_definition.cpp +++ b/src/duckdb/src/parser/column_definition.cpp @@ -123,7 +123,7 @@ bool ColumnDefinition::Generated() const { //===--------------------------------------------------------------------===// static void VerifyColumnRefs(ParsedExpression &expr) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &column_ref = expr.Cast(); if (column_ref.IsQualified()) { throw ParserException( @@ -135,13 +135,13 @@ static void VerifyColumnRefs(ParsedExpression &expr) { } static void InnerGetListOfDependencies(ParsedExpression &expr, vector &dependencies) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto columnref = expr.Cast(); auto &name = columnref.GetColumnName(); dependencies.push_back(name); } ParsedExpressionIterator::EnumerateChildren(expr, [&](const ParsedExpression &child) { - if (expr.GetExpressionType() == ExpressionType::LAMBDA) { + if (expr.type == ExpressionType::LAMBDA) { throw NotImplementedException("Lambda functions are currently not supported in generated columns."); } InnerGetListOfDependencies((ParsedExpression &)child, dependencies); diff --git a/src/duckdb/src/parser/constraints/unique_constraint.cpp b/src/duckdb/src/parser/constraints/unique_constraint.cpp index 51c4631b3..8613231eb 100644 --- a/src/duckdb/src/parser/constraints/unique_constraint.cpp +++ b/src/duckdb/src/parser/constraints/unique_constraint.cpp @@ -1,5 +1,6 @@ #include "duckdb/parser/constraints/unique_constraint.hpp" +#include "duckdb/common/limits.hpp" #include "duckdb/parser/keyword_helper.hpp" namespace duckdb { @@ -7,11 +8,10 @@ namespace duckdb { UniqueConstraint::UniqueConstraint() : Constraint(ConstraintType::UNIQUE), index(DConstants::INVALID_INDEX) { } -UniqueConstraint::UniqueConstraint(const LogicalIndex index, const bool is_primary_key) +UniqueConstraint::UniqueConstraint(LogicalIndex index, bool is_primary_key) : Constraint(ConstraintType::UNIQUE), index(index), is_primary_key(is_primary_key) { } - -UniqueConstraint::UniqueConstraint(vector columns, const bool is_primary_key) +UniqueConstraint::UniqueConstraint(vector columns, bool is_primary_key) : Constraint(ConstraintType::UNIQUE), index(DConstants::INVALID_INDEX), columns(std::move(columns)), is_primary_key(is_primary_key) { } @@ -30,76 +30,13 @@ string UniqueConstraint::ToString() const { unique_ptr UniqueConstraint::Copy() const { if (!HasIndex()) { return make_uniq(columns, is_primary_key); + } else { + auto result = make_uniq(index, is_primary_key); + if (!columns.empty()) { + result->columns.push_back(columns[0]); + } + return std::move(result); } - - auto result = make_uniq(index, is_primary_key); - if (!columns.empty()) { - result->columns.push_back(columns[0]); - } - return std::move(result); -} - -bool UniqueConstraint::IsPrimaryKey() const { - return is_primary_key; -} - -bool UniqueConstraint::HasIndex() const { - return index.index != DConstants::INVALID_INDEX; -} - -LogicalIndex UniqueConstraint::GetIndex() const { - if (!HasIndex()) { - throw InternalException("UniqueConstraint::GetIndex called on a unique constraint without an index"); - } - return index; -} - -void UniqueConstraint::SetIndex(const LogicalIndex new_index) { - D_ASSERT(new_index.index != DConstants::INVALID_INDEX); - index = new_index; -} - -const vector &UniqueConstraint::GetColumnNames() const { - D_ASSERT(!columns.empty()); - return columns; -} - -vector &UniqueConstraint::GetColumnNamesMutable() { - D_ASSERT(!columns.empty()); - return columns; -} - -vector UniqueConstraint::GetLogicalIndexes(const ColumnList &column_list) const { - if (HasIndex()) { - return {GetIndex()}; - } - - vector indexes; - for (auto &col_name : GetColumnNames()) { - D_ASSERT(column_list.ColumnExists(col_name)); - auto &col = column_list.GetColumn(col_name); - D_ASSERT(!col.Generated()); - indexes.push_back(col.Logical()); - } - return indexes; -} - -string UniqueConstraint::GetName(const string &table_name) const { - auto type = IsPrimaryKey() ? IndexConstraintType::PRIMARY : IndexConstraintType::UNIQUE; - auto type_name = EnumUtil::ToString(type); - - string name; - for (const auto &column_name : GetColumnNames()) { - name += "_" + column_name; - } - return type_name + "_" + table_name + name; -} - -void UniqueConstraint::SetColumnName(const string &column_name) { - if (!columns.empty()) { - return; - } - columns.push_back(column_name); } } // namespace duckdb diff --git a/src/duckdb/src/parser/expression/columnref_expression.cpp b/src/duckdb/src/parser/expression/columnref_expression.cpp index c1eb6e9cd..70720f97d 100644 --- a/src/duckdb/src/parser/expression/columnref_expression.cpp +++ b/src/duckdb/src/parser/expression/columnref_expression.cpp @@ -3,7 +3,9 @@ #include "duckdb/common/types/hash.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/parser/qualified_name.hpp" -#include "duckdb/planner/binding_alias.hpp" + +#include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" namespace duckdb { @@ -15,20 +17,6 @@ ColumnRefExpression::ColumnRefExpression(string column_name, string table_name) : vector {std::move(table_name), std::move(column_name)}) { } -ColumnRefExpression::ColumnRefExpression(string column_name, const BindingAlias &alias) - : ParsedExpression(ExpressionType::COLUMN_REF, ExpressionClass::COLUMN_REF) { - if (alias.IsSet()) { - if (!alias.GetCatalog().empty()) { - column_names.push_back(alias.GetCatalog()); - } - if (!alias.GetSchema().empty()) { - column_names.push_back(alias.GetSchema()); - } - column_names.push_back(alias.GetAlias()); - } - column_names.push_back(std::move(column_name)); -} - ColumnRefExpression::ColumnRefExpression(string column_name) : ColumnRefExpression(vector {std::move(column_name)}) { } diff --git a/src/duckdb/src/parser/expression/conjunction_expression.cpp b/src/duckdb/src/parser/expression/conjunction_expression.cpp index a11759b8f..78a076bff 100644 --- a/src/duckdb/src/parser/expression/conjunction_expression.cpp +++ b/src/duckdb/src/parser/expression/conjunction_expression.cpp @@ -26,7 +26,7 @@ ConjunctionExpression::ConjunctionExpression(ExpressionType type, unique_ptr expr) { - if (expr->GetExpressionType() == type) { + if (expr->type == type) { // expr is a conjunction of the same type: merge the expression lists together auto &other = expr->Cast(); for (auto &child : other.children) { diff --git a/src/duckdb/src/parser/expression/function_expression.cpp b/src/duckdb/src/parser/expression/function_expression.cpp index a38b3024e..8cd5d4c70 100644 --- a/src/duckdb/src/parser/expression/function_expression.cpp +++ b/src/duckdb/src/parser/expression/function_expression.cpp @@ -102,7 +102,7 @@ bool FunctionExpression::IsLambdaFunction() const { } // Check the children for lambda expressions. for (auto &child : children) { - if (child->GetExpressionClass() == ExpressionClass::LAMBDA) { + if (child->expression_class == ExpressionClass::LAMBDA) { return true; } } diff --git a/src/duckdb/src/parser/expression/lambda_expression.cpp b/src/duckdb/src/parser/expression/lambda_expression.cpp index bdf32e6c0..be5034114 100644 --- a/src/duckdb/src/parser/expression/lambda_expression.cpp +++ b/src/duckdb/src/parser/expression/lambda_expression.cpp @@ -22,13 +22,13 @@ vector> LambdaExpression::ExtractColumnRefExpression // since we can't distinguish between a lambda function and the JSON operator yet vector> column_refs; - if (lhs->GetExpressionClass() == ExpressionClass::COLUMN_REF) { + if (lhs->expression_class == ExpressionClass::COLUMN_REF) { // single column reference column_refs.emplace_back(*lhs); return column_refs; } - if (lhs->GetExpressionClass() == ExpressionClass::FUNCTION) { + if (lhs->expression_class == ExpressionClass::FUNCTION) { // list of column references auto &func_expr = lhs->Cast(); if (func_expr.function_name != "row") { @@ -37,7 +37,7 @@ vector> LambdaExpression::ExtractColumnRefExpression } for (auto &child : func_expr.children) { - if (child->GetExpressionClass() != ExpressionClass::COLUMN_REF) { + if (child->expression_class != ExpressionClass::COLUMN_REF) { error_message = InvalidParametersErrorMessage(); return column_refs; } diff --git a/src/duckdb/src/parser/expression/lambdaref_expression.cpp b/src/duckdb/src/parser/expression/lambdaref_expression.cpp index fed844fea..786d10912 100644 --- a/src/duckdb/src/parser/expression/lambdaref_expression.cpp +++ b/src/duckdb/src/parser/expression/lambdaref_expression.cpp @@ -47,7 +47,7 @@ LambdaRefExpression::FindMatchingBinding(optional_ptr> &lam if (lambda_bindings) { for (idx_t i = lambda_bindings->size(); i > 0; i--) { if ((*lambda_bindings)[i - 1].HasMatchingBinding(column_name)) { - D_ASSERT((*lambda_bindings)[i - 1].alias.IsSet()); + D_ASSERT(!(*lambda_bindings)[i - 1].alias.empty()); return make_uniq(i - 1, column_name); } } diff --git a/src/duckdb/src/parser/expression/star_expression.cpp b/src/duckdb/src/parser/expression/star_expression.cpp index 22279f121..3589b9533 100644 --- a/src/duckdb/src/parser/expression/star_expression.cpp +++ b/src/duckdb/src/parser/expression/star_expression.cpp @@ -33,7 +33,7 @@ string StarExpression::ToString() const { if (!first_entry) { result += ", "; } - result += entry.ToString(); + result += KeywordHelper::WriteOptionallyQuoted(entry); first_entry = false; } result += ")"; @@ -52,20 +52,6 @@ string StarExpression::ToString() const { } result += ")"; } - if (!rename_list.empty()) { - result += " RENAME ("; - bool first_entry = true; - for (auto &entry : rename_list) { - if (!first_entry) { - result += ", "; - } - result += entry.first.ToString(); - result += " AS "; - result += KeywordHelper::WriteOptionallyQuoted(entry.second); - first_entry = false; - } - result += ")"; - } if (columns) { result += ")"; } @@ -73,7 +59,7 @@ string StarExpression::ToString() const { } bool StarExpression::Equal(const StarExpression &a, const StarExpression &b) { - if (a.relation_name != b.relation_name || a.exclude_list != b.exclude_list || a.rename_list != b.rename_list) { + if (a.relation_name != b.relation_name || a.exclude_list != b.exclude_list) { return false; } if (a.columns != b.columns) { @@ -130,7 +116,6 @@ unique_ptr StarExpression::Copy() const { for (auto &entry : replace_list) { copy->replace_list[entry.first] = entry.second->Copy(); } - copy->rename_list = rename_list; copy->columns = columns; copy->expr = expr ? expr->Copy() : nullptr; copy->CopyProperties(*this); @@ -138,33 +123,4 @@ unique_ptr StarExpression::Copy() const { return std::move(copy); } -StarExpression::StarExpression(const case_insensitive_set_t &exclude_list_p, qualified_column_set_t qualified_set) - : ParsedExpression(ExpressionType::STAR, ExpressionClass::STAR), exclude_list(std::move(qualified_set)) { - for (auto &entry : exclude_list_p) { - exclude_list.insert(QualifiedColumnName(entry)); - } -} - -case_insensitive_set_t StarExpression::SerializedExcludeList() const { - // we serialize non-qualified elements in a separate list of only column names for backwards compatibility - case_insensitive_set_t result; - for (auto &entry : exclude_list) { - if (!entry.IsQualified()) { - result.insert(entry.column); - } - } - return result; -} - -qualified_column_set_t StarExpression::SerializedQualifiedExcludeList() const { - // we serialize only qualified elements in the qualified list for backwards compatibility - qualified_column_set_t result; - for (auto &entry : exclude_list) { - if (entry.IsQualified()) { - result.insert(entry); - } - } - return result; -} - } // namespace duckdb diff --git a/src/duckdb/src/parser/expression/window_expression.cpp b/src/duckdb/src/parser/expression/window_expression.cpp index 666bfbd3f..66e7fe835 100644 --- a/src/duckdb/src/parser/expression/window_expression.cpp +++ b/src/duckdb/src/parser/expression/window_expression.cpp @@ -82,29 +82,13 @@ bool WindowExpression::Equal(const WindowExpression &a, const WindowExpression & if (a.exclude_clause != b.exclude_clause) { return false; } - // check if the framing expressions are equivalent + // check if the framing expressions are equivalentbind_ if (!ParsedExpression::Equals(a.start_expr, b.start_expr) || !ParsedExpression::Equals(a.end_expr, b.end_expr) || !ParsedExpression::Equals(a.offset_expr, b.offset_expr) || !ParsedExpression::Equals(a.default_expr, b.default_expr)) { return false; } - // check if the argument orderings are equivalent - if (a.arg_orders.size() != b.arg_orders.size()) { - return false; - } - for (idx_t i = 0; i < a.arg_orders.size(); i++) { - if (a.arg_orders[i].type != b.arg_orders[i].type) { - return false; - } - if (a.arg_orders[i].null_order != b.arg_orders[i].null_order) { - return false; - } - if (!a.arg_orders[i].expression->Equals(*b.arg_orders[i].expression)) { - return false; - } - } - // check if the partitions are equivalent if (!ParsedExpression::ListEquals(a.partitions, b.partitions)) { return false; @@ -117,9 +101,6 @@ bool WindowExpression::Equal(const WindowExpression &a, const WindowExpression & if (a.orders[i].type != b.orders[i].type) { return false; } - if (a.orders[i].null_order != b.orders[i].null_order) { - return false; - } if (!a.orders[i].expression->Equals(*b.orders[i].expression)) { return false; } @@ -148,10 +129,6 @@ unique_ptr WindowExpression::Copy() const { new_window->orders.emplace_back(o.type, o.null_order, o.expression->Copy()); } - for (auto &o : arg_orders) { - new_window->arg_orders.emplace_back(o.type, o.null_order, o.expression->Copy()); - } - new_window->filter_expr = filter_expr ? filter_expr->Copy() : nullptr; new_window->start = start; diff --git a/src/duckdb/src/parser/parsed_data/alter_info.cpp b/src/duckdb/src/parser/parsed_data/alter_info.cpp index 2f90d0abf..e4a78ba91 100644 --- a/src/duckdb/src/parser/parsed_data/alter_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_info.cpp @@ -1,8 +1,7 @@ #include "duckdb/parser/parsed_data/alter_info.hpp" - -#include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" #include "duckdb/parser/parsed_data/alter_table_info.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" +#include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" +#include "duckdb/parser/parsed_data/alter_table_function_info.hpp" namespace duckdb { @@ -26,27 +25,4 @@ AlterEntryData AlterInfo::GetAlterEntryData() const { return data; } -bool AlterInfo::IsAddPrimaryKey() const { - if (type != AlterType::ALTER_TABLE) { - return false; - } - - auto &table_info = Cast(); - if (table_info.alter_table_type != AlterTableType::ADD_CONSTRAINT) { - return false; - } - - auto &constraint_info = table_info.Cast(); - if (constraint_info.constraint->type != ConstraintType::UNIQUE) { - return false; - } - - auto &unique_info = constraint_info.constraint->Cast(); - if (!unique_info.IsPrimaryKey()) { - return false; - } - - return true; -} - } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp b/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp index 3de4fc52a..269a87d66 100644 --- a/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp @@ -1,5 +1,5 @@ #include "duckdb/parser/parsed_data/alter_scalar_function_info.hpp" -#include "duckdb/parser/parsed_data/create_scalar_function_info.hpp" + #include "duckdb/parser/constraint.hpp" namespace duckdb { @@ -22,8 +22,7 @@ CatalogType AlterScalarFunctionInfo::GetCatalogType() const { //===--------------------------------------------------------------------===// // AddScalarFunctionOverloadInfo //===--------------------------------------------------------------------===// -AddScalarFunctionOverloadInfo::AddScalarFunctionOverloadInfo(AlterEntryData data, - unique_ptr new_overloads_p) +AddScalarFunctionOverloadInfo::AddScalarFunctionOverloadInfo(AlterEntryData data, ScalarFunctionSet new_overloads_p) : AlterScalarFunctionInfo(AlterScalarFunctionType::ADD_FUNCTION_OVERLOADS, std::move(data)), new_overloads(std::move(new_overloads_p)) { this->allow_internal = true; @@ -33,8 +32,7 @@ AddScalarFunctionOverloadInfo::~AddScalarFunctionOverloadInfo() { } unique_ptr AddScalarFunctionOverloadInfo::Copy() const { - return make_uniq_base( - GetAlterEntryData(), unique_ptr_cast(new_overloads->Copy())); + return make_uniq_base(GetAlterEntryData(), new_overloads); } string AddScalarFunctionOverloadInfo::ToString() const { diff --git a/src/duckdb/src/parser/parsed_data/alter_table_info.cpp b/src/duckdb/src/parser/parsed_data/alter_table_info.cpp index ddf7db07d..1a82ca1fd 100644 --- a/src/duckdb/src/parser/parsed_data/alter_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/alter_table_info.cpp @@ -261,9 +261,7 @@ string ChangeColumnTypeInfo::ToString() const { result += " ALTER COLUMN "; result += KeywordHelper::WriteOptionallyQuoted(column_name); result += " TYPE "; - if (target_type.IsValid()) { - result += target_type.ToString(); - } + result += target_type.ToString(); // FIXME: ToSQLString ? auto extra_type_info = target_type.AuxInfo(); if (extra_type_info && extra_type_info->type == ExtraTypeInfoType::STRING_TYPE_INFO) { auto &string_info = extra_type_info->Cast(); @@ -447,30 +445,4 @@ string RenameViewInfo::ToString() const { return result; } -//===--------------------------------------------------------------------===// -// AddConstraintInfo -//===--------------------------------------------------------------------===// -AddConstraintInfo::AddConstraintInfo() : AlterTableInfo(AlterTableType::ADD_CONSTRAINT) { -} - -AddConstraintInfo::AddConstraintInfo(AlterEntryData data, unique_ptr constraint_p) - : AlterTableInfo(AlterTableType::ADD_CONSTRAINT, std::move(data)), constraint(std::move(constraint_p)) { -} - -AddConstraintInfo::~AddConstraintInfo() { -} - -unique_ptr AddConstraintInfo::Copy() const { - return make_uniq_base(GetAlterEntryData(), constraint->Copy()); -} - -string AddConstraintInfo::ToString() const { - string result = "ALTER TABLE "; - result += QualifierToString(catalog, schema, name); - result += " ADD "; - result += constraint->ToString(); - result += ";"; - return result; -} - } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/attach_info.cpp b/src/duckdb/src/parser/parsed_data/attach_info.cpp index 3ad50d8bb..63cf8b66c 100644 --- a/src/duckdb/src/parser/parsed_data/attach_info.cpp +++ b/src/duckdb/src/parser/parsed_data/attach_info.cpp @@ -6,18 +6,18 @@ namespace duckdb { -StorageOptions AttachInfo::GetStorageOptions() const { - StorageOptions storage_options; +optional_idx AttachInfo::GetBlockAllocSize() const { + for (auto &entry : options) { if (entry.first == "block_size") { // Extract the block allocation size. This is NOT the actual memory available on a block (block_size), // even though the corresponding option we expose to the user is called "block_size". - storage_options.block_alloc_size = entry.second.GetValue(); - } else if (entry.first == "row_group_size") { - storage_options.row_group_size = entry.second.GetValue(); + idx_t block_alloc_size = UBigIntValue::Get(entry.second.DefaultCastAs(LogicalType::UBIGINT)); + Storage::VerifyBlockAllocSize(block_alloc_size); + return block_alloc_size; } } - return storage_options; + return optional_idx(); } unique_ptr AttachInfo::Copy() const { diff --git a/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp index 4e7476b88..8e4f31e20 100644 --- a/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_aggregate_function_info.cpp @@ -20,7 +20,7 @@ CreateAggregateFunctionInfo::CreateAggregateFunctionInfo(AggregateFunctionSet se unique_ptr CreateAggregateFunctionInfo::Copy() const { auto result = make_uniq(functions); - CopyFunctionProperties(*result); + CopyProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_function_info.cpp deleted file mode 100644 index 2c3dde835..000000000 --- a/src/duckdb/src/parser/parsed_data/create_function_info.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "duckdb/parser/parsed_data/create_function_info.hpp" - -namespace duckdb { - -CreateFunctionInfo::CreateFunctionInfo(CatalogType type, string schema) : CreateInfo(type, std::move(schema)) { - D_ASSERT(type == CatalogType::SCALAR_FUNCTION_ENTRY || type == CatalogType::AGGREGATE_FUNCTION_ENTRY || - type == CatalogType::TABLE_FUNCTION_ENTRY || type == CatalogType::PRAGMA_FUNCTION_ENTRY || - type == CatalogType::MACRO_ENTRY || type == CatalogType::TABLE_MACRO_ENTRY); -} - -void CreateFunctionInfo::CopyFunctionProperties(CreateFunctionInfo &other) const { - CopyProperties(other); - other.name = name; - other.descriptions = descriptions; -} - -} // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_index_info.cpp b/src/duckdb/src/parser/parsed_data/create_index_info.cpp index 1d062a702..01e2840fa 100644 --- a/src/duckdb/src/parser/parsed_data/create_index_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_index_info.cpp @@ -1,7 +1,6 @@ #include "duckdb/parser/parsed_data/create_index_info.hpp" - -#include "duckdb/parser/expression/columnref_expression.hpp" #include "duckdb/parser/parsed_expression_iterator.hpp" +#include "duckdb/parser/expression/columnref_expression.hpp" namespace duckdb { @@ -15,17 +14,16 @@ CreateIndexInfo::CreateIndexInfo(const duckdb::CreateIndexInfo &info) } static void RemoveTableQualificationRecursive(unique_ptr &expr, const string &table_name) { - if (expr->GetExpressionType() != ExpressionType::COLUMN_REF) { + if (expr->GetExpressionType() == ExpressionType::COLUMN_REF) { + auto &col_ref = expr->Cast(); + auto &col_names = col_ref.column_names; + if (col_ref.IsQualified() && col_ref.GetTableName() == table_name) { + col_names.erase(col_names.begin()); + } + } else { ParsedExpressionIterator::EnumerateChildren(*expr, [&table_name](unique_ptr &child) { RemoveTableQualificationRecursive(child, table_name); }); - return; - } - - auto &col_ref = expr->Cast(); - auto &col_names = col_ref.column_names; - if (col_ref.IsQualified() && col_ref.GetTableName() == table_name) { - col_names.erase(col_names.begin()); } } @@ -35,19 +33,18 @@ vector CreateIndexInfo::ExpressionsToList() const { for (idx_t i = 0; i < parsed_expressions.size(); i++) { auto &expr = parsed_expressions[i]; auto copy = expr->Copy(); - - // Column reference expressions are qualified with the table name. - // We need to remove them to reproduce the original query. + // column ref expressions are qualified with the table name + // we need to remove them to reproduce the original query RemoveTableQualificationRecursive(copy, table); bool add_parenthesis = true; - if (copy->GetExpressionType() == ExpressionType::COLUMN_REF) { + if (copy->type == ExpressionType::COLUMN_REF) { auto &column_ref = copy->Cast(); if (!column_ref.IsQualified()) { - // Only not qualified references like (col1, col2) don't need parenthesis. + // Only when column references are not qualified, i.e (col1, col2) + // then these expressions do not need to be wrapped in parenthesis add_parenthesis = false; } } - if (add_parenthesis) { list.push_back(StringUtil::Format("(%s)", copy->ToString())); } else { @@ -102,6 +99,7 @@ string CreateIndexInfo::ToString() const { } unique_ptr CreateIndexInfo::Copy() const { + auto result = make_uniq(*this); CopyProperties(*result); @@ -111,6 +109,7 @@ unique_ptr CreateIndexInfo::Copy() const { for (auto &expr : parsed_expressions) { result->parsed_expressions.push_back(expr->Copy()); } + return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_macro_info.cpp b/src/duckdb/src/parser/parsed_data/create_macro_info.cpp index 0891b32dc..a732eac58 100644 --- a/src/duckdb/src/parser/parsed_data/create_macro_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_macro_info.cpp @@ -46,7 +46,7 @@ unique_ptr CreateMacroInfo::Copy() const { result->macros.push_back(macro->Copy()); } result->name = name; - CopyFunctionProperties(*result); + CopyProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp index 7e38ee885..6d2c8a154 100644 --- a/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_pragma_function_info.cpp @@ -16,7 +16,7 @@ CreatePragmaFunctionInfo::CreatePragmaFunctionInfo(string name, PragmaFunctionSe unique_ptr CreatePragmaFunctionInfo::Copy() const { auto result = make_uniq(functions.name, functions); - CopyFunctionProperties(*result); + CopyProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp index 51598a72e..6d01bcfb3 100644 --- a/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp @@ -22,14 +22,13 @@ unique_ptr CreateScalarFunctionInfo::Copy() const { ScalarFunctionSet set(name); set.functions = functions.functions; auto result = make_uniq(std::move(set)); - CopyFunctionProperties(*result); + CopyProperties(*result); return std::move(result); } unique_ptr CreateScalarFunctionInfo::GetAlterInfo() const { return make_uniq_base( - AlterEntryData(catalog, schema, name, OnEntryNotFound::RETURN_NULL), - unique_ptr_cast(Copy())); + AlterEntryData(catalog, schema, name, OnEntryNotFound::RETURN_NULL), functions); } } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_data/create_schema_info.cpp b/src/duckdb/src/parser/parsed_data/create_schema_info.cpp index e7c7f3f8b..36796b952 100644 --- a/src/duckdb/src/parser/parsed_data/create_schema_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_schema_info.cpp @@ -22,7 +22,7 @@ string CreateSchemaInfo::ToString() const { break; } case OnCreateConflict::IGNORE_ON_CONFLICT: { - ret += "CREATE SCHEMA IF NOT EXISTS " + qualified + ";"; + ret += "CREATE SCHEMA " + qualified + " IF NOT EXISTS;"; break; } case OnCreateConflict::REPLACE_ON_CONFLICT: { diff --git a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp index 3e774fba9..c2d297b5e 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp @@ -22,7 +22,7 @@ unique_ptr CreateTableFunctionInfo::Copy() const { TableFunctionSet set(name); set.functions = functions.functions; auto result = make_uniq(std::move(set)); - CopyFunctionProperties(*result); + CopyProperties(*result); return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/create_table_info.cpp b/src/duckdb/src/parser/parsed_data/create_table_info.cpp index 0568a8fd1..c9df25783 100644 --- a/src/duckdb/src/parser/parsed_data/create_table_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_table_info.cpp @@ -47,7 +47,6 @@ string CreateTableInfo::ToString() const { ret += QualifierToString(temporary ? "" : catalog, schema, table); if (query != nullptr) { - ret += TableCatalogEntry::ColumnNamesToSQL(columns); ret += " AS " + query->ToString(); } else { ret += TableCatalogEntry::ColumnsToSQL(columns, constraints) + ";"; diff --git a/src/duckdb/src/parser/parsed_data/create_type_info.cpp b/src/duckdb/src/parser/parsed_data/create_type_info.cpp index 1ce0327c3..3c0472c9f 100644 --- a/src/duckdb/src/parser/parsed_data/create_type_info.cpp +++ b/src/duckdb/src/parser/parsed_data/create_type_info.cpp @@ -6,11 +6,11 @@ namespace duckdb { -CreateTypeInfo::CreateTypeInfo() : CreateInfo(CatalogType::TYPE_ENTRY), bind_function(nullptr) { +CreateTypeInfo::CreateTypeInfo() : CreateInfo(CatalogType::TYPE_ENTRY), bind_modifiers(nullptr) { } -CreateTypeInfo::CreateTypeInfo(string name_p, LogicalType type_p, bind_logical_type_function_t bind_function_p) +CreateTypeInfo::CreateTypeInfo(string name_p, LogicalType type_p, bind_type_modifiers_function_t bind_modifiers_p) : CreateInfo(CatalogType::TYPE_ENTRY), name(std::move(name_p)), type(std::move(type_p)), - bind_function(bind_function_p) { + bind_modifiers(bind_modifiers_p) { } unique_ptr CreateTypeInfo::Copy() const { @@ -21,7 +21,7 @@ unique_ptr CreateTypeInfo::Copy() const { if (query) { result->query = query->Copy(); } - result->bind_function = bind_function; + result->bind_modifiers = bind_modifiers; return std::move(result); } diff --git a/src/duckdb/src/parser/parsed_data/load_info.cpp b/src/duckdb/src/parser/parsed_data/load_info.cpp index ea1fae141..30142961c 100644 --- a/src/duckdb/src/parser/parsed_data/load_info.cpp +++ b/src/duckdb/src/parser/parsed_data/load_info.cpp @@ -11,7 +11,6 @@ unique_ptr LoadInfo::Copy() const { result->repository = repository; result->load_type = load_type; result->repo_is_alias = repo_is_alias; - result->version = version; return result; } diff --git a/src/duckdb/src/parser/parsed_data/sample_options.cpp b/src/duckdb/src/parser/parsed_data/sample_options.cpp index 54be9d1cb..03c8b322a 100644 --- a/src/duckdb/src/parser/parsed_data/sample_options.cpp +++ b/src/duckdb/src/parser/parsed_data/sample_options.cpp @@ -9,30 +9,15 @@ string SampleMethodToString(SampleMethod method) { return EnumUtil::ToString(method); } -SampleOptions::SampleOptions(int64_t seed_) { - repeatable = false; - if (seed_ >= 0) { - seed = static_cast(seed_); - } - sample_size = 0; - is_percentage = false; - method = SampleMethod::INVALID; -} - unique_ptr SampleOptions::Copy() { auto result = make_uniq(); result->sample_size = sample_size; result->is_percentage = is_percentage; result->method = method; result->seed = seed; - result->repeatable = repeatable; return result; } -void SampleOptions::SetSeed(idx_t new_seed) { - seed = new_seed; -} - bool SampleOptions::Equals(SampleOptions *a, SampleOptions *b) { if (a == b) { return true; @@ -40,26 +25,11 @@ bool SampleOptions::Equals(SampleOptions *a, SampleOptions *b) { if (!a || !b) { return false; } - // if only one is valid, they are not equal - if (a->seed.IsValid() != b->seed.IsValid()) { - return false; - } - // if both are invalid, then they are technically the same - if (!a->seed.IsValid() && !b->seed.IsValid()) { - return true; - } if (a->sample_size != b->sample_size || a->is_percentage != b->is_percentage || a->method != b->method || - a->seed.GetIndex() != b->seed.GetIndex()) { + a->seed != b->seed) { return false; } return true; } -int64_t SampleOptions::GetSeed() const { - if (seed.IsValid()) { - return static_cast(seed.GetIndex()); - } - return -1; -} - } // namespace duckdb diff --git a/src/duckdb/src/parser/parsed_expression.cpp b/src/duckdb/src/parser/parsed_expression.cpp index 1ba33bfd8..617d60a3d 100644 --- a/src/duckdb/src/parser/parsed_expression.cpp +++ b/src/duckdb/src/parser/parsed_expression.cpp @@ -94,7 +94,7 @@ bool ParsedExpression::Equals(const BaseExpression &other) const { } hash_t ParsedExpression::Hash() const { - hash_t hash = duckdb::Hash(static_cast(type)); + hash_t hash = duckdb::Hash((uint32_t)type); ParsedExpressionIterator::EnumerateChildren( *this, [&](const ParsedExpression &child) { hash = CombineHash(child.Hash(), hash); }); return hash; diff --git a/src/duckdb/src/parser/parsed_expression_iterator.cpp b/src/duckdb/src/parser/parsed_expression_iterator.cpp index ca1df3a6b..8b29ed7fe 100644 --- a/src/duckdb/src/parser/parsed_expression_iterator.cpp +++ b/src/duckdb/src/parser/parsed_expression_iterator.cpp @@ -28,7 +28,7 @@ void ParsedExpressionIterator::EnumerateChildren(ParsedExpression &expr, void ParsedExpressionIterator::EnumerateChildren( ParsedExpression &expr, const std::function &child)> &callback) { - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BETWEEN: { auto &cast_expr = expr.Cast(); callback(cast_expr.input); @@ -140,9 +140,6 @@ void ParsedExpressionIterator::EnumerateChildren( if (window_expr.default_expr) { callback(window_expr.default_expr); } - for (auto &order : window_expr.arg_orders) { - callback(order.expression); - } break; } case ExpressionClass::BOUND_EXPRESSION: diff --git a/src/duckdb/src/parser/parser.cpp b/src/duckdb/src/parser/parser.cpp index 77ad899f1..0feef2aaa 100644 --- a/src/duckdb/src/parser/parser.cpp +++ b/src/duckdb/src/parser/parser.cpp @@ -1,6 +1,5 @@ #include "duckdb/parser/parser.hpp" -#include "duckdb/parser/expression/cast_expression.hpp" #include "duckdb/parser/group_by_node.hpp" #include "duckdb/parser/parsed_data/create_table_info.hpp" #include "duckdb/parser/parser_extension.hpp" @@ -340,134 +339,6 @@ vector Parser::Tokenize(const string &query) { return result; } -vector Parser::TokenizeError(const string &error_msg) { - idx_t error_start = 0; - idx_t error_end = error_msg.size(); - - vector tokens; - // find "XXX Error:" - this marks the start of the error message - auto error = StringUtil::Find(error_msg, "Error: "); - if (error.IsValid()) { - SimplifiedToken token; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_ERROR; - token.start = 0; - tokens.push_back(token); - - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER; - token.start = error.GetIndex() + 6; - tokens.push_back(token); - - error_start = error.GetIndex() + 7; - } - - // find "LINE (number)" - this marks the end of the message - auto line_pos = StringUtil::Find(error_msg, "\nLINE "); - if (line_pos.IsValid()) { - // tokenize between - error_end = line_pos.GetIndex(); - } - - // now iterate over the - bool in_quotes = false; - char quote_char = '\0'; - for (idx_t i = error_start; i < error_end; i++) { - if (in_quotes) { - // in a quote - look for the quote character - if (error_msg[i] == quote_char) { - SimplifiedToken token; - token.start = i; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER; - tokens.push_back(token); - in_quotes = false; - } - if (StringUtil::CharacterIsNewline(error_msg[i])) { - // found a newline in a quote, abort the quoted state entirely - tokens.pop_back(); - in_quotes = false; - } - } else if (error_msg[i] == '"' || error_msg[i] == '\'') { - // not quoted and found a quote - enter the quoted state - SimplifiedToken token; - token.start = i; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_STRING_CONSTANT; - token.start++; - tokens.push_back(token); - quote_char = error_msg[i]; - in_quotes = true; - } - } - if (in_quotes) { - // unterminated quotes at the end of the error - pop back the quoted state - tokens.pop_back(); - } - if (line_pos.IsValid()) { - SimplifiedToken token; - token.start = line_pos.GetIndex() + 1; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_COMMENT; - tokens.push_back(token); - - // tokenize the LINE part - idx_t query_start; - for (query_start = line_pos.GetIndex() + 6; query_start < error_msg.size(); query_start++) { - if (error_msg[query_start] != ':' && !StringUtil::CharacterIsDigit(error_msg[query_start])) { - break; - } - } - if (query_start < error_msg.size()) { - token.start = query_start; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_IDENTIFIER; - tokens.push_back(token); - - idx_t query_end; - for (query_end = query_start; query_end < error_msg.size(); query_end++) { - if (error_msg[query_end] == '\n') { - break; - } - } - // after LINE XXX: comes a caret - look for it - idx_t caret_position = error_msg.size(); - bool place_caret = false; - idx_t caret_start = query_end + 1; - if (caret_start < error_msg.size()) { - for (idx_t i = caret_start; i < error_msg.size(); i++) { - if (error_msg[i] == '^') { - // found the caret - // to get the caret position in the query we need to - caret_position = i - caret_start - ((query_start - line_pos.GetIndex()) - 1); - place_caret = true; - break; - } - } - } - // tokenize the actual query - string query = error_msg.substr(query_start, query_end - query_start); - auto query_tokens = Tokenize(query); - for (auto &query_token : query_tokens) { - if (place_caret) { - if (query_token.start >= caret_position) { - // we need to place the caret here - query_token.start = query_start + caret_position; - query_token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_ERROR; - tokens.push_back(query_token); - - place_caret = false; - continue; - } - } - query_token.start += query_start; - tokens.push_back(query_token); - } - // FIXME: find the caret position and highlight/bold the identifier it points to - if (query_end < error_msg.size()) { - token.start = query_end; - token.type = SimplifiedTokenType::SIMPLIFIED_TOKEN_ERROR; - tokens.push_back(token); - } - } - } - return tokens; -} - KeywordCategory ToKeywordCategory(duckdb_libpgquery::PGKeywordCategory type) { switch (type) { case duckdb_libpgquery::PGKeywordCategory::PG_KEYWORD_RESERVED: diff --git a/src/duckdb/src/parser/qualified_name.cpp b/src/duckdb/src/parser/qualified_name.cpp deleted file mode 100644 index c4567edea..000000000 --- a/src/duckdb/src/parser/qualified_name.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "duckdb/parser/qualified_name.hpp" -#include "duckdb/parser/parsed_data/parse_info.hpp" - -namespace duckdb { - -string QualifiedName::ToString() const { - return ParseInfo::QualifierToString(catalog, schema, name); -} - -QualifiedName QualifiedName::Parse(const string &input) { - string catalog; - string schema; - string name; - idx_t idx = 0; - vector entries; - string entry; -normal: - //! quote - for (; idx < input.size(); idx++) { - if (input[idx] == '"') { - idx++; - goto quoted; - } else if (input[idx] == '.') { - goto separator; - } - entry += input[idx]; - } - goto end; -separator: - entries.push_back(entry); - entry = ""; - idx++; - goto normal; -quoted: - //! look for another quote - for (; idx < input.size(); idx++) { - if (input[idx] == '"') { - //! unquote - idx++; - goto normal; - } - entry += input[idx]; - } - throw ParserException("Unterminated quote in qualified name!"); -end: - if (entries.empty()) { - catalog = INVALID_CATALOG; - schema = INVALID_SCHEMA; - name = entry; - } else if (entries.size() == 1) { - catalog = INVALID_CATALOG; - schema = entries[0]; - name = entry; - } else if (entries.size() == 2) { - catalog = entries[0]; - schema = entries[1]; - name = entry; - } else { - throw ParserException("Expected catalog.entry, schema.entry or entry: too many entries found"); - } - return QualifiedName {catalog, schema, name}; -} - -QualifiedColumnName::QualifiedColumnName() { -} -QualifiedColumnName::QualifiedColumnName(string column_p) : column(std::move(column_p)) { -} -QualifiedColumnName::QualifiedColumnName(string table_p, string column_p) - : table(std::move(table_p)), column(std::move(column_p)) { -} -QualifiedColumnName::QualifiedColumnName(const BindingAlias &alias, string column_p) - : catalog(alias.GetCatalog()), schema(alias.GetSchema()), table(alias.GetAlias()), column(std::move(column_p)) { -} - -string QualifiedColumnName::ToString() const { - string result; - if (!catalog.empty()) { - result += KeywordHelper::WriteOptionallyQuoted(catalog) + "."; - } - if (!schema.empty()) { - result += KeywordHelper::WriteOptionallyQuoted(schema) + "."; - } - if (!table.empty()) { - result += KeywordHelper::WriteOptionallyQuoted(table) + "."; - } - result += KeywordHelper::WriteOptionallyQuoted(column); - return result; -} - -bool QualifiedColumnName::IsQualified() const { - return !catalog.empty() || !schema.empty() || !table.empty(); -} - -bool QualifiedColumnName::operator==(const QualifiedColumnName &rhs) const { - return StringUtil::CIEquals(catalog, rhs.catalog) && StringUtil::CIEquals(schema, rhs.schema) && - StringUtil::CIEquals(table, rhs.table) && StringUtil::CIEquals(column, rhs.column); -} - -} // namespace duckdb diff --git a/src/duckdb/src/parser/query_error_context.cpp b/src/duckdb/src/parser/query_error_context.cpp index f8545714e..5dd544780 100644 --- a/src/duckdb/src/parser/query_error_context.cpp +++ b/src/duckdb/src/parser/query_error_context.cpp @@ -9,7 +9,6 @@ namespace duckdb { string QueryErrorContext::Format(const string &query, const string &error_message, optional_idx error_loc, bool add_line_indicator) { - static constexpr idx_t MAX_LINE_RENDER_WIDTH = 120; if (!error_loc.IsValid()) { // no location in query provided return error_message; @@ -59,7 +58,6 @@ string QueryErrorContext::Format(const string &query, const string &error_messag idx_t len = end_pos - start_pos; vector render_widths; vector positions; - vector natural_break; if (Utf8Proc::IsValid(buf, len)) { // for unicode awareness, we traverse the graphemes of the current line and keep track of their render widths // and of their position in the string @@ -67,8 +65,6 @@ string QueryErrorContext::Format(const string &query, const string &error_messag auto char_render_width = Utf8Proc::RenderWidth(buf, len, cpos); positions.push_back(cpos); render_widths.push_back(char_render_width); - natural_break.push_back(StringUtil::CharacterIsOperator(buf[cpos]) || - StringUtil::CharacterIsSpace(buf[cpos])); cpos = Utf8Proc::NextGraphemeCluster(buf, len, cpos); } } else { // LCOV_EXCL_START @@ -77,8 +73,6 @@ string QueryErrorContext::Format(const string &query, const string &error_messag for (idx_t cpos = 0; cpos < len; cpos++) { positions.push_back(cpos); render_widths.push_back(1); - natural_break.push_back(StringUtil::CharacterIsOperator(buf[cpos]) || - StringUtil::CharacterIsSpace(buf[cpos])); } } // LCOV_EXCL_STOP // now we want to find the (unicode aware) start and end position @@ -94,25 +88,13 @@ string QueryErrorContext::Format(const string &query, const string &error_messag bool truncate_end = false; idx_t spos = 0; // now we iterate backwards from the error location - // we show max 60 render width before the error location - idx_t error_line_start = start_pos; + // we show max 40 render width before the error location idx_t current_render_width = 0; for (idx_t i = epos; i > 0; i--) { current_render_width += render_widths[i]; - if (current_render_width >= MAX_LINE_RENDER_WIDTH / 2) { - // we're exceeding the render width - truncate the beginning - // try to break at a "nice" point (i.e. a space, bracket, etc) - // try to find a natural break that is within 4 bytes of here - idx_t start_scan = i > 4 ? i - 4 : 0; - idx_t end_scan = MinValue(i + 4, epos); - for (idx_t k = start_scan; k < end_scan; k++) { - if (natural_break[k]) { - i = k; - break; - } - } + if (current_render_width >= 40) { truncate_beginning = true; - start_pos += positions[i]; + start_pos = positions[i]; spos = i; break; } @@ -121,20 +103,9 @@ string QueryErrorContext::Format(const string &query, const string &error_messag current_render_width = 0; for (idx_t i = epos; i < positions.size(); i++) { current_render_width += render_widths[i]; - if (current_render_width >= MAX_LINE_RENDER_WIDTH / 2) { - // we're exceeding the render width - truncate the end - // try to break at a "nice" point (i.e. a space, bracket, etc) - // try to find a natural break that is within 4 bytes of here - idx_t start_scan = i > epos + 4 ? i - 4 : epos; - idx_t end_scan = MinValue(i + 4, positions.size()); - for (idx_t k = start_scan; k < end_scan; k++) { - if (natural_break[k]) { - i = k; - break; - } - } + if (current_render_width >= 40) { truncate_end = true; - end_pos = error_line_start + positions[i]; + end_pos = positions[i]; break; } } @@ -154,7 +125,7 @@ string QueryErrorContext::Format(const string &query, const string &error_messag // now first print the error message plus the current line (or a subset of the line) string result = error_message; - result += "\n\n" + line_indicator + begin_trunc + query.substr(start_pos, end_pos - start_pos) + end_trunc; + result += "\n" + line_indicator + begin_trunc + query.substr(start_pos, end_pos - start_pos) + end_trunc; // print an arrow pointing at the error location result += "\n" + string(error_render_width, ' ') + "^"; return result; diff --git a/src/duckdb/src/parser/query_node/select_node.cpp b/src/duckdb/src/parser/query_node/select_node.cpp index 3c3e4537c..66ad5dc72 100644 --- a/src/duckdb/src/parser/query_node/select_node.cpp +++ b/src/duckdb/src/parser/query_node/select_node.cpp @@ -41,8 +41,8 @@ string SelectNode::ToString() const { result += ", "; } result += select_list[i]->ToString(); - if (!select_list[i]->GetAlias().empty()) { - result += StringUtil::Format(" AS %s", SQLIdentifier(select_list[i]->GetAlias())); + if (!select_list[i]->alias.empty()) { + result += StringUtil::Format(" AS %s", SQLIdentifier(select_list[i]->alias)); } } if (from_table && from_table->type != TableReferenceType::EMPTY_FROM) { @@ -101,8 +101,8 @@ string SelectNode::ToString() const { result += "%"; } result += " (" + EnumUtil::ToString(sample->method); - if (sample->seed.IsValid()) { - result += ", " + std::to_string(sample->seed.GetIndex()); + if (sample->seed >= 0) { + result += ", " + std::to_string(sample->seed); } result += ")"; } diff --git a/src/duckdb/src/parser/statement/delete_statement.cpp b/src/duckdb/src/parser/statement/delete_statement.cpp index 0c3293e29..1de2767ca 100644 --- a/src/duckdb/src/parser/statement/delete_statement.cpp +++ b/src/duckdb/src/parser/statement/delete_statement.cpp @@ -43,12 +43,7 @@ string DeleteStatement::ToString() const { if (i > 0) { result += ", "; } - auto column = returning_list[i]->ToString(); - if (!returning_list[i]->GetAlias().empty()) { - column += - StringUtil::Format(" AS %s", KeywordHelper::WriteOptionallyQuoted(returning_list[i]->GetAlias())); - } - result += column; + result += returning_list[i]->ToString(); } } return result; diff --git a/src/duckdb/src/parser/statement/insert_statement.cpp b/src/duckdb/src/parser/statement/insert_statement.cpp index f59a2ef3a..fc3842326 100644 --- a/src/duckdb/src/parser/statement/insert_statement.cpp +++ b/src/duckdb/src/parser/statement/insert_statement.cpp @@ -157,9 +157,8 @@ string InsertStatement::ToString() const { result += ", "; } auto column = returning_list[i]->ToString(); - if (!returning_list[i]->GetAlias().empty()) { - column += - StringUtil::Format(" AS %s", KeywordHelper::WriteOptionallyQuoted(returning_list[i]->GetAlias())); + if (!returning_list[i]->alias.empty()) { + column += StringUtil::Format(" AS %s", KeywordHelper::WriteOptionallyQuoted(returning_list[i]->alias)); } result += column; } @@ -191,7 +190,7 @@ optional_ptr InsertStatement::GetValuesList() const { if (node.aggregate_handling != AggregateHandling::STANDARD_HANDLING) { return nullptr; } - if (node.select_list.size() != 1 || node.select_list[0]->GetExpressionType() != ExpressionType::STAR) { + if (node.select_list.size() != 1 || node.select_list[0]->type != ExpressionType::STAR) { return nullptr; } if (!node.from_table || node.from_table->type != TableReferenceType::EXPRESSION_LIST) { diff --git a/src/duckdb/src/parser/statement/update_statement.cpp b/src/duckdb/src/parser/statement/update_statement.cpp index cabd1d36e..6c0c79919 100644 --- a/src/duckdb/src/parser/statement/update_statement.cpp +++ b/src/duckdb/src/parser/statement/update_statement.cpp @@ -65,12 +65,7 @@ string UpdateStatement::ToString() const { if (i > 0) { result += ", "; } - auto column = returning_list[i]->ToString(); - if (!returning_list[i]->GetAlias().empty()) { - column += - StringUtil::Format(" AS %s", KeywordHelper::WriteOptionallyQuoted(returning_list[i]->GetAlias())); - } - result += column; + result += returning_list[i]->ToString(); } } return result; diff --git a/src/duckdb/src/parser/tableref.cpp b/src/duckdb/src/parser/tableref.cpp index 9ce290237..f8b8db70c 100644 --- a/src/duckdb/src/parser/tableref.cpp +++ b/src/duckdb/src/parser/tableref.cpp @@ -31,8 +31,8 @@ string TableRef::BaseToString(string result, const vector &column_name_a if (sample) { result += " TABLESAMPLE " + EnumUtil::ToString(sample->method); result += "(" + sample->sample_size.ToString() + " " + string(sample->is_percentage ? "PERCENT" : "ROWS") + ")"; - if (sample->seed.IsValid()) { - result += "REPEATABLE (" + to_string(sample->seed.GetIndex()) + ")"; + if (sample->seed >= 0) { + result += "REPEATABLE (" + to_string(sample->seed) + ")"; } } diff --git a/src/duckdb/src/parser/tableref/pivotref.cpp b/src/duckdb/src/parser/tableref/pivotref.cpp index ffeef36f4..341aa9564 100644 --- a/src/duckdb/src/parser/tableref/pivotref.cpp +++ b/src/duckdb/src/parser/tableref/pivotref.cpp @@ -143,8 +143,8 @@ string PivotRef::ToString() const { result += ", "; } result += aggregates[aggr_idx]->ToString(); - if (!aggregates[aggr_idx]->GetAlias().empty()) { - result += " AS " + KeywordHelper::WriteOptionallyQuoted(aggregates[aggr_idx]->GetAlias()); + if (!aggregates[aggr_idx]->alias.empty()) { + result += " AS " + KeywordHelper::WriteOptionallyQuoted(aggregates[aggr_idx]->alias); } } } else { diff --git a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp index 8439fc863..dcb467e9c 100644 --- a/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp +++ b/src/duckdb/src/parser/transform/constraint/transform_constraint.cpp @@ -68,42 +68,50 @@ TransformForeignKeyConstraint(duckdb_libpgquery::PGConstraint &constraint, return make_uniq(pk_columns, fk_columns, std::move(fk_info)); } -unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGConstraint &constraint) { - switch (constraint.contype) { +unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGListCell &cell) { + + auto constraint = PGPointerCast(cell.data.ptr_value); + D_ASSERT(constraint); + + switch (constraint->contype) { case duckdb_libpgquery::PG_CONSTR_UNIQUE: case duckdb_libpgquery::PG_CONSTR_PRIMARY: { - bool is_primary_key = constraint.contype == duckdb_libpgquery::PG_CONSTR_PRIMARY; - if (!constraint.keys) { + bool is_primary_key = constraint->contype == duckdb_libpgquery::PG_CONSTR_PRIMARY; + if (!constraint->keys) { throw ParserException("UNIQUE USING INDEX is not supported"); } vector columns; - for (auto kc = constraint.keys->head; kc; kc = kc->next) { + for (auto kc = constraint->keys->head; kc; kc = kc->next) { auto value = PGPointerCast(kc->data.ptr_value); columns.emplace_back(value->val.str); } return make_uniq(columns, is_primary_key); } case duckdb_libpgquery::PG_CONSTR_CHECK: { - auto expression = TransformExpression(constraint.raw_expr); + auto expression = TransformExpression(constraint->raw_expr); if (expression->HasSubquery()) { throw ParserException("subqueries prohibited in CHECK constraints"); } - return make_uniq(TransformExpression(constraint.raw_expr)); + return make_uniq(TransformExpression(constraint->raw_expr)); } case duckdb_libpgquery::PG_CONSTR_FOREIGN: - return TransformForeignKeyConstraint(constraint); + return TransformForeignKeyConstraint(*constraint.get()); default: throw NotImplementedException("Constraint type not handled yet!"); } } -unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGConstraint &constraint, - ColumnDefinition &column, idx_t index) { - switch (constraint.contype) { +unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGListCell &cell, ColumnDefinition &column, + idx_t index) { + + auto constraint = PGPointerCast(cell.data.ptr_value); + D_ASSERT(constraint); + + switch (constraint->contype) { case duckdb_libpgquery::PG_CONSTR_NOTNULL: return make_uniq(LogicalIndex(index)); case duckdb_libpgquery::PG_CONSTR_CHECK: - return TransformConstraint(constraint); + return TransformConstraint(cell); case duckdb_libpgquery::PG_CONSTR_PRIMARY: return make_uniq(LogicalIndex(index), true); case duckdb_libpgquery::PG_CONSTR_UNIQUE: @@ -115,23 +123,23 @@ unique_ptr Transformer::TransformConstraint(duckdb_libpgquery::PGCon throw InvalidInputException("\"%s\" has a DEFAULT value set, it can not become a GENERATED column", column.Name()); } - column.SetGeneratedExpression(TransformExpression(constraint.raw_expr)); + column.SetGeneratedExpression(TransformExpression(constraint->raw_expr)); return nullptr; } case duckdb_libpgquery::PG_CONSTR_GENERATED_STORED: throw InvalidInputException("Can not create a STORED generated column!"); case duckdb_libpgquery::PG_CONSTR_DEFAULT: - column.SetDefaultValue(TransformExpression(constraint.raw_expr)); + column.SetDefaultValue(TransformExpression(constraint->raw_expr)); return nullptr; case duckdb_libpgquery::PG_CONSTR_COMPRESSION: - column.SetCompressionType(CompressionTypeFromString(constraint.compression_name)); + column.SetCompressionType(CompressionTypeFromString(constraint->compression_name)); if (column.CompressionType() == CompressionType::COMPRESSION_AUTO) { throw ParserException("Unrecognized option for column compression, expected none, uncompressed, rle, " "dictionary, pfor, bitpacking or fsst"); } return nullptr; case duckdb_libpgquery::PG_CONSTR_FOREIGN: - return TransformForeignKeyConstraint(constraint, &column.Name()); + return TransformForeignKeyConstraint(*constraint.get(), &column.Name()); default: throw NotImplementedException("Constraint not implemented!"); } diff --git a/src/duckdb/src/parser/transform/expression/transform_array_access.cpp b/src/duckdb/src/parser/transform/expression/transform_array_access.cpp index 447688c61..b5d149d53 100644 --- a/src/duckdb/src/parser/transform/expression/transform_array_access.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_array_access.cpp @@ -60,7 +60,7 @@ unique_ptr Transformer::TransformArrayAccess(duckdb_libpgquery case duckdb_libpgquery::T_PGFuncCall: { auto func = PGCast(*target.get()); auto function = TransformFuncCall(func); - if (function->GetExpressionType() != ExpressionType::FUNCTION) { + if (function->type != ExpressionType::FUNCTION) { throw ParserException("%s.%s() call must be a function", result->ToString(), function->ToString()); } auto &function_expr = function->Cast(); diff --git a/src/duckdb/src/parser/transform/expression/transform_bool_expr.cpp b/src/duckdb/src/parser/transform/expression/transform_bool_expr.cpp index 76078f5e2..40a98ccb6 100644 --- a/src/duckdb/src/parser/transform/expression/transform_bool_expr.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_bool_expr.cpp @@ -29,15 +29,15 @@ unique_ptr Transformer::TransformBoolExpr(duckdb_libpgquery::P break; } case duckdb_libpgquery::PG_NOT_EXPR: { - if (next->GetExpressionType() == ExpressionType::COMPARE_IN) { + if (next->type == ExpressionType::COMPARE_IN) { // convert COMPARE_IN to COMPARE_NOT_IN - next->SetExpressionTypeUnsafe(ExpressionType::COMPARE_NOT_IN); + next->type = ExpressionType::COMPARE_NOT_IN; result = std::move(next); - } else if (next->GetExpressionType() >= ExpressionType::COMPARE_EQUAL && - next->GetExpressionType() <= ExpressionType::COMPARE_GREATERTHANOREQUALTO) { + } else if (next->type >= ExpressionType::COMPARE_EQUAL && + next->type <= ExpressionType::COMPARE_GREATERTHANOREQUALTO) { // NOT on a comparison: we can negate the comparison // e.g. NOT(x > y) is equivalent to x <= y - next->SetExpressionTypeUnsafe(NegateComparisonExpression(next->GetExpressionType())); + next->type = NegateComparisonExpression(next->type); result = std::move(next); } else { result = make_uniq(ExpressionType::OPERATOR_NOT, std::move(next)); diff --git a/src/duckdb/src/parser/transform/expression/transform_columnref.cpp b/src/duckdb/src/parser/transform/expression/transform_columnref.cpp index a232219fa..7137169f8 100644 --- a/src/duckdb/src/parser/transform/expression/transform_columnref.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_columnref.cpp @@ -6,44 +6,17 @@ namespace duckdb { -QualifiedColumnName TransformQualifiedColumnName(duckdb_libpgquery::PGList &list) { - QualifiedColumnName result; - switch (list.length) { - case 1: - result.column = const_char_ptr_cast(list.head->data.ptr_value); - break; - case 2: - result.table = const_char_ptr_cast(list.head->data.ptr_value); - result.column = const_char_ptr_cast(list.head->next->data.ptr_value); - break; - case 3: - result.schema = const_char_ptr_cast(list.head->data.ptr_value); - result.table = const_char_ptr_cast(list.head->next->data.ptr_value); - result.column = const_char_ptr_cast(list.head->next->next->data.ptr_value); - break; - case 4: - result.catalog = const_char_ptr_cast(list.head->data.ptr_value); - result.schema = const_char_ptr_cast(list.head->next->data.ptr_value); - result.table = const_char_ptr_cast(list.head->next->next->data.ptr_value); - result.column = const_char_ptr_cast(list.head->next->next->next->data.ptr_value); - break; - default: - throw ParserException("Qualified column name must have between 1 and 4 elements"); - } - return result; -} - unique_ptr Transformer::TransformStarExpression(duckdb_libpgquery::PGAStar &star) { auto result = make_uniq(star.relation ? star.relation : string()); if (star.except_list) { for (auto head = star.except_list->head; head; head = head->next) { - auto exclude_column_list = PGPointerCast(head->data.ptr_value); - auto exclude_column = TransformQualifiedColumnName(*exclude_column_list); - // qualified - add to exclude list - if (result->exclude_list.find(exclude_column) != result->exclude_list.end()) { - throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", exclude_column.ToString()); + auto value = PGPointerCast(head->data.ptr_value); + D_ASSERT(value->type == duckdb_libpgquery::T_PGString); + string exclude_entry = value->val.str; + if (result->exclude_list.find(exclude_entry) != result->exclude_list.end()) { + throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", exclude_entry); } - result->exclude_list.insert(std::move(exclude_column)); + result->exclude_list.insert(std::move(exclude_entry)); } } if (star.replace_list) { @@ -54,35 +27,14 @@ unique_ptr Transformer::TransformStarExpression(duckdb_libpgqu TransformExpression(PGPointerCast(list->head->data.ptr_value)); auto value = PGPointerCast(list->tail->data.ptr_value); D_ASSERT(value->type == duckdb_libpgquery::T_PGString); - string replace_entry = value->val.str; - if (result->replace_list.find(replace_entry) != result->replace_list.end()) { - throw ParserException("Duplicate entry \"%s\" in REPLACE list", replace_entry); - } - if (result->exclude_list.find(QualifiedColumnName(replace_entry)) != result->exclude_list.end()) { - throw ParserException("Column \"%s\" cannot occur in both EXCLUDE and REPLACE list", replace_entry); - } - result->replace_list.insert(make_pair(std::move(replace_entry), std::move(replace_expression))); - } - } - if (star.rename_list) { - for (auto head = star.rename_list->head; head; head = head->next) { - auto list = PGPointerCast(head->data.ptr_value); - D_ASSERT(list->length == 2); - auto rename_column_list = PGPointerCast(list->head->data.ptr_value); - auto rename_column = TransformQualifiedColumnName(*rename_column_list); - string new_name = char_ptr_cast(list->tail->data.ptr_value); - if (result->rename_list.find(rename_column) != result->rename_list.end()) { - throw ParserException("Duplicate entry \"%s\" in EXCLUDE list", rename_column.ToString()); - } - if (result->exclude_list.find(rename_column) != result->exclude_list.end()) { - throw ParserException("Column \"%s\" cannot occur in both EXCLUDE and RENAME list", - rename_column.ToString()); + string exclude_entry = value->val.str; + if (result->replace_list.find(exclude_entry) != result->replace_list.end()) { + throw ParserException("Duplicate entry \"%s\" in REPLACE list", exclude_entry); } - if (result->replace_list.find(rename_column.column) != result->replace_list.end()) { - throw ParserException("Column \"%s\" cannot occur in both REPLACE and RENAME list", - rename_column.ToString()); + if (result->exclude_list.find(exclude_entry) != result->exclude_list.end()) { + throw ParserException("Column \"%s\" cannot occur in both EXCEPT and REPLACE list", exclude_entry); } - result->rename_list.insert(make_pair(std::move(rename_column), std::move(new_name))); + result->replace_list.insert(make_pair(std::move(exclude_entry), std::move(replace_expression))); } } if (star.expr) { @@ -97,7 +49,7 @@ unique_ptr Transformer::TransformStarExpression(duckdb_libpgqu result->exclude_list = std::move(child_star.exclude_list); result->replace_list = std::move(child_star.replace_list); result->expr.reset(); - } else if (result->expr->GetExpressionType() == ExpressionType::LAMBDA) { + } else if (result->expr->type == ExpressionType::LAMBDA) { vector> children; children.push_back(make_uniq()); children.push_back(std::move(result->expr)); diff --git a/src/duckdb/src/parser/transform/expression/transform_constant.cpp b/src/duckdb/src/parser/transform/expression/transform_constant.cpp index 88fd295ff..358325600 100644 --- a/src/duckdb/src/parser/transform/expression/transform_constant.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_constant.cpp @@ -55,12 +55,6 @@ unique_ptr Transformer::TransformValue(duckdb_libpgquery::PG // successfully cast to bigint: bigint value return make_uniq(Value::HUGEINT(hugeint_value)); } - uhugeint_t uhugeint_value; - // if that is not successful; try to cast as uhugeint - if (TryCast::Operation(str_val, uhugeint_value)) { - // successfully cast to bigint: bigint value - return make_uniq(Value::UHUGEINT(uhugeint_value)); - } } idx_t decimal_offset = val.val.str[0] == '-' ? 3 : 2; if (try_cast_as_decimal && decimal_position.IsValid() && @@ -97,7 +91,7 @@ unique_ptr Transformer::TransformConstant(duckdb_libpgquery::P bool Transformer::ConstructConstantFromExpression(const ParsedExpression &expr, Value &value) { // We have to construct it like this because we don't have the ClientContext for binding/executing the expr here - switch (expr.GetExpressionType()) { + switch (expr.type) { case ExpressionType::FUNCTION: { auto &function = expr.Cast(); if (function.function_name == "struct_pack") { @@ -105,14 +99,14 @@ bool Transformer::ConstructConstantFromExpression(const ParsedExpression &expr, child_list_t values; values.reserve(function.children.size()); for (const auto &child : function.children) { - if (!unique_names.insert(child->GetAlias()).second) { - throw BinderException("Duplicate struct entry name \"%s\"", child->GetAlias()); + if (!unique_names.insert(child->alias).second) { + throw BinderException("Duplicate struct entry name \"%s\"", child->alias); } Value child_value; if (!ConstructConstantFromExpression(*child, child_value)) { return false; } - values.emplace_back(child->GetAlias(), std::move(child_value)); + values.emplace_back(child->alias, std::move(child_value)); } value = Value::STRUCT(std::move(values)); return true; diff --git a/src/duckdb/src/parser/transform/expression/transform_expression.cpp b/src/duckdb/src/parser/transform/expression/transform_expression.cpp index 1f64c8ed4..9f7e7a89a 100644 --- a/src/duckdb/src/parser/transform/expression/transform_expression.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_expression.cpp @@ -10,7 +10,7 @@ unique_ptr Transformer::TransformResTarget(duckdb_libpgquery:: return nullptr; } if (root.name) { - expr->SetAlias(root.name); + expr->alias = string(root.name); } return expr; } @@ -19,7 +19,7 @@ unique_ptr Transformer::TransformNamedArg(duckdb_libpgquery::P auto expr = TransformExpression(PGPointerCast(root.arg)); if (root.name) { - expr->SetAlias(root.name); + expr->alias = string(root.name); } return expr; } diff --git a/src/duckdb/src/parser/transform/expression/transform_function.cpp b/src/duckdb/src/parser/transform/expression/transform_function.cpp index e410b7049..16c50fa70 100644 --- a/src/duckdb/src/parser/transform/expression/transform_function.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_function.cpp @@ -90,7 +90,7 @@ void Transformer::TransformWindowFrame(duckdb_libpgquery::PGWindowDef &window_sp } bool Transformer::ExpressionIsEmptyStar(ParsedExpression &expr) { - if (expr.GetExpressionClass() != ExpressionClass::STAR) { + if (expr.expression_class != ExpressionClass::STAR) { return false; } auto &star = expr.Cast(); @@ -110,27 +110,6 @@ bool Transformer::InWindowDefinition() { return false; } -static bool IsOrderableWindowFunction(ExpressionType type) { - switch (type) { - case ExpressionType::WINDOW_FIRST_VALUE: - case ExpressionType::WINDOW_LAST_VALUE: - case ExpressionType::WINDOW_NTH_VALUE: - case ExpressionType::WINDOW_RANK: - case ExpressionType::WINDOW_PERCENT_RANK: - case ExpressionType::WINDOW_ROW_NUMBER: - case ExpressionType::WINDOW_NTILE: - case ExpressionType::WINDOW_CUME_DIST: - case ExpressionType::WINDOW_LEAD: - case ExpressionType::WINDOW_LAG: - case ExpressionType::WINDOW_AGGREGATE: - return true; - case ExpressionType::WINDOW_RANK_DENSE: - return false; - default: - throw InternalException("Unknown orderable window type %s", ExpressionTypeToString(type).c_str()); - } -} - unique_ptr Transformer::TransformFuncCall(duckdb_libpgquery::PGFuncCall &root) { auto name = root.funcname; string catalog, schema, function_name; @@ -178,8 +157,8 @@ unique_ptr Transformer::TransformFuncCall(duckdb_libpgquery::P throw ParserException("DISTINCT is not implemented for non-aggregate window functions!"); } - if (root.agg_order && !IsOrderableWindowFunction(win_fun_type)) { - throw ParserException("ORDER BY is not supported for the window function \"%s\"", lowercase_name.c_str()); + if (root.agg_order) { + throw ParserException("ORDER BY is not implemented for window functions!"); } if (win_fun_type != ExpressionType::WINDOW_AGGREGATE && root.agg_filter) { @@ -203,12 +182,6 @@ unique_ptr Transformer::TransformFuncCall(duckdb_libpgquery::P expr->filter_expr = std::move(filter_expr); } - if (root.agg_order) { - auto order_bys = make_uniq(); - TransformOrderBy(root.agg_order, order_bys->orders); - expr->arg_orders = std::move(order_bys->orders); - } - if (win_fun_type == ExpressionType::WINDOW_AGGREGATE) { expr->children = std::move(children); } else { diff --git a/src/duckdb/src/parser/transform/expression/transform_operator.cpp b/src/duckdb/src/parser/transform/expression/transform_operator.cpp index 46a2d6c09..fdc9393d5 100644 --- a/src/duckdb/src/parser/transform/expression/transform_operator.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_operator.cpp @@ -168,7 +168,7 @@ unique_ptr Transformer::TransformAExprInternal(duckdb_libpgque auto &similar_func = right_expr->Cast(); D_ASSERT(similar_func.function_name == "similar_escape"); D_ASSERT(similar_func.children.size() == 2); - if (similar_func.children[1]->GetExpressionType() != ExpressionType::VALUE_CONSTANT) { + if (similar_func.children[1]->type != ExpressionType::VALUE_CONSTANT) { throw NotImplementedException("Custom escape in SIMILAR TO"); } auto &constant = similar_func.children[1]->Cast(); diff --git a/src/duckdb/src/parser/transform/expression/transform_subquery.cpp b/src/duckdb/src/parser/transform/expression/transform_subquery.cpp index 6f6d74207..9d93b5485 100644 --- a/src/duckdb/src/parser/transform/expression/transform_subquery.cpp +++ b/src/duckdb/src/parser/transform/expression/transform_subquery.cpp @@ -74,30 +74,16 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P case duckdb_libpgquery::PG_ARRAY_SUBLINK: { // ARRAY expression // wrap subquery into - // "SELECT CASE WHEN ARRAY_AGG(col) IS NULL THEN [] ELSE ARRAY_AGG(col) END FROM (...) tbl" + // "SELECT CASE WHEN ARRAY_AGG(COLUMNS(*)) IS NULL THEN [] ELSE ARRAY_AGG(COLUMNS(*)) END FROM (...) tbl" auto select_node = make_uniq(); - unique_ptr array_agg_child; - optional_ptr sub_select; - if (subquery_expr->subquery->node->type == QueryNodeType::SELECT_NODE) { - // easy case - subquery is a SELECT - sub_select = subquery_expr->subquery->node->Cast(); - if (sub_select->select_list.size() != 1) { - throw BinderException(*subquery_expr, "Subquery returns %zu columns - expected 1", - sub_select->select_list.size()); - } - array_agg_child = make_uniq(1ULL); - } else { - // subquery is not a SELECT but a UNION or CTE - // we can still support this but it is more challenging since we can't push columns for the ORDER BY - auto columns_star = make_uniq(); - columns_star->columns = true; - array_agg_child = std::move(columns_star); - } + // COLUMNS(*) + auto columns_star = make_uniq(); + columns_star->columns = true; // ARRAY_AGG(COLUMNS(*)) vector> children; - children.push_back(std::move(array_agg_child)); + children.push_back(std::move(columns_star)); auto aggr = make_uniq("array_agg", std::move(children)); // push ORDER BY modifiers into the array_agg for (auto &modifier : subquery_expr->subquery->node->modifiers) { @@ -109,7 +95,7 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P // transform constants (e.g. ORDER BY 1) into positional references (ORDER BY #1) if (aggr->order_bys) { for (auto &order : aggr->order_bys->orders) { - if (order.expression->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (order.expression->type == ExpressionType::VALUE_CONSTANT) { auto &constant_expr = order.expression->Cast(); Value bigint_value; string error; @@ -118,12 +104,7 @@ unique_ptr Transformer::TransformSubquery(duckdb_libpgquery::P idx_t positional_index = order_index < 0 ? NumericLimits::Maximum() : idx_t(order_index); order.expression = make_uniq(positional_index); } - } else if (sub_select) { - // if we have a SELECT we can push the ORDER BY clause into the SELECT list and reference it - sub_select->select_list.push_back(std::move(order.expression)); - order.expression = make_uniq(sub_select->select_list.size() - 1); } else { - // otherwise we remove order qualifications RemoveOrderQualificationRecursive(order.expression); } } diff --git a/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp b/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp index 2a8a95c94..c61071c4a 100644 --- a/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp +++ b/src/duckdb/src/parser/transform/helpers/transform_groupby.cpp @@ -40,7 +40,7 @@ static void MergeGroupingSet(GroupingSet &result, GroupingSet &other) { void Transformer::AddGroupByExpression(unique_ptr expression, GroupingExpressionMap &map, GroupByNode &result, vector &result_set) { - if (expression->GetExpressionType() == ExpressionType::FUNCTION) { + if (expression->type == ExpressionType::FUNCTION) { auto &func = expression->Cast(); if (func.function_name == "row") { for (auto &child : func.children) { diff --git a/src/duckdb/src/parser/transform/helpers/transform_sample.cpp b/src/duckdb/src/parser/transform/helpers/transform_sample.cpp index bd1cc75a2..0cffebfed 100644 --- a/src/duckdb/src/parser/transform/helpers/transform_sample.cpp +++ b/src/duckdb/src/parser/transform/helpers/transform_sample.cpp @@ -25,13 +25,7 @@ unique_ptr Transformer::TransformSampleOptions(optional_ptr(); auto &sample_options = PGCast(*options); auto &sample_size = *PGPointerCast(sample_options.sample_size); - auto sample_expression = TransformExpression(sample_size.sample_size); - if (sample_expression->GetExpressionType() != ExpressionType::VALUE_CONSTANT) { - throw ParserException(sample_expression->GetQueryLocation(), - "Only constants are supported in sample clause currently"); - } - auto &const_expr = sample_expression->Cast(); - auto &sample_value = const_expr.value; + auto sample_value = TransformValue(sample_size.sample_size)->value; result->is_percentage = sample_size.is_percentage; if (sample_size.is_percentage) { // sample size is given in sample_size: use system sampling @@ -53,9 +47,8 @@ unique_ptr Transformer::TransformSampleOptions(optional_ptrmethod = GetSampleMethod(sample_options.method); } - if (sample_options.has_seed && sample_options.seed >= 0) { - result->seed = static_cast(sample_options.seed); - result->repeatable = true; + if (sample_options.has_seed) { + result->seed = sample_options.seed; } return result; } diff --git a/src/duckdb/src/parser/transform/helpers/transform_typename.cpp b/src/duckdb/src/parser/transform/helpers/transform_typename.cpp index a7beb3ba2..bd6b97a10 100644 --- a/src/duckdb/src/parser/transform/helpers/transform_typename.cpp +++ b/src/duckdb/src/parser/transform/helpers/transform_typename.cpp @@ -57,15 +57,14 @@ vector Transformer::TransformTypeModifiers(duckdb_libpgquery::PGTypeName if (type_name.typmods) { for (auto node = type_name.typmods->head; node; node = node->next) { if (type_mods.size() > 9) { - const auto &name = - *PGPointerCast(type_name.names->tail->data.ptr_value)->val.str; + auto name = PGPointerCast(type_name.names->tail->data.ptr_value)->val.str; throw ParserException("'%s': a maximum of 9 type modifiers is allowed", name); } - const auto &const_val = *PGPointerCast(node->data.ptr_value); + auto &const_val = *PGPointerCast(node->data.ptr_value); if (const_val.type != duckdb_libpgquery::T_PGAConst) { throw ParserException("Expected a constant as type modifier"); } - const auto const_expr = TransformValue(const_val.val); + auto const_expr = TransformValue(const_val.val); type_mods.push_back(std::move(const_expr->value)); } } diff --git a/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp b/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp index 2537daaec..d3b57c8e2 100644 --- a/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_alter_table.cpp @@ -39,9 +39,8 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte auto column_entry = TransformColumnDefinition(*column_def); if (column_def->constraints) { - for (auto cell = column_def->constraints->head; cell != nullptr; cell = cell->next) { - auto pg_constraint = PGPointerCast(cell->data.ptr_value); - auto constraint = TransformConstraint(*pg_constraint, column_entry, 0); + for (auto constr = column_def->constraints->head; constr != nullptr; constr = constr->next) { + auto constraint = TransformConstraint(*constr, column_entry, 0); if (!constraint) { continue; } @@ -75,11 +74,6 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte if (stmt.relkind != duckdb_libpgquery::PG_OBJECT_TABLE) { throw ParserException("Alter column's type is only supported for tables"); } - - if (column_entry.GetType() == LogicalType::UNKNOWN && !column_def->raw_default) { - throw ParserException("Omitting the type is only possible in combination with USING"); - } - if (column_def->raw_default) { expr = TransformExpression(column_def->raw_default); } else { @@ -98,16 +92,7 @@ unique_ptr Transformer::TransformAlter(duckdb_libpgquery::PGAlte result->info = make_uniq(std::move(data), command->name); break; } - case duckdb_libpgquery::PG_AT_AddConstraint: { - auto pg_constraint = PGCast(*command->def); - if (pg_constraint.contype != duckdb_libpgquery::PGConstrType::PG_CONSTR_PRIMARY) { - throw NotImplementedException("No support for that ALTER TABLE option yet!"); - } - - auto constraint = TransformConstraint(pg_constraint); - result->info = make_uniq(std::move(data), std::move(constraint)); - break; - } + case duckdb_libpgquery::PG_AT_DropConstraint: default: throw NotImplementedException("No support for that ALTER TABLE option yet!"); } diff --git a/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp b/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp index 6ab5d9e68..097b0c273 100644 --- a/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_comment_on.cpp @@ -46,7 +46,7 @@ unique_ptr Transformer::TransformCommentOn(duckdb_libpgquery::PG unique_ptr info; auto expr = TransformExpression(stmt.value); - if (expr->GetExpressionClass() != ExpressionClass::CONSTANT) { + if (expr->expression_class != ExpressionClass::CONSTANT) { throw NotImplementedException("Can only use constants as comments"); } auto comment_value = expr->Cast().value; diff --git a/src/duckdb/src/parser/transform/statement/transform_copy.cpp b/src/duckdb/src/parser/transform/statement/transform_copy.cpp index 7c199ac5b..1fa2464f5 100644 --- a/src/duckdb/src/parser/transform/statement/transform_copy.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_copy.cpp @@ -1,5 +1,6 @@ #include "duckdb/common/string_util.hpp" #include "duckdb/common/types/value.hpp" +#include "duckdb/core_functions/scalar/struct_functions.hpp" #include "duckdb/function/replacement_scan.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" diff --git a/src/duckdb/src/parser/transform/statement/transform_create_function.cpp b/src/duckdb/src/parser/transform/statement/transform_create_function.cpp index 6fdb68aab..82917ee25 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_function.cpp @@ -26,15 +26,15 @@ unique_ptr Transformer::TransformMacroFunction(duckdb_libpgquery: Value const_param; if (ConstructConstantFromExpression(*param, const_param)) { // parameters with default value (must have an alias) - if (param->GetAlias().empty()) { + if (param->alias.empty()) { throw ParserException("Invalid parameter: '%s'", param->ToString()); } - if (macro_func->default_parameters.find(param->GetAlias()) != macro_func->default_parameters.end()) { - throw ParserException("Duplicate default parameter: '%s'", param->GetAlias()); + if (macro_func->default_parameters.find(param->alias) != macro_func->default_parameters.end()) { + throw ParserException("Duplicate default parameter: '%s'", param->alias); } auto constructed_constant = make_uniq(std::move(const_param)); - constructed_constant->SetAlias(param->GetAlias()); - macro_func->default_parameters[param->GetAlias()] = std::move(constructed_constant); + constructed_constant->alias = param->alias; + macro_func->default_parameters[param->alias] = std::move(constructed_constant); } else if (param->GetExpressionClass() == ExpressionClass::COLUMN_REF) { // positional parameters if (!macro_func->default_parameters.empty()) { diff --git a/src/duckdb/src/parser/transform/statement/transform_create_table.cpp b/src/duckdb/src/parser/transform/statement/transform_create_table.cpp index 412a73cd3..e0177e4fa 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_table.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_table.cpp @@ -47,22 +47,12 @@ unique_ptr Transformer::TransformCollateExpr(duckdb_libpgquery } ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGColumnDef &cdef) { - string name; + string colname; if (cdef.colname) { - name = cdef.colname; + colname = cdef.colname; } - - auto optional_type = cdef.category == duckdb_libpgquery::COL_GENERATED; - LogicalType target_type; - if (optional_type && !cdef.typeName) { - target_type = LogicalType::ANY; - } else if (!cdef.typeName) { - // ALTER TABLE tbl ALTER TYPE USING ... - target_type = LogicalType::UNKNOWN; - } else { - target_type = TransformTypeName(*cdef.typeName); - } - + bool optional_type = cdef.category == duckdb_libpgquery::COL_GENERATED; + LogicalType target_type = (optional_type && !cdef.typeName) ? LogicalType::ANY : TransformTypeName(*cdef.typeName); if (cdef.collClause) { if (cdef.category == duckdb_libpgquery::COL_GENERATED) { throw ParserException("Collations are not supported on generated columns"); @@ -73,7 +63,7 @@ ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGCol target_type = LogicalType::VARCHAR_COLLATION(TransformCollation(cdef.collClause)); } - return ColumnDefinition(name, target_type); + return ColumnDefinition(colname, target_type); } unique_ptr Transformer::TransformCreateTable(duckdb_libpgquery::PGCreateStmt &stmt) { @@ -107,26 +97,22 @@ unique_ptr Transformer::TransformCreateTable(duckdb_libpgquery: auto node = PGPointerCast(c->data.ptr_value); switch (node->type) { case duckdb_libpgquery::T_PGColumnDef: { - auto pg_col_def = PGPointerCast(c->data.ptr_value); - auto col_def = TransformColumnDefinition(*pg_col_def); - - if (pg_col_def->constraints) { - for (auto cell = pg_col_def->constraints->head; cell != nullptr; cell = cell->next) { - auto pg_constraint = PGPointerCast(cell->data.ptr_value); - auto constraint = TransformConstraint(*pg_constraint, col_def, info->columns.LogicalColumnCount()); + auto cdef = PGPointerCast(c->data.ptr_value); + auto centry = TransformColumnDefinition(*cdef); + if (cdef->constraints) { + for (auto constr = cdef->constraints->head; constr != nullptr; constr = constr->next) { + auto constraint = TransformConstraint(*constr, centry, info->columns.LogicalColumnCount()); if (constraint) { info->constraints.push_back(std::move(constraint)); } } } - - info->columns.AddColumn(std::move(col_def)); + info->columns.AddColumn(std::move(centry)); column_count++; break; } case duckdb_libpgquery::T_PGConstraint: { - auto pg_constraint = PGPointerCast(c->data.ptr_value); - info->constraints.push_back(TransformConstraint(*pg_constraint)); + info->constraints.push_back(TransformConstraint(*c)); break; } default: diff --git a/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp b/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp index 3770194a7..6af7fe4e7 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_table_as.cpp @@ -8,25 +8,17 @@ unique_ptr Transformer::TransformCreateTableAs(duckdb_libpgquer if (stmt.relkind == duckdb_libpgquery::PG_OBJECT_MATVIEW) { throw NotImplementedException("Materialized view not implemented"); } - if (stmt.is_select_into || stmt.into->options) { + if (stmt.is_select_into || stmt.into->colNames || stmt.into->options) { throw NotImplementedException("Unimplemented features for CREATE TABLE as"); } + auto qname = TransformQualifiedName(*stmt.into->rel); if (stmt.query->type != duckdb_libpgquery::T_PGSelectStmt) { throw ParserException("CREATE TABLE AS requires a SELECT clause"); } + auto query = TransformSelectStmt(*stmt.query, false); auto result = make_uniq(); auto info = make_uniq(); - auto qname = TransformQualifiedName(*stmt.into->rel); - auto query = TransformSelectStmt(*stmt.query, false); - - if (stmt.into->colNames) { - auto cols = TransformStringList(stmt.into->colNames); - for (idx_t i = 0; i < cols.size(); i++) { - // We really don't know the type of the columns during parsing, so we just use UNKNOWN - info->columns.AddColumn(ColumnDefinition(cols[i], LogicalType::UNKNOWN)); - } - } info->catalog = qname.catalog; info->schema = qname.schema; info->table = qname.name; diff --git a/src/duckdb/src/parser/transform/statement/transform_create_view.cpp b/src/duckdb/src/parser/transform/statement/transform_create_view.cpp index 24a26c022..8504ecfc9 100644 --- a/src/duckdb/src/parser/transform/statement/transform_create_view.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_create_view.cpp @@ -21,7 +21,7 @@ unique_ptr Transformer::TransformCreateView(duckdb_libpgquery:: } info->on_conflict = TransformOnConflict(stmt.onconflict); - info->query = TransformSelectStmt(*stmt.query, false); + info->query = TransformSelectStmt(*PGPointerCast(stmt.query), false); PivotEntryCheck("view"); diff --git a/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp b/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp index 94bafd72f..8b798a83c 100644 --- a/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp @@ -163,8 +163,6 @@ unique_ptr Transformer::TransformPivotStatement(duckdb_libpgquery::PG if (pivot->aggrs) { TransformExpressionList(*pivot->aggrs, select_node->select_list); } - // transform order by/limit modifiers - TransformModifiers(select, *select_node); return std::move(select_node); } diff --git a/src/duckdb/src/parser/transform/statement/transform_pragma.cpp b/src/duckdb/src/parser/transform/statement/transform_pragma.cpp index c0ff7b8cb..63a5c35d4 100644 --- a/src/duckdb/src/parser/transform/statement/transform_pragma.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_pragma.cpp @@ -21,14 +21,14 @@ unique_ptr Transformer::TransformPragma(duckdb_libpgquery::PGPragm auto node = PGPointerCast(cell->data.ptr_value); auto expr = TransformExpression(node); - if (expr->GetExpressionType() == ExpressionType::COMPARE_EQUAL) { + if (expr->type == ExpressionType::COMPARE_EQUAL) { auto &comp = expr->Cast(); - if (comp.left->GetExpressionType() != ExpressionType::COLUMN_REF) { + if (comp.left->type != ExpressionType::COLUMN_REF) { throw ParserException("Named parameter requires a column reference on the LHS"); } auto &columnref = comp.left->Cast(); info.named_parameters.insert(make_pair(columnref.GetName(), std::move(comp.right))); - } else if (expr->GetExpressionType() == ExpressionType::COLUMN_REF) { + } else if (expr->type == ExpressionType::COLUMN_REF) { auto &colref = expr->Cast(); if (!colref.IsQualified()) { info.parameters.emplace_back(make_uniq(Value(colref.GetColumnName()))); diff --git a/src/duckdb/src/parser/transform/statement/transform_prepare.cpp b/src/duckdb/src/parser/transform/statement/transform_prepare.cpp index 9c1fc9ba2..546673127 100644 --- a/src/duckdb/src/parser/transform/statement/transform_prepare.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_prepare.cpp @@ -39,19 +39,19 @@ unique_ptr Transformer::TransformExecute(duckdb_libpgquery::PG if (!expr->IsScalar()) { throw InvalidInputException(NotAcceptedExpressionException()); } - if (!expr->GetAlias().empty() && param_idx != 0) { + if (!expr->alias.empty() && param_idx != 0) { // Found unnamed parameters mixed with named parameters throw NotImplementedException("Mixing named parameters and positional parameters is not supported yet"); } - auto param_name = expr->GetAlias(); - if (expr->GetAlias().empty()) { + auto param_name = expr->alias; + if (expr->alias.empty()) { param_name = std::to_string(param_idx + 1); if (param_idx != i) { throw NotImplementedException("Mixing named parameters and positional parameters is not supported yet"); } param_idx++; } - expr->ClearAlias(); + expr->alias.clear(); result->named_values[param_name] = std::move(expr); } intermediate_values.clear(); diff --git a/src/duckdb/src/parser/transform/statement/transform_set.cpp b/src/duckdb/src/parser/transform/statement/transform_set.cpp index 6df82aec3..68dae9311 100644 --- a/src/duckdb/src/parser/transform/statement/transform_set.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_set.cpp @@ -52,7 +52,7 @@ unique_ptr Transformer::TransformSetVariable(duckdb_libpgquery::PG D_ASSERT(stmt.args->head && stmt.args->head->data.ptr_value); auto const_val = PGPointerCast(stmt.args->head->data.ptr_value); auto expr = TransformExpression(const_val); - if (expr->GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr->type == ExpressionType::COLUMN_REF) { auto &colref = expr->Cast(); Value val; if (!colref.IsQualified()) { @@ -62,7 +62,7 @@ unique_ptr Transformer::TransformSetVariable(duckdb_libpgquery::PG } expr = make_uniq(std::move(val)); } - if (expr->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { + if (expr->type == ExpressionType::VALUE_DEFAULT) { // set to default = reset return make_uniq(std::move(name), scope); } diff --git a/src/duckdb/src/parser/transform/statement/transform_show.cpp b/src/duckdb/src/parser/transform/statement/transform_show.cpp index 648dbb9b7..12e6d6860 100644 --- a/src/duckdb/src/parser/transform/statement/transform_show.cpp +++ b/src/duckdb/src/parser/transform/statement/transform_show.cpp @@ -10,30 +10,12 @@ namespace duckdb { unique_ptr Transformer::TransformShow(duckdb_libpgquery::PGVariableShowStmt &stmt) { - // create the query that holds the show statement + string name = stmt.name; + auto select_node = make_uniq(); select_node->select_list.push_back(make_uniq()); auto showref = make_uniq(); - if (stmt.set) { - // describing a set (e.g. SHOW ALL TABLES) - push it in the table name - showref->table_name = stmt.set; - } else if (!stmt.relation->schemaname) { - // describing an unqualified relation - check if this is a "special" relation - string table_name = StringUtil::Lower(stmt.relation->relname); - if (table_name == "databases" || table_name == "tables" || table_name == "variables") { - showref->table_name = "\"" + std::move(table_name) + "\""; - } - } - if (showref->table_name.empty()) { - // describing a single relation - // wrap the relation in a "SELECT * FROM [table_name]" query - auto show_select_node = make_uniq(); - show_select_node->select_list.push_back(make_uniq()); - auto tableref = TransformRangeVar(*stmt.relation); - show_select_node->from_table = std::move(tableref); - showref->query = std::move(show_select_node); - } - + showref->table_name = std::move(name); showref->show_type = stmt.is_summary ? ShowType::SUMMARY : ShowType::DESCRIBE; select_node->from_table = std::move(showref); return std::move(select_node); diff --git a/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp b/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp index d042d881d..62ca0e1b7 100644 --- a/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +++ b/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp @@ -8,11 +8,11 @@ namespace duckdb { bool Transformer::TransformPivotInList(unique_ptr &expr, PivotColumnEntry &entry, bool root_entry) { - switch (expr->GetExpressionType()) { + switch (expr->type) { case ExpressionType::COLUMN_REF: { auto &colref = expr->Cast(); if (colref.IsQualified()) { - throw ParserException(expr->GetQueryLocation(), "PIVOT IN list cannot contain qualified column references"); + throw ParserException(expr->query_location, "PIVOT IN list cannot contain qualified column references"); } entry.values.emplace_back(colref.GetColumnName()); return true; @@ -46,11 +46,10 @@ PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot, TransformExpressionList(*pivot.pivot_columns, col.pivot_expressions); for (auto &expr : col.pivot_expressions) { if (expr->IsScalar()) { - throw ParserException(expr->GetQueryLocation(), "Cannot pivot on constant value \"%s\"", - expr->ToString()); + throw ParserException(expr->query_location, "Cannot pivot on constant value \"%s\"", expr->ToString()); } if (expr->HasSubquery()) { - throw ParserException(expr->GetQueryLocation(), "Cannot pivot on subquery \"%s\"", expr->ToString()); + throw ParserException(expr->query_location, "Cannot pivot on subquery \"%s\"", expr->ToString()); } } } else if (pivot.unpivot_columns) { @@ -63,17 +62,16 @@ PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot &pivot, auto n = PGPointerCast(node->data.ptr_value); auto expr = TransformExpression(n); PivotColumnEntry entry; - entry.alias = expr->GetAlias(); + entry.alias = expr->alias; auto transformed = TransformPivotInList(expr, entry); if (!transformed) { // could not transform into list of constant values if (is_pivot) { // for pivot - throw an exception - throw ParserException(expr->GetQueryLocation(), + throw ParserException(expr->query_location, "PIVOT IN list must contain columns or lists of columns"); } else { // for unpivot - we can forward the expression immediately - entry.values.clear(); entry.expr = std::move(expr); } } diff --git a/src/duckdb/src/parser/transformer.cpp b/src/duckdb/src/parser/transformer.cpp index c3b27dbc4..123a3b5f1 100644 --- a/src/duckdb/src/parser/transformer.cpp +++ b/src/duckdb/src/parser/transformer.cpp @@ -259,14 +259,14 @@ void Transformer::SetQueryLocation(ParsedExpression &expr, int query_location) { if (query_location < 0) { return; } - expr.SetQueryLocation(optional_idx(static_cast(query_location))); + expr.query_location = optional_idx(idx_t(query_location)); } void Transformer::SetQueryLocation(TableRef &ref, int query_location) { if (query_location < 0) { return; } - ref.query_location = optional_idx(static_cast(query_location)); + ref.query_location = optional_idx(idx_t(query_location)); } } // namespace duckdb diff --git a/src/duckdb/src/planner/bind_context.cpp b/src/duckdb/src/planner/bind_context.cpp index d135ed2ae..d446f3cf9 100644 --- a/src/duckdb/src/planner/bind_context.cpp +++ b/src/duckdb/src/planner/bind_context.cpp @@ -24,32 +24,21 @@ namespace duckdb { BindContext::BindContext(Binder &binder) : binder(binder) { } -string MinimumUniqueAlias(const BindingAlias &alias, const BindingAlias &other) { - if (!StringUtil::CIEquals(alias.GetAlias(), other.GetAlias())) { - return alias.GetAlias(); - } - if (!StringUtil::CIEquals(alias.GetSchema(), other.GetSchema())) { - return alias.GetSchema() + "." + alias.GetAlias(); - } - return alias.ToString(); -} - -optional_ptr BindContext::GetMatchingBinding(const string &column_name) { - optional_ptr result; - for (auto &binding_ptr : bindings_list) { - auto &binding = *binding_ptr; - auto is_using_binding = GetUsingBinding(column_name, binding.alias); +string BindContext::GetMatchingBinding(const string &column_name) { + string result; + for (auto &kv : bindings) { + auto binding = kv.second.get(); + auto is_using_binding = GetUsingBinding(column_name, kv.first); if (is_using_binding) { continue; } - if (binding.HasMatchingBinding(column_name)) { - if (result || is_using_binding) { + if (binding->HasMatchingBinding(column_name)) { + if (!result.empty() || is_using_binding) { throw BinderException("Ambiguous reference to column name \"%s\" (use: \"%s.%s\" " "or \"%s.%s\")", - column_name, MinimumUniqueAlias(result->alias, binding.alias), column_name, - MinimumUniqueAlias(binding.alias, result->alias), column_name); + column_name, result, column_name, kv.first, column_name); } - result = &binding; + result = kv.first; } } return result; @@ -57,17 +46,11 @@ optional_ptr BindContext::GetMatchingBinding(const string &column_name) vector BindContext::GetSimilarBindings(const string &column_name) { vector> scores; - for (auto &binding_ptr : bindings_list) { - auto binding = *binding_ptr; - for (auto &name : binding.names) { + for (auto &kv : bindings) { + auto binding = kv.second.get(); + for (auto &name : binding->names) { double distance = StringUtil::SimilarityRating(name, column_name); - // check if we need to qualify the column - auto matching_bindings = GetMatchingBindings(name); - if (matching_bindings.size() > 1) { - scores.emplace_back(binding.GetAlias() + "." + name, distance); - } else { - scores.emplace_back(name, distance); - } + scores.emplace_back(binding->alias + "." + name, distance); } } return StringUtil::TopNStrings(scores); @@ -98,7 +81,7 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n } else { result_bindings += ", "; } - result_bindings += binding.GetAlias(); + result_bindings += binding; result_bindings += "."; result_bindings += GetActualColumnName(binding, column_name); } @@ -112,8 +95,8 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n throw InternalException("Using binding found but no entries"); } -optional_ptr BindContext::GetUsingBinding(const string &column_name, const BindingAlias &binding) { - if (!binding.IsSet()) { +optional_ptr BindContext::GetUsingBinding(const string &column_name, const string &binding_name) { + if (binding_name.empty()) { throw InternalException("GetUsingBinding: expected non-empty binding_name"); } auto entry = using_columns.find(column_name); @@ -124,10 +107,8 @@ optional_ptr BindContext::GetUsingBinding(const string &column_n for (auto &using_set_ref : using_bindings) { auto &using_set = using_set_ref.get(); auto &bindings = using_set.bindings; - for (auto &using_binding : bindings) { - if (using_binding == binding) { - return &using_set; - } + if (bindings.find(binding_name) != bindings.end()) { + return &using_set; } } return nullptr; @@ -148,59 +129,52 @@ void BindContext::RemoveUsingBinding(const string &column_name, UsingColumnSet & } void BindContext::TransferUsingBinding(BindContext ¤t_context, optional_ptr current_set, - UsingColumnSet &new_set, const string &using_column) { + UsingColumnSet &new_set, const string &binding, const string &using_column) { AddUsingBinding(using_column, new_set); if (current_set) { current_context.RemoveUsingBinding(using_column, *current_set); } } -string BindContext::GetActualColumnName(Binding &binding, const string &column_name) { - column_t binding_index; - if (!binding.TryGetBindingIndex(column_name, binding_index)) { // LCOV_EXCL_START - throw InternalException("Binding with name \"%s\" does not have a column named \"%s\"", binding.GetAlias(), - column_name); - } // LCOV_EXCL_STOP - return binding.names[binding_index]; -} - -string BindContext::GetActualColumnName(const BindingAlias &binding_alias, const string &column_name) { +string BindContext::GetActualColumnName(const string &binding_name, const string &column_name) { ErrorData error; - auto binding = GetBinding(binding_alias, error); + auto binding = GetBinding(binding_name, error); if (!binding) { - throw InternalException("No binding with name \"%s\": %s", binding_alias.GetAlias(), error.RawMessage()); + throw InternalException("No binding with name \"%s\": %s", binding_name, error.RawMessage()); } - return GetActualColumnName(*binding, column_name); + column_t binding_index; + if (!binding->TryGetBindingIndex(column_name, binding_index)) { // LCOV_EXCL_START + throw InternalException("Binding with name \"%s\" does not have a column named \"%s\"", binding_name, + column_name); + } // LCOV_EXCL_STOP + return binding->names[binding_index]; } -vector> BindContext::GetMatchingBindings(const string &column_name) { - vector> result; - for (auto &binding_ptr : bindings_list) { - auto &binding = *binding_ptr; - if (binding.HasMatchingBinding(column_name)) { - result.push_back(binding); +unordered_set BindContext::GetMatchingBindings(const string &column_name) { + unordered_set result; + for (auto &kv : bindings) { + auto binding = kv.second.get(); + if (binding->HasMatchingBinding(column_name)) { + result.insert(kv.first); } } return result; } -unique_ptr BindContext::ExpandGeneratedColumn(TableBinding &table_binding, - const string &column_name) { +unique_ptr BindContext::ExpandGeneratedColumn(const string &table_name, const string &column_name) { + ErrorData error; + + auto binding = GetBinding(table_name, error); + D_ASSERT(binding && !error.HasError()); + auto &table_binding = binding->Cast(); auto result = table_binding.ExpandGeneratedColumn(column_name); - result->SetAlias(column_name); + result->alias = column_name; return result; } -unique_ptr BindContext::CreateColumnReference(const BindingAlias &table_alias, - const string &column_name, ColumnBindType bind_type) { - return CreateColumnReference(table_alias.GetCatalog(), table_alias.GetSchema(), table_alias.GetAlias(), column_name, - bind_type); -} - -unique_ptr BindContext::CreateColumnReference(const string &table_name, const string &column_name, - ColumnBindType bind_type) { +unique_ptr BindContext::CreateColumnReference(const string &table_name, const string &column_name) { string schema_name; - return CreateColumnReference(schema_name, table_name, column_name, bind_type); + return CreateColumnReference(schema_name, table_name, column_name); } static bool ColumnIsGenerated(Binding &binding, column_t index) { @@ -221,8 +195,7 @@ static bool ColumnIsGenerated(Binding &binding, column_t index) { } unique_ptr BindContext::CreateColumnReference(const string &catalog_name, const string &schema_name, - const string &table_name, const string &column_name, - ColumnBindType bind_type) { + const string &table_name, const string &column_name) { ErrorData error; vector names; if (!catalog_name.empty()) { @@ -234,27 +207,26 @@ unique_ptr BindContext::CreateColumnReference(const string &ca names.push_back(table_name); names.push_back(column_name); - BindingAlias alias(catalog_name, schema_name, table_name); auto result = make_uniq(std::move(names)); - auto binding = GetBinding(alias, column_name, error); + auto binding = GetBinding(table_name, error); if (!binding) { return std::move(result); } auto column_index = binding->GetBindingIndex(column_name); - if (bind_type == ColumnBindType::EXPAND_GENERATED_COLUMNS && ColumnIsGenerated(*binding, column_index)) { - return ExpandGeneratedColumn(binding->Cast(), column_name); + if (ColumnIsGenerated(*binding, column_index)) { + return ExpandGeneratedColumn(table_name, column_name); } else if (column_index < binding->names.size() && binding->names[column_index] != column_name) { // because of case insensitivity in the binder we rename the column to the original name // as it appears in the binding itself - result->SetAlias(binding->names[column_index]); + result->alias = binding->names[column_index]; } return std::move(result); } unique_ptr BindContext::CreateColumnReference(const string &schema_name, const string &table_name, - const string &column_name, ColumnBindType bind_type) { + const string &column_name) { string catalog_name; - return CreateColumnReference(catalog_name, schema_name, table_name, column_name, bind_type); + return CreateColumnReference(catalog_name, schema_name, table_name, column_name); } optional_ptr BindContext::GetCTEBinding(const string &ctename) { @@ -265,128 +237,21 @@ optional_ptr BindContext::GetCTEBinding(const string &ctename) { return match->second.get(); } -vector> BindContext::GetBindings(const BindingAlias &alias, ErrorData &out_error) { - if (!alias.IsSet()) { - throw InternalException("BindingAlias is not set"); - } - vector> matching_bindings; - for (auto &binding : bindings_list) { - if (binding->alias.Matches(alias)) { - matching_bindings.push_back(*binding); - } - } - if (matching_bindings.empty()) { +optional_ptr BindContext::GetBinding(const string &name, ErrorData &out_error) { + auto match = bindings.find(name); + if (match == bindings.end()) { // alias not found in this BindContext vector candidates; - for (auto &binding : bindings_list) { - candidates.push_back(binding->alias.GetAlias()); - } - string candidate_str = StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, alias.GetAlias()), - "Candidate tables"); - out_error = ErrorData(ExceptionType::BINDER, StringUtil::Format("Referenced table \"%s\" not found!%s", - alias.GetAlias(), candidate_str)); - } - return matching_bindings; -} - -string BindContext::AmbiguityException(const BindingAlias &alias, const vector> &bindings) { - D_ASSERT(bindings.size() > 1); - // found multiple matching aliases - string result = "(use: "; - for (idx_t i = 0; i < bindings.size(); i++) { - if (i > 0) { - if (i + 1 == bindings.size()) { - result += " or "; - } else { - result += ", "; - } - } - // find the minimum alias that uniquely describes this table reference - auto ¤t_alias = bindings[i].get().alias; - string minimum_alias; - bool duplicate_alias = false; - for (idx_t k = 0; k < bindings.size(); k++) { - if (k == i) { - continue; - } - auto &other_alias = bindings[k].get().alias; - if (current_alias == other_alias) { - duplicate_alias = true; - } - string new_minimum_alias = MinimumUniqueAlias(current_alias, other_alias); - if (new_minimum_alias.size() > minimum_alias.size()) { - minimum_alias = std::move(new_minimum_alias); - } - } - if (duplicate_alias) { - result = "(duplicate alias \"" + alias.ToString() + - "\", explicitly alias one of the tables using \"AS my_alias\""; - } else { - result += minimum_alias; + for (auto &kv : bindings) { + candidates.push_back(kv.first); } - } - result += ")"; - return result; -} - -optional_ptr BindContext::GetBinding(const BindingAlias &alias, const string &column_name, - ErrorData &out_error) { - auto matching_bindings = GetBindings(alias, out_error); - if (matching_bindings.empty()) { - // no bindings found + string candidate_str = + StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, name), "Candidate tables"); + out_error = ErrorData(ExceptionType::BINDER, + StringUtil::Format("Referenced table \"%s\" not found!%s", name, candidate_str)); return nullptr; } - - optional_ptr result; - // find the binding that this column name belongs to - for (auto &binding_ref : matching_bindings) { - auto &binding = binding_ref.get(); - if (!binding.HasMatchingBinding(column_name)) { - continue; - } - if (result) { - // we found multiple bindings that this column name belongs to - ambiguity - string helper_message = AmbiguityException(alias, matching_bindings); - throw BinderException("Ambiguous reference to table \"%s\" %s", alias.ToString(), helper_message); - } else { - result = &binding; - } - } - if (!result) { - // found the table binding - but could not find the column - out_error = matching_bindings[0].get().ColumnNotFoundError(column_name); - } - return result; -} - -optional_ptr BindContext::GetBinding(const BindingAlias &alias, ErrorData &out_error) { - auto matching_bindings = GetBindings(alias, out_error); - if (matching_bindings.empty()) { - return nullptr; - } - if (matching_bindings.size() > 1) { - string helper_message = AmbiguityException(alias, matching_bindings); - throw BinderException("Ambiguous reference to table \"%s\" %s", alias.ToString(), helper_message); - } - // found a single matching alias - return &matching_bindings[0].get(); -} - -optional_ptr BindContext::GetBinding(const string &name, ErrorData &out_error) { - return GetBinding(BindingAlias(name), out_error); -} - -BindingAlias GetBindingAlias(ColumnRefExpression &colref) { - if (colref.column_names.size() <= 1 || colref.column_names.size() > 4) { - throw InternalException("Cannot get binding alias from column ref unless it has 2..4 entries"); - } - if (colref.column_names.size() >= 4) { - return BindingAlias(colref.column_names[0], colref.column_names[1], colref.column_names[2]); - } - if (colref.column_names.size() == 3) { - return BindingAlias(colref.column_names[0], colref.column_names[1]); - } - return BindingAlias(colref.column_names[0]); + return match->second.get(); } BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) { @@ -395,8 +260,7 @@ BindResult BindContext::BindColumn(ColumnRefExpression &colref, idx_t depth) { } ErrorData error; - BindingAlias alias; - auto binding = GetBinding(GetBindingAlias(colref), colref.GetColumnName(), error); + auto binding = GetBinding(colref.GetTableName(), error); if (!binding) { return BindResult(std::move(error)); } @@ -407,16 +271,16 @@ string BindContext::BindColumn(PositionalReferenceExpression &ref, string &table idx_t total_columns = 0; idx_t current_position = ref.index - 1; for (auto &entry : bindings_list) { - auto &binding = *entry; + auto &binding = entry.get(); idx_t entry_column_count = binding.names.size(); if (ref.index == 0) { // this is a row id - table_name = binding.alias.GetAlias(); + table_name = binding.alias; column_name = "rowid"; return string(); } if (current_position < entry_column_count) { - table_name = binding.alias.GetAlias(); + table_name = binding.alias; column_name = binding.names[current_position]; return string(); } else { @@ -437,54 +301,38 @@ unique_ptr BindContext::PositionToColumn(PositionalReferenc return make_uniq(column_name, table_name); } -struct ExclusionListInfo { - explicit ExclusionListInfo(vector> &new_select_list) - : new_select_list(new_select_list) { - } - - vector> &new_select_list; - case_insensitive_set_t excluded_columns; - qualified_column_set_t excluded_qualified_columns; -}; - -bool CheckExclusionList(StarExpression &expr, const QualifiedColumnName &qualified_name, ExclusionListInfo &info) { - if (expr.exclude_list.find(qualified_name) != expr.exclude_list.end()) { - info.excluded_qualified_columns.insert(qualified_name); +bool BindContext::CheckExclusionList(StarExpression &expr, const string &column_name, + vector> &new_select_list, + case_insensitive_set_t &excluded_columns) { + if (expr.exclude_list.find(column_name) != expr.exclude_list.end()) { + excluded_columns.insert(column_name); return true; } - auto entry = expr.replace_list.find(qualified_name.column); + auto entry = expr.replace_list.find(column_name); if (entry != expr.replace_list.end()) { auto new_entry = entry->second->Copy(); - new_entry->SetAlias(entry->first); - info.excluded_columns.insert(entry->first); - info.new_select_list.push_back(std::move(new_entry)); + new_entry->alias = entry->first; + excluded_columns.insert(entry->first); + new_select_list.push_back(std::move(new_entry)); return true; } return false; } -void HandleRename(StarExpression &expr, const QualifiedColumnName &qualified_name, ParsedExpression &new_expr) { - auto rename_entry = expr.rename_list.find(qualified_name); - if (rename_entry != expr.rename_list.end()) { - new_expr.SetAlias(rename_entry->second); - } -} - void BindContext::GenerateAllColumnExpressions(StarExpression &expr, vector> &new_select_list) { if (bindings_list.empty()) { throw BinderException("* expression without FROM clause!"); } - ExclusionListInfo exclusion_info(new_select_list); + case_insensitive_set_t excluded_columns; if (expr.relation_name.empty()) { // SELECT * case // bind all expressions of each table in-order reference_set_t handled_using_columns; for (auto &entry : bindings_list) { - auto &binding = *entry; + auto &binding = entry.get(); for (auto &column_name : binding.names) { - QualifiedColumnName qualified_column(binding.alias, column_name); - if (CheckExclusionList(expr, qualified_column, exclusion_info)) { + if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) { continue; } // check if this column is a USING column @@ -498,28 +346,23 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, continue; } // we have not! output the using column - if (!using_binding.primary_binding.IsSet()) { + if (using_binding.primary_binding.empty()) { // no primary binding: output a coalesce auto coalesce = make_uniq(ExpressionType::OPERATOR_COALESCE); for (auto &child_binding : using_binding.bindings) { coalesce->children.push_back(make_uniq(column_name, child_binding)); } - coalesce->SetAlias(column_name); - HandleRename(expr, qualified_column, *coalesce); + coalesce->alias = column_name; new_select_list.push_back(std::move(coalesce)); } else { // primary binding: output the qualified column ref - auto new_expr = make_uniq(column_name, using_binding.primary_binding); - HandleRename(expr, qualified_column, *new_expr); - new_select_list.push_back(std::move(new_expr)); + new_select_list.push_back( + make_uniq(column_name, using_binding.primary_binding)); } handled_using_columns.insert(using_binding); continue; } - auto new_expr = - CreateColumnReference(binding.alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS); - HandleRename(expr, qualified_column, *new_expr); - new_select_list.push_back(std::move(new_expr)); + new_select_list.push_back(make_uniq(column_name, binding.alias)); } } } else { @@ -529,10 +372,11 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, auto binding = GetBinding(expr.relation_name, error); bool is_struct_ref = false; if (!binding) { - binding = GetMatchingBinding(expr.relation_name); - if (!binding) { + auto binding_name = GetMatchingBinding(expr.relation_name); + if (binding_name.empty()) { error.Throw(); } + binding = bindings[binding_name].get(); is_struct_ref = true; } @@ -545,28 +389,22 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, } auto &struct_children = StructType::GetChildTypes(col_type); vector column_names(3); - column_names[0] = binding->alias.GetAlias(); + column_names[0] = binding->alias; column_names[1] = expr.relation_name; for (auto &child : struct_children) { - QualifiedColumnName qualified_name(child.first); - if (CheckExclusionList(expr, qualified_name, exclusion_info)) { + if (CheckExclusionList(expr, child.first, new_select_list, excluded_columns)) { continue; } column_names[2] = child.first; - auto new_expr = make_uniq(column_names); - HandleRename(expr, qualified_name, *new_expr); - new_select_list.push_back(std::move(new_expr)); + new_select_list.push_back(make_uniq(column_names)); } } else { for (auto &column_name : binding->names) { - QualifiedColumnName qualified_name(binding->alias, column_name); - if (CheckExclusionList(expr, qualified_name, exclusion_info)) { + if (CheckExclusionList(expr, column_name, new_select_list, excluded_columns)) { continue; } - auto new_expr = - CreateColumnReference(binding->alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS); - HandleRename(expr, qualified_name, *new_expr); - new_select_list.push_back(std::move(new_expr)); + + new_select_list.push_back(make_uniq(column_name, binding->alias)); } } } @@ -575,14 +413,13 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, expr.replace_list.clear(); } for (auto &excluded : expr.exclude_list) { - if (exclusion_info.excluded_qualified_columns.find(excluded) == - exclusion_info.excluded_qualified_columns.end()) { - throw BinderException("Column \"%s\" in EXCLUDE list not found in %s", excluded.ToString(), + if (excluded_columns.find(excluded) == excluded_columns.end()) { + throw BinderException("Column \"%s\" in EXCLUDE list not found in %s", excluded, expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str()); } } for (auto &entry : expr.replace_list) { - if (exclusion_info.excluded_columns.find(entry.first) == exclusion_info.excluded_columns.end()) { + if (excluded_columns.find(entry.first) == excluded_columns.end()) { throw BinderException("Column \"%s\" in REPLACE list not found in %s", entry.first, expr.relation_name.empty() ? "FROM clause" : expr.relation_name.c_str()); } @@ -591,7 +428,7 @@ void BindContext::GenerateAllColumnExpressions(StarExpression &expr, void BindContext::GetTypesAndNames(vector &result_names, vector &result_types) { for (auto &binding_entry : bindings_list) { - auto &binding = *binding_entry; + auto &binding = binding_entry.get(); D_ASSERT(binding.names.size() == binding.types.size()); for (idx_t i = 0; i < binding.names.size(); i++) { result_names.push_back(binding.names[i]); @@ -600,27 +437,24 @@ void BindContext::GetTypesAndNames(vector &result_names, vector binding) { - bindings_list.push_back(std::move(binding)); -} - -void BindContext::AddBaseTable(idx_t index, const string &alias, const vector &names, - const vector &types, vector &bound_column_ids, - StandardEntry &entry, bool add_row_id) { - AddBinding(make_uniq(alias, types, names, bound_column_ids, &entry, index, add_row_id)); +void BindContext::AddBinding(const string &alias, unique_ptr binding) { + if (bindings.find(alias) != bindings.end()) { + throw BinderException("Duplicate alias \"%s\" in query!", alias); + } + bindings_list.push_back(*binding); + bindings[alias] = std::move(binding); } void BindContext::AddBaseTable(idx_t index, const string &alias, const vector &names, - const vector &types, vector &bound_column_ids, - const string &table_name) { - AddBinding(make_uniq(alias.empty() ? table_name : alias, types, names, bound_column_ids, nullptr, - index, true)); + const vector &types, vector &bound_column_ids, + StandardEntry *entry, bool add_row_id) { + AddBinding(alias, make_uniq(alias, types, names, bound_column_ids, entry, index, add_row_id)); } void BindContext::AddTableFunction(idx_t index, const string &alias, const vector &names, - const vector &types, vector &bound_column_ids, - optional_ptr entry) { - AddBinding(make_uniq(alias, types, names, bound_column_ids, entry, index)); + const vector &types, vector &bound_column_ids, + StandardEntry *entry) { + AddBinding(alias, make_uniq(alias, types, names, bound_column_ids, entry, index)); } static string AddColumnNameToBinding(const string &base_name, case_insensitive_set_t ¤t_names) { @@ -659,13 +493,13 @@ void BindContext::AddSubquery(idx_t index, const string &alias, SubqueryRef &ref void BindContext::AddEntryBinding(idx_t index, const string &alias, const vector &names, const vector &types, StandardEntry &entry) { - AddBinding(make_uniq(alias, types, names, index, entry)); + AddBinding(alias, make_uniq(alias, types, names, index, entry)); } void BindContext::AddView(idx_t index, const string &alias, SubqueryRef &ref, BoundQueryNode &subquery, - ViewCatalogEntry &view) { + ViewCatalogEntry *view) { auto names = AliasColumnNames(alias, subquery.names, ref.column_name_alias); - AddEntryBinding(index, alias, names, subquery.types, view.Cast()); + AddEntryBinding(index, alias, names, subquery.types, view->Cast()); } void BindContext::AddSubquery(idx_t index, const string &alias, TableFunctionRef &ref, BoundQueryNode &subquery) { @@ -675,63 +509,57 @@ void BindContext::AddSubquery(idx_t index, const string &alias, TableFunctionRef void BindContext::AddGenericBinding(idx_t index, const string &alias, const vector &names, const vector &types) { - AddBinding(make_uniq(BindingType::BASE, BindingAlias(alias), types, names, index)); + AddBinding(alias, make_uniq(BindingType::BASE, alias, types, names, index)); } void BindContext::AddCTEBinding(idx_t index, const string &alias, const vector &names, const vector &types) { - auto binding = make_shared_ptr(BindingType::BASE, BindingAlias(alias), types, names, index); + auto binding = make_shared_ptr(BindingType::BASE, alias, types, names, index); if (cte_bindings.find(alias) != cte_bindings.end()) { - throw BinderException("Duplicate CTE binding \"%s\" in query!", alias); + throw BinderException("Duplicate alias \"%s\" in query!", alias); } cte_bindings[alias] = std::move(binding); cte_references[alias] = make_shared_ptr(0); } void BindContext::AddContext(BindContext other) { + for (auto &binding : other.bindings) { + if (bindings.find(binding.first) != bindings.end()) { + throw BinderException("Duplicate alias \"%s\" in query!", binding.first); + } + bindings[binding.first] = std::move(binding.second); + } for (auto &binding : other.bindings_list) { - AddBinding(std::move(binding)); + bindings_list.push_back(binding); } for (auto &entry : other.using_columns) { for (auto &alias : entry.second) { +#ifdef DEBUG + for (auto &other_alias : using_columns[entry.first]) { + for (auto &col : alias.get().bindings) { + D_ASSERT(other_alias.get().bindings.find(col) == other_alias.get().bindings.end()); + } + } +#endif using_columns[entry.first].insert(alias); } } } -vector BindContext::GetBindingAliases() { - vector result; - for (auto &binding : bindings_list) { - result.push_back(BindingAlias(binding->alias)); +void BindContext::RemoveContext(vector> &other_bindings_list) { + for (auto &other_binding : other_bindings_list) { + auto it = std::remove_if(bindings_list.begin(), bindings_list.end(), [other_binding](reference x) { + return x.get().alias == other_binding.get().alias; + }); + bindings_list.erase(it, bindings_list.end()); } - return result; -} -void BindContext::RemoveContext(const vector &aliases) { - for (auto &alias : aliases) { - // remove the binding from any USING columns - vector removed_using_columns; - for (auto &using_sets : using_columns) { - for (auto &using_set_ref : using_sets.second) { - auto &using_set = using_set_ref.get(); - auto it = std::remove_if(using_set.bindings.begin(), using_set.bindings.end(), - [&](const BindingAlias &using_alias) { return using_alias == alias; }); - using_set.bindings.erase(it, using_set.bindings.end()); - if (using_set.bindings.empty() || using_set.primary_binding == alias) { - // if the using column is no longer referred to - remove it entirely - removed_using_columns.push_back(using_sets.first); - } - } - } - for (auto &removed_col : removed_using_columns) { - using_columns.erase(removed_col); + for (auto &other_binding : other_bindings_list) { + auto &alias = other_binding.get().alias; + if (bindings.find(alias) != bindings.end()) { + bindings.erase(alias); } - - // remove the binding from the list of bindings - auto it = std::remove_if(bindings_list.begin(), bindings_list.end(), - [&](unique_ptr &x) { return x->alias == alias; }); - bindings_list.erase(it, bindings_list.end()); } } diff --git a/src/duckdb/src/planner/binder.cpp b/src/duckdb/src/planner/binder.cpp index 7333ac393..9f0abf398 100644 --- a/src/duckdb/src/planner/binder.cpp +++ b/src/duckdb/src/planner/binder.cpp @@ -7,7 +7,6 @@ #include "duckdb/common/helper.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/optimizer/optimizer.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" #include "duckdb/parser/parsed_expression_iterator.hpp" @@ -60,7 +59,7 @@ Binder::Binder(ClientContext &context, shared_ptr parent_p, BinderType b : context(context), bind_context(*this), parent(std::move(parent_p)), bound_tables(0), binder_type(binder_type), entry_retriever(context) { if (parent) { - entry_retriever.Inherit(parent->entry_retriever); + entry_retriever.SetCallback(parent->entry_retriever.GetCallback()); // We have to inherit macro and lambda parameter bindings and from the parent binder, if there is a parent. macro_binding = parent->macro_binding; @@ -211,7 +210,7 @@ void Binder::AddCTEMap(CommonTableExpressionMap &cte_map) { static void GetTableRefCountsNode(case_insensitive_map_t &cte_ref_counts, QueryNode &node); static void GetTableRefCountsExpr(case_insensitive_map_t &cte_ref_counts, ParsedExpression &expr) { - if (expr.GetExpressionType() == ExpressionType::SUBQUERY) { + if (expr.type == ExpressionType::SUBQUERY) { auto &subquery = expr.Cast(); GetTableRefCountsNode(cte_ref_counts, *subquery.subquery->node); } else { @@ -238,7 +237,7 @@ static bool ParsedExpressionIsAggregate(Binder &binder, const ParsedExpression & if (expr.GetExpressionClass() == ExpressionClass::FUNCTION) { auto &function = expr.Cast(); QueryErrorContext error_context; - auto entry = binder.GetCatalogEntry(CatalogType::AGGREGATE_FUNCTION_ENTRY, function.catalog, function.schema, + auto entry = binder.GetCatalogEntry(CatalogType::SCALAR_FUNCTION_ENTRY, function.catalog, function.schema, function.function_name, OnEntryNotFound::RETURN_NULL, error_context); if (entry && entry->type == CatalogType::AGGREGATE_FUNCTION_ENTRY) { return true; @@ -344,8 +343,9 @@ unique_ptr Binder::BindNode(QueryNode &node) { BoundStatement Binder::Bind(QueryNode &node) { BoundStatement result; if (node.type != QueryNodeType::CTE_NODE && // Issue #13850 - Don't auto-materialize if users materialize (for now) - !Optimizer::OptimizerDisabled(context, OptimizerType::MATERIALIZED_CTE) && context.config.enable_optimizer && - OptimizeCTEs(node)) { + context.db->config.options.disabled_optimizers.find(OptimizerType::MATERIALIZED_CTE) == + context.db->config.options.disabled_optimizers.end() && + context.config.enable_optimizer && OptimizeCTEs(node)) { switch (node.type) { case QueryNodeType::SELECT_NODE: result = BindWithCTE(node.Cast()); @@ -584,30 +584,51 @@ void Binder::AddCorrelatedColumn(const CorrelatedColumnInfo &info) { } } -optional_ptr Binder::GetMatchingBinding(const string &table_name, const string &column_name, - ErrorData &error) { +bool Binder::HasMatchingBinding(const string &table_name, const string &column_name, ErrorData &error) { string empty_schema; - return GetMatchingBinding(empty_schema, table_name, column_name, error); + return HasMatchingBinding(empty_schema, table_name, column_name, error); } -optional_ptr Binder::GetMatchingBinding(const string &schema_name, const string &table_name, - const string &column_name, ErrorData &error) { +bool Binder::HasMatchingBinding(const string &schema_name, const string &table_name, const string &column_name, + ErrorData &error) { string empty_catalog; - return GetMatchingBinding(empty_catalog, schema_name, table_name, column_name, error); + return HasMatchingBinding(empty_catalog, schema_name, table_name, column_name, error); } -optional_ptr Binder::GetMatchingBinding(const string &catalog_name, const string &schema_name, - const string &table_name, const string &column_name, - ErrorData &error) { +bool Binder::HasMatchingBinding(const string &catalog_name, const string &schema_name, const string &table_name, + const string &column_name, ErrorData &error) { optional_ptr binding; D_ASSERT(!lambda_bindings); - if (macro_binding && table_name == macro_binding->GetAlias()) { + if (macro_binding && table_name == macro_binding->alias) { binding = optional_ptr(macro_binding.get()); } else { - BindingAlias alias(catalog_name, schema_name, table_name); - binding = bind_context.GetBinding(alias, column_name, error); + binding = bind_context.GetBinding(table_name, error); } - return binding; + + if (!binding) { + return false; + } + if (!catalog_name.empty() || !schema_name.empty()) { + auto catalog_entry = binding->GetStandardEntry(); + if (!catalog_entry) { + return false; + } + if (!catalog_name.empty() && catalog_entry->catalog.GetName() != catalog_name) { + return false; + } + if (!schema_name.empty() && catalog_entry->schema.name != schema_name) { + return false; + } + if (catalog_entry->name != table_name) { + return false; + } + } + bool binding_found; + binding_found = binding->HasMatchingBinding(column_name); + if (!binding_found) { + error = binding->ColumnNotFoundError(column_name); + } + return binding_found; } void Binder::SetBindingMode(BindingMode mode) { @@ -658,7 +679,7 @@ case_insensitive_map_t> &Binder::GetReplacementScans() { // FIXME: this is extremely naive void VerifyNotExcluded(ParsedExpression &expr) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &column_ref = expr.Cast(); if (!column_ref.IsQualified()) { return; @@ -682,18 +703,19 @@ BoundStatement Binder::BindReturning(vector> return auto binder = Binder::CreateBinder(context); - vector bound_columns; + vector bound_columns; idx_t column_count = 0; for (auto &col : table.GetColumns().Logical()) { names.push_back(col.Name()); types.push_back(col.Type()); if (!col.Generated()) { - bound_columns.emplace_back(column_count); + bound_columns.push_back(column_count); } column_count++; } - binder->bind_context.AddBaseTable(update_table_index, alias, names, types, bound_columns, table, false); + binder->bind_context.AddBaseTable(update_table_index, alias.empty() ? table.name : alias, names, types, + bound_columns, &table, false); ReturningBinder returning_binder(*binder, context); vector> projection_expressions; diff --git a/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp index beba67f83..2051bb1e9 100644 --- a/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_aggregate_expression.cpp @@ -4,7 +4,6 @@ #include "duckdb/execution/expression_executor.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/function/scalar/generic_functions.hpp" -#include "duckdb/function/scalar/generic_common.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" @@ -21,31 +20,16 @@ namespace duckdb { -static bool IsFunctionallyDependent(const unique_ptr &expr, const vector> &deps) { - // Volatile expressions can't depend on anything else - if (expr->IsVolatile()) { - return false; - } - // Constant expressions are always FD - if (expr->IsFoldable()) { - return true; - } - // If the expression matches ANY of the dependencies, then it is FD on them - for (const auto &dep : deps) { - // We don't need to check volatility of the dependencies because we checked it for the expression. - if (expr->Equals(*dep)) { - return true; - } +static bool ExtractFunctionalDependencies(column_binding_set_t &deps, const unique_ptr &expr) { + if (expr->type == ExpressionType::BOUND_COLUMN_REF) { + auto &colref = expr->Cast(); + deps.insert(colref.binding); } - // The expression doesn't match any dependency, so check ALL children. - bool has_children = false; - bool are_dependent = true; - ExpressionIterator::EnumerateChildren(*expr, [&](unique_ptr &child) { - has_children = true; - are_dependent &= IsFunctionallyDependent(child, deps); - }); - return has_children && are_dependent; + bool is_volatile = expr->IsVolatile(); + ExpressionIterator::EnumerateChildren( + *expr, [&](unique_ptr &child) { is_volatile |= ExtractFunctionalDependencies(deps, child); }); + return is_volatile; } static Value NegatePercentileValue(const Value &v, const bool desc) { @@ -90,7 +74,7 @@ static Value NegatePercentileValue(const Value &v, const bool desc) { static void NegatePercentileFractions(ClientContext &context, unique_ptr &fractions, bool desc) { D_ASSERT(fractions.get()); - D_ASSERT(fractions->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(fractions->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound = BoundExpression::GetExpression(*fractions); if (!bound->IsFoldable()) { @@ -157,7 +141,7 @@ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFu // Bind the ORDER BYs, if any if (aggr.order_bys && !aggr.order_bys->orders.empty()) { for (auto &order : aggr.order_bys->orders) { - if (order.expression->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (order.expression->type == ExpressionType::VALUE_CONSTANT) { auto &const_expr = order.expression->Cast(); if (!const_expr.value.type().IsIntegral()) { auto &config = ClientConfig::GetConfig(context); @@ -255,7 +239,7 @@ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFu } // bind the aggregate - FunctionBinder function_binder(binder); + FunctionBinder function_binder(context); auto best_function = function_binder.BindFunction(func.name, func.functions, types, error); if (!best_function.IsValid()) { error.AddQueryLocation(aggr); @@ -280,9 +264,26 @@ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFu // If the aggregate is DISTINCT then the ORDER BYs need to be functional dependencies of the arguments. if (aggr.distinct && order_bys) { - bool in_args = true; + column_binding_set_t child_dependencies; + bool children_volatile = false; + for (const auto &child : children) { + children_volatile |= ExtractFunctionalDependencies(child_dependencies, child); + } + + column_binding_set_t order_dependencies; + bool order_volatile = false; for (const auto &order_by : order_bys->orders) { - in_args &= IsFunctionallyDependent(order_by.expression, children); + order_volatile |= ExtractFunctionalDependencies(order_dependencies, order_by.expression); + } + + bool in_args = !children_volatile && !order_volatile; + if (in_args) { + for (const auto &binding : order_dependencies) { + if (!child_dependencies.count(binding)) { + in_args = false; + break; + } + } } if (!in_args) { @@ -313,7 +314,7 @@ BindResult BaseSelectBinder::BindAggregate(FunctionExpression &aggr, AggregateFu // now create a column reference referring to the aggregate auto colref = make_uniq( - aggr.GetAlias().empty() ? node.aggregates[aggr_index]->ToString() : aggr.GetAlias(), + aggr.alias.empty() ? node.aggregates[aggr_index]->ToString() : aggr.alias, node.aggregates[aggr_index]->return_type, ColumnBinding(node.aggregate_index, aggr_index), depth); // move the aggregate expression into the set of bound aggregates return BindResult(std::move(colref)); diff --git a/src/duckdb/src/planner/binder/expression/bind_between_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_between_expression.cpp index 09c92dd48..6a0043fc6 100644 --- a/src/duckdb/src/planner/binder/expression/bind_between_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_between_expression.cpp @@ -30,15 +30,13 @@ BindResult ExpressionBinder::BindExpression(BetweenExpression &expr, idx_t depth // cast the input types to the same type // now obtain the result type of the input types LogicalType input_type; - if (!BoundComparisonExpression::TryBindComparison(context, input_sql_type, lower_sql_type, input_type, - expr.GetExpressionType())) { + if (!BoundComparisonExpression::TryBindComparison(context, input_sql_type, lower_sql_type, input_type, expr.type)) { throw BinderException(expr, "Cannot mix values of type %s and %s in BETWEEN clause - an explicit cast is required", input_sql_type.ToString(), lower_sql_type.ToString()); } - if (!BoundComparisonExpression::TryBindComparison(context, input_type, upper_sql_type, input_type, - expr.GetExpressionType())) { + if (!BoundComparisonExpression::TryBindComparison(context, input_type, upper_sql_type, input_type, expr.type)) { throw BinderException(expr, "Cannot mix values of type %s and %s in BETWEEN clause - an explicit cast is required", input_type.ToString(), upper_sql_type.ToString()); diff --git a/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp index 1c9bc238b..03a6fdbda 100644 --- a/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_columnref_expression.cpp @@ -60,7 +60,7 @@ unique_ptr ExpressionBinder::QualifyColumnName(const string &c // we are referencing a USING column // check if we can refer to one of the base columns directly unique_ptr expression; - if (using_binding->primary_binding.IsSet()) { + if (!using_binding->primary_binding.empty()) { // we can! just assign the table name and re-bind return binder.bind_context.CreateColumnReference(using_binding->primary_binding, column_name); } else { @@ -81,25 +81,26 @@ unique_ptr ExpressionBinder::QualifyColumnName(const string &c } // find a table binding that contains this column name - auto table_binding = binder.bind_context.GetMatchingBinding(column_name); + string table_name = binder.bind_context.GetMatchingBinding(column_name); // throw an error if a macro parameter name conflicts with a column name auto is_macro_column = false; if (binder.macro_binding && binder.macro_binding->HasMatchingBinding(column_name)) { is_macro_column = true; - if (table_binding) { + if (!table_name.empty()) { throw BinderException("Conflicting column names for column " + column_name + "!"); } } // bind as a macro column if (is_macro_column) { - return binder.bind_context.CreateColumnReference(binder.macro_binding->alias, column_name); + D_ASSERT(!binder.macro_binding->alias.empty()); + return make_uniq(column_name, binder.macro_binding->alias); } // bind as a regular column - if (table_binding) { - return binder.bind_context.CreateColumnReference(table_binding->alias, column_name); + if (!table_name.empty()) { + return binder.bind_context.CreateColumnReference(table_name, column_name); } // it's not, find candidates and error @@ -113,8 +114,9 @@ void ExpressionBinder::QualifyColumnNames(unique_ptr &expr, const bool within_function_expression) { bool next_within_function_expression = false; - switch (expr->GetExpressionType()) { + switch (expr->type) { case ExpressionType::COLUMN_REF: { + auto &col_ref = expr->Cast(); // don't qualify lambda parameters @@ -126,28 +128,28 @@ void ExpressionBinder::QualifyColumnNames(unique_ptr &expr, auto new_expr = QualifyColumnName(col_ref, error); if (new_expr) { - if (!expr->GetAlias().empty()) { + if (!expr->alias.empty()) { // Pre-existing aliases are added to the qualified column reference - new_expr->SetAlias(expr->GetAlias()); + new_expr->alias = expr->alias; } else if (within_function_expression) { // Qualifying the column reference may add an alias, but this needs to be removed within function // expressions, because the alias here means a named parameter instead of a positional parameter - new_expr->ClearAlias(); + new_expr->alias = ""; } // replace the expression with the qualified column reference - new_expr->SetQueryLocation(col_ref.GetQueryLocation()); + new_expr->query_location = col_ref.query_location; expr = std::move(new_expr); } return; } case ExpressionType::POSITIONAL_REFERENCE: { auto &ref = expr->Cast(); - if (ref.GetAlias().empty()) { + if (ref.alias.empty()) { string table_name, column_name; auto error = binder.bind_context.BindColumn(ref, table_name, column_name); if (error.empty()) { - ref.SetAlias(column_name); + ref.alias = column_name; } } break; @@ -176,7 +178,7 @@ void ExpressionBinder::QualifyColumnNamesInLambda(FunctionExpression &function, vector> &lambda_params) { for (auto &child : function.children) { - if (child->GetExpressionClass() != ExpressionClass::LAMBDA) { + if (child->expression_class != ExpressionClass::LAMBDA) { // not a lambda expression QualifyColumnNames(child, lambda_params, true); continue; @@ -218,11 +220,6 @@ void ExpressionBinder::QualifyColumnNames(Binder &binder, unique_ptr &expr) { - vector> lambda_params; - expression_binder.QualifyColumnNames(expr, lambda_params); -} - unique_ptr ExpressionBinder::CreateStructExtract(unique_ptr base, const string &field_name) { @@ -234,57 +231,59 @@ unique_ptr ExpressionBinder::CreateStructExtract(unique_ptr ExpressionBinder::CreateStructPack(ColumnRefExpression &col_ref) { - if (col_ref.column_names.size() > 3) { - return nullptr; - } - D_ASSERT(!col_ref.column_names.empty()); + + D_ASSERT(col_ref.column_names.size() <= 3); // get a matching binding ErrorData error; - optional_ptr binding; - switch (col_ref.column_names.size()) { - case 1: { - // single entry - this must be the table name - BindingAlias alias(col_ref.column_names[0]); - binding = binder.bind_context.GetBinding(alias, error); - break; - } - case 2: { - // two entries - this can either be "catalog.table" or "schema.table" - try both - BindingAlias alias(col_ref.column_names[0], col_ref.column_names[1]); - binding = binder.bind_context.GetBinding(alias, error); - if (!binding) { - alias = BindingAlias(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1]); - binding = binder.bind_context.GetBinding(alias, error); - } - break; - } - case 3: { - // three entries - this must be "catalog.schema.table" - BindingAlias alias(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2]); - binding = binder.bind_context.GetBinding(alias, error); - break; - } - default: - throw InternalException("Expected 1, 2 or 3 column names for CreateStructPack"); - } + auto &table_name = col_ref.column_names.back(); + auto binding = binder.bind_context.GetBinding(table_name, error); + if (!binding) { return nullptr; } + if (col_ref.column_names.size() >= 2) { + // "schema_name.table_name" + auto catalog_entry = binding->GetStandardEntry(); + if (!catalog_entry) { + return nullptr; + } + + if (catalog_entry->name != table_name) { + return nullptr; + } + + if (col_ref.column_names.size() == 2) { + auto &qualifier = col_ref.column_names[0]; + if (catalog_entry->catalog.GetName() != qualifier && catalog_entry->schema.name != qualifier) { + return nullptr; + } + + } else if (col_ref.column_names.size() == 3) { + auto &catalog_name = col_ref.column_names[0]; + auto &schema_name = col_ref.column_names[1]; + if (catalog_entry->catalog.GetName() != catalog_name || catalog_entry->schema.name != schema_name) { + return nullptr; + } + + } else { + throw InternalException("Expected 2 or 3 column names for CreateStructPack"); + } + } + // We found the table, now create the struct_pack expression vector> child_expressions; child_expressions.reserve(binding->names.size()); for (const auto &column_name : binding->names) { - child_expressions.push_back(binder.bind_context.CreateColumnReference( - binding->alias, column_name, ColumnBindType::DO_NOT_EXPAND_GENERATED_COLUMNS)); + child_expressions.push_back(make_uniq(column_name, table_name)); } return make_uniq("struct_pack", std::move(child_expressions)); } -unique_ptr ExpressionBinder::QualifyColumnNameWithManyDotsInternal(ColumnRefExpression &col_ref, - ErrorData &error, - idx_t &struct_extract_start) { +unique_ptr ExpressionBinder::QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, + ErrorData &error) { + // two or more dots (i.e. "part1.part2.part3.part4...") // -> part1 is a catalog, part2 is a schema, part3 is a table, part4 is a column name, part 5 and beyond are // struct fields @@ -300,56 +299,50 @@ unique_ptr ExpressionBinder::QualifyColumnNameWithManyDotsInte // -> 3. resolve "part1" as a table // -> 4. resolve "part1" as a column + unique_ptr result_expr; + idx_t struct_extract_start; + // first check if part1 is a catalog - optional_ptr binding; - if (col_ref.column_names.size() > 3) { - binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], - col_ref.column_names[3], error); - if (binding) { - // part1 is a catalog - the column reference is "catalog.schema.table.column" - struct_extract_start = 4; - return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[3]); - } - } - binding = binder.GetMatchingBinding(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1], - col_ref.column_names[2], error); - if (binding) { + if (col_ref.column_names.size() > 3 && + binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], + col_ref.column_names[3], error)) { + // part1 is a catalog - the column reference is "catalog.schema.table.column" + result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1], + col_ref.column_names[2], col_ref.column_names[3]); + struct_extract_start = 4; + + } else if (binder.HasMatchingBinding(col_ref.column_names[0], INVALID_SCHEMA, col_ref.column_names[1], + col_ref.column_names[2], error)) { // part1 is a catalog - the column reference is "catalog.table.column" + result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], INVALID_SCHEMA, + col_ref.column_names[1], col_ref.column_names[2]); struct_extract_start = 3; - return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[2]); - } - binding = - binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], error); - if (binding) { + + } else if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], col_ref.column_names[2], + error)) { // part1 is a schema - the column reference is "schema.table.column" // any additional fields are turned into struct_extract calls + result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1], + col_ref.column_names[2]); struct_extract_start = 3; - return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[2]); - } - binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error); - if (binding) { + + } else if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error)) { // part1 is a table // the column reference is "table.column" // any additional fields are turned into struct_extract calls + result_expr = binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1]); struct_extract_start = 2; - return binder.bind_context.CreateColumnReference(binding->alias, col_ref.column_names[1]); - } - // part1 could be a column - ErrorData col_error; - auto result_expr = QualifyColumnName(col_ref.column_names[0], col_error); - if (result_expr) { + + } else { + // part1 could be a column + ErrorData col_error; + result_expr = QualifyColumnName(col_ref.column_names[0], col_error); + if (!result_expr) { + // it is not! Try creating an implicit struct_pack + return CreateStructPack(col_ref); + } // it is! add the struct extract calls struct_extract_start = 1; - return result_expr; - } - return CreateStructPack(col_ref); -} -unique_ptr ExpressionBinder::QualifyColumnNameWithManyDots(ColumnRefExpression &col_ref, - ErrorData &error) { - idx_t struct_extract_start = col_ref.column_names.size(); - auto result_expr = QualifyColumnNameWithManyDotsInternal(col_ref, error, struct_extract_start); - if (!result_expr) { - return nullptr; } // create a struct extract with all remaining column names @@ -394,10 +387,9 @@ unique_ptr ExpressionBinder::QualifyColumnName(ColumnRefExpres // -> part1 is a column, part2 is a property of that column (i.e. struct_extract) // first check if part1 is a table, and part2 is a standard column name - auto binding = binder.GetMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error); - if (binding) { + if (binder.HasMatchingBinding(col_ref.column_names[0], col_ref.column_names[1], error)) { // it is! return the column reference directly - return binder.bind_context.CreateColumnReference(binding->alias, col_ref.GetColumnName()); + return binder.bind_context.CreateColumnReference(col_ref.column_names[0], col_ref.column_names[1]); } // otherwise check if we can turn this into a struct extract @@ -447,16 +439,16 @@ BindResult ExpressionBinder::BindExpression(ColumnRefExpression &col_ref_p, idx_ return BindResult(std::move(error)); } - expr->SetQueryLocation(col_ref_p.GetQueryLocation()); + expr->query_location = col_ref_p.query_location; // the above QualifyColumName returns a generated expression for a generated // column, and struct_extract for a struct, or a lambda reference expression, // all of them are not column reference expressions, so we return here - if (expr->GetExpressionType() != ExpressionType::COLUMN_REF) { - auto alias = expr->GetAlias(); + if (expr->type != ExpressionType::COLUMN_REF) { + auto alias = expr->alias; auto result = BindExpression(expr, depth); if (result.expression) { - result.expression->SetAlias(std::move(alias)); + result.expression->alias = std::move(alias); } return result; } @@ -469,7 +461,7 @@ BindResult ExpressionBinder::BindExpression(ColumnRefExpression &col_ref_p, idx_ D_ASSERT(col_ref.IsQualified()); auto &table_name = col_ref.GetTableName(); - if (binder.macro_binding && table_name == binder.macro_binding->GetAlias()) { + if (binder.macro_binding && table_name == binder.macro_binding->alias) { result = binder.macro_binding->Bind(col_ref, depth); } else { result = binder.bind_context.BindColumn(col_ref, depth); @@ -483,7 +475,7 @@ BindResult ExpressionBinder::BindExpression(ColumnRefExpression &col_ref_p, idx_ // we bound the column reference BoundColumnReferenceInfo ref; ref.name = col_ref.column_names.back(); - ref.query_location = col_ref.GetQueryLocation(); + ref.query_location = col_ref.query_location; bound_columns.push_back(std::move(ref)); return result; } diff --git a/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp index cd490f433..2ec1611a5 100644 --- a/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_comparison_expression.cpp @@ -16,9 +16,9 @@ namespace duckdb { bool ExpressionBinder::PushCollation(ClientContext &context, unique_ptr &source, - const LogicalType &sql_type, CollationType type) { + const LogicalType &sql_type) { auto &collation_binding = CollationBinding::Get(context); - return collation_binding.PushCollation(context, source, sql_type, type); + return collation_binding.PushCollation(context, source, sql_type); } void ExpressionBinder::TestCollation(ClientContext &context, const string &collation) { @@ -139,7 +139,7 @@ LogicalType BoundComparisonExpression::BindComparison(ClientContext &context, co } LogicalType ExpressionBinder::GetExpressionReturnType(const Expression &expr) { - if (expr.GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { + if (expr.expression_class == ExpressionClass::BOUND_CONSTANT) { if (expr.return_type == LogicalTypeId::VARCHAR && StringType::GetCollation(expr.return_type).empty()) { return LogicalTypeId::STRING_LITERAL; } @@ -170,8 +170,7 @@ BindResult ExpressionBinder::BindExpression(ComparisonExpression &expr, idx_t de // cast the input types to the same type // now obtain the result type of the input types LogicalType input_type; - if (!BoundComparisonExpression::TryBindComparison(context, left_sql_type, right_sql_type, input_type, - expr.GetExpressionType())) { + if (!BoundComparisonExpression::TryBindComparison(context, left_sql_type, right_sql_type, input_type, expr.type)) { return BindResult(BinderException(expr, "Cannot compare values of type %s and type %s - an explicit cast is required", left_sql_type.ToString(), right_sql_type.ToString())); @@ -186,8 +185,7 @@ BindResult ExpressionBinder::BindExpression(ComparisonExpression &expr, idx_t de PushCollation(context, right, input_type); // now create the bound comparison expression - return BindResult( - make_uniq(expr.GetExpressionType(), std::move(left), std::move(right))); + return BindResult(make_uniq(expr.type, std::move(left), std::move(right))); } } // namespace duckdb diff --git a/src/duckdb/src/planner/binder/expression/bind_conjunction_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_conjunction_expression.cpp index b93cb5a2d..5125b1dba 100644 --- a/src/duckdb/src/planner/binder/expression/bind_conjunction_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_conjunction_expression.cpp @@ -17,7 +17,7 @@ BindResult ExpressionBinder::BindExpression(ConjunctionExpression &expr, idx_t d // the children have been successfully resolved // cast the input types to boolean (if necessary) // and construct the bound conjunction expression - auto result = make_uniq(expr.GetExpressionType()); + auto result = make_uniq(expr.type); for (auto &child_expr : expr.children) { auto &child = BoundExpression::GetExpression(*child_expr); result->children.push_back(BoundCastExpression::AddCastToType(context, std::move(child), LogicalType::BOOLEAN)); diff --git a/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp index b2a44072c..0477c0481 100644 --- a/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_function_expression.cpp @@ -37,7 +37,7 @@ BindResult ExpressionBinder::TryBindLambdaOrJson(FunctionExpression &function, i BindResult ExpressionBinder::BindExpression(FunctionExpression &function, idx_t depth, unique_ptr &expr_ptr) { // lookup the function in the catalog - QueryErrorContext error_context(function.GetQueryLocation()); + QueryErrorContext error_context(function.query_location); binder.BindSchemaOrCatalog(function.catalog, function.schema); auto func = GetCatalogEntry(CatalogType::SCALAR_FUNCTION_ENTRY, function.catalog, function.schema, function.function_name, OnEntryNotFound::RETURN_NULL, error_context); @@ -125,13 +125,13 @@ BindResult ExpressionBinder::BindFunction(FunctionExpression &function, ScalarFu children.push_back(std::move(child)); } - FunctionBinder function_binder(binder); + FunctionBinder function_binder(context); auto result = function_binder.BindScalarFunction(func, std::move(children), error, function.is_operator, &binder); if (!result) { error.AddQueryLocation(function); error.Throw(); } - if (result->GetExpressionType() == ExpressionType::BOUND_FUNCTION) { + if (result->type == ExpressionType::BOUND_FUNCTION) { auto &bound_function = result->Cast(); if (bound_function.function.stability == FunctionStability::CONSISTENT_WITHIN_QUERY) { binder.SetAlwaysRequireRebind(); @@ -195,10 +195,10 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc } // successfully bound: replace the node with a BoundExpression - auto alias = function.children[1]->GetAlias(); - bind_lambda_result.expression->SetAlias(alias); + auto alias = function.children[1]->alias; + bind_lambda_result.expression->alias = alias; if (!alias.empty()) { - bind_lambda_result.expression->SetAlias(alias); + bind_lambda_result.expression->alias = alias; } function.children[1] = make_uniq(std::move(bind_lambda_result.expression)); @@ -218,7 +218,7 @@ BindResult ExpressionBinder::BindLambdaFunction(FunctionExpression &function, Sc auto &bound_lambda_expr = children.back()->Cast(); CaptureLambdaColumns(bound_lambda_expr, bound_lambda_expr.lambda_expr, &bind_lambda_function, list_child_type); - FunctionBinder function_binder(binder); + FunctionBinder function_binder(context); unique_ptr result = function_binder.BindScalarFunction(func, std::move(children), error, function.is_operator, &binder); if (!result) { diff --git a/src/duckdb/src/planner/binder/expression/bind_lambda.cpp b/src/duckdb/src/planner/binder/expression/bind_lambda.cpp index acc68ed0b..7da2c592e 100644 --- a/src/duckdb/src/planner/binder/expression/bind_lambda.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_lambda.cpp @@ -126,10 +126,10 @@ void ExpressionBinder::TransformCapturedLambdaColumn(unique_ptr &ori const LogicalType &list_child_type) { // check if the original expression is a lambda parameter - if (original->GetExpressionClass() == ExpressionClass::BOUND_LAMBDA_REF) { + if (original->expression_class == ExpressionClass::BOUND_LAMBDA_REF) { auto &bound_lambda_ref = original->Cast(); - auto alias = bound_lambda_ref.GetAlias(); + auto alias = bound_lambda_ref.alias; // refers to a lambda parameter outside the current lambda function // so the lambda parameter will be inside the lambda_bindings @@ -169,7 +169,7 @@ void ExpressionBinder::TransformCapturedLambdaColumn(unique_ptr &ori offset += bound_lambda_expr.parameter_count; offset += bound_lambda_expr.captures.size(); - replacement = make_uniq(original->GetAlias(), original->return_type, offset); + replacement = make_uniq(original->alias, original->return_type, offset); bound_lambda_expr.captures.push_back(std::move(original)); } @@ -177,25 +177,25 @@ void ExpressionBinder::CaptureLambdaColumns(BoundLambdaExpression &bound_lambda_ const optional_ptr bind_lambda_function, const LogicalType &list_child_type) { - if (expr->GetExpressionClass() == ExpressionClass::BOUND_SUBQUERY) { + if (expr->expression_class == ExpressionClass::BOUND_SUBQUERY) { throw BinderException("subqueries in lambda expressions are not supported"); } // these are bound depth-first - D_ASSERT(expr->GetExpressionClass() != ExpressionClass::BOUND_LAMBDA); + D_ASSERT(expr->expression_class != ExpressionClass::BOUND_LAMBDA); // we do not need to replace anything, as these will be constant in the lambda expression // when executed by the expression executor - if (expr->GetExpressionClass() == ExpressionClass::BOUND_CONSTANT) { + if (expr->expression_class == ExpressionClass::BOUND_CONSTANT) { return; } // these expression classes do not have children, transform them - if (expr->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF || - expr->GetExpressionClass() == ExpressionClass::BOUND_PARAMETER || - expr->GetExpressionClass() == ExpressionClass::BOUND_LAMBDA_REF) { + if (expr->expression_class == ExpressionClass::BOUND_COLUMN_REF || + expr->expression_class == ExpressionClass::BOUND_PARAMETER || + expr->expression_class == ExpressionClass::BOUND_LAMBDA_REF) { - if (expr->GetExpressionClass() == ExpressionClass::BOUND_COLUMN_REF) { + if (expr->expression_class == ExpressionClass::BOUND_COLUMN_REF) { // Search for UNNEST. auto &column_binding = expr->Cast().binding; ThrowIfUnnestInLambda(column_binding); diff --git a/src/duckdb/src/planner/binder/expression/bind_macro_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_macro_expression.cpp index c6c12a985..358dd5db0 100644 --- a/src/duckdb/src/planner/binder/expression/bind_macro_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_macro_expression.cpp @@ -1,9 +1,10 @@ #include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp" #include "duckdb/common/enums/expression_type.hpp" +#include "duckdb/common/reference_map.hpp" +#include "duckdb/common/string_util.hpp" #include "duckdb/function/scalar_macro_function.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" -#include "duckdb/parser/expression/window_expression.hpp" #include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/planner/expression_binder.hpp" @@ -13,7 +14,7 @@ void ExpressionBinder::ReplaceMacroParametersInLambda(FunctionExpression &functi vector> &lambda_params) { for (auto &child : function.children) { - if (child->GetExpressionClass() != ExpressionClass::LAMBDA) { + if (child->expression_class != ExpressionClass::LAMBDA) { ReplaceMacroParameters(child, lambda_params); continue; } @@ -111,13 +112,13 @@ void ExpressionBinder::UnfoldMacroExpression(FunctionExpression &function, Scala vector names; // positional parameters for (idx_t i = 0; i < macro_def.parameters.size(); i++) { - types.emplace_back(LogicalTypeId::UNKNOWN); + types.emplace_back(LogicalType::SQLNULL); auto ¶m = macro_def.parameters[i]->Cast(); names.push_back(param.GetColumnName()); } // default parameters for (auto it = macro_def.default_parameters.begin(); it != macro_def.default_parameters.end(); it++) { - types.emplace_back(LogicalTypeId::UNKNOWN); + types.emplace_back(LogicalType::SQLNULL); names.push_back(it->first); // now push the defaults into the positionals positionals.push_back(std::move(defaults[it->first])); @@ -127,26 +128,7 @@ void ExpressionBinder::UnfoldMacroExpression(FunctionExpression &function, Scala macro_binding = new_macro_binding.get(); // replace current expression with stored macro expression - // special case: If this is a window function, then we need to return a window expression - if (expr->GetExpressionClass() == ExpressionClass::WINDOW) { - // Only allowed if the expression is a function - if (macro_def.expression->GetExpressionType() != ExpressionType::FUNCTION) { - throw BinderException("Window function macros must be functions"); - } - auto macro_copy = macro_def.expression->Copy(); - auto ¯o_expr = macro_copy->Cast(); - // Transfer the macro function attributes - auto &window_expr = expr->Cast(); - window_expr.catalog = macro_expr.catalog; - window_expr.schema = macro_expr.schema; - window_expr.function_name = macro_expr.function_name; - window_expr.children = std::move(macro_expr.children); - window_expr.distinct = macro_expr.distinct; - window_expr.filter_expr = std::move(macro_expr.filter); - // TODO: transfer order_bys when window functions support them - } else { - expr = macro_def.expression->Copy(); - } + expr = macro_def.expression->Copy(); // qualify only the macro parameters with a new empty binder that only knows the macro binding auto dummy_binder = Binder::CreateBinder(context); diff --git a/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp index 9326c8849..572e0bb2b 100644 --- a/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_operator_expression.cpp @@ -1,9 +1,9 @@ #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/operator_expression.hpp" -#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_case_expression.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" @@ -24,18 +24,16 @@ LogicalType ExpressionBinder::ResolveCoalesceType(OperatorExpression &op, vector } // get the maximum type from the children LogicalType max_type = ExpressionBinder::GetExpressionReturnType(*children[0]); - bool is_in_operator = (op.GetExpressionType() == ExpressionType::COMPARE_IN || - op.GetExpressionType() == ExpressionType::COMPARE_NOT_IN); + bool is_in_operator = (op.type == ExpressionType::COMPARE_IN || op.type == ExpressionType::COMPARE_NOT_IN); for (idx_t i = 1; i < children.size(); i++) { auto child_return = ExpressionBinder::GetExpressionReturnType(*children[i]); if (is_in_operator) { // If it's IN/NOT_IN operator, adjust DECIMAL and VARCHAR returned type. - if (!BoundComparisonExpression::TryBindComparison(context, max_type, child_return, max_type, - op.GetExpressionType())) { + if (!BoundComparisonExpression::TryBindComparison(context, max_type, child_return, max_type, op.type)) { throw BinderException(op, "Cannot mix values of type %s and %s in %s clause - an explicit cast is required", max_type.ToString(), child_return.ToString(), - op.GetExpressionType() == ExpressionType::COMPARE_IN ? "IN" : "NOT IN"); + op.type == ExpressionType::COMPARE_IN ? "IN" : "NOT IN"); } } else { // If it's COALESCE operator, don't do extra adjustment. @@ -59,7 +57,7 @@ LogicalType ExpressionBinder::ResolveCoalesceType(OperatorExpression &op, vector } LogicalType ExpressionBinder::ResolveOperatorType(OperatorExpression &op, vector> &children) { - switch (op.GetExpressionType()) { + switch (op.type) { case ExpressionType::OPERATOR_IS_NULL: case ExpressionType::OPERATOR_IS_NOT_NULL: // IS (NOT) NULL always returns a boolean, and does not cast its children @@ -87,7 +85,7 @@ BindResult ExpressionBinder::BindGroupingFunction(OperatorExpression &op, idx_t } BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) { - if (op.GetExpressionType() == ExpressionType::GROUPING_FUNCTION) { + if (op.type == ExpressionType::GROUPING_FUNCTION) { return BindGroupingFunction(op, depth); } @@ -103,9 +101,9 @@ BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) // all children bound successfully string function_name; - switch (op.GetExpressionType()) { + switch (op.type) { case ExpressionType::ARRAY_EXTRACT: { - D_ASSERT(op.children[0]->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(op.children[0]->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &b_exp = BoundExpression::GetExpression(*op.children[0]); const auto &b_exp_type = b_exp->return_type; if (b_exp_type.id() == LogicalTypeId::MAP) { @@ -131,25 +129,19 @@ BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) break; case ExpressionType::STRUCT_EXTRACT: { D_ASSERT(op.children.size() == 2); - D_ASSERT(op.children[0]->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); - D_ASSERT(op.children[1]->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(op.children[0]->expression_class == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(op.children[1]->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &extract_exp = BoundExpression::GetExpression(*op.children[0]); - if (extract_exp->HasParameter() || extract_exp->return_type.id() == LogicalTypeId::UNKNOWN) { - throw ParameterNotResolvedException(); - } auto &name_exp = BoundExpression::GetExpression(*op.children[1]); const auto &extract_expr_type = extract_exp->return_type; if (extract_expr_type.id() != LogicalTypeId::STRUCT && extract_expr_type.id() != LogicalTypeId::UNION && - extract_expr_type.id() != LogicalTypeId::MAP && extract_expr_type.id() != LogicalTypeId::SQLNULL && - !extract_expr_type.IsJSONType()) { + extract_expr_type.id() != LogicalTypeId::SQLNULL && !extract_expr_type.IsJSONType()) { return BindResult(StringUtil::Format( - "Cannot extract field %s from expression \"%s\" because it is not a struct, union, map, or json", + "Cannot extract field %s from expression \"%s\" because it is not a struct, union, or json", name_exp->ToString(), extract_exp->ToString())); } if (extract_expr_type.id() == LogicalTypeId::UNION) { function_name = "union_extract"; - } else if (extract_expr_type.id() == LogicalTypeId::MAP) { - function_name = "map_extract"; } else if (extract_expr_type.IsJSONType()) { function_name = "json_extract"; // Make sure we only extract fields, not array elements, by adding $. syntax @@ -181,12 +173,12 @@ BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) vector> children; for (idx_t i = 0; i < op.children.size(); i++) { - D_ASSERT(op.children[i]->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(op.children[i]->expression_class == ExpressionClass::BOUND_EXPRESSION); children.push_back(std::move(BoundExpression::GetExpression(*op.children[i]))); } // now resolve the types LogicalType result_type = ResolveOperatorType(op, children); - if (op.GetExpressionType() == ExpressionType::OPERATOR_COALESCE) { + if (op.type == ExpressionType::OPERATOR_COALESCE) { if (children.empty()) { throw BinderException("COALESCE needs at least one child"); } @@ -195,7 +187,7 @@ BindResult ExpressionBinder::BindExpression(OperatorExpression &op, idx_t depth) } } - auto result = make_uniq(op.GetExpressionType(), result_type); + auto result = make_uniq(op.type, result_type); for (auto &child : children) { result->children.push_back(std::move(child)); } diff --git a/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp index 109c0ecbd..678faf269 100644 --- a/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp @@ -24,7 +24,7 @@ BindResult ExpressionBinder::BindExpression(ParameterExpression &expr, idx_t dep bool is_literal = return_type.id() == LogicalTypeId::INTEGER_LITERAL || return_type.id() == LogicalTypeId::STRING_LITERAL; auto constant = make_uniq(data.GetValue()); - constant->SetAlias(expr.GetAlias()); + constant->alias = expr.alias; if (is_literal) { return BindResult(std::move(constant)); } diff --git a/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp index 179fad7da..e25c69c16 100644 --- a/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_star_expression.cpp @@ -12,7 +12,7 @@ namespace duckdb { string GetColumnsStringValue(ParsedExpression &expr) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); return colref.GetColumnName(); } else { @@ -44,11 +44,6 @@ bool Binder::FindStarExpression(unique_ptr &expr, StarExpressi throw BinderException( "STAR expression with REPLACE list is only allowed as the root element of COLUMNS"); } - if (!current_star.rename_list.empty()) { - // '*' inside COLUMNS can not have a REPLACE list - throw BinderException( - "STAR expression with RENAME list is only allowed as the root element of COLUMNS"); - } // '*' expression inside a COLUMNS - convert to a constant list of strings (column names) vector> star_list; @@ -91,10 +86,10 @@ void Binder::ReplaceStarExpression(unique_ptr &expr, unique_pt D_ASSERT(expr); if (StarExpression::IsColumns(*expr) || StarExpression::IsStar(*expr)) { D_ASSERT(replacement); - auto alias = expr->GetAlias(); + auto alias = expr->alias; expr = replacement->Copy(); if (!alias.empty()) { - expr->SetAlias(std::move(alias)); + expr->alias = std::move(alias); } return; } @@ -139,88 +134,8 @@ static string ReplaceColumnsAlias(const string &alias, const string &column_name return result; } -void TryTransformStarLike(unique_ptr &root) { - // detect "* LIKE [literal]" and similar expressions - if (root->GetExpressionClass() != ExpressionClass::FUNCTION) { - return; - } - auto &function = root->Cast(); - if (function.children.size() != 2) { - return; - } - auto &left = function.children[0]; - // expression must have a star on the LHS, and a literal on the RHS - if (left->GetExpressionClass() != ExpressionClass::STAR) { - return; - } - auto &star = left->Cast(); - if (star.columns) { - // COLUMNS(*) has different semantics - return; - } - unordered_set supported_ops {"~~", "!~~", "~~~", "!~~~", "~~*", "!~~*", "regexp_full_match"}; - if (supported_ops.count(function.function_name) == 0) { - // unsupported op for * expression - throw BinderException(*root, "Function \"%s\" cannot be applied to a star expression", function.function_name); - } - auto &right = function.children[1]; - if (right->GetExpressionClass() != ExpressionClass::CONSTANT) { - throw BinderException(*root, "Pattern applied to a star expression must be a constant"); - } - if (!star.rename_list.empty()) { - throw BinderException(*root, "Rename list cannot be combined with a filtering operation"); - } - if (!star.replace_list.empty()) { - throw BinderException(*root, "Replace list cannot be combined with a filtering operation"); - } - auto original_alias = root->GetAlias(); - auto star_expr = std::move(left); - unique_ptr child_expr; - if (function.function_name == "regexp_full_match" && star.exclude_list.empty()) { - // * SIMILAR TO '[regex]' is equivalent to COLUMNS('[regex]') so we can just move the expression directly - child_expr = std::move(right); - } else { - // for other expressions -> generate a columns expression - // "* LIKE '%literal%' - // -> COLUMNS(list_filter(*, x -> x LIKE '%literal%')) - auto lhs = make_uniq("__lambda_col"); - function.children[0] = lhs->Copy(); - - auto lambda = make_uniq(std::move(lhs), std::move(root)); - vector> filter_children; - filter_children.push_back(std::move(star_expr)); - filter_children.push_back(std::move(lambda)); - auto list_filter = make_uniq("list_filter", std::move(filter_children)); - child_expr = std::move(list_filter); - } - - auto columns_expr = make_uniq(); - columns_expr->columns = true; - columns_expr->expr = std::move(child_expr); - columns_expr->SetAlias(std::move(original_alias)); - root = std::move(columns_expr); -} - -optional_ptr Binder::GetResolvedColumnExpression(ParsedExpression &root_expr) { - optional_ptr expr = &root_expr; - while (expr) { - if (expr->GetExpressionType() == ExpressionType::COLUMN_REF) { - break; - } - if (expr->GetExpressionType() == ExpressionType::OPERATOR_COALESCE) { - expr = expr->Cast().children[0].get(); - } else { - // unknown expression - return nullptr; - } - } - return expr; -} - void Binder::ExpandStarExpression(unique_ptr expr, vector> &new_select_list) { - TryTransformStarLike(expr); - StarExpression *star = nullptr; if (!FindStarExpression(expr, &star, true, false)) { // no star expression: add it as-is @@ -264,11 +179,7 @@ void Binder::ExpandStarExpression(unique_ptr expr, } vector> new_list; for (idx_t i = 0; i < star_list.size(); i++) { - auto child_expr = GetResolvedColumnExpression(*star_list[i]); - if (!child_expr) { - continue; - } - auto &colref = child_expr->Cast(); + auto &colref = star_list[i]->Cast(); if (!RE2::PartialMatch(colref.GetColumnName(), *regex)) { continue; } @@ -333,13 +244,24 @@ void Binder::ExpandStarExpression(unique_ptr expr, auto new_expr = expr->Copy(); ReplaceStarExpression(new_expr, star_list[i]); if (StarExpression::IsColumns(*star)) { - auto expr = GetResolvedColumnExpression(*star_list[i]); + optional_ptr expr = star_list[i].get(); + while (expr) { + if (expr->type == ExpressionType::COLUMN_REF) { + break; + } + if (expr->type == ExpressionType::OPERATOR_COALESCE) { + expr = expr->Cast().children[0].get(); + } else { + // unknown expression + expr = nullptr; + } + } if (expr) { auto &colref = expr->Cast(); - if (new_expr->GetAlias().empty()) { - new_expr->SetAlias(colref.GetColumnName()); + if (new_expr->alias.empty()) { + new_expr->alias = colref.GetColumnName(); } else { - new_expr->SetAlias(ReplaceColumnsAlias(new_expr->GetAlias(), colref.GetColumnName(), regex.get())); + new_expr->alias = ReplaceColumnsAlias(new_expr->alias, colref.GetColumnName(), regex.get()); } } } diff --git a/src/duckdb/src/planner/binder/expression/bind_subquery_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_subquery_expression.cpp index 45dc31a33..dc0f7624c 100644 --- a/src/duckdb/src/planner/binder/expression/bind_subquery_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_subquery_expression.cpp @@ -1,7 +1,6 @@ #include "duckdb/parser/expression/subquery_expression.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression/bound_function_expression.hpp" #include "duckdb/planner/expression/bound_subquery_expression.hpp" #include "duckdb/planner/expression_binder.hpp" #include "duckdb/common/string_util.hpp" @@ -39,48 +38,6 @@ class BoundSubqueryNode : public QueryNode { } }; -bool TypeIsUnnamedStruct(const LogicalType &type) { - if (type.id() != LogicalTypeId::STRUCT) { - return false; - } - return StructType::IsUnnamed(type); -} - -void ExtractSubqueryChildren(unique_ptr &child, vector> &result, - const vector &types) { - // two scenarios - // Single Expression (standard): - // x IN (...) - // Multi-Expression/Struct: - // (a, b) IN (SELECT ...) - // the latter has an unnamed struct on the LHS that is created by a "ROW" expression - auto &return_type = child->return_type; - if (!TypeIsUnnamedStruct(return_type)) { - // child is not an unnamed struct - return; - } - if (child->GetExpressionClass() != ExpressionClass::BOUND_FUNCTION) { - // not a function - return; - } - auto &function = child->Cast(); - if (function.function.name != "row") { - // not "ROW" - return; - } - // we found (a, b, ...) - we can extract all children of this function - // note that we don't always want to do this - if (types.size() == 1 && TypeIsUnnamedStruct(types[0]) && function.children.size() != types.size()) { - // old case: we have an unnamed struct INSIDE the subquery as well - // i.e. (a, b) IN (SELECT (a, b) ...) - // unnesting the struct is guaranteed to throw an error - match the structs against each-other instead - return; - } - for (auto &row_child : function.children) { - result.push_back(std::move(row_child)); - } -} - BindResult ExpressionBinder::BindExpression(SubqueryExpression &expr, idx_t depth) { if (expr.subquery->node->type != QueryNodeType::BOUND_SUBQUERY_NODE) { // first bind the actual subquery in a new binder @@ -97,6 +54,9 @@ BindResult ExpressionBinder::BindExpression(SubqueryExpression &expr, idx_t dept binder.AddCorrelatedColumn(corr); } } + if (expr.subquery_type != SubqueryType::EXISTS && bound_node->types.size() > 1) { + throw BinderException(expr, "Subquery returns %zu columns - expected 1", bound_node->types.size()); + } auto prior_subquery = std::move(expr.subquery); expr.subquery = make_uniq(); expr.subquery->node = @@ -110,25 +70,9 @@ BindResult ExpressionBinder::BindExpression(SubqueryExpression &expr, idx_t dept return BindResult(std::move(error)); } } - auto &bound_subquery = expr.subquery->node->Cast(); - vector> child_expressions; - if (expr.subquery_type != SubqueryType::EXISTS) { - idx_t expected_columns = 1; - if (expr.child) { - auto &child = BoundExpression::GetExpression(*expr.child); - ExtractSubqueryChildren(child, child_expressions, bound_subquery.bound_node->types); - if (child_expressions.empty()) { - child_expressions.push_back(std::move(child)); - } - expected_columns = child_expressions.size(); - } - if (bound_subquery.bound_node->types.size() != expected_columns) { - throw BinderException(expr, "Subquery returns %zu columns - expected %d", - bound_subquery.bound_node->types.size(), expected_columns); - } - } // both binding the child and binding the subquery was successful D_ASSERT(expr.subquery->node->type == QueryNodeType::BOUND_SUBQUERY_NODE); + auto &bound_subquery = expr.subquery->node->Cast(); auto subquery_binder = std::move(bound_subquery.subquery_binder); auto bound_node = std::move(bound_subquery.bound_node); LogicalType return_type = @@ -141,21 +85,19 @@ BindResult ExpressionBinder::BindExpression(SubqueryExpression &expr, idx_t dept if (expr.subquery_type == SubqueryType::ANY) { // ANY comparison // cast child and subquery child to equivalent types - for (idx_t child_idx = 0; child_idx < child_expressions.size(); child_idx++) { - auto &child = child_expressions[child_idx]; - auto child_type = ExpressionBinder::GetExpressionReturnType(*child); - auto &subquery_type = bound_node->types[child_idx]; - LogicalType compare_type; - if (!LogicalType::TryGetMaxLogicalType(context, child_type, subquery_type, compare_type)) { - throw BinderException( - expr, "Cannot compare values of type %s and %s in IN/ANY/ALL clause - an explicit cast is required", - child_type.ToString(), subquery_type); - } - child = BoundCastExpression::AddCastToType(context, std::move(child), compare_type); - result->child_types.push_back(subquery_type); - result->child_target = compare_type; - result->children.push_back(std::move(child)); + D_ASSERT(bound_node->types.size() == 1); + auto &child = BoundExpression::GetExpression(*expr.child); + auto child_type = ExpressionBinder::GetExpressionReturnType(*child); + LogicalType compare_type; + if (!LogicalType::TryGetMaxLogicalType(context, child_type, bound_node->types[0], compare_type)) { + throw BinderException( + expr, "Cannot compare values of type %s and %s in IN/ANY/ALL clause - an explicit cast is required", + child_type.ToString(), bound_node->types[0]); } + child = BoundCastExpression::AddCastToType(context, std::move(child), compare_type); + result->child_type = bound_node->types[0]; + result->child_target = compare_type; + result->child = std::move(child); } result->binder = std::move(subquery_binder); result->subquery = std::move(bound_node); diff --git a/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp index ba9c0715b..139003c3d 100644 --- a/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_unnest_expression.cpp @@ -21,12 +21,12 @@ unique_ptr CreateBoundStructExtract(ClientContext &context, unique_p vector> arguments; arguments.push_back(std::move(expr)); arguments.push_back(make_uniq(Value(key))); - auto extract_function = GetKeyExtractFunction(); + auto extract_function = StructExtractFun::KeyExtractFunction(); auto bind_info = extract_function.bind(context, extract_function, arguments); auto return_type = extract_function.return_type; auto result = make_uniq(return_type, std::move(extract_function), std::move(arguments), std::move(bind_info)); - result->SetAlias(std::move(key)); + result->alias = std::move(key); return std::move(result); } @@ -34,12 +34,12 @@ unique_ptr CreateBoundStructExtractIndex(ClientContext &context, uni vector> arguments; arguments.push_back(std::move(expr)); arguments.push_back(make_uniq(Value::BIGINT(int64_t(key)))); - auto extract_function = GetIndexExtractFunction(); + auto extract_function = StructExtractFun::IndexExtractFunction(); auto bind_info = extract_function.bind(context, extract_function, arguments); auto return_type = extract_function.return_type; auto result = make_uniq(return_type, std::move(extract_function), std::move(arguments), std::move(bind_info)); - result->SetAlias("element" + to_string(key)); + result->alias = "element" + to_string(key); return std::move(result); } @@ -89,7 +89,7 @@ BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth, b if (!function.children[i]->IsScalar()) { break; } - auto alias = StringUtil::Lower(function.children[i]->GetAlias()); + auto alias = StringUtil::Lower(function.children[i]->alias); BindChild(function.children[i], depth, error); if (error.HasError()) { return BindResult(std::move(error)); @@ -187,7 +187,7 @@ BindResult SelectBinder::BindUnnest(FunctionExpression &function, idx_t depth, b } auto result = make_uniq(return_type); result->child = std::move(unnest_expr); - auto alias = function.GetAlias().empty() ? result->ToString() : function.GetAlias(); + auto alias = function.alias.empty() ? result->ToString() : function.alias; auto current_level = unnest_level + list_unnests - current_depth - 1; auto entry = node.unnests.find(current_level); diff --git a/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp b/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp index 72a6c4be2..5909df507 100644 --- a/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp +++ b/src/duckdb/src/planner/binder/expression/bind_window_expression.cpp @@ -69,7 +69,7 @@ static unique_ptr GetExpression(unique_ptr &expr) return nullptr; } D_ASSERT(expr.get()); - D_ASSERT(expr->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_EXPRESSION); return std::move(BoundExpression::GetExpression(*expr)); } @@ -78,7 +78,7 @@ static unique_ptr CastWindowExpression(unique_ptr return nullptr; } D_ASSERT(expr.get()); - D_ASSERT(expr->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound = BoundExpression::GetExpression(*expr); bound = BoundCastExpression::AddDefaultCastToType(std::move(bound), type); @@ -113,14 +113,14 @@ static LogicalType BindRangeExpression(ClientContext &context, const string &nam vector> children; D_ASSERT(order_expr.get()); - D_ASSERT(order_expr->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(order_expr->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound_order = BoundExpression::GetExpression(*order_expr); children.emplace_back(bound_order->Copy()); D_ASSERT(expr.get()); - D_ASSERT(expr->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(expr->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound = BoundExpression::GetExpression(*expr); - QueryErrorContext error_context(bound->GetQueryLocation()); + QueryErrorContext error_context(bound->query_location); if (bound->return_type == LogicalType::SQLNULL) { throw BinderException(error_context, "Window RANGE expressions cannot be NULL"); } @@ -142,21 +142,9 @@ static LogicalType BindRangeExpression(ClientContext &context, const string &nam } BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { - QueryErrorContext error_context(window.GetQueryLocation()); - // Check for macros pretending to be aggregates - auto entry = GetCatalogEntry(CatalogType::SCALAR_FUNCTION_ENTRY, window.catalog, window.schema, - window.function_name, OnEntryNotFound::RETURN_NULL, error_context); - if (window.GetExpressionType() == ExpressionType::WINDOW_AGGREGATE && entry && - entry->type == CatalogType::MACRO_ENTRY) { - auto macro = make_uniq(window.catalog, window.schema, window.function_name, - std::move(window.children), std::move(window.filter_expr), nullptr, - window.distinct); - auto macro_expr = window.Copy(); - return BindMacro(*macro, entry->Cast(), depth, macro_expr); - } - - auto name = window.alias; + auto name = window.GetName(); + QueryErrorContext error_context(window.query_location); if (inside_window) { throw BinderException(error_context, "window function calls cannot be nested"); } @@ -205,10 +193,6 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { BindChild(window.offset_expr, depth, error); BindChild(window.default_expr, depth, error); - for (auto &order : window.arg_orders) { - BindChild(order.expression, depth, error); - } - inside_window = false; if (error.HasError()) { // failed to bind children of window function @@ -216,11 +200,6 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { } // Restore any collation expressions - for (auto &order : window.arg_orders) { - auto &order_expr = order.expression; - auto &bound_order = BoundExpression::GetExpression(*order_expr); - ExpressionBinder::PushCollation(context, bound_order, bound_order->return_type); - } for (auto &part_expr : window.partitions) { auto &bound_partition = BoundExpression::GetExpression(*part_expr); ExpressionBinder::PushCollation(context, bound_partition, bound_partition->return_type); @@ -235,11 +214,11 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { vector> children; for (auto &child : window.children) { D_ASSERT(child.get()); - D_ASSERT(child->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(child->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound = BoundExpression::GetExpression(*child); // Add casts for positional arguments const auto argno = children.size(); - switch (window.GetExpressionType()) { + switch (window.type) { case ExpressionType::WINDOW_NTILE: // ntile(bigint) if (argno == 0) { @@ -262,14 +241,10 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { LogicalType sql_type; unique_ptr aggregate; unique_ptr bind_info; - if (window.GetExpressionType() == ExpressionType::WINDOW_AGGREGATE) { + if (window.type == ExpressionType::WINDOW_AGGREGATE) { // Look up the aggregate function in the catalog - if (!entry || entry->type != CatalogType::AGGREGATE_FUNCTION_ENTRY) { - // Not an aggregate: Look it up to generate error - Catalog::GetEntry(context, window.catalog, window.schema, - window.function_name, error_context); - } - auto &func = entry->Cast(); + auto &func = Catalog::GetEntry(context, window.catalog, window.schema, + window.function_name, error_context); D_ASSERT(func.type == CatalogType::AGGREGATE_FUNCTION_ENTRY); // bind the aggregate @@ -292,10 +267,9 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { } else { // fetch the child of the non-aggregate window function (if any) - sql_type = ResolveWindowExpressionType(window.GetExpressionType(), types); + sql_type = ResolveWindowExpressionType(window.type, types); } - auto result = make_uniq(window.GetExpressionType(), sql_type, std::move(aggregate), - std::move(bind_info)); + auto result = make_uniq(window.type, sql_type, std::move(aggregate), std::move(bind_info)); result->children = std::move(children); for (auto &child : window.partitions) { result->partitions.push_back(GetExpression(child)); @@ -343,7 +317,7 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { auto &order_expr = window.orders[0].expression; D_ASSERT(order_expr.get()); - D_ASSERT(order_expr->GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION); + D_ASSERT(order_expr->expression_class == ExpressionClass::BOUND_EXPRESSION); auto &bound_order = BoundExpression::GetExpression(*order_expr); auto order_type = bound_order->return_type; if (window.start_expr) { @@ -365,14 +339,6 @@ BindResult BaseSelectBinder::BindWindow(WindowExpression &window, idx_t depth) { result->orders.emplace_back(type, null_order, std::move(expression)); } - // Argument orders are just like arguments, not frames - for (auto &order : window.arg_orders) { - auto type = config.ResolveOrder(order.type); - auto null_order = config.ResolveNullOrder(type, order.null_order); - auto expression = GetExpression(order.expression); - result->arg_orders.emplace_back(type, null_order, std::move(expression)); - } - result->filter_expr = CastWindowExpression(window.filter_expr, LogicalType::BOOLEAN); result->start_expr = CastWindowExpression(window.start_expr, start_type); result->end_expr = CastWindowExpression(window.end_expr, end_type); diff --git a/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp index 126ae001f..d58b3868e 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp @@ -1,7 +1,7 @@ #include "duckdb/common/limits.hpp" #include "duckdb/common/string_util.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" +#include "duckdb/function/aggregate/distributive_functions.hpp" #include "duckdb/function/function_binder.hpp" #include "duckdb/main/config.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" @@ -40,7 +40,7 @@ unique_ptr Binder::BindOrderExpression(OrderBinder &order_binder, un // remove the expression from the DISTINCT ON list return nullptr; } - D_ASSERT(bound_expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT); + D_ASSERT(bound_expr->type == ExpressionType::VALUE_CONSTANT); return bound_expr; } @@ -86,7 +86,7 @@ BoundLimitNode Binder::BindLimitValue(OrderBinder &order_binder, unique_ptr(); } if (constant_val < 0) { - throw BinderException(expr->GetQueryLocation(), "LIMIT/OFFSET cannot be negative"); + throw BinderException(expr->query_location, "LIMIT/OFFSET cannot be negative"); } return BoundLimitNode::ConstantValue(constant_val); } @@ -160,7 +160,7 @@ void Binder::PrepareModifiers(OrderBinder &order_binder, QueryNode &statement, B auto &config = DBConfig::GetConfig(context); D_ASSERT(!order.orders.empty()); auto &order_binders = order_binder.GetBinders(); - if (order.orders.size() == 1 && order.orders[0].expression->GetExpressionType() == ExpressionType::STAR) { + if (order.orders.size() == 1 && order.orders[0].expression->type == ExpressionType::STAR) { auto &star = order.orders[0].expression->Cast(); if (star.exclude_list.empty() && star.replace_list.empty() && !star.expr) { // ORDER BY ALL @@ -179,7 +179,7 @@ void Binder::PrepareModifiers(OrderBinder &order_binder, QueryNode &statement, B // e.g. it breaks EXPLAIN output on queries bool can_replace = true; for (auto &order_node : order.orders) { - if (order_node.expression->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (order_node.expression->type == ExpressionType::VALUE_CONSTANT) { // we cannot replace the sort key when we order by literals (e.g. ORDER BY 1, 2` can_replace = false; break; @@ -242,10 +242,10 @@ unique_ptr CreateOrderExpression(unique_ptr expr, const if (index >= sql_types.size()) { throw BinderException(*expr, "ORDER term out of range - should be between 1 and %lld", sql_types.size()); } - auto result = - make_uniq(expr->GetAlias(), sql_types[index], ColumnBinding(table_index, index)); - if (result->GetAlias().empty() && index < names.size()) { - result->SetAlias(names[index]); + auto result = make_uniq(std::move(expr->alias), sql_types[index], + ColumnBinding(table_index, index)); + if (result->alias.empty() && index < names.size()) { + result->alias = names[index]; } return std::move(result); } @@ -294,10 +294,10 @@ static void AssignReturnType(unique_ptr &expr, idx_t table_index, co if (!expr) { return; } - if (expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (expr->type == ExpressionType::VALUE_CONSTANT) { expr = FinalizeBindOrderExpression(std::move(expr), table_index, names, sql_types, bind_state); } - if (expr->GetExpressionType() != ExpressionType::BOUND_COLUMN_REF) { + if (expr->type != ExpressionType::BOUND_COLUMN_REF) { return; } auto &bound_colref = expr->Cast(); @@ -310,6 +310,7 @@ void Binder::BindModifiers(BoundQueryNode &result, idx_t table_index, const vect switch (bound_mod->type) { case ResultModifierType::DISTINCT_MODIFIER: { auto &distinct = bound_mod->Cast(); + D_ASSERT(!distinct.target_distincts.empty()); // set types of distinct targets for (auto &expr : distinct.target_distincts) { expr = FinalizeBindOrderExpression(std::move(expr), table_index, names, sql_types, bind_state); @@ -346,7 +347,7 @@ void Binder::BindModifiers(BoundQueryNode &result, idx_t table_index, const vect for (idx_t i = 0; i < sql_types.size(); i++) { auto expr = make_uniq(sql_types[i], ColumnBinding(table_index, i)); if (i < names.size()) { - expr->SetAlias(names[i]); + expr->alias = names[i]; } order.orders.emplace_back(order_type, null_order, std::move(expr)); } @@ -374,14 +375,14 @@ unique_ptr Binder::BindNode(SelectNode &statement) { void Binder::BindWhereStarExpression(unique_ptr &expr) { // expand any expressions in the upper AND recursively - if (expr->GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (expr->type == ExpressionType::CONJUNCTION_AND) { auto &conj = expr->Cast(); for (auto &child : conj.children) { BindWhereStarExpression(child); } return; } - if (expr->GetExpressionType() == ExpressionType::STAR) { + if (expr->type == ExpressionType::STAR) { auto &star = expr->Cast(); if (!star.columns) { throw ParserException("STAR expression is not allowed in the WHERE clause. Use COLUMNS(*) instead."); @@ -434,9 +435,9 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ auto &expr = statement.select_list[i]; result->names.push_back(expr->GetName()); ExpressionBinder::QualifyColumnNames(*this, expr); - if (!expr->GetAlias().empty()) { - bind_state.alias_map[expr->GetAlias()] = i; - result->names[i] = expr->GetAlias(); + if (!expr->alias.empty()) { + bind_state.alias_map[expr->alias] = i; + result->names[i] = expr->alias; } bind_state.projection_map[*expr] = i; bind_state.original_expressions.push_back(expr->Copy()); @@ -491,14 +492,14 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ // but also push a first(x) aggregate in case x is selected (uncollated) info.collated_groups[i] = result->aggregates.size(); - auto first_fun = FirstFunctionGetter::GetFunction(bound_expr_ref.return_type); + auto first_fun = FirstFun::GetFunction(bound_expr_ref.return_type); vector> first_children; // FIXME: would be better to just refer to this expression, but for now we copy first_children.push_back(bound_expr_ref.Copy()); - FunctionBinder function_binder(*this); + FunctionBinder function_binder(context); auto function = function_binder.BindAggregateFunction(first_fun, std::move(first_children)); - function->SetAlias("__collated_group"); + function->alias = "__collated_group"; result->aggregates.push_back(std::move(function)); } result->groups.group_expressions.push_back(std::move(bound_expr)); @@ -517,7 +518,7 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ // bind the HAVING clause, if any if (statement.having) { HavingBinder having_binder(*this, context, *result, info, statement.aggregate_handling); - ExpressionBinder::QualifyColumnNames(having_binder, statement.having); + ExpressionBinder::QualifyColumnNames(*this, statement.having); result->having = having_binder.Bind(statement.having); } @@ -557,7 +558,7 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ statement.aggregate_handling == AggregateHandling::FORCE_AGGREGATES && is_original_column; result->bound_column_count++; - if (expr->GetExpressionType() == ExpressionType::BOUND_EXPANDED) { + if (expr->type == ExpressionType::BOUND_EXPANDED) { if (!is_original_column) { throw BinderException("UNNEST of struct cannot be used in ORDER BY/DISTINCT ON clause"); } @@ -615,7 +616,6 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ } // push the GROUP BY ALL expressions into the group set - for (auto &group_by_all_index : group_by_all_indexes) { auto &expr = result->select_list[group_by_all_index]; auto group_ref = make_uniq( @@ -623,15 +623,6 @@ unique_ptr Binder::BindSelectNode(SelectNode &statement, unique_ result->groups.group_expressions.push_back(std::move(expr)); expr = std::move(group_ref); } - set group_by_all_indexes_set; - if (!group_by_all_indexes.empty()) { - idx_t num_set_indexes = result->groups.group_expressions.size(); - for (idx_t i = 0; i < num_set_indexes; i++) { - group_by_all_indexes_set.insert(i); - } - D_ASSERT(result->groups.grouping_sets.empty()); - result->groups.grouping_sets.push_back(group_by_all_indexes_set); - } result->column_count = new_names.size(); result->names = std::move(new_names); result->need_prune = result->select_list.size() > result->column_count; diff --git a/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp index 82d6c754b..66ffede4d 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_setop_node.cpp @@ -88,18 +88,14 @@ static void BuildUnionByNameInfo(ClientContext &context, BoundSetOperationNode & // We throw a binder exception if two same name in the SELECT list for (idx_t i = 0; i < left_node.names.size(); ++i) { if (left_names_map.find(left_node.names[i]) != left_names_map.end()) { - throw BinderException("UNION (ALL) BY NAME operation doesn't support duplicate names in the SELECT list - " - "the name \"%s\" occurs multiple times in the left-hand side", - left_node.names[i]); + throw BinderException("UNION(ALL) BY NAME operation doesn't support same name in SELECT list"); } left_names_map[left_node.names[i]] = i; } for (idx_t i = 0; i < right_node.names.size(); ++i) { if (right_names_map.find(right_node.names[i]) != right_names_map.end()) { - throw BinderException("UNION (ALL) BY NAME operation doesn't support duplicate names in the SELECT list - " - "the name \"%s\" occurs multiple times in the right-hand side", - right_node.names[i]); + throw BinderException("UNION(ALL) BY NAME operation doesn't support same name in SELECT list"); } if (left_names_map.find(right_node.names[i]) == left_names_map.end()) { result.names.push_back(right_node.names[i]); @@ -186,16 +182,6 @@ static void BuildUnionByNameInfo(ClientContext &context, BoundSetOperationNode & } } -static void GatherSetOpBinders(BoundQueryNode &node, Binder &binder, vector> &binders) { - if (node.type != QueryNodeType::SET_OPERATION_NODE) { - binders.push_back(binder); - return; - } - auto &setop_node = node.Cast(); - GatherSetOpBinders(*setop_node.left, *setop_node.left_binder, binders); - GatherSetOpBinders(*setop_node.right, *setop_node.right_binder, binders); -} - unique_ptr Binder::BindNode(SetOperationNode &statement) { auto result = make_uniq(); result->setop_type = statement.setop_type; @@ -261,10 +247,7 @@ unique_ptr Binder::BindNode(SetOperationNode &statement) { GatherAliases(*result, bind_state, reorder_idx); } // now we perform the actual resolution of the ORDER BY/DISTINCT expressions - vector> binders; - GatherSetOpBinders(*result->left, *result->left_binder, binders); - GatherSetOpBinders(*result->right, *result->right_binder, binders); - OrderBinder order_binder(binders, bind_state); + OrderBinder order_binder({*result->left_binder, *result->right_binder}, bind_state); PrepareModifiers(order_binder, statement, *result); } diff --git a/src/duckdb/src/planner/binder/query_node/bind_table_macro_node.cpp b/src/duckdb/src/planner/binder/query_node/bind_table_macro_node.cpp index 0f90c1155..df896704d 100644 --- a/src/duckdb/src/planner/binder/query_node/bind_table_macro_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/bind_table_macro_node.cpp @@ -36,13 +36,13 @@ unique_ptr Binder::BindTableMacro(FunctionExpression &function, Table vector names; // positional parameters for (idx_t i = 0; i < macro_def.parameters.size(); i++) { - types.emplace_back(LogicalTypeId::UNKNOWN); + types.emplace_back(LogicalType::SQLNULL); auto ¶m = macro_def.parameters[i]->Cast(); names.push_back(param.GetColumnName()); } // default parameters for (auto it = macro_def.default_parameters.begin(); it != macro_def.default_parameters.end(); it++) { - types.emplace_back(LogicalTypeId::UNKNOWN); + types.emplace_back(LogicalType::SQLNULL); names.push_back(it->first); // now push the defaults into the positionals positionals.push_back(std::move(defaults[it->first])); diff --git a/src/duckdb/src/planner/binder/query_node/plan_query_node.cpp b/src/duckdb/src/planner/binder/query_node/plan_query_node.cpp index c448f2f11..97678d227 100644 --- a/src/duckdb/src/planner/binder/query_node/plan_query_node.cpp +++ b/src/duckdb/src/planner/binder/query_node/plan_query_node.cpp @@ -13,9 +13,6 @@ unique_ptr Binder::VisitQueryNode(BoundQueryNode &node, unique_ switch (mod->type) { case ResultModifierType::DISTINCT_MODIFIER: { auto &bound = mod->Cast(); - if (bound.target_distincts.empty()) { - break; - } auto distinct = make_uniq(std::move(bound.target_distincts), bound.distinct_type); distinct->AddChild(std::move(root)); root = std::move(distinct); diff --git a/src/duckdb/src/planner/binder/query_node/plan_setop.cpp b/src/duckdb/src/planner/binder/query_node/plan_setop.cpp index ba929bcd8..1afca3422 100644 --- a/src/duckdb/src/planner/binder/query_node/plan_setop.cpp +++ b/src/duckdb/src/planner/binder/query_node/plan_setop.cpp @@ -33,15 +33,14 @@ unique_ptr Binder::CastLogicalOperatorToTypes(vector new_column_types; bool do_pushdown = true; for (idx_t i = 0; i < op->expressions.size(); i++) { - if (op->expressions[i]->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (op->expressions[i]->type == ExpressionType::BOUND_COLUMN_REF) { auto &col_ref = op->expressions[i]->Cast(); - auto column_id = column_ids[col_ref.binding.column_index].GetPrimaryIndex(); - if (new_column_types.find(column_id) != new_column_types.end()) { + if (new_column_types.find(column_ids[col_ref.binding.column_index]) != new_column_types.end()) { // Only one reference per column is accepted do_pushdown = false; break; } - new_column_types[column_id] = target_types[i]; + new_column_types[column_ids[col_ref.binding.column_index]] = target_types[i]; } else { do_pushdown = false; break; @@ -61,10 +60,10 @@ unique_ptr Binder::CastLogicalOperatorToTypes(vectorexpressions[i]->GetAlias(); + string cur_alias = node->expressions[i]->alias; node->expressions[i] = BoundCastExpression::AddCastToType(context, std::move(node->expressions[i]), target_types[i]); - node->expressions[i]->SetAlias(cur_alias); + node->expressions[i]->alias = cur_alias; } } return op; diff --git a/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp b/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp index 1e1c06c1e..d020d5399 100644 --- a/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp +++ b/src/duckdb/src/planner/binder/query_node/plan_subquery.cpp @@ -1,5 +1,4 @@ #include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/main/client_config.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" @@ -18,7 +17,7 @@ #include "duckdb/common/enums/logical_operator_type.hpp" #include "duckdb/planner/operator/logical_dependent_join.hpp" #include "duckdb/planner/subquery/recursive_dependent_join_planner.hpp" -#include "duckdb/function/scalar/generic_functions.hpp" +#include "duckdb/core_functions/scalar/generic_functions.hpp" namespace duckdb { @@ -37,7 +36,7 @@ static unique_ptr PlanUncorrelatedSubquery(Binder &binder, BoundSubq // now we push a COUNT(*) aggregate onto the limit, this will be either 0 or 1 (EXISTS or NOT EXISTS) auto count_star_fun = CountStarFun::GetFunction(); - FunctionBinder function_binder(binder); + FunctionBinder function_binder(binder.context); auto count_star = function_binder.BindAggregateFunction(count_star_fun, {}, nullptr, AggregateType::NON_DISTINCT); auto idx_type = count_star->return_type; @@ -87,10 +86,9 @@ static unique_ptr PlanUncorrelatedSubquery(Binder &binder, BoundSubq vector> first_children; first_children.push_back(std::move(bound)); - FunctionBinder function_binder(binder); - auto first_agg = - function_binder.BindAggregateFunction(FirstFunctionGetter::GetFunction(expr.return_type), - std::move(first_children), nullptr, AggregateType::NON_DISTINCT); + FunctionBinder function_binder(binder.context); + auto first_agg = function_binder.BindAggregateFunction( + FirstFun::GetFunction(expr.return_type), std::move(first_children), nullptr, AggregateType::NON_DISTINCT); expressions.push_back(std::move(first_agg)); if (error_on_multiple_rows) { @@ -163,15 +161,12 @@ static unique_ptr PlanUncorrelatedSubquery(Binder &binder, BoundSubq join->AddChild(std::move(root)); join->AddChild(std::move(plan)); // create the JOIN condition - for (idx_t child_idx = 0; child_idx < expr.children.size(); child_idx++) { - JoinCondition cond; - cond.left = std::move(expr.children[child_idx]); - auto &child_type = expr.child_types[child_idx]; - cond.right = BoundCastExpression::AddDefaultCastToType( - make_uniq(child_type, plan_columns[child_idx]), expr.child_target); - cond.comparison = expr.comparison_type; - join->conditions.push_back(std::move(cond)); - } + JoinCondition cond; + cond.left = std::move(expr.child); + cond.right = BoundCastExpression::AddDefaultCastToType( + make_uniq(expr.child_type, plan_columns[0]), expr.child_target); + cond.comparison = expr.comparison_type; + join->conditions.push_back(std::move(cond)); root = std::move(join); // we replace the original subquery with a BoundColumnRefExpression referring to the mark column @@ -193,7 +188,7 @@ CreateDuplicateEliminatedJoin(const vector &correlated_col make_uniq(ExpressionType::WINDOW_ROW_NUMBER, LogicalType::BIGINT, nullptr, nullptr); row_number->start = WindowBoundary::UNBOUNDED_PRECEDING; row_number->end = WindowBoundary::CURRENT_ROW_ROWS; - row_number->SetAlias("delim_index"); + row_number->alias = "delim_index"; window->expressions.push_back(std::move(row_number)); window->AddChild(std::move(original_plan)); original_plan = std::move(window); @@ -357,24 +352,13 @@ static unique_ptr PlanCorrelatedSubquery(Binder &binder, BoundSubque // now we create the join conditions between the dependent join and the original table CreateDelimJoinConditions(*delim_join, correlated_columns, plan_columns, flatten.delim_offset, perform_delim); - if (expr.children.size() > 1) { - // FIXME: the code to generate the plan here is actually correct - // the problem is in the hash join - specifically PhysicalHashJoin::InitializeHashTable - // this contains code that is hard-coded for a single comparison - // -> (delim_types.size() + 1 == conditions.size()) - // this needs to be generalized to get this to work - throw NotImplementedException("Correlated IN/ANY/ALL with multiple columns not yet supported"); - } // add the actual condition based on the ANY/ALL predicate - for (idx_t child_idx = 0; child_idx < expr.children.size(); child_idx++) { - JoinCondition compare_cond; - compare_cond.left = std::move(expr.children[child_idx]); - auto &child_type = expr.child_types[child_idx]; - compare_cond.right = BoundCastExpression::AddDefaultCastToType( - make_uniq(child_type, plan_columns[child_idx]), expr.child_target); - compare_cond.comparison = expr.comparison_type; - delim_join->conditions.push_back(std::move(compare_cond)); - } + JoinCondition compare_cond; + compare_cond.left = std::move(expr.child); + compare_cond.right = BoundCastExpression::AddDefaultCastToType( + make_uniq(expr.child_type, plan_columns[0]), expr.child_target); + compare_cond.comparison = expr.comparison_type; + delim_join->conditions.push_back(std::move(compare_cond)); delim_join->AddChild(std::move(dependent_join)); root = std::move(delim_join); @@ -449,7 +433,7 @@ void Binder::PlanSubqueries(unique_ptr &expr_ptr, unique_ptr &expr) { PlanSubqueries(expr, root); }); // check if this is a subquery node - if (expr.GetExpressionClass() == ExpressionClass::BOUND_SUBQUERY) { + if (expr.expression_class == ExpressionClass::BOUND_SUBQUERY) { auto &subquery = expr.Cast(); // subquery node! plan it if (!is_outside_flattened) { @@ -471,9 +455,6 @@ unique_ptr Binder::PlanLateralJoin(unique_ptr vector conditions; vector> arbitrary_expressions; if (condition) { - if (condition->HasSubquery()) { - throw BinderException(*condition, "Subqueries are not supported in LATERAL join conditions"); - } // extract join conditions, if there are any LogicalComparisonJoin::ExtractJoinConditions(context, join_type, JoinRefType::REGULAR, left, right, std::move(condition), conditions, arbitrary_expressions); diff --git a/src/duckdb/src/planner/binder/statement/bind_copy.cpp b/src/duckdb/src/planner/binder/statement/bind_copy.cpp index ce2f93ad8..d95db2e0a 100644 --- a/src/duckdb/src/planner/binder/statement/bind_copy.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_copy.cpp @@ -29,6 +29,12 @@ static bool GetBooleanArg(ClientContext &context, const vector &arg) { } BoundStatement Binder::BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type) { + // COPY TO a file + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("COPY TO is disabled by configuration"); + } + // lookup the format in the catalog auto ©_function = Catalog::GetEntry(context, INVALID_CATALOG, DEFAULT_SCHEMA, stmt.info->format); @@ -122,7 +128,7 @@ BoundStatement Binder::BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type) return_type = CopyFunctionReturnType::CHANGED_ROWS_AND_FILE_LIST; } } else if (loption == "write_partition_columns") { - write_partition_columns = GetBooleanArg(context, option.second); + write_partition_columns = true; } else { stmt.info->options[option.first] = option.second; } @@ -266,6 +272,10 @@ BoundStatement Binder::BindCopyTo(CopyStatement &stmt, CopyToType copy_to_type) } BoundStatement Binder::BindCopyFrom(CopyStatement &stmt) { + auto &config = DBConfig::GetConfig(context); + if (!config.options.enable_external_access) { + throw PermissionException("COPY FROM is disabled by configuration"); + } BoundStatement result; result.types = {LogicalType::BIGINT}; result.names = {"Count"}; @@ -274,7 +284,7 @@ BoundStatement Binder::BindCopyFrom(CopyStatement &stmt) { throw ParserException("COPY FROM requires a table name to be specified"); } // COPY FROM a file - // generate an insert statement for the to-be-inserted table + // generate an insert statement for the the to-be-inserted table InsertStatement insert; insert.table = stmt.info->table; insert.schema = stmt.info->schema; diff --git a/src/duckdb/src/planner/binder/statement/bind_create.cpp b/src/duckdb/src/planner/binder/statement/bind_create.cpp index 49c2f37b7..a35d6e13c 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create.cpp @@ -1,46 +1,48 @@ #include "duckdb/catalog/catalog.hpp" +#include "duckdb/catalog/catalog_search_path.hpp" #include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" -#include "duckdb/catalog/catalog_search_path.hpp" -#include "duckdb/catalog/duck_catalog.hpp" -#include "duckdb/function/scalar_macro_function.hpp" -#include "duckdb/function/table/table_scan.hpp" -#include "duckdb/main/attached_database.hpp" +#include "duckdb/main/secret/secret_manager.hpp" #include "duckdb/main/client_context.hpp" -#include "duckdb/main/client_data.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/main/database_manager.hpp" -#include "duckdb/main/secret/secret_manager.hpp" -#include "duckdb/parser/constraints/foreign_key_constraint.hpp" -#include "duckdb/parser/constraints/list.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" +#include "duckdb/planner/expression/bound_cast_expression.hpp" +#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/parser/parsed_data/create_macro_info.hpp" -#include "duckdb/parser/parsed_data/create_secret_info.hpp" #include "duckdb/parser/parsed_data/create_view_info.hpp" +#include "duckdb/parser/tableref/table_function_ref.hpp" +#include "duckdb/parser/parsed_data/create_secret_info.hpp" #include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/parser/statement/create_statement.hpp" -#include "duckdb/parser/tableref/basetableref.hpp" -#include "duckdb/parser/tableref/table_function_ref.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/bound_query_node.hpp" -#include "duckdb/planner/expression/bound_cast_expression.hpp" -#include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/expression_binder/index_binder.hpp" #include "duckdb/planner/expression_binder/select_binder.hpp" #include "duckdb/planner/operator/logical_create.hpp" +#include "duckdb/planner/operator/logical_create_index.hpp" #include "duckdb/planner/operator/logical_create_table.hpp" #include "duckdb/planner/operator/logical_get.hpp" #include "duckdb/planner/operator/logical_projection.hpp" #include "duckdb/planner/parsed_data/bound_create_table_info.hpp" #include "duckdb/planner/query_node/bound_select_node.hpp" #include "duckdb/planner/tableref/bound_basetableref.hpp" +#include "duckdb/parser/constraints/foreign_key_constraint.hpp" +#include "duckdb/function/scalar_macro_function.hpp" +#include "duckdb/storage/data_table.hpp" #include "duckdb/storage/storage_extension.hpp" -#include "duckdb/common/extension_type_info.hpp" +#include "duckdb/main/client_data.hpp" +#include "duckdb/parser/constraints/unique_constraint.hpp" +#include "duckdb/parser/constraints/list.hpp" +#include "duckdb/main/database_manager.hpp" +#include "duckdb/main/attached_database.hpp" +#include "duckdb/catalog/duck_catalog.hpp" +#include "duckdb/function/table/table_scan.hpp" +#include "duckdb/parser/tableref/basetableref.hpp" +#include "duckdb/planner/expression_binder/select_bind_state.hpp" namespace duckdb { @@ -145,7 +147,8 @@ void Binder::BindCreateViewInfo(CreateViewInfo &base) { auto &catalog = Catalog::GetCatalog(context, base.catalog); auto &db_config = DBConfig::GetConfig(context); - bool should_create_dependencies = db_config.GetSetting(context); + auto should_create_dependencies = db_config.options.enable_view_dependencies; + if (should_create_dependencies) { view_binder->SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { if (&catalog != &entry.ParentCatalog()) { @@ -196,7 +199,7 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { if (param.IsQualified()) { throw BinderException("Invalid parameter name '%s': must be unqualified", param.ToString()); } - dummy_types.emplace_back(LogicalType::UNKNOWN); + dummy_types.emplace_back(LogicalType::SQLNULL); dummy_names.push_back(param.GetColumnName()); } // default parameters @@ -216,7 +219,7 @@ SchemaCatalogEntry &Binder::BindCreateFunctionInfo(CreateInfo &info) { BoundSelectNode sel_node; BoundGroupInformation group_info; SelectBinder binder(*this, context, sel_node, group_info); - bool should_create_dependencies = db_config.GetSetting(context); + auto should_create_dependencies = db_config.options.enable_macro_dependencies; if (should_create_dependencies) { binder.SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { @@ -254,122 +257,363 @@ static bool IsValidUserType(optional_ptr entry) { } void Binder::BindLogicalType(LogicalType &type, optional_ptr catalog, const string &schema) { - if (type.id() != LogicalTypeId::USER) { - // Recursive types, make sure to bind any nested user types recursively + if (type.id() == LogicalTypeId::LIST || type.id() == LogicalTypeId::MAP) { + auto child_type = ListType::GetChildType(type); + BindLogicalType(child_type, catalog, schema); auto alias = type.GetAlias(); - auto ext_info = type.HasExtensionInfo() ? make_uniq(*type.GetExtensionInfo()) : nullptr; - - switch (type.id()) { - case LogicalTypeId::LIST: { - auto child_type = ListType::GetChildType(type); - BindLogicalType(child_type, catalog, schema); + auto modifiers = type.GetModifiersCopy(); + if (type.id() == LogicalTypeId::LIST) { type = LogicalType::LIST(child_type); - } break; - case LogicalTypeId::MAP: { - auto key_type = MapType::KeyType(type); - BindLogicalType(key_type, catalog, schema); - auto value_type = MapType::ValueType(type); - BindLogicalType(value_type, catalog, schema); - type = LogicalType::MAP(key_type, value_type); - } break; - case LogicalTypeId::ARRAY: { - auto child_type = ArrayType::GetChildType(type); - auto array_size = ArrayType::GetSize(type); - BindLogicalType(child_type, catalog, schema); - type = LogicalType::ARRAY(child_type, array_size); - } break; - case LogicalTypeId::STRUCT: { - auto child_types = StructType::GetChildTypes(type); - for (auto &child_type : child_types) { - BindLogicalType(child_type.second, catalog, schema); + } else { + D_ASSERT(child_type.id() == LogicalTypeId::STRUCT); // map must be list of structs + type = LogicalType::MAP(child_type); + } + + type.SetAlias(alias); + type.SetModifiers(modifiers); + } else if (type.id() == LogicalTypeId::STRUCT) { + auto child_types = StructType::GetChildTypes(type); + for (auto &child_type : child_types) { + BindLogicalType(child_type.second, catalog, schema); + } + // Generate new Struct Type + auto alias = type.GetAlias(); + auto modifiers = type.GetModifiersCopy(); + type = LogicalType::STRUCT(child_types); + type.SetAlias(alias); + type.SetModifiers(modifiers); + } else if (type.id() == LogicalTypeId::ARRAY) { + auto child_type = ArrayType::GetChildType(type); + auto array_size = ArrayType::GetSize(type); + BindLogicalType(child_type, catalog, schema); + auto alias = type.GetAlias(); + auto modifiers = type.GetModifiersCopy(); + type = LogicalType::ARRAY(child_type, array_size); + type.SetAlias(alias); + type.SetModifiers(modifiers); + } else if (type.id() == LogicalTypeId::UNION) { + auto member_types = UnionType::CopyMemberTypes(type); + for (auto &member_type : member_types) { + BindLogicalType(member_type.second, catalog, schema); + } + // Generate new Union Type + auto alias = type.GetAlias(); + auto modifiers = type.GetModifiersCopy(); + type = LogicalType::UNION(member_types); + type.SetAlias(alias); + type.SetModifiers(modifiers); + } else if (type.id() == LogicalTypeId::USER) { + auto user_type_name = UserType::GetTypeName(type); + auto user_type_schema = UserType::GetSchema(type); + auto user_type_mods = UserType::GetTypeModifiers(type); + + bind_type_modifiers_function_t user_bind_modifiers_func = nullptr; + + if (catalog) { + // The search order is: + // 1) In the explicitly set schema (my_schema.my_type) + // 2) In the same schema as the table + // 3) In the same catalog + // 4) System catalog + + optional_ptr entry = nullptr; + if (!user_type_schema.empty()) { + entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, user_type_schema, user_type_name, + OnEntryNotFound::RETURN_NULL); } - type = LogicalType::STRUCT(child_types); - } break; - case LogicalTypeId::UNION: { - auto member_types = UnionType::CopyMemberTypes(type); - for (auto &member_type : member_types) { - BindLogicalType(member_type.second, catalog, schema); + if (!IsValidUserType(entry)) { + entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, schema, user_type_name, + OnEntryNotFound::RETURN_NULL); } - type = LogicalType::UNION(member_types); - } break; - default: - break; + if (!IsValidUserType(entry)) { + entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, INVALID_SCHEMA, user_type_name, + OnEntryNotFound::RETURN_NULL); + } + if (!IsValidUserType(entry)) { + entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, INVALID_CATALOG, INVALID_SCHEMA, + user_type_name, OnEntryNotFound::THROW_EXCEPTION); + } + auto &type_entry = entry->Cast(); + type = type_entry.user_type; + user_bind_modifiers_func = type_entry.bind_modifiers; + } else { + string type_catalog = UserType::GetCatalog(type); + string type_schema = UserType::GetSchema(type); + + BindSchemaOrCatalog(context, type_catalog, type_schema); + auto entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, type_catalog, type_schema, user_type_name); + auto &type_entry = entry->Cast(); + type = type_entry.user_type; + user_bind_modifiers_func = type_entry.bind_modifiers; } - // Set the alias and extension info back - type.SetAlias(alias); - type.SetExtensionInfo(std::move(ext_info)); + BindLogicalType(type, catalog, schema); + + // Apply the type modifiers (if any) + if (user_bind_modifiers_func) { + // If an explicit bind_modifiers function was provided, use that to set the type modifier + BindTypeModifiersInput input {context, type, user_type_mods}; + type = user_bind_modifiers_func(input); + } else if (type.HasModifiers()) { + // If the type already has modifiers, try to replace them with the user-provided ones if they are compatible + // This enables registering custom types with "default" type modifiers that can be overridden, without + // having to provide a custom bind_modifiers function + auto type_mods_size = type.GetModifiers()->size(); + + // Are we trying to pass more type modifiers than the type has? + if (user_type_mods.size() > type_mods_size) { + throw BinderException( + "Cannot apply '%d' type modifier(s) to type '%s' taking at most '%d' type modifier(s)", + user_type_mods.size(), user_type_name, type_mods_size); + } - return; + // Deep copy the type so that we can replace the type modifiers + type = type.DeepCopy(); + + // Re-fetch the type modifiers now that we've deduplicated the ExtraTypeInfo + auto &type_mods = *type.GetModifiers(); + + // Replace them in order, casting if necessary + for (idx_t i = 0; i < MinValue(type_mods.size(), user_type_mods.size()); i++) { + auto &type_mod = type_mods[i]; + auto user_type_mod = user_type_mods[i]; + if (type_mod.type() == user_type_mod.type()) { + type_mod = std::move(user_type_mod); + } else if (user_type_mod.DefaultTryCastAs(type_mod.type())) { + type_mod = std::move(user_type_mod); + } else { + throw BinderException("Cannot apply type modifier '%s' to type '%s', expected value of type '%s'", + user_type_mod.ToString(), user_type_name, type_mod.type().ToString()); + } + } + } else if (!user_type_mods.empty()) { + // We're trying to pass type modifiers to a type that doesnt have any + throw BinderException("Type '%s' does not take any type modifiers", user_type_name); + } } +} - // User type, bind the user type - auto user_type_name = UserType::GetTypeName(type); - auto user_type_schema = UserType::GetSchema(type); - auto user_type_mods = UserType::GetTypeModifiers(type); - - bind_logical_type_function_t user_bind_modifiers_func = nullptr; - - if (catalog) { - // The search order is: - // 1) In the explicitly set schema (my_schema.my_type) - // 2) In the same schema as the table - // 3) In the same catalog - // 4) System catalog +static void FindMatchingPrimaryKeyColumns(const ColumnList &columns, const vector> &constraints, + ForeignKeyConstraint &fk) { + // find the matching primary key constraint + bool found_constraint = false; + // if no columns are defined, we will automatically try to bind to the primary key + bool find_primary_key = fk.pk_columns.empty(); + for (auto &constr : constraints) { + if (constr->type != ConstraintType::UNIQUE) { + continue; + } + auto &unique = constr->Cast(); + if (find_primary_key && !unique.IsPrimaryKey()) { + continue; + } + found_constraint = true; - optional_ptr entry = nullptr; - if (!user_type_schema.empty()) { - entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, user_type_schema, user_type_name, - OnEntryNotFound::RETURN_NULL); + vector pk_names; + if (unique.HasIndex()) { + pk_names.push_back(columns.GetColumn(LogicalIndex(unique.GetIndex())).Name()); + } else { + pk_names = unique.GetColumnNames(); } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, schema, user_type_name, - OnEntryNotFound::RETURN_NULL); + if (find_primary_key) { + // found matching primary key + if (pk_names.size() != fk.fk_columns.size()) { + auto pk_name_str = StringUtil::Join(pk_names, ","); + auto fk_name_str = StringUtil::Join(fk.fk_columns, ","); + throw BinderException( + "Failed to create foreign key: number of referencing (%s) and referenced columns (%s) differ", + fk_name_str, pk_name_str); + } + fk.pk_columns = pk_names; + return; + } + if (pk_names.size() != fk.fk_columns.size()) { + // the number of referencing and referenced columns for foreign keys must be the same + continue; } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, *catalog, INVALID_SCHEMA, user_type_name, - OnEntryNotFound::RETURN_NULL); + bool equals = true; + for (idx_t i = 0; i < fk.pk_columns.size(); i++) { + if (!StringUtil::CIEquals(fk.pk_columns[i], pk_names[i])) { + equals = false; + break; + } } - if (!IsValidUserType(entry)) { - entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, INVALID_CATALOG, INVALID_SCHEMA, user_type_name, - OnEntryNotFound::THROW_EXCEPTION); + if (!equals) { + continue; } - auto &type_entry = entry->Cast(); - type = type_entry.user_type; - user_bind_modifiers_func = type_entry.bind_function; - } else { - string type_catalog = UserType::GetCatalog(type); - string type_schema = UserType::GetSchema(type); + // found match + return; + } + // no match found! examine why + if (!found_constraint) { + // no unique constraint or primary key + string search_term = find_primary_key ? "primary key" : "primary key or unique constraint"; + throw BinderException("Failed to create foreign key: there is no %s for referenced table \"%s\"", search_term, + fk.info.table); + } + // check if all the columns exist + for (auto &name : fk.pk_columns) { + bool found = columns.ColumnExists(name); + if (!found) { + throw BinderException( + "Failed to create foreign key: referenced table \"%s\" does not have a column named \"%s\"", + fk.info.table, name); + } + } + auto fk_names = StringUtil::Join(fk.pk_columns, ","); + throw BinderException("Failed to create foreign key: referenced table \"%s\" does not have a primary key or unique " + "constraint on the columns %s", + fk.info.table, fk_names); +} - BindSchemaOrCatalog(context, type_catalog, type_schema); - auto entry = entry_retriever.GetEntry(CatalogType::TYPE_ENTRY, type_catalog, type_schema, user_type_name); - auto &type_entry = entry->Cast(); - type = type_entry.user_type; - user_bind_modifiers_func = type_entry.bind_function; +static void FindForeignKeyIndexes(const ColumnList &columns, const vector &names, + vector &indexes) { + D_ASSERT(indexes.empty()); + D_ASSERT(!names.empty()); + for (auto &name : names) { + if (!columns.ColumnExists(name)) { + throw BinderException("column \"%s\" named in key does not exist", name); + } + auto &column = columns.GetColumn(name); + if (column.Generated()) { + throw BinderException("Failed to create foreign key: referenced column \"%s\" is a generated column", + column.Name()); + } + indexes.push_back(column.Physical()); } +} - // Now we bind the inner user type - BindLogicalType(type, catalog, schema); +static void CheckForeignKeyTypes(const ColumnList &pk_columns, const ColumnList &fk_columns, ForeignKeyConstraint &fk) { + D_ASSERT(fk.info.pk_keys.size() == fk.info.fk_keys.size()); + for (idx_t c_idx = 0; c_idx < fk.info.pk_keys.size(); c_idx++) { + auto &pk_col = pk_columns.GetColumn(fk.info.pk_keys[c_idx]); + auto &fk_col = fk_columns.GetColumn(fk.info.fk_keys[c_idx]); + if (pk_col.Type() != fk_col.Type()) { + throw BinderException("Failed to create foreign key: incompatible types between column \"%s\" (\"%s\") and " + "column \"%s\" (\"%s\")", + pk_col.Name(), pk_col.Type().ToString(), fk_col.Name(), fk_col.Type().ToString()); + } + } +} - // Apply the type modifiers (if any) - if (user_bind_modifiers_func) { - // If an explicit bind_modifiers function was provided, use that to construct the type +void ExpressionContainsGeneratedColumn(const ParsedExpression &expr, const unordered_set &gcols, + bool &contains_gcol) { + if (contains_gcol) { + return; + } + if (expr.type == ExpressionType::COLUMN_REF) { + auto &column_ref = expr.Cast(); + auto &name = column_ref.GetColumnName(); + if (gcols.count(name)) { + contains_gcol = true; + return; + } + } + ParsedExpressionIterator::EnumerateChildren( + expr, [&](const ParsedExpression &child) { ExpressionContainsGeneratedColumn(child, gcols, contains_gcol); }); +} - BindLogicalTypeInput input {context, type, user_type_mods}; - type = user_bind_modifiers_func(input); - } else { - if (!user_type_mods.empty()) { - throw BinderException("Type '%s' does not take any type modifiers", user_type_name); +static bool AnyConstraintReferencesGeneratedColumn(CreateTableInfo &table_info) { + unordered_set generated_columns; + for (auto &col : table_info.columns.Logical()) { + if (!col.Generated()) { + continue; } + generated_columns.insert(col.Name()); } + if (generated_columns.empty()) { + return false; + } + + for (auto &constr : table_info.constraints) { + switch (constr->type) { + case ConstraintType::CHECK: { + auto &constraint = constr->Cast(); + auto &expr = constraint.expression; + bool contains_generated_column = false; + ExpressionContainsGeneratedColumn(*expr, generated_columns, contains_generated_column); + if (contains_generated_column) { + return true; + } + break; + } + case ConstraintType::NOT_NULL: { + auto &constraint = constr->Cast(); + if (table_info.columns.GetColumn(constraint.index).Generated()) { + return true; + } + break; + } + case ConstraintType::UNIQUE: { + auto &constraint = constr->Cast(); + if (!constraint.HasIndex()) { + for (auto &col : constraint.GetColumnNames()) { + if (generated_columns.count(col)) { + return true; + } + } + } else { + if (table_info.columns.GetColumn(constraint.GetIndex()).Generated()) { + return true; + } + } + break; + } + case ConstraintType::FOREIGN_KEY: { + // If it contained a generated column, an exception would have been thrown inside AddDataTableIndex earlier + break; + } + default: { + throw NotImplementedException("ConstraintType not implemented"); + } + } + } + return false; } unique_ptr DuckCatalog::BindCreateIndex(Binder &binder, CreateStatement &stmt, TableCatalogEntry &table, unique_ptr plan) { D_ASSERT(plan->type == LogicalOperatorType::LOGICAL_GET); - auto create_index_info = unique_ptr_cast(std::move(stmt.info)); + auto &base = stmt.info->Cast(); + + auto &get = plan->Cast(); + // bind the index expressions IndexBinder index_binder(binder, binder.context); - return index_binder.BindCreateIndex(binder.context, std::move(create_index_info), table, std::move(plan), nullptr); + auto &dependencies = base.dependencies; + auto &catalog = Catalog::GetCatalog(binder.context, base.catalog); + index_binder.SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { + if (&catalog != &entry.ParentCatalog()) { + // Don't register any cross-catalog dependencies + return; + } + dependencies.AddDependency(entry); + }); + vector> expressions; + expressions.reserve(base.expressions.size()); + for (auto &expr : base.expressions) { + expressions.push_back(index_binder.Bind(expr)); + } + + auto create_index_info = unique_ptr_cast(std::move(stmt.info)); + auto &column_ids = get.GetColumnIds(); + for (auto &column_id : column_ids) { + if (column_id == COLUMN_IDENTIFIER_ROW_ID) { + throw BinderException("Cannot create an index on the rowid!"); + } + create_index_info->scan_types.push_back(get.returned_types[column_id]); + } + create_index_info->scan_types.emplace_back(LogicalType::ROW_TYPE); + create_index_info->names = get.names; + create_index_info->column_ids = column_ids; + create_index_info->schema = table.schema.name; + auto &bind_data = get.bind_data->Cast(); + bind_data.is_create_index = true; + get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); + + // the logical CREATE INDEX also needs all fields to scan the referenced table + auto result = make_uniq(std::move(create_index_info), std::move(expressions), table); + result->children.push_back(std::move(plan)); + return std::move(result); } BoundStatement Binder::Bind(CreateStatement &stmt) { @@ -415,17 +659,18 @@ BoundStatement Binder::Bind(CreateStatement &stmt) { break; } case CatalogType::INDEX_ENTRY: { - auto &create_index_info = stmt.info->Cast(); + auto &base = stmt.info->Cast(); + + // visit the table reference + auto table_ref = make_uniq(); + table_ref->catalog_name = base.catalog; + table_ref->schema_name = base.schema; + table_ref->table_name = base.table; - // Plan the table scan. - TableDescription table_description(create_index_info.catalog, create_index_info.schema, - create_index_info.table); - auto table_ref = make_uniq(table_description); auto bound_table = Bind(*table_ref); if (bound_table->type != TableReferenceType::BASE_TABLE) { - throw BinderException("can only create an index on a base table"); + throw BinderException("Can only create an index over a base table!"); } - auto &table_binding = bound_table->Cast(); auto &table = table_binding.table; if (table.temporary) { @@ -438,13 +683,63 @@ BoundStatement Binder::Bind(CreateStatement &stmt) { if (plan->type != LogicalOperatorType::LOGICAL_GET) { throw BinderException("Cannot create index on a view!"); } - result.plan = table.catalog.BindCreateIndex(*this, stmt, table, std::move(plan)); break; } case CatalogType::TABLE_ENTRY: { + auto &create_info = stmt.info->Cast(); + // If there is a foreign key constraint, resolve primary key column's index from primary key column's name + reference_set_t fk_schemas; + for (idx_t i = 0; i < create_info.constraints.size(); i++) { + auto &cond = create_info.constraints[i]; + if (cond->type != ConstraintType::FOREIGN_KEY) { + continue; + } + auto &fk = cond->Cast(); + if (fk.info.type != ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE) { + continue; + } + D_ASSERT(fk.info.pk_keys.empty()); + D_ASSERT(fk.info.fk_keys.empty()); + FindForeignKeyIndexes(create_info.columns, fk.fk_columns, fk.info.fk_keys); + if (StringUtil::CIEquals(create_info.table, fk.info.table)) { + // self-referential foreign key constraint + fk.info.type = ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE; + FindMatchingPrimaryKeyColumns(create_info.columns, create_info.constraints, fk); + FindForeignKeyIndexes(create_info.columns, fk.pk_columns, fk.info.pk_keys); + CheckForeignKeyTypes(create_info.columns, create_info.columns, fk); + } else { + // have to resolve referenced table + auto table_entry = + entry_retriever.GetEntry(CatalogType::TABLE_ENTRY, INVALID_CATALOG, fk.info.schema, fk.info.table); + auto &pk_table_entry_ptr = table_entry->Cast(); + fk_schemas.insert(pk_table_entry_ptr.schema); + FindMatchingPrimaryKeyColumns(pk_table_entry_ptr.GetColumns(), pk_table_entry_ptr.GetConstraints(), fk); + FindForeignKeyIndexes(pk_table_entry_ptr.GetColumns(), fk.pk_columns, fk.info.pk_keys); + CheckForeignKeyTypes(pk_table_entry_ptr.GetColumns(), create_info.columns, fk); + auto &storage = pk_table_entry_ptr.GetStorage(); + + if (!storage.HasForeignKeyIndex(fk.info.pk_keys, ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE)) { + auto fk_column_names = StringUtil::Join(fk.pk_columns, ","); + throw BinderException("Failed to create foreign key on %s(%s): no UNIQUE or PRIMARY KEY constraint " + "present on these columns", + pk_table_entry_ptr.name, fk_column_names); + } + } + D_ASSERT(fk.info.pk_keys.size() == fk.info.fk_keys.size()); + D_ASSERT(fk.info.pk_keys.size() == fk.pk_columns.size()); + D_ASSERT(fk.info.fk_keys.size() == fk.fk_columns.size()); + } + if (AnyConstraintReferencesGeneratedColumn(create_info)) { + throw BinderException("Constraints on generated columns are not supported yet"); + } auto bound_info = BindCreateTableInfo(std::move(stmt.info)); auto root = std::move(bound_info->query); + for (auto &fk_schema : fk_schemas) { + if (&fk_schema.get() != &bound_info->schema) { + throw BinderException("Creating foreign keys across different schemas or catalogs is not supported"); + } + } // create the logical operator auto &schema = bound_info->schema; diff --git a/src/duckdb/src/planner/binder/statement/bind_create_table.cpp b/src/duckdb/src/planner/binder/statement/bind_create_table.cpp index 80d50d074..7ffbaf236 100644 --- a/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_create_table.cpp @@ -11,6 +11,7 @@ #include "duckdb/catalog/dependency_manager.hpp" #include "duckdb/function/table/table_scan.hpp" #include "duckdb/planner/operator/logical_get.hpp" +#include "duckdb/parser/parsed_expression_iterator.hpp" #include "duckdb/common/string.hpp" #include "duckdb/common/queue.hpp" #include "duckdb/parser/expression/list.hpp" @@ -19,8 +20,8 @@ #include "duckdb/planner/expression_binder/index_binder.hpp" #include "duckdb/parser/parsed_data/create_index_info.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" -#include "duckdb/parser/parsed_expression_iterator.hpp" -#include "duckdb/storage/data_table.hpp" + +#include namespace duckdb { @@ -34,6 +35,19 @@ static void CreateColumnDependencyManager(BoundCreateTableInfo &info) { } } +static unique_ptr BindCheckConstraint(Binder &binder, const string &table_name, + const ColumnList &columns, const unique_ptr &cond) { + auto bound_constraint = make_uniq(); + // check constraint: bind the expression + CheckBinder check_binder(binder, binder.context, table_name, columns, bound_constraint->bound_columns); + auto &check = cond->Cast(); + // create a copy of the unbound expression because the binding destroys the constraint + auto unbound_expression = check.expression->Copy(); + // now bind the constraint and create a new BoundCheckConstraint + bound_constraint->expression = check_binder.Bind(unbound_expression); + return std::move(bound_constraint); +} + vector> Binder::BindConstraints(ClientContext &context, const vector> &constraints, const string &table_name, const ColumnList &columns) { @@ -48,8 +62,76 @@ vector> Binder::BindConstraints(const TableCatalogEn vector> Binder::BindConstraints(const vector> &constraints, const string &table_name, const ColumnList &columns) { vector> bound_constraints; - for (const auto &constr : constraints) { - bound_constraints.push_back(BindConstraint(*constr, table_name, columns)); + for (auto &constr : constraints) { + switch (constr->type) { + case ConstraintType::CHECK: { + bound_constraints.push_back(BindCheckConstraint(*this, table_name, columns, constr)); + break; + } + case ConstraintType::NOT_NULL: { + auto ¬_null = constr->Cast(); + auto &col = columns.GetColumn(LogicalIndex(not_null.index)); + bound_constraints.push_back(make_uniq(PhysicalIndex(col.StorageOid()))); + break; + } + case ConstraintType::UNIQUE: { + auto &unique = constr->Cast(); + // have to resolve columns of the unique constraint + vector keys; + logical_index_set_t key_set; + if (unique.HasIndex()) { + D_ASSERT(unique.GetIndex().index < columns.LogicalColumnCount()); + // unique constraint is given by single index + unique.SetColumnName(columns.GetColumn(unique.GetIndex()).Name()); + keys.push_back(unique.GetIndex()); + key_set.insert(unique.GetIndex()); + } else { + // unique constraint is given by list of names + // have to resolve names + for (auto &keyname : unique.GetColumnNames()) { + if (!columns.ColumnExists(keyname)) { + throw ParserException("column \"%s\" named in key does not exist", keyname); + } + auto &column = columns.GetColumn(keyname); + auto column_index = column.Logical(); + if (key_set.find(column_index) != key_set.end()) { + throw ParserException("column \"%s\" appears twice in " + "primary key constraint", + keyname); + } + keys.push_back(column_index); + key_set.insert(column_index); + } + } + bound_constraints.push_back( + make_uniq(std::move(keys), std::move(key_set), unique.IsPrimaryKey())); + break; + } + case ConstraintType::FOREIGN_KEY: { + auto &fk = constr->Cast(); + D_ASSERT((fk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE && !fk.info.pk_keys.empty()) || + (fk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE && !fk.info.pk_keys.empty()) || + fk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE); + physical_index_set_t fk_key_set, pk_key_set; + for (auto &pk_key : fk.info.pk_keys) { + if (pk_key_set.find(pk_key) != pk_key_set.end()) { + throw BinderException("Duplicate primary key referenced in FOREIGN KEY constraint"); + } + pk_key_set.insert(pk_key); + } + for (auto &fk_key : fk.info.fk_keys) { + if (fk_key_set.find(fk_key) != fk_key_set.end()) { + throw BinderException("Duplicate key specified in FOREIGN KEY constraint"); + } + fk_key_set.insert(fk_key); + } + bound_constraints.push_back( + make_uniq(fk.info, std::move(pk_key_set), std::move(fk_key_set))); + break; + } + default: + throw NotImplementedException("unrecognized constraint type in bind"); + } } return bound_constraints; } @@ -58,26 +140,30 @@ vector> Binder::BindNewConstraints(vector primary_keys; - - for (const auto &bound_constr : bound_constraints) { - switch (bound_constr->type) { + logical_index_set_t not_null_columns; + vector primary_keys; + for (idx_t c = 0; c < constraints.size(); c++) { + auto &constr = constraints[c]; + switch (constr->type) { case ConstraintType::NOT_NULL: { - auto ¬_null = bound_constr->Cast(); + auto ¬_null = constr->Cast(); + auto &col = columns.GetColumn(LogicalIndex(not_null.index)); + bound_constraints.push_back(make_uniq(PhysicalIndex(col.StorageOid()))); not_null_columns.insert(not_null.index); break; } case ConstraintType::UNIQUE: { - const auto &unique = bound_constr->Cast(); - if (unique.is_primary_key) { + auto &unique = constr->Cast(); + auto &bound_unique = bound_constraints[c]->Cast(); + if (unique.IsPrimaryKey()) { + // we can only have one primary key per table if (has_primary_key) { throw ParserException("table \"%s\" has more than one primary key", table_name); } has_primary_key = true; - primary_keys = unique.keys; + primary_keys = bound_unique.keys; } break; } @@ -85,127 +171,21 @@ vector> Binder::BindNewConstraints(vector(logical_index)); - bound_constraints.push_back(make_uniq(column_index)); + auto physical_index = columns.LogicalToPhysical(column_index); + constraints.push_back(make_uniq(column_index)); + bound_constraints.push_back(make_uniq(physical_index)); } } - return bound_constraints; } -unique_ptr BindCheckConstraint(Binder &binder, Constraint &constraint, const string &table, - const ColumnList &columns) { - auto bound_constraint = make_uniq(); - auto &bound_check = bound_constraint->Cast(); - - // Bind the CHECK expression. - CheckBinder check_binder(binder, binder.context, table, columns, bound_check.bound_columns); - auto &check = constraint.Cast(); - - // Create a copy of the unbound expression because binding can invalidate it. - auto unbound_expression = check.expression->Copy(); - - // Bind the constraint and reset the original expression. - bound_check.expression = check_binder.Bind(check.expression); - check.expression = std::move(unbound_expression); - return std::move(bound_constraint); -} - -unique_ptr Binder::BindUniqueConstraint(Constraint &constraint, const string &table, - const ColumnList &columns) { - auto &unique = constraint.Cast(); - - // Resolve the columns. - vector indexes; - physical_index_set_t index_set; - - // HasIndex refers to a column index, not an index(-structure). - // If set, then the UNIQUE constraint is defined on a single column. - if (unique.HasIndex()) { - auto &col = columns.GetColumn(unique.GetIndex()); - unique.SetColumnName(col.Name()); - indexes.push_back(col.Physical()); - index_set.insert(col.Physical()); - return make_uniq(std::move(indexes), std::move(index_set), unique.IsPrimaryKey()); - } - - // The UNIQUE constraint is defined on a list of columns. - for (auto &col_name : unique.GetColumnNames()) { - if (!columns.ColumnExists(col_name)) { - throw CatalogException("table \"%s\" does not have a column named \"%s\"", table, col_name); - } - auto &col = columns.GetColumn(col_name); - if (col.Generated()) { - throw BinderException("cannot create a PRIMARY KEY on a generated column: %s", col.GetName()); - } - - auto physical_index = col.Physical(); - if (index_set.find(physical_index) != index_set.end()) { - throw ParserException("column \"%s\" appears twice in primary key constraint", col_name); - } - indexes.push_back(physical_index); - index_set.insert(physical_index); - } - - return make_uniq(std::move(indexes), std::move(index_set), unique.IsPrimaryKey()); -} - -unique_ptr BindForeignKey(Constraint &constraint) { - auto &fk = constraint.Cast(); - D_ASSERT((fk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE && !fk.info.pk_keys.empty()) || - (fk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE && !fk.info.pk_keys.empty()) || - fk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE); - - physical_index_set_t pk_key_set; - for (auto &pk_key : fk.info.pk_keys) { - if (pk_key_set.find(pk_key) != pk_key_set.end()) { - throw ParserException("duplicate primary key referenced in FOREIGN KEY constraint"); - } - pk_key_set.insert(pk_key); - } - - physical_index_set_t fk_key_set; - for (auto &fk_key : fk.info.fk_keys) { - if (fk_key_set.find(fk_key) != fk_key_set.end()) { - throw ParserException("duplicate key specified in FOREIGN KEY constraint"); - } - fk_key_set.insert(fk_key); - } - - return make_uniq(fk.info, std::move(pk_key_set), std::move(fk_key_set)); -} - -unique_ptr Binder::BindConstraint(Constraint &constraint, const string &table, - const ColumnList &columns) { - switch (constraint.type) { - case ConstraintType::CHECK: { - return BindCheckConstraint(*this, constraint, table, columns); - } - case ConstraintType::NOT_NULL: { - auto ¬_null = constraint.Cast(); - auto &col = columns.GetColumn(not_null.index); - return make_uniq(col.Physical()); - } - case ConstraintType::UNIQUE: { - return BindUniqueConstraint(constraint, table, columns); - } - case ConstraintType::FOREIGN_KEY: { - return BindForeignKey(constraint); - } - default: - throw NotImplementedException("unrecognized constraint type in bind"); - } -} - void Binder::BindGeneratedColumns(BoundCreateTableInfo &info) { auto &base = info.base->Cast(); @@ -264,21 +244,7 @@ void Binder::BindGeneratedColumns(BoundCreateTableInfo &info) { } } -void Binder::BindDefaultValues(const ColumnList &columns, vector> &bound_defaults, - const string &catalog_name, const string &schema_p) { - string schema_name = schema_p; - if (schema_p.empty()) { - schema_name = DEFAULT_SCHEMA; - } - - // FIXME: We might want to save the existing search path of the binder - vector defaults_search_path; - defaults_search_path.emplace_back(catalog_name, schema_name); - if (schema_name != DEFAULT_SCHEMA) { - defaults_search_path.emplace_back(catalog_name, DEFAULT_SCHEMA); - } - entry_retriever.SetSearchPath(std::move(defaults_search_path)); - +void Binder::BindDefaultValues(const ColumnList &columns, vector> &bound_defaults) { for (auto &column : columns.Physical()) { unique_ptr bound_default; if (column.HasDefaultValue()) { @@ -299,252 +265,42 @@ void Binder::BindDefaultValues(const ColumnList &columns, vector Binder::BindCreateTableInfo(unique_ptr info, SchemaCatalogEntry &schema) { - vector> bound_defaults; - return BindCreateTableInfo(std::move(info), schema, bound_defaults); -} - -unique_ptr Binder::BindCreateTableCheckpoint(unique_ptr info, - SchemaCatalogEntry &schema) { - auto result = make_uniq(schema, std::move(info)); - CreateColumnDependencyManager(*result); - return result; -} - -void ExpressionContainsGeneratedColumn(const ParsedExpression &expr, const unordered_set &gcols, - bool &contains_gcol) { - if (contains_gcol) { - return; - } - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { - auto &column_ref = expr.Cast(); - auto &name = column_ref.GetColumnName(); - if (gcols.count(name)) { - contains_gcol = true; - return; - } - } - ParsedExpressionIterator::EnumerateChildren( - expr, [&](const ParsedExpression &child) { ExpressionContainsGeneratedColumn(child, gcols, contains_gcol); }); -} - -static bool AnyConstraintReferencesGeneratedColumn(CreateTableInfo &table_info) { - unordered_set generated_columns; - for (auto &col : table_info.columns.Logical()) { - if (!col.Generated()) { - continue; - } - generated_columns.insert(col.Name()); - } - if (generated_columns.empty()) { - return false; - } - - for (auto &constr : table_info.constraints) { - switch (constr->type) { - case ConstraintType::CHECK: { - auto &constraint = constr->Cast(); - auto &expr = constraint.expression; - bool contains_generated_column = false; - ExpressionContainsGeneratedColumn(*expr, generated_columns, contains_generated_column); - if (contains_generated_column) { - return true; - } - break; - } - case ConstraintType::NOT_NULL: { - auto &constraint = constr->Cast(); - if (table_info.columns.GetColumn(constraint.index).Generated()) { - return true; - } - break; - } - case ConstraintType::UNIQUE: { - auto &constraint = constr->Cast(); - if (!constraint.HasIndex()) { - for (auto &col : constraint.GetColumnNames()) { - if (generated_columns.count(col)) { - return true; - } - } - } else { - if (table_info.columns.GetColumn(constraint.GetIndex()).Generated()) { - return true; - } - } - break; - } - case ConstraintType::FOREIGN_KEY: { - // If it contained a generated column, an exception would have been thrown inside AddDataTableIndex earlier - break; - } - default: { - throw NotImplementedException("ConstraintType not implemented"); - } - } - } - return false; -} - -static void FindForeignKeyIndexes(const ColumnList &columns, const vector &names, - vector &indexes) { - D_ASSERT(indexes.empty()); - D_ASSERT(!names.empty()); - for (auto &name : names) { - if (!columns.ColumnExists(name)) { - throw BinderException("column \"%s\" named in key does not exist", name); - } - auto &column = columns.GetColumn(name); - if (column.Generated()) { - throw BinderException("Failed to create foreign key: referenced column \"%s\" is a generated column", - column.Name()); +static void ExtractExpressionDependencies(Expression &expr, LogicalDependencyList &dependencies) { + if (expr.type == ExpressionType::BOUND_FUNCTION) { + auto &function = expr.Cast(); + if (function.function.dependency) { + function.function.dependency(function, dependencies); } - indexes.push_back(column.Physical()); } + ExpressionIterator::EnumerateChildren( + expr, [&](Expression &child) { ExtractExpressionDependencies(child, dependencies); }); } -static void FindMatchingPrimaryKeyColumns(const ColumnList &columns, const vector> &constraints, - ForeignKeyConstraint &fk) { - // find the matching primary key constraint - bool found_constraint = false; - // if no columns are defined, we will automatically try to bind to the primary key - bool find_primary_key = fk.pk_columns.empty(); - for (auto &constr : constraints) { - if (constr->type != ConstraintType::UNIQUE) { - continue; - } - auto &unique = constr->Cast(); - if (find_primary_key && !unique.IsPrimaryKey()) { - continue; - } - found_constraint = true; - - vector pk_names; - if (unique.HasIndex()) { - pk_names.push_back(columns.GetColumn(LogicalIndex(unique.GetIndex())).Name()); - } else { - pk_names = unique.GetColumnNames(); - } - if (find_primary_key) { - // found matching primary key - if (pk_names.size() != fk.fk_columns.size()) { - auto pk_name_str = StringUtil::Join(pk_names, ","); - auto fk_name_str = StringUtil::Join(fk.fk_columns, ","); - throw BinderException( - "Failed to create foreign key: number of referencing (%s) and referenced columns (%s) differ", - fk_name_str, pk_name_str); - } - fk.pk_columns = pk_names; - return; - } - if (pk_names.size() != fk.fk_columns.size()) { - // the number of referencing and referenced columns for foreign keys must be the same - continue; +static void ExtractDependencies(BoundCreateTableInfo &info, vector> &defaults, + vector> &constraints) { + for (auto &default_value : defaults) { + if (default_value) { + ExtractExpressionDependencies(*default_value, info.dependencies); } - bool equals = true; - for (idx_t i = 0; i < fk.pk_columns.size(); i++) { - if (!StringUtil::CIEquals(fk.pk_columns[i], pk_names[i])) { - equals = false; - break; - } - } - if (!equals) { - continue; - } - // found match - return; - } - // no match found! examine why - if (!found_constraint) { - // no unique constraint or primary key - string search_term = find_primary_key ? "primary key" : "primary key or unique constraint"; - throw BinderException("Failed to create foreign key: there is no %s for referenced table \"%s\"", search_term, - fk.info.table); } - // check if all the columns exist - for (auto &name : fk.pk_columns) { - bool found = columns.ColumnExists(name); - if (!found) { - throw BinderException( - "Failed to create foreign key: referenced table \"%s\" does not have a column named \"%s\"", - fk.info.table, name); + for (auto &constraint : constraints) { + if (constraint->type == ConstraintType::CHECK) { + auto &bound_check = constraint->Cast(); + ExtractExpressionDependencies(*bound_check.expression, info.dependencies); } } - auto fk_names = StringUtil::Join(fk.pk_columns, ","); - throw BinderException("Failed to create foreign key: referenced table \"%s\" does not have a primary key or unique " - "constraint on the columns %s", - fk.info.table, fk_names); } -static void CheckForeignKeyTypes(const ColumnList &pk_columns, const ColumnList &fk_columns, ForeignKeyConstraint &fk) { - D_ASSERT(fk.info.pk_keys.size() == fk.info.fk_keys.size()); - for (idx_t c_idx = 0; c_idx < fk.info.pk_keys.size(); c_idx++) { - auto &pk_col = pk_columns.GetColumn(fk.info.pk_keys[c_idx]); - auto &fk_col = fk_columns.GetColumn(fk.info.fk_keys[c_idx]); - if (pk_col.Type() != fk_col.Type()) { - throw BinderException("Failed to create foreign key: incompatible types between column \"%s\" (\"%s\") and " - "column \"%s\" (\"%s\")", - pk_col.Name(), pk_col.Type().ToString(), fk_col.Name(), fk_col.Type().ToString()); - } - } +unique_ptr Binder::BindCreateTableInfo(unique_ptr info, SchemaCatalogEntry &schema) { + vector> bound_defaults; + return BindCreateTableInfo(std::move(info), schema, bound_defaults); } -static void BindCreateTableConstraints(CreateTableInfo &create_info, CatalogEntryRetriever &entry_retriever, - SchemaCatalogEntry &schema) { - // If there is a foreign key constraint, resolve primary key column's index from primary key column's name - reference_set_t fk_schemas; - for (idx_t i = 0; i < create_info.constraints.size(); i++) { - auto &cond = create_info.constraints[i]; - if (cond->type != ConstraintType::FOREIGN_KEY) { - continue; - } - auto &fk = cond->Cast(); - if (fk.info.type != ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE) { - continue; - } - if (!fk.info.pk_keys.empty() && !fk.info.fk_keys.empty()) { - return; - } - D_ASSERT(fk.info.pk_keys.empty()); - D_ASSERT(fk.info.fk_keys.empty()); - FindForeignKeyIndexes(create_info.columns, fk.fk_columns, fk.info.fk_keys); - - // Resolve the self-reference. - if (StringUtil::CIEquals(create_info.table, fk.info.table)) { - fk.info.type = ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE; - FindMatchingPrimaryKeyColumns(create_info.columns, create_info.constraints, fk); - FindForeignKeyIndexes(create_info.columns, fk.pk_columns, fk.info.pk_keys); - CheckForeignKeyTypes(create_info.columns, create_info.columns, fk); - continue; - } - - // Resolve the table reference. - auto table_entry = - entry_retriever.GetEntry(CatalogType::TABLE_ENTRY, INVALID_CATALOG, fk.info.schema, fk.info.table); - if (table_entry->type == CatalogType::VIEW_ENTRY) { - throw BinderException("cannot reference a VIEW with a FOREIGN KEY"); - } - - auto &pk_table_entry_ptr = table_entry->Cast(); - if (&pk_table_entry_ptr.schema != &schema) { - throw BinderException("Creating foreign keys across different schemas or catalogs is not supported"); - } - FindMatchingPrimaryKeyColumns(pk_table_entry_ptr.GetColumns(), pk_table_entry_ptr.GetConstraints(), fk); - FindForeignKeyIndexes(pk_table_entry_ptr.GetColumns(), fk.pk_columns, fk.info.pk_keys); - CheckForeignKeyTypes(pk_table_entry_ptr.GetColumns(), create_info.columns, fk); - auto &storage = pk_table_entry_ptr.GetStorage(); - - if (!storage.HasForeignKeyIndex(fk.info.pk_keys, ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE)) { - auto fk_column_names = StringUtil::Join(fk.pk_columns, ","); - throw BinderException("Failed to create foreign key on %s(%s): no UNIQUE or PRIMARY KEY constraint " - "present on these columns", - pk_table_entry_ptr.name, fk_column_names); - } - - D_ASSERT(fk.info.pk_keys.size() == fk.info.fk_keys.size()); - D_ASSERT(fk.info.pk_keys.size() == fk.pk_columns.size()); - D_ASSERT(fk.info.fk_keys.size() == fk.fk_columns.size()); - } +unique_ptr Binder::BindCreateTableCheckpoint(unique_ptr info, + SchemaCatalogEntry &schema) { + auto result = make_uniq(schema, std::move(info)); + CreateColumnDependencyManager(*result); + return result; } unique_ptr Binder::BindCreateTableInfo(unique_ptr info, SchemaCatalogEntry &schema, @@ -563,38 +319,10 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptr sql_types.size()) { - throw BinderException("Target table has more colum names than query result."); - } else if (target_col_names.size() < sql_types.size()) { - // filled the target_col_names with the name of query names - for (idx_t i = target_col_names.size(); i < sql_types.size(); i++) { - target_col_names.push_back(names[i]); - } - } - ColumnList new_colums; - for (idx_t i = 0; i < target_col_names.size(); i++) { - new_colums.AddColumn(ColumnDefinition(target_col_names[i], sql_types[i])); - } - base.columns = std::move(new_colums); - } else { - for (idx_t i = 0; i < names.size(); i++) { - base.columns.AddColumn(ColumnDefinition(names[i], sql_types[i])); - } - } - // bind collations to detect any unsupported collation errors - for (idx_t i = 0; i < base.columns.PhysicalColumnCount(); i++) { - auto &column = base.columns.GetColumnMutable(PhysicalIndex(i)); - if (column.Type().id() == LogicalTypeId::VARCHAR) { - ExpressionBinder::TestCollation(context, StringType::GetCollation(column.Type())); - } - BindLogicalType(column.TypeMutable(), &result->schema.catalog, result->schema.name); + for (idx_t i = 0; i < names.size(); i++) { + base.columns.AddColumn(ColumnDefinition(names[i], sql_types[i])); } } else { SetCatalogLookupCallback([&dependencies, &schema](CatalogEntry &entry) { @@ -608,31 +336,24 @@ unique_ptr Binder::BindCreateTableInfo(unique_ptrschema.catalog, result->schema.name); - } - BindCreateTableConstraints(base, entry_retriever, schema); - - if (AnyConstraintReferencesGeneratedColumn(base)) { - throw BinderException("Constraints on generated columns are not supported yet"); - } bound_constraints = BindNewConstraints(base.constraints, base.table, base.columns); // bind the default values - auto &catalog_name = schema.ParentCatalog().GetName(); - auto &schema_name = schema.name; - BindDefaultValues(base.columns, bound_defaults, catalog_name, schema_name); + BindDefaultValues(base.columns, bound_defaults); } + // extract dependencies from any default values or CHECK constraints + ExtractDependencies(*result, bound_defaults, bound_constraints); if (base.columns.PhysicalColumnCount() == 0) { throw BinderException("Creating a table without physical (non-generated) columns is not supported"); } - + // bind collations to detect any unsupported collation errors + for (idx_t i = 0; i < base.columns.PhysicalColumnCount(); i++) { + auto &column = base.columns.GetColumnMutable(PhysicalIndex(i)); + if (column.Type().id() == LogicalTypeId::VARCHAR) { + ExpressionBinder::TestCollation(context, StringType::GetCollation(column.Type())); + } + BindLogicalType(column.TypeMutable(), &result->schema.catalog, result->schema.name); + } result->dependencies.VerifyDependencies(schema.catalog, result->Base().table); auto &properties = GetStatementProperties(); diff --git a/src/duckdb/src/planner/binder/statement/bind_delete.cpp b/src/duckdb/src/planner/binder/statement/bind_delete.cpp index 822f487ed..cb9457d70 100644 --- a/src/duckdb/src/planner/binder/statement/bind_delete.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_delete.cpp @@ -76,7 +76,7 @@ BoundStatement Binder::Bind(DeleteStatement &stmt) { // set up the delete expression auto &column_ids = get.GetColumnIds(); del->expressions.push_back( - make_uniq(table.GetRowIdType(), ColumnBinding(get.table_index, column_ids.size()))); + make_uniq(LogicalType::ROW_TYPE, ColumnBinding(get.table_index, column_ids.size()))); get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); if (!stmt.returning_list.empty()) { diff --git a/src/duckdb/src/planner/binder/statement/bind_drop.cpp b/src/duckdb/src/planner/binder/statement/bind_drop.cpp index e17287bed..973854d7a 100644 --- a/src/duckdb/src/planner/binder/statement/bind_drop.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_drop.cpp @@ -35,11 +35,6 @@ BoundStatement Binder::Bind(DropStatement &stmt) { case CatalogType::TABLE_ENTRY: case CatalogType::TYPE_ENTRY: { BindSchemaOrCatalog(stmt.info->catalog, stmt.info->schema); - auto catalog = Catalog::GetCatalogEntry(context, stmt.info->catalog); - if (catalog) { - // mark catalog as accessed - properties.RegisterDBRead(*catalog, context); - } auto entry = Catalog::GetEntry(context, stmt.info->type, stmt.info->catalog, stmt.info->schema, stmt.info->name, stmt.info->if_not_found); if (!entry) { diff --git a/src/duckdb/src/planner/binder/statement/bind_execute.cpp b/src/duckdb/src/planner/binder/statement/bind_execute.cpp index 3e3af4d6a..31255101a 100644 --- a/src/duckdb/src/planner/binder/statement/bind_execute.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_execute.cpp @@ -35,7 +35,7 @@ BoundStatement Binder::Bind(ExecuteStatement &stmt) { auto constant_binder = Binder::CreateBinder(context); constant_binder->SetCanContainNulls(true); for (auto &pair : mapped_named_values) { - bool is_literal = pair.second->GetExpressionType() == ExpressionType::VALUE_CONSTANT; + bool is_literal = pair.second->type == ExpressionType::VALUE_CONSTANT; ConstantBinder cbinder(*constant_binder, context, "EXECUTE statement"); auto bound_expr = cbinder.Bind(pair.second); diff --git a/src/duckdb/src/planner/binder/statement/bind_export.cpp b/src/duckdb/src/planner/binder/statement/bind_export.cpp index 68b5b80d2..924df011f 100644 --- a/src/duckdb/src/planner/binder/statement/bind_export.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_export.cpp @@ -159,6 +159,10 @@ unique_ptr Binder::UnionOperators(vector ExpandDefaultExpression(const ColumnDefinition &col } void ReplaceDefaultExpression(unique_ptr &expr, const ColumnDefinition &column) { - D_ASSERT(expr->GetExpressionType() == ExpressionType::VALUE_DEFAULT); + D_ASSERT(expr->type == ExpressionType::VALUE_DEFAULT); expr = ExpandDefaultExpression(column); } @@ -56,7 +56,7 @@ void ExpressionBinder::DoUpdateSetQualifyInLambda(FunctionExpression &function, vector> &lambda_params) { for (auto &child : function.children) { - if (child->GetExpressionClass() != ExpressionClass::LAMBDA) { + if (child->expression_class != ExpressionClass::LAMBDA) { DoUpdateSetQualify(child, table_name, lambda_params); continue; } @@ -135,7 +135,7 @@ void ExpressionBinder::DoUpdateSetQualify(unique_ptr &expr, co // Replace binding.table_index with 'dest' if it's 'source' void ReplaceColumnBindings(Expression &expr, idx_t source, idx_t dest) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_columnref = expr.Cast(); if (bound_columnref.binding.table_index == source) { bound_columnref.binding.table_index = dest; @@ -148,6 +148,7 @@ void ReplaceColumnBindings(Expression &expr, idx_t source, idx_t dest) { void Binder::BindDoUpdateSetExpressions(const string &table_alias, LogicalInsert &insert, UpdateSetInfo &set_info, TableCatalogEntry &table, TableStorageInfo &storage_info) { D_ASSERT(insert.children.size() == 1); + D_ASSERT(insert.children[0]->type == LogicalOperatorType::LOGICAL_PROJECTION); vector logical_column_ids; vector column_names; @@ -167,16 +168,11 @@ void Binder::BindDoUpdateSetExpressions(const string &table_alias, LogicalInsert insert.set_columns.end()) { throw BinderException("Multiple assignments to same column \"%s\"", colname); } - - if (!column.Type().SupportsRegularUpdate()) { - insert.update_is_del_and_insert = true; - } - insert.set_columns.push_back(column.Physical()); logical_column_ids.push_back(column.Oid()); insert.set_types.push_back(column.Type()); column_names.push_back(colname); - if (expr->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { + if (expr->type == ExpressionType::VALUE_DEFAULT) { expr = ExpandDefaultExpression(column); } @@ -201,13 +197,13 @@ void Binder::BindDoUpdateSetExpressions(const string &table_alias, LogicalInsert } } - // If any column targeted by a SET expression has an index, then - // we need to rewrite this to an DELETE + INSERT. + // Verify that none of the columns that are targeted with a SET expression are indexed on for (idx_t i = 0; i < logical_column_ids.size(); i++) { auto &column = logical_column_ids[i]; if (indexed_columns.count(column)) { - insert.update_is_del_and_insert = true; - break; + throw BinderException("Can not assign to column '%s' because it has a UNIQUE/PRIMARY KEY constraint or is " + "referenced by an INDEX", + column_names[i]); } } } @@ -255,15 +251,6 @@ unique_ptr CreateSetInfoForReplace(TableCatalogEntry &table, Inse return set_info; } -vector GetColumnsToFetch(const TableBinding &binding) { - auto &bound_columns = binding.GetBoundColumnIds(); - vector result; - for (auto &col : bound_columns) { - result.push_back(col.GetPrimaryIndex()); - } - return result; -} - void Binder::BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &table, InsertStatement &stmt) { if (!stmt.on_conflict_info) { insert.action_type = OnConflictAction::THROW; @@ -435,7 +422,7 @@ void Binder::BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &tabl // of the original table, to execute the expressions D_ASSERT(original_binding->binding_type == BindingType::TABLE); auto &table_binding = original_binding->Cast(); - insert.columns_to_fetch = GetColumnsToFetch(table_binding); + insert.columns_to_fetch = table_binding.GetBoundColumnIds(); return; } @@ -461,7 +448,7 @@ void Binder::BindOnConflictClause(LogicalInsert &insert, TableCatalogEntry &tabl // of the original table, to execute the expressions D_ASSERT(original_binding->binding_type == BindingType::TABLE); auto &table_binding = original_binding->Cast(); - insert.columns_to_fetch = GetColumnsToFetch(table_binding); + insert.columns_to_fetch = table_binding.GetBoundColumnIds(); // Replace the column bindings to refer to the child operator for (auto &expr : insert.expressions) { @@ -499,9 +486,6 @@ BoundStatement Binder::Bind(InsertStatement &stmt) { if (values_list) { throw BinderException("INSERT BY NAME can only be used when inserting from a SELECT statement"); } - if (stmt.default_values) { - throw BinderException("INSERT BY NAME cannot be combined with with DEFAULT VALUES"); - } if (!stmt.columns.empty()) { throw BinderException("INSERT BY NAME cannot be combined with an explicit column list"); } @@ -556,9 +540,7 @@ BoundStatement Binder::Bind(InsertStatement &stmt) { } // bind the default values - auto &catalog_name = table.ParentCatalog().GetName(); - auto &schema_name = table.ParentSchema().name; - BindDefaultValues(table.GetColumns(), insert->bound_defaults, catalog_name, schema_name); + BindDefaultValues(table.GetColumns(), insert->bound_defaults); insert->bound_constraints = BindConstraints(table); if (!stmt.select_statement && !stmt.default_values) { result.plan = std::move(insert); @@ -589,7 +571,7 @@ BoundStatement Binder::Bind(InsertStatement &stmt) { // now replace any DEFAULT values with the corresponding default expression for (idx_t list_idx = 0; list_idx < expr_list.values.size(); list_idx++) { - if (expr_list.values[list_idx][col_idx]->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { + if (expr_list.values[list_idx][col_idx]->type == ExpressionType::VALUE_DEFAULT) { // DEFAULT value! replace the entry ReplaceDefaultExpression(expr_list.values[list_idx][col_idx], column); } diff --git a/src/duckdb/src/planner/binder/statement/bind_pragma.cpp b/src/duckdb/src/planner/binder/statement/bind_pragma.cpp index 3955cf897..8f89dec5b 100644 --- a/src/duckdb/src/planner/binder/statement/bind_pragma.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_pragma.cpp @@ -29,7 +29,7 @@ unique_ptr Binder::BindPragma(PragmaInfo &info, QueryErrorConte // bind the pragma function auto &entry = Catalog::GetEntry(context, INVALID_CATALOG, DEFAULT_SCHEMA, info.name); - FunctionBinder function_binder(*this); + FunctionBinder function_binder(context); ErrorData error; auto bound_idx = function_binder.BindFunction(entry.name, entry.functions, params, error); if (!bound_idx.IsValid()) { diff --git a/src/duckdb/src/planner/binder/statement/bind_simple.cpp b/src/duckdb/src/planner/binder/statement/bind_simple.cpp index d4d862843..70e11af36 100644 --- a/src/duckdb/src/planner/binder/statement/bind_simple.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_simple.cpp @@ -1,127 +1,58 @@ +#include "duckdb/parser/statement/alter_statement.hpp" +#include "duckdb/parser/statement/transaction_statement.hpp" +#include "duckdb/planner/operator/logical_simple.hpp" #include "duckdb/catalog/catalog.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" +#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" +#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" -#include "duckdb/catalog/duck_catalog.hpp" -#include "duckdb/execution/index/art/art.hpp" -#include "duckdb/function/table/table_scan.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" #include "duckdb/parser/parsed_data/comment_on_column_info.hpp" -#include "duckdb/parser/statement/alter_statement.hpp" -#include "duckdb/parser/statement/transaction_statement.hpp" -#include "duckdb/parser/tableref/basetableref.hpp" #include "duckdb/planner/binder.hpp" -#include "duckdb/planner/constraints/bound_unique_constraint.hpp" -#include "duckdb/planner/expression_binder/index_binder.hpp" -#include "duckdb/planner/operator/logical_create_index.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/planner/operator/logical_simple.hpp" - -namespace duckdb { -unique_ptr DuckCatalog::BindAlterAddIndex(Binder &binder, TableCatalogEntry &table_entry, - unique_ptr plan, - unique_ptr create_info, - unique_ptr alter_info) { - D_ASSERT(plan->type == LogicalOperatorType::LOGICAL_GET); - IndexBinder index_binder(binder, binder.context); - return index_binder.BindCreateIndex(binder.context, std::move(create_info), table_entry, std::move(plan), - std::move(alter_info)); -} - -BoundStatement Binder::BindAlterAddIndex(BoundStatement &result, CatalogEntry &entry, - unique_ptr alter_info) { - auto &table_info = alter_info->Cast(); - auto &constraint_info = table_info.Cast(); - auto &table = entry.Cast(); - auto &column_list = table.GetColumns(); - - auto bound_constraint = BindUniqueConstraint(*constraint_info.constraint, table_info.name, column_list); - auto &bound_unique = bound_constraint->Cast(); - - // Create the CreateIndexInfo. - auto create_index_info = make_uniq(); - create_index_info->table = table_info.name; - create_index_info->index_type = ART::TYPE_NAME; - create_index_info->constraint_type = IndexConstraintType::PRIMARY; +//! This file contains the binder definitions for statements that do not need to be bound at all and only require a +//! straightforward conversion - for (const auto &physical_index : bound_unique.keys) { - auto &col = column_list.GetColumn(physical_index); - unique_ptr parsed = make_uniq(col.GetName(), table_info.name); - create_index_info->expressions.push_back(parsed->Copy()); - create_index_info->parsed_expressions.push_back(parsed->Copy()); - } - - auto unique_constraint = constraint_info.constraint->Cast(); - auto index_name = unique_constraint.GetName(table_info.name); - create_index_info->index_name = index_name; - D_ASSERT(!create_index_info->index_name.empty()); - - // Plan the table scan. - TableDescription table_description(table_info.catalog, table_info.schema, table_info.name); - auto table_ref = make_uniq(table_description); - auto bound_table = Bind(*table_ref); - if (bound_table->type != TableReferenceType::BASE_TABLE) { - throw BinderException("can only add an index to a base table"); - } - auto plan = CreatePlan(*bound_table); - auto &get = plan->Cast(); - get.names = column_list.GetColumnNames(); - - auto alter_table_info = unique_ptr_cast(std::move(alter_info)); - result.plan = table.catalog.BindAlterAddIndex(*this, table, std::move(plan), std::move(create_index_info), - std::move(alter_table_info)); - return std::move(result); -} +namespace duckdb { BoundStatement Binder::Bind(AlterStatement &stmt) { BoundStatement result; result.names = {"Success"}; result.types = {LogicalType::BOOLEAN}; + BindSchemaOrCatalog(stmt.info->catalog, stmt.info->schema); optional_ptr entry; if (stmt.info->type == AlterType::SET_COLUMN_COMMENT) { - // Extra step for column comments: They can alter a table or a view, and we resolve that here. + // for column comments we need to an extra step: they can alter a table or a view, we resolve that here. auto &info = stmt.info->Cast(); entry = info.TryResolveCatalogEntry(entry_retriever); - } else { - // For any other ALTER, we retrieve the catalog entry directly. + // All other AlterTypes entry = entry_retriever.GetEntry(stmt.info->GetCatalogType(), stmt.info->catalog, stmt.info->schema, stmt.info->name, stmt.info->if_not_found); } auto &properties = GetStatementProperties(); - properties.return_type = StatementReturnType::NOTHING; - if (!entry) { - result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); - return result; - } - - D_ASSERT(!entry->deleted); - auto &catalog = entry->ParentCatalog(); - if (catalog.IsSystemCatalog()) { - throw BinderException("Can not comment on System Catalog entries"); + if (entry) { + D_ASSERT(!entry->deleted); + auto &catalog = entry->ParentCatalog(); + if (catalog.IsSystemCatalog()) { + throw BinderException("Can not comment on System Catalog entries"); + } + if (!entry->temporary) { + // we can only alter temporary tables/views in read-only mode + properties.RegisterDBModify(catalog, context); + } + stmt.info->catalog = catalog.GetName(); + stmt.info->schema = entry->ParentSchema().name; } - if (!entry->temporary) { - // We can only alter temporary tables and views in read-only mode. - properties.RegisterDBModify(catalog, context); - } - stmt.info->catalog = catalog.GetName(); - stmt.info->schema = entry->ParentSchema().name; - - if (!stmt.info->IsAddPrimaryKey()) { - result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); - return result; - } - - return BindAlterAddIndex(result, *entry, std::move(stmt.info)); + result.plan = make_uniq(LogicalOperatorType::LOGICAL_ALTER, std::move(stmt.info)); + properties.return_type = StatementReturnType::NOTHING; + return result; } BoundStatement Binder::Bind(TransactionStatement &stmt) { auto &properties = GetStatementProperties(); - - // Transaction statements do not require a valid transaction. + // transaction statements do not require a valid transaction properties.requires_valid_transaction = stmt.info->type == TransactionType::BEGIN_TRANSACTION; BoundStatement result; diff --git a/src/duckdb/src/planner/binder/statement/bind_summarize.cpp b/src/duckdb/src/planner/binder/statement/bind_summarize.cpp index b5c87e1ad..dac43d8f7 100644 --- a/src/duckdb/src/planner/binder/statement/bind_summarize.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_summarize.cpp @@ -19,7 +19,7 @@ static unique_ptr SummarizeWrapUnnest(vector> unnest_children; unnest_children.push_back(std::move(list_function)); auto unnest_function = make_uniq("unnest", std::move(unnest_children)); - unnest_function->SetAlias(alias); + unnest_function->alias = alias; return std::move(unnest_function); } diff --git a/src/duckdb/src/planner/binder/statement/bind_update.cpp b/src/duckdb/src/planner/binder/statement/bind_update.cpp index 75dd39074..4e27e1610 100644 --- a/src/duckdb/src/planner/binder/statement/bind_update.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_update.cpp @@ -43,7 +43,7 @@ unique_ptr Binder::BindUpdateSet(LogicalOperator &op, unique_pt throw BinderException("Multiple assignments to same column \"%s\"", colname); } columns.push_back(column.Physical()); - if (expr->GetExpressionType() == ExpressionType::VALUE_DEFAULT) { + if (expr->type == ExpressionType::VALUE_DEFAULT) { op.expressions.push_back(make_uniq(column.Type())); } else { UpdateBinder binder(*this, context); @@ -106,9 +106,7 @@ BoundStatement Binder::Bind(UpdateStatement &stmt) { update->return_chunk = true; } // bind the default values - auto &catalog_name = table.ParentCatalog().GetName(); - auto &schema_name = table.ParentSchema().name; - BindDefaultValues(table.GetColumns(), update->bound_defaults, catalog_name, schema_name); + BindDefaultValues(table.GetColumns(), update->bound_defaults); update->bound_constraints = BindConstraints(table); // project any additional columns required for the condition/expressions @@ -135,7 +133,7 @@ BoundStatement Binder::Bind(UpdateStatement &stmt) { // finally add the row id column to the projection list auto &column_ids = get->GetColumnIds(); proj->expressions.push_back( - make_uniq(table.GetRowIdType(), ColumnBinding(get->table_index, column_ids.size()))); + make_uniq(LogicalType::ROW_TYPE, ColumnBinding(get->table_index, column_ids.size()))); get->AddColumnId(COLUMN_IDENTIFIER_ROW_ID); // set the projection as child of the update node and finalize the result diff --git a/src/duckdb/src/planner/binder/statement/bind_vacuum.cpp b/src/duckdb/src/planner/binder/statement/bind_vacuum.cpp index 93e70fe5b..6ef9446e8 100644 --- a/src/duckdb/src/planner/binder/statement/bind_vacuum.cpp +++ b/src/duckdb/src/planner/binder/statement/bind_vacuum.cpp @@ -27,9 +27,8 @@ void Binder::BindVacuumTable(LogicalVacuum &vacuum, unique_ptr auto &columns = info.columns; if (columns.empty()) { // Empty means ALL columns should be vacuumed/analyzed - for (auto &col : table.GetColumns().Physical()) { - columns.push_back(col.GetName()); - } + auto &get = ref->get->Cast(); + columns.insert(columns.end(), get.names.begin(), get.names.end()); } case_insensitive_set_t column_name_set; @@ -46,9 +45,7 @@ void Binder::BindVacuumTable(LogicalVacuum &vacuum, unique_ptr auto &col = table.GetColumn(col_name); // ignore generated column if (col.Generated()) { - throw BinderException( - "cannot vacuum or analyze generated column \"%s\" - specify non-generated columns to vacuum or analyze", - col.GetName()); + continue; } non_generated_column_names.push_back(col_name); ColumnRefExpression colref(col_name, table.name); @@ -59,6 +56,8 @@ void Binder::BindVacuumTable(LogicalVacuum &vacuum, unique_ptr select_list.push_back(std::move(result.expression)); } info.columns = std::move(non_generated_column_names); + // Creating a table without any physical columns is not supported + D_ASSERT(!select_list.empty()); auto table_scan = CreatePlan(*ref); D_ASSERT(table_scan->type == LogicalOperatorType::LOGICAL_GET); @@ -69,7 +68,7 @@ void Binder::BindVacuumTable(LogicalVacuum &vacuum, unique_ptr D_ASSERT(select_list.size() == column_ids.size()); D_ASSERT(info.columns.size() == column_ids.size()); for (idx_t i = 0; i < column_ids.size(); i++) { - vacuum.column_id_map[i] = table.GetColumns().LogicalToPhysical(column_ids[i].ToLogical()).index; + vacuum.column_id_map[i] = table.GetColumns().LogicalToPhysical(LogicalIndex(column_ids[i])).index; } auto projection = make_uniq(GenerateTableIndex(), std::move(select_list)); diff --git a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp index f2566cf71..40f2662d4 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_basetableref.cpp @@ -15,7 +15,6 @@ #include "duckdb/planner/tableref/bound_cteref.hpp" #include "duckdb/planner/tableref/bound_dummytableref.hpp" #include "duckdb/planner/tableref/bound_subqueryref.hpp" -#include "duckdb/catalog/catalog_search_path.hpp" namespace duckdb { @@ -203,17 +202,6 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { return replacement_scan_bind_result; } } - auto &config = DBConfig::GetConfig(context); - if (context.config.use_replacement_scans && config.options.enable_external_access && - ExtensionHelper::IsFullPath(full_path)) { - auto &fs = FileSystem::GetFileSystem(context); - if (fs.FileExists(full_path)) { - throw BinderException( - "No extension found that is capable of reading the file \"%s\"\n* If this file is a supported file " - "format you can explicitly use the reader functions, such as read_csv, read_json or read_parquet", - full_path); - } - } // could not find an alternative: bind again to get the error (void)entry_retriever.GetEntry(CatalogType::TABLE_ENTRY, ref.catalog_name, ref.schema_name, ref.table_name, @@ -232,6 +220,7 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { unique_ptr bind_data; auto scan_function = table.GetScanFunction(context, bind_data); + auto alias = ref.alias.empty() ? ref.table_name : ref.alias; // TODO: bundle the type and name vector in a struct (e.g PackedColumnMetadata) vector table_types; vector table_names; @@ -245,18 +234,12 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { return_types.push_back(col.Type()); return_names.push_back(col.Name()); } - table_names = BindContext::AliasColumnNames(ref.table_name, table_names, ref.column_name_alias); + table_names = BindContext::AliasColumnNames(alias, table_names, ref.column_name_alias); - auto logical_get = - make_uniq(table_index, scan_function, std::move(bind_data), std::move(return_types), - std::move(return_names), table.GetRowIdType()); - auto table_entry = logical_get->GetTable(); - auto &col_ids = logical_get->GetMutableColumnIds(); - if (!table_entry) { - bind_context.AddBaseTable(table_index, ref.alias, table_names, table_types, col_ids, ref.table_name); - } else { - bind_context.AddBaseTable(table_index, ref.alias, table_names, table_types, col_ids, *table_entry); - } + auto logical_get = make_uniq(table_index, scan_function, std::move(bind_data), + std::move(return_types), std::move(return_names)); + bind_context.AddBaseTable(table_index, alias, table_names, table_types, logical_get->GetMutableColumnIds(), + logical_get->GetTable().get()); return make_uniq_base(table, std::move(logical_get)); } case CatalogType::VIEW_ENTRY: { @@ -268,24 +251,14 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { auto view_binder = Binder::CreateBinder(context, this, BinderType::VIEW_BINDER); view_binder->can_contain_nulls = true; SubqueryRef subquery(unique_ptr_cast(view_catalog_entry.query->Copy())); - subquery.alias = ref.alias; + subquery.alias = ref.alias.empty() ? ref.table_name : ref.alias; // construct view names by first (1) taking the view aliases, (2) adding the view names, then (3) applying // subquery aliases vector view_names = view_catalog_entry.aliases; for (idx_t n = view_names.size(); n < view_catalog_entry.names.size(); n++) { view_names.push_back(view_catalog_entry.names[n]); } - subquery.column_name_alias = BindContext::AliasColumnNames(ref.table_name, view_names, ref.column_name_alias); - - // when binding a view, we always look into the catalog/schema where the view is stored first - vector view_search_path; - auto &catalog_name = view_catalog_entry.ParentCatalog().GetName(); - auto &schema_name = view_catalog_entry.ParentSchema().name; - view_search_path.emplace_back(catalog_name, schema_name); - if (schema_name != DEFAULT_SCHEMA) { - view_search_path.emplace_back(view_catalog_entry.ParentCatalog().GetName(), DEFAULT_SCHEMA); - } - view_binder->entry_retriever.SetSearchPath(std::move(view_search_path)); + subquery.column_name_alias = BindContext::AliasColumnNames(subquery.alias, view_names, ref.column_name_alias); // bind the child subquery view_binder->AddBoundView(view_catalog_entry); auto bound_child = view_binder->Bind(subquery); @@ -314,7 +287,7 @@ unique_ptr Binder::Bind(BaseTableRef &ref) { } } bind_context.AddView(bound_subquery.subquery->GetRootIndex(), subquery.alias, subquery, - *bound_subquery.subquery, view_catalog_entry); + *bound_subquery.subquery, &view_catalog_entry); return bound_child; } default: diff --git a/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp b/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp index 257e275be..c07c6424f 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp @@ -15,7 +15,7 @@ namespace duckdb { -static unique_ptr BindColumn(Binder &binder, ClientContext &context, const BindingAlias &alias, +static unique_ptr BindColumn(Binder &binder, ClientContext &context, const string &alias, const string &column_name) { auto expr = make_uniq_base(column_name, alias); ExpressionBinder expr_binder(binder, context); @@ -24,7 +24,7 @@ static unique_ptr BindColumn(Binder &binder, ClientContext &co } static unique_ptr AddCondition(ClientContext &context, Binder &left_binder, Binder &right_binder, - const BindingAlias &left_alias, const BindingAlias &right_alias, + const string &left_alias, const string &right_alias, const string &column_name, ExpressionType type) { ExpressionBinder expr_binder(left_binder, context); auto left = BindColumn(left_binder, context, left_alias, column_name); @@ -32,7 +32,7 @@ static unique_ptr AddCondition(ClientContext &context, Binder return make_uniq(type, std::move(left), std::move(right)); } -bool Binder::TryFindBinding(const string &using_column, const string &join_side, BindingAlias &result) { +bool Binder::TryFindBinding(const string &using_column, const string &join_side, string &result) { // for each using column, get the matching binding auto bindings = bind_context.GetMatchingBindings(using_column); if (bindings.empty()) { @@ -40,48 +40,46 @@ bool Binder::TryFindBinding(const string &using_column, const string &join_side, } // find the join binding for (auto &binding : bindings) { - if (result.IsSet()) { + if (!result.empty()) { string error = "Column name \""; error += using_column; error += "\" is ambiguous: it exists more than once on "; error += join_side; error += " side of join.\nCandidates:"; - for (auto &binding_ref : bindings) { - auto &other_binding = binding_ref.get(); + for (auto &binding : bindings) { error += "\n\t"; - error += other_binding.GetAlias(); + error += binding; error += "."; - error += bind_context.GetActualColumnName(other_binding, using_column); + error += bind_context.GetActualColumnName(binding, using_column); } throw BinderException(error); } else { - result = binding.get().alias; + result = binding; } } return true; } -BindingAlias Binder::FindBinding(const string &using_column, const string &join_side) { - BindingAlias result; +string Binder::FindBinding(const string &using_column, const string &join_side) { + string result; if (!TryFindBinding(using_column, join_side, result)) { throw BinderException("Column \"%s\" does not exist on %s side of join!", using_column, join_side); } return result; } -static void AddUsingBindings(UsingColumnSet &set, optional_ptr input_set, - const BindingAlias &input_binding) { +static void AddUsingBindings(UsingColumnSet &set, optional_ptr input_set, const string &input_binding) { if (input_set) { for (auto &entry : input_set->bindings) { - set.bindings.push_back(entry); + set.bindings.insert(entry); } } else { - set.bindings.push_back(input_binding); + set.bindings.insert(input_binding); } } -static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const BindingAlias &left_binding, - const BindingAlias &right_binding) { +static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const string &left_binding, + const string &right_binding) { switch (join_type) { case JoinType::LEFT: case JoinType::INNER: @@ -99,9 +97,9 @@ static void SetPrimaryBinding(UsingColumnSet &set, JoinType join_type, const Bin } } -BindingAlias Binder::RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, - const string &using_column, const string &join_side) { - BindingAlias binding; +string Binder::RetrieveUsingBinding(Binder ¤t_binder, optional_ptr current_set, + const string &using_column, const string &join_side) { + string binding; if (!current_set) { binding = current_binder.FindBinding(using_column, join_side); } else { @@ -188,7 +186,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { case_insensitive_set_t lhs_columns; auto &lhs_binding_list = left_binder.bind_context.GetBindingsList(); for (auto &binding : lhs_binding_list) { - for (auto &column_name : binding->names) { + for (auto &column_name : binding.get().names) { lhs_columns.insert(column_name); } } @@ -196,7 +194,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { for (auto &column_name : lhs_columns) { auto right_using_binding = right_binder.bind_context.GetUsingBinding(column_name); - BindingAlias right_binding; + string right_binding; // loop over the set of lhs columns, and figure out if there is a table in the rhs with the same name if (!right_using_binding) { if (!right_binder.TryFindBinding(column_name, "right", right_binding)) { @@ -214,21 +212,21 @@ unique_ptr Binder::Bind(JoinRef &ref) { string left_candidates, right_candidates; auto &rhs_binding_list = right_binder.bind_context.GetBindingsList(); for (auto &binding_ref : lhs_binding_list) { - auto &binding = *binding_ref; + auto &binding = binding_ref.get(); for (auto &column_name : binding.names) { if (!left_candidates.empty()) { left_candidates += ", "; } - left_candidates += binding.GetAlias() + "." + column_name; + left_candidates += binding.alias + "." + column_name; } } for (auto &binding_ref : rhs_binding_list) { - auto &binding = *binding_ref; + auto &binding = binding_ref.get(); for (auto &column_name : binding.names) { if (!right_candidates.empty()) { right_candidates += ", "; } - right_candidates += binding.GetAlias() + "." + column_name; + right_candidates += binding.alias + "." + column_name; } } error_msg += "\n Left candidates: " + left_candidates; @@ -275,8 +273,8 @@ unique_ptr Binder::Bind(JoinRef &ref) { for (idx_t i = 0; i < extra_using_columns.size(); i++) { auto &using_column = extra_using_columns[i]; - BindingAlias left_binding; - BindingAlias right_binding; + string left_binding; + string right_binding; auto set = make_uniq(); auto &left_using_binding = left_using_bindings[i]; @@ -295,14 +293,16 @@ unique_ptr Binder::Bind(JoinRef &ref) { AddUsingBindings(*set, left_using_binding, left_binding); AddUsingBindings(*set, right_using_binding, right_binding); SetPrimaryBinding(*set, ref.type, left_binding, right_binding); - bind_context.TransferUsingBinding(left_binder.bind_context, left_using_binding, *set, using_column); - bind_context.TransferUsingBinding(right_binder.bind_context, right_using_binding, *set, using_column); + bind_context.TransferUsingBinding(left_binder.bind_context, left_using_binding, *set, left_binding, + using_column); + bind_context.TransferUsingBinding(right_binder.bind_context, right_using_binding, *set, right_binding, + using_column); AddUsingBindingSet(std::move(set)); } } - auto right_bindings = right_binder.bind_context.GetBindingAliases(); - auto left_bindings = left_binder.bind_context.GetBindingAliases(); + auto right_bindings_list_copy = right_binder.bind_context.GetBindingsList(); + auto left_bindings_list_copy = left_binder.bind_context.GetBindingsList(); bind_context.AddContext(std::move(left_binder.bind_context)); bind_context.AddContext(std::move(right_binder.bind_context)); @@ -338,7 +338,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { } if (result->type == JoinType::SEMI || result->type == JoinType::ANTI || result->type == JoinType::MARK) { - bind_context.RemoveContext(right_bindings); + bind_context.RemoveContext(right_bindings_list_copy); if (result->type == JoinType::MARK) { auto mark_join_idx = GenerateTableIndex(); string mark_join_alias = "__internal_mark_join_ref" + to_string(mark_join_idx); @@ -348,7 +348,7 @@ unique_ptr Binder::Bind(JoinRef &ref) { } } if (result->type == JoinType::RIGHT_SEMI || result->type == JoinType::RIGHT_ANTI) { - bind_context.RemoveContext(left_bindings); + bind_context.RemoveContext(left_bindings_list_copy); } return std::move(result); diff --git a/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp b/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp index 3899ecdd6..174698558 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp @@ -58,7 +58,7 @@ static void ConstructPivots(PivotRef &ref, vector &pivot_valu } static void ExtractPivotExpressions(ParsedExpression &expr, case_insensitive_set_t &handled_columns) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &child_colref = expr.Cast(); if (child_colref.IsQualified()) { throw BinderException("PIVOT expression cannot contain qualified columns"); @@ -69,27 +69,6 @@ static void ExtractPivotExpressions(ParsedExpression &expr, case_insensitive_set expr, [&](ParsedExpression &child) { ExtractPivotExpressions(child, handled_columns); }); } -void ExtractPivotAggregateExpression(ClientContext &context, ParsedExpression &expr, - vector> &aggregates) { - if (expr.GetExpressionType() == ExpressionType::FUNCTION) { - auto &aggr_function = expr.Cast(); - - // check if this is an aggregate to ensure it is an aggregate and not a scalar function - auto &entry = Catalog::GetEntry(context, CatalogType::SCALAR_FUNCTION_ENTRY, aggr_function.catalog, - aggr_function.schema, aggr_function.function_name); - if (entry.type == CatalogType::AGGREGATE_FUNCTION_ENTRY) { - // aggregate - aggregates.push_back(aggr_function); - return; - } - } - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { - throw BinderException(expr, "Columns can only be referenced within the aggregate of a PIVOT expression"); - } - ParsedExpressionIterator::EnumerateChildren( - expr, [&](ParsedExpression &child) { ExtractPivotAggregateExpression(context, child, aggregates); }); -} - static unique_ptr ConstructInitialGrouping(PivotRef &ref, vector> all_columns, const case_insensitive_set_t &handled_columns) { auto subquery = make_uniq(); @@ -97,11 +76,10 @@ static unique_ptr ConstructInitialGrouping(PivotRef &ref, vectortype != ExpressionType::COLUMN_REF) { throw InternalException("Unexpected child of pivot source - not a ColumnRef"); } - auto &columnref = column_entry->Cast(); + auto &columnref = entry->Cast(); if (handled_columns.find(columnref.GetColumnName()) == handled_columns.end()) { // not handled - add to grouping set subquery->groups.group_expressions.push_back(make_uniq( @@ -120,8 +98,7 @@ static unique_ptr ConstructInitialGrouping(PivotRef &ref, vector PivotFilteredAggregate(ClientContext &context, PivotRef &ref, - vector> all_columns, +static unique_ptr PivotFilteredAggregate(PivotRef &ref, vector> all_columns, const case_insensitive_set_t &handled_columns, vector pivot_values) { auto subquery = ConstructInitialGrouping(ref, std::move(all_columns), handled_columns); @@ -147,20 +124,15 @@ static unique_ptr PivotFilteredAggregate(ClientContext &context, Piv } for (auto &aggregate : ref.aggregates) { auto copied_aggr = aggregate->Copy(); - - vector> aggregates; - ExtractPivotAggregateExpression(context, *copied_aggr, aggregates); - D_ASSERT(aggregates.size() == 1); - - auto &aggr = aggregates[0].get().Cast(); + auto &aggr = copied_aggr->Cast(); aggr.filter = filter->Copy(); - auto &aggr_name = aggregate->GetAlias(); + auto &aggr_name = aggregate->alias; auto name = pivot_value.name; if (ref.aggregates.size() > 1 || !aggr_name.empty()) { // if there are multiple aggregates specified we add the name of the aggregate as well name += "_" + (aggr_name.empty() ? aggregate->GetName() : aggr_name); } - copied_aggr->SetAlias(name); + aggr.alias = name; subquery->select_list.push_back(std::move(copied_aggr)); } } @@ -182,19 +154,19 @@ static unique_ptr PivotInitialAggregate(PivotBindState &bind_state, idx_t group_count = 0; for (auto &expr : subquery_stage1->select_list) { bind_state.group_names.push_back(expr->GetName()); - if (expr->GetAlias().empty()) { - expr->SetAlias("__internal_pivot_group" + std::to_string(++group_count)); + if (expr->alias.empty()) { + expr->alias = "__internal_pivot_group" + std::to_string(++group_count); } - bind_state.internal_group_names.push_back(expr->GetAlias()); + bind_state.internal_group_names.push_back(expr->alias); } // group by all of the pivot values idx_t pivot_count = 0; for (auto &pivot_column : ref.pivots) { for (auto &pivot_expr : pivot_column.pivot_expressions) { - if (pivot_expr->GetAlias().empty()) { - pivot_expr->SetAlias("__internal_pivot_ref" + std::to_string(++pivot_count)); + if (pivot_expr->alias.empty()) { + pivot_expr->alias = "__internal_pivot_ref" + std::to_string(++pivot_count); } - auto pivot_alias = pivot_expr->GetAlias(); + auto pivot_alias = pivot_expr->alias; subquery_stage1->groups.group_expressions.push_back(make_uniq( Value::INTEGER(UnsafeNumericCast(subquery_stage1->select_list.size() + 1)))); subquery_stage1->select_list.push_back(std::move(pivot_expr)); @@ -205,9 +177,9 @@ static unique_ptr PivotInitialAggregate(PivotBindState &bind_state, // finally add the aggregates for (auto &aggregate : ref.aggregates) { auto aggregate_alias = "__internal_pivot_aggregate" + std::to_string(++aggregate_count); - bind_state.aggregate_names.push_back(aggregate->GetAlias()); + bind_state.aggregate_names.push_back(aggregate->alias); bind_state.internal_aggregate_names.push_back(aggregate_alias); - aggregate->SetAlias(std::move(aggregate_alias)); + aggregate->alias = std::move(aggregate_alias); subquery_stage1->select_list.push_back(std::move(aggregate)); } return subquery_stage1; @@ -235,7 +207,7 @@ static unique_ptr PivotListAggregate(PivotBindState &bind_state, Piv subquery_stage2->groups.group_expressions.push_back(make_uniq( Value::INTEGER(UnsafeNumericCast(subquery_stage2->select_list.size() + 1)))); auto group_reference = make_uniq(bind_state.internal_group_names[gr]); - group_reference->SetAlias(bind_state.internal_group_names[gr]); + group_reference->alias = bind_state.internal_group_names[gr]; subquery_stage2->select_list.push_back(std::move(group_reference)); } @@ -245,7 +217,7 @@ static unique_ptr PivotListAggregate(PivotBindState &bind_state, Piv vector> list_children; list_children.push_back(std::move(colref)); auto aggregate = make_uniq("list", std::move(list_children)); - aggregate->SetAlias(bind_state.internal_aggregate_names[aggr]); + aggregate->alias = bind_state.internal_aggregate_names[aggr]; subquery_stage2->select_list.push_back(std::move(aggregate)); } // construct the pivot list @@ -273,7 +245,7 @@ static unique_ptr PivotListAggregate(PivotBindState &bind_state, Piv list_children.push_back(std::move(expr)); auto aggregate = make_uniq("list", std::move(list_children)); - aggregate->SetAlias(pivot_name); + aggregate->alias = pivot_name; subquery_stage2->select_list.push_back(std::move(aggregate)); subquery_stage2->from_table = std::move(subquery_ref); @@ -318,7 +290,7 @@ void ExtractPivotAggregates(BoundTableRef &node, vector> } auto &select2 = subq2.subquery->Cast(); for (auto &aggr : select2.aggregates) { - if (aggr->GetAlias() == "__collated_group") { + if (aggr->alias == "__collated_group") { continue; } aggregates.push_back(aggr->Copy()); @@ -388,27 +360,22 @@ unique_ptr Binder::BindPivot(PivotRef &ref, vector> pivot_aggregates; // parse the aggregate, and extract the referenced columns from the aggregate for (auto &aggr : ref.aggregates) { + if (aggr->type != ExpressionType::FUNCTION) { + throw BinderException(*aggr, "Pivot expression must be an aggregate"); + } if (aggr->HasSubquery()) { throw BinderException(*aggr, "Pivot expression cannot contain subqueries"); } if (aggr->IsWindow()) { throw BinderException(*aggr, "Pivot expression cannot contain window functions"); } - idx_t aggregate_count = pivot_aggregates.size(); - ExtractPivotAggregateExpression(context, *aggr, pivot_aggregates); - if (pivot_aggregates.size() != aggregate_count + 1) { - string error_str = pivot_aggregates.size() == aggregate_count - ? "but no aggregates were found" - : "but " + to_string(pivot_aggregates.size() - aggregate_count) + " were found"; - throw BinderException(*aggr, "Pivot expression must contain exactly one aggregate, %s", error_str); - } - } - for (auto &aggr : pivot_aggregates) { - ExtractPivotExpressions(aggr.get(), handled_columns); + // bind the function as an aggregate to ensure it is an aggregate and not a scalar function + auto &aggr_function = aggr->Cast(); + (void)Catalog::GetEntry(context, aggr_function.catalog, aggr_function.schema, + aggr_function.function_name); + ExtractPivotExpressions(*aggr, handled_columns); } // first add all pivots to the set of handled columns, and check for duplicates @@ -422,9 +389,6 @@ unique_ptr Binder::BindPivot(PivotRef &ref, vector Binder::BindPivot(PivotRef &ref, vectorGetAlias().empty()) { - unpivot_entry.alias = expr->GetAlias(); + if (!expr->alias.empty()) { + unpivot_entry.alias = std::move(expr->alias); } unpivot_entry.expressions.push_back(std::move(expr)); unpivot_entries.push_back(std::move(unpivot_entry)); @@ -549,12 +512,12 @@ void Binder::ExtractUnpivotEntries(Binder &child_binder, PivotColumnEntry &entry } void Binder::ExtractUnpivotColumnName(ParsedExpression &expr, vector &result) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); result.push_back(colref.GetColumnName()); return; } - if (expr.GetExpressionType() == ExpressionType::SUBQUERY) { + if (expr.type == ExpressionType::SUBQUERY) { throw BinderException(expr, "UNPIVOT list cannot contain subqueries"); } ParsedExpressionIterator::EnumerateChildren( @@ -607,7 +570,7 @@ unique_ptr Binder::BindUnpivot(Binder &child_binder, PivotRef &ref, } for (auto &col_expr : all_columns) { - if (col_expr->GetExpressionType() != ExpressionType::COLUMN_REF) { + if (col_expr->type != ExpressionType::COLUMN_REF) { throw InternalException("Unexpected child of pivot source - not a ColumnRef"); } auto &columnref = col_expr->Cast(); @@ -668,7 +631,7 @@ unique_ptr Binder::BindUnpivot(Binder &child_binder, PivotRef &ref, vector> unnest_name_children; unnest_name_children.push_back(std::move(unpivot_name_expr)); auto unnest_name_expr = make_uniq("unnest", std::move(unnest_name_children)); - unnest_name_expr->SetAlias(unpivot.unpivot_names[0]); + unnest_name_expr->alias = unpivot.unpivot_names[0]; select_node->select_list.push_back(std::move(unnest_name_expr)); // construct the UNNEST expression for the set of unpivoted columns @@ -682,7 +645,7 @@ unique_ptr Binder::BindUnpivot(Binder &child_binder, PivotRef &ref, unnest_val_children.push_back(std::move(list_expr)); auto unnest_val_expr = make_uniq("unnest", std::move(unnest_val_children)); auto unnest_name = i < ref.column_name_alias.size() ? ref.column_name_alias[i] : ref.unpivot_names[i]; - unnest_val_expr->SetAlias(unnest_name); + unnest_val_expr->alias = unnest_name; select_node->select_list.push_back(std::move(unnest_val_expr)); if (!ref.include_nulls) { // if we are running with EXCLUDE NULLS we need to add an IS NOT NULL filter diff --git a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp index d61b98f67..9af266be4 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_showref.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_showref.cpp @@ -1,86 +1,13 @@ +#include "duckdb/planner/binder.hpp" +#include "duckdb/parser/tableref/showref.hpp" +#include "duckdb/planner/tableref/bound_table_function.hpp" +#include "duckdb/planner/operator/logical_column_data_get.hpp" #include "duckdb/function/pragma/pragma_functions.hpp" -#include "duckdb/function/table/system_functions.hpp" #include "duckdb/parser/parsed_data/create_view_info.hpp" -#include "duckdb/parser/tableref/showref.hpp" #include "duckdb/parser/tableref/subqueryref.hpp" -#include "duckdb/planner/binder.hpp" -#include "duckdb/planner/operator/logical_column_data_get.hpp" -#include "duckdb/planner/tableref/bound_table_function.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/planner/operator/logical_projection.hpp" -#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" namespace duckdb { -struct BaseTableColumnInfo { - optional_ptr table; - optional_ptr column; -}; - -BaseTableColumnInfo FindBaseTableColumn(LogicalOperator &op, ColumnBinding binding) { - BaseTableColumnInfo result; - switch (op.type) { - case LogicalOperatorType::LOGICAL_GET: { - auto &get = op.Cast(); - if (get.table_index != binding.table_index) { - return result; - } - auto table = get.GetTable(); - if (!table) { - break; - } - if (!get.projection_ids.empty()) { - throw InternalException("Projection ids should not exist here"); - } - result.table = table; - auto base_column_id = get.GetColumnIds()[binding.column_index]; - result.column = &table->GetColumn(LogicalIndex(base_column_id.GetPrimaryIndex())); - return result; - } - case LogicalOperatorType::LOGICAL_PROJECTION: { - auto &projection = op.Cast(); - if (binding.table_index != projection.table_index) { - break; - } - auto &expr = projection.expressions[binding.column_index]; - if (expr->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { - // if the projection at this index only has a column reference we can directly trace it to the base table - auto &bound_colref = expr->Cast(); - return FindBaseTableColumn(*projection.children[0], bound_colref.binding); - } - break; - } - case LogicalOperatorType::LOGICAL_LIMIT: - case LogicalOperatorType::LOGICAL_ORDER_BY: - case LogicalOperatorType::LOGICAL_TOP_N: - case LogicalOperatorType::LOGICAL_SAMPLE: - case LogicalOperatorType::LOGICAL_DISTINCT: - case LogicalOperatorType::LOGICAL_FILTER: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - case LogicalOperatorType::LOGICAL_JOIN: - case LogicalOperatorType::LOGICAL_ANY_JOIN: - case LogicalOperatorType::LOGICAL_ASOF_JOIN: - case LogicalOperatorType::LOGICAL_CROSS_PRODUCT: - // for any "pass-through" operators - search in children directly - for (auto &child : op.children) { - result = FindBaseTableColumn(*child, binding); - if (result.table) { - return result; - } - } - break; - default: - // unsupported operator - break; - } - return result; -} - -BaseTableColumnInfo FindBaseTableColumn(LogicalOperator &op, idx_t column_index) { - auto bindings = op.GetColumnBindings(); - return FindBaseTableColumn(op, bindings[column_index]); -} - unique_ptr Binder::BindShowQuery(ShowRef &ref) { // bind the child plan of the DESCRIBE statement auto child_binder = Binder::CreateBinder(context, this); @@ -97,29 +24,21 @@ unique_ptr Binder::BindShowQuery(ShowRef &ref) { ColumnDataAppendState append_state; collection->InitializeAppend(append_state); for (idx_t column_idx = 0; column_idx < plan.types.size(); column_idx++) { - // check if we can trace the column to a base table so that we can figure out constraint information - auto result = FindBaseTableColumn(*plan.plan, column_idx); - if (result.table) { - // we can! emit the information from the base table directly - PragmaTableInfo::GetColumnInfo(*result.table, *result.column, output, output.size()); - } else { - // we cannot - read the type/name from the plan instead - auto type = plan.types[column_idx]; - auto &name = plan.names[column_idx]; + auto type = plan.types[column_idx]; + auto &name = plan.names[column_idx]; - // "name", TypeId::VARCHAR - output.SetValue(0, output.size(), Value(name)); - // "type", TypeId::VARCHAR - output.SetValue(1, output.size(), Value(type.ToString())); - // "null", TypeId::VARCHAR - output.SetValue(2, output.size(), Value("YES")); - // "pk", TypeId::BOOL - output.SetValue(3, output.size(), Value()); - // "dflt_value", TypeId::VARCHAR - output.SetValue(4, output.size(), Value()); - // "extra", TypeId::VARCHAR - output.SetValue(5, output.size(), Value()); - } + // "name", TypeId::VARCHAR + output.SetValue(0, output.size(), Value(name)); + // "type", TypeId::VARCHAR + output.SetValue(1, output.size(), Value(type.ToString())); + // "null", TypeId::VARCHAR + output.SetValue(2, output.size(), Value("YES")); + // "pk", TypeId::BOOL + output.SetValue(3, output.size(), Value()); + // "dflt_value", TypeId::VARCHAR + output.SetValue(4, output.size(), Value()); + // "extra", TypeId::VARCHAR + output.SetValue(5, output.size(), Value()); output.SetCardinality(output.size() + 1); if (output.size() == STANDARD_VECTOR_SIZE) { diff --git a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp index 3f4c249bd..79972fefb 100644 --- a/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp +++ b/src/duckdb/src/planner/binder/tableref/bind_table_function.cpp @@ -108,22 +108,21 @@ bool Binder::BindTableFunctionParameters(TableFunctionCatalogEntry &table_functi string parameter_name; // hack to make named parameters work - if (child->GetExpressionType() == ExpressionType::COMPARE_EQUAL) { + if (child->type == ExpressionType::COMPARE_EQUAL) { // comparison, check if the LHS is a columnref auto &comp = child->Cast(); - if (comp.left->GetExpressionType() == ExpressionType::COLUMN_REF) { + if (comp.left->type == ExpressionType::COLUMN_REF) { auto &colref = comp.left->Cast(); if (!colref.IsQualified()) { parameter_name = colref.GetColumnName(); child = std::move(comp.right); } } - } else if (!child->GetAlias().empty()) { + } else if (!child->alias.empty()) { // => will set the alias of to - parameter_name = child->GetAlias(); + parameter_name = child->alias; } - if (bind_type == TableFunctionBindType::TABLE_PARAMETER_FUNCTION && - child->GetExpressionType() == ExpressionType::SUBQUERY) { + if (bind_type == TableFunctionBindType::TABLE_PARAMETER_FUNCTION && child->type == ExpressionType::SUBQUERY) { D_ASSERT(table_function.functions.Size() == 1); auto fun = table_function.functions.GetFunctionByOffset(0); if (table_function.functions.Size() != 1 || fun.arguments.empty() || @@ -178,7 +177,7 @@ static string GetAlias(const TableFunctionRef &ref) { if (!ref.alias.empty()) { return ref.alias; } - if (ref.function && ref.function->GetExpressionType() == ExpressionType::FUNCTION) { + if (ref.function && ref.function->type == ExpressionType::FUNCTION) { auto &function_expr = ref.function->Cast(); return function_expr.function_name; } @@ -263,16 +262,12 @@ unique_ptr Binder::BindTableFunction(TableFunction &function, v unique_ptr Binder::Bind(TableFunctionRef &ref) { QueryErrorContext error_context(ref.query_location); - D_ASSERT(ref.function->GetExpressionType() == ExpressionType::FUNCTION); + D_ASSERT(ref.function->type == ExpressionType::FUNCTION); auto &fexpr = ref.function->Cast(); - string catalog = fexpr.catalog; - string schema = fexpr.schema; - Binder::BindSchemaOrCatalog(context, catalog, schema); - // fetch the function from the catalog - auto &func_catalog = *GetCatalogEntry(CatalogType::TABLE_FUNCTION_ENTRY, catalog, schema, fexpr.function_name, - OnEntryNotFound::THROW_EXCEPTION, error_context); + auto &func_catalog = *GetCatalogEntry(CatalogType::TABLE_FUNCTION_ENTRY, fexpr.catalog, fexpr.schema, + fexpr.function_name, OnEntryNotFound::THROW_EXCEPTION, error_context); if (func_catalog.type == CatalogType::TABLE_MACRO_ENTRY) { auto ¯o_func = func_catalog.Cast(); @@ -283,14 +278,7 @@ unique_ptr Binder::Bind(TableFunctionRef &ref) { binder->can_contain_nulls = true; binder->alias = ref.alias.empty() ? "unnamed_query" : ref.alias; - unique_ptr query; - try { - query = binder->BindNode(*query_node); - } catch (std::exception &ex) { - ErrorData error(ex); - error.AddQueryLocation(ref); - error.Throw(); - } + auto query = binder->BindNode(*query_node); idx_t bind_index = query->GetRootIndex(); // string alias; @@ -318,7 +306,7 @@ unique_ptr Binder::Bind(TableFunctionRef &ref) { } // select the function based on the input parameters - FunctionBinder function_binder(*this); + FunctionBinder function_binder(context); auto best_function_idx = function_binder.BindFunction(function.name, function.functions, arguments, error); if (!best_function_idx.IsValid()) { error.AddQueryLocation(ref); diff --git a/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp b/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp index aa96ff857..53c2ee8cc 100644 --- a/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp +++ b/src/duckdb/src/planner/binder/tableref/plan_joinref.cpp @@ -1,23 +1,22 @@ -#include "duckdb/execution/expression_executor.hpp" -#include "duckdb/main/client_context.hpp" -#include "duckdb/optimizer/optimizer.hpp" -#include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_columnref_expression.hpp" #include "duckdb/planner/expression/bound_comparison_expression.hpp" #include "duckdb/planner/expression/bound_conjunction_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/planner/expression/bound_subquery_expression.hpp" -#include "duckdb/planner/expression_binder/lateral_binder.hpp" #include "duckdb/planner/expression_iterator.hpp" +#include "duckdb/planner/binder.hpp" #include "duckdb/planner/operator/logical_any_join.hpp" #include "duckdb/planner/operator/logical_comparison_join.hpp" #include "duckdb/planner/operator/logical_cross_product.hpp" #include "duckdb/planner/operator/logical_dependent_join.hpp" #include "duckdb/planner/operator/logical_filter.hpp" #include "duckdb/planner/operator/logical_positional_join.hpp" -#include "duckdb/planner/subquery/recursive_dependent_join_planner.hpp" #include "duckdb/planner/tableref/bound_joinref.hpp" +#include "duckdb/main/client_context.hpp" +#include "duckdb/planner/expression_binder/lateral_binder.hpp" +#include "duckdb/planner/subquery/recursive_dependent_join_planner.hpp" +#include "duckdb/execution/expression_executor.hpp" namespace duckdb { @@ -51,13 +50,13 @@ static bool CreateJoinCondition(Expression &expr, const unordered_set &le if (left_side != JoinSide::BOTH && right_side != JoinSide::BOTH) { // join condition can be divided in a left/right side JoinCondition condition; - condition.comparison = expr.GetExpressionType(); + condition.comparison = expr.type; auto left = std::move(comparison.left); auto right = std::move(comparison.right); if (left_side == JoinSide::RIGHT) { // left = right, right = left, flip the comparison symbol and reverse sides swap(left, right); - condition.comparison = FlipComparisonExpression(expr.GetExpressionType()); + condition.comparison = FlipComparisonExpression(expr.type); } condition.left = std::move(left); condition.right = std::move(right); @@ -99,20 +98,19 @@ void LogicalComparisonJoin::ExtractJoinConditions( continue; } } - } else if (expr->GetExpressionType() == ExpressionType::COMPARE_EQUAL || - expr->GetExpressionType() == ExpressionType::COMPARE_NOTEQUAL || - expr->GetExpressionType() == ExpressionType::COMPARE_BOUNDARY_START || - expr->GetExpressionType() == ExpressionType::COMPARE_LESSTHAN || - expr->GetExpressionType() == ExpressionType::COMPARE_GREATERTHAN || - expr->GetExpressionType() == ExpressionType::COMPARE_LESSTHANOREQUALTO || - expr->GetExpressionType() == ExpressionType::COMPARE_GREATERTHANOREQUALTO || - expr->GetExpressionType() == ExpressionType::COMPARE_BOUNDARY_START || - expr->GetExpressionType() == ExpressionType::COMPARE_NOT_DISTINCT_FROM || - expr->GetExpressionType() == ExpressionType::COMPARE_DISTINCT_FROM) + } else if (expr->type == ExpressionType::COMPARE_EQUAL || expr->type == ExpressionType::COMPARE_NOTEQUAL || + expr->type == ExpressionType::COMPARE_BOUNDARY_START || + expr->type == ExpressionType::COMPARE_LESSTHAN || + expr->type == ExpressionType::COMPARE_GREATERTHAN || + expr->type == ExpressionType::COMPARE_LESSTHANOREQUALTO || + expr->type == ExpressionType::COMPARE_GREATERTHANOREQUALTO || + expr->type == ExpressionType::COMPARE_BOUNDARY_START || + expr->type == ExpressionType::COMPARE_NOT_DISTINCT_FROM || + expr->type == ExpressionType::COMPARE_DISTINCT_FROM) { // comparison, check if we can create a comparison JoinCondition - if (IsJoinTypeCondition(ref_type, expr->GetExpressionType()) && + if (IsJoinTypeCondition(ref_type, expr->type) && CreateJoinCondition(*expr, left_bindings, right_bindings, conditions)) { // successfully created the join condition continue; @@ -247,7 +245,7 @@ unique_ptr LogicalComparisonJoin::CreateJoin(ClientContext &con } static bool HasCorrelatedColumns(Expression &expression) { - if (expression.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expression.Cast(); if (colref.depth > 0) { return true; @@ -294,8 +292,7 @@ unique_ptr Binder::CreatePlan(BoundJoinRef &ref) { } if (ref.type == JoinType::RIGHT && ref.ref_type != JoinRefType::ASOF && - ClientConfig::GetConfig(context).enable_optimizer && - !Optimizer::OptimizerDisabled(context, OptimizerType::BUILD_SIDE_PROBE_SIDE)) { + ClientConfig::GetConfig(context).enable_optimizer) { // we turn any right outer joins into left outer joins for optimization purposes // they are the same but with sides flipped, so treating them the same simplifies life ref.type = JoinType::LEFT; diff --git a/src/duckdb/src/planner/binding_alias.cpp b/src/duckdb/src/planner/binding_alias.cpp deleted file mode 100644 index 62f60dfa1..000000000 --- a/src/duckdb/src/planner/binding_alias.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "duckdb/planner/binding_alias.hpp" -#include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" -#include "duckdb/catalog/catalog.hpp" - -namespace duckdb { - -BindingAlias::BindingAlias() { -} - -BindingAlias::BindingAlias(string alias_p) : alias(std::move(alias_p)) { -} - -BindingAlias::BindingAlias(string schema_p, string alias_p) : schema(std::move(schema_p)), alias(std::move(alias_p)) { -} - -BindingAlias::BindingAlias(const StandardEntry &entry) - : catalog(entry.ParentCatalog().GetName()), schema(entry.schema.name), alias(entry.name) { -} - -BindingAlias::BindingAlias(string catalog_p, string schema_p, string alias_p) - : catalog(std::move(catalog_p)), schema(std::move(schema_p)), alias(std::move(alias_p)) { -} - -bool BindingAlias::IsSet() const { - return !alias.empty(); -} - -const string &BindingAlias::GetAlias() const { - if (!IsSet()) { - throw InternalException("Calling BindingAlias::GetAlias on a non-set alias"); - } - return alias; -} - -string BindingAlias::ToString() const { - string result; - if (!catalog.empty()) { - result += KeywordHelper::WriteOptionallyQuoted(catalog) + "."; - } - if (!schema.empty()) { - result += KeywordHelper::WriteOptionallyQuoted(schema) + "."; - } - result += KeywordHelper::WriteOptionallyQuoted(alias); - return result; -} - -bool BindingAlias::Matches(const BindingAlias &other) const { - // we match based on the specificity of the other entry - // i.e. "tbl" matches "catalog.schema.tbl" - // but "schema2.tbl" does not match "schema.tbl" - if (!other.catalog.empty()) { - if (!StringUtil::CIEquals(catalog, other.catalog)) { - return false; - } - } - if (!other.schema.empty()) { - if (!StringUtil::CIEquals(schema, other.schema)) { - return false; - } - } - return StringUtil::CIEquals(alias, other.alias); -} - -bool BindingAlias::operator==(const BindingAlias &other) const { - return StringUtil::CIEquals(catalog, other.catalog) && StringUtil::CIEquals(schema, other.schema) && - StringUtil::CIEquals(alias, other.alias); -} - -} // namespace duckdb diff --git a/src/duckdb/src/planner/bound_parameter_map.cpp b/src/duckdb/src/planner/bound_parameter_map.cpp index 112a17934..aac752302 100644 --- a/src/duckdb/src/planner/bound_parameter_map.cpp +++ b/src/duckdb/src/planner/bound_parameter_map.cpp @@ -54,7 +54,7 @@ unique_ptr BoundParameterMap::BindParameterExpression( auto bound_expr = make_uniq(identifier); bound_expr->parameter_data = param_data; - bound_expr->SetAlias(expr.GetAlias()); + bound_expr->alias = expr.alias; auto param_type = param_data->return_type; auto identifier_type = GetReturnType(identifier); diff --git a/src/duckdb/src/planner/bound_result_modifier.cpp b/src/duckdb/src/planner/bound_result_modifier.cpp index 4f4706076..a4cb6ed4f 100644 --- a/src/duckdb/src/planner/bound_result_modifier.cpp +++ b/src/duckdb/src/planner/bound_result_modifier.cpp @@ -93,7 +93,7 @@ bool BoundOrderModifier::Equals(const unique_ptr &left, return BoundOrderModifier::Equals(*left, *right); } -bool BoundOrderModifier::Simplify(vector &orders, const vector> &groups) { +bool BoundOrderModifier::Simplify(const vector> &groups) { // for each ORDER BY - check if it is actually necessary // expressions that are in the groups do not need to be ORDERED BY // `ORDER BY` on a group has no effect, because for each aggregate, the group is unique @@ -113,11 +113,7 @@ bool BoundOrderModifier::Simplify(vector &orders, const vector } orders.swap(new_order_nodes); - return orders.empty(); // NOLINT -} - -bool BoundOrderModifier::Simplify(const vector> &groups) { - return Simplify(orders, groups); + return orders.empty(); } BoundLimitNode::BoundLimitNode(LimitNodeType type, idx_t constant_integer, double constant_percentage, diff --git a/src/duckdb/src/planner/collation_binding.cpp b/src/duckdb/src/planner/collation_binding.cpp index aabde7f55..d68ffc608 100644 --- a/src/duckdb/src/planner/collation_binding.cpp +++ b/src/duckdb/src/planner/collation_binding.cpp @@ -8,8 +8,7 @@ namespace duckdb { -bool PushVarcharCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type, - CollationType type) { +bool PushVarcharCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type) { if (sql_type.id() != LogicalTypeId::VARCHAR) { // only VARCHAR columns require collation return false; @@ -31,12 +30,7 @@ bool PushVarcharCollation(ClientContext &context, unique_ptr &source auto &catalog = Catalog::GetSystemCatalog(context); auto splits = StringUtil::Split(StringUtil::Lower(collation), "."); vector> entries; - unordered_set collations; for (auto &collation_argument : splits) { - if (collations.count(collation_argument)) { - // we already applied this collation - continue; - } auto &collation_entry = catalog.GetEntry(context, DEFAULT_SCHEMA, collation_argument); if (collation_entry.combinable) { entries.insert(entries.begin(), collation_entry); @@ -47,14 +41,9 @@ bool PushVarcharCollation(ClientContext &context, unique_ptr &source } entries.push_back(collation_entry); } - collations.insert(collation_argument); } for (auto &entry : entries) { auto &collation_entry = entry.get(); - if (!collation_entry.combinable && type == CollationType::COMBINABLE_COLLATIONS) { - // not a combinable collation - ignore - return false; - } vector> children; children.push_back(std::move(source)); @@ -65,8 +54,7 @@ bool PushVarcharCollation(ClientContext &context, unique_ptr &source return true; } -bool PushTimeTZCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type, - CollationType) { +bool PushTimeTZCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type) { if (sql_type.id() != LogicalTypeId::TIME_TZ) { return false; } @@ -87,32 +75,10 @@ bool PushTimeTZCollation(ClientContext &context, unique_ptr &source, return true; } -bool PushIntervalCollation(ClientContext &context, unique_ptr &source, const LogicalType &sql_type, - CollationType) { - if (sql_type.id() != LogicalTypeId::INTERVAL) { - return false; - } - - auto &catalog = Catalog::GetSystemCatalog(context); - auto &function_entry = catalog.GetEntry(context, DEFAULT_SCHEMA, "normalized_interval"); - if (function_entry.functions.Size() != 1) { - throw InternalException("normalized_interval should only have a single overload"); - } - auto &scalar_function = function_entry.functions.GetFunctionReferenceByOffset(0); - vector> children; - children.push_back(std::move(source)); - - FunctionBinder function_binder(context); - auto function = function_binder.BindScalarFunction(scalar_function, std::move(children)); - source = std::move(function); - return true; -} - // timetz_byte_comparable CollationBinding::CollationBinding() { RegisterCollation(CollationCallback(PushVarcharCollation)); RegisterCollation(CollationCallback(PushTimeTZCollation)); - RegisterCollation(CollationCallback(PushIntervalCollation)); } void CollationBinding::RegisterCollation(CollationCallback callback) { @@ -120,9 +86,9 @@ void CollationBinding::RegisterCollation(CollationCallback callback) { } bool CollationBinding::PushCollation(ClientContext &context, unique_ptr &source, - const LogicalType &sql_type, CollationType type) const { + const LogicalType &sql_type) const { for (auto &collation : collations) { - if (collation.try_push_collation(context, source, sql_type, type)) { + if (collation.try_push_collation(context, source, sql_type)) { // successfully pushed a collation return true; } diff --git a/src/duckdb/src/planner/expression.cpp b/src/duckdb/src/planner/expression.cpp index 3eb0118c1..9fa426b8a 100644 --- a/src/duckdb/src/planner/expression.cpp +++ b/src/duckdb/src/planner/expression.cpp @@ -58,12 +58,6 @@ bool Expression::IsConsistent() const { return is_consistent; } -bool Expression::CanThrow() const { - bool can_throw = false; - ExpressionIterator::EnumerateChildren(*this, [&](const Expression &child) { can_throw |= child.CanThrow(); }); - return can_throw; -} - bool Expression::PropagatesNullValues() const { if (type == ExpressionType::OPERATOR_IS_NULL || type == ExpressionType::OPERATOR_IS_NOT_NULL || type == ExpressionType::COMPARE_NOT_DISTINCT_FROM || type == ExpressionType::COMPARE_DISTINCT_FROM || @@ -104,7 +98,7 @@ bool Expression::HasSubquery() const { } hash_t Expression::Hash() const { - hash_t hash = duckdb::Hash(static_cast(type)); + hash_t hash = duckdb::Hash((uint32_t)type); hash = CombineHash(hash, return_type.Hash()); ExpressionIterator::EnumerateChildren(*this, [&](const Expression &child) { hash = CombineHash(child.Hash(), hash); }); diff --git a/src/duckdb/src/planner/expression/bound_cast_expression.cpp b/src/duckdb/src/planner/expression/bound_cast_expression.cpp index 4168bf3e5..1c8dc9518 100644 --- a/src/duckdb/src/planner/expression/bound_cast_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_cast_expression.cpp @@ -2,7 +2,6 @@ #include "duckdb/planner/expression/bound_default_expression.hpp" #include "duckdb/planner/expression/bound_parameter_expression.hpp" #include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression_iterator.hpp" #include "duckdb/function/cast_rules.hpp" #include "duckdb/function/cast/cast_function_set.hpp" #include "duckdb/main/config.hpp" @@ -42,7 +41,7 @@ unique_ptr AddCastExpressionInternal(unique_ptr expr, co } } auto result = make_uniq(std::move(expr), target_type, std::move(bound_cast), try_cast); - result->SetQueryLocation(result->child->GetQueryLocation()); + result->query_location = result->child->query_location; return std::move(result); } @@ -50,7 +49,7 @@ unique_ptr AddCastToTypeInternal(unique_ptr expr, const CastFunctionSet &cast_functions, GetCastFunctionInput &get_input, bool try_cast) { D_ASSERT(expr); - if (expr->GetExpressionClass() == ExpressionClass::BOUND_PARAMETER) { + if (expr->expression_class == ExpressionClass::BOUND_PARAMETER) { auto ¶meter = expr->Cast(); if (!target_type.IsValid()) { // invalidate the parameter @@ -79,7 +78,7 @@ unique_ptr AddCastToTypeInternal(unique_ptr expr, const parameter.parameter_data->return_type = LogicalType::INVALID; parameter.return_type = target_type; return expr; - } else if (expr->GetExpressionClass() == ExpressionClass::BOUND_DEFAULT) { + } else if (expr->expression_class == ExpressionClass::BOUND_DEFAULT) { D_ASSERT(target_type.IsValid()); auto &def = expr->Cast(); def.return_type = target_type; @@ -96,7 +95,7 @@ unique_ptr BoundCastExpression::AddDefaultCastToType(unique_ptrGetQueryLocation(); + get_input.query_location = expr->query_location; return AddCastToTypeInternal(std::move(expr), target_type, default_set, get_input, try_cast); } @@ -104,7 +103,7 @@ unique_ptr BoundCastExpression::AddCastToType(ClientContext &context const LogicalType &target_type, bool try_cast) { auto &cast_functions = DBConfig::GetConfig(context).GetCastFunctions(); GetCastFunctionInput get_input(context); - get_input.query_location = expr->GetQueryLocation(); + get_input.query_location = expr->query_location; return AddCastToTypeInternal(std::move(expr), target_type, cast_functions, get_input, try_cast); } @@ -218,15 +217,4 @@ unique_ptr BoundCastExpression::Copy() const { return std::move(copy); } -bool BoundCastExpression::CanThrow() const { - const auto child_type = child->return_type; - if (return_type.id() != child_type.id() && - LogicalType::ForceMaxLogicalType(return_type, child_type) == child_type.id()) { - return true; - } - bool changes_type = false; - ExpressionIterator::EnumerateChildren(*this, [&](const Expression &child) { changes_type |= child.CanThrow(); }); - return changes_type; -} - } // namespace duckdb diff --git a/src/duckdb/src/planner/expression/bound_expression.cpp b/src/duckdb/src/planner/expression/bound_expression.cpp index b475c4f49..864357ff6 100644 --- a/src/duckdb/src/planner/expression/bound_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_expression.cpp @@ -5,7 +5,7 @@ namespace duckdb { BoundExpression::BoundExpression(unique_ptr expr_p) : ParsedExpression(ExpressionType::INVALID, ExpressionClass::BOUND_EXPRESSION), expr(std::move(expr_p)) { - this->alias = expr->GetAlias(); + this->alias = expr->alias; } unique_ptr &BoundExpression::GetExpression(ParsedExpression &expr) { diff --git a/src/duckdb/src/planner/expression/bound_function_expression.cpp b/src/duckdb/src/planner/expression/bound_function_expression.cpp index 1be272540..f31df2719 100644 --- a/src/duckdb/src/planner/expression/bound_function_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_function_expression.cpp @@ -5,7 +5,7 @@ #include "duckdb/function/function_serialization.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/function/lambda_functions.hpp" +#include "duckdb/core_functions/lambda_functions.hpp" namespace duckdb { @@ -42,13 +42,6 @@ bool BoundFunctionExpression::IsFoldable() const { return function.stability == FunctionStability::VOLATILE ? false : Expression::IsFoldable(); } -bool BoundFunctionExpression::CanThrow() const { - if (function.errors == FunctionErrors::CAN_THROW_RUNTIME_ERROR) { - return true; - } - return Expression::CanThrow(); -} - string BoundFunctionExpression::ToString() const { return FunctionExpression::ToString(*this, string(), string(), function.name, is_operator); diff --git a/src/duckdb/src/planner/expression/bound_parameter_expression.cpp b/src/duckdb/src/planner/expression/bound_parameter_expression.cpp index 82ceca2d4..65357d806 100644 --- a/src/duckdb/src/planner/expression/bound_parameter_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_parameter_expression.cpp @@ -29,7 +29,7 @@ BoundParameterExpression::BoundParameterExpression(bound_parameter_map_t &global } void BoundParameterExpression::Invalidate(Expression &expr) { - if (expr.GetExpressionType() != ExpressionType::VALUE_PARAMETER) { + if (expr.type != ExpressionType::VALUE_PARAMETER) { throw InternalException("BoundParameterExpression::Invalidate requires a parameter as input"); } auto &bound_parameter = expr.Cast(); @@ -38,7 +38,7 @@ void BoundParameterExpression::Invalidate(Expression &expr) { } void BoundParameterExpression::InvalidateRecursive(Expression &expr) { - if (expr.GetExpressionType() == ExpressionType::VALUE_PARAMETER) { + if (expr.type == ExpressionType::VALUE_PARAMETER) { Invalidate(expr); return; } diff --git a/src/duckdb/src/planner/expression/bound_window_expression.cpp b/src/duckdb/src/planner/expression/bound_window_expression.cpp index b189b8e6e..8ddfa5e33 100644 --- a/src/duckdb/src/planner/expression/bound_window_expression.cpp +++ b/src/duckdb/src/planner/expression/bound_window_expression.cpp @@ -64,16 +64,6 @@ bool BoundWindowExpression::Equals(const BaseExpression &other_p) const { return false; } - // check if the argument orderings are equivalent - if (arg_orders.size() != other.arg_orders.size()) { - return false; - } - for (idx_t i = 0; i < arg_orders.size(); i++) { - if (!arg_orders[i].Equals(other.arg_orders[i])) { - return false; - } - } - // check if the framing expressions are equivalent if (!Expression::Equals(start_expr, other.start_expr) || !Expression::Equals(end_expr, other.end_expr) || !Expression::Equals(offset_expr, other.offset_expr) || !Expression::Equals(default_expr, other.default_expr)) { @@ -101,23 +91,19 @@ bool BoundWindowExpression::PartitionsAreEquivalent(const BoundWindowExpression return true; } -idx_t BoundWindowExpression::GetSharedOrders(const vector &lhs, const vector &rhs) { - const auto overlap = MinValue(lhs.size(), rhs.size()); +idx_t BoundWindowExpression::GetSharedOrders(const BoundWindowExpression &other) const { + const auto overlap = MinValue(orders.size(), other.orders.size()); idx_t result = 0; for (; result < overlap; ++result) { - if (!lhs.at(result).Equals(rhs.at(result))) { - return 0; + if (!orders[result].Equals(other.orders[result])) { + return false; } } return result; } -idx_t BoundWindowExpression::GetSharedOrders(const BoundWindowExpression &other) const { - return GetSharedOrders(orders, other.orders); -} - bool BoundWindowExpression::KeysAreCompatible(const BoundWindowExpression &other) const { if (!PartitionsAreEquivalent(other)) { return false; @@ -161,10 +147,6 @@ unique_ptr BoundWindowExpression::Copy() const { new_window->orders.emplace_back(o.type, o.null_order, o.expression->Copy()); } - for (auto &o : arg_orders) { - new_window->arg_orders.emplace_back(o.type, o.null_order, o.expression->Copy()); - } - new_window->filter_expr = filter_expr ? filter_expr->Copy() : nullptr; new_window->start = start; @@ -207,7 +189,6 @@ void BoundWindowExpression::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(211, "default_expr", default_expr, unique_ptr()); serializer.WriteProperty(212, "exclude_clause", exclude_clause); serializer.WriteProperty(213, "distinct", distinct); - serializer.WriteProperty(214, "arg_orders", arg_orders); } unique_ptr BoundWindowExpression::Deserialize(Deserializer &deserializer) { @@ -237,7 +218,6 @@ unique_ptr BoundWindowExpression::Deserialize(Deserializer &deserial deserializer.ReadPropertyWithExplicitDefault(211, "default_expr", result->default_expr, unique_ptr()); deserializer.ReadProperty(212, "exclude_clause", result->exclude_clause); deserializer.ReadProperty(213, "distinct", result->distinct); - deserializer.ReadPropertyWithExplicitDefault(214, "arg_orders", result->arg_orders, vector()); return std::move(result); } diff --git a/src/duckdb/src/planner/expression_binder.cpp b/src/duckdb/src/planner/expression_binder.cpp index d09f796b9..7d36654ee 100644 --- a/src/duckdb/src/planner/expression_binder.cpp +++ b/src/duckdb/src/planner/expression_binder.cpp @@ -60,7 +60,7 @@ BindResult ExpressionBinder::BindExpression(unique_ptr &expr, auto stack_checker = StackCheck(*expr); auto &expr_ref = *expr; - switch (expr_ref.GetExpressionClass()) { + switch (expr_ref.expression_class) { case ExpressionClass::BETWEEN: return BindExpression(expr_ref.Cast(), depth); case ExpressionClass::CASE: @@ -228,7 +228,7 @@ void ExpressionBinder::BindChild(unique_ptr &expr, idx_t depth } void ExpressionBinder::ExtractCorrelatedExpressions(Binder &binder, Expression &expr) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_colref = expr.Cast(); if (bound_colref.depth > 0) { binder.AddCorrelatedColumn(CorrelatedColumnInfo(bound_colref)); @@ -354,9 +354,9 @@ unique_ptr ExpressionBinder::Bind(unique_ptr &expr ErrorData ExpressionBinder::Bind(unique_ptr &expr, idx_t depth, bool root_expression) { // bind the node, but only if it has not been bound yet - auto query_location = expr->GetQueryLocation(); + auto query_location = expr->query_location; auto &expression = *expr; - auto alias = expression.GetAlias(); + auto alias = expression.alias; if (expression.GetExpressionClass() == ExpressionClass::BOUND_EXPRESSION) { // already bound, don't bind it again return ErrorData(); @@ -367,12 +367,12 @@ ErrorData ExpressionBinder::Bind(unique_ptr &expr, idx_t depth return std::move(result.error); } // successfully bound: replace the node with a BoundExpression - result.expression->SetQueryLocation(query_location); + result.expression->query_location = query_location; expr = make_uniq(std::move(result.expression)); auto &be = expr->Cast(); - be.SetAlias(alias); + be.alias = alias; if (!alias.empty()) { - be.expr->SetAlias(alias); + be.expr->alias = alias; } return ErrorData(); } diff --git a/src/duckdb/src/planner/expression_binder/aggregate_binder.cpp b/src/duckdb/src/planner/expression_binder/aggregate_binder.cpp index b02cbf970..353002b5a 100644 --- a/src/duckdb/src/planner/expression_binder/aggregate_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/aggregate_binder.cpp @@ -9,7 +9,7 @@ AggregateBinder::AggregateBinder(Binder &binder, ClientContext &context) : Expre BindResult AggregateBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::WINDOW: throw BinderException::Unsupported(expr, "aggregate function calls cannot contain window function calls"); default: diff --git a/src/duckdb/src/planner/expression_binder/base_select_binder.cpp b/src/duckdb/src/planner/expression_binder/base_select_binder.cpp index e0adf5398..a8b1addc0 100644 --- a/src/duckdb/src/planner/expression_binder/base_select_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/base_select_binder.cpp @@ -27,7 +27,7 @@ BindResult BaseSelectBinder::BindExpression(unique_ptr &expr_p if (group_index != DConstants::INVALID_INDEX) { return BindGroup(expr, depth, group_index); } - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::COLUMN_REF: return BindColumnRef(expr_ptr, depth, root_expression); case ExpressionClass::DEFAULT: @@ -41,7 +41,7 @@ BindResult BaseSelectBinder::BindExpression(unique_ptr &expr_p idx_t BaseSelectBinder::TryBindGroup(ParsedExpression &expr) { // first check the group alias map, if expr is a ColumnRefExpression - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); if (!colref.IsQualified()) { auto alias_entry = info.alias_map.find(colref.column_names[0]); diff --git a/src/duckdb/src/planner/expression_binder/group_binder.cpp b/src/duckdb/src/planner/expression_binder/group_binder.cpp index cdec41e15..36ef5e622 100644 --- a/src/duckdb/src/planner/expression_binder/group_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/group_binder.cpp @@ -18,7 +18,7 @@ GroupBinder::GroupBinder(Binder &binder, ClientContext &context, SelectNode &nod BindResult GroupBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; if (root_expression && depth == 0) { - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::COLUMN_REF: return BindColumnRef(expr.Cast()); case ExpressionClass::CONSTANT: @@ -29,7 +29,7 @@ BindResult GroupBinder::BindExpression(unique_ptr &expr_ptr, i break; } } - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::DEFAULT: return BindUnsupportedExpression(expr, depth, "GROUP BY clause cannot contain DEFAULT clause"); case ExpressionClass::WINDOW: diff --git a/src/duckdb/src/planner/expression_binder/having_binder.cpp b/src/duckdb/src/planner/expression_binder/having_binder.cpp index 6f0c96a06..27b0124bc 100644 --- a/src/duckdb/src/planner/expression_binder/having_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/having_binder.cpp @@ -22,22 +22,6 @@ BindResult HavingBinder::BindLambdaReference(LambdaRefExpression &expr, idx_t de return (*lambda_bindings)[expr.lambda_idx].Bind(lambda_ref, depth); } -unique_ptr HavingBinder::QualifyColumnName(ColumnRefExpression &colref, ErrorData &error) { - auto qualified_colref = ExpressionBinder::QualifyColumnName(colref, error); - if (!qualified_colref) { - return nullptr; - } - - auto group_index = TryBindGroup(*qualified_colref); - if (group_index != DConstants::INVALID_INDEX) { - return qualified_colref; - } - if (column_alias_binder.QualifyColumnAlias(colref)) { - return nullptr; - } - return qualified_colref; -} - BindResult HavingBinder::BindColumnRef(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { // Keep the original column name to return a meaningful error message. diff --git a/src/duckdb/src/planner/expression_binder/index_binder.cpp b/src/duckdb/src/planner/expression_binder/index_binder.cpp index 950edb6e6..e0138ecb3 100644 --- a/src/duckdb/src/planner/expression_binder/index_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/index_binder.cpp @@ -8,9 +8,6 @@ #include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/planner/operator/logical_get.hpp" -#include "duckdb/function/table/table_scan.hpp" -#include "duckdb/planner/operator/logical_create_index.hpp" namespace duckdb { @@ -48,58 +45,9 @@ unique_ptr IndexBinder::BindIndex(const UnboundIndex &unbound_index) return index_type->create_instance(input); } -void IndexBinder::InitCreateIndexInfo(LogicalGet &get, CreateIndexInfo &info, const string &schema) { - auto &column_ids = get.GetColumnIds(); - for (auto &column_id : column_ids) { - if (column_id.IsRowIdColumn()) { - throw BinderException("cannot create an index on the rowid"); - } - auto col_id = column_id.GetPrimaryIndex(); - info.column_ids.push_back(col_id); - info.scan_types.push_back(get.returned_types[col_id]); - } - - info.scan_types.emplace_back(LogicalType::ROW_TYPE); - info.names = get.names; - info.schema = schema; - get.AddColumnId(COLUMN_IDENTIFIER_ROW_ID); -} - -unique_ptr IndexBinder::BindCreateIndex(ClientContext &context, - unique_ptr create_index_info, - TableCatalogEntry &table_entry, - unique_ptr plan, - unique_ptr alter_table_info) { - // Add the dependencies. - auto &dependencies = create_index_info->dependencies; - auto &catalog = Catalog::GetCatalog(context, create_index_info->catalog); - SetCatalogLookupCallback([&dependencies, &catalog](CatalogEntry &entry) { - if (&catalog != &entry.ParentCatalog()) { - return; - } - dependencies.AddDependency(entry); - }); - - // Bind the index expressions. - vector> expressions; - for (auto &expr : create_index_info->expressions) { - expressions.push_back(Bind(expr)); - } - - auto &get = plan->Cast(); - InitCreateIndexInfo(get, *create_index_info, table_entry.schema.name); - auto &bind_data = get.bind_data->Cast(); - bind_data.is_create_index = true; - - auto result = make_uniq(std::move(create_index_info), std::move(expressions), table_entry, - std::move(alter_table_info)); - result->children.push_back(std::move(plan)); - return std::move(result); -} - BindResult IndexBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::WINDOW: return BindResult(BinderException::Unsupported(expr, "window functions are not allowed in index expressions")); case ExpressionClass::SUBQUERY: diff --git a/src/duckdb/src/planner/expression_binder/lateral_binder.cpp b/src/duckdb/src/planner/expression_binder/lateral_binder.cpp index 205b644e8..a2c56611f 100644 --- a/src/duckdb/src/planner/expression_binder/lateral_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/lateral_binder.cpp @@ -11,7 +11,7 @@ LateralBinder::LateralBinder(Binder &binder, ClientContext &context) : Expressio } void LateralBinder::ExtractCorrelatedColumns(Expression &expr) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &bound_colref = expr.Cast(); if (bound_colref.depth > 0) { // add the correlated column info @@ -88,9 +88,9 @@ class ExpressionDepthReducerRecursive : public BoundNodeVisitor { } void VisitExpression(unique_ptr &expression) override { - if (expression->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression->type == ExpressionType::BOUND_COLUMN_REF) { ReduceColumnRefDepth(expression->Cast(), correlated_columns); - } else if (expression->GetExpressionType() == ExpressionType::SUBQUERY) { + } else if (expression->type == ExpressionType::SUBQUERY) { ReduceExpressionSubquery(expression->Cast(), correlated_columns); } BoundNodeVisitor::VisitExpression(expression); diff --git a/src/duckdb/src/planner/expression_binder/order_binder.cpp b/src/duckdb/src/planner/expression_binder/order_binder.cpp index af78102b8..ff864bbbd 100644 --- a/src/duckdb/src/planner/expression_binder/order_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/order_binder.cpp @@ -30,13 +30,13 @@ unique_ptr OrderBinder::CreateProjectionReference(ParsedExpression & if (extra_list && index < extra_list->size()) { alias = extra_list->at(index)->ToString(); } else { - if (!expr.GetAlias().empty()) { - alias = expr.GetAlias(); + if (!expr.alias.empty()) { + alias = expr.alias; } } auto result = make_uniq(Value::UBIGINT(index)); - result->SetAlias(std::move(alias)); - result->SetQueryLocation(expr.GetQueryLocation()); + result->alias = std::move(alias); + result->query_location = expr.query_location; return std::move(result); } @@ -51,7 +51,7 @@ unique_ptr OrderBinder::CreateExtraReference(unique_ptr(); // ORDER BY a constant @@ -112,8 +112,8 @@ unique_ptr OrderBinder::BindConstant(ParsedExpression &expr) { child_list_t values; values.push_back(make_pair("index", Value::UBIGINT(index.GetIndex()))); auto result = make_uniq(Value::STRUCT(std::move(values))); - result->SetAlias(expr.GetAlias()); - result->SetQueryLocation(expr.GetQueryLocation()); + result->alias = std::move(expr.alias); + result->query_location = expr.query_location; return std::move(result); } @@ -123,7 +123,7 @@ unique_ptr OrderBinder::Bind(unique_ptr expr) { // if there is no matching entry in the SELECT list already, we add the expression to the SELECT list and refer the // new expression the new entry will then be bound later during the binding of the SELECT list we also don't do type // resolution here: this only happens after the SELECT list has been bound - switch (expr->GetExpressionClass()) { + switch (expr->expression_class) { case ExpressionClass::CONSTANT: { // ORDER BY constant // is the ORDER BY expression a constant integer? (e.g. ORDER BY 1) diff --git a/src/duckdb/src/planner/expression_binder/relation_binder.cpp b/src/duckdb/src/planner/expression_binder/relation_binder.cpp index 10a0516cf..d6cfe83cb 100644 --- a/src/duckdb/src/planner/expression_binder/relation_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/relation_binder.cpp @@ -8,7 +8,7 @@ RelationBinder::RelationBinder(Binder &binder, ClientContext &context, string op BindResult RelationBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::AGGREGATE: return BindResult(BinderException::Unsupported(expr, "aggregate functions are not allowed in " + op)); case ExpressionClass::DEFAULT: diff --git a/src/duckdb/src/planner/expression_binder/select_bind_state.cpp b/src/duckdb/src/planner/expression_binder/select_bind_state.cpp index dbdbcf0ff..23ada81d0 100644 --- a/src/duckdb/src/planner/expression_binder/select_bind_state.cpp +++ b/src/duckdb/src/planner/expression_binder/select_bind_state.cpp @@ -7,7 +7,7 @@ unique_ptr SelectBindState::BindAlias(idx_t index) { if (volatile_expressions.find(index) != volatile_expressions.end()) { throw BinderException("Alias \"%s\" referenced - but the expression has side " "effects. This is not yet supported.", - original_expressions[index]->GetAlias()); + original_expressions[index]->alias); } referenced_aliases.insert(index); return original_expressions[index]->Copy(); @@ -18,7 +18,7 @@ void SelectBindState::SetExpressionIsVolatile(idx_t index) { if (referenced_aliases.find(index) != referenced_aliases.end()) { throw BinderException("Alias \"%s\" referenced - but the expression has side " "effects. This is not yet supported.", - original_expressions[index]->GetAlias()); + original_expressions[index]->alias); } volatile_expressions.insert(index); } diff --git a/src/duckdb/src/planner/expression_binder/table_function_binder.cpp b/src/duckdb/src/planner/expression_binder/table_function_binder.cpp index fca04a10b..f1bdac9c8 100644 --- a/src/duckdb/src/planner/expression_binder/table_function_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/table_function_binder.cpp @@ -30,7 +30,7 @@ BindResult TableFunctionBinder::BindColumnReference(unique_ptr throw ParameterNotResolvedException(); } } - auto query_location = col_ref.GetQueryLocation(); + auto query_location = col_ref.query_location; auto column_names = col_ref.column_names; auto result_name = StringUtil::Join(column_names, "."); if (!table_function_name.empty()) { diff --git a/src/duckdb/src/planner/expression_binder/update_binder.cpp b/src/duckdb/src/planner/expression_binder/update_binder.cpp index 5d69e94b3..b3f7e6389 100644 --- a/src/duckdb/src/planner/expression_binder/update_binder.cpp +++ b/src/duckdb/src/planner/expression_binder/update_binder.cpp @@ -7,7 +7,7 @@ UpdateBinder::UpdateBinder(Binder &binder, ClientContext &context) : ExpressionB BindResult UpdateBinder::BindExpression(unique_ptr &expr_ptr, idx_t depth, bool root_expression) { auto &expr = *expr_ptr; - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::WINDOW: return BindResult(BinderException::Unsupported(expr, "window functions are not allowed in UPDATE")); default: diff --git a/src/duckdb/src/planner/expression_iterator.cpp b/src/duckdb/src/planner/expression_iterator.cpp index af2afe826..1b271112e 100644 --- a/src/duckdb/src/planner/expression_iterator.cpp +++ b/src/duckdb/src/planner/expression_iterator.cpp @@ -22,7 +22,7 @@ void ExpressionIterator::EnumerateChildren(Expression &expr, const std::function void ExpressionIterator::EnumerateChildren(Expression &expr, const std::function &child)> &callback) { - switch (expr.GetExpressionClass()) { + switch (expr.expression_class) { case ExpressionClass::BOUND_AGGREGATE: { auto &aggr_expr = expr.Cast(); for (auto &child : aggr_expr.children) { @@ -88,8 +88,8 @@ void ExpressionIterator::EnumerateChildren(Expression &expr, } case ExpressionClass::BOUND_SUBQUERY: { auto &subquery_expr = expr.Cast(); - for (auto &child : subquery_expr.children) { - callback(child); + if (subquery_expr.child) { + callback(subquery_expr.child); } break; } @@ -119,9 +119,6 @@ void ExpressionIterator::EnumerateChildren(Expression &expr, if (window_expr.default_expr) { callback(window_expr.default_expr); } - for (auto &order : window_expr.arg_orders) { - callback(order.expression); - } break; } case ExpressionClass::BOUND_UNNEST: { diff --git a/src/duckdb/src/planner/filter/constant_filter.cpp b/src/duckdb/src/planner/filter/constant_filter.cpp index 9384cd204..34e161004 100644 --- a/src/duckdb/src/planner/filter/constant_filter.cpp +++ b/src/duckdb/src/planner/filter/constant_filter.cpp @@ -14,11 +14,6 @@ ConstantFilter::ConstantFilter(ExpressionType comparison_type_p, Value constant_ } FilterPropagateResult ConstantFilter::CheckStatistics(BaseStatistics &stats) { - if (!stats.CanHaveNoNull()) { - // no non-null values are possible: always false - return FilterPropagateResult::FILTER_ALWAYS_FALSE; - } - FilterPropagateResult result; D_ASSERT(constant.type().id() == stats.GetType().id()); switch (constant.type().InternalType()) { case PhysicalType::UINT8: @@ -33,22 +28,12 @@ FilterPropagateResult ConstantFilter::CheckStatistics(BaseStatistics &stats) { case PhysicalType::INT128: case PhysicalType::FLOAT: case PhysicalType::DOUBLE: - result = NumericStats::CheckZonemap(stats, comparison_type, array_ptr(&constant, 1)); - break; + return NumericStats::CheckZonemap(stats, comparison_type, constant); case PhysicalType::VARCHAR: - result = StringStats::CheckZonemap(stats, comparison_type, array_ptr(&constant, 1)); - break; + return StringStats::CheckZonemap(stats, comparison_type, StringValue::Get(constant)); default: return FilterPropagateResult::NO_PRUNING_POSSIBLE; } - if (result == FilterPropagateResult::FILTER_ALWAYS_TRUE) { - // the numeric filter is always true, but the column can have NULL values - // we can't prune the filter - if (stats.CanHaveNull()) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } - } - return result; } string ConstantFilter::ToString(const string &column_name) { diff --git a/src/duckdb/src/planner/filter/dynamic_filter.cpp b/src/duckdb/src/planner/filter/dynamic_filter.cpp deleted file mode 100644 index 23de4bf42..000000000 --- a/src/duckdb/src/planner/filter/dynamic_filter.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "duckdb/planner/filter/dynamic_filter.hpp" -#include "duckdb/planner/filter/constant_filter.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" - -namespace duckdb { - -DynamicFilter::DynamicFilter() : TableFilter(TableFilterType::DYNAMIC_FILTER) { -} - -DynamicFilter::DynamicFilter(shared_ptr filter_data_p) - : TableFilter(TableFilterType::DYNAMIC_FILTER), filter_data(std::move(filter_data_p)) { -} - -FilterPropagateResult DynamicFilter::CheckStatistics(BaseStatistics &stats) { - if (!filter_data) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } - lock_guard l(filter_data->lock); - if (!filter_data->initialized) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } - return filter_data->filter->CheckStatistics(stats); -} - -string DynamicFilter::ToString(const string &column_name) { - if (filter_data) { - return "Dynamic Filter (" + column_name + ")"; - } else { - return "Empty Dynamic Filter (" + column_name + ")"; - } -} - -unique_ptr DynamicFilter::ToExpression(const Expression &column) const { - if (!filter_data || !filter_data->initialized) { - auto bound_constant = make_uniq(Value(true)); - return std::move(bound_constant); - } - lock_guard l(filter_data->lock); - return filter_data->filter->ToExpression(column); -} - -bool DynamicFilter::Equals(const TableFilter &other_p) const { - if (!TableFilter::Equals(other_p)) { - return false; - } - auto &other = other_p.Cast(); - return other.filter_data.get() == filter_data.get(); -} - -unique_ptr DynamicFilter::Copy() const { - return make_uniq(filter_data); -} - -void DynamicFilterData::SetValue(Value val) { - if (val.IsNull()) { - return; - } - lock_guard l(lock); - filter->Cast().constant = std::move(val); - initialized = true; -} - -void DynamicFilterData::Reset() { - lock_guard l(lock); - initialized = false; -} - -} // namespace duckdb diff --git a/src/duckdb/src/planner/filter/in_filter.cpp b/src/duckdb/src/planner/filter/in_filter.cpp deleted file mode 100644 index b3eff6e23..000000000 --- a/src/duckdb/src/planner/filter/in_filter.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "duckdb/planner/filter/in_filter.hpp" -#include "duckdb/storage/statistics/base_statistics.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_operator_expression.hpp" - -namespace duckdb { - -InFilter::InFilter(vector values_p) : InFilter(std::move(values_p), false) { -} - -InFilter::InFilter(vector values_p, bool origin_is_hash_join) - : TableFilter(TableFilterType::IN_FILTER), values(std::move(values_p)), origin_is_hash_join(origin_is_hash_join) { - for (auto &val : values) { - if (val.IsNull()) { - throw InternalException("InFilter constant cannot be NULL - use IsNullFilter instead"); - } - } - for (idx_t i = 1; i < values.size(); i++) { - if (values[0].type() != values[i].type()) { - throw InternalException("InFilter constants must all have the same type"); - } - } - if (values.empty()) { - throw InternalException("InFilter constants cannot be empty"); - } -} - -FilterPropagateResult InFilter::CheckStatistics(BaseStatistics &stats) { - switch (values[0].type().InternalType()) { - case PhysicalType::UINT8: - case PhysicalType::UINT16: - case PhysicalType::UINT32: - case PhysicalType::UINT64: - case PhysicalType::UINT128: - case PhysicalType::INT8: - case PhysicalType::INT16: - case PhysicalType::INT32: - case PhysicalType::INT64: - case PhysicalType::INT128: - case PhysicalType::FLOAT: - case PhysicalType::DOUBLE: - return NumericStats::CheckZonemap(stats, ExpressionType::COMPARE_EQUAL, - array_ptr(values.data(), values.size())); - case PhysicalType::VARCHAR: - return StringStats::CheckZonemap(stats, ExpressionType::COMPARE_EQUAL, - array_ptr(values.data(), values.size())); - default: - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } -} - -string InFilter::ToString(const string &column_name) { - string in_list; - for (auto &val : values) { - if (!in_list.empty()) { - in_list += ", "; - } - in_list += val.ToSQLString(); - } - return column_name + " IN (" + in_list + ")"; -} - -unique_ptr InFilter::ToExpression(const Expression &column) const { - auto result = make_uniq(ExpressionType::COMPARE_IN, LogicalType::BOOLEAN); - result->children.push_back(column.Copy()); - for (auto &val : values) { - result->children.push_back(make_uniq(val)); - } - return std::move(result); -} - -bool InFilter::Equals(const TableFilter &other_p) const { - if (!TableFilter::Equals(other_p)) { - return false; - } - auto &other = other_p.Cast(); - return other.values == values && other.origin_is_hash_join == origin_is_hash_join; -} - -unique_ptr InFilter::Copy() const { - return make_uniq(values, origin_is_hash_join); -} - -} // namespace duckdb diff --git a/src/duckdb/src/planner/filter/null_filter.cpp b/src/duckdb/src/planner/filter/null_filter.cpp index 6848191e9..a451c8a74 100644 --- a/src/duckdb/src/planner/filter/null_filter.cpp +++ b/src/duckdb/src/planner/filter/null_filter.cpp @@ -1,4 +1,5 @@ #include "duckdb/planner/filter/null_filter.hpp" + #include "duckdb/planner/expression/bound_operator_expression.hpp" #include "duckdb/storage/statistics/base_statistics.hpp" @@ -20,7 +21,7 @@ FilterPropagateResult IsNullFilter::CheckStatistics(BaseStatistics &stats) { } string IsNullFilter::ToString(const string &column_name) { - return column_name + " IS NULL"; + return column_name + "IS NULL"; } unique_ptr IsNullFilter::Copy() const { diff --git a/src/duckdb/src/planner/filter/optional_filter.cpp b/src/duckdb/src/planner/filter/optional_filter.cpp deleted file mode 100644 index 891e9014d..000000000 --- a/src/duckdb/src/planner/filter/optional_filter.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "duckdb/planner/table_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" -#include "duckdb/planner/expression.hpp" - -namespace duckdb { - -OptionalFilter::OptionalFilter(unique_ptr filter) - : TableFilter(TableFilterType::OPTIONAL_FILTER), child_filter(std::move(filter)) { -} - -FilterPropagateResult OptionalFilter::CheckStatistics(BaseStatistics &stats) { - return child_filter->CheckStatistics(stats); -} - -string OptionalFilter::ToString(const string &column_name) { - return string("optional: ") + child_filter->ToString(column_name); -} - -unique_ptr OptionalFilter::ToExpression(const Expression &column) const { - return child_filter->ToExpression(column); -} - -unique_ptr OptionalFilter::Copy() const { - auto copy = make_uniq(); - copy->child_filter = child_filter->Copy(); - return duckdb::unique_ptr_cast(std::move(copy)); -} - -} // namespace duckdb diff --git a/src/duckdb/src/planner/filter/struct_filter.cpp b/src/duckdb/src/planner/filter/struct_filter.cpp index 91d3b323d..2c9c3541f 100644 --- a/src/duckdb/src/planner/filter/struct_filter.cpp +++ b/src/duckdb/src/planner/filter/struct_filter.cpp @@ -21,10 +21,7 @@ FilterPropagateResult StructFilter::CheckStatistics(BaseStatistics &stats) { } string StructFilter::ToString(const string &column_name) { - if (!child_name.empty()) { - return child_filter->ToString(column_name + "." + child_name); - } - return child_filter->ToString("struct_extract_at(" + column_name + "," + std::to_string(child_idx + 1) + ")"); + return child_filter->ToString(column_name + "." + child_name); } bool StructFilter::Equals(const TableFilter &other_p) const { @@ -32,10 +29,8 @@ bool StructFilter::Equals(const TableFilter &other_p) const { return false; } auto &other = other_p.Cast(); - if ((!child_name.empty()) && (!other.child_name.empty())) { // if both child_names are known, sanity check - D_ASSERT((other.child_idx == child_idx) == StringUtil::CIEquals(other.child_name, child_name)); - } - return other.child_idx == child_idx && other.child_filter->Equals(*child_filter); + return other.child_idx == child_idx && StringUtil::CIEquals(other.child_name, child_name) && + other.child_filter->Equals(*child_filter); } unique_ptr StructFilter::Copy() const { @@ -46,9 +41,9 @@ unique_ptr StructFilter::ToExpression(const Expression &column) cons auto &child_type = StructType::GetChildType(column.return_type, child_idx); vector> arguments; arguments.push_back(column.Copy()); - arguments.push_back(make_uniq(Value::BIGINT(NumericCast(child_idx + 1)))); - auto child = make_uniq(child_type, GetExtractAtFunction(), std::move(arguments), - GetBindData(child_idx)); + arguments.push_back(make_uniq(Value::BIGINT(NumericCast(child_idx)))); + auto child = make_uniq(child_type, StructExtractFun::IndexExtractFunction(), + std::move(arguments), StructExtractFun::GetBindData(child_idx)); return child_filter->ToExpression(*child); } } // namespace duckdb diff --git a/src/duckdb/src/planner/joinside.cpp b/src/duckdb/src/planner/joinside.cpp index b4c571b91..ba5b49cc3 100644 --- a/src/duckdb/src/planner/joinside.cpp +++ b/src/duckdb/src/planner/joinside.cpp @@ -57,21 +57,20 @@ JoinSide JoinSide::GetJoinSide(idx_t table_binding, const unordered_set & JoinSide JoinSide::GetJoinSide(Expression &expression, const unordered_set &left_bindings, const unordered_set &right_bindings) { - if (expression.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expression.Cast(); if (colref.depth > 0) { throw NotImplementedException("Non-inner join on correlated columns not supported"); } return GetJoinSide(colref.binding.table_index, left_bindings, right_bindings); } - D_ASSERT(expression.GetExpressionType() != ExpressionType::BOUND_REF); - if (expression.GetExpressionType() == ExpressionType::SUBQUERY) { + D_ASSERT(expression.type != ExpressionType::BOUND_REF); + if (expression.type == ExpressionType::SUBQUERY) { D_ASSERT(expression.GetExpressionClass() == ExpressionClass::BOUND_SUBQUERY); auto &subquery = expression.Cast(); JoinSide side = JoinSide::NONE; - for (auto &child : subquery.children) { - auto child_side = GetJoinSide(*child, left_bindings, right_bindings); - side = CombineJoinSide(side, child_side); + if (subquery.child) { + side = GetJoinSide(*subquery.child, left_bindings, right_bindings); } // correlated subquery, check the side of each of correlated columns in the subquery for (auto &corr : subquery.binder->correlated_columns) { diff --git a/src/duckdb/src/planner/logical_operator.cpp b/src/duckdb/src/planner/logical_operator.cpp index c8e73a1fe..17cd2d982 100644 --- a/src/duckdb/src/planner/logical_operator.cpp +++ b/src/duckdb/src/planner/logical_operator.cpp @@ -1,6 +1,5 @@ #include "duckdb/planner/logical_operator.hpp" -#include "duckdb/common/enum_util.hpp" #include "duckdb/common/printer.hpp" #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/binary_serializer.hpp" @@ -9,9 +8,6 @@ #include "duckdb/common/tree_renderer.hpp" #include "duckdb/parser/parser.hpp" #include "duckdb/planner/operator/list.hpp" -#include "duckdb/planner/operator/logical_filter.hpp" -#include "duckdb/planner/operator/logical_join.hpp" -#include "duckdb/planner/operator/logical_order.hpp" namespace duckdb { @@ -77,6 +73,7 @@ InsertionOrderPreservingMap LogicalOperator::ParamsToString() const { } void LogicalOperator::ResolveOperatorTypes() { + types.clear(); // first resolve child types for (auto &child : children) { diff --git a/src/duckdb/src/planner/logical_operator_visitor.cpp b/src/duckdb/src/planner/logical_operator_visitor.cpp index 7ebf3151e..367fb5f20 100644 --- a/src/duckdb/src/planner/logical_operator_visitor.cpp +++ b/src/duckdb/src/planner/logical_operator_visitor.cpp @@ -12,75 +12,9 @@ void LogicalOperatorVisitor::VisitOperator(LogicalOperator &op) { } void LogicalOperatorVisitor::VisitOperatorChildren(LogicalOperator &op) { - if (op.HasProjectionMap()) { - VisitOperatorWithProjectionMapChildren(op); - } else { - for (auto &child : op.children) { - VisitOperator(*child); - } - } -} - -void LogicalOperatorVisitor::VisitOperatorWithProjectionMapChildren(LogicalOperator &op) { - D_ASSERT(op.HasProjectionMap()); - switch (op.type) { - case LogicalOperatorType::LOGICAL_ANY_JOIN: - case LogicalOperatorType::LOGICAL_COMPARISON_JOIN: - case LogicalOperatorType::LOGICAL_DELIM_JOIN: - case LogicalOperatorType::LOGICAL_ASOF_JOIN: { - auto &join = op.Cast(); - VisitChildOfOperatorWithProjectionMap(*op.children[0], join.left_projection_map); - VisitChildOfOperatorWithProjectionMap(*op.children[1], join.right_projection_map); - break; - } - case LogicalOperatorType::LOGICAL_ORDER_BY: { - auto &order = op.Cast(); - VisitChildOfOperatorWithProjectionMap(*op.children[0], order.projection_map); - break; - } - case LogicalOperatorType::LOGICAL_FILTER: { - auto &filter = op.Cast(); - VisitChildOfOperatorWithProjectionMap(*op.children[0], filter.projection_map); - break; - } - default: - throw NotImplementedException("VisitOperatorWithProjectionMapChildren for %s", EnumUtil::ToString(op.type)); - } -} - -void LogicalOperatorVisitor::VisitChildOfOperatorWithProjectionMap(LogicalOperator &child, - vector &projection_map) { - const auto child_bindings_before = child.GetColumnBindings(); - VisitOperator(child); - if (projection_map.empty()) { - return; // Nothing to fix here - } - // Child binding order may have changed due to 'fun'. - const auto child_bindings_after = child.GetColumnBindings(); - if (child_bindings_before == child_bindings_after) { - return; // Nothing changed - } - // The desired order is 'projection_map' applied to 'child_bindings_before' - // We create 'new_projection_map', which ensures this order even if 'child_bindings_after' is different - vector new_projection_map; - new_projection_map.reserve(projection_map.size()); - for (const auto proj_idx_before : projection_map) { - auto &desired_binding = child_bindings_before[proj_idx_before]; - idx_t proj_idx_after; - for (proj_idx_after = 0; proj_idx_after < child_bindings_after.size(); proj_idx_after++) { - if (child_bindings_after[proj_idx_after] == desired_binding) { - break; - } - } - if (proj_idx_after == child_bindings_after.size()) { - // VisitOperator has removed this binding, e.g., by replacing one binding with another - // Inside here we don't know how it has been replaced, and projection maps are positional: bail - new_projection_map.clear(); - break; - } - new_projection_map.push_back(proj_idx_after); + for (auto &child : op.children) { + VisitOperator(*child); } - projection_map = std::move(new_projection_map); } void LogicalOperatorVisitor::EnumerateExpressions(LogicalOperator &op, diff --git a/src/duckdb/src/planner/operator/logical_comparison_join.cpp b/src/duckdb/src/planner/operator/logical_comparison_join.cpp index 48efe6259..f844b1824 100644 --- a/src/duckdb/src/planner/operator/logical_comparison_join.cpp +++ b/src/duckdb/src/planner/operator/logical_comparison_join.cpp @@ -28,27 +28,4 @@ InsertionOrderPreservingMap LogicalComparisonJoin::ParamsToString() cons return result; } -bool LogicalComparisonJoin::HasEquality(idx_t &range_count) const { - for (size_t c = 0; c < conditions.size(); ++c) { - auto &cond = conditions[c]; - switch (cond.comparison) { - case ExpressionType::COMPARE_EQUAL: - case ExpressionType::COMPARE_NOT_DISTINCT_FROM: - return true; - case ExpressionType::COMPARE_LESSTHAN: - case ExpressionType::COMPARE_GREATERTHAN: - case ExpressionType::COMPARE_LESSTHANOREQUALTO: - case ExpressionType::COMPARE_GREATERTHANOREQUALTO: - ++range_count; - break; - case ExpressionType::COMPARE_NOTEQUAL: - case ExpressionType::COMPARE_DISTINCT_FROM: - break; - default: - throw NotImplementedException("Unimplemented comparison join"); - } - } - return false; -} - } // namespace duckdb diff --git a/src/duckdb/src/planner/operator/logical_create_index.cpp b/src/duckdb/src/planner/operator/logical_create_index.cpp index e1bc0f0ee..65e36069a 100644 --- a/src/duckdb/src/planner/operator/logical_create_index.cpp +++ b/src/duckdb/src/planner/operator/logical_create_index.cpp @@ -7,14 +7,13 @@ namespace duckdb { LogicalCreateIndex::LogicalCreateIndex(unique_ptr info_p, vector> expressions_p, - TableCatalogEntry &table_p, unique_ptr alter_table_info) - : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), info(std::move(info_p)), table(table_p), - alter_table_info(std::move(alter_table_info)) { + TableCatalogEntry &table_p) + : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), info(std::move(info_p)), table(table_p) { for (auto &expr : expressions_p) { - unbound_expressions.push_back(expr->Copy()); + this->unbound_expressions.push_back(expr->Copy()); } - expressions = std::move(expressions_p); + this->expressions = std::move(expressions_p); if (info->column_ids.empty()) { throw BinderException("CREATE INDEX does not refer to any columns in the base table!"); @@ -22,26 +21,23 @@ LogicalCreateIndex::LogicalCreateIndex(unique_ptr info_p, vecto } LogicalCreateIndex::LogicalCreateIndex(ClientContext &context, unique_ptr info_p, - vector> expressions_p, - unique_ptr alter_table_info) + vector> expressions_p) : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), - info(unique_ptr_cast(std::move(info_p))), table(BindTable(context, *info)), - alter_table_info(unique_ptr_cast(std::move(alter_table_info))) { - + info(unique_ptr_cast(std::move(info_p))), table(BindTable(context, *info)) { for (auto &expr : expressions_p) { - unbound_expressions.push_back(expr->Copy()); + this->unbound_expressions.push_back(expr->Copy()); } - expressions = std::move(expressions_p); + this->expressions = std::move(expressions_p); } void LogicalCreateIndex::ResolveTypes() { types.emplace_back(LogicalType::BIGINT); } -TableCatalogEntry &LogicalCreateIndex::BindTable(ClientContext &context, CreateIndexInfo &info_p) { - auto &catalog = info_p.catalog; - auto &schema = info_p.schema; - auto &table_name = info_p.table; +TableCatalogEntry &LogicalCreateIndex::BindTable(ClientContext &context, CreateIndexInfo &info) { + auto &catalog = info.catalog; + auto &schema = info.schema; + auto &table_name = info.table; return Catalog::GetEntry(context, catalog, schema, table_name); } diff --git a/src/duckdb/src/planner/operator/logical_filter.cpp b/src/duckdb/src/planner/operator/logical_filter.cpp index aa9b21642..4fc18c08b 100644 --- a/src/duckdb/src/planner/operator/logical_filter.cpp +++ b/src/duckdb/src/planner/operator/logical_filter.cpp @@ -25,7 +25,7 @@ vector LogicalFilter::GetColumnBindings() { bool LogicalFilter::SplitPredicates(vector> &expressions) { bool found_conjunction = false; for (idx_t i = 0; i < expressions.size(); i++) { - if (expressions[i]->GetExpressionType() == ExpressionType::CONJUNCTION_AND) { + if (expressions[i]->type == ExpressionType::CONJUNCTION_AND) { auto &conjunction = expressions[i]->Cast(); found_conjunction = true; // AND expression, append the other children diff --git a/src/duckdb/src/planner/operator/logical_get.cpp b/src/duckdb/src/planner/operator/logical_get.cpp index be7b5aa5d..d6e9fda93 100644 --- a/src/duckdb/src/planner/operator/logical_get.cpp +++ b/src/duckdb/src/planner/operator/logical_get.cpp @@ -17,10 +17,10 @@ LogicalGet::LogicalGet() : LogicalOperator(LogicalOperatorType::LOGICAL_GET) { } LogicalGet::LogicalGet(idx_t table_index, TableFunction function, unique_ptr bind_data, - vector returned_types, vector returned_names, LogicalType rowid_type) + vector returned_types, vector returned_names) : LogicalOperator(LogicalOperatorType::LOGICAL_GET), table_index(table_index), function(std::move(function)), bind_data(std::move(bind_data)), returned_types(std::move(returned_types)), names(std::move(returned_names)), - extra_info(), rowid_type(std::move(rowid_type)) { + extra_info() { } optional_ptr LogicalGet::GetTable() const { @@ -48,10 +48,6 @@ InsertionOrderPreservingMap LogicalGet::ParamsToString() const { } result["Filters"] = filters_info; - if (extra_info.sample_options) { - result["Sample Method"] = "System: " + extra_info.sample_options->sample_size.ToString() + "%"; - } - if (!extra_info.file_filters.empty()) { result["File Filters"] = extra_info.file_filters; if (extra_info.filtered_files.IsValid() && extra_info.total_files.IsValid()) { @@ -61,33 +57,29 @@ InsertionOrderPreservingMap LogicalGet::ParamsToString() const { } if (function.to_string) { - TableFunctionToStringInput input(function, bind_data.get()); - auto to_string_result = function.to_string(input); - for (const auto &it : to_string_result) { - result[it.first] = it.second; - } + result["__text__"] = function.to_string(bind_data.get()); } SetParamsEstimatedCardinality(result); return result; } -void LogicalGet::SetColumnIds(vector &&column_ids) { +void LogicalGet::SetColumnIds(vector &&column_ids) { this->column_ids = std::move(column_ids); } void LogicalGet::AddColumnId(column_t column_id) { - column_ids.emplace_back(column_id); + column_ids.push_back(column_id); } void LogicalGet::ClearColumnIds() { column_ids.clear(); } -const vector &LogicalGet::GetColumnIds() const { +const vector &LogicalGet::GetColumnIds() const { return column_ids; } -vector &LogicalGet::GetMutableColumnIds() { +vector &LogicalGet::GetMutableColumnIds() { return column_ids; } @@ -120,24 +112,24 @@ vector LogicalGet::GetColumnBindings() { void LogicalGet::ResolveTypes() { if (column_ids.empty()) { - column_ids.emplace_back(COLUMN_IDENTIFIER_ROW_ID); + column_ids.push_back(COLUMN_IDENTIFIER_ROW_ID); } types.clear(); if (projection_ids.empty()) { for (auto &index : column_ids) { - if (index.IsRowIdColumn()) { - types.emplace_back(LogicalType(rowid_type)); + if (index == COLUMN_IDENTIFIER_ROW_ID) { + types.emplace_back(LogicalType::ROW_TYPE); } else { - types.push_back(returned_types[index.GetPrimaryIndex()]); + types.push_back(returned_types[index]); } } } else { for (auto &proj_index : projection_ids) { auto &index = column_ids[proj_index]; - if (index.IsRowIdColumn()) { - types.emplace_back(LogicalType(rowid_type)); + if (index == COLUMN_IDENTIFIER_ROW_ID) { + types.emplace_back(LogicalType::ROW_TYPE); } else { - types.push_back(returned_types[index.GetPrimaryIndex()]); + types.push_back(returned_types[index]); } } } @@ -174,7 +166,7 @@ void LogicalGet::Serialize(Serializer &serializer) const { serializer.WriteProperty(200, "table_index", table_index); serializer.WriteProperty(201, "returned_types", returned_types); serializer.WriteProperty(202, "names", names); - /* [Deleted] (vector) "column_ids" */ + serializer.WriteProperty(203, "column_ids", column_ids); serializer.WriteProperty(204, "projection_ids", projection_ids); serializer.WriteProperty(205, "table_filters", table_filters); FunctionSerializer::Serialize(serializer, function, bind_data.get()); @@ -187,17 +179,14 @@ void LogicalGet::Serialize(Serializer &serializer) const { serializer.WriteProperty(209, "input_table_names", input_table_names); } serializer.WriteProperty(210, "projected_input", projected_input); - serializer.WritePropertyWithDefault(211, "column_indexes", column_ids); } unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) { - vector legacy_column_ids; - auto result = unique_ptr(new LogicalGet()); deserializer.ReadProperty(200, "table_index", result->table_index); deserializer.ReadProperty(201, "returned_types", result->returned_types); deserializer.ReadProperty(202, "names", result->names); - deserializer.ReadPropertyWithDefault(203, "column_ids", legacy_column_ids); + deserializer.ReadProperty(203, "column_ids", result->column_ids); deserializer.ReadProperty(204, "projection_ids", result->projection_ids); deserializer.ReadProperty(205, "table_filters", result->table_filters); auto entry = FunctionSerializer::DeserializeBase( @@ -205,27 +194,13 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) result->function = entry.first; auto &function = result->function; auto has_serialize = entry.second; + unique_ptr bind_data; if (!has_serialize) { deserializer.ReadProperty(206, "parameters", result->parameters); deserializer.ReadProperty(207, "named_parameters", result->named_parameters); deserializer.ReadProperty(208, "input_table_types", result->input_table_types); deserializer.ReadProperty(209, "input_table_names", result->input_table_names); - } else { - bind_data = FunctionSerializer::FunctionDeserialize(deserializer, function); - } - deserializer.ReadProperty(210, "projected_input", result->projected_input); - deserializer.ReadPropertyWithDefault(211, "column_indexes", result->column_ids); - if (!legacy_column_ids.empty()) { - if (!result->column_ids.empty()) { - throw SerializationException( - "LogicalGet::Deserialize - either column_ids or column_indexes should be set - not both"); - } - for (auto &col_id : legacy_column_ids) { - result->column_ids.emplace_back(col_id); - } - } - if (!has_serialize) { TableFunctionRef empty_ref; TableFunctionBindInput input(result->parameters, result->named_parameters, result->input_table_types, result->input_table_names, function.function_info.get(), nullptr, result->function, @@ -239,22 +214,24 @@ unique_ptr LogicalGet::Deserialize(Deserializer &deserializer) bind_data = function.bind(deserializer.Get(), input, bind_return_types, bind_names); for (auto &col_id : result->column_ids) { - if (col_id.IsRowIdColumn()) { + if (IsRowIdColumnId(col_id)) { // rowid continue; } - auto idx = col_id.GetPrimaryIndex(); - auto &ret_type = result->returned_types[idx]; - auto &col_name = result->names[idx]; - if (bind_return_types[idx] != ret_type) { + auto &ret_type = result->returned_types[col_id]; + auto &col_name = result->names[col_id]; + if (bind_return_types[col_id] != ret_type) { throw SerializationException("Table function deserialization failure in function \"%s\" - column with " "name %s was serialized with type %s, but now has type %s", - function.name, col_name, ret_type, bind_return_types[idx]); + function.name, col_name, ret_type, bind_return_types[col_id]); } } result->returned_types = std::move(bind_return_types); + } else { + bind_data = FunctionSerializer::FunctionDeserialize(deserializer, function); } result->bind_data = std::move(bind_data); + deserializer.ReadProperty(210, "projected_input", result->projected_input); return std::move(result); } diff --git a/src/duckdb/src/planner/operator/logical_insert.cpp b/src/duckdb/src/planner/operator/logical_insert.cpp index 10f115697..dd5bf92aa 100644 --- a/src/duckdb/src/planner/operator/logical_insert.cpp +++ b/src/duckdb/src/planner/operator/logical_insert.cpp @@ -8,7 +8,7 @@ namespace duckdb { LogicalInsert::LogicalInsert(TableCatalogEntry &table, idx_t table_index) : LogicalOperator(LogicalOperatorType::LOGICAL_INSERT), table(table), table_index(table_index), return_chunk(false), - action_type(OnConflictAction::THROW), update_is_del_and_insert(false) { + action_type(OnConflictAction::THROW) { } LogicalInsert::LogicalInsert(ClientContext &context, const unique_ptr table_info) diff --git a/src/duckdb/src/planner/operator/logical_join.cpp b/src/duckdb/src/planner/operator/logical_join.cpp index 9545e6602..eacf7b8e7 100644 --- a/src/duckdb/src/planner/operator/logical_join.cpp +++ b/src/duckdb/src/planner/operator/logical_join.cpp @@ -58,7 +58,7 @@ void LogicalJoin::GetTableReferences(LogicalOperator &op, unordered_set & } void LogicalJoin::GetExpressionBindings(Expression &expr, unordered_set &bindings) { - if (expr.GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expr.type == ExpressionType::BOUND_COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(colref.depth == 0); bindings.insert(colref.binding.table_index); diff --git a/src/duckdb/src/planner/operator/logical_order.cpp b/src/duckdb/src/planner/operator/logical_order.cpp index bf904c3f3..78a0c357b 100644 --- a/src/duckdb/src/planner/operator/logical_order.cpp +++ b/src/duckdb/src/planner/operator/logical_order.cpp @@ -8,10 +8,15 @@ LogicalOrder::LogicalOrder(vector orders) vector LogicalOrder::GetColumnBindings() { auto child_bindings = children[0]->GetColumnBindings(); - if (!HasProjectionMap()) { + if (projections.empty()) { return child_bindings; } - return MapBindings(child_bindings, projection_map); + + vector result; + for (auto &col_idx : projections) { + result.push_back(child_bindings[col_idx]); + } + return result; } InsertionOrderPreservingMap LogicalOrder::ParamsToString() const { @@ -30,10 +35,12 @@ InsertionOrderPreservingMap LogicalOrder::ParamsToString() const { void LogicalOrder::ResolveTypes() { const auto child_types = children[0]->types; - if (!HasProjectionMap()) { + if (projections.empty()) { types = child_types; } else { - types = MapTypes(child_types, projection_map); + for (auto &col_idx : projections) { + types.push_back(child_types[col_idx]); + } } } diff --git a/src/duckdb/src/planner/operator/logical_top_n.cpp b/src/duckdb/src/planner/operator/logical_top_n.cpp index 098fcf1bb..53cb12727 100644 --- a/src/duckdb/src/planner/operator/logical_top_n.cpp +++ b/src/duckdb/src/planner/operator/logical_top_n.cpp @@ -2,13 +2,6 @@ namespace duckdb { -LogicalTopN::LogicalTopN(vector orders, idx_t limit, idx_t offset) - : LogicalOperator(LogicalOperatorType::LOGICAL_TOP_N), orders(std::move(orders)), limit(limit), offset(offset) { -} - -LogicalTopN::~LogicalTopN() { -} - idx_t LogicalTopN::EstimateCardinality(ClientContext &context) { auto child_cardinality = LogicalOperator::EstimateCardinality(context); if (child_cardinality < limit) { diff --git a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp index a297a7855..ac36e9eae 100644 --- a/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp +++ b/src/duckdb/src/planner/subquery/flatten_dependent_join.cpp @@ -3,7 +3,6 @@ #include "duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp" #include "duckdb/common/operator/add.hpp" #include "duckdb/function/aggregate/distributive_functions.hpp" -#include "duckdb/function/aggregate/distributive_function_utils.hpp" #include "duckdb/planner/binder.hpp" #include "duckdb/planner/expression/bound_aggregate_expression.hpp" #include "duckdb/planner/expression/list.hpp" @@ -100,7 +99,7 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoin(unique_ } bool SubqueryDependentFilter(Expression &expr) { - if (expr.GetExpressionClass() == ExpressionClass::BOUND_CONJUNCTION && + if (expr.expression_class == ExpressionClass::BOUND_CONJUNCTION && expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { auto &bound_conjunction = expr.Cast(); for (auto &child : bound_conjunction.children) { @@ -109,7 +108,7 @@ bool SubqueryDependentFilter(Expression &expr) { } } } - if (expr.GetExpressionClass() == ExpressionClass::BOUND_SUBQUERY) { + if (expr.expression_class == ExpressionClass::BOUND_SUBQUERY) { return true; } return false; @@ -241,7 +240,7 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal delim_data_offset = aggr.groups.size(); for (idx_t i = 0; i < correlated_columns.size(); i++) { auto &col = correlated_columns[i]; - auto first_aggregate = FirstFunctionGetter::GetFunction(col.type); + auto first_aggregate = FirstFun::GetFunction(col.type); auto colref = make_uniq( col.name, col.type, ColumnBinding(base_binding.table_index, base_binding.column_index + i)); vector> aggr_children; @@ -301,8 +300,7 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal D_ASSERT(aggr.expressions[i]->GetExpressionClass() == ExpressionClass::BOUND_AGGREGATE); auto &bound = aggr.expressions[i]->Cast(); vector arguments; - if (bound.function == CountFunctionBase::GetFunction() || - bound.function == CountStarFun::GetFunction()) { + if (bound.function == CountFun::GetFunction() || bound.function == CountStarFun::GetFunction()) { // have to replace this ColumnBinding with the CASE expression replacement_map[ColumnBinding(aggr.aggregate_index, i)] = i; } @@ -414,7 +412,7 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal return plan; } } else if (join.join_type == JoinType::RIGHT) { - // right outer join + // left outer join if (!left_has_correlation) { // only right has correlation: push into right plan->children[1] = PushDownDependentJoinInternal(std::move(plan->children[1]), @@ -450,7 +448,6 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal this->base_binding = left_binding; } else if (join.join_type == JoinType::RIGHT) { this->base_binding = right_binding; - delim_offset += plan->children[0]->GetColumnBindings().size(); } // add the correlated columns to the join conditions for (idx_t i = 0; i < correlated_columns.size(); i++) { @@ -621,29 +618,6 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal #endif plan->children[0] = PushDownDependentJoin(std::move(plan->children[0])); plan->children[1] = PushDownDependentJoin(std::move(plan->children[1])); - for (idx_t i = 0; i < plan->children.size(); i++) { - if (plan->children[i]->type == LogicalOperatorType::LOGICAL_CROSS_PRODUCT) { - auto proj_index = binder.GenerateTableIndex(); - auto bindings = plan->children[i]->GetColumnBindings(); - plan->children[i]->ResolveOperatorTypes(); - auto types = plan->children[i]->types; - vector> expressions; - expressions.reserve(bindings.size()); - D_ASSERT(bindings.size() == types.size()); - - // No column binding replaceent is needed because the parent operator is - // a setop which will immediately assign new bindings. - for (idx_t col_idx = 0; col_idx < bindings.size(); col_idx++) { - expressions.push_back(make_uniq(types[col_idx], bindings[col_idx])); - } - auto proj = make_uniq(proj_index, std::move(expressions)); - proj->children.push_back(std::move(plan->children[i])); - plan->children[i] = std::move(proj); - } - } - - // here we need to check the children. If they have reorderable bindings, you need to plan a projection - // on top that will guarantee the order of the bindings. #ifdef DEBUG D_ASSERT(plan->children[0]->GetColumnBindings().size() == plan->children[1]->GetColumnBindings().size()); plan->children[0]->ResolveOperatorTypes(); @@ -774,8 +748,6 @@ unique_ptr FlattenDependentJoins::PushDownDependentJoinInternal } case LogicalOperatorType::LOGICAL_SAMPLE: throw BinderException("Sampling in correlated subqueries is not (yet) supported"); - case LogicalOperatorType::LOGICAL_POSITIONAL_JOIN: - throw BinderException("Positional join in correlated subqueries is not (yet) supported"); default: throw InternalException("Logical operator type \"%s\" for dependent join", LogicalOperatorToString(plan->type)); } diff --git a/src/duckdb/src/planner/subquery/rewrite_correlated_expressions.cpp b/src/duckdb/src/planner/subquery/rewrite_correlated_expressions.cpp index 61c9c7ba2..00444dcfb 100644 --- a/src/duckdb/src/planner/subquery/rewrite_correlated_expressions.cpp +++ b/src/duckdb/src/planner/subquery/rewrite_correlated_expressions.cpp @@ -132,7 +132,7 @@ void RewriteCorrelatedRecursive::RewriteCorrelatedSubquery(Binder &binder, Bound } void RewriteCorrelatedRecursive::VisitExpression(unique_ptr &expression) { - if (expression->GetExpressionType() == ExpressionType::BOUND_COLUMN_REF) { + if (expression->type == ExpressionType::BOUND_COLUMN_REF) { // bound column reference auto &bound_colref = expression->Cast(); if (bound_colref.depth == 0) { @@ -148,7 +148,7 @@ void RewriteCorrelatedRecursive::VisitExpression(unique_ptr &express bound_colref.binding = ColumnBinding(base_binding.table_index, base_binding.column_index + entry->second); bound_colref.depth--; } - } else if (expression->GetExpressionType() == ExpressionType::SUBQUERY) { + } else if (expression->type == ExpressionType::SUBQUERY) { // we encountered another subquery: rewrite recursively auto &bound_subquery = expression->Cast(); RewriteCorrelatedSubquery(*bound_subquery.binder, *bound_subquery.subquery); diff --git a/src/duckdb/src/planner/table_binding.cpp b/src/duckdb/src/planner/table_binding.cpp index 455834a4b..7b9e65bc6 100644 --- a/src/duckdb/src/planner/table_binding.cpp +++ b/src/duckdb/src/planner/table_binding.cpp @@ -15,25 +15,20 @@ namespace duckdb { -Binding::Binding(BindingType binding_type, BindingAlias alias_p, vector coltypes, vector colnames, - idx_t index, LogicalType rowid_type) - : binding_type(binding_type), alias(std::move(alias_p)), index(index), types(std::move(coltypes)), - names(std::move(colnames)), rowid_type(std::move(rowid_type)) { +Binding::Binding(BindingType binding_type, const string &alias, vector coltypes, vector colnames, + idx_t index) + : binding_type(binding_type), alias(alias), index(index), types(std::move(coltypes)), names(std::move(colnames)) { D_ASSERT(types.size() == names.size()); for (idx_t i = 0; i < names.size(); i++) { auto &name = names[i]; D_ASSERT(!name.empty()); if (name_map.find(name) != name_map.end()) { - throw BinderException("table \"%s\" has duplicate column name \"%s\"", alias.GetAlias(), name); + throw BinderException("table \"%s\" has duplicate column name \"%s\"", alias, name); } name_map[name] = i; } } -string Binding::GetAlias() const { - return alias.GetAlias(); -} - bool Binding::TryGetBindingIndex(const string &column_name, column_t &result) { auto entry = name_map.find(column_name); if (entry == name_map.end()) { @@ -58,8 +53,8 @@ bool Binding::HasMatchingBinding(const string &column_name) { } ErrorData Binding::ColumnNotFoundError(const string &column_name) const { - return ErrorData(ExceptionType::BINDER, StringUtil::Format("Values list \"%s\" does not have a column named \"%s\"", - GetAlias(), column_name)); + return ErrorData(ExceptionType::BINDER, + StringUtil::Format("Values list \"%s\" does not have a column named \"%s\"", alias, column_name)); } BindResult Binding::Bind(ColumnRefExpression &colref, idx_t depth) { @@ -73,8 +68,8 @@ BindResult Binding::Bind(ColumnRefExpression &colref, idx_t depth) { binding.table_index = index; binding.column_index = column_index; LogicalType sql_type = types[column_index]; - if (colref.GetAlias().empty()) { - colref.SetAlias(names[column_index]); + if (colref.alias.empty()) { + colref.alias = names[column_index]; } return BindResult(make_uniq(colref.GetName(), sql_type, binding, depth)); } @@ -83,29 +78,9 @@ optional_ptr Binding::GetStandardEntry() { return nullptr; } -BindingAlias Binding::GetAlias(const string &explicit_alias, const StandardEntry &entry) { - if (!explicit_alias.empty()) { - return BindingAlias(explicit_alias); - } - // no explicit alias provided - generate from entry - return BindingAlias(entry); -} - -BindingAlias Binding::GetAlias(const string &explicit_alias, optional_ptr entry) { - if (!explicit_alias.empty()) { - return BindingAlias(explicit_alias); - } - if (!entry) { - throw InternalException("Binding::GetAlias called - but neither an alias nor an entry was provided"); - } - // no explicit alias provided - generate from entry - return BindingAlias(*entry); -} - EntryBinding::EntryBinding(const string &alias, vector types_p, vector names_p, idx_t index, StandardEntry &entry) - : Binding(BindingType::CATALOG_ENTRY, GetAlias(alias, entry), std::move(types_p), std::move(names_p), index), - entry(entry) { + : Binding(BindingType::CATALOG_ENTRY, alias, std::move(types_p), std::move(names_p), index), entry(entry) { } optional_ptr EntryBinding::GetStandardEntry() { @@ -113,10 +88,9 @@ optional_ptr EntryBinding::GetStandardEntry() { } TableBinding::TableBinding(const string &alias, vector types_p, vector names_p, - vector &bound_column_ids, optional_ptr entry, idx_t index, + vector &bound_column_ids, optional_ptr entry, idx_t index, bool add_row_id) - : Binding(BindingType::TABLE, GetAlias(alias, entry), std::move(types_p), std::move(names_p), index, - (add_row_id && entry) ? entry->Cast().GetRowIdType() : LogicalType::ROW_TYPE), + : Binding(BindingType::TABLE, alias, std::move(types_p), std::move(names_p), index), bound_column_ids(bound_column_ids), entry(entry) { if (add_row_id) { if (name_map.find("rowid") == name_map.end()) { @@ -127,7 +101,7 @@ TableBinding::TableBinding(const string &alias, vector types_p, vec static void ReplaceAliases(ParsedExpression &expr, const ColumnList &list, const unordered_map &alias_map) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(!colref.IsQualified()); auto &col_names = colref.column_names; @@ -137,24 +111,18 @@ static void ReplaceAliases(ParsedExpression &expr, const ColumnList &list, col_names = {alias}; } ParsedExpressionIterator::EnumerateChildren( - expr, [&](ParsedExpression &child) { ReplaceAliases(child, list, alias_map); }); + expr, [&](const ParsedExpression &child) { ReplaceAliases((ParsedExpression &)child, list, alias_map); }); } -static void BakeTableName(ParsedExpression &expr, const BindingAlias &binding_alias) { - if (expr.GetExpressionType() == ExpressionType::COLUMN_REF) { +static void BakeTableName(ParsedExpression &expr, const string &table_name) { + if (expr.type == ExpressionType::COLUMN_REF) { auto &colref = expr.Cast(); D_ASSERT(!colref.IsQualified()); auto &col_names = colref.column_names; - col_names.insert(col_names.begin(), binding_alias.GetAlias()); - if (!binding_alias.GetSchema().empty()) { - col_names.insert(col_names.begin(), binding_alias.GetSchema()); - } - if (!binding_alias.GetCatalog().empty()) { - col_names.insert(col_names.begin(), binding_alias.GetCatalog()); - } + col_names.insert(col_names.begin(), table_name); } - ParsedExpressionIterator::EnumerateChildren(expr, - [&](ParsedExpression &child) { BakeTableName(child, binding_alias); }); + ParsedExpressionIterator::EnumerateChildren( + expr, [&](const ParsedExpression &child) { BakeTableName((ParsedExpression &)child, table_name); }); } unique_ptr TableBinding::ExpandGeneratedColumn(const string &column_name) { @@ -178,16 +146,15 @@ unique_ptr TableBinding::ExpandGeneratedColumn(const string &c return (expression); } -const vector &TableBinding::GetBoundColumnIds() const { +const vector &TableBinding::GetBoundColumnIds() const { #ifdef DEBUG - unordered_set column_ids; - for (auto &col_id : bound_column_ids) { - idx_t id = col_id.IsRowIdColumn() ? DConstants::INVALID_INDEX : col_id.GetPrimaryIndex(); + unordered_set column_ids; + for (auto &id : bound_column_ids) { auto result = column_ids.insert(id); // assert that all entries in the bound_column_ids are unique D_ASSERT(result.second); auto it = std::find_if(name_map.begin(), name_map.end(), - [&](const std::pair &it) { return it.second == id; }); + [&](const std::pair &it) { return it.second == id; }); // assert that every id appears in the name_map D_ASSERT(it != name_map.end()); // the order that they appear in is not guaranteed to be sequential @@ -201,17 +168,13 @@ ColumnBinding TableBinding::GetColumnBinding(column_t column_index) { ColumnBinding binding; // Locate the column_id that matches the 'column_index' - binding.column_index = column_ids.size(); - for (idx_t i = 0; i < column_ids.size(); ++i) { - auto &col_id = column_ids[i]; - if (col_id.GetPrimaryIndex() == column_index) { - binding.column_index = i; - break; - } - } + auto it = std::find_if(column_ids.begin(), column_ids.end(), + [&](const column_t &id) -> bool { return id == column_index; }); + // Get the index of it + binding.column_index = NumericCast(std::distance(column_ids.begin(), it)); // If it wasn't found, add it - if (binding.column_index == column_ids.size()) { - column_ids.emplace_back(column_index); + if (it == column_ids.end()) { + column_ids.push_back(column_index); } binding.table_index = index; @@ -239,12 +202,12 @@ BindResult TableBinding::Bind(ColumnRefExpression &colref, idx_t depth) { // fetch the type of the column LogicalType col_type; if (column_index == COLUMN_IDENTIFIER_ROW_ID) { - col_type = LogicalType(rowid_type); + col_type = LogicalType::ROW_TYPE; } else { // normal column: fetch type from base column col_type = types[column_index]; - if (colref.GetAlias().empty()) { - colref.SetAlias(names[column_index]); + if (colref.alias.empty()) { + colref.alias = names[column_index]; } } ColumnBinding binding = GetColumnBinding(column_index); @@ -256,14 +219,13 @@ optional_ptr TableBinding::GetStandardEntry() { } ErrorData TableBinding::ColumnNotFoundError(const string &column_name) const { - auto candidate_message = StringUtil::CandidatesErrorMessage(names, column_name, "Candidate bindings: "); - return ErrorData(ExceptionType::BINDER, StringUtil::Format("Table \"%s\" does not have a column named \"%s\"\n%s", - alias.GetAlias(), column_name, candidate_message)); + return ErrorData(ExceptionType::BINDER, + StringUtil::Format("Table \"%s\" does not have a column named \"%s\"", alias, column_name)); } DummyBinding::DummyBinding(vector types, vector names, string dummy_name) - : Binding(BindingType::DUMMY, BindingAlias(DummyBinding::DUMMY_NAME + dummy_name), std::move(types), - std::move(names), DConstants::INVALID_INDEX), + : Binding(BindingType::DUMMY, DummyBinding::DUMMY_NAME + dummy_name, std::move(types), std::move(names), + DConstants::INVALID_INDEX), dummy_name(std::move(dummy_name)) { } @@ -294,7 +256,7 @@ unique_ptr DummyBinding::ParamToArg(ColumnRefExpression &colre throw InternalException("Column %s not found in macro", colref.GetColumnName()); } auto arg = (*arguments)[column_index]->Copy(); - arg->SetAlias(colref.GetAlias()); + arg->alias = colref.alias; return arg; } diff --git a/src/duckdb/src/planner/table_filter.cpp b/src/duckdb/src/planner/table_filter.cpp index f8544102d..636a7671d 100644 --- a/src/duckdb/src/planner/table_filter.cpp +++ b/src/duckdb/src/planner/table_filter.cpp @@ -7,8 +7,7 @@ namespace duckdb { -void TableFilterSet::PushFilter(const ColumnIndex &col_idx, unique_ptr filter) { - auto column_index = col_idx.GetPrimaryIndex(); +void TableFilterSet::PushFilter(idx_t column_index, unique_ptr filter) { auto entry = filters.find(column_index); if (entry == filters.end()) { // no filter yet: push the filter directly @@ -47,7 +46,7 @@ void DynamicTableFilterSet::PushFilter(const PhysicalOperator &op, idx_t column_ } else { filter_ptr = entry->second.get(); } - filter_ptr->PushFilter(ColumnIndex(column_index), std::move(filter)); + filter_ptr->PushFilter(column_index, std::move(filter)); } bool DynamicTableFilterSet::HasFilters() const { @@ -62,12 +61,16 @@ DynamicTableFilterSet::GetFinalTableFilters(const PhysicalTableScan &scan, auto result = make_uniq(); if (existing_filters) { for (auto &entry : existing_filters->filters) { - result->PushFilter(ColumnIndex(entry.first), entry.second->Copy()); + result->PushFilter(entry.first, entry.second->Copy()); } } for (auto &entry : filters) { for (auto &filter : entry.second->filters) { - result->PushFilter(ColumnIndex(filter.first), filter.second->Copy()); + if (IsRowIdColumnId(scan.column_ids[filter.first])) { + // skip row id filters + continue; + } + result->PushFilter(filter.first, filter.second->Copy()); } } if (result->filters.empty()) { diff --git a/src/duckdb/src/storage/arena_allocator.cpp b/src/duckdb/src/storage/arena_allocator.cpp index 000444f75..a67eeb286 100644 --- a/src/duckdb/src/storage/arena_allocator.cpp +++ b/src/duckdb/src/storage/arena_allocator.cpp @@ -107,13 +107,12 @@ data_ptr_t ArenaAllocator::Reallocate(data_ptr_t pointer, idx_t old_size, idx_t return pointer; } - const auto head_ptr = head->data.get() + head->current_position - old_size; - int64_t current_position = NumericCast(head->current_position); + auto head_ptr = head->data.get() + head->current_position; int64_t diff = NumericCast(size) - NumericCast(old_size); - if (pointer == head_ptr && - (size < old_size || current_position + diff <= NumericCast(head->maximum_size))) { + if (pointer == head_ptr && (size < old_size || NumericCast(head->current_position) + diff <= + NumericCast(head->maximum_size))) { // passed pointer is the head pointer, and the diff fits on the current chunk - head->current_position = NumericCast(current_position + diff); + head->current_position += NumericCast(diff); return pointer; } else { // allocate new memory diff --git a/src/duckdb/src/storage/buffer/block_handle.cpp b/src/duckdb/src/storage/buffer/block_handle.cpp index 1d1c333b3..9523b2962 100644 --- a/src/duckdb/src/storage/buffer/block_handle.cpp +++ b/src/duckdb/src/storage/buffer/block_handle.cpp @@ -10,10 +10,9 @@ namespace duckdb { BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag) - : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), buffer_type(FileBufferType::BLOCK), - buffer(nullptr), eviction_seq_num(0), destroy_buffer_upon(DestroyBufferUpon::BLOCK), - memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), unswizzled(nullptr), - eviction_queue_idx(DConstants::INVALID_INDEX) { + : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), buffer(nullptr), eviction_seq_num(0), + destroy_buffer_upon(DestroyBufferUpon::BLOCK), memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), + unswizzled(nullptr) { eviction_seq_num = 0; state = BlockState::BLOCK_UNLOADED; memory_usage = block_manager.GetBlockAllocSize(); @@ -22,10 +21,9 @@ BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, Mem BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, MemoryTag tag, unique_ptr buffer_p, DestroyBufferUpon destroy_buffer_upon_p, idx_t block_size, BufferPoolReservation &&reservation) - : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), buffer_type(buffer_p->GetBufferType()), - eviction_seq_num(0), destroy_buffer_upon(destroy_buffer_upon_p), - memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), unswizzled(nullptr), - eviction_queue_idx(DConstants::INVALID_INDEX) { + : block_manager(block_manager), readers(0), block_id(block_id_p), tag(tag), eviction_seq_num(0), + destroy_buffer_upon(destroy_buffer_upon_p), memory_charge(tag, block_manager.buffer_manager.GetBufferPool()), + unswizzled(nullptr) { buffer = std::move(buffer_p); state = BlockState::BLOCK_LOADED; memory_usage = block_size; @@ -35,11 +33,10 @@ BlockHandle::BlockHandle(BlockManager &block_manager, block_id_t block_id_p, Mem BlockHandle::~BlockHandle() { // NOLINT: allow internal exceptions // being destroyed, so any unswizzled pointers are just binary junk now. unswizzled = nullptr; - D_ASSERT(!buffer || buffer->GetBufferType() == buffer_type); - if (buffer && buffer_type != FileBufferType::TINY_BUFFER) { + if (buffer && buffer->type != FileBufferType::TINY_BUFFER) { // we kill the latest version in the eviction queue auto &buffer_manager = block_manager.buffer_manager; - buffer_manager.GetBufferPool().IncrementDeadNodes(*this); + buffer_manager.GetBufferPool().IncrementDeadNodes(buffer->type); } // no references remain to this block: erase @@ -59,7 +56,7 @@ unique_ptr AllocateBlock(BlockManager &block_manager, unique_ptrGetBufferType() == FileBufferType::BLOCK) { + if (reusable_buffer->type == FileBufferType::BLOCK) { // we can reuse the buffer entirely auto &block = reinterpret_cast(*reusable_buffer); block.id = block_id; @@ -74,71 +71,21 @@ unique_ptr AllocateBlock(BlockManager &block_manager, unique_ptr(delta); - memory_charge.Resize(memory_usage); -} - -unique_ptr &BlockHandle::GetBuffer(BlockLock &l) { - VerifyMutex(l); - return buffer; -} - -void BlockHandle::VerifyMutex(BlockLock &l) const { - D_ASSERT(l.owns_lock()); - D_ASSERT(l.mutex() == &lock); -} - -BufferPoolReservation &BlockHandle::GetMemoryCharge(BlockLock &l) { - VerifyMutex(l); - return memory_charge; -} - -void BlockHandle::MergeMemoryReservation(BlockLock &l, BufferPoolReservation reservation) { - VerifyMutex(l); - memory_charge.Merge(std::move(reservation)); -} - -void BlockHandle::ResizeMemory(BlockLock &l, idx_t alloc_size) { - VerifyMutex(l); - memory_charge.Resize(alloc_size); -} - -void BlockHandle::ResizeBuffer(BlockLock &l, idx_t block_size, int64_t memory_delta) { - VerifyMutex(l); - - D_ASSERT(buffer); - // resize and adjust current memory - buffer->Resize(block_size); - memory_usage = NumericCast(NumericCast(memory_usage.load()) + memory_delta); - D_ASSERT(memory_usage == buffer->AllocSize()); -} - -BufferHandle BlockHandle::LoadFromBuffer(BlockLock &l, data_ptr_t data, unique_ptr reusable_buffer, - BufferPoolReservation reservation) { - VerifyMutex(l); - +BufferHandle BlockHandle::LoadFromBuffer(data_ptr_t data, unique_ptr reusable_buffer) { D_ASSERT(state != BlockState::BLOCK_LOADED); - D_ASSERT(readers == 0); // copy over the data into the block from the file buffer auto block = AllocateBlock(block_manager, std::move(reusable_buffer), block_id); memcpy(block->InternalBuffer(), data, block->AllocSize()); buffer = std::move(block); state = BlockState::BLOCK_LOADED; - readers = 1; - memory_charge = std::move(reservation); - return BufferHandle(shared_from_this(), buffer.get()); + return BufferHandle(shared_from_this()); } BufferHandle BlockHandle::Load(unique_ptr reusable_buffer) { if (state == BlockState::BLOCK_LOADED) { // already loaded D_ASSERT(buffer); - ++readers; - return BufferHandle(shared_from_this(), buffer.get()); + return BufferHandle(shared_from_this()); } if (block_id < MAXIMUM_BLOCK) { @@ -153,13 +100,10 @@ BufferHandle BlockHandle::Load(unique_ptr reusable_buffer) { } } state = BlockState::BLOCK_LOADED; - readers = 1; - return BufferHandle(shared_from_this(), buffer.get()); + return BufferHandle(shared_from_this()); } -unique_ptr BlockHandle::UnloadAndTakeBlock(BlockLock &lock) { - VerifyMutex(lock); - +unique_ptr BlockHandle::UnloadAndTakeBlock() { if (state == BlockState::BLOCK_UNLOADED) { // already unloaded: nothing to do return nullptr; @@ -176,12 +120,12 @@ unique_ptr BlockHandle::UnloadAndTakeBlock(BlockLock &lock) { return std::move(buffer); } -void BlockHandle::Unload(BlockLock &lock) { - auto block = UnloadAndTakeBlock(lock); +void BlockHandle::Unload() { + auto block = UnloadAndTakeBlock(); block.reset(); } -bool BlockHandle::CanUnload() const { +bool BlockHandle::CanUnload() { if (state == BlockState::BLOCK_UNLOADED) { // already unloaded return false; @@ -201,19 +145,4 @@ bool BlockHandle::CanUnload() const { return true; } -void BlockHandle::ConvertToPersistent(BlockLock &l, BlockHandle &new_block, unique_ptr new_buffer) { - VerifyMutex(l); - - // move the data from the old block into data for the new block - new_block.state = BlockState::BLOCK_LOADED; - new_block.buffer = std::move(new_buffer); - new_block.memory_usage = memory_usage.load(); - new_block.memory_charge = std::move(memory_charge); - - // clear out the buffer data from this block - buffer.reset(); - state = BlockState::BLOCK_UNLOADED; - memory_usage = 0; -} - } // namespace duckdb diff --git a/src/duckdb/src/storage/buffer/block_manager.cpp b/src/duckdb/src/storage/buffer/block_manager.cpp index 1ee4fb6da..22cb54d13 100644 --- a/src/duckdb/src/storage/buffer/block_manager.cpp +++ b/src/duckdb/src/storage/buffer/block_manager.cpp @@ -30,52 +30,44 @@ shared_ptr BlockManager::RegisterBlock(block_id_t block_id) { return result; } -shared_ptr BlockManager::ConvertToPersistent(block_id_t block_id, shared_ptr old_block, - BufferHandle old_handle) { - // register a block with the new block id - auto new_block = RegisterBlock(block_id); - D_ASSERT(new_block->GetState() == BlockState::BLOCK_UNLOADED); - D_ASSERT(new_block->Readers() == 0); - - auto lock = old_block->GetLock(); - D_ASSERT(old_block->GetState() == BlockState::BLOCK_LOADED); - D_ASSERT(old_block->GetBuffer(lock)); - if (old_block->Readers() > 1) { - throw InternalException("BlockManager::ConvertToPersistent - cannot be called for block %d as old_block has " - "multiple readers active", - block_id); - } +shared_ptr BlockManager::ConvertToPersistent(block_id_t block_id, shared_ptr old_block) { + // pin the old block to ensure we have it loaded in memory + auto old_handle = buffer_manager.Pin(old_block); + D_ASSERT(old_block->state == BlockState::BLOCK_LOADED); + D_ASSERT(old_block->buffer); // Temp buffers can be larger than the storage block size. // But persistent buffers cannot. - D_ASSERT(old_block->GetBuffer(lock)->AllocSize() <= GetBlockAllocSize()); - - // convert the buffer to a block - auto converted_buffer = ConvertBlock(block_id, *old_block->GetBuffer(lock)); - - // persist the new block to disk - Write(*converted_buffer, block_id); - - // now convert the actual block - old_block->ConvertToPersistent(lock, *new_block, std::move(converted_buffer)); + D_ASSERT(old_block->buffer->AllocSize() <= GetBlockAllocSize()); - // destroy the old buffer - lock.unlock(); + // register a block with the new block id + auto new_block = RegisterBlock(block_id); + D_ASSERT(new_block->state == BlockState::BLOCK_UNLOADED); + D_ASSERT(new_block->readers == 0); + + // move the data from the old block into data for the new block + new_block->state = BlockState::BLOCK_LOADED; + new_block->buffer = ConvertBlock(block_id, *old_block->buffer); + new_block->memory_usage = old_block->memory_usage; + new_block->memory_charge = std::move(old_block->memory_charge); + + // clear the old buffer and unload it + old_block->buffer.reset(); + old_block->state = BlockState::BLOCK_UNLOADED; + old_block->memory_usage = 0; old_handle.Destroy(); old_block.reset(); + // persist the new block to disk + Write(*new_block->buffer, block_id); + // potentially purge the queue auto purge_queue = buffer_manager.GetBufferPool().AddToEvictionQueue(new_block); if (purge_queue) { - buffer_manager.GetBufferPool().PurgeQueue(*new_block); + buffer_manager.GetBufferPool().PurgeQueue(new_block->buffer->type); } - return new_block; -} -shared_ptr BlockManager::ConvertToPersistent(block_id_t block_id, shared_ptr old_block) { - // pin the old block to ensure we have it loaded in memory - auto handle = buffer_manager.Pin(old_block); - return ConvertToPersistent(block_id, std::move(old_block), std::move(handle)); + return new_block; } void BlockManager::UnregisterBlock(block_id_t id) { diff --git a/src/duckdb/src/storage/buffer/buffer_handle.cpp b/src/duckdb/src/storage/buffer/buffer_handle.cpp index a0a5d20c9..29c80e07a 100644 --- a/src/duckdb/src/storage/buffer/buffer_handle.cpp +++ b/src/duckdb/src/storage/buffer/buffer_handle.cpp @@ -7,8 +7,8 @@ namespace duckdb { BufferHandle::BufferHandle() : handle(nullptr), node(nullptr) { } -BufferHandle::BufferHandle(shared_ptr handle_p, optional_ptr node_p) - : handle(std::move(handle_p)), node(node_p) { +BufferHandle::BufferHandle(shared_ptr handle_p) + : handle(std::move(handle_p)), node(handle ? handle->buffer.get() : nullptr) { } BufferHandle::BufferHandle(BufferHandle &&other) noexcept : node(nullptr) { diff --git a/src/duckdb/src/storage/buffer/buffer_pool.cpp b/src/duckdb/src/storage/buffer/buffer_pool.cpp index 867e88ec1..30d6b648b 100644 --- a/src/duckdb/src/storage/buffer/buffer_pool.cpp +++ b/src/duckdb/src/storage/buffer/buffer_pool.cpp @@ -16,7 +16,7 @@ BufferEvictionNode::BufferEvictionNode(weak_ptr handle_p, idx_t evi } bool BufferEvictionNode::CanUnload(BlockHandle &handle_p) { - if (handle_sequence_number != handle_p.EvictionSequenceNumber()) { + if (handle_sequence_number != handle_p.eviction_seq_num) { // handle was used in between return false; } @@ -41,8 +41,7 @@ typedef duckdb_moodycamel::ConcurrentQueue eviction_queue_t; struct EvictionQueue { public: - explicit EvictionQueue(const FileBufferType file_buffer_type_p) - : file_buffer_type(file_buffer_type_p), evict_queue_insertions(0), total_dead_nodes(0) { + EvictionQueue() : evict_queue_insertions(0), total_dead_nodes(0) { } public: @@ -70,8 +69,6 @@ struct EvictionQueue { void PurgeIteration(const idx_t purge_size); public: - //! The type of the buffers in this queue - const FileBufferType file_buffer_type; //! The concurrent queue eviction_queue_t q; @@ -199,34 +196,30 @@ void EvictionQueue::PurgeIteration(const idx_t purge_size) { BufferPool::BufferPool(idx_t maximum_memory, bool track_eviction_timestamps, idx_t allocator_bulk_deallocation_flush_threshold) - : eviction_queue_sizes({BLOCK_QUEUE_SIZE, MANAGED_BUFFER_QUEUE_SIZE, TINY_BUFFER_QUEUE_SIZE}), - maximum_memory(maximum_memory), + : maximum_memory(maximum_memory), allocator_bulk_deallocation_flush_threshold(allocator_bulk_deallocation_flush_threshold), track_eviction_timestamps(track_eviction_timestamps), temporary_memory_manager(make_uniq()) { - for (uint8_t type_idx = 0; type_idx < FILE_BUFFER_TYPE_COUNT; type_idx++) { - const auto type = static_cast(type_idx + 1); - const auto &type_queue_size = eviction_queue_sizes[type_idx]; - for (idx_t queue_idx = 0; queue_idx < type_queue_size; queue_idx++) { - queues.push_back(make_uniq(type)); - } + queues.reserve(FILE_BUFFER_TYPE_COUNT); + for (idx_t i = 0; i < FILE_BUFFER_TYPE_COUNT; i++) { + queues.push_back(make_uniq()); } } BufferPool::~BufferPool() { } bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { - auto &queue = GetEvictionQueueForBlockHandle(*handle); + auto &queue = GetEvictionQueueForType(handle->buffer->type); // The block handle is locked during this operation (Unpin), // or the block handle is still a local variable (ConvertToPersistent) - D_ASSERT(handle->Readers() == 0); - auto ts = handle->NextEvictionSequenceNumber(); + D_ASSERT(handle->readers == 0); + auto ts = ++handle->eviction_seq_num; if (track_eviction_timestamps) { - handle->SetLRUTimestamp( + handle->lru_timestamp_msec = std::chrono::time_point_cast(std::chrono::steady_clock::now()) .time_since_epoch() - .count()); + .count(); } if (ts != 1) { @@ -234,37 +227,16 @@ bool BufferPool::AddToEvictionQueue(shared_ptr &handle) { queue.IncrementDeadNodes(); } - // Get the eviction queue for the block and add it + // Get the eviction queue for the buffer type and add it return queue.AddToEvictionQueue(BufferEvictionNode(weak_ptr(handle), ts)); } -EvictionQueue &BufferPool::GetEvictionQueueForBlockHandle(const BlockHandle &handle) { - const auto &handle_buffer_type = handle.GetBufferType(); - - // Get offset into eviction queues for this FileBufferType - idx_t queue_index = 0; - for (uint8_t type_idx = 0; type_idx < FILE_BUFFER_TYPE_COUNT; type_idx++) { - const auto queue_buffer_type = static_cast(type_idx + 1); - if (handle_buffer_type == queue_buffer_type) { - break; - } - const auto &type_queue_size = eviction_queue_sizes[type_idx]; - queue_index += type_queue_size; - } - - const auto &queue_size = eviction_queue_sizes[static_cast(handle_buffer_type) - 1]; - // Adjust if eviction_queue_idx is set (idx == 0 -> add at back, idx >= queue_size -> add at front) - auto eviction_queue_idx = handle.GetEvictionQueueIndex(); - if (eviction_queue_idx < queue_size) { - queue_index += queue_size - eviction_queue_idx - 1; - } - - D_ASSERT(queues[queue_index]->file_buffer_type == handle_buffer_type); - return *queues[queue_index]; +EvictionQueue &BufferPool::GetEvictionQueueForType(FileBufferType type) { + return *queues[uint8_t(type) - 1]; } -void BufferPool::IncrementDeadNodes(const BlockHandle &handle) { - GetEvictionQueueForBlockHandle(handle).IncrementDeadNodes(); +void BufferPool::IncrementDeadNodes(FileBufferType type) { + GetEvictionQueueForType(type).IncrementDeadNodes(); } void BufferPool::UpdateUsedMemory(MemoryTag tag, int64_t size) { @@ -289,14 +261,23 @@ TemporaryMemoryManager &BufferPool::GetTemporaryMemoryManager() { BufferPool::EvictionResult BufferPool::EvictBlocks(MemoryTag tag, idx_t extra_memory, idx_t memory_limit, unique_ptr *buffer) { - for (auto &queue : queues) { - auto block_result = EvictBlocksInternal(*queue, tag, extra_memory, memory_limit, buffer); - if (block_result.success || RefersToSameObject(*queue, *queues.back())) { - return block_result; // Return upon success or upon last queue - } + // First, we try to evict persistent table data + auto block_result = + EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::BLOCK), tag, extra_memory, memory_limit, buffer); + if (block_result.success) { + return block_result; } - // This can never happen since we always return when i == 1. Exception to silence compiler warning - throw InternalException("Exited BufferPool::EvictBlocksInternal without obtaining BufferPool::EvictionResult"); + + // If that does not succeed, we try to evict temporary data + auto managed_buffer_result = EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::MANAGED_BUFFER), tag, + extra_memory, memory_limit, buffer); + if (managed_buffer_result.success) { + return managed_buffer_result; + } + + // Finally, we try to evict tiny buffers + return EvictBlocksInternal(GetEvictionQueueForType(FileBufferType::TINY_BUFFER), tag, extra_memory, memory_limit, + buffer); } BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, MemoryTag tag, idx_t extra_memory, @@ -311,17 +292,17 @@ BufferPool::EvictionResult BufferPool::EvictBlocksInternal(EvictionQueue &queue, return {true, std::move(r)}; } - queue.IterateUnloadableBlocks([&](BufferEvictionNode &, const shared_ptr &handle, BlockLock &lock) { + queue.IterateUnloadableBlocks([&](BufferEvictionNode &, const shared_ptr &handle) { // hooray, we can unload the block - if (buffer && handle->GetBuffer(lock)->AllocSize() == extra_memory) { + if (buffer && handle->buffer->AllocSize() == extra_memory) { // we can re-use the memory directly - *buffer = handle->UnloadAndTakeBlock(lock); + *buffer = handle->UnloadAndTakeBlock(); found = true; return false; } // release the memory and mark the block as unloaded - handle->Unload(lock); + handle->Unload(); if (memory_usage.GetUsedMemory(MemoryUsageCaches::NO_FLUSH) <= memory_limit) { found = true; @@ -355,17 +336,15 @@ idx_t BufferPool::PurgeAgedBlocks(uint32_t max_age_sec) { idx_t BufferPool::PurgeAgedBlocksInternal(EvictionQueue &queue, uint32_t max_age_sec, int64_t now, int64_t limit) { idx_t purged_bytes = 0; - queue.IterateUnloadableBlocks( - [&](BufferEvictionNode &node, const shared_ptr &handle, BlockLock &lock) { - // We will unload this block regardless. But stop the iteration immediately afterward if this - // block is younger than the age threshold. - auto lru_timestamp_msec = handle->GetLRUTimestamp(); - bool is_fresh = lru_timestamp_msec >= limit && lru_timestamp_msec <= now; - purged_bytes += handle->GetMemoryUsage(); - handle->Unload(lock); - // Return false to stop iterating if the current block is_fresh - return !is_fresh; - }); + queue.IterateUnloadableBlocks([&](BufferEvictionNode &node, const shared_ptr &handle) { + // We will unload this block regardless. But stop the iteration immediately afterward if this + // block is younger than the age threshold. + bool is_fresh = handle->lru_timestamp_msec >= limit && handle->lru_timestamp_msec <= now; + purged_bytes += handle->GetMemoryUsage(); + handle->Unload(); + // Return false to stop iterating if the current block is_fresh + return !is_fresh; + }); return purged_bytes; } @@ -390,21 +369,21 @@ void EvictionQueue::IterateUnloadableBlocks(FN fn) { } // we might be able to free this block: grab the mutex and check if we can free it - auto lock = handle->GetLock(); + lock_guard lock(handle->lock); if (!node.CanUnload(*handle)) { // something changed in the mean-time, bail out DecrementDeadNodes(); continue; } - if (!fn(node, handle, lock)) { + if (!fn(node, handle)) { break; } } } -void BufferPool::PurgeQueue(const BlockHandle &block) { - GetEvictionQueueForBlockHandle(block).Purge(); +void BufferPool::PurgeQueue(FileBufferType type) { + GetEvictionQueueForType(type).Purge(); } void BufferPool::SetLimit(idx_t limit, const char *exception_postscript) { diff --git a/src/duckdb/src/storage/buffer_manager.cpp b/src/duckdb/src/storage/buffer_manager.cpp index 1ff33caa4..c758fae84 100644 --- a/src/duckdb/src/storage/buffer_manager.cpp +++ b/src/duckdb/src/storage/buffer_manager.cpp @@ -13,10 +13,6 @@ shared_ptr BufferManager::RegisterTransientMemory(const idx_t size, } shared_ptr BufferManager::RegisterSmallMemory(const idx_t size) { - return RegisterSmallMemory(MemoryTag::BASE_TABLE, size); -} - -shared_ptr BufferManager::RegisterSmallMemory(MemoryTag tag, const idx_t size) { throw NotImplementedException("This type of BufferManager can not create 'small-memory' blocks"); } diff --git a/src/duckdb/src/storage/checkpoint_manager.cpp b/src/duckdb/src/storage/checkpoint_manager.cpp index f28bdc454..cd46862ee 100644 --- a/src/duckdb/src/storage/checkpoint_manager.cpp +++ b/src/duckdb/src/storage/checkpoint_manager.cpp @@ -30,7 +30,6 @@ #include "duckdb/storage/table/column_checkpoint_state.hpp" #include "duckdb/transaction/meta_transaction.hpp" #include "duckdb/transaction/transaction_manager.hpp" -#include "duckdb/catalog/dependency_manager.hpp" namespace duckdb { @@ -150,14 +149,6 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { // we scan the set of committed schemas auto &catalog = Catalog::GetCatalog(db).Cast(); catalog.ScanSchemas([&](SchemaCatalogEntry &entry) { schemas.push_back(entry); }); - - catalog_entry_vector_t catalog_entries; - D_ASSERT(catalog.IsDuckCatalog()); - - auto &dependency_manager = *catalog.GetDependencyManager(); - catalog_entries = GetCatalogEntries(schemas); - dependency_manager.ReorderEntries(catalog_entries); - // write the actual data into the database // Create a serializer to write the checkpoint data @@ -178,6 +169,7 @@ void SingleFileCheckpointWriter::CreateCheckpoint() { ] } */ + auto catalog_entries = GetCatalogEntries(schemas); SerializationOptions serialization_options; serialization_options.serialization_compatibility = config.options.serialization_compatibility; @@ -450,12 +442,7 @@ void CheckpointReader::ReadIndex(CatalogTransaction transaction, Deserializer &d // look for the table in the catalog auto &schema = catalog.GetSchema(transaction, create_info->schema); - auto catalog_table = schema.GetEntry(transaction, CatalogType::TABLE_ENTRY, info.table); - if (!catalog_table) { - // See internal issue 3663. - throw IOException("corrupt database file - index entry without table entry"); - } - auto &table = catalog_table->Cast(); + auto &table = schema.GetEntry(transaction, CatalogType::TABLE_ENTRY, info.table)->Cast(); // we also need to make sure the index type is loaded // backwards compatibility: @@ -467,7 +454,6 @@ void CheckpointReader::ReadIndex(CatalogTransaction transaction, Deserializer &d // now we can look for the index in the catalog and assign the table info auto &index = schema.CreateIndex(transaction, info, table)->Cast(); auto &data_table = table.GetStorage(); - auto &table_info = data_table.GetDataTableInfo(); IndexStorageInfo index_storage_info; if (root_block_pointer.IsValid()) { @@ -477,7 +463,7 @@ void CheckpointReader::ReadIndex(CatalogTransaction transaction, Deserializer &d } else { // Read the matching index storage info. - for (auto const &elem : table_info->GetIndexStorageInfo()) { + for (auto const &elem : data_table.GetDataTableInfo()->GetIndexStorageInfo()) { if (elem.name == index.name) { index_storage_info = elem; break; @@ -485,13 +471,12 @@ void CheckpointReader::ReadIndex(CatalogTransaction transaction, Deserializer &d } } - D_ASSERT(index_storage_info.IsValid()); - D_ASSERT(!index_storage_info.name.empty()); + D_ASSERT(index_storage_info.IsValid() && !index_storage_info.name.empty()); // Create an unbound index and add it to the table. auto unbound_index = make_uniq(std::move(create_info), index_storage_info, TableIOManager::Get(data_table), data_table.db); - table_info->GetIndexes().AddIndex(std::move(unbound_index)); + data_table.GetDataTableInfo()->GetIndexes().AddIndex(std::move(unbound_index)); } //===--------------------------------------------------------------------===// @@ -553,10 +538,6 @@ void CheckpointReader::ReadTable(CatalogTransaction transaction, Deserializer &d auto &schema = catalog.GetSchema(transaction, info->schema); auto bound_info = Binder::BindCreateTableCheckpoint(std::move(info), schema); - for (auto &dep : bound_info->Base().dependencies.Set()) { - bound_info->dependencies.AddDependency(dep); - } - // now read the actual table data and place it into the CreateTableInfo ReadTableData(transaction, deserializer, *bound_info); diff --git a/src/duckdb/src/storage/compression/bitpacking.cpp b/src/duckdb/src/storage/compression/bitpacking.cpp index af2e35c2d..7561a260f 100644 --- a/src/duckdb/src/storage/compression/bitpacking.cpp +++ b/src/duckdb/src/storage/compression/bitpacking.cpp @@ -377,18 +377,18 @@ idx_t BitpackingFinalAnalyze(AnalyzeState &state) { template ::type> struct BitpackingCompressState : public CompressionState { public: - explicit BitpackingCompressState(ColumnDataCheckpointData &checkpoint_data, const CompressionInfo &info) - : CompressionState(info), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_BITPACKING)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); + explicit BitpackingCompressState(ColumnDataCheckpointer &checkpointer, const CompressionInfo &info) + : CompressionState(info), checkpointer(checkpointer), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_BITPACKING)) { + CreateEmptySegment(checkpointer.GetRowGroup().start); state.data_ptr = reinterpret_cast(this); - auto &config = DBConfig::GetConfig(checkpoint_data.GetDatabase()); + auto &config = DBConfig::GetConfig(checkpointer.GetDatabase()); state.mode = config.options.force_bitpacking_mode; } - ColumnDataCheckpointData &checkpoint_data; + ColumnDataCheckpointer &checkpointer; CompressionFunction &function; unique_ptr current_segment; BufferHandle handle; @@ -495,11 +495,12 @@ struct BitpackingCompressState : public CompressionState { } void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); + auto compressed_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); + compressed_segment->function = function; current_segment = std::move(compressed_segment); auto &buffer_manager = BufferManager::GetBufferManager(db); @@ -528,7 +529,7 @@ struct BitpackingCompressState : public CompressionState { } void FlushSegment() { - auto &state = checkpoint_data.GetCheckpointState(); + auto &state = checkpointer.GetCheckpointState(); auto base_ptr = handle.Ptr(); // Compact the segment by moving the metadata next to the data. @@ -551,8 +552,9 @@ struct BitpackingCompressState : public CompressionState { // Store the offset of the metadata of the first group (which is at the highest address). Store(metadata_offset + metadata_size, base_ptr); + handle.Destroy(); - state.FlushSegment(std::move(current_segment), std::move(handle), total_segment_size); + state.FlushSegment(std::move(current_segment), total_segment_size); } void Finalize() { @@ -563,9 +565,9 @@ struct BitpackingCompressState : public CompressionState { }; template -unique_ptr BitpackingInitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr BitpackingInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { - return make_uniq>(checkpoint_data, state->info); + return make_uniq>(checkpointer, state->info); } template diff --git a/src/duckdb/src/storage/compression/dictionary/analyze.cpp b/src/duckdb/src/storage/compression/dictionary/analyze.cpp deleted file mode 100644 index 3d12bc2e1..000000000 --- a/src/duckdb/src/storage/compression/dictionary/analyze.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "duckdb/storage/compression/dictionary/analyze.hpp" - -namespace duckdb { - -DictionaryAnalyzeState::DictionaryAnalyzeState(const CompressionInfo &info) - : DictionaryCompressionState(info), segment_count(0), current_tuple_count(0), current_unique_count(0), - current_dict_size(0), current_width(0), next_width(0) { -} - -bool DictionaryAnalyzeState::LookupString(string_t str) { - return current_set.count(str); -} - -void DictionaryAnalyzeState::AddNewString(string_t str) { - current_tuple_count++; - current_unique_count++; - current_dict_size += str.GetSize(); - if (str.IsInlined()) { - current_set.insert(str); - } else { - current_set.insert(heap.AddBlob(str)); - } - current_width = next_width; -} - -void DictionaryAnalyzeState::AddLastLookup() { - current_tuple_count++; -} - -void DictionaryAnalyzeState::AddNull() { - current_tuple_count++; -} - -bool DictionaryAnalyzeState::CalculateSpaceRequirements(bool new_string, idx_t string_size) { - if (!new_string) { - return DictionaryCompression::HasEnoughSpace(current_tuple_count + 1, current_unique_count, current_dict_size, - current_width, info.GetBlockSize()); - } - next_width = BitpackingPrimitives::MinimumBitWidth(current_unique_count + 2); // 1 for null, one for new string - return DictionaryCompression::HasEnoughSpace(current_tuple_count + 1, current_unique_count + 1, - current_dict_size + string_size, next_width, info.GetBlockSize()); -} - -void DictionaryAnalyzeState::Flush(bool final) { - segment_count++; - current_tuple_count = 0; - current_unique_count = 0; - current_dict_size = 0; - current_set.clear(); -} -void DictionaryAnalyzeState::Verify() { -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/dictionary/common.cpp b/src/duckdb/src/storage/compression/dictionary/common.cpp deleted file mode 100644 index 05be9aaed..000000000 --- a/src/duckdb/src/storage/compression/dictionary/common.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "duckdb/storage/compression/dictionary/common.hpp" - -namespace duckdb { - -//===--------------------------------------------------------------------===// -// Helper Functions -//===--------------------------------------------------------------------===// -bool DictionaryCompression::HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size, - bitpacking_width_t packing_width, const idx_t block_size) { - return RequiredSpace(current_count, index_count, dict_size, packing_width) <= block_size; -} - -idx_t DictionaryCompression::RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size, - bitpacking_width_t packing_width) { - idx_t base_space = DICTIONARY_HEADER_SIZE + dict_size; - idx_t string_number_space = BitpackingPrimitives::GetRequiredSize(current_count, packing_width); - idx_t index_space = index_count * sizeof(uint32_t); - - idx_t used_space = base_space + index_space + string_number_space; - - return used_space; -} - -StringDictionaryContainer DictionaryCompression::GetDictionary(ColumnSegment &segment, BufferHandle &handle) { - auto header_ptr = reinterpret_cast(handle.Ptr() + segment.GetBlockOffset()); - StringDictionaryContainer container; - container.size = Load(data_ptr_cast(&header_ptr->dict_size)); - container.end = Load(data_ptr_cast(&header_ptr->dict_end)); - return container; -} - -void DictionaryCompression::SetDictionary(ColumnSegment &segment, BufferHandle &handle, - StringDictionaryContainer container) { - auto header_ptr = reinterpret_cast(handle.Ptr() + segment.GetBlockOffset()); - Store(container.size, data_ptr_cast(&header_ptr->dict_size)); - Store(container.end, data_ptr_cast(&header_ptr->dict_end)); -} - -DictionaryCompressionState::DictionaryCompressionState(const CompressionInfo &info) : CompressionState(info) { -} -DictionaryCompressionState::~DictionaryCompressionState() { -} - -bool DictionaryCompressionState::UpdateState(Vector &scan_vector, idx_t count) { - UnifiedVectorFormat vdata; - scan_vector.ToUnifiedFormat(count, vdata); - auto data = UnifiedVectorFormat::GetData(vdata); - Verify(); - - for (idx_t i = 0; i < count; i++) { - auto idx = vdata.sel->get_index(i); - idx_t string_size = 0; - bool new_string = false; - auto row_is_valid = vdata.validity.RowIsValid(idx); - - if (row_is_valid) { - string_size = data[idx].GetSize(); - if (string_size >= StringUncompressed::GetStringBlockLimit(info.GetBlockSize())) { - // Big strings not implemented for dictionary compression - return false; - } - new_string = !LookupString(data[idx]); - } - - bool fits = CalculateSpaceRequirements(new_string, string_size); - if (!fits) { - Flush(); - new_string = true; - - fits = CalculateSpaceRequirements(new_string, string_size); - if (!fits) { - throw InternalException("Dictionary compression could not write to new segment"); - } - } - - if (!row_is_valid) { - AddNull(); - } else if (new_string) { - AddNewString(data[idx]); - } else { - AddLastLookup(); - } - - Verify(); - } - - return true; -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/dictionary/compression.cpp b/src/duckdb/src/storage/compression/dictionary/compression.cpp deleted file mode 100644 index 64a3db402..000000000 --- a/src/duckdb/src/storage/compression/dictionary/compression.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "duckdb/storage/compression/dictionary/compression.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" - -namespace duckdb { - -DictionaryCompressionCompressState::DictionaryCompressionCompressState(ColumnDataCheckpointData &checkpoint_data_p, - const CompressionInfo &info) - : DictionaryCompressionState(info), checkpoint_data(checkpoint_data_p), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_DICTIONARY)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); -} - -void DictionaryCompressionCompressState::CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); - - auto compressed_segment = - ColumnSegment::CreateTransientSegment(db, function, type, row_start, info.GetBlockSize(), info.GetBlockSize()); - current_segment = std::move(compressed_segment); - - // Reset the buffers and the string map. - current_string_map.clear(); - index_buffer.clear(); - - // Reserve index 0 for null strings. - index_buffer.push_back(0); - selection_buffer.clear(); - - current_width = 0; - next_width = 0; - - // Reset the pointers into the current segment. - auto &buffer_manager = BufferManager::GetBufferManager(checkpoint_data.GetDatabase()); - current_handle = buffer_manager.Pin(current_segment->block); - current_dictionary = DictionaryCompression::GetDictionary(*current_segment, current_handle); - current_end_ptr = current_handle.Ptr() + current_dictionary.end; -} - -void DictionaryCompressionCompressState::Verify() { - current_dictionary.Verify(info.GetBlockSize()); - D_ASSERT(current_segment->count == selection_buffer.size()); - D_ASSERT(DictionaryCompression::HasEnoughSpace(current_segment->count.load(), index_buffer.size(), - current_dictionary.size, current_width, info.GetBlockSize())); - D_ASSERT(current_dictionary.end == info.GetBlockSize()); - D_ASSERT(index_buffer.size() == current_string_map.size() + 1); // +1 is for null value -} - -bool DictionaryCompressionCompressState::LookupString(string_t str) { - auto search = current_string_map.find(str); - auto has_result = search != current_string_map.end(); - - if (has_result) { - latest_lookup_result = search->second; - } - return has_result; -} - -void DictionaryCompressionCompressState::AddNewString(string_t str) { - UncompressedStringStorage::UpdateStringStats(current_segment->stats, str); - - // Copy string to dict - current_dictionary.size += str.GetSize(); - auto dict_pos = current_end_ptr - current_dictionary.size; - memcpy(dict_pos, str.GetData(), str.GetSize()); - current_dictionary.Verify(info.GetBlockSize()); - D_ASSERT(current_dictionary.end == info.GetBlockSize()); - - // Update buffers and map - index_buffer.push_back(current_dictionary.size); - selection_buffer.push_back(UnsafeNumericCast(index_buffer.size() - 1)); - if (str.IsInlined()) { - current_string_map.insert({str, index_buffer.size() - 1}); - } else { - string_t dictionary_string((const char *)dict_pos, UnsafeNumericCast(str.GetSize())); // NOLINT - D_ASSERT(!dictionary_string.IsInlined()); - current_string_map.insert({dictionary_string, index_buffer.size() - 1}); - } - DictionaryCompression::SetDictionary(*current_segment, current_handle, current_dictionary); - - current_width = next_width; - current_segment->count++; -} - -void DictionaryCompressionCompressState::AddNull() { - selection_buffer.push_back(0); - current_segment->count++; -} - -void DictionaryCompressionCompressState::AddLastLookup() { - selection_buffer.push_back(latest_lookup_result); - current_segment->count++; -} - -bool DictionaryCompressionCompressState::CalculateSpaceRequirements(bool new_string, idx_t string_size) { - if (!new_string) { - return DictionaryCompression::HasEnoughSpace(current_segment->count.load() + 1, index_buffer.size(), - current_dictionary.size, current_width, info.GetBlockSize()); - } - next_width = BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1 + new_string); - return DictionaryCompression::HasEnoughSpace(current_segment->count.load() + 1, index_buffer.size() + 1, - current_dictionary.size + string_size, next_width, - info.GetBlockSize()); -} - -void DictionaryCompressionCompressState::Flush(bool final) { - auto next_start = current_segment->start + current_segment->count; - - auto segment_size = Finalize(); - auto &state = checkpoint_data.GetCheckpointState(); - state.FlushSegment(std::move(current_segment), std::move(current_handle), segment_size); - - if (!final) { - CreateEmptySegment(next_start); - } -} - -idx_t DictionaryCompressionCompressState::Finalize() { - auto &buffer_manager = BufferManager::GetBufferManager(checkpoint_data.GetDatabase()); - auto handle = buffer_manager.Pin(current_segment->block); - D_ASSERT(current_dictionary.end == info.GetBlockSize()); - - // calculate sizes - auto compressed_selection_buffer_size = - BitpackingPrimitives::GetRequiredSize(current_segment->count, current_width); - auto index_buffer_size = index_buffer.size() * sizeof(uint32_t); - auto total_size = DictionaryCompression::DICTIONARY_HEADER_SIZE + compressed_selection_buffer_size + - index_buffer_size + current_dictionary.size; - - // calculate ptr and offsets - auto base_ptr = handle.Ptr(); - auto header_ptr = reinterpret_cast(base_ptr); - auto compressed_selection_buffer_offset = DictionaryCompression::DICTIONARY_HEADER_SIZE; - auto index_buffer_offset = compressed_selection_buffer_offset + compressed_selection_buffer_size; - - // Write compressed selection buffer - BitpackingPrimitives::PackBuffer(base_ptr + compressed_selection_buffer_offset, - (sel_t *)(selection_buffer.data()), current_segment->count, - current_width); - - // Write the index buffer - memcpy(base_ptr + index_buffer_offset, index_buffer.data(), index_buffer_size); - - // Store sizes and offsets in segment header - Store(NumericCast(index_buffer_offset), data_ptr_cast(&header_ptr->index_buffer_offset)); - Store(NumericCast(index_buffer.size()), data_ptr_cast(&header_ptr->index_buffer_count)); - Store((uint32_t)current_width, data_ptr_cast(&header_ptr->bitpacking_width)); - - D_ASSERT(current_width == BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1)); - D_ASSERT(DictionaryCompression::HasEnoughSpace(current_segment->count, index_buffer.size(), current_dictionary.size, - current_width, info.GetBlockSize())); - D_ASSERT((uint64_t)*max_element(std::begin(selection_buffer), std::end(selection_buffer)) == - index_buffer.size() - 1); - - // Early-out, if the block is sufficiently full. - if (total_size >= info.GetCompactionFlushLimit()) { - return info.GetBlockSize(); - } - - // Sufficient space: calculate how much space we can save. - auto move_amount = info.GetBlockSize() - total_size; - - // Move the dictionary to align it with the offsets. - auto new_dictionary_offset = index_buffer_offset + index_buffer_size; - memmove(base_ptr + new_dictionary_offset, base_ptr + current_dictionary.end - current_dictionary.size, - current_dictionary.size); - current_dictionary.end -= move_amount; - D_ASSERT(current_dictionary.end == total_size); - - // Write the new dictionary with the updated "end". - DictionaryCompression::SetDictionary(*current_segment, handle, current_dictionary); - return total_size; -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/dictionary/decompression.cpp b/src/duckdb/src/storage/compression/dictionary/decompression.cpp deleted file mode 100644 index 4063e9224..000000000 --- a/src/duckdb/src/storage/compression/dictionary/decompression.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "duckdb/storage/compression/dictionary/decompression.hpp" - -namespace duckdb { - -uint16_t CompressedStringScanState::GetStringLength(sel_t index) { - if (index == 0) { - return 0; - } else { - return UnsafeNumericCast(index_buffer_ptr[index] - index_buffer_ptr[index - 1]); - } -} - -string_t CompressedStringScanState::FetchStringFromDict(int32_t dict_offset, uint16_t string_len) { - D_ASSERT(dict_offset >= 0 && dict_offset <= NumericCast(block_size)); - if (dict_offset == 0) { - return string_t(nullptr, 0); - } - - // normal string: read string from this block - auto dict_end = baseptr + dict.end; - auto dict_pos = dict_end - dict_offset; - - auto str_ptr = char_ptr_cast(dict_pos); - return string_t(str_ptr, string_len); -} - -void CompressedStringScanState::Initialize(ColumnSegment &segment, bool initialize_dictionary) { - baseptr = handle->Ptr() + segment.GetBlockOffset(); - - // Load header values - auto header_ptr = reinterpret_cast(baseptr); - auto index_buffer_offset = Load(data_ptr_cast(&header_ptr->index_buffer_offset)); - index_buffer_count = Load(data_ptr_cast(&header_ptr->index_buffer_count)); - current_width = (bitpacking_width_t)(Load(data_ptr_cast(&header_ptr->bitpacking_width))); - if (segment.GetBlockOffset() + index_buffer_offset + sizeof(uint32_t) * index_buffer_count > - segment.GetBlockManager().GetBlockSize()) { - throw IOException( - "Failed to scan dictionary string - index was out of range. Database file appears to be corrupted."); - } - index_buffer_ptr = reinterpret_cast(baseptr + index_buffer_offset); - base_data = data_ptr_cast(baseptr + DictionaryCompression::DICTIONARY_HEADER_SIZE); - - block_size = segment.GetBlockManager().GetBlockSize(); - - dict = DictionaryCompression::GetDictionary(segment, *handle); - - if (!initialize_dictionary) { - // Used by fetch, as fetch will never produce a DictionaryVector - return; - } - - dictionary = make_buffer(segment.type, index_buffer_count); - dictionary_size = index_buffer_count; - auto dict_child_data = FlatVector::GetData(*(dictionary)); - auto &validity = FlatVector::Validity(*dictionary); - D_ASSERT(index_buffer_count >= 1); - validity.SetInvalid(0); - for (uint32_t i = 0; i < index_buffer_count; i++) { - // NOTE: the passing of dict_child_vector, will not be used, its for big strings - uint16_t str_len = GetStringLength(i); - dict_child_data[i] = FetchStringFromDict(UnsafeNumericCast(index_buffer_ptr[i]), str_len); - } -} - -void CompressedStringScanState::ScanToFlatVector(Vector &result, idx_t result_offset, idx_t start, idx_t scan_count) { - auto result_data = FlatVector::GetData(result); - auto &validity = FlatVector::Validity(result); - - // Handling non-bitpacking-group-aligned start values; - idx_t start_offset = start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; - - // We will scan in blocks of BITPACKING_ALGORITHM_GROUP_SIZE, so we may scan some extra values. - idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count + start_offset); - - // Create a decompression buffer of sufficient size if we don't already have one. - if (!sel_vec || sel_vec_size < decompress_count) { - sel_vec_size = decompress_count; - sel_vec = make_buffer(decompress_count); - } - - data_ptr_t src = &base_data[((start - start_offset) * current_width) / 8]; - sel_t *sel_vec_ptr = sel_vec->data(); - - BitpackingPrimitives::UnPackBuffer(data_ptr_cast(sel_vec_ptr), src, decompress_count, current_width); - - for (idx_t i = 0; i < scan_count; i++) { - // Lookup dict offset in index buffer - auto string_number = sel_vec->get_index(i + start_offset); - if (string_number == 0) { - validity.SetInvalid(result_offset + i); - } - auto dict_offset = index_buffer_ptr[string_number]; - auto str_len = GetStringLength(UnsafeNumericCast(string_number)); - result_data[result_offset + i] = FetchStringFromDict(UnsafeNumericCast(dict_offset), str_len); - } -} - -void CompressedStringScanState::ScanToDictionaryVector(ColumnSegment &segment, Vector &result, idx_t result_offset, - idx_t start, idx_t scan_count) { - D_ASSERT(start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0); - D_ASSERT(scan_count == STANDARD_VECTOR_SIZE); - D_ASSERT(result_offset == 0); - - idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count); - - // Create a selection vector of sufficient size if we don't already have one. - if (!sel_vec || sel_vec_size < decompress_count) { - sel_vec_size = decompress_count; - sel_vec = make_buffer(decompress_count); - } - - // Scanning 2048 values, emitting a dict vector - data_ptr_t dst = data_ptr_cast(sel_vec->data()); - data_ptr_t src = data_ptr_cast(&base_data[(start * current_width) / 8]); - - BitpackingPrimitives::UnPackBuffer(dst, src, scan_count, current_width); - - result.Dictionary(*(dictionary), dictionary_size, *sel_vec, scan_count); - DictionaryVector::SetDictionaryId(result, to_string(CastPointerToValue(&segment))); -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/dictionary_compression.cpp b/src/duckdb/src/storage/compression/dictionary_compression.cpp index 78915a374..64318a297 100644 --- a/src/duckdb/src/storage/compression/dictionary_compression.cpp +++ b/src/duckdb/src/storage/compression/dictionary_compression.cpp @@ -1,7 +1,3 @@ -#include "duckdb/storage/compression/dictionary/analyze.hpp" -#include "duckdb/storage/compression/dictionary/compression.hpp" -#include "duckdb/storage/compression/dictionary/decompression.hpp" - #include "duckdb/common/bitpacking.hpp" #include "duckdb/common/numeric_utils.hpp" #include "duckdb/common/operator/comparison_operators.hpp" @@ -13,46 +9,95 @@ #include "duckdb/storage/string_uncompressed.hpp" #include "duckdb/storage/table/column_data_checkpointer.hpp" -/* -Data layout per segment: -+------------------------------------------------------+ -| Header | -| +----------------------------------------------+ | -| | dictionary_compression_header_t header | | -| +----------------------------------------------+ | -| | -+------------------------------------------------------+ -| Selection Buffer | -| +------------------------------------+ | -| | uint16_t index_buffer_idx[] | | -| +------------------------------------+ | -| tuple index -> index buffer idx | -| | -+--------------------------------------------+ -| Index Buffer | -| +------------------------------------+ | -| | uint16_t dictionary_offset[] | | -| +------------------------------------+ | -| string_index -> offset in the dictionary | -| | -+--------------------------------------------+ -| Dictionary | -| +------------------------------------+ | -| | uint8_t *raw_string_data | | -| +------------------------------------+ | -| the string data without lengths | -| | -+--------------------------------------------+ -*/ - namespace duckdb { +//! Abstract class managing the compression state for size analysis or compression. +class DictionaryCompressionState : public CompressionState { +public: + explicit DictionaryCompressionState(const CompressionInfo &info) : CompressionState(info) {}; + +public: + bool UpdateState(Vector &scan_vector, idx_t count) { + UnifiedVectorFormat vdata; + scan_vector.ToUnifiedFormat(count, vdata); + auto data = UnifiedVectorFormat::GetData(vdata); + Verify(); + + for (idx_t i = 0; i < count; i++) { + auto idx = vdata.sel->get_index(i); + idx_t string_size = 0; + bool new_string = false; + auto row_is_valid = vdata.validity.RowIsValid(idx); + + if (row_is_valid) { + string_size = data[idx].GetSize(); + if (string_size >= StringUncompressed::GetStringBlockLimit(info.GetBlockSize())) { + // Big strings not implemented for dictionary compression + return false; + } + new_string = !LookupString(data[idx]); + } + + bool fits = CalculateSpaceRequirements(new_string, string_size); + if (!fits) { + Flush(); + new_string = true; + + fits = CalculateSpaceRequirements(new_string, string_size); + if (!fits) { + throw InternalException("Dictionary compression could not write to new segment"); + } + } + + if (!row_is_valid) { + AddNull(); + } else if (new_string) { + AddNewString(data[idx]); + } else { + AddLastLookup(); + } + + Verify(); + } + + return true; + } + +protected: + // Should verify the State + virtual void Verify() = 0; + // Performs a lookup of str, storing the result internally + virtual bool LookupString(string_t str) = 0; + // Add the most recently looked up str to compression state + virtual void AddLastLookup() = 0; + // Add string to the state that is known to not be seen yet + virtual void AddNewString(string_t str) = 0; + // Add a null value to the compression state + virtual void AddNull() = 0; + // Needs to be called before adding a value. Will return false if a flush is required first. + virtual bool CalculateSpaceRequirements(bool new_string, idx_t string_size) = 0; + // Flush the segment to disk if compressing or reset the counters if analyzing + virtual void Flush(bool final = false) = 0; +}; + +typedef struct { + uint32_t dict_size; + uint32_t dict_end; + uint32_t index_buffer_offset; + uint32_t index_buffer_count; + uint32_t bitpacking_width; +} dictionary_compression_header_t; + struct DictionaryCompressionStorage { + static constexpr float MINIMUM_COMPRESSION_RATIO = 1.2F; + //! Dictionary header size at the beginning of the string segment (offset + length) + static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(dictionary_compression_header_t); + static unique_ptr StringInitAnalyze(ColumnData &col_data, PhysicalType type); static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count); static idx_t StringFinalAnalyze(AnalyzeState &state_p); - static unique_ptr InitCompression(ColumnDataCheckpointData &checkpoint_data, + static unique_ptr InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state); static void Compress(CompressionState &state_p, Vector &scan_vector, idx_t count); static void FinalizeCompress(CompressionState &state_p); @@ -64,11 +109,292 @@ struct DictionaryCompressionStorage { static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result); static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx); + + static bool HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size, + bitpacking_width_t packing_width, const idx_t block_size); + static idx_t RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size, + bitpacking_width_t packing_width); + + static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle); + static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer container); + static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, data_ptr_t baseptr, + int32_t dict_offset, uint16_t string_len); + static uint16_t GetStringLength(uint32_t *index_buffer_ptr, sel_t index); +}; + +// Dictionary compression uses a combination of bitpacking and a dictionary to compress string segments. The data is +// stored across three buffers: the index buffer, the selection buffer and the dictionary. Firstly the Index buffer +// contains the offsets into the dictionary which are also used to determine the string lengths. Each value in the +// dictionary gets a single unique index in the index buffer. Secondly, the selection buffer maps the tuples to an index +// in the index buffer. The selection buffer is compressed with bitpacking. Finally, the dictionary contains simply all +// the unique strings without lengths or null termination as we can deduce the lengths from the index buffer. The +// addition of the selection buffer is done for two reasons: firstly, to allow the scan to emit dictionary vectors by +// scanning the whole dictionary at once and then scanning the selection buffer for each emitted vector. Secondly, it +// allows for efficient bitpacking compression as the selection values should remain relatively small. +struct DictionaryCompressionCompressState : public DictionaryCompressionState { + DictionaryCompressionCompressState(ColumnDataCheckpointer &checkpointer_p, const CompressionInfo &info) + : DictionaryCompressionState(info), checkpointer(checkpointer_p), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_DICTIONARY)), + heap(BufferAllocator::Get(checkpointer.GetDatabase())) { + CreateEmptySegment(checkpointer.GetRowGroup().start); + } + + ColumnDataCheckpointer &checkpointer; + CompressionFunction &function; + + // State regarding current segment + unique_ptr current_segment; + BufferHandle current_handle; + StringDictionaryContainer current_dictionary; + data_ptr_t current_end_ptr; + + // Buffers and map for current segment + StringHeap heap; + string_map_t current_string_map; + vector index_buffer; + vector selection_buffer; + + bitpacking_width_t current_width = 0; + bitpacking_width_t next_width = 0; + + // Result of latest LookupString call + uint32_t latest_lookup_result; + +public: + void CreateEmptySegment(idx_t row_start) { + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); + + auto compressed_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); + current_segment = std::move(compressed_segment); + current_segment->function = function; + + // Reset the buffers and the string map. + current_string_map.clear(); + index_buffer.clear(); + + // Reserve index 0 for null strings. + index_buffer.push_back(0); + selection_buffer.clear(); + + current_width = 0; + next_width = 0; + + // Reset the pointers into the current segment. + auto &buffer_manager = BufferManager::GetBufferManager(checkpointer.GetDatabase()); + current_handle = buffer_manager.Pin(current_segment->block); + current_dictionary = DictionaryCompressionStorage::GetDictionary(*current_segment, current_handle); + current_end_ptr = current_handle.Ptr() + current_dictionary.end; + } + + void Verify() override { + current_dictionary.Verify(info.GetBlockSize()); + D_ASSERT(current_segment->count == selection_buffer.size()); + D_ASSERT(DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load(), index_buffer.size(), + current_dictionary.size, current_width, + info.GetBlockSize())); + D_ASSERT(current_dictionary.end == info.GetBlockSize()); + D_ASSERT(index_buffer.size() == current_string_map.size() + 1); // +1 is for null value + } + + bool LookupString(string_t str) override { + auto search = current_string_map.find(str); + auto has_result = search != current_string_map.end(); + + if (has_result) { + latest_lookup_result = search->second; + } + return has_result; + } + + void AddNewString(string_t str) override { + UncompressedStringStorage::UpdateStringStats(current_segment->stats, str); + + // Copy string to dict + current_dictionary.size += str.GetSize(); + auto dict_pos = current_end_ptr - current_dictionary.size; + memcpy(dict_pos, str.GetData(), str.GetSize()); + current_dictionary.Verify(info.GetBlockSize()); + D_ASSERT(current_dictionary.end == info.GetBlockSize()); + + // Update buffers and map + index_buffer.push_back(current_dictionary.size); + selection_buffer.push_back(UnsafeNumericCast(index_buffer.size() - 1)); + if (str.IsInlined()) { + current_string_map.insert({str, index_buffer.size() - 1}); + } else { + current_string_map.insert({heap.AddBlob(str), index_buffer.size() - 1}); + } + DictionaryCompressionStorage::SetDictionary(*current_segment, current_handle, current_dictionary); + + current_width = next_width; + current_segment->count++; + } + + void AddNull() override { + selection_buffer.push_back(0); + current_segment->count++; + } + + void AddLastLookup() override { + selection_buffer.push_back(latest_lookup_result); + current_segment->count++; + } + + bool CalculateSpaceRequirements(bool new_string, idx_t string_size) override { + if (!new_string) { + return DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load() + 1, index_buffer.size(), + current_dictionary.size, current_width, + info.GetBlockSize()); + } + next_width = BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1 + new_string); + return DictionaryCompressionStorage::HasEnoughSpace(current_segment->count.load() + 1, index_buffer.size() + 1, + current_dictionary.size + string_size, next_width, + info.GetBlockSize()); + } + + void Flush(bool final = false) override { + auto next_start = current_segment->start + current_segment->count; + + auto segment_size = Finalize(); + auto &state = checkpointer.GetCheckpointState(); + state.FlushSegment(std::move(current_segment), segment_size); + + if (!final) { + CreateEmptySegment(next_start); + } + } + + idx_t Finalize() { + auto &buffer_manager = BufferManager::GetBufferManager(checkpointer.GetDatabase()); + auto handle = buffer_manager.Pin(current_segment->block); + D_ASSERT(current_dictionary.end == info.GetBlockSize()); + + // calculate sizes + auto compressed_selection_buffer_size = + BitpackingPrimitives::GetRequiredSize(current_segment->count, current_width); + auto index_buffer_size = index_buffer.size() * sizeof(uint32_t); + auto total_size = DictionaryCompressionStorage::DICTIONARY_HEADER_SIZE + compressed_selection_buffer_size + + index_buffer_size + current_dictionary.size; + + // calculate ptr and offsets + auto base_ptr = handle.Ptr(); + auto header_ptr = reinterpret_cast(base_ptr); + auto compressed_selection_buffer_offset = DictionaryCompressionStorage::DICTIONARY_HEADER_SIZE; + auto index_buffer_offset = compressed_selection_buffer_offset + compressed_selection_buffer_size; + + // Write compressed selection buffer + BitpackingPrimitives::PackBuffer(base_ptr + compressed_selection_buffer_offset, + (sel_t *)(selection_buffer.data()), current_segment->count, + current_width); + + // Write the index buffer + memcpy(base_ptr + index_buffer_offset, index_buffer.data(), index_buffer_size); + + // Store sizes and offsets in segment header + Store(NumericCast(index_buffer_offset), data_ptr_cast(&header_ptr->index_buffer_offset)); + Store(NumericCast(index_buffer.size()), data_ptr_cast(&header_ptr->index_buffer_count)); + Store((uint32_t)current_width, data_ptr_cast(&header_ptr->bitpacking_width)); + + D_ASSERT(current_width == BitpackingPrimitives::MinimumBitWidth(index_buffer.size() - 1)); + D_ASSERT(DictionaryCompressionStorage::HasEnoughSpace( + current_segment->count, index_buffer.size(), current_dictionary.size, current_width, info.GetBlockSize())); + D_ASSERT((uint64_t)*max_element(std::begin(selection_buffer), std::end(selection_buffer)) == + index_buffer.size() - 1); + + // Early-out, if the block is sufficiently full. + if (total_size >= info.GetCompactionFlushLimit()) { + return info.GetBlockSize(); + } + + // Sufficient space: calculate how much space we can save. + auto move_amount = info.GetBlockSize() - total_size; + + // Move the dictionary to align it with the offsets. + auto new_dictionary_offset = index_buffer_offset + index_buffer_size; + memmove(base_ptr + new_dictionary_offset, base_ptr + current_dictionary.end - current_dictionary.size, + current_dictionary.size); + current_dictionary.end -= move_amount; + D_ASSERT(current_dictionary.end == total_size); + + // Write the new dictionary with the updated "end". + DictionaryCompressionStorage::SetDictionary(*current_segment, handle, current_dictionary); + return total_size; + } }; //===--------------------------------------------------------------------===// // Analyze //===--------------------------------------------------------------------===// +struct DictionaryAnalyzeState : public DictionaryCompressionState { + explicit DictionaryAnalyzeState(const CompressionInfo &info) + : DictionaryCompressionState(info), segment_count(0), current_tuple_count(0), current_unique_count(0), + current_dict_size(0), current_width(0), next_width(0) { + } + + idx_t segment_count; + idx_t current_tuple_count; + idx_t current_unique_count; + idx_t current_dict_size; + StringHeap heap; + string_set_t current_set; + bitpacking_width_t current_width; + bitpacking_width_t next_width; + + bool LookupString(string_t str) override { + return current_set.count(str); + } + + void AddNewString(string_t str) override { + current_tuple_count++; + current_unique_count++; + current_dict_size += str.GetSize(); + if (str.IsInlined()) { + current_set.insert(str); + } else { + current_set.insert(heap.AddBlob(str)); + } + current_width = next_width; + } + + void AddLastLookup() override { + current_tuple_count++; + } + + void AddNull() override { + current_tuple_count++; + } + + bool CalculateSpaceRequirements(bool new_string, idx_t string_size) override { + if (!new_string) { + return DictionaryCompressionStorage::HasEnoughSpace(current_tuple_count + 1, current_unique_count, + current_dict_size, current_width, info.GetBlockSize()); + } + next_width = BitpackingPrimitives::MinimumBitWidth(current_unique_count + 2); // 1 for null, one for new string + return DictionaryCompressionStorage::HasEnoughSpace(current_tuple_count + 1, current_unique_count + 1, + current_dict_size + string_size, next_width, + info.GetBlockSize()); + } + + void Flush(bool final = false) override { + segment_count++; + current_tuple_count = 0; + current_unique_count = 0; + current_dict_size = 0; + current_set.clear(); + } + void Verify() override {}; +}; + +struct DictionaryCompressionAnalyzeState : public AnalyzeState { + explicit DictionaryCompressionAnalyzeState(const CompressionInfo &info) + : AnalyzeState(info), analyze_state(make_uniq(info)) { + } + + unique_ptr analyze_state; +}; + unique_ptr DictionaryCompressionStorage::StringInitAnalyze(ColumnData &col_data, PhysicalType type) { CompressionInfo info(col_data.GetBlockManager().GetBlockSize()); return make_uniq(info); @@ -84,19 +410,19 @@ idx_t DictionaryCompressionStorage::StringFinalAnalyze(AnalyzeState &state_p) { auto &state = *analyze_state.analyze_state; auto width = BitpackingPrimitives::MinimumBitWidth(state.current_unique_count + 1); - auto req_space = DictionaryCompression::RequiredSpace(state.current_tuple_count, state.current_unique_count, - state.current_dict_size, width); + auto req_space = + RequiredSpace(state.current_tuple_count, state.current_unique_count, state.current_dict_size, width); const auto total_space = state.segment_count * state.info.GetBlockSize() + req_space; - return LossyNumericCast(DictionaryCompression::MINIMUM_COMPRESSION_RATIO * float(total_space)); + return LossyNumericCast(MINIMUM_COMPRESSION_RATIO * float(total_space)); } //===--------------------------------------------------------------------===// // Compress //===--------------------------------------------------------------------===// -unique_ptr DictionaryCompressionStorage::InitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr DictionaryCompressionStorage::InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { - return make_uniq(checkpoint_data, state->info); + return make_uniq(checkpointer, state->info); } void DictionaryCompressionStorage::Compress(CompressionState &state_p, Vector &scan_vector, idx_t count) { @@ -112,10 +438,40 @@ void DictionaryCompressionStorage::FinalizeCompress(CompressionState &state_p) { //===--------------------------------------------------------------------===// // Scan //===--------------------------------------------------------------------===// +struct CompressedStringScanState : public StringScanState { + BufferHandle handle; + buffer_ptr dictionary; + bitpacking_width_t current_width; + buffer_ptr sel_vec; + idx_t sel_vec_size = 0; +}; + unique_ptr DictionaryCompressionStorage::StringInitScan(ColumnSegment &segment) { + auto state = make_uniq(); auto &buffer_manager = BufferManager::GetBufferManager(segment.db); - auto state = make_uniq(buffer_manager.Pin(segment.block)); - state->Initialize(segment, true); + state->handle = buffer_manager.Pin(segment.block); + + auto baseptr = state->handle.Ptr() + segment.GetBlockOffset(); + + // Load header values + auto dict = DictionaryCompressionStorage::GetDictionary(segment, state->handle); + auto header_ptr = reinterpret_cast(baseptr); + auto index_buffer_offset = Load(data_ptr_cast(&header_ptr->index_buffer_offset)); + auto index_buffer_count = Load(data_ptr_cast(&header_ptr->index_buffer_count)); + state->current_width = (bitpacking_width_t)(Load(data_ptr_cast(&header_ptr->bitpacking_width))); + + auto index_buffer_ptr = reinterpret_cast(baseptr + index_buffer_offset); + + state->dictionary = make_buffer(segment.type, index_buffer_count); + auto dict_child_data = FlatVector::GetData(*(state->dictionary)); + + for (uint32_t i = 0; i < index_buffer_count; i++) { + // NOTE: the passing of dict_child_vector, will not be used, its for big strings + uint16_t str_len = GetStringLength(index_buffer_ptr, i); + dict_child_data[i] = + FetchStringFromDict(segment, dict, baseptr, UnsafeNumericCast(index_buffer_ptr[i]), str_len); + } + return std::move(state); } @@ -127,13 +483,69 @@ void DictionaryCompressionStorage::StringScanPartial(ColumnSegment &segment, Col Vector &result, idx_t result_offset) { // clear any previously locked buffers and get the primary buffer handle auto &scan_state = state.scan_state->Cast(); - auto start = segment.GetRelativeIndex(state.row_index); + + auto baseptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); + auto dict = DictionaryCompressionStorage::GetDictionary(segment, scan_state.handle); + + auto header_ptr = reinterpret_cast(baseptr); + auto index_buffer_offset = Load(data_ptr_cast(&header_ptr->index_buffer_offset)); + auto index_buffer_ptr = reinterpret_cast(baseptr + index_buffer_offset); + + auto base_data = data_ptr_cast(baseptr + DICTIONARY_HEADER_SIZE); + auto result_data = FlatVector::GetData(result); + if (!ALLOW_DICT_VECTORS || scan_count != STANDARD_VECTOR_SIZE || start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE != 0) { - scan_state.ScanToFlatVector(result, result_offset, start, scan_count); + // Emit regular vector + + // Handling non-bitpacking-group-aligned start values; + idx_t start_offset = start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; + + // We will scan in blocks of BITPACKING_ALGORITHM_GROUP_SIZE, so we may scan some extra values. + idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count + start_offset); + + // Create a decompression buffer of sufficient size if we don't already have one. + if (!scan_state.sel_vec || scan_state.sel_vec_size < decompress_count) { + scan_state.sel_vec_size = decompress_count; + scan_state.sel_vec = make_buffer(decompress_count); + } + + data_ptr_t src = &base_data[((start - start_offset) * scan_state.current_width) / 8]; + sel_t *sel_vec_ptr = scan_state.sel_vec->data(); + + BitpackingPrimitives::UnPackBuffer(data_ptr_cast(sel_vec_ptr), src, decompress_count, + scan_state.current_width); + + for (idx_t i = 0; i < scan_count; i++) { + // Lookup dict offset in index buffer + auto string_number = scan_state.sel_vec->get_index(i + start_offset); + auto dict_offset = index_buffer_ptr[string_number]; + auto str_len = GetStringLength(index_buffer_ptr, UnsafeNumericCast(string_number)); + result_data[result_offset + i] = + FetchStringFromDict(segment, dict, baseptr, UnsafeNumericCast(dict_offset), str_len); + } + } else { - scan_state.ScanToDictionaryVector(segment, result, result_offset, start, scan_count); + D_ASSERT(start % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE == 0); + D_ASSERT(scan_count == STANDARD_VECTOR_SIZE); + D_ASSERT(result_offset == 0); + + idx_t decompress_count = BitpackingPrimitives::RoundUpToAlgorithmGroupSize(scan_count); + + // Create a selection vector of sufficient size if we don't already have one. + if (!scan_state.sel_vec || scan_state.sel_vec_size < decompress_count) { + scan_state.sel_vec_size = decompress_count; + scan_state.sel_vec = make_buffer(decompress_count); + } + + // Scanning 1024 values, emitting a dict vector + data_ptr_t dst = data_ptr_cast(scan_state.sel_vec->data()); + data_ptr_t src = data_ptr_cast(&base_data[(start * scan_state.current_width) / 8]); + + BitpackingPrimitives::UnPackBuffer(dst, src, scan_count, scan_state.current_width); + + result.Slice(*(scan_state.dictionary), *scan_state.sel_vec, scan_count); } } @@ -148,29 +560,107 @@ void DictionaryCompressionStorage::StringScan(ColumnSegment &segment, ColumnScan void DictionaryCompressionStorage::StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx) { // fetch a single row from the string segment - CompressedStringScanState scan_state(state.GetOrInsertHandle(segment)); - scan_state.Initialize(segment, false); - scan_state.ScanToFlatVector(result, result_idx, NumericCast(row_id), 1); + // first pin the main buffer if it is not already pinned + auto &handle = state.GetOrInsertHandle(segment); + + auto baseptr = handle.Ptr() + segment.GetBlockOffset(); + auto header_ptr = reinterpret_cast(baseptr); + auto dict = DictionaryCompressionStorage::GetDictionary(segment, handle); + auto index_buffer_offset = Load(data_ptr_cast(&header_ptr->index_buffer_offset)); + auto width = (bitpacking_width_t)Load(data_ptr_cast(&header_ptr->bitpacking_width)); + auto index_buffer_ptr = reinterpret_cast(baseptr + index_buffer_offset); + auto base_data = data_ptr_cast(baseptr + DICTIONARY_HEADER_SIZE); + auto result_data = FlatVector::GetData(result); + + // Handling non-bitpacking-group-aligned start values; + idx_t start_offset = NumericCast(row_id) % BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; + + // Decompress part of selection buffer we need for this value. + sel_t decompression_buffer[BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE]; + data_ptr_t src = data_ptr_cast(&base_data[((NumericCast(row_id) - start_offset) * width) / 8]); + BitpackingPrimitives::UnPackBuffer(data_ptr_cast(decompression_buffer), src, + BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE, width); + + auto selection_value = decompression_buffer[start_offset]; + auto dict_offset = index_buffer_ptr[selection_value]; + uint16_t str_len = GetStringLength(index_buffer_ptr, selection_value); + + result_data[result_idx] = FetchStringFromDict(segment, dict, baseptr, NumericCast(dict_offset), str_len); +} + +//===--------------------------------------------------------------------===// +// Helper Functions +//===--------------------------------------------------------------------===// +bool DictionaryCompressionStorage::HasEnoughSpace(idx_t current_count, idx_t index_count, idx_t dict_size, + bitpacking_width_t packing_width, const idx_t block_size) { + return RequiredSpace(current_count, index_count, dict_size, packing_width) <= block_size; +} + +idx_t DictionaryCompressionStorage::RequiredSpace(idx_t current_count, idx_t index_count, idx_t dict_size, + bitpacking_width_t packing_width) { + idx_t base_space = DICTIONARY_HEADER_SIZE + dict_size; + idx_t string_number_space = BitpackingPrimitives::GetRequiredSize(current_count, packing_width); + idx_t index_space = index_count * sizeof(uint32_t); + + idx_t used_space = base_space + index_space + string_number_space; + + return used_space; +} + +StringDictionaryContainer DictionaryCompressionStorage::GetDictionary(ColumnSegment &segment, BufferHandle &handle) { + auto header_ptr = reinterpret_cast(handle.Ptr() + segment.GetBlockOffset()); + StringDictionaryContainer container; + container.size = Load(data_ptr_cast(&header_ptr->dict_size)); + container.end = Load(data_ptr_cast(&header_ptr->dict_end)); + return container; +} + +void DictionaryCompressionStorage::SetDictionary(ColumnSegment &segment, BufferHandle &handle, + StringDictionaryContainer container) { + auto header_ptr = reinterpret_cast(handle.Ptr() + segment.GetBlockOffset()); + Store(container.size, data_ptr_cast(&header_ptr->dict_size)); + Store(container.end, data_ptr_cast(&header_ptr->dict_end)); +} + +string_t DictionaryCompressionStorage::FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, + data_ptr_t baseptr, int32_t dict_offset, + uint16_t string_len) { + + D_ASSERT(dict_offset >= 0 && dict_offset <= NumericCast(segment.GetBlockManager().GetBlockSize())); + if (dict_offset == 0) { + return string_t(nullptr, 0); + } + + // normal string: read string from this block + auto dict_end = baseptr + dict.end; + auto dict_pos = dict_end - dict_offset; + + auto str_ptr = char_ptr_cast(dict_pos); + return string_t(str_ptr, string_len); +} + +uint16_t DictionaryCompressionStorage::GetStringLength(uint32_t *index_buffer_ptr, sel_t index) { + if (index == 0) { + return 0; + } else { + return UnsafeNumericCast(index_buffer_ptr[index] - index_buffer_ptr[index - 1]); + } } //===--------------------------------------------------------------------===// // Get Function //===--------------------------------------------------------------------===// CompressionFunction DictionaryCompressionFun::GetFunction(PhysicalType data_type) { - auto res = CompressionFunction( + return CompressionFunction( CompressionType::COMPRESSION_DICTIONARY, data_type, DictionaryCompressionStorage ::StringInitAnalyze, DictionaryCompressionStorage::StringAnalyze, DictionaryCompressionStorage::StringFinalAnalyze, DictionaryCompressionStorage::InitCompression, DictionaryCompressionStorage::Compress, DictionaryCompressionStorage::FinalizeCompress, DictionaryCompressionStorage::StringInitScan, DictionaryCompressionStorage::StringScan, DictionaryCompressionStorage::StringScanPartial, - DictionaryCompressionStorage::StringFetchRow, UncompressedFunctions::EmptySkip, - UncompressedStringStorage::StringInitSegment); - res.validity = CompressionValidity::NO_VALIDITY_REQUIRED; - return res; + DictionaryCompressionStorage::StringFetchRow, UncompressedFunctions::EmptySkip); } bool DictionaryCompressionFun::TypeIsSupported(const PhysicalType physical_type) { return physical_type == PhysicalType::VARCHAR; } - } // namespace duckdb diff --git a/src/duckdb/src/storage/compression/empty_validity.cpp b/src/duckdb/src/storage/compression/empty_validity.cpp deleted file mode 100644 index 0b6534153..000000000 --- a/src/duckdb/src/storage/compression/empty_validity.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/storage/compression/empty_validity.hpp" - -namespace duckdb { - -CompressionFunction EmptyValidityCompressionFun::GetFunction(PhysicalType type) { - return EmptyValidityCompression::CreateFunction(); -} - -bool EmptyValidityCompressionFun::TypeIsSupported(const PhysicalType physical_type) { - D_ASSERT(physical_type == PhysicalType::BIT); - return true; -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp b/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp index 3215f1b8f..3b4a09ce0 100644 --- a/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp +++ b/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp @@ -42,54 +42,45 @@ idx_t FixedSizeFinalAnalyze(AnalyzeState &state_p) { // Compress //===--------------------------------------------------------------------===// struct UncompressedCompressState : public CompressionState { -public: - UncompressedCompressState(ColumnDataCheckpointData &checkpoint_data, const CompressionInfo &info); + UncompressedCompressState(ColumnDataCheckpointer &checkpointer, const CompressionInfo &info); + + ColumnDataCheckpointer &checkpointer; + unique_ptr current_segment; + ColumnAppendState append_state; -public: virtual void CreateEmptySegment(idx_t row_start); void FlushSegment(idx_t segment_size); void Finalize(idx_t segment_size); - -public: - ColumnDataCheckpointData &checkpoint_data; - CompressionFunction &function; - unique_ptr current_segment; - ColumnAppendState append_state; }; -UncompressedCompressState::UncompressedCompressState(ColumnDataCheckpointData &checkpoint_data, - const CompressionInfo &info) - : CompressionState(info), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_UNCOMPRESSED)) { - UncompressedCompressState::CreateEmptySegment(checkpoint_data.GetRowGroup().start); +UncompressedCompressState::UncompressedCompressState(ColumnDataCheckpointer &checkpointer, const CompressionInfo &info) + : CompressionState(info), checkpointer(checkpointer) { + UncompressedCompressState::CreateEmptySegment(checkpointer.GetRowGroup().start); } void UncompressedCompressState::CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); auto compressed_segment = - ColumnSegment::CreateTransientSegment(db, function, type, row_start, info.GetBlockSize(), info.GetBlockSize()); + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); if (type.InternalType() == PhysicalType::VARCHAR) { auto &state = compressed_segment->GetSegmentState()->Cast(); state.overflow_writer = - make_uniq(checkpoint_data.GetCheckpointState().GetPartialBlockManager()); + make_uniq(checkpointer.GetCheckpointState().GetPartialBlockManager()); } current_segment = std::move(compressed_segment); current_segment->InitializeAppend(append_state); } void UncompressedCompressState::FlushSegment(idx_t segment_size) { - auto &state = checkpoint_data.GetCheckpointState(); + auto &state = checkpointer.GetCheckpointState(); if (current_segment->type.InternalType() == PhysicalType::VARCHAR) { auto &segment_state = current_segment->GetSegmentState()->Cast(); segment_state.overflow_writer->Flush(); segment_state.overflow_writer.reset(); } - append_state.child_appends.clear(); - append_state.append_state.reset(); - append_state.lock.reset(); - state.FlushSegmentInternal(std::move(current_segment), segment_size); + state.FlushSegment(std::move(current_segment), segment_size); } void UncompressedCompressState::Finalize(idx_t segment_size) { @@ -97,9 +88,9 @@ void UncompressedCompressState::Finalize(idx_t segment_size) { current_segment.reset(); } -unique_ptr UncompressedFunctions::InitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr UncompressedFunctions::InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { - return make_uniq(checkpoint_data, state->info); + return make_uniq(checkpointer, state->info); } void UncompressedFunctions::Compress(CompressionState &state_p, Vector &data, idx_t count) { diff --git a/src/duckdb/src/storage/compression/fsst.cpp b/src/duckdb/src/storage/compression/fsst.cpp index bc5c52228..8492aabfa 100644 --- a/src/duckdb/src/storage/compression/fsst.cpp +++ b/src/duckdb/src/storage/compression/fsst.cpp @@ -13,7 +13,6 @@ #include "miniz_wrapper.hpp" namespace duckdb { -struct FSSTScanState; typedef struct { uint32_t dict_size; @@ -43,7 +42,7 @@ struct FSSTStorage { static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count); static idx_t StringFinalAnalyze(AnalyzeState &state_p); - static unique_ptr InitCompression(ColumnDataCheckpointData &checkpoint_data, + static unique_ptr InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr analyze_state_p); static void Compress(CompressionState &state_p, Vector &scan_vector, idx_t count); static void FinalizeCompress(CompressionState &state_p); @@ -55,8 +54,6 @@ struct FSSTStorage { static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result); static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx); - static void Select(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count); static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer container); static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle); @@ -65,9 +62,6 @@ struct FSSTStorage { static bp_delta_offsets_t CalculateBpDeltaOffsets(int64_t last_known_row, idx_t start, idx_t scan_count); static bool ParseFSSTSegmentHeader(data_ptr_t base_ptr, duckdb_fsst_decoder_t *decoder_out, bitpacking_width_t *width_out); - static bp_delta_offsets_t StartScan(FSSTScanState &scan_state, data_ptr_t base_data, idx_t start, - idx_t vector_count); - static void EndScan(FSSTScanState &scan_state, bp_delta_offsets_t &offsets, idx_t start, idx_t scan_count); }; //===--------------------------------------------------------------------===// @@ -208,10 +202,10 @@ idx_t FSSTStorage::StringFinalAnalyze(AnalyzeState &state_p) { class FSSTCompressionState : public CompressionState { public: - FSSTCompressionState(ColumnDataCheckpointData &checkpoint_data, const CompressionInfo &info) - : CompressionState(info), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_FSST)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); + FSSTCompressionState(ColumnDataCheckpointer &checkpointer, const CompressionInfo &info) + : CompressionState(info), checkpointer(checkpointer), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_FSST)) { + CreateEmptySegment(checkpointer.GetRowGroup().start); } ~FSSTCompressionState() override { @@ -234,12 +228,13 @@ class FSSTCompressionState : public CompressionState { } void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); + auto compressed_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); current_segment = std::move(compressed_segment); + current_segment->function = function; Reset(); } @@ -318,8 +313,8 @@ class FSSTCompressionState : public CompressionState { auto next_start = current_segment->start + current_segment->count; auto segment_size = Finalize(); - auto &state = checkpoint_data.GetCheckpointState(); - state.FlushSegment(std::move(current_segment), std::move(current_handle), segment_size); + auto &state = checkpointer.GetCheckpointState(); + state.FlushSegment(std::move(current_segment), segment_size); if (!final) { CreateEmptySegment(next_start); @@ -382,7 +377,7 @@ class FSSTCompressionState : public CompressionState { return total_size; } - ColumnDataCheckpointData &checkpoint_data; + ColumnDataCheckpointer &checkpointer; CompressionFunction &function; // State regarding current segment @@ -403,10 +398,10 @@ class FSSTCompressionState : public CompressionState { size_t fsst_serialized_symbol_table_size = sizeof(duckdb_fsst_decoder_t); }; -unique_ptr FSSTStorage::InitCompression(ColumnDataCheckpointData &checkpoint_data, +unique_ptr FSSTStorage::InitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr analyze_state_p) { auto &analyze_state = analyze_state_p->Cast(); - auto compression_state = make_uniq(checkpoint_data, analyze_state.info); + auto compression_state = make_uniq(checkpointer, analyze_state.info); if (analyze_state.fsst_encoder == nullptr) { throw InternalException("No encoder found during FSST compression"); @@ -520,11 +515,6 @@ struct FSSTScanState : public StringScanState { uint32_t last_known_index; int64_t last_known_row; - unsafe_unique_array bitunpack_buffer; - idx_t bitunpack_buffer_capacity = 0; - unsafe_unique_array delta_decode_buffer; - idx_t delta_decode_capacity = 0; - void StoreLastDelta(uint32_t value, int64_t row) { last_known_index = value; last_known_row = row; @@ -533,18 +523,6 @@ struct FSSTScanState : public StringScanState { last_known_index = 0; last_known_row = -1; } - inline string_t DecompressString(StringDictionaryContainer dict, data_ptr_t baseptr, - const bp_delta_offsets_t &offsets, idx_t index, Vector &result) { - uint32_t str_len = bitunpack_buffer[offsets.scan_offset + index]; - auto str_ptr = FSSTStorage::FetchStringPointer( - dict, baseptr, - UnsafeNumericCast(delta_decode_buffer[index + offsets.unused_delta_decoded_values])); - - if (str_len == 0) { - return string_t(nullptr, 0); - } - return FSSTPrimitives::DecompressValue(duckdb_fsst_decoder.get(), result, str_ptr, str_len, decompress_buffer); - } }; unique_ptr FSSTStorage::StringInitScan(ColumnSegment &segment) { @@ -580,35 +558,6 @@ void BitUnpackRange(data_ptr_t src_ptr, data_ptr_t dst_ptr, idx_t count, idx_t r //===--------------------------------------------------------------------===// // Scan base data //===--------------------------------------------------------------------===// -bp_delta_offsets_t FSSTStorage::StartScan(FSSTScanState &scan_state, data_ptr_t base_data, idx_t start, - idx_t scan_count) { - if (start == 0 || scan_state.last_known_row >= (int64_t)start) { - scan_state.ResetStoredDelta(); - } - - auto offsets = CalculateBpDeltaOffsets(scan_state.last_known_row, start, scan_count); - - if (scan_state.bitunpack_buffer_capacity < offsets.total_bitunpack_count) { - scan_state.bitunpack_buffer = make_unsafe_uniq_array(offsets.total_bitunpack_count); - scan_state.bitunpack_buffer_capacity = offsets.total_bitunpack_count; - } - BitUnpackRange(base_data, data_ptr_cast(scan_state.bitunpack_buffer.get()), offsets.total_bitunpack_count, - offsets.bitunpack_start_row, scan_state.current_width); - if (scan_state.delta_decode_capacity < offsets.total_delta_decode_count) { - scan_state.delta_decode_buffer = make_unsafe_uniq_array(offsets.total_delta_decode_count); - scan_state.delta_decode_capacity = offsets.total_delta_decode_count; - } - DeltaDecodeIndices(scan_state.bitunpack_buffer.get() + offsets.bitunpack_alignment_offset, - scan_state.delta_decode_buffer.get(), offsets.total_delta_decode_count, - scan_state.last_known_index); - return offsets; -} - -void FSSTStorage::EndScan(FSSTScanState &scan_state, bp_delta_offsets_t &offsets, idx_t start, idx_t scan_count) { - scan_state.StoreLastDelta(scan_state.delta_decode_buffer[scan_count + offsets.unused_delta_decoded_values - 1], - UnsafeNumericCast(start + scan_count - 1)); -} - template void FSSTStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, idx_t result_offset) { @@ -650,9 +599,19 @@ void FSSTStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &sta result_data = FlatVector::GetData(result); } - auto offsets = StartScan(scan_state, base_data, start, scan_count); - auto &bitunpack_buffer = scan_state.bitunpack_buffer; - auto &delta_decode_buffer = scan_state.delta_decode_buffer; + if (start == 0 || scan_state.last_known_row >= (int64_t)start) { + scan_state.ResetStoredDelta(); + } + + auto offsets = CalculateBpDeltaOffsets(scan_state.last_known_row, start, scan_count); + + auto bitunpack_buffer = unsafe_unique_ptr(new uint32_t[offsets.total_bitunpack_count]); + BitUnpackRange(base_data, data_ptr_cast(bitunpack_buffer.get()), offsets.total_bitunpack_count, + offsets.bitunpack_start_row, scan_state.current_width); + auto delta_decode_buffer = unsafe_unique_ptr(new uint32_t[offsets.total_delta_decode_count]); + DeltaDecodeIndices(bitunpack_buffer.get() + offsets.bitunpack_alignment_offset, delta_decode_buffer.get(), + offsets.total_delta_decode_count, scan_state.last_known_index); + if (enable_fsst_vectors) { // Lookup decompressed offsets in dict for (idx_t i = 0; i < scan_count; i++) { @@ -666,39 +625,28 @@ void FSSTStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &sta } else { // Just decompress for (idx_t i = 0; i < scan_count; i++) { - result_data[i + result_offset] = scan_state.DecompressString(dict, baseptr, offsets, i, result); + uint32_t str_len = bitunpack_buffer[i + offsets.scan_offset]; + auto str_ptr = FSSTStorage::FetchStringPointer( + dict, baseptr, + UnsafeNumericCast(delta_decode_buffer[i + offsets.unused_delta_decoded_values])); + + if (str_len > 0) { + result_data[i + result_offset] = FSSTPrimitives::DecompressValue( + scan_state.duckdb_fsst_decoder.get(), result, str_ptr, str_len, scan_state.decompress_buffer); + } else { + result_data[i + result_offset] = string_t(nullptr, 0); + } } } - EndScan(scan_state, offsets, start, scan_count); + + scan_state.StoreLastDelta(delta_decode_buffer[scan_count + offsets.unused_delta_decoded_values - 1], + UnsafeNumericCast(start + scan_count - 1)); } void FSSTStorage::StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result) { StringScanPartial(segment, state, scan_count, result, 0); } -//===--------------------------------------------------------------------===// -// Select -//===--------------------------------------------------------------------===// -void FSSTStorage::Select(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count) { - auto &scan_state = state.scan_state->Cast(); - auto start = segment.GetRelativeIndex(state.row_index); - - auto baseptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); - auto dict = GetDictionary(segment, scan_state.handle); - auto base_data = data_ptr_cast(baseptr + sizeof(fsst_compression_header_t)); - - D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - - auto offsets = StartScan(scan_state, base_data, start, vector_count); - auto result_data = FlatVector::GetData(result); - for (idx_t i = 0; i < sel_count; i++) { - idx_t index = sel.get_index(i); - result_data[i] = scan_state.DecompressString(dict, baseptr, offsets, index, result); - } - EndScan(scan_state, offsets, start, vector_count); -} - //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// @@ -751,13 +699,11 @@ void FSSTStorage::StringFetchRow(ColumnSegment &segment, ColumnFetchState &state //===--------------------------------------------------------------------===// CompressionFunction FSSTFun::GetFunction(PhysicalType data_type) { D_ASSERT(data_type == PhysicalType::VARCHAR); - return CompressionFunction(CompressionType::COMPRESSION_FSST, data_type, FSSTStorage::StringInitAnalyze, - FSSTStorage::StringAnalyze, FSSTStorage::StringFinalAnalyze, - FSSTStorage::InitCompression, FSSTStorage::Compress, FSSTStorage::FinalizeCompress, - FSSTStorage::StringInitScan, FSSTStorage::StringScan, - FSSTStorage::StringScanPartial, FSSTStorage::StringFetchRow, - UncompressedFunctions::EmptySkip, UncompressedStringStorage::StringInitSegment, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, FSSTStorage::Select); + return CompressionFunction( + CompressionType::COMPRESSION_FSST, data_type, FSSTStorage::StringInitAnalyze, FSSTStorage::StringAnalyze, + FSSTStorage::StringFinalAnalyze, FSSTStorage::InitCompression, FSSTStorage::Compress, + FSSTStorage::FinalizeCompress, FSSTStorage::StringInitScan, FSSTStorage::StringScan, + FSSTStorage::StringScanPartial, FSSTStorage::StringFetchRow, UncompressedFunctions::EmptySkip); } bool FSSTFun::TypeIsSupported(const PhysicalType physical_type) { diff --git a/src/duckdb/src/storage/compression/numeric_constant.cpp b/src/duckdb/src/storage/compression/numeric_constant.cpp index 097ab9068..599c0682a 100644 --- a/src/duckdb/src/storage/compression/numeric_constant.cpp +++ b/src/duckdb/src/storage/compression/numeric_constant.cpp @@ -87,93 +87,6 @@ void ConstantFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row ConstantFillFunction(segment, result, result_idx, 1); } -//===--------------------------------------------------------------------===// -// Select -//===--------------------------------------------------------------------===// -void ConstantSelectValidity(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count) { - ConstantScanFunctionValidity(segment, state, vector_count, result); -} - -template -void ConstantSelect(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count) { - ConstantScanFunction(segment, state, vector_count, result); -} - -//===--------------------------------------------------------------------===// -// Filter -//===--------------------------------------------------------------------===// -void FiltersNullValues(const TableFilter &filter, bool &filters_nulls, bool &filters_valid_values) { - filters_nulls = false; - filters_valid_values = false; - - switch (filter.filter_type) { - case TableFilterType::OPTIONAL_FILTER: - break; - case TableFilterType::CONJUNCTION_OR: { - auto &conjunction_or = filter.Cast(); - filters_nulls = true; - filters_valid_values = true; - for (auto &child_filter : conjunction_or.child_filters) { - bool child_filters_nulls, child_filters_valid_values; - FiltersNullValues(*child_filter, child_filters_nulls, child_filters_valid_values); - filters_nulls = filters_nulls && child_filters_nulls; - filters_valid_values = filters_valid_values && child_filters_valid_values; - } - break; - } - case TableFilterType::CONJUNCTION_AND: { - auto &conjunction_and = filter.Cast(); - filters_nulls = false; - filters_valid_values = false; - for (auto &child_filter : conjunction_and.child_filters) { - bool child_filters_nulls, child_filters_valid_values; - FiltersNullValues(*child_filter, child_filters_nulls, child_filters_valid_values); - filters_nulls = filters_nulls || child_filters_nulls; - filters_valid_values = filters_valid_values || child_filters_valid_values; - } - break; - } - case TableFilterType::CONSTANT_COMPARISON: - filters_nulls = true; - break; - case TableFilterType::IS_NULL: - filters_valid_values = true; - break; - case TableFilterType::IS_NOT_NULL: - filters_nulls = true; - break; - default: - throw InternalException("FIXME: unsupported type for filter selection in validity select"); - } -} - -void ConstantFilterValidity(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - SelectionVector &sel, idx_t &sel_count, const TableFilter &filter) { - // check what effect the filter has on NULL values - bool filters_nulls, filters_valid_values; - FiltersNullValues(filter, filters_nulls, filters_valid_values); - - auto &stats = segment.stats.statistics; - if (stats.CanHaveNull()) { - // all values are NULL - if (filters_nulls) { - // ... and the filter removes NULL values - sel_count = 0; - return; - } - } else { - // all values are valid - if (filters_valid_values) { - // ... and the filter removes valid values - sel_count = 0; - return; - } - } - ConstantScanFunctionValidity(segment, state, vector_count, result); -} - //===--------------------------------------------------------------------===// // Get Function //===--------------------------------------------------------------------===// @@ -181,17 +94,14 @@ CompressionFunction ConstantGetFunctionValidity(PhysicalType data_type) { D_ASSERT(data_type == PhysicalType::BIT); return CompressionFunction(CompressionType::COMPRESSION_CONSTANT, data_type, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ConstantInitScan, ConstantScanFunctionValidity, - ConstantScanPartialValidity, ConstantFetchRowValidity, UncompressedFunctions::EmptySkip, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - ConstantSelectValidity, ConstantFilterValidity); + ConstantScanPartialValidity, ConstantFetchRowValidity, UncompressedFunctions::EmptySkip); } template CompressionFunction ConstantGetFunction(PhysicalType data_type) { return CompressionFunction(CompressionType::COMPRESSION_CONSTANT, data_type, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ConstantInitScan, ConstantScanFunction, ConstantScanPartial, - ConstantFetchRow, UncompressedFunctions::EmptySkip, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ConstantSelect); + ConstantFetchRow, UncompressedFunctions::EmptySkip); } CompressionFunction ConstantFun::GetFunction(PhysicalType data_type) { diff --git a/src/duckdb/src/storage/compression/rle.cpp b/src/duckdb/src/storage/compression/rle.cpp index 0144ff829..61524cda8 100644 --- a/src/duckdb/src/storage/compression/rle.cpp +++ b/src/duckdb/src/storage/compression/rle.cpp @@ -137,21 +137,22 @@ struct RLECompressState : public CompressionState { return (info.GetBlockSize() - RLEConstants::RLE_HEADER_SIZE) / entry_size; } - RLECompressState(ColumnDataCheckpointData &checkpoint_data_p, const CompressionInfo &info) - : CompressionState(info), checkpoint_data(checkpoint_data_p), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_RLE)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); + RLECompressState(ColumnDataCheckpointer &checkpointer_p, const CompressionInfo &info) + : CompressionState(info), checkpointer(checkpointer_p), + function(checkpointer.GetCompressionFunction(CompressionType::COMPRESSION_RLE)) { + CreateEmptySegment(checkpointer.GetRowGroup().start); state.dataptr = (void *)this; max_rle_count = MaxRLECount(); } void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); + auto &db = checkpointer.GetDatabase(); + auto &type = checkpointer.GetType(); - auto column_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, info.GetBlockSize(), - info.GetBlockSize()); + auto column_segment = + ColumnSegment::CreateTransientSegment(db, type, row_start, info.GetBlockSize(), info.GetBlockSize()); + column_segment->function = function; current_segment = std::move(column_segment); auto &buffer_manager = BufferManager::GetBufferManager(db); @@ -203,8 +204,8 @@ struct RLECompressState : public CompressionState { Store(minimal_rle_offset, data_ptr); handle.Destroy(); - auto &state = checkpoint_data.GetCheckpointState(); - state.FlushSegment(std::move(current_segment), std::move(handle), total_segment_size); + auto &state = checkpointer.GetCheckpointState(); + state.FlushSegment(std::move(current_segment), total_segment_size); } void Finalize() { @@ -214,7 +215,7 @@ struct RLECompressState : public CompressionState { current_segment.reset(); } - ColumnDataCheckpointData &checkpoint_data; + ColumnDataCheckpointer &checkpointer; CompressionFunction &function; unique_ptr current_segment; BufferHandle handle; @@ -225,9 +226,8 @@ struct RLECompressState : public CompressionState { }; template -unique_ptr RLEInitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr state) { - return make_uniq>(checkpoint_data, state->info); +unique_ptr RLEInitCompression(ColumnDataCheckpointer &checkpointer, unique_ptr state) { + return make_uniq>(checkpointer, state->info); } template @@ -259,43 +259,26 @@ struct RLEScanState : public SegmentScanState { D_ASSERT(rle_count_offset <= segment.GetBlockManager().GetBlockSize()); } - inline void SkipInternal(rle_count_t *index_pointer, idx_t skip_count) { - while (skip_count > 0) { - rle_count_t run_end = index_pointer[entry_pos]; - idx_t skip_amount = MinValue(skip_count, run_end - position_in_entry); - - skip_count -= skip_amount; - position_in_entry += skip_amount; - if (ExhaustedRun(index_pointer)) { - ForwardToNextRun(); - } - } - } - void Skip(ColumnSegment &segment, idx_t skip_count) { auto data = handle.Ptr() + segment.GetBlockOffset(); auto index_pointer = reinterpret_cast(data + rle_count_offset); - SkipInternal(index_pointer, skip_count); - } - inline void ForwardToNextRun() { - // handled all entries in this RLE value - // move to the next entry - entry_pos++; - position_in_entry = 0; - } - - inline bool ExhaustedRun(rle_count_t *index_pointer) { - return position_in_entry >= index_pointer[entry_pos]; + for (idx_t i = 0; i < skip_count; i++) { + // assign the current value + position_in_entry++; + if (position_in_entry >= index_pointer[entry_pos]) { + // handled all entries in this RLE value + // move to the next entry + entry_pos++; + position_in_entry = 0; + } + } } BufferHandle handle; idx_t entry_pos; idx_t position_in_entry; uint32_t rle_count_offset; - //! If we are running a filter over the column - the runs that match the filter - unsafe_unique_array matching_runs; - idx_t matching_run_count = 0; }; template @@ -329,6 +312,19 @@ static bool CanEmitConstantVector(idx_t position, idx_t run_length, idx_t scan_c return remaining_in_run >= scan_count; } +template +inline static void ForwardToNextRun(RLEScanState &scan_state) { + // handled all entries in this RLE value + // move to the next entry + scan_state.entry_pos++; + scan_state.position_in_entry = 0; +} + +template +inline static bool ExhaustedRun(RLEScanState &scan_state, rle_count_t *index_pointer) { + return scan_state.position_in_entry >= index_pointer[scan_state.entry_pos]; +} + template static void RLEScanConstant(RLEScanState &scan_state, rle_count_t *index_pointer, T *data_pointer, idx_t scan_count, Vector &result) { @@ -336,8 +332,8 @@ static void RLEScanConstant(RLEScanState &scan_state, rle_count_t *index_poin auto result_data = ConstantVector::GetData(result); result_data[0] = data_pointer[scan_state.entry_pos]; scan_state.position_in_entry += scan_count; - if (scan_state.ExhaustedRun(index_pointer)) { - scan_state.ForwardToNextRun(); + if (ExhaustedRun(scan_state, index_pointer)) { + ForwardToNextRun(scan_state); } return; } @@ -360,27 +356,13 @@ void RLEScanPartialInternal(ColumnSegment &segment, ColumnScanState &state, idx_ auto result_data = FlatVector::GetData(result); result.SetVectorType(VectorType::FLAT_VECTOR); - - idx_t result_end = result_offset + scan_count; - while (result_offset < result_end) { - rle_count_t run_end = index_pointer[scan_state.entry_pos]; - idx_t run_count = run_end - scan_state.position_in_entry; - idx_t remaining_scan_count = result_end - result_offset; - T element = data_pointer[scan_state.entry_pos]; - if (DUCKDB_UNLIKELY(run_count > remaining_scan_count)) { - for (idx_t i = 0; i < remaining_scan_count; i++) { - result_data[result_offset + i] = element; - } - scan_state.position_in_entry += remaining_scan_count; - break; + for (idx_t i = 0; i < scan_count; i++) { + // assign the current value + result_data[result_offset + i] = data_pointer[scan_state.entry_pos]; + scan_state.position_in_entry++; + if (ExhaustedRun(scan_state, index_pointer)) { + ForwardToNextRun(scan_state); } - - for (idx_t i = 0; i < run_count; i++) { - result_data[result_offset + i] = element; - } - - result_offset += run_count; - scan_state.ForwardToNextRun(); } } @@ -395,156 +377,6 @@ void RLEScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, V RLEScanPartialInternal(segment, state, scan_count, result, 0); } -//===--------------------------------------------------------------------===// -// Select -//===--------------------------------------------------------------------===// -template -void RLESelect(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, - const SelectionVector &sel, idx_t sel_count) { - auto &scan_state = state.scan_state->Cast>(); - - auto data = scan_state.handle.Ptr() + segment.GetBlockOffset(); - auto data_pointer = reinterpret_cast(data + RLEConstants::RLE_HEADER_SIZE); - auto index_pointer = reinterpret_cast(data + scan_state.rle_count_offset); - - // If we are scanning an entire Vector and it contains only a single run we don't need to select at all - if (CanEmitConstantVector(scan_state.position_in_entry, index_pointer[scan_state.entry_pos], vector_count)) { - RLEScanConstant(scan_state, index_pointer, data_pointer, vector_count, result); - return; - } - - auto result_data = FlatVector::GetData(result); - result.SetVectorType(VectorType::FLAT_VECTOR); - - idx_t prev_idx = 0; - for (idx_t i = 0; i < sel_count; i++) { - auto next_idx = sel.get_index(i); - if (next_idx < prev_idx) { - throw InternalException("Error in RLESelect - selection vector indices are not ordered"); - } - // skip forward to the next index - scan_state.SkipInternal(index_pointer, next_idx - prev_idx); - // read the element - result_data[i] = data_pointer[scan_state.entry_pos]; - // move the next to the prev - prev_idx = next_idx; - } - // skip the tail - scan_state.SkipInternal(index_pointer, vector_count - prev_idx); -} - -//===--------------------------------------------------------------------===// -// Filter -//===--------------------------------------------------------------------===// -template -void RLEFilter(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, Vector &result, SelectionVector &sel, - idx_t &sel_count, const TableFilter &filter) { - auto &scan_state = state.scan_state->Cast>(); - - auto data = scan_state.handle.Ptr() + segment.GetBlockOffset(); - auto data_pointer = reinterpret_cast(data + RLEConstants::RLE_HEADER_SIZE); - auto index_pointer = reinterpret_cast(data + scan_state.rle_count_offset); - - auto total_run_count = (scan_state.rle_count_offset - RLEConstants::RLE_HEADER_SIZE) / sizeof(T); - if (!scan_state.matching_runs) { - // we haven't applied the filter yet - // apply the filter to all RLE values at once - - // initialize the filter set to all false (all runs are filtered out) - scan_state.matching_runs = make_unsafe_uniq_array(total_run_count); - memset(scan_state.matching_runs.get(), 0, sizeof(bool) * total_run_count); - - // execute the filter over all runs at once - Vector run_vector(result.GetType(), data_ptr_cast(data_pointer)); - - UnifiedVectorFormat run_format; - run_vector.ToUnifiedFormat(total_run_count, run_format); - - SelectionVector run_matches; - scan_state.matching_run_count = total_run_count; - ColumnSegment::FilterSelection(run_matches, run_vector, run_format, filter, total_run_count, - scan_state.matching_run_count); - - // for any runs that pass the filter - set the matches to true - for (idx_t i = 0; i < scan_state.matching_run_count; i++) { - auto idx = run_matches.get_index(i); - scan_state.matching_runs[idx] = true; - } - } - if (scan_state.matching_run_count == 0) { - // early-out, no runs match the filter so the filter can never pass - sel_count = 0; - return; - } - // scan (the subset of) the matching runs AND set the output selection vector with the rows that match - auto result_data = FlatVector::GetData(result); - result.SetVectorType(VectorType::FLAT_VECTOR); - - idx_t matching_count = 0; - SelectionVector matching_sel(sel_count); - if (!sel.IsSet()) { - // no selection vector yet - fast path - // this is essentially the normal scan, but we apply the filter and fill the selection vector - idx_t result_offset = 0; - idx_t result_end = sel_count; - while (result_offset < result_end) { - rle_count_t run_end = index_pointer[scan_state.entry_pos]; - idx_t run_count = run_end - scan_state.position_in_entry; - idx_t remaining_scan_count = result_end - result_offset; - // the run is scanned - scan it - T element = data_pointer[scan_state.entry_pos]; - if (DUCKDB_UNLIKELY(run_count > remaining_scan_count)) { - if (scan_state.matching_runs[scan_state.entry_pos]) { - for (idx_t i = 0; i < remaining_scan_count; i++) { - result_data[result_offset + i] = element; - matching_sel.set_index(matching_count++, result_offset + i); - } - } - scan_state.position_in_entry += remaining_scan_count; - break; - } - - if (scan_state.matching_runs[scan_state.entry_pos]) { - for (idx_t i = 0; i < run_count; i++) { - result_data[result_offset + i] = element; - matching_sel.set_index(matching_count++, result_offset + i); - } - } - - result_offset += run_count; - scan_state.ForwardToNextRun(); - } - } else { - // we already have a selection applied - this is more complex since we need to merge it with our filter - // use a simpler (but slower) approach - idx_t prev_idx = 0; - for (idx_t i = 0; i < sel_count; i++) { - auto read_idx = sel.get_index(i); - if (read_idx < prev_idx) { - throw InternalException("Error in RLEFilter - selection vector indices are not ordered"); - } - // skip forward to the next index - scan_state.SkipInternal(index_pointer, read_idx - prev_idx); - prev_idx = read_idx; - if (!scan_state.matching_runs[scan_state.entry_pos]) { - // this run is filtered out - we don't need to scan it - continue; - } - // the run is not filtered out - read the element - result_data[read_idx] = data_pointer[scan_state.entry_pos]; - matching_sel.set_index(matching_count++, read_idx); - } - // skip the tail - scan_state.SkipInternal(index_pointer, vector_count - prev_idx); - } - - // set up the filter result - if (matching_count != sel_count) { - sel.Initialize(matching_sel); - sel_count = matching_count; - } -} - //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// @@ -567,9 +399,7 @@ CompressionFunction GetRLEFunction(PhysicalType data_type) { return CompressionFunction(CompressionType::COMPRESSION_RLE, data_type, RLEInitAnalyze, RLEAnalyze, RLEFinalAnalyze, RLEInitCompression, RLECompress, RLEFinalizeCompress, - RLEInitScan, RLEScan, RLEScanPartial, RLEFetchRow, RLESkip, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, RLESelect, - RLEFilter); + RLEInitScan, RLEScan, RLEScanPartial, RLEFetchRow, RLESkip); } CompressionFunction RLEFun::GetFunction(PhysicalType type) { diff --git a/src/duckdb/src/storage/compression/roaring/analyze.cpp b/src/duckdb/src/storage/compression/roaring/analyze.cpp deleted file mode 100644 index f5a49eb29..000000000 --- a/src/duckdb/src/storage/compression/roaring/analyze.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "duckdb/storage/compression/roaring/roaring.hpp" -#include "duckdb/storage/compression/roaring/appender.hpp" - -#include "duckdb/common/limits.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/bitpacking.hpp" - -namespace duckdb { - -namespace roaring { - -static unsafe_unique_array CreateBitmaskTable() { - unsafe_unique_array result; - result = make_unsafe_uniq_array_uninitialized(NumericLimits::Maximum() + 1); - - for (uint16_t val = 0; val < NumericLimits::Maximum() + 1; val++) { - bool previous_bit; - auto &entry = result[val]; - entry.valid_count = 0; - entry.run_count = 0; - for (uint8_t i = 0; i < 8; i++) { - const bool bit_set = val & (1 << i); - if (!i) { - entry.first_bit_set = bit_set; - } else if (i == 7) { - entry.last_bit_set = bit_set; - } - entry.valid_count += bit_set; - - if (i && !bit_set && previous_bit == true) { - entry.run_count++; - } - previous_bit = bit_set; - } - } - - return result; -} - -//===--------------------------------------------------------------------===// -// Analyze -//===--------------------------------------------------------------------===// -RoaringAnalyzeState::RoaringAnalyzeState(const CompressionInfo &info) - : AnalyzeState(info), bitmask_table(CreateBitmaskTable()) { -} - -void RoaringAnalyzeState::HandleByte(RoaringAnalyzeState &state, uint8_t array_index) { - auto bit_info = state.bitmask_table[static_cast(array_index)]; - - state.run_count += - bit_info.run_count + (bit_info.first_bit_set == false && (!state.count || state.last_bit_set == true)); - state.one_count += bit_info.valid_count; - D_ASSERT(bit_info.valid_count <= 8); - state.zero_count += 8 - bit_info.valid_count; - state.last_bit_set = bit_info.last_bit_set; - state.count += 8; -} - -static inline void HandleBit(RoaringAnalyzeState &state, bool bit_set) { - if (!bit_set && (state.count == 0 || state.last_bit_set == true)) { - state.run_count++; - } - state.one_count += bit_set; - state.zero_count += !bit_set; - state.last_bit_set = bit_set; - state.count++; -} - -void RoaringAnalyzeState::HandleRaggedByte(RoaringAnalyzeState &state, uint8_t array_index, idx_t relevant_bits) { - D_ASSERT(relevant_bits <= 8); - for (idx_t i = 0; i < relevant_bits; i++) { - const bool bit_set = array_index & (1 << i); - HandleBit(state, bit_set); - } -} - -void RoaringAnalyzeState::HandleAllValid(RoaringAnalyzeState &state, idx_t amount) { - state.one_count += amount; - state.last_bit_set = true; - state.count += amount; -} - -void RoaringAnalyzeState::HandleNoneValid(RoaringAnalyzeState &state, idx_t amount) { - if (!state.count || (state.last_bit_set != false)) { - state.run_count++; - } - state.zero_count += amount; - state.last_bit_set = false; - state.count += amount; -} - -idx_t RoaringAnalyzeState::Count(RoaringAnalyzeState &state) { - return state.count; -} - -void RoaringAnalyzeState::Flush(RoaringAnalyzeState &state) { - state.FlushContainer(); -} - -bool RoaringAnalyzeState::HasEnoughSpaceInSegment(idx_t required_space) { - D_ASSERT(space_used <= info.GetBlockSize()); - idx_t remaining_space = info.GetBlockSize() - space_used; - if (required_space > remaining_space) { - return false; - } - return true; -} - -void RoaringAnalyzeState::FlushSegment() { - if (!current_count) { - D_ASSERT(!space_used); - return; - } - metadata_collection.FlushSegment(); - total_size += space_used; - space_used = 0; - current_count = 0; - segment_count++; -} - -ContainerMetadata RoaringAnalyzeState::GetResult() { - return ContainerMetadata::CreateMetadata(count, zero_count, one_count, run_count); -} - -void RoaringAnalyzeState::FlushContainer() { - if (!count) { - return; - } - auto metadata = GetResult(); - idx_t runs_count = metadata_collection.GetRunContainerCount(); - idx_t arrays_count = metadata_collection.GetArrayAndBitsetContainerCount(); - - if (metadata.IsRun()) { - runs_count++; - } else { - arrays_count++; - } - - idx_t required_space = metadata_collection.GetMetadataSize(runs_count + arrays_count, runs_count, arrays_count); - - required_space += metadata.GetDataSizeInBytes(count); - if (!HasEnoughSpaceInSegment(required_space)) { - FlushSegment(); - } - container_metadata.push_back(metadata); - metadata_collection.AddMetadata(metadata); - space_used += required_space; - current_count += count; - - // Reset the container analyze state - one_count = 0; - zero_count = 0; - run_count = 0; - last_bit_set = false; - count = 0; -} - -void RoaringAnalyzeState::Analyze(Vector &input, idx_t count) { - auto &self = *this; - - RoaringStateAppender::AppendVector(self, input, count); - total_count += count; -} - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/roaring/common.cpp b/src/duckdb/src/storage/compression/roaring/common.cpp deleted file mode 100644 index e5dad7503..000000000 --- a/src/duckdb/src/storage/compression/roaring/common.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include "duckdb/storage/compression/roaring/roaring.hpp" - -#include "duckdb/common/limits.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/bitpacking.hpp" - -/* -Data layout per segment: - - Offsets -+--------------------------------------+ -| +------------------------------+ | -| | uint64_t metadata_offset | | -| +------------------------------+ | -+--------------------------------------+ - - [Container Data]+ -+------------------------------------------------------+ -| Uncompressed Array Container | -| +----------------------------------------------+ | -| | uint16_t values[] | | -| +----------------------------------------------+ | -| | -| Compressed Array Container | -| +----------------------------------------------+ | -| | uint8_t counts[COMPRESSED_SEGMENT_COUNT] | | -| | uint8_t values[] | | -| +----------------------------------------------+ | -+------------------------------------------------------+ -| Bitset Container | -| +----------------------------------------------+ | -| | uint32_t page_offset[] | | -| | uint64_t uncompressed_size[] | | -| | uint64_t compressed_size[] | | -| +----------------------------------------------+ | -| | -+------------------------------------------------------+ -| Uncompressed Run Container | -| +----------------------------------------------+ | -| | (uint16_t, uint16_t) runs[] | | -| +----------------------------------------------+ | -| | -| Compressed Run Container | -| +----------------------------------------------+ | -| | uint8_t counts[COMPRESSED_SEGMENT_COUNT] | | -| | (uint8_t, uint8_t) runs[] | | -| +----------------------------------------------+ | -+------------------------------------------------------+ - - Container Metadata -+--------------------------------------------+ -| Container Types | -| +------------------------------------+ | -| | uint8_t:1 is_run | | -| | uint8_t:1 is_inverted | | -| +------------------------------------+ | -| | -| Run Container Sizes | -| +------------------------------------+ | -| | uint8_t:7 size | | -| +------------------------------------+ | -| | -| Array/Bitset Container Sizes | -| +------------------------------------+ | -| | uint8_t:8 size | | -| +------------------------------------+ | -+--------------------------------------------+ -*/ - -namespace duckdb { - -namespace roaring { - -// Set all the bits from start (inclusive) to end (exclusive) to 0 -void SetInvalidRange(ValidityMask &result, idx_t start, idx_t end) { - if (end <= start) { - throw InternalException("SetInvalidRange called with end (%d) <= start (%d)", end, start); - } - result.EnsureWritable(); - auto result_data = (validity_t *)result.GetData(); - -#ifdef DEBUG - ValidityMask copy_for_verification(result.Capacity()); - copy_for_verification.EnsureWritable(); - for (idx_t i = 0; - i < AlignValue(result.Capacity()) / ValidityMask::BITS_PER_VALUE; i++) { - copy_for_verification.GetData()[i] = result.GetData()[i]; - } -#endif - idx_t index = start; - - if ((index % ValidityMask::BITS_PER_VALUE) != 0) { - // Adjust the high bits of the first entry - - // +======================================+ - // |xxxxxxxxxxxxxxxxxxxxxxxxx| | - // +======================================+ - // - // 'x': bits to set to 0 in the result - - idx_t right_bits = index % ValidityMask::BITS_PER_VALUE; - idx_t bits_to_set = ValidityMask::BITS_PER_VALUE - right_bits; - idx_t left_bits = 0; - if (index + bits_to_set > end) { - // Limit the amount of bits to set - left_bits = (index + bits_to_set) - end; - bits_to_set = end - index; - } - - // Prepare the mask - validity_t mask = ValidityUncompressed::LOWER_MASKS[right_bits]; - if (left_bits) { - // Mask off the part that we don't want to touch (if the range doesn't fully cover the bits) - mask |= ValidityUncompressed::UPPER_MASKS[left_bits]; - } - - idx_t entry_idx = index / ValidityMask::BITS_PER_VALUE; - index += bits_to_set; - result_data[entry_idx] &= mask; - } - - idx_t remaining_bits = end - index; - idx_t full_entries = remaining_bits / ValidityMask::BITS_PER_VALUE; - idx_t entry_idx = index / ValidityMask::BITS_PER_VALUE; - // Set all the entries that are fully covered by the range to 0 - for (idx_t i = 0; i < full_entries; i++) { - result_data[entry_idx + i] = (validity_t)0; - } - - if ((remaining_bits % ValidityMask::BITS_PER_VALUE) != 0) { - // The last entry touched by the range is only partially covered - - // +======================================+ - // | |xxxxxxxxxxxx| - // +======================================+ - // - // 'x': bits to set to 0 in the result - - idx_t bits_to_set = end % ValidityMask::BITS_PER_VALUE; - idx_t left_bits = ValidityMask::BITS_PER_VALUE - bits_to_set; - validity_t mask = ValidityUncompressed::UPPER_MASKS[left_bits]; - idx_t entry_idx = end / ValidityMask::BITS_PER_VALUE; - result_data[entry_idx] &= mask; - } - -#ifdef DEBUG - D_ASSERT(end <= result.Capacity()); - for (idx_t i = 0; i < result.Capacity(); i++) { - if (i >= start && i < end) { - D_ASSERT(!result.RowIsValidUnsafe(i)); - } else { - // Ensure no others bits are touched by this method - D_ASSERT(copy_for_verification.RowIsValidUnsafe(i) == result.RowIsValidUnsafe(i)); - } - } -#endif -} - -unique_ptr RoaringInitAnalyze(ColumnData &col_data, PhysicalType type) { - CompressionInfo info(col_data.GetBlockManager().GetBlockSize()); - auto state = make_uniq(info); - - return std::move(state); -} - -bool RoaringAnalyze(AnalyzeState &state, Vector &input, idx_t count) { - auto &analyze_state = state.Cast(); - analyze_state.Analyze(input, count); - return true; -} - -idx_t RoaringFinalAnalyze(AnalyzeState &state) { - auto &roaring_state = state.Cast(); - roaring_state.FlushContainer(); - roaring_state.FlushSegment(); - - constexpr const double ROARING_COMPRESS_PENALTY = 2.0; - return LossyNumericCast((double)roaring_state.total_size * ROARING_COMPRESS_PENALTY); -} - -unique_ptr RoaringInitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr state) { - return make_uniq(checkpoint_data, std::move(state)); -} - -void RoaringCompress(CompressionState &state_p, Vector &scan_vector, idx_t count) { - auto &state = state_p.Cast(); - state.Compress(scan_vector, count); -} - -void RoaringFinalizeCompress(CompressionState &state_p) { - auto &state = state_p.Cast(); - state.Finalize(); -} - -unique_ptr RoaringInitScan(ColumnSegment &segment) { - auto result = make_uniq(segment); - return std::move(result); -} - -//===--------------------------------------------------------------------===// -// Scan base data -//===--------------------------------------------------------------------===// -void RoaringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, - idx_t result_offset) { - auto &scan_state = state.scan_state->Cast(); - auto start = segment.GetRelativeIndex(state.row_index); - - scan_state.ScanPartial(start, result, result_offset, scan_count); -} - -void RoaringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result) { - RoaringScanPartial(segment, state, scan_count, result, 0); -} - -//===--------------------------------------------------------------------===// -// Fetch -//===--------------------------------------------------------------------===// -void RoaringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, idx_t result_idx) { - RoaringScanState scan_state(segment); - - idx_t internal_offset; - idx_t container_idx = scan_state.GetContainerIndex(static_cast(row_id), internal_offset); - auto &container_state = scan_state.LoadContainer(container_idx, internal_offset); - - scan_state.ScanInternal(container_state, 1, result, result_idx); -} - -void RoaringSkip(ColumnSegment &segment, ColumnScanState &state, idx_t skip_count) { - // NO OP - // We skip inside scan instead, if the container boundary gets crossed we can avoid a bunch of work anyways - return; -} - -unique_ptr RoaringInitSegment(ColumnSegment &segment, block_id_t block_id, - optional_ptr segment_state) { - // 'ValidityInitSegment' is used normally, which memsets the page to all bits set. - return nullptr; -} - -} // namespace roaring - -//===--------------------------------------------------------------------===// -// Get Function -//===--------------------------------------------------------------------===// -CompressionFunction GetCompressionFunction(PhysicalType data_type) { - return CompressionFunction(CompressionType::COMPRESSION_ROARING, data_type, roaring::RoaringInitAnalyze, - roaring::RoaringAnalyze, roaring::RoaringFinalAnalyze, roaring::RoaringInitCompression, - roaring::RoaringCompress, roaring::RoaringFinalizeCompress, roaring::RoaringInitScan, - roaring::RoaringScan, roaring::RoaringScanPartial, roaring::RoaringFetchRow, - roaring::RoaringSkip, roaring::RoaringInitSegment); -} - -CompressionFunction RoaringCompressionFun::GetFunction(PhysicalType type) { - switch (type) { - case PhysicalType::BIT: - return GetCompressionFunction(type); - default: - throw InternalException("Unsupported type for Roaring"); - } -} - -bool RoaringCompressionFun::TypeIsSupported(const PhysicalType physical_type) { - switch (physical_type) { - case PhysicalType::BIT: - return true; - default: - return false; - } -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/roaring/compress.cpp b/src/duckdb/src/storage/compression/roaring/compress.cpp deleted file mode 100644 index 77463d9e2..000000000 --- a/src/duckdb/src/storage/compression/roaring/compress.cpp +++ /dev/null @@ -1,478 +0,0 @@ -#include "duckdb/storage/compression/roaring/roaring.hpp" -#include "duckdb/storage/compression/roaring/appender.hpp" - -#include "duckdb/common/limits.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/bitpacking.hpp" - -namespace duckdb { - -namespace roaring { - -ContainerCompressionState::ContainerCompressionState() { - Reset(); -} - -inline void AppendBitset(ContainerCompressionState &state, bool null, uint16_t amount) { - D_ASSERT(state.uncompressed); - if (null) { - ValidityMask mask(state.uncompressed, ROARING_CONTAINER_SIZE); - SetInvalidRange(mask, state.appended_count, state.appended_count + amount); - } -} - -inline void AppendRun(ContainerCompressionState &state, bool null, uint16_t amount) { - // Adjust the run - auto run_idx = state.run_idx; - auto appended_count = state.appended_count; - if (!null && run_idx < MAX_RUN_IDX && appended_count && (null != state.last_is_null)) { - if (run_idx < COMPRESSED_RUN_THRESHOLD) { - auto &last_run = state.runs[run_idx]; - // End the last run - last_run.length = (appended_count - last_run.start) - 1; - } - state.compressed_runs[(run_idx * 2) + 1] = static_cast(appended_count & (COMPRESSED_SEGMENT_SIZE - 1)); - state.run_counts[appended_count >> COMPRESSED_SEGMENT_SHIFT_AMOUNT]++; - state.run_idx++; - } else if (null && run_idx < MAX_RUN_IDX && (!appended_count || null != state.last_is_null)) { - if (run_idx < COMPRESSED_RUN_THRESHOLD) { - auto ¤t_run = state.runs[run_idx]; - // Initialize a new run - current_run.start = appended_count; - } - state.compressed_runs[(run_idx * 2) + 0] = static_cast(appended_count & (COMPRESSED_SEGMENT_SIZE - 1)); - state.run_counts[appended_count >> COMPRESSED_SEGMENT_SHIFT_AMOUNT]++; - } -} - -template -inline void AppendToArray(ContainerCompressionState &state, bool null, uint16_t amount) { - if (DUCKDB_LIKELY(INVERTED != null)) { - return; - } - - auto current_array_idx = state.array_idx[null]; - if (current_array_idx + amount > MAX_ARRAY_IDX) { - return; - } - auto appended_count = state.appended_count; - auto array_count = state.array_counts[null]; - auto compressed_array = state.compressed_arrays[null]; - uint16_t appended = 0; - while (appended < amount) { - uint16_t remaining = amount - appended; - uint8_t segment_offset = appended ? 0 : (appended_count + appended) & (COMPRESSED_SEGMENT_SIZE - 1); - uint8_t to_append = - static_cast(MinValue(remaining, COMPRESSED_SEGMENT_SIZE - segment_offset)); - for (uint8_t i = 0; i < to_append; i++) { - auto index = current_array_idx + appended + i; - compressed_array[index] = segment_offset + i; - } - - idx_t segment_index = (appended_count + appended) / COMPRESSED_SEGMENT_SIZE; - array_count[segment_index] += to_append; - appended += to_append; - } - - if (current_array_idx + amount < COMPRESSED_ARRAY_THRESHOLD) { - auto &array = state.arrays[null]; - for (uint16_t i = 0; i < amount; i++) { - array[current_array_idx + i] = appended_count + i; - } - } - state.array_idx[null] += amount; -} - -void ContainerCompressionState::Append(bool null, uint16_t amount) { - append_function(*this, null, amount); - last_is_null = null; - null_count += null * amount; - appended_count += amount; -} - -void ContainerCompressionState::OverrideArray(data_ptr_t destination, bool nulls, idx_t count) { - if (nulls) { - append_function = AppendToArray; - } else { - append_function = AppendToArray; - } - - if (count >= COMPRESSED_ARRAY_THRESHOLD) { - memset(destination, 0, sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT); - array_counts[nulls] = reinterpret_cast(destination); - destination += sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT; - compressed_arrays[nulls] = reinterpret_cast(destination); - } else { - arrays[nulls] = reinterpret_cast(destination); - } -} - -void ContainerCompressionState::OverrideRun(data_ptr_t destination, idx_t count) { - append_function = AppendRun; - - if (count >= COMPRESSED_RUN_THRESHOLD) { - memset(destination, 0, sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT); - run_counts = reinterpret_cast(destination); - destination += sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT; - compressed_runs = reinterpret_cast(destination); - } else { - runs = reinterpret_cast(destination); - } -} - -void ContainerCompressionState::OverrideUncompressed(data_ptr_t destination) { - append_function = AppendBitset; - uncompressed = reinterpret_cast(destination); -} - -void ContainerCompressionState::Finalize() { - D_ASSERT(!finalized); - if (appended_count && last_is_null && run_idx < MAX_RUN_IDX) { - if (run_idx < COMPRESSED_RUN_THRESHOLD) { - auto &last_run = runs[run_idx]; - // End the last run - last_run.length = (appended_count - last_run.start); - } - compressed_runs[(run_idx * 2) + 1] = static_cast(appended_count % COMPRESSED_SEGMENT_SIZE); - if (appended_count != ROARING_CONTAINER_SIZE) { - run_counts[appended_count >> COMPRESSED_SEGMENT_SHIFT_AMOUNT]++; - } - run_idx++; - } - finalized = true; -} - -ContainerMetadata ContainerCompressionState::GetResult() { - if (uncompressed) { - return ContainerMetadata::BitsetContainer(appended_count); - } - D_ASSERT(finalized); - return ContainerMetadata::CreateMetadata(appended_count, array_idx[NULLS], array_idx[NON_NULLS], run_idx); -} - -void ContainerCompressionState::Reset() { - length = 0; - - appended_count = 0; - null_count = 0; - run_idx = 0; - array_idx[NON_NULLS] = 0; - array_idx[NULLS] = 0; - finalized = false; - last_is_null = false; - - // Reset the arrays + runs - arrays[NULLS] = base_arrays[NULLS]; - arrays[NON_NULLS] = base_arrays[NON_NULLS]; - runs = base_runs; - - compressed_arrays[NULLS] = base_compressed_arrays[NULLS]; - compressed_arrays[NON_NULLS] = base_compressed_arrays[NON_NULLS]; - compressed_runs = base_compressed_runs; - - array_counts[NULLS] = base_array_counts[NULLS]; - array_counts[NON_NULLS] = base_array_counts[NON_NULLS]; - run_counts = base_run_counts; - - memset(array_counts[NULLS], 0, sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT); - memset(array_counts[NON_NULLS], 0, sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT); - memset(run_counts, 0, sizeof(uint8_t) * COMPRESSED_SEGMENT_COUNT); - uncompressed = nullptr; -} - -//===--------------------------------------------------------------------===// -// Compress -//===--------------------------------------------------------------------===// -RoaringCompressState::RoaringCompressState(ColumnDataCheckpointData &checkpoint_data, - unique_ptr analyze_state_p) - : CompressionState(analyze_state_p->info), owned_analyze_state(std::move(analyze_state_p)), - analyze_state(owned_analyze_state->Cast()), container_state(), - container_metadata(analyze_state.container_metadata), checkpoint_data(checkpoint_data), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ROARING)) { - CreateEmptySegment(checkpoint_data.GetRowGroup().start); - total_count = 0; - InitializeContainer(); -} - -idx_t RoaringCompressState::GetContainerIndex() { - idx_t index = total_count / ROARING_CONTAINER_SIZE; - return index; -} - -idx_t RoaringCompressState::GetRemainingSpace() { - return static_cast(metadata_ptr - data_ptr); -} - -bool RoaringCompressState::CanStore(idx_t container_size, const ContainerMetadata &metadata) { - idx_t required_space = 0; - if (metadata.IsUncompressed()) { - // Account for the alignment we might need for this container - required_space += (AlignValue(reinterpret_cast(data_ptr))) - reinterpret_cast(data_ptr); - } - required_space += metadata.GetDataSizeInBytes(container_size); - - idx_t runs_count = metadata_collection.GetRunContainerCount(); - idx_t arrays_count = metadata_collection.GetArrayAndBitsetContainerCount(); -#ifdef DEBUG - idx_t current_size = metadata_collection.GetMetadataSize(runs_count + arrays_count, runs_count, arrays_count); - (void)current_size; - D_ASSERT(required_space + current_size <= GetRemainingSpace()); -#endif - if (metadata.IsRun()) { - runs_count++; - } else { - arrays_count++; - } - idx_t metadata_size = metadata_collection.GetMetadataSize(runs_count + arrays_count, runs_count, arrays_count); - required_space += metadata_size; - - if (required_space > GetRemainingSpace()) { - return false; - } - return true; -} - -void RoaringCompressState::InitializeContainer() { - if (total_count == analyze_state.total_count) { - // No more containers left - return; - } - auto container_index = GetContainerIndex(); - D_ASSERT(container_index < container_metadata.size()); - auto metadata = container_metadata[container_index]; - - idx_t container_size = AlignValue( - MinValue(analyze_state.total_count - container_state.appended_count, ROARING_CONTAINER_SIZE)); - if (!CanStore(container_size, metadata)) { - idx_t row_start = current_segment->start + current_segment->count; - FlushSegment(); - CreateEmptySegment(row_start); - } - - // Override the pointer to write directly into the block - if (metadata.IsUncompressed()) { - data_ptr = reinterpret_cast(AlignValue(reinterpret_cast(data_ptr))); - FastMemset(data_ptr, ~0, sizeof(validity_t) * (container_size / ValidityMask::BITS_PER_VALUE)); - container_state.OverrideUncompressed(data_ptr); - } else if (metadata.IsRun()) { - auto number_of_runs = metadata.NumberOfRuns(); - container_state.OverrideRun(data_ptr, number_of_runs); - } else { - auto cardinality = metadata.Cardinality(); - container_state.OverrideArray(data_ptr, metadata.IsInverted(), cardinality); - } - data_ptr += metadata.GetDataSizeInBytes(container_size); - metadata_collection.AddMetadata(metadata); -} - -void RoaringCompressState::CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); - - auto compressed_segment = - ColumnSegment::CreateTransientSegment(db, function, type, row_start, info.GetBlockSize(), info.GetBlockSize()); - current_segment = std::move(compressed_segment); - - auto &buffer_manager = BufferManager::GetBufferManager(db); - handle = buffer_manager.Pin(current_segment->block); - data_ptr = handle.Ptr(); - data_ptr += sizeof(idx_t); - metadata_ptr = handle.Ptr() + info.GetBlockSize(); -} - -void RoaringCompressState::FlushSegment() { - auto &state = checkpoint_data.GetCheckpointState(); - auto base_ptr = handle.Ptr(); - // +======================================+ - // |x|ddddddddddddddd||mmm| | - // +======================================+ - - // x: metadata_offset (to the "right" of it) - // d: data of the containers - // m: metadata of the containers - - // This is after 'x' - base_ptr += sizeof(idx_t); - - // Size of the 'd' part - idx_t data_size = NumericCast(data_ptr - base_ptr); - data_size = AlignValue(data_size); - - // Size of the 'm' part - idx_t metadata_size = metadata_collection.GetMetadataSizeForSegment(); - - if (current_segment->count.load() == 0) { - D_ASSERT(metadata_size == 0); - return; - } - - idx_t serialized_metadata_size = metadata_collection.Serialize(data_ptr); - metadata_collection.FlushSegment(); - (void)serialized_metadata_size; - D_ASSERT(metadata_size == serialized_metadata_size); - idx_t metadata_start = static_cast(data_ptr - base_ptr); - Store(metadata_start, handle.Ptr()); - idx_t total_segment_size = sizeof(idx_t) + data_size + metadata_size; - state.FlushSegment(std::move(current_segment), std::move(handle), total_segment_size); -} - -void RoaringCompressState::Finalize() { - FlushContainer(); - FlushSegment(); - current_segment.reset(); -} - -void RoaringCompressState::FlushContainer() { - if (container_state.length) { - container_state.Append(!container_state.last_bit_set, container_state.length); - container_state.length = 0; - } - - if (!container_state.appended_count) { - return; - } - container_state.Finalize(); -#ifdef DEBUG - auto container_index = GetContainerIndex(); - auto metadata = container_metadata[container_index]; - - idx_t container_size = container_state.appended_count; - if (!metadata.IsUncompressed()) { - unique_ptr scan_state; - if (metadata.IsRun()) { - D_ASSERT(metadata.IsInverted()); - auto number_of_runs = metadata.NumberOfRuns(); - if (number_of_runs >= COMPRESSED_RUN_THRESHOLD) { - auto segments = container_state.run_counts; - auto data_ptr = container_state.compressed_runs; - scan_state = make_uniq(container_index, container_size, number_of_runs, - segments, data_ptr); - } else { - auto data_ptr = reinterpret_cast(container_state.runs); - scan_state = - make_uniq(container_index, container_size, number_of_runs, data_ptr); - } - } else { - auto cardinality = metadata.Cardinality(); - if (cardinality >= COMPRESSED_ARRAY_THRESHOLD) { - if (metadata.IsInverted()) { - auto segments = reinterpret_cast(container_state.array_counts[NULLS]); - auto data_ptr = reinterpret_cast(container_state.compressed_arrays[NULLS]); - scan_state = make_uniq>(container_index, container_size, - cardinality, segments, data_ptr); - } else { - auto segments = reinterpret_cast(container_state.array_counts[NON_NULLS]); - auto data_ptr = reinterpret_cast(container_state.compressed_arrays[NON_NULLS]); - scan_state = make_uniq>( - container_index, container_size, cardinality, segments, data_ptr); - } - } else { - if (metadata.IsInverted()) { - auto data_ptr = reinterpret_cast(container_state.arrays[NULLS]); - scan_state = make_uniq>(container_index, container_size, cardinality, - data_ptr); - } else { - auto data_ptr = reinterpret_cast(container_state.arrays[NON_NULLS]); - scan_state = make_uniq>(container_index, container_size, - cardinality, data_ptr); - } - } - } - scan_state->Verify(); - } - -#endif - total_count += container_state.appended_count; - bool has_nulls = container_state.null_count != 0; - bool has_non_nulls = container_state.null_count != container_state.appended_count; - if (has_nulls || container_state.uncompressed) { - current_segment->stats.statistics.SetHasNullFast(); - } - if (has_non_nulls || container_state.uncompressed) { - current_segment->stats.statistics.SetHasNoNullFast(); - } - current_segment->count += container_state.appended_count; - container_state.Reset(); -} - -void RoaringCompressState::NextContainer() { - FlushContainer(); - InitializeContainer(); -} - -void RoaringCompressState::HandleByte(RoaringCompressState &state, uint8_t array_index) { - if (array_index == NumericLimits::Maximum()) { - HandleAllValid(state, 8); - } else if (array_index == 0) { - HandleNoneValid(state, 8); - } else { - HandleRaggedByte(state, array_index, 8); - } -} - -static inline void HandleBit(RoaringCompressState &state, bool bit_set) { - auto &container_state = state.container_state; - if (container_state.length && container_state.last_bit_set != bit_set) { - container_state.Append(!container_state.last_bit_set, container_state.length); - container_state.length = 0; - } - container_state.length += 1; - container_state.last_bit_set = bit_set; -} - -void RoaringCompressState::HandleRaggedByte(RoaringCompressState &state, uint8_t array_index, idx_t relevant_bits) { - D_ASSERT(relevant_bits <= 8); - for (idx_t i = 0; i < relevant_bits; i++) { - const bool bit_set = array_index & (1 << i); - HandleBit(state, bit_set); - } -} - -void RoaringCompressState::HandleAllValid(RoaringCompressState &state, idx_t amount) { - auto &container_state = state.container_state; - if (container_state.length && container_state.last_bit_set == false) { - container_state.Append(!container_state.last_bit_set, container_state.length); - container_state.length = 0; - } - container_state.length += amount; - container_state.last_bit_set = true; -} - -void RoaringCompressState::HandleNoneValid(RoaringCompressState &state, idx_t amount) { - auto &container_state = state.container_state; - if (container_state.length && container_state.last_bit_set == true) { - container_state.Append(!container_state.last_bit_set, container_state.length); - container_state.length = 0; - } - container_state.length += amount; - container_state.last_bit_set = false; -} - -idx_t RoaringCompressState::Count(RoaringCompressState &state) { - auto &container_state = state.container_state; - // How much is appended and waiting to be appended - return container_state.appended_count + container_state.length; -} - -void RoaringCompressState::Flush(RoaringCompressState &state) { - state.NextContainer(); -} - -void RoaringCompressState::Compress(Vector &input, idx_t count) { - auto &self = *this; - RoaringStateAppender::AppendVector(self, input, count); -} - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/roaring/metadata.cpp b/src/duckdb/src/storage/compression/roaring/metadata.cpp deleted file mode 100644 index 9322f5a34..000000000 --- a/src/duckdb/src/storage/compression/roaring/metadata.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include "duckdb/storage/compression/roaring/roaring.hpp" - -#include "duckdb/common/limits.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/bitpacking.hpp" - -namespace duckdb { - -namespace roaring { - -ContainerMetadata ContainerMetadata::CreateMetadata(uint16_t count, uint16_t array_null, uint16_t array_non_null, - uint16_t runs) { - const bool can_use_null_array = array_null < MAX_ARRAY_IDX; - const bool can_use_non_null_array = array_non_null < MAX_ARRAY_IDX; - - const bool can_use_run = runs < MAX_RUN_IDX; - - const bool can_use_array = can_use_null_array || can_use_non_null_array; - if (!can_use_array && !can_use_run) { - // Can not efficiently encode at all, write it as bitset - return ContainerMetadata::BitsetContainer(count); - } - uint16_t null_array_cost = array_null < COMPRESSED_ARRAY_THRESHOLD - ? array_null * sizeof(uint16_t) - : COMPRESSED_SEGMENT_COUNT + (array_null * sizeof(uint8_t)); - uint16_t non_null_array_cost = array_non_null < COMPRESSED_ARRAY_THRESHOLD - ? array_non_null * sizeof(uint16_t) - : COMPRESSED_SEGMENT_COUNT + (array_non_null * sizeof(uint8_t)); - - uint16_t lowest_array_cost = MinValue(null_array_cost, non_null_array_cost); - uint16_t lowest_run_cost = runs < COMPRESSED_RUN_THRESHOLD ? runs * sizeof(uint32_t) - : COMPRESSED_SEGMENT_COUNT + (runs * sizeof(uint16_t)); - uint16_t bitset_cost = - (AlignValue(count) / ValidityMask::BITS_PER_VALUE) * sizeof(validity_t); - if (MinValue(lowest_array_cost, lowest_run_cost) > bitset_cost) { - // The amount of values is too small, better off using bitset - // we can detect this at decompression because we know how many values are left - return ContainerMetadata::BitsetContainer(count); - } - - if (lowest_array_cost <= lowest_run_cost) { - if (array_null <= array_non_null) { - return ContainerMetadata::ArrayContainer(array_null, NULLS); - } else { - return ContainerMetadata::ArrayContainer(array_non_null, NON_NULLS); - } - } else { - return ContainerMetadata::RunContainer(runs); - } -} - -idx_t ContainerMetadata::GetDataSizeInBytes(idx_t container_size) const { - if (IsUncompressed()) { - return (container_size / ValidityMask::BITS_PER_VALUE) * sizeof(validity_t); - } - if (IsRun()) { - auto number_of_runs = NumberOfRuns(); - if (number_of_runs >= COMPRESSED_RUN_THRESHOLD) { - return COMPRESSED_SEGMENT_COUNT + (sizeof(uint8_t) * number_of_runs * 2); - } else { - return sizeof(RunContainerRLEPair) * number_of_runs; - } - } else { - auto cardinality = Cardinality(); - if (cardinality >= COMPRESSED_ARRAY_THRESHOLD) { - return COMPRESSED_SEGMENT_COUNT + (sizeof(uint8_t) * cardinality); - } else { - return sizeof(uint16_t) * cardinality; - } - } -} - -ContainerMetadataCollection::ContainerMetadataCollection() { -} - -void ContainerMetadataCollection::AddMetadata(ContainerMetadata metadata) { - if (metadata.IsRun()) { - AddRunContainer(metadata.NumberOfRuns(), metadata.IsInverted()); - } else if (metadata.IsUncompressed()) { - AddBitsetContainer(); - } else { - AddArrayContainer(metadata.Cardinality(), metadata.IsInverted()); - } -} - -idx_t ContainerMetadataCollection::GetMetadataSizeForSegment() const { - idx_t runs_count = GetRunContainerCount(); - idx_t arrays_count = GetArrayAndBitsetContainerCount(); - return GetMetadataSize(runs_count + arrays_count, runs_count, arrays_count); -} - -idx_t ContainerMetadataCollection::GetMetadataSize(idx_t container_count, idx_t run_containers, - idx_t array_containers) const { - idx_t types_size = BitpackingPrimitives::GetRequiredSize(container_count, CONTAINER_TYPE_BITWIDTH); - idx_t runs_size = BitpackingPrimitives::GetRequiredSize(run_containers, RUN_CONTAINER_SIZE_BITWIDTH); - idx_t arrays_size = sizeof(uint8_t) * array_containers; - return types_size + runs_size + arrays_size; -} - -idx_t ContainerMetadataCollection::GetRunContainerCount() const { - return runs_in_segment; -} -idx_t ContainerMetadataCollection::GetArrayAndBitsetContainerCount() const { - return arrays_in_segment; -} - -void ContainerMetadataCollection::FlushSegment() { - runs_in_segment = 0; - count_in_segment = 0; - arrays_in_segment = 0; -} - -void ContainerMetadataCollection::Reset() { - FlushSegment(); - container_type.clear(); - number_of_runs.clear(); - cardinality.clear(); -} - -// Write the metadata for the current segment -idx_t ContainerMetadataCollection::Serialize(data_ptr_t dest) const { - // Element sizes (in bits) for written metadata - // +======================================+ - // |mmmmmm|rrrrrr|aaaaaaa| | - // +======================================+ - // - // m: 2: (1: is_run, 1: is_inverted) - // r: 7: number_of_runs - // a: 8: cardinality - - idx_t types_size = BitpackingPrimitives::GetRequiredSize(count_in_segment, CONTAINER_TYPE_BITWIDTH); - idx_t runs_size = BitpackingPrimitives::GetRequiredSize(runs_in_segment, RUN_CONTAINER_SIZE_BITWIDTH); - idx_t arrays_size = sizeof(uint8_t) * arrays_in_segment; - - idx_t types_offset = container_type.size() - count_in_segment; - data_ptr_t types_data = (data_ptr_t)(container_type.data()); // NOLINT: c-style cast (for const) - BitpackingPrimitives::PackBuffer(dest, types_data + types_offset, count_in_segment, - CONTAINER_TYPE_BITWIDTH); - dest += types_size; - - if (!number_of_runs.empty()) { - idx_t runs_offset = number_of_runs.size() - runs_in_segment; - data_ptr_t run_data = (data_ptr_t)(number_of_runs.data()); // NOLINT: c-style cast (for const) - BitpackingPrimitives::PackBuffer(dest, run_data + runs_offset, runs_in_segment, - RUN_CONTAINER_SIZE_BITWIDTH); - dest += runs_size; - } - - if (!cardinality.empty()) { - idx_t arrays_offset = cardinality.size() - arrays_in_segment; - data_ptr_t arrays_data = (data_ptr_t)(cardinality.data()); // NOLINT: c-style cast (for const) - memcpy(dest, arrays_data + arrays_offset, sizeof(uint8_t) * arrays_in_segment); - } - return types_size + runs_size + arrays_size; -} - -void ContainerMetadataCollection::Deserialize(data_ptr_t src, idx_t container_count) { - container_type.resize(AlignValue(container_count)); - count_in_segment = container_count; - - // Load the types of the containers - idx_t types_size = BitpackingPrimitives::GetRequiredSize(container_type.size(), 2); - BitpackingPrimitives::UnPackBuffer(container_type.data(), src, container_count, 2, true); - src += types_size; - - // Figure out how many are run containers - idx_t runs_count = 0; - for (idx_t i = 0; i < container_count; i++) { - auto type = container_type[i]; - runs_count += ((type >> 1) & 1) == 1; - } - runs_in_segment = runs_count; - number_of_runs.resize(AlignValue(runs_count)); - cardinality.resize(container_count - runs_count); - - // Load the run containers - if (runs_count) { - idx_t runs_size = BitpackingPrimitives::GetRequiredSize(runs_count, RUN_CONTAINER_SIZE_BITWIDTH); - BitpackingPrimitives::UnPackBuffer(number_of_runs.data(), src, runs_count, RUN_CONTAINER_SIZE_BITWIDTH, - true); - src += runs_size; - } - - // Load the array/bitset containers - if (!cardinality.empty()) { - idx_t arrays_size = sizeof(uint8_t) * cardinality.size(); - arrays_in_segment = arrays_size; - memcpy(cardinality.data(), src, arrays_size); - } -} - -void ContainerMetadataCollection::AddBitsetContainer() { - AddContainerType(false, false); - cardinality.push_back(BITSET_CONTAINER_SENTINEL_VALUE); - arrays_in_segment++; - count_in_segment++; -} - -void ContainerMetadataCollection::AddArrayContainer(idx_t amount, bool is_inverted) { - AddContainerType(false, is_inverted); - D_ASSERT(amount < MAX_ARRAY_IDX); - cardinality.push_back(NumericCast(amount)); - arrays_in_segment++; - count_in_segment++; -} - -void ContainerMetadataCollection::AddRunContainer(idx_t amount, bool is_inverted) { - AddContainerType(true, is_inverted); - D_ASSERT(amount < MAX_RUN_IDX); - number_of_runs.push_back(NumericCast(amount)); - runs_in_segment++; - count_in_segment++; -} - -void ContainerMetadataCollection::AddContainerType(bool is_run, bool is_inverted) { - uint8_t type = 0; - if (is_run) { - type |= IS_RUN_FLAG; - } - if (is_inverted) { - type |= IS_INVERTED_FLAG; - } - container_type.push_back(type); -} - -ContainerMetadataCollectionScanner::ContainerMetadataCollectionScanner(ContainerMetadataCollection &collection) - : collection(collection) { -} - -ContainerMetadata ContainerMetadataCollectionScanner::GetNext() { - D_ASSERT(idx < collection.count_in_segment); - auto type = collection.container_type[idx++]; - const bool is_inverted = (type & 1) == 1; - const bool is_run = ((type >> 1) & 1) == 1; - uint8_t amount; - if (is_run) { - amount = collection.number_of_runs[run_idx++]; - } else { - amount = collection.cardinality[array_idx++]; - } - if (is_run) { - return ContainerMetadata::RunContainer(amount); - } - if (amount == BITSET_CONTAINER_SENTINEL_VALUE) { - return ContainerMetadata::BitsetContainer(amount); - } - return ContainerMetadata::ArrayContainer(amount, is_inverted); -} - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/roaring/scan.cpp b/src/duckdb/src/storage/compression/roaring/scan.cpp deleted file mode 100644 index 73ef83bfe..000000000 --- a/src/duckdb/src/storage/compression/roaring/scan.cpp +++ /dev/null @@ -1,358 +0,0 @@ -#include "duckdb/storage/compression/roaring/roaring.hpp" - -#include "duckdb/common/limits.hpp" -#include "duckdb/common/likely.hpp" -#include "duckdb/common/numeric_utils.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/function/compression_function.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/storage/buffer_manager.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/table/column_segment.hpp" -#include "duckdb/storage/table/scan_state.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" -#include "duckdb/common/fast_mem.hpp" -#include "duckdb/common/bitpacking.hpp" - -namespace duckdb { - -namespace roaring { - -//===--------------------------------------------------------------------===// -// Scan -//===--------------------------------------------------------------------===// - -ContainerSegmentScan::ContainerSegmentScan(data_ptr_t data) - : segments(reinterpret_cast(data)), index(0), count(0) { -} - -// Returns the base of the current segment, forwarding the index if the segment is depleted of values -uint16_t ContainerSegmentScan::operator++(int) { - while (index < COMPRESSED_SEGMENT_COUNT && count >= segments[index]) { - count = 0; - index++; - } - count++; - - // index == COMPRESSED_SEGMENT_COUNT is allowed for runs, as the last run could end at ROARING_CONTAINER_SIZE - D_ASSERT(index <= COMPRESSED_SEGMENT_COUNT); - if (index < COMPRESSED_SEGMENT_COUNT) { - D_ASSERT(segments[index] != 0); - } - uint16_t base = static_cast(index) * COMPRESSED_SEGMENT_SIZE; - return base; -} - -//===--------------------------------------------------------------------===// -// ContainerScanState -//===--------------------------------------------------------------------===// - -//! RunContainer - -RunContainerScanState::RunContainerScanState(idx_t container_index, idx_t container_size, idx_t count, - data_ptr_t data_p) - : ContainerScanState(container_index, container_size), count(count), data(data_p) { -} - -void RunContainerScanState::ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) { - auto &result_mask = FlatVector::Validity(result); - - // This method assumes that the validity mask starts off as having all bits set for the entries that are being - // scanned. - - idx_t result_idx = 0; - if (!run_index) { - LoadNextRun(); - } - while (!finished && result_idx < to_scan) { - // Either we are already inside a run, then 'start_of_run' will be scanned_count - // or we're skipping values until the run begins - auto start_of_run = - MaxValue(MinValue(run.start, scanned_count + to_scan), scanned_count + result_idx); - result_idx = start_of_run - scanned_count; - - // How much of the run are we covering? - idx_t run_end = run.start + 1 + run.length; - auto run_or_scan_end = MinValue(run_end, scanned_count + to_scan); - - // Process the run - D_ASSERT(run_or_scan_end >= start_of_run); - if (run_or_scan_end > start_of_run) { - idx_t amount = run_or_scan_end - start_of_run; - idx_t start = result_offset + result_idx; - idx_t end = start + amount; - SetInvalidRange(result_mask, start, end); - } - - result_idx += run_or_scan_end - start_of_run; - if (scanned_count + result_idx == run_end) { - // Fully processed the current run - LoadNextRun(); - } - } - scanned_count += to_scan; -} - -void RunContainerScanState::Skip(idx_t to_skip) { - idx_t end = scanned_count + to_skip; - if (!run_index) { - LoadNextRun(); - } - while (scanned_count < end && !finished) { - idx_t run_end = run.start + 1 + run.length; - scanned_count = MinValue(run_end, end); - if (scanned_count == run_end) { - LoadNextRun(); - } - } - // In case run_index has already reached count - scanned_count = end; -} - -void RunContainerScanState::Verify() const { -#ifdef DEBUG - uint16_t index = 0; - for (idx_t i = 0; i < count; i++) { - auto run = reinterpret_cast(data)[i]; - D_ASSERT(run.start >= index); - index = run.start + 1 + run.length; - } -#endif -} - -void RunContainerScanState::LoadNextRun() { - if (run_index >= count) { - finished = true; - return; - } - run = reinterpret_cast(data)[run_index]; - run_index++; -} - -CompressedRunContainerScanState::CompressedRunContainerScanState(idx_t container_index, idx_t container_size, - idx_t count, data_ptr_t segments, data_ptr_t data) - : RunContainerScanState(container_index, container_size, count, data), segments(segments), segment(segments) { - D_ASSERT(count >= COMPRESSED_RUN_THRESHOLD); - //! Used by Verify, have to use it to avoid a compiler warning/error - (void)this->segments; -} - -void CompressedRunContainerScanState::LoadNextRun() { - if (run_index >= count) { - finished = true; - return; - } - uint16_t start = segment++; - start += reinterpret_cast(data)[(run_index * 2) + 0]; - - uint16_t end = segment++; - end += reinterpret_cast(data)[(run_index * 2) + 1]; - - D_ASSERT(end > start); - run = RunContainerRLEPair {start, static_cast(end - 1 - start)}; - run_index++; -} - -void CompressedRunContainerScanState::Verify() const { -#ifdef DEBUG - uint16_t index = 0; - ContainerSegmentScan verify_segment(segments); - for (idx_t i = 0; i < count; i++) { - // Get the start index of the run - uint16_t start = verify_segment++; - start += reinterpret_cast(data)[(i * 2) + 0]; - - // Get the end index of the run - uint16_t end = verify_segment++; - end += reinterpret_cast(data)[(i * 2) + 1]; - - D_ASSERT(!i || start >= index); - D_ASSERT(end > start); - index = end; - } -#endif -} - -//! BitsetContainer - -BitsetContainerScanState::BitsetContainerScanState(idx_t container_index, idx_t count, validity_t *bitset) - : ContainerScanState(container_index, count), bitset(bitset) { -} - -void BitsetContainerScanState::ScanPartial(Vector &result, idx_t result_offset, idx_t to_scan) { - if (!result_offset && (to_scan % ValidityMask::BITS_PER_VALUE) == 0 && - (scanned_count % ValidityMask::BITS_PER_VALUE) == 0) { - ValidityUncompressed::AlignedScan(reinterpret_cast(bitset), scanned_count, result, to_scan); - } else { - ValidityUncompressed::UnalignedScan(reinterpret_cast(bitset), container_size, scanned_count, result, - result_offset, to_scan); - } - scanned_count += to_scan; -} - -void BitsetContainerScanState::Skip(idx_t to_skip) { - // NO OP: we only need to forward scanned_count - scanned_count += to_skip; -} - -void BitsetContainerScanState::Verify() const { - // uncompressed, nothing to verify - return; -} - -RoaringScanState::RoaringScanState(ColumnSegment &segment) : segment(segment) { - auto &buffer_manager = BufferManager::GetBufferManager(segment.db); - handle = buffer_manager.Pin(segment.block); - auto base_ptr = handle.Ptr() + segment.GetBlockOffset(); - data_ptr = base_ptr + sizeof(idx_t); - - // Deserialize the container metadata for this segment - auto metadata_offset = Load(base_ptr); - auto metadata_ptr = data_ptr + metadata_offset; - - auto segment_count = segment.count.load(); - auto container_count = segment_count / ROARING_CONTAINER_SIZE; - if (segment_count % ROARING_CONTAINER_SIZE != 0) { - container_count++; - } - metadata_collection.Deserialize(metadata_ptr, container_count); - ContainerMetadataCollectionScanner scanner(metadata_collection); - data_start_position.reserve(container_count); - idx_t position = 0; - for (idx_t i = 0; i < container_count; i++) { - auto metadata = scanner.GetNext(); - container_metadata.push_back(metadata); - if (metadata.IsUncompressed()) { - position = AlignValue(position); - } - data_start_position.push_back(position); - position += SkipVector(metadata); - } -} - -idx_t RoaringScanState::SkipVector(const ContainerMetadata &metadata) { - // NOTE: this doesn't care about smaller containers, since only the last container can be smaller - return metadata.GetDataSizeInBytes(ROARING_CONTAINER_SIZE); -} - -bool RoaringScanState::UseContainerStateCache(idx_t container_index, idx_t internal_offset) { - if (!current_container) { - // No container loaded yet - return false; - } - if (current_container->container_index != container_index) { - // Not the same container - return false; - } - if (current_container->scanned_count != internal_offset) { - // Not the same scan offset - return false; - } - return true; -} - -ContainerMetadata RoaringScanState::GetContainerMetadata(idx_t container_index) { - return container_metadata[container_index]; -} - -data_ptr_t RoaringScanState::GetStartOfContainerData(idx_t container_index) { - return data_ptr + data_start_position[container_index]; -} - -ContainerScanState &RoaringScanState::LoadContainer(idx_t container_index, idx_t internal_offset) { - if (UseContainerStateCache(container_index, internal_offset)) { - return *current_container; - } - auto metadata = GetContainerMetadata(container_index); - auto data_ptr = GetStartOfContainerData(container_index); - - auto segment_count = segment.count.load(); - auto start_of_container = container_index * ROARING_CONTAINER_SIZE; - auto container_size = MinValue(segment_count - start_of_container, ROARING_CONTAINER_SIZE); - if (metadata.IsUncompressed()) { - current_container = make_uniq(container_index, container_size, - reinterpret_cast(data_ptr)); - } else if (metadata.IsRun()) { - D_ASSERT(metadata.IsInverted()); - auto number_of_runs = metadata.NumberOfRuns(); - if (number_of_runs >= COMPRESSED_RUN_THRESHOLD) { - auto segments = data_ptr; - data_ptr = segments + COMPRESSED_SEGMENT_COUNT; - current_container = make_uniq(container_index, container_size, - number_of_runs, segments, data_ptr); - } else { - current_container = - make_uniq(container_index, container_size, number_of_runs, data_ptr); - } - } else { - auto cardinality = metadata.Cardinality(); - if (cardinality >= COMPRESSED_ARRAY_THRESHOLD) { - auto segments = data_ptr; - data_ptr = segments + COMPRESSED_SEGMENT_COUNT; - if (metadata.IsInverted()) { - current_container = make_uniq>( - container_index, container_size, cardinality, segments, data_ptr); - } else { - current_container = make_uniq>( - container_index, container_size, cardinality, segments, data_ptr); - } - } else { - if (metadata.IsInverted()) { - current_container = - make_uniq>(container_index, container_size, cardinality, data_ptr); - } else { - current_container = make_uniq>(container_index, container_size, - cardinality, data_ptr); - } - } - } - - current_container->Verify(); - - auto &scan_state = *current_container; - if (internal_offset) { - Skip(scan_state, internal_offset); - } - return *current_container; -} - -void RoaringScanState::ScanInternal(ContainerScanState &scan_state, idx_t to_scan, Vector &result, idx_t offset) { - scan_state.ScanPartial(result, offset, to_scan); -} - -idx_t RoaringScanState::GetContainerIndex(idx_t start_index, idx_t &offset) { - idx_t container_index = start_index / ROARING_CONTAINER_SIZE; - offset = start_index % ROARING_CONTAINER_SIZE; - return container_index; -} - -void RoaringScanState::ScanPartial(idx_t start_idx, Vector &result, idx_t offset, idx_t count) { - result.Flatten(count); - idx_t remaining = count; - idx_t scanned = 0; - while (remaining) { - idx_t internal_offset; - idx_t container_idx = GetContainerIndex(start_idx + scanned, internal_offset); - auto &scan_state = LoadContainer(container_idx, internal_offset); - idx_t remaining_in_container = scan_state.container_size - scan_state.scanned_count; - idx_t to_scan = MinValue(remaining, remaining_in_container); - ScanInternal(scan_state, to_scan, result, offset + scanned); - remaining -= to_scan; - scanned += to_scan; - } - D_ASSERT(scanned == count); -} - -void RoaringScanState::Skip(ContainerScanState &scan_state, idx_t skip_count) { - D_ASSERT(scan_state.scanned_count + skip_count <= scan_state.container_size); - if (scan_state.scanned_count + skip_count == scan_state.container_size) { - scan_state.scanned_count = scan_state.container_size; - // This skips all remaining values covered by this container - return; - } - scan_state.Skip(skip_count); -} - -} // namespace roaring - -} // namespace duckdb diff --git a/src/duckdb/src/storage/compression/string_uncompressed.cpp b/src/duckdb/src/storage/compression/string_uncompressed.cpp index a2279529f..aa340f781 100644 --- a/src/duckdb/src/storage/compression/string_uncompressed.cpp +++ b/src/duckdb/src/storage/compression/string_uncompressed.cpp @@ -102,10 +102,9 @@ void UncompressedStringStorage::StringScanPartial(ColumnSegment &segment, Column for (idx_t i = 0; i < scan_count; i++) { // std::abs used since offsets can be negative to indicate big strings - auto current_offset = base_data[start + i]; - auto string_length = UnsafeNumericCast(std::abs(current_offset) - std::abs(previous_offset)); + auto string_length = UnsafeNumericCast(std::abs(base_data[start + i]) - std::abs(previous_offset)); result_data[result_offset + i] = - FetchStringFromDict(segment, dict, result, baseptr, current_offset, string_length); + FetchStringFromDict(segment, dict, result, baseptr, base_data[start + i], string_length); previous_offset = base_data[start + i]; } } @@ -115,29 +114,6 @@ void UncompressedStringStorage::StringScan(ColumnSegment &segment, ColumnScanSta StringScanPartial(segment, state, scan_count, result, 0); } -//===--------------------------------------------------------------------===// -// Select -//===--------------------------------------------------------------------===// -void UncompressedStringStorage::Select(ColumnSegment &segment, ColumnScanState &state, idx_t vector_count, - Vector &result, const SelectionVector &sel, idx_t sel_count) { - // clear any previously locked buffers and get the primary buffer handle - auto &scan_state = state.scan_state->Cast(); - auto start = segment.GetRelativeIndex(state.row_index); - - auto baseptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); - auto dict = GetDictionary(segment, scan_state.handle); - auto base_data = reinterpret_cast(baseptr + DICTIONARY_HEADER_SIZE); - auto result_data = FlatVector::GetData(result); - - for (idx_t i = 0; i < sel_count; i++) { - idx_t index = start + sel.get_index(i); - auto current_offset = base_data[index]; - auto prev_offset = index > 0 ? base_data[index - 1] : 0; - auto string_length = UnsafeNumericCast(std::abs(current_offset) - std::abs(prev_offset)); - result_data[i] = FetchStringFromDict(segment, dict, result, baseptr, current_offset, string_length); - } -} - //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// @@ -170,7 +146,7 @@ void UncompressedStringStorage::StringFetchRow(ColumnSegment &segment, ColumnFet auto dict_offset = base_data[row_id]; uint32_t string_length; - if (DUCKDB_UNLIKELY(row_id == 0LL)) { + if ((idx_t)row_id == 0) { // edge case where this is the first string in the dict string_length = NumericCast(std::abs(dict_offset)); } else { @@ -182,16 +158,17 @@ void UncompressedStringStorage::StringFetchRow(ColumnSegment &segment, ColumnFet //===--------------------------------------------------------------------===// // Append //===--------------------------------------------------------------------===// -SerializedStringSegmentState::SerializedStringSegmentState() { -} - -SerializedStringSegmentState::SerializedStringSegmentState(vector blocks_p) { - blocks = std::move(blocks_p); -} +struct SerializedStringSegmentState : public ColumnSegmentState { + SerializedStringSegmentState() { + } + explicit SerializedStringSegmentState(vector blocks_p) { + blocks = std::move(blocks_p); + } -void SerializedStringSegmentState::Serialize(Serializer &serializer) const { - serializer.WriteProperty(1, "overflow_blocks", blocks); -} + void Serialize(Serializer &serializer) const override { + serializer.WriteProperty(1, "overflow_blocks", blocks); + } +}; unique_ptr UncompressedStringStorage::StringInitSegment(ColumnSegment &segment, block_id_t block_id, @@ -270,17 +247,17 @@ void UncompressedStringStorage::CleanupState(ColumnSegment &segment) { //===--------------------------------------------------------------------===// CompressionFunction StringUncompressed::GetFunction(PhysicalType data_type) { D_ASSERT(data_type == PhysicalType::VARCHAR); - return CompressionFunction( - CompressionType::COMPRESSION_UNCOMPRESSED, data_type, UncompressedStringStorage::StringInitAnalyze, - UncompressedStringStorage::StringAnalyze, UncompressedStringStorage::StringFinalAnalyze, - UncompressedFunctions::InitCompression, UncompressedFunctions::Compress, - UncompressedFunctions::FinalizeCompress, UncompressedStringStorage::StringInitScan, - UncompressedStringStorage::StringScan, UncompressedStringStorage::StringScanPartial, - UncompressedStringStorage::StringFetchRow, UncompressedFunctions::EmptySkip, - UncompressedStringStorage::StringInitSegment, UncompressedStringStorage::StringInitAppend, - UncompressedStringStorage::StringAppend, UncompressedStringStorage::FinalizeAppend, nullptr, - UncompressedStringStorage::SerializeState, UncompressedStringStorage::DeserializeState, - UncompressedStringStorage::CleanupState, UncompressedStringInitPrefetch, UncompressedStringStorage::Select); + return CompressionFunction(CompressionType::COMPRESSION_UNCOMPRESSED, data_type, + UncompressedStringStorage::StringInitAnalyze, UncompressedStringStorage::StringAnalyze, + UncompressedStringStorage::StringFinalAnalyze, UncompressedFunctions::InitCompression, + UncompressedFunctions::Compress, UncompressedFunctions::FinalizeCompress, + UncompressedStringStorage::StringInitScan, UncompressedStringStorage::StringScan, + UncompressedStringStorage::StringScanPartial, UncompressedStringStorage::StringFetchRow, + UncompressedFunctions::EmptySkip, UncompressedStringStorage::StringInitSegment, + UncompressedStringStorage::StringInitAppend, UncompressedStringStorage::StringAppend, + UncompressedStringStorage::FinalizeAppend, nullptr, + UncompressedStringStorage::SerializeState, UncompressedStringStorage::DeserializeState, + UncompressedStringStorage::CleanupState, UncompressedStringInitPrefetch); } //===--------------------------------------------------------------------===// @@ -444,4 +421,45 @@ void UncompressedStringStorage::ReadStringMarker(data_ptr_t target, block_id_t & memcpy(&offset, target, sizeof(int32_t)); } +string_location_t UncompressedStringStorage::FetchStringLocation(StringDictionaryContainer dict, data_ptr_t base_ptr, + int32_t dict_offset, const idx_t block_size) { + D_ASSERT(dict_offset + NumericCast(block_size) >= 0 && dict_offset <= NumericCast(block_size)); + if (dict_offset >= 0) { + return string_location_t(INVALID_BLOCK, dict_offset); + } + + string_location_t result; + ReadStringMarker(base_ptr + dict.end - NumericCast(-1 * dict_offset), result.block_id, result.offset); + return result; +} + +string_t UncompressedStringStorage::FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, + Vector &result, data_ptr_t base_ptr, int32_t dict_offset, + uint32_t string_length) { + // Fetch the base data. + auto block_size = segment.GetBlockManager().GetBlockSize(); + D_ASSERT(dict_offset <= NumericCast(block_size)); + string_location_t location = FetchStringLocation(dict, base_ptr, dict_offset, block_size); + return FetchString(segment, dict, result, base_ptr, location, string_length); +} + +string_t UncompressedStringStorage::FetchString(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result, + data_ptr_t base_ptr, string_location_t location, + uint32_t string_length) { + if (location.block_id != INVALID_BLOCK) { + // big string marker: read from separate block + return ReadOverflowString(segment, result, location.block_id, location.offset); + } + if (location.offset == 0) { + return string_t(nullptr, 0); + } + + // normal string: read string from this block + auto dict_end = base_ptr + dict.end; + auto dict_pos = dict_end - location.offset; + + auto str_ptr = char_ptr_cast(dict_pos); + return string_t(str_ptr, string_length); +} + } // namespace duckdb diff --git a/src/duckdb/src/storage/compression/validity_uncompressed.cpp b/src/duckdb/src/storage/compression/validity_uncompressed.cpp index 8fa4acca9..96271da1b 100644 --- a/src/duckdb/src/storage/compression/validity_uncompressed.cpp +++ b/src/duckdb/src/storage/compression/validity_uncompressed.cpp @@ -218,12 +218,17 @@ unique_ptr ValidityInitScan(ColumnSegment &segment) { //===--------------------------------------------------------------------===// // Scan base data //===--------------------------------------------------------------------===// +void ValidityScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, + idx_t result_offset) { + auto start = segment.GetRelativeIndex(state.row_index); + + static_assert(sizeof(validity_t) == sizeof(uint64_t), "validity_t should be 64-bit"); + auto &scan_state = state.scan_state->Cast(); -void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx_t input_start, Vector &result, - idx_t result_offset, idx_t scan_count) { - D_ASSERT(input_start < input_size); auto &result_mask = FlatVector::Validity(result); - auto input_data = reinterpret_cast(input); + auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); + D_ASSERT(scan_state.block_id == segment.block->BlockId()); + auto input_data = reinterpret_cast(buffer_ptr); #ifdef DEBUG // this method relies on all the bits we are going to write to being set to valid @@ -234,11 +239,11 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx #if STANDARD_VECTOR_SIZE < 128 // fallback for tiny vector sizes // the bitwise ops we use below don't work if the vector size is too small - ValidityMask source_mask(input_data, input_size); + ValidityMask source_mask(input_data); for (idx_t i = 0; i < scan_count; i++) { - if (!source_mask.RowIsValid(input_start + i)) { + if (!source_mask.RowIsValid(start + i)) { if (result_mask.AllValid()) { - result_mask.Initialize(); + result_mask.Initialize(result_mask.TargetCount()); } result_mask.SetInvalid(result_offset + i); } @@ -253,8 +258,8 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx idx_t result_idx = result_offset - result_entry * ValidityMask::BITS_PER_VALUE; // same for the input: find the validity_entry we are pulling from, together with the bit-index WITHIN that entry - idx_t input_entry = input_start / ValidityMask::BITS_PER_VALUE; - idx_t input_idx = input_start - input_entry * ValidityMask::BITS_PER_VALUE; + idx_t input_entry = start / ValidityMask::BITS_PER_VALUE; + idx_t input_idx = start - input_entry * ValidityMask::BITS_PER_VALUE; // now start the bit games idx_t pos = 0; @@ -266,16 +271,6 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx // construct the mask to AND together with the result if (result_idx < input_idx) { - // +======================================+ - // input: |xxxxxxxxx| | - // +======================================+ - // - // +======================================+ - // result: | xxxxxxxxx| | - // +======================================+ - // 1. We shift (>>) 'input' to line up with 'result' - // 2. We set the bits we shifted to 1 - // we have to shift the input RIGHT if the result_idx is smaller than the input_idx auto shift_amount = input_idx - result_idx; D_ASSERT(shift_amount > 0 && shift_amount <= ValidityMask::BITS_PER_VALUE); @@ -293,17 +288,6 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx input_idx = 0; result_idx += offset; } else if (result_idx > input_idx) { - // +======================================+ - // input: | xxxxxxxxx| | - // +======================================+ - // - // +======================================+ - // result: |xxxxxxxxx| | - // +======================================+ - // 1. We set the bits to the left of the relevant bits (x) to 0 - // 1. We shift (<<) 'input' to line up with 'result' - // 2. We set the bits that we zeroed to the right of the relevant bits (x) to 1 - // we have to shift the input LEFT if the result_idx is bigger than the input_idx auto shift_amount = result_idx - input_idx; D_ASSERT(shift_amount > 0 && shift_amount <= ValidityMask::BITS_PER_VALUE); @@ -333,13 +317,6 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx // OR if we need to mask from the right side pos += offset; if (pos > scan_count) { - // +======================================+ - // mask: | |xxxxxxxxxxxxxxxxxxxxxxxxx| - // +======================================+ - // - // The bits on the right side of the relevant bits (x) need to stay 1, to be adjusted by later scans - // so we adjust the mask to clear out any 0s that might be present on the right side. - // we need to set any bits that are past the scan_count on the right-side to 1 // this is required so we don't influence any bits that are not part of the scan input_mask |= ValidityUncompressed::UPPER_MASKS[pos - scan_count]; @@ -347,7 +324,7 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx // now finally we can merge the input mask with the result mask if (input_mask != ValidityMask::ValidityBuffer::MAX_ENTRY) { if (!result_data) { - result_mask.Initialize(); + result_mask.Initialize(result_mask.TargetCount()); result_data = (validity_t *)result_mask.GetData(); } result_data[current_result_idx] &= input_mask; @@ -357,49 +334,13 @@ void ValidityUncompressed::UnalignedScan(data_ptr_t input, idx_t input_size, idx #ifdef DEBUG // verify that we actually accomplished the bitwise ops equivalent that we wanted to do - ValidityMask input_mask(input_data, input_size); + ValidityMask input_mask(input_data); for (idx_t i = 0; i < scan_count; i++) { - D_ASSERT(result_mask.RowIsValid(result_offset + i) == input_mask.RowIsValid(input_start + i)); + D_ASSERT(result_mask.RowIsValid(result_offset + i) == input_mask.RowIsValid(start + i)); } #endif } -void ValidityUncompressed::AlignedScan(data_ptr_t input, idx_t input_start, Vector &result, idx_t scan_count) { - D_ASSERT(input_start % ValidityMask::BITS_PER_VALUE == 0); - - // aligned scan: no need to do anything fancy - // note: this is only an optimization which avoids having to do messy bitshifting in the common case - // it is not required for correctness - auto &result_mask = FlatVector::Validity(result); - auto input_data = reinterpret_cast(input); - auto result_data = result_mask.GetData(); - idx_t start_offset = input_start / ValidityMask::BITS_PER_VALUE; - idx_t entry_scan_count = (scan_count + ValidityMask::BITS_PER_VALUE - 1) / ValidityMask::BITS_PER_VALUE; - for (idx_t i = 0; i < entry_scan_count; i++) { - auto input_entry = input_data[start_offset + i]; - if (!result_data && input_entry == ValidityMask::ValidityBuffer::MAX_ENTRY) { - continue; - } - if (!result_data) { - result_mask.Initialize(); - result_data = result_mask.GetData(); - } - result_data[i] = input_entry; - } -} - -void ValidityScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, - idx_t result_offset) { - auto start = segment.GetRelativeIndex(state.row_index); - - static_assert(sizeof(validity_t) == sizeof(uint64_t), "validity_t should be 64-bit"); - auto &scan_state = state.scan_state->Cast(); - - auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); - D_ASSERT(scan_state.block_id == segment.block->BlockId()); - ValidityUncompressed::UnalignedScan(buffer_ptr, segment.count, start, result, result_offset, scan_count); -} - void ValidityScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result) { result.Flatten(scan_count); @@ -407,37 +348,33 @@ void ValidityScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_cou if (start % ValidityMask::BITS_PER_VALUE == 0) { auto &scan_state = state.scan_state->Cast(); + // aligned scan: no need to do anything fancy + // note: this is only an optimization which avoids having to do messy bitshifting in the common case + // it is not required for correctness + auto &result_mask = FlatVector::Validity(result); auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); D_ASSERT(scan_state.block_id == segment.block->BlockId()); - ValidityUncompressed::AlignedScan(buffer_ptr, start, result, scan_count); + auto input_data = reinterpret_cast(buffer_ptr); + auto result_data = result_mask.GetData(); + idx_t start_offset = start / ValidityMask::BITS_PER_VALUE; + idx_t entry_scan_count = (scan_count + ValidityMask::BITS_PER_VALUE - 1) / ValidityMask::BITS_PER_VALUE; + for (idx_t i = 0; i < entry_scan_count; i++) { + auto input_entry = input_data[start_offset + i]; + if (!result_data && input_entry == ValidityMask::ValidityBuffer::MAX_ENTRY) { + continue; + } + if (!result_data) { + result_mask.Initialize(result_mask.TargetCount()); + result_data = result_mask.GetData(); + } + result_data[i] = input_entry; + } } else { // unaligned scan: fall back to scan_partial which does bitshift tricks ValidityScanPartial(segment, state, scan_count, result, 0); } } -//===--------------------------------------------------------------------===// -// Select -//===--------------------------------------------------------------------===// -void ValiditySelect(ColumnSegment &segment, ColumnScanState &state, idx_t, Vector &result, const SelectionVector &sel, - idx_t sel_count) { - result.Flatten(sel_count); - - auto &scan_state = state.scan_state->Cast(); - auto buffer_ptr = scan_state.handle.Ptr() + segment.GetBlockOffset(); - auto &result_mask = FlatVector::Validity(result); - auto input_data = reinterpret_cast(buffer_ptr); - - auto start = segment.GetRelativeIndex(state.row_index); - ValidityMask source_mask(input_data, segment.count); - for (idx_t i = 0; i < sel_count; i++) { - auto source_idx = start + sel.get_index(i); - if (!source_mask.RowIsValidUnsafe(source_idx)) { - result_mask.SetInvalid(i); - } - } -} - //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// @@ -446,7 +383,7 @@ void ValidityFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row auto &buffer_manager = BufferManager::GetBufferManager(segment.db); auto handle = buffer_manager.Pin(segment.block); auto dataptr = handle.Ptr() + segment.GetBlockOffset(); - ValidityMask mask(reinterpret_cast(dataptr), segment.count); + ValidityMask mask(reinterpret_cast(dataptr)); auto &result_mask = FlatVector::Validity(result); if (!mask.RowIsValidUnsafe(NumericCast(row_id))) { result_mask.SetInvalid(result_idx); @@ -486,7 +423,7 @@ idx_t ValidityAppend(CompressionAppendState &append_state, ColumnSegment &segmen return append_count; } - ValidityMask mask(reinterpret_cast(append_state.handle.Ptr()), max_tuples); + ValidityMask mask(reinterpret_cast(append_state.handle.Ptr())); for (idx_t i = 0; i < append_count; i++) { auto idx = data.sel->get_index(offset + i); if (!data.validity.RowIsValidUnsafe(idx)) { @@ -514,7 +451,7 @@ void ValidityRevertAppend(ColumnSegment &segment, idx_t start_row) { // handle sub-bit stuff (yay) idx_t byte_pos = start_bit / 8; idx_t bit_end = (byte_pos + 1) * 8; - ValidityMask mask(reinterpret_cast(handle.Ptr()), segment.count); + ValidityMask mask(reinterpret_cast(handle.Ptr())); for (idx_t i = start_bit; i < bit_end; i++) { mask.SetValid(i); } diff --git a/src/duckdb/src/storage/compression/zstd.cpp b/src/duckdb/src/storage/compression/zstd.cpp deleted file mode 100644 index 6552f0dc8..000000000 --- a/src/duckdb/src/storage/compression/zstd.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -#include "duckdb/common/bitpacking.hpp" -#include "duckdb/storage/string_uncompressed.hpp" -#include "duckdb/function/compression/compression.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" -#include "duckdb/storage/block_manager.hpp" -#include "duckdb/main/config.hpp" -#include "duckdb/common/constants.hpp" -#include "duckdb/common/allocator.hpp" -#include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/storage/segment/uncompressed.hpp" - -#include "zstd.h" - -/* -Data layout per segment: -+--------------------------------------------+ -| Vector Metadata | -| +------------------------------------+ | -| | int64_t page_id[] | | -| | uint32_t page_offset[] | | -| | uint64_t uncompressed_size[] | | -| | uint64_t compressed_size[] | | -| +------------------------------------+ | -| | -+--------------------------------------------+ -| [Vector Data]+ | -| +------------------------------------+ | -| | uint32_t lengths[] | | -| | void *compressed_data | | -| +------------------------------------+ | -| | -+--------------------------------------------+ -*/ - -using page_id_t = int64_t; -using page_offset_t = uint32_t; -using uncompressed_size_t = uint64_t; -using compressed_size_t = uint64_t; -using string_length_t = uint32_t; - -static int32_t GetCompressionLevel() { - return duckdb_zstd::ZSTD_defaultCLevel(); -} - -static constexpr idx_t ZSTD_VECTOR_SIZE = STANDARD_VECTOR_SIZE > 2048 ? STANDARD_VECTOR_SIZE : 2048; - -namespace duckdb { - -static idx_t GetWritableSpace(const CompressionInfo &info) { - return info.GetBlockSize() - sizeof(block_id_t); -} - -static idx_t GetVectorCount(idx_t count) { - idx_t vector_count = count / ZSTD_VECTOR_SIZE; - vector_count += (count % ZSTD_VECTOR_SIZE) != 0; - return vector_count; -} - -static idx_t GetVectorMetadataSize(idx_t vector_count) { - idx_t vector_metadata_size = 0; - vector_metadata_size += sizeof(page_id_t) * vector_count; - - vector_metadata_size = AlignValue(vector_metadata_size); - vector_metadata_size += sizeof(page_offset_t) * vector_count; - - vector_metadata_size = AlignValue(vector_metadata_size); - vector_metadata_size += sizeof(uncompressed_size_t) * vector_count; - - vector_metadata_size = AlignValue(vector_metadata_size); - vector_metadata_size += sizeof(compressed_size_t) * vector_count; - return vector_metadata_size; -} - -struct ZSTDStorage { - static unique_ptr StringInitAnalyze(ColumnData &col_data, PhysicalType type); - static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count); - static idx_t StringFinalAnalyze(AnalyzeState &state_p); - - static unique_ptr InitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr analyze_state_p); - static void Compress(CompressionState &state_p, Vector &scan_vector, idx_t count); - static void FinalizeCompress(CompressionState &state_p); - - static unique_ptr StringInitScan(ColumnSegment &segment); - static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, - idx_t result_offset); - static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result); - static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, - idx_t result_idx); - static void StringSkip(ColumnSegment &segment, ColumnScanState &state, idx_t skip_count) { - // NO OP - } - - // Segment state metadata - // Required because we are creating additional pages that have to be cleaned up - - static unique_ptr StringInitSegment(ColumnSegment &segment, block_id_t block_id, - optional_ptr segment_state); - static unique_ptr SerializeState(ColumnSegment &segment); - static unique_ptr DeserializeState(Deserializer &deserializer); - static void CleanupState(ColumnSegment &segment); -}; - -//===--------------------------------------------------------------------===// -// Analyze -//===--------------------------------------------------------------------===// - -struct ZSTDAnalyzeState : public AnalyzeState { -public: - ZSTDAnalyzeState(CompressionInfo &info, DBConfig &config) : AnalyzeState(info), config(config), context(nullptr) { - context = duckdb_zstd::ZSTD_createCCtx(); - } - ~ZSTDAnalyzeState() override { - duckdb_zstd::ZSTD_freeCCtx(context); - } - -public: - inline void AppendString(const string_t &str) { - auto string_size = str.GetSize(); - total_size += string_size; - } - -public: - DBConfig &config; - - duckdb_zstd::ZSTD_CCtx *context; - //! The combined string lengths for all values in the segment - idx_t total_size = 0; - //! The total amount of values in the segment - idx_t count = 0; - - //! The amount of vectors per filled segment - idx_t vectors_per_segment = 0; - //! The total amount of segments we will create - idx_t segment_count = 0; - //! Current vector in the segment - idx_t vectors_in_segment = 0; - //! Current amount of values in the vector - idx_t values_in_vector = 0; -}; - -unique_ptr ZSTDStorage::StringInitAnalyze(ColumnData &col_data, PhysicalType type) { - CompressionInfo info(col_data.GetBlockManager().GetBlockSize()); - auto &data_table_info = col_data.info; - auto &attached_db = data_table_info.GetDB(); - auto &config = DBConfig::Get(attached_db); - - return make_uniq(info, config); -} - -bool ZSTDStorage::StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count) { - auto &state = state_p.Cast(); - UnifiedVectorFormat vdata; - input.ToUnifiedFormat(count, vdata); - - auto data = UnifiedVectorFormat::GetData(vdata); - for (idx_t i = 0; i < count; i++) { - auto idx = vdata.sel->get_index(i); - if (!vdata.validity.RowIsValid(idx)) { - continue; - } - auto &str = data[idx]; - auto string_size = str.GetSize(); - state.total_size += string_size; - } - state.values_in_vector += count; - while (state.values_in_vector >= ZSTD_VECTOR_SIZE) { - if (GetVectorMetadataSize(state.vectors_in_segment + 1) > GetWritableSpace(state.info)) { - state.vectors_per_segment = state.vectors_in_segment; - state.segment_count++; - state.vectors_in_segment = 0; - } else { - state.vectors_in_segment++; - } - state.values_in_vector -= ZSTD_VECTOR_SIZE; - } - state.count += count; - return true; -} - -// Compression score to determine which compression to use -idx_t ZSTDStorage::StringFinalAnalyze(AnalyzeState &state_p) { - auto &state = state_p.Cast(); - - if (!state.count) { - return NumericLimits::Maximum(); - } - - if (state.values_in_vector) { - D_ASSERT(state.values_in_vector < ZSTD_VECTOR_SIZE); - state.segment_count++; - } - - double penalty; - idx_t average_length = state.total_size / state.count; - auto threshold = state.config.options.zstd_min_string_length; - if (average_length >= threshold) { - penalty = 1.0; - } else { - // Inbetween these two points you're better off using uncompressed or a different compression algorithm. - return NumericLimits::Maximum(); - } - - auto expected_compressed_size = (double)state.total_size / 2.0; - - idx_t estimated_size = 0; - estimated_size += LossyNumericCast(expected_compressed_size); - - estimated_size += state.count * sizeof(string_length_t); - estimated_size += GetVectorMetadataSize(GetVectorCount(state.count)); - - return LossyNumericCast((double)estimated_size * penalty); -} - -//===--------------------------------------------------------------------===// -// Compress -//===--------------------------------------------------------------------===// - -class ZSTDCompressionState : public CompressionState { -public: - explicit ZSTDCompressionState(ColumnDataCheckpointData &checkpoint_data, - unique_ptr &&analyze_state_p) - : CompressionState(analyze_state_p->info), analyze_state(std::move(analyze_state_p)), - checkpoint_data(checkpoint_data), - partial_block_manager(checkpoint_data.GetCheckpointState().GetPartialBlockManager()), - function(checkpoint_data.GetCompressionFunction(CompressionType::COMPRESSION_ZSTD)) { - - total_vector_count = GetVectorCount(analyze_state->count); - total_segment_count = analyze_state->segment_count; - vectors_per_segment = analyze_state->vectors_per_segment; - - segment_count = 0; - vector_count = 0; - vector_in_segment_count = 0; - tuple_count = 0; - - idx_t offset = NewSegment(); - SetCurrentBuffer(segment_handle); - current_buffer_ptr = segment_handle.Ptr() + offset; - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); - } - -public: - void ResetOutBuffer() { - out_buffer.dst = current_buffer_ptr; - out_buffer.pos = 0; - - auto remaining_space = info.GetBlockSize() - GetCurrentOffset() - sizeof(block_id_t); - out_buffer.size = remaining_space; - } - - void SetCurrentBuffer(BufferHandle &handle) { - current_buffer = &handle; - current_buffer_ptr = handle.Ptr(); - } - - BufferHandle &GetExtraPageBuffer(block_id_t current_block_id) { - auto &block_manager = partial_block_manager.GetBlockManager(); - auto &buffer_manager = block_manager.buffer_manager; - - optional_ptr to_use; - - if (in_vector) { - // Currently in a Vector, we have to be mindful of the buffer that the string_lengths lives on - // as that will have to stay writable until the Vector is finished - bool already_separated = current_buffer != vector_lengths_buffer; - if (already_separated) { - // Already separated, can keep using the other buffer (flush it first) - FlushPage(*current_buffer, current_block_id); - to_use = current_buffer; - } else { - // Not already separated, have to use the other page - to_use = current_buffer == &extra_pages[0] ? &extra_pages[1] : &extra_pages[0]; - } - } else { - // Start of a new Vector, the string_lengths did not fit on the previous page - bool previous_page_is_segment = current_buffer == &segment_handle; - if (!previous_page_is_segment) { - // We're asking for a fresh buffer to start the vectors data - // that means the previous vector is finished - so we can flush the current page and reuse it - D_ASSERT(current_block_id != INVALID_BLOCK); - FlushPage(*current_buffer, current_block_id); - to_use = current_buffer; - } else { - // Previous buffer was the segment, take the first extra page in this case - to_use = &extra_pages[0]; - } - } - - if (!to_use->IsValid()) { - *to_use = buffer_manager.Allocate(MemoryTag::OVERFLOW_STRINGS, block_manager.GetBlockSize()); - } - return *to_use; - } - - idx_t NewSegment() { - if (current_buffer == &segment_handle) { - // This should never happen, the string lengths + vector metadata size should always exceed a page size, - // even if the strings are all empty - throw InternalException("We are asking for a new segment, but somehow we're still writing vector data onto " - "the initial (segment) page"); - } - idx_t row_start; - if (segment) { - row_start = segment->start + segment->count; - FlushSegment(); - } else { - row_start = checkpoint_data.GetRowGroup().start; - } - CreateEmptySegment(row_start); - - // Figure out how many vectors we are storing in this segment - idx_t vectors_in_segment; - if (segment_count + 1 >= total_segment_count) { - vectors_in_segment = total_vector_count - vector_count; - } else { - vectors_in_segment = vectors_per_segment; - } - - idx_t offset = 0; - page_ids = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(page_id_t) * vectors_in_segment); - - offset = AlignValue(offset); - page_offsets = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(page_offset_t) * vectors_in_segment); - - offset = AlignValue(offset); - uncompressed_sizes = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(uncompressed_size_t) * vectors_in_segment); - - offset = AlignValue(offset); - compressed_sizes = reinterpret_cast(segment_handle.Ptr() + offset); - offset += (sizeof(compressed_size_t) * vectors_in_segment); - - D_ASSERT(offset == GetVectorMetadataSize(vectors_in_segment)); - return offset; - } - - void InitializeVector() { - D_ASSERT(!in_vector); - if (vector_count + 1 >= total_vector_count) { - vector_size = analyze_state->count - (ZSTD_VECTOR_SIZE * vector_count); - } else { - vector_size = ZSTD_VECTOR_SIZE; - } - auto current_offset = GetCurrentOffset(); - current_offset = UnsafeNumericCast( - AlignValue(UnsafeNumericCast(current_offset))); - current_buffer_ptr = current_buffer->Ptr() + current_offset; - compressed_size = 0; - uncompressed_size = 0; - - if (GetVectorMetadataSize(vector_in_segment_count + 1) > GetWritableSpace(info)) { - D_ASSERT(vector_in_segment_count <= vectors_per_segment); - // Can't fit this vector on this segment anymore, have to flush and a grab new one - NewSegment(); - } - - if (current_offset + (vector_size * sizeof(string_length_t)) >= GetWritableSpace(info)) { - // Check if there is room on the current page for the vector data - NewPage(); - } - current_offset = GetCurrentOffset(); - starting_offset = current_offset; - starting_page = GetCurrentId(); - - vector_lengths_buffer = current_buffer; - string_lengths = reinterpret_cast(current_buffer->Ptr() + current_offset); - current_buffer_ptr = reinterpret_cast(string_lengths); - current_buffer_ptr += vector_size * sizeof(string_length_t); - // 'out_buffer' should be set to point directly after the string_lengths - ResetOutBuffer(); - - // Initialize the context for streaming compression - duckdb_zstd::ZSTD_CCtx_reset(analyze_state->context, duckdb_zstd::ZSTD_reset_session_only); - duckdb_zstd::ZSTD_CCtx_refCDict(analyze_state->context, nullptr); - duckdb_zstd::ZSTD_CCtx_setParameter(analyze_state->context, duckdb_zstd::ZSTD_c_compressionLevel, - GetCompressionLevel()); - in_vector = true; - } - - void CompressString(const string_t &string, bool end_of_vector) { - duckdb_zstd::ZSTD_inBuffer in_buffer = {/*data = */ string.GetData(), - /*length = */ size_t(string.GetSize()), - /*pos = */ 0}; - - if (!end_of_vector && string.GetSize() == 0) { - return; - } - uncompressed_size += string.GetSize(); - const auto end_mode = end_of_vector ? duckdb_zstd::ZSTD_e_end : duckdb_zstd::ZSTD_e_continue; - - size_t compress_result; - while (true) { - idx_t old_pos = out_buffer.pos; - - compress_result = - duckdb_zstd::ZSTD_compressStream2(analyze_state->context, &out_buffer, &in_buffer, end_mode); - D_ASSERT(out_buffer.pos >= old_pos); - auto diff = out_buffer.pos - old_pos; - compressed_size += diff; - current_buffer_ptr += diff; - - if (duckdb_zstd::ZSTD_isError(compress_result)) { - throw InvalidInputException("ZSTD Compression failed: %s", - duckdb_zstd::ZSTD_getErrorName(compress_result)); - } - if (compress_result == 0) { - // Finished - break; - } - if (out_buffer.pos != out_buffer.size) { - throw InternalException("Expected ZSTD_compressStream2 to fully utilize the current buffer, but pos is " - "%d, while size is %d", - out_buffer.pos, out_buffer.size); - } - NewPage(); - } - } - - void AddString(const string_t &string) { - if (!tuple_count) { - InitializeVector(); - } - - string_lengths[tuple_count] = UnsafeNumericCast(string.GetSize()); - bool final_tuple = tuple_count + 1 >= vector_size; - CompressString(string, final_tuple); - - tuple_count++; - if (tuple_count == vector_size) { - // Reached the end of this vector - FlushVector(); - } - - UncompressedStringStorage::UpdateStringStats(segment->stats, string); - } - - void NewPage(bool additional_data_page = false) { - block_id_t new_id = FinalizePage(); - block_id_t current_block_id = block_id; - auto &buffer = GetExtraPageBuffer(current_block_id); - block_id = new_id; - SetCurrentBuffer(buffer); - ResetOutBuffer(); - } - - block_id_t FinalizePage() { - auto &block_manager = partial_block_manager.GetBlockManager(); - auto new_id = block_manager.GetFreeBlockId(); - auto &state = segment->GetSegmentState()->Cast(); - state.RegisterBlock(block_manager, new_id); - - D_ASSERT(GetCurrentOffset() <= GetWritableSpace(info)); - - // Write the new id at the end of the last page - Store(new_id, current_buffer_ptr); - current_buffer_ptr += sizeof(block_id_t); - return new_id; - } - - void FlushPage(BufferHandle &buffer, block_id_t block_id) { - if (block_id == INVALID_BLOCK) { - return; - } - - // Write the current page to disk - auto &block_manager = partial_block_manager.GetBlockManager(); - block_manager.Write(buffer.GetFileBuffer(), block_id); - { - auto lock = partial_block_manager.GetLock(); - partial_block_manager.AddWrittenBlock(block_id); - } - } - - void FlushVector() { - // Write the metadata for this Vector - page_ids[vector_in_segment_count] = starting_page; - page_offsets[vector_in_segment_count] = starting_offset; - compressed_sizes[vector_in_segment_count] = compressed_size; - uncompressed_sizes[vector_in_segment_count] = uncompressed_size; - vector_count++; - vector_in_segment_count++; - in_vector = false; - segment->count += tuple_count; - - const bool is_last_vector = vector_count == total_vector_count; - tuple_count = 0; - if (is_last_vector) { - FlushPage(*current_buffer, block_id); - if (starting_page != block_id) { - FlushPage(*vector_lengths_buffer, starting_page); - } - } else { - if (vector_lengths_buffer == current_buffer) { - // We did not cross a page boundary writing this vector - return; - } - // Flush the page that holds the vector lengths - FlushPage(*vector_lengths_buffer, starting_page); - } - } - - page_id_t GetCurrentId() { - if (&segment_handle == current_buffer.get()) { - return INVALID_BLOCK; - } - return block_id; - } - - page_offset_t GetCurrentOffset() { - auto &handle = *current_buffer; - auto start_of_buffer = handle.Ptr(); - D_ASSERT(current_buffer_ptr >= start_of_buffer); - auto res = (page_offset_t)(current_buffer_ptr - start_of_buffer); - D_ASSERT(res <= GetWritableSpace(info)); - return res; - } - - void CreateEmptySegment(idx_t row_start) { - auto &db = checkpoint_data.GetDatabase(); - auto &type = checkpoint_data.GetType(); - auto compressed_segment = ColumnSegment::CreateTransientSegment(db, function, type, row_start, - info.GetBlockSize(), info.GetBlockSize()); - segment = std::move(compressed_segment); - - auto &buffer_manager = BufferManager::GetBufferManager(checkpoint_data.GetDatabase()); - segment_handle = buffer_manager.Pin(segment->block); - } - - void FlushSegment() { - auto &state = checkpoint_data.GetCheckpointState(); - idx_t segment_block_size; - - if (current_buffer.get() == &segment_handle) { - segment_block_size = GetCurrentOffset(); - } else { - // Block is fully used - segment_block_size = info.GetBlockSize(); - } - - state.FlushSegment(std::move(segment), std::move(segment_handle), segment_block_size); - segment_count++; - vector_in_segment_count = 0; - } - - void Finalize() { - D_ASSERT(!tuple_count); - FlushSegment(); - segment.reset(); - } - - void AddNull() { - AddString(""); - } - -public: - unique_ptr analyze_state; - ColumnDataCheckpointData &checkpoint_data; - PartialBlockManager &partial_block_manager; - CompressionFunction &function; - - // The segment state - //! Current segment index we're at - idx_t segment_count = 0; - //! The total amount of segments we're writing - idx_t total_segment_count = 0; - //! The vectors to store in the last segment - idx_t vectors_in_last_segment = 0; - //! The vectors to store in a segment (not the last one) - idx_t vectors_per_segment = 0; - unique_ptr segment; - BufferHandle segment_handle; - - // Non-segment buffers - BufferHandle extra_pages[2]; - block_id_t block_id = INVALID_BLOCK; - - // Current block state - optional_ptr current_buffer; - //! The buffer that contains the vector lengths - optional_ptr vector_lengths_buffer; - data_ptr_t current_buffer_ptr; - - //===--------------------------------------------------------------------===// - // Vector metadata - //===--------------------------------------------------------------------===// - page_id_t starting_page; - page_offset_t starting_offset; - - page_id_t *page_ids; - page_offset_t *page_offsets; - uncompressed_size_t *uncompressed_sizes; - compressed_size_t *compressed_sizes; - //! The amount of vectors we've seen so far - idx_t vector_count = 0; - //! The amount of vectors we've seen in the current segment - idx_t vector_in_segment_count = 0; - //! The amount of vectors we're writing - idx_t total_vector_count = 0; - //! Whether we are currently in a Vector - bool in_vector = false; - //! The compression context indicating where we are in the output buffer - duckdb_zstd::ZSTD_outBuffer out_buffer; - idx_t uncompressed_size = 0; - idx_t compressed_size = 0; - string_length_t *string_lengths; - - //! Amount of tuples we have seen for the current vector - idx_t tuple_count = 0; - //! The expected size of this vector (ZSTD_VECTOR_SIZE except for the last one) - idx_t vector_size; -}; - -unique_ptr ZSTDStorage::InitCompression(ColumnDataCheckpointData &checkpoint_data, - unique_ptr analyze_state_p) { - return make_uniq(checkpoint_data, - unique_ptr_cast(std::move(analyze_state_p))); -} - -void ZSTDStorage::Compress(CompressionState &state_p, Vector &input, idx_t count) { - auto &state = state_p.Cast(); - - // Get vector data - UnifiedVectorFormat vdata; - input.ToUnifiedFormat(count, vdata); - auto data = UnifiedVectorFormat::GetData(vdata); - - for (idx_t i = 0; i < count; i++) { - auto idx = vdata.sel->get_index(i); - // Note: we treat nulls and empty strings the same - if (!vdata.validity.RowIsValid(idx) || data[idx].GetSize() == 0) { - state.AddNull(); - continue; - } - state.AddString(data[idx]); - } -} - -void ZSTDStorage::FinalizeCompress(CompressionState &state_p) { - auto &state = state_p.Cast(); - state.Finalize(); -} - -struct ZSTDVectorScanMetadata { - //! The index of the (internal) vector being read - idx_t vector_idx; - block_id_t block_id; - page_offset_t block_offset; - - uncompressed_size_t uncompressed_size; - compressed_size_t compressed_size; - - //! The amount of tuples that are in this Vector - idx_t count; -}; - -struct ZSTDVectorScanState { -public: - ZSTDVectorScanState() { - } - ZSTDVectorScanState(ZSTDVectorScanState &&other) = default; - ZSTDVectorScanState(const ZSTDVectorScanState &other) = delete; - -public: - //! The metadata of the vector - ZSTDVectorScanMetadata metadata; - //! The (pinned) buffer handle(s) for this vectors data - vector buffer_handles; - //! The current pointer at which we're reading the vectors data - data_ptr_t current_buffer_ptr; - //! The (uncompressed) string lengths for this vector - string_length_t *string_lengths; - //! The amount of values already consumed from the state - idx_t scanned_count = 0; - //! The amount of compressed data read - idx_t compressed_scan_count = 0; - //! The inBuffer that ZSTD_decompressStream reads the compressed data from - duckdb_zstd::ZSTD_inBuffer in_buffer; -}; - -//===--------------------------------------------------------------------===// -// Scan -//===--------------------------------------------------------------------===// -struct ZSTDScanState : public SegmentScanState { -public: - explicit ZSTDScanState(ColumnSegment &segment) - : state(segment.GetSegmentState()->Cast()), - block_manager(segment.GetBlockManager()), buffer_manager(BufferManager::GetBufferManager(segment.db)), - segment_block_offset(segment.GetBlockOffset()) { - decompression_context = duckdb_zstd::ZSTD_createDCtx(); - segment_handle = buffer_manager.Pin(segment.block); - - auto data = segment_handle.Ptr() + segment.GetBlockOffset(); - idx_t offset = 0; - - segment_count = segment.count.load(); - idx_t amount_of_vectors = (segment_count / ZSTD_VECTOR_SIZE) + ((segment_count % ZSTD_VECTOR_SIZE) != 0); - - // Set pointers to the Vector Metadata - offset = AlignValue(offset); - page_ids = reinterpret_cast(data + offset); - offset += (sizeof(page_id_t) * amount_of_vectors); - - offset = AlignValue(offset); - page_offsets = reinterpret_cast(data + offset); - offset += (sizeof(page_offset_t) * amount_of_vectors); - - offset = AlignValue(offset); - uncompressed_sizes = reinterpret_cast(data + offset); - offset += (sizeof(uncompressed_size_t) * amount_of_vectors); - - offset = AlignValue(offset); - compressed_sizes = reinterpret_cast(data + offset); - offset += (sizeof(compressed_size_t) * amount_of_vectors); - - scanned_count = 0; - } - ~ZSTDScanState() override { - duckdb_zstd::ZSTD_freeDCtx(decompression_context); - } - -public: - idx_t GetVectorIndex(idx_t start_index, idx_t &offset) { - idx_t vector_idx = start_index / ZSTD_VECTOR_SIZE; - offset = start_index % ZSTD_VECTOR_SIZE; - return vector_idx; - } - - ZSTDVectorScanMetadata GetVectorMetadata(idx_t vector_idx) { - idx_t previous_value_count = vector_idx * ZSTD_VECTOR_SIZE; - idx_t value_count = MinValue(segment_count - previous_value_count, ZSTD_VECTOR_SIZE); - - return ZSTDVectorScanMetadata {/* vector_idx = */ vector_idx, - /* block_id = */ page_ids[vector_idx], - /* block_offset = */ page_offsets[vector_idx], - /* uncompressed_size = */ uncompressed_sizes[vector_idx], - /* compressed_size = */ compressed_sizes[vector_idx], - /* count = */ value_count}; - } - - shared_ptr LoadPage(block_id_t block_id) { - return state.GetHandle(block_manager, block_id); - } - - bool UseVectorStateCache(idx_t vector_idx, idx_t internal_offset) { - if (!current_vector) { - // No vector loaded yet - return false; - } - if (current_vector->metadata.vector_idx != vector_idx) { - // Not the same vector - return false; - } - if (current_vector->scanned_count != internal_offset) { - // Not the same scan offset - return false; - } - return true; - } - - ZSTDVectorScanState &LoadVector(idx_t vector_idx, idx_t internal_offset) { - if (UseVectorStateCache(vector_idx, internal_offset)) { - return *current_vector; - } - current_vector = make_uniq(); - current_vector->metadata = GetVectorMetadata(vector_idx); - auto &metadata = current_vector->metadata; - auto &scan_state = *current_vector; - data_ptr_t handle_start; - idx_t ptr_offset = 0; - if (metadata.block_id == INVALID_BLOCK) { - // Data lives on the segment's page - handle_start = segment_handle.Ptr(); - ptr_offset += segment_block_offset; - } else { - // Data lives on an extra page, have to load the block first - auto block = LoadPage(metadata.block_id); - auto data_handle = buffer_manager.Pin(block); - handle_start = data_handle.Ptr(); - scan_state.buffer_handles.push_back(std::move(data_handle)); - } - - ptr_offset += metadata.block_offset; - ptr_offset = AlignValue(ptr_offset); - scan_state.current_buffer_ptr = handle_start + ptr_offset; - - auto vector_size = metadata.count; - - scan_state.string_lengths = reinterpret_cast(scan_state.current_buffer_ptr); - scan_state.current_buffer_ptr += (sizeof(string_length_t) * vector_size); - - // Update the in_buffer to point to the start of the compressed data frame - idx_t current_offset = UnsafeNumericCast(scan_state.current_buffer_ptr - handle_start); - scan_state.in_buffer.src = scan_state.current_buffer_ptr; - scan_state.in_buffer.pos = 0; - scan_state.in_buffer.size = block_manager.GetBlockSize() - sizeof(block_id_t) - current_offset; - - // Initialize the context for streaming decompression - duckdb_zstd::ZSTD_DCtx_reset(decompression_context, duckdb_zstd::ZSTD_reset_session_only); - duckdb_zstd::ZSTD_DCtx_refDDict(decompression_context, nullptr); - - if (internal_offset) { - Skip(scan_state, internal_offset); - } - return scan_state; - } - - void LoadNextPageForVector(ZSTDVectorScanState &scan_state) { - if (scan_state.in_buffer.pos != scan_state.in_buffer.size) { - throw InternalException( - "(ZSTDScanState::LoadNextPageForVector) Trying to load the next page before consuming the current one"); - } - // Read the next block id from the end of the page - auto base_ptr = - reinterpret_cast(const_cast(scan_state.in_buffer.src)); // NOLINT: const cast - auto next_id_ptr = base_ptr + scan_state.in_buffer.size; - block_id_t next_id = Load(next_id_ptr); - - // Load the next page - auto block = LoadPage(next_id); - auto handle = buffer_manager.Pin(block); - auto ptr = handle.Ptr(); - scan_state.buffer_handles.push_back(std::move(handle)); - scan_state.current_buffer_ptr = ptr; - - // Update the in_buffer to point to the new page - scan_state.in_buffer.src = ptr; - scan_state.in_buffer.pos = 0; - - idx_t page_size = block_manager.GetBlockSize() - sizeof(block_id_t); - idx_t remaining_compressed_data = scan_state.metadata.compressed_size - scan_state.compressed_scan_count; - scan_state.in_buffer.size = MinValue(page_size, remaining_compressed_data); - } - - void DecompressString(ZSTDVectorScanState &scan_state, data_ptr_t destination, idx_t uncompressed_length) { - if (uncompressed_length == 0) { - return; - } - - duckdb_zstd::ZSTD_outBuffer out_buffer; - - out_buffer.dst = destination; - out_buffer.pos = 0; - out_buffer.size = uncompressed_length; - - while (true) { - idx_t old_pos = scan_state.in_buffer.pos; - size_t res = duckdb_zstd::ZSTD_decompressStream( - /* zds = */ decompression_context, - /* output =*/&out_buffer, - /* input =*/&scan_state.in_buffer); - scan_state.compressed_scan_count += scan_state.in_buffer.pos - old_pos; - if (duckdb_zstd::ZSTD_isError(res)) { - throw InvalidInputException("ZSTD Decompression failed: %s", duckdb_zstd::ZSTD_getErrorName(res)); - } - if (out_buffer.pos == out_buffer.size) { - break; - } - // Did not fully decompress, it needs a new page to read from - LoadNextPageForVector(scan_state); - } - } - - void Skip(ZSTDVectorScanState &scan_state, idx_t count) { - if (!skip_buffer) { - skip_buffer = Allocator::DefaultAllocator().Allocate(duckdb_zstd::ZSTD_DStreamOutSize()); - } - - D_ASSERT(scan_state.scanned_count + count <= scan_state.metadata.count); - - // Figure out how much we need to skip - string_length_t *string_lengths = &scan_state.string_lengths[scan_state.scanned_count]; - idx_t uncompressed_length = 0; - for (idx_t i = 0; i < count; i++) { - uncompressed_length += string_lengths[i]; - } - - // Skip that many bytes by decompressing into the skip_buffer - idx_t remaining = uncompressed_length; - while (remaining) { - idx_t to_scan = MinValue(skip_buffer.GetSize(), remaining); - DecompressString(scan_state, skip_buffer.get(), to_scan); - remaining -= to_scan; - } - scan_state.scanned_count += count; - scanned_count += count; - } - - void ScanInternal(ZSTDVectorScanState &scan_state, idx_t count, Vector &result, idx_t result_offset) { - D_ASSERT(scan_state.scanned_count + count <= scan_state.metadata.count); - D_ASSERT(result.GetType().InternalType() == PhysicalType::VARCHAR); - - string_length_t *string_lengths = &scan_state.string_lengths[scan_state.scanned_count]; - idx_t uncompressed_length = 0; - for (idx_t i = 0; i < count; i++) { - uncompressed_length += string_lengths[i]; - } - auto empty_string = StringVector::EmptyString(result, uncompressed_length); - auto uncompressed_data = empty_string.GetDataWriteable(); - auto string_data = FlatVector::GetData(result); - - DecompressString(scan_state, reinterpret_cast(uncompressed_data), uncompressed_length); - - idx_t offset = 0; - auto uncompressed_data_const = empty_string.GetData(); - for (idx_t i = 0; i < count; i++) { - string_data[result_offset + i] = string_t(uncompressed_data_const + offset, string_lengths[i]); - offset += string_lengths[i]; - } - scan_state.scanned_count += count; - scanned_count += count; - } - - void ScanPartial(idx_t start_idx, Vector &result, idx_t offset, idx_t count) { - idx_t remaining = count; - idx_t scanned = 0; - while (remaining) { - idx_t internal_offset; - idx_t vector_idx = GetVectorIndex(start_idx + scanned, internal_offset); - auto &scan_state = LoadVector(vector_idx, internal_offset); - idx_t remaining_in_vector = scan_state.metadata.count - scan_state.scanned_count; - idx_t to_scan = MinValue(remaining, remaining_in_vector); - ScanInternal(scan_state, to_scan, result, offset + scanned); - remaining -= to_scan; - scanned += to_scan; - } - D_ASSERT(scanned == count); - } - -public: - UncompressedStringSegmentState &state; - BlockManager &block_manager; - BufferManager &buffer_manager; - - duckdb_zstd::ZSTD_DCtx *decompression_context = nullptr; - - idx_t segment_block_offset; - BufferHandle segment_handle; - - //===--------------------------------------------------------------------===// - // Vector metadata - //===--------------------------------------------------------------------===// - page_id_t *page_ids; - page_offset_t *page_offsets; - uncompressed_size_t *uncompressed_sizes; - compressed_size_t *compressed_sizes; - - //! Cache of (the scan state of) the current vector being read - unique_ptr current_vector; - - //! The amount of tuples stored in the segment - idx_t segment_count; - //! The amount of tuples consumed - idx_t scanned_count = 0; - - //! Buffer for skipping data - AllocatedData skip_buffer; -}; - -unique_ptr ZSTDStorage::StringInitScan(ColumnSegment &segment) { - auto result = make_uniq(segment); - return std::move(result); -} - -//===--------------------------------------------------------------------===// -// Scan base data -//===--------------------------------------------------------------------===// -void ZSTDStorage::StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result, - idx_t result_offset) { - auto &scan_state = state.scan_state->template Cast(); - auto start = segment.GetRelativeIndex(state.row_index); - - scan_state.ScanPartial(start, result, result_offset, scan_count); -} - -void ZSTDStorage::StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result) { - StringScanPartial(segment, state, scan_count, result, 0); -} - -//===--------------------------------------------------------------------===// -// Fetch -//===--------------------------------------------------------------------===// -void ZSTDStorage::StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result, - idx_t result_idx) { - ZSTDScanState scan_state(segment); - scan_state.ScanPartial(UnsafeNumericCast(row_id), result, result_idx, 1); -} - -//===--------------------------------------------------------------------===// -// Serialization & Cleanup -//===--------------------------------------------------------------------===// - -unique_ptr ZSTDStorage::StringInitSegment(ColumnSegment &segment, block_id_t block_id, - optional_ptr segment_state) { - auto result = make_uniq(); - if (segment_state) { - auto &serialized_state = segment_state->Cast(); - result->on_disk_blocks = std::move(serialized_state.blocks); - } - return std::move(result); -} - -unique_ptr ZSTDStorage::SerializeState(ColumnSegment &segment) { - auto &state = segment.GetSegmentState()->Cast(); - if (state.on_disk_blocks.empty()) { - // no on-disk blocks - nothing to write - return nullptr; - } - return make_uniq(state.on_disk_blocks); -} - -unique_ptr ZSTDStorage::DeserializeState(Deserializer &deserializer) { - auto result = make_uniq(); - deserializer.ReadProperty(1, "overflow_blocks", result->blocks); - return std::move(result); -} - -void ZSTDStorage::CleanupState(ColumnSegment &segment) { - auto &state = segment.GetSegmentState()->Cast(); - auto &block_manager = segment.GetBlockManager(); - for (auto &block_id : state.on_disk_blocks) { - block_manager.MarkBlockAsModified(block_id); - } -} - -//===--------------------------------------------------------------------===// -// Get Function -//===--------------------------------------------------------------------===// -CompressionFunction ZSTDFun::GetFunction(PhysicalType data_type) { - D_ASSERT(data_type == PhysicalType::VARCHAR); - auto zstd = CompressionFunction( - CompressionType::COMPRESSION_ZSTD, data_type, ZSTDStorage::StringInitAnalyze, ZSTDStorage::StringAnalyze, - ZSTDStorage::StringFinalAnalyze, ZSTDStorage::InitCompression, ZSTDStorage::Compress, - ZSTDStorage::FinalizeCompress, ZSTDStorage::StringInitScan, ZSTDStorage::StringScan, - ZSTDStorage::StringScanPartial, ZSTDStorage::StringFetchRow, ZSTDStorage::StringSkip); - zstd.init_segment = ZSTDStorage::StringInitSegment; - zstd.serialize_state = ZSTDStorage::SerializeState; - zstd.deserialize_state = ZSTDStorage::DeserializeState; - zstd.cleanup_state = ZSTDStorage::CleanupState; - return zstd; -} - -bool ZSTDFun::TypeIsSupported(PhysicalType type) { - return type == PhysicalType::VARCHAR; -} - -} // namespace duckdb diff --git a/src/duckdb/src/storage/data_table.cpp b/src/duckdb/src/storage/data_table.cpp index 81bf50100..3e7b63da2 100644 --- a/src/duckdb/src/storage/data_table.cpp +++ b/src/duckdb/src/storage/data_table.cpp @@ -3,32 +3,30 @@ #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/common/chrono.hpp" #include "duckdb/common/exception.hpp" -#include "duckdb/common/exception/transaction_exception.hpp" #include "duckdb/common/helper.hpp" -#include "duckdb/common/types/conflict_manager.hpp" -#include "duckdb/common/types/constraint_conflict_info.hpp" #include "duckdb/common/vector_operations/vector_operations.hpp" #include "duckdb/execution/expression_executor.hpp" -#include "duckdb/main/attached_database.hpp" #include "duckdb/main/client_context.hpp" #include "duckdb/parser/constraints/list.hpp" #include "duckdb/planner/constraints/list.hpp" -#include "duckdb/planner/expression/bound_constant_expression.hpp" -#include "duckdb/planner/expression/bound_reference_expression.hpp" #include "duckdb/planner/expression_binder/check_binder.hpp" -#include "duckdb/planner/expression_binder/constant_binder.hpp" #include "duckdb/planner/table_filter.hpp" #include "duckdb/storage/checkpoint/table_data_writer.hpp" #include "duckdb/storage/storage_manager.hpp" -#include "duckdb/storage/table/append_state.hpp" -#include "duckdb/storage/table/delete_state.hpp" +#include "duckdb/storage/table_storage_info.hpp" #include "duckdb/storage/table/persistent_table_data.hpp" #include "duckdb/storage/table/row_group.hpp" -#include "duckdb/storage/table/scan_state.hpp" #include "duckdb/storage/table/standard_column_data.hpp" -#include "duckdb/storage/table/update_state.hpp" -#include "duckdb/storage/table_storage_info.hpp" #include "duckdb/transaction/duck_transaction.hpp" +#include "duckdb/transaction/transaction_manager.hpp" +#include "duckdb/main/attached_database.hpp" +#include "duckdb/common/types/conflict_manager.hpp" +#include "duckdb/common/types/constraint_conflict_info.hpp" +#include "duckdb/storage/table/append_state.hpp" +#include "duckdb/storage/table/delete_state.hpp" +#include "duckdb/storage/table/scan_state.hpp" +#include "duckdb/storage/table/update_state.hpp" +#include "duckdb/common/exception/transaction_exception.hpp" namespace duckdb { @@ -52,8 +50,8 @@ DataTable::DataTable(AttachedDatabase &db, shared_ptr table_io_m column_definitions(std::move(column_definitions_p)), is_root(true) { // initialize the table with the existing data from disk, if any auto types = GetTypes(); - auto &io_manager = TableIOManager::Get(*this); - this->row_groups = make_shared_ptr(info, io_manager, types, 0); + this->row_groups = + make_shared_ptr(info, TableIOManager::Get(*this).GetBlockManagerForRowData(), types, 0); if (data && data->row_group_count > 0) { this->row_groups->Initialize(*data); } else { @@ -136,32 +134,29 @@ DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t removed_co parent.is_root = false; } -DataTable::DataTable(ClientContext &context, DataTable &parent, BoundConstraint &constraint) +// Alter column to add new constraint +DataTable::DataTable(ClientContext &context, DataTable &parent, unique_ptr constraint) : db(parent.db), info(parent.info), row_groups(parent.row_groups), is_root(true) { - // ALTER COLUMN to add a new constraint. - - // Clone the storage info vector or the table. - for (const auto &index_info : parent.info->index_storage_infos) { - info->index_storage_infos.push_back(IndexStorageInfo(index_info.name)); - } - info->InitializeIndexes(context); - auto &local_storage = LocalStorage::Get(context, db); lock_guard parent_lock(parent.append_lock); for (auto &column_def : parent.column_definitions) { column_definitions.emplace_back(column_def.Copy()); } - if (constraint.type != ConstraintType::UNIQUE) { - VerifyNewConstraint(local_storage, parent, constraint); - } + info->InitializeIndexes(context); + + // Verify the new constraint against current persistent/local data + VerifyNewConstraint(local_storage, parent, *constraint); + + // Get the local data ownership from old dt local_storage.MoveStorage(parent, *this); + // this table replaces the previous table, hence the parent is no longer the root DataTable parent.is_root = false; } DataTable::DataTable(ClientContext &context, DataTable &parent, idx_t changed_idx, const LogicalType &target_type, - const vector &bound_columns, Expression &cast_expr) + const vector &bound_columns, Expression &cast_expr) : db(parent.db), info(parent.info), is_root(true) { auto &local_storage = LocalStorage::Get(context, db); // prevent any tuples from being added to the parent @@ -228,37 +223,34 @@ TableIOManager &TableIOManager::Get(DataTable &table) { //===--------------------------------------------------------------------===// // Scan //===--------------------------------------------------------------------===// -void DataTable::InitializeScan(DuckTransaction &transaction, TableScanState &state, - const vector &column_ids, TableFilterSet *table_filters) { - state.checkpoint_lock = transaction.SharedLockTable(*info); - auto &local_storage = LocalStorage::Get(transaction); +void DataTable::InitializeScan(TableScanState &state, const vector &column_ids, + TableFilterSet *table_filters) { + if (!state.checkpoint_lock) { + state.checkpoint_lock = make_shared_ptr(info->checkpoint_lock.GetSharedLock()); + } state.Initialize(column_ids, table_filters); row_groups->InitializeScan(state.table_state, column_ids, table_filters); - local_storage.InitializeScan(*this, state.local_state, table_filters); } -void DataTable::InitializeScanWithOffset(DuckTransaction &transaction, TableScanState &state, - const vector &column_ids, idx_t start_row, idx_t end_row) { +void DataTable::InitializeScan(DuckTransaction &transaction, TableScanState &state, const vector &column_ids, + TableFilterSet *table_filters) { state.checkpoint_lock = transaction.SharedLockTable(*info); - state.Initialize(column_ids); - row_groups->InitializeScanWithOffset(state.table_state, column_ids, start_row, end_row); -} - -idx_t DataTable::GetRowGroupSize() const { - return row_groups->GetRowGroupSize(); + auto &local_storage = LocalStorage::Get(transaction); + InitializeScan(state, column_ids, table_filters); + local_storage.InitializeScan(*this, state.local_state, table_filters); } -vector DataTable::GetPartitionStats(ClientContext &context) { - auto result = row_groups->GetPartitionStats(); - auto &local_storage = LocalStorage::Get(context, db); - auto local_partitions = local_storage.GetPartitionStats(*this); - result.insert(result.end(), local_partitions.begin(), local_partitions.end()); - return result; +void DataTable::InitializeScanWithOffset(TableScanState &state, const vector &column_ids, idx_t start_row, + idx_t end_row) { + if (!state.checkpoint_lock) { + state.checkpoint_lock = make_shared_ptr(info->checkpoint_lock.GetSharedLock()); + } + state.Initialize(column_ids); + row_groups->InitializeScanWithOffset(state.table_state, column_ids, start_row, end_row); } -idx_t DataTable::MaxThreads(ClientContext &context) const { - idx_t row_group_size = GetRowGroupSize(); - idx_t parallel_scan_vector_count = row_group_size / STANDARD_VECTOR_SIZE; +idx_t DataTable::MaxThreads(ClientContext &context) { + idx_t parallel_scan_vector_count = Storage::ROW_GROUP_VECTOR_COUNT; if (ClientConfig::GetConfig(context).verify_parallelism) { parallel_scan_vector_count = 1; } @@ -319,21 +311,6 @@ bool DataTable::HasIndexes() const { return !info->indexes.Empty(); } -bool DataTable::HasUniqueIndexes() const { - if (!HasIndexes()) { - return false; - } - bool has_unique_index = false; - info->indexes.Scan([&](Index &index) { - if (index.IsUnique()) { - has_unique_index = true; - return true; - } - return false; - }); - return has_unique_index; -} - void DataTable::AddIndex(unique_ptr index) { info->indexes.AddIndex(std::move(index)); } @@ -403,7 +380,7 @@ TableStorageInfo DataTable::GetStorageInfo() { //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// -void DataTable::Fetch(DuckTransaction &transaction, DataChunk &result, const vector &column_ids, +void DataTable::Fetch(DuckTransaction &transaction, DataChunk &result, const vector &column_ids, const Vector &row_identifiers, idx_t fetch_count, ColumnFetchState &state) { auto lock = info->checkpoint_lock.GetSharedLock(); row_groups->Fetch(transaction, result, column_ids, row_identifiers, fetch_count, state); @@ -438,20 +415,17 @@ static void VerifyGeneratedExpressionSuccess(ClientContext &context, TableCatalo } } -static void VerifyCheckConstraint(ClientContext &context, TableCatalogEntry &table, Expression &expr, DataChunk &chunk, - CheckConstraint &check) { +static void VerifyCheckConstraint(ClientContext &context, TableCatalogEntry &table, Expression &expr, + DataChunk &chunk) { ExpressionExecutor executor(context, expr); Vector result(LogicalType::INTEGER); try { executor.ExecuteExpression(chunk, result); } catch (std::exception &ex) { ErrorData error(ex); - throw ConstraintException("CHECK constraint failed on table %s with expression %s (Error: %s)", table.name, - check.ToString(), error.RawMessage()); - } catch (...) { - // LCOV_EXCL_START - throw ConstraintException("CHECK constraint failed on table %s with expression %s (Unknown Error)", table.name, - check.ToString()); + throw ConstraintException("CHECK constraint failed: %s (Error: %s)", table.name, error.RawMessage()); + } catch (...) { // LCOV_EXCL_START + throw ConstraintException("CHECK constraint failed: %s (Unknown Error)", table.name); } // LCOV_EXCL_STOP UnifiedVectorFormat vdata; result.ToUnifiedFormat(chunk.size(), vdata); @@ -460,8 +434,7 @@ static void VerifyCheckConstraint(ClientContext &context, TableCatalogEntry &tab for (idx_t i = 0; i < chunk.size(); i++) { auto idx = vdata.sel->get_index(i); if (vdata.validity.RowIsValid(idx) && dataptr[idx] == 0) { - throw ConstraintException("CHECK constraint failed on table %s with expression %s", table.name, - check.ToString()); + throw ConstraintException("CHECK constraint failed: %s", table.name); } } } @@ -504,12 +477,15 @@ static idx_t FirstMissingMatch(const ManagedSelection &matches) { } idx_t LocateErrorIndex(bool is_append, const ManagedSelection &matches) { - // We expected to find nothing, so the first error is the first match. + idx_t failed_index = DConstants::INVALID_INDEX; if (!is_append) { - return matches[0]; + // We expected to find nothing, so the first error is the first match + failed_index = matches[0]; + } else { + // We expected to find matches for all of them, so the first missing match is the first error + return FirstMissingMatch(matches); } - // We expected to find matches for all of them, so the first missing match is the first error. - return FirstMissingMatch(matches); + return failed_index; } [[noreturn]] static void ThrowForeignKeyConstraintError(idx_t failed_index, bool is_append, Index &conflict_index, @@ -681,82 +657,83 @@ void DataTable::VerifyNewConstraint(LocalStorage &local_storage, DataTable &pare local_storage.VerifyNewConstraint(parent, constraint); } -void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, optional_ptr storage, DataChunk &chunk, - optional_ptr manager) { - // Verify the constraint without a conflict manager. - if (!manager) { - return indexes.ScanBound([&](ART &art) { - if (!art.IsUnique()) { - return false; - } +bool HasUniqueIndexes(TableIndexList &list) { + bool has_unique_index = false; + list.Scan([&](Index &index) { + if (index.IsUnique()) { + has_unique_index = true; + return true; + } + return false; + }); + return has_unique_index; +} - if (storage) { - auto delete_index = storage->delete_indexes.Find(art.GetIndexName()); - art.VerifyAppend(chunk, delete_index, nullptr); - } else { - art.VerifyAppend(chunk, nullptr, nullptr); +void DataTable::VerifyUniqueIndexes(TableIndexList &indexes, ClientContext &context, DataChunk &chunk, + optional_ptr conflict_manager) { + //! check whether or not the chunk can be inserted into the indexes + if (!conflict_manager) { + // Only need to verify that no unique constraints are violated + indexes.Scan([&](Index &index) { + if (!index.IsUnique()) { + return false; } + D_ASSERT(index.IsBound()); + index.Cast().VerifyAppend(chunk); return false; }); + return; } - // The conflict manager is only provided for statements containing ON CONFLICT. - auto &conflict_info = manager->GetConflictInfo(); + D_ASSERT(conflict_manager); + // The conflict manager is only provided when a ON CONFLICT clause was provided to the INSERT statement - // Find all indexes matching the conflict target. - indexes.ScanBound([&](ART &art) { - if (!art.IsUnique()) { + idx_t matching_indexes = 0; + auto &conflict_info = conflict_manager->GetConflictInfo(); + // First we figure out how many indexes match our conflict target + // So we can optimize accordingly + indexes.Scan([&](Index &index) { + matching_indexes += conflict_info.ConflictTargetMatches(index); + return false; + }); + conflict_manager->SetMode(ConflictManagerMode::SCAN); + conflict_manager->SetIndexCount(matching_indexes); + // First we verify only the indexes that match our conflict target + unordered_set checked_indexes; + indexes.Scan([&](Index &index) { + if (!index.IsUnique()) { return false; } - if (!conflict_info.ConflictTargetMatches(art)) { - return false; - } - - if (storage) { - auto delete_index = storage->delete_indexes.Find(art.GetIndexName()); - manager->AddIndex(art, delete_index); - } else { - manager->AddIndex(art, nullptr); + if (conflict_info.ConflictTargetMatches(index)) { + D_ASSERT(index.IsBound()); + index.Cast().VerifyAppend(chunk, *conflict_manager); + checked_indexes.insert(&index); } return false; }); - // Verify indexes matching the conflict target. - manager->SetMode(ConflictManagerMode::SCAN); - auto &matched_indexes = manager->MatchedIndexes(); - auto &matched_delete_indexes = manager->MatchedDeleteIndexes(); - for (idx_t i = 0; i < matched_indexes.size(); i++) { - matched_indexes[i].get().VerifyAppend(chunk, matched_delete_indexes[i], *manager); - } - - // Scan the other indexes and throw, if there are any conflicts. - manager->SetMode(ConflictManagerMode::THROW); - indexes.ScanBound([&](ART &art) { - if (!art.IsUnique()) { + conflict_manager->SetMode(ConflictManagerMode::THROW); + // Then we scan the other indexes, throwing if they cause conflicts on tuples that were not found during + // the scan + indexes.Scan([&](Index &index) { + if (!index.IsUnique()) { return false; } - if (manager->MatchedIndex(art)) { + if (checked_indexes.count(&index)) { + // Already checked this constraint return false; } - - if (storage) { - auto delete_index = storage->delete_indexes.Find(art.GetIndexName()); - art.VerifyAppend(chunk, delete_index, *manager); - } else { - art.VerifyAppend(chunk, nullptr, *manager); - } + D_ASSERT(index.IsBound()); + index.Cast().VerifyAppend(chunk, *conflict_manager); return false; }); } -void DataTable::VerifyAppendConstraints(ConstraintState &constraint_state, ClientContext &context, DataChunk &chunk, - optional_ptr storage, - optional_ptr manager) { - - auto &table = constraint_state.table; - +void DataTable::VerifyAppendConstraints(ConstraintState &state, ClientContext &context, DataChunk &chunk, + optional_ptr conflict_manager) { + auto &table = state.table; if (table.HasGeneratedColumns()) { - // Verify the generated columns against the inserted values. + // Verify that the generated columns expression work with the inserted values auto binder = Binder::CreateBinder(context); physical_index_set_t bound_columns; CheckBinder generated_check_binder(*binder, context, table.name, table.GetColumns(), bound_columns); @@ -772,34 +749,33 @@ void DataTable::VerifyAppendConstraints(ConstraintState &constraint_state, Clien } } - if (HasUniqueIndexes()) { - VerifyUniqueIndexes(info->indexes, storage, chunk, manager); + if (HasUniqueIndexes(info->indexes)) { + VerifyUniqueIndexes(info->indexes, context, chunk, conflict_manager); } auto &constraints = table.GetConstraints(); - for (idx_t i = 0; i < constraint_state.bound_constraints.size(); i++) { + for (idx_t i = 0; i < state.bound_constraints.size(); i++) { auto &base_constraint = constraints[i]; - auto &constraint = constraint_state.bound_constraints[i]; + auto &constraint = state.bound_constraints[i]; switch (base_constraint->type) { case ConstraintType::NOT_NULL: { - auto &bound_not_null = constraint->Cast(); - auto ¬_null = base_constraint->Cast(); + auto &bound_not_null = *reinterpret_cast(constraint.get()); + auto ¬_null = *reinterpret_cast(base_constraint.get()); auto &col = table.GetColumns().GetColumn(LogicalIndex(not_null.index)); VerifyNotNullConstraint(table, chunk.data[bound_not_null.index.index], chunk.size(), col.Name()); break; } case ConstraintType::CHECK: { - auto &check = base_constraint->Cast(); - auto &bound_check = constraint->Cast(); - VerifyCheckConstraint(context, table, *bound_check.expression, chunk, check); + auto &check = *reinterpret_cast(constraint.get()); + VerifyCheckConstraint(context, table, *check.expression, chunk); break; } case ConstraintType::UNIQUE: { - // These were handled earlier. + // These were handled earlier on break; } case ConstraintType::FOREIGN_KEY: { - auto &bfk = constraint->Cast(); + auto &bfk = *reinterpret_cast(constraint.get()); if (bfk.info.type == ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { VerifyAppendForeignKeyConstraint(bfk, context, chunk); @@ -807,7 +783,7 @@ void DataTable::VerifyAppendConstraints(ConstraintState &constraint_state, Clien break; } default: - throw InternalException("invalid constraint type"); + throw NotImplementedException("Constraint type not implemented!"); } } } @@ -825,37 +801,28 @@ void DataTable::InitializeLocalAppend(LocalAppendState &state, TableCatalogEntry } auto &local_storage = LocalStorage::Get(context, db); local_storage.InitializeAppend(state, *this); - state.constraint_state = InitializeConstraintState(table, bound_constraints); -} - -void DataTable::InitializeLocalStorage(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context, - const vector> &bound_constraints) { - if (!is_root) { - throw TransactionException("Transaction conflict: adding entries to a table that has been altered!"); - } - auto &local_storage = LocalStorage::Get(context, db); - local_storage.InitializeStorage(state, *this); state.constraint_state = InitializeConstraintState(table, bound_constraints); } -void DataTable::LocalAppend(LocalAppendState &state, ClientContext &context, DataChunk &chunk, bool unsafe) { +void DataTable::LocalAppend(LocalAppendState &state, TableCatalogEntry &table, ClientContext &context, DataChunk &chunk, + bool unsafe) { if (chunk.size() == 0) { return; } + D_ASSERT(chunk.ColumnCount() == table.GetColumns().PhysicalColumnCount()); if (!is_root) { - throw TransactionException("write conflict: adding entries to a table that has been altered"); + throw TransactionException("Transaction conflict: adding entries to a table that has been altered!"); } + chunk.Verify(); - // Insert any row ids into the DELETE ART and verify constraints afterward. - // This happens only for the global indexes. + // verify any constraints on the new chunk if (!unsafe) { - auto &constraint_state = *state.constraint_state; - VerifyAppendConstraints(constraint_state, context, chunk, *state.storage, nullptr); + VerifyAppendConstraints(*state.constraint_state, context, chunk); } - // Append to the transaction-local data. + // append to the transaction local data LocalStorage::Append(state, chunk); } @@ -883,78 +850,17 @@ void DataTable::LocalAppend(TableCatalogEntry &table, ClientContext &context, Da LocalAppendState append_state; auto &storage = table.GetStorage(); storage.InitializeLocalAppend(append_state, table, context, bound_constraints); - - storage.LocalAppend(append_state, context, chunk, false); - storage.FinalizeLocalAppend(append_state); -} - -void DataTable::LocalAppend(TableCatalogEntry &table, ClientContext &context, DataChunk &chunk, - const vector> &bound_constraints, Vector &row_ids, - DataChunk &delete_chunk) { - LocalAppendState append_state; - auto &storage = table.GetStorage(); - storage.InitializeLocalAppend(append_state, table, context, bound_constraints); - append_state.storage->AppendToDeleteIndexes(row_ids, delete_chunk); - - storage.LocalAppend(append_state, context, chunk, false); + storage.LocalAppend(append_state, table, context, chunk); storage.FinalizeLocalAppend(append_state); } void DataTable::LocalAppend(TableCatalogEntry &table, ClientContext &context, ColumnDataCollection &collection, - const vector> &bound_constraints, - optional_ptr> column_ids) { - + const vector> &bound_constraints) { LocalAppendState append_state; auto &storage = table.GetStorage(); storage.InitializeLocalAppend(append_state, table, context, bound_constraints); - - if (!column_ids || column_ids->empty()) { - for (auto &chunk : collection.Chunks()) { - storage.LocalAppend(append_state, context, chunk, false); - } - storage.FinalizeLocalAppend(append_state); - return; - } - - auto &column_list = table.GetColumns(); - map> active_expressions; - for (idx_t i = 0; i < column_ids->size(); i++) { - auto &col = column_list.GetColumn((*column_ids)[i]); - auto expr = make_uniq(col.Name(), col.Type(), i); - active_expressions[col.Physical()] = std::move(expr); - } - - auto binder = Binder::CreateBinder(context); - ConstantBinder default_binder(*binder, context, "DEFAULT value"); - vector> expressions; - for (idx_t i = 0; i < column_list.PhysicalColumnCount(); i++) { - auto expr = active_expressions.find(PhysicalIndex(i)); - if (expr != active_expressions.end()) { - expressions.push_back(std::move(expr->second)); - continue; - } - - auto &col = column_list.GetColumn(PhysicalIndex(i)); - if (!col.HasDefaultValue()) { - auto null_expr = make_uniq(Value(col.Type())); - expressions.push_back(std::move(null_expr)); - continue; - } - - auto default_copy = col.DefaultValue().Copy(); - default_binder.target_type = col.Type(); - auto bound_default = default_binder.Bind(default_copy); - expressions.push_back(std::move(bound_default)); - } - - ExpressionExecutor expression_executor(context, expressions); - DataChunk result; - result.Initialize(context, table.GetTypes()); - for (auto &chunk : collection.Chunks()) { - expression_executor.Execute(chunk, result); - storage.LocalAppend(append_state, context, result, false); - result.Reset(); + storage.LocalAppend(append_state, table, context, chunk); } storage.FinalizeLocalAppend(append_state); } @@ -985,18 +891,17 @@ void DataTable::FinalizeAppend(DuckTransaction &transaction, TableAppendState &s row_groups->FinalizeAppend(transaction, state); } -void DataTable::ScanTableSegment(DuckTransaction &transaction, idx_t row_start, idx_t count, - const std::function &function) { +void DataTable::ScanTableSegment(idx_t row_start, idx_t count, const std::function &function) { if (count == 0) { return; } idx_t end = row_start + count; - vector column_ids; + vector column_ids; vector types; for (idx_t i = 0; i < this->column_definitions.size(); i++) { auto &col = this->column_definitions[i]; - column_ids.emplace_back(i); + column_ids.push_back(i); types.push_back(col.Type()); } DataChunk chunk; @@ -1004,7 +909,7 @@ void DataTable::ScanTableSegment(DuckTransaction &transaction, idx_t row_start, CreateIndexScanState state; - InitializeScanWithOffset(transaction, state, column_ids, row_start, row_start + count); + InitializeScanWithOffset(state, column_ids, row_start, row_start + count); auto row_start_aligned = state.table_state.row_group->start + state.table_state.vector_index * STANDARD_VECTOR_SIZE; idx_t current_row = row_start_aligned; @@ -1046,7 +951,7 @@ void DataTable::MergeStorage(RowGroupCollection &data, TableIndexList &, row_groups->Verify(); } -void DataTable::WriteToLog(DuckTransaction &transaction, WriteAheadLog &log, idx_t row_start, idx_t count, +void DataTable::WriteToLog(WriteAheadLog &log, idx_t row_start, idx_t count, optional_ptr commit_state) { log.WriteSetTable(info->schema, info->table); if (commit_state) { @@ -1068,7 +973,7 @@ void DataTable::WriteToLog(DuckTransaction &transaction, WriteAheadLog &log, idx } } } - ScanTableSegment(transaction, row_start, count, [&](DataChunk &chunk) { log.WriteInsert(chunk); }); + ScanTableSegment(row_start, count, [&](DataChunk &chunk) { log.WriteInsert(chunk); }); } void DataTable::CommitAppend(transaction_t commit_id, idx_t row_start, idx_t count) { @@ -1082,7 +987,7 @@ void DataTable::RevertAppendInternal(idx_t start_row) { row_groups->RevertAppendInternal(start_row); } -void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_t count) { +void DataTable::RevertAppend(idx_t start_row, idx_t count) { lock_guard lock(append_lock); // revert any appends to indexes @@ -1091,7 +996,7 @@ void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_ row_t row_data[STANDARD_VECTOR_SIZE]; Vector row_identifiers(LogicalType::ROW_TYPE, data_ptr_cast(row_data)); idx_t scan_count = MinValue(count, row_groups->GetTotalRows() - start_row); - ScanTableSegment(transaction, start_row, scan_count, [&](DataChunk &chunk) { + ScanTableSegment(start_row, scan_count, [&](DataChunk &chunk) { for (idx_t i = 0; i < chunk.size(); i++) { row_data[i] = NumericCast(current_row_base + i); } @@ -1123,40 +1028,30 @@ void DataTable::RevertAppend(DuckTransaction &transaction, idx_t start_row, idx_ //===--------------------------------------------------------------------===// // Indexes //===--------------------------------------------------------------------===// -ErrorData DataTable::AppendToIndexes(TableIndexList &indexes, optional_ptr delete_indexes, - DataChunk &chunk, row_t row_start) { +ErrorData DataTable::AppendToIndexes(TableIndexList &indexes, DataChunk &chunk, row_t row_start) { ErrorData error; if (indexes.Empty()) { return error; } - // first generate the vector of row identifiers - Vector row_ids(LogicalType::ROW_TYPE); - VectorOperations::GenerateSequence(row_ids, chunk.size(), row_start, 1); + Vector row_identifiers(LogicalType::ROW_TYPE); + VectorOperations::GenerateSequence(row_identifiers, chunk.size(), row_start, 1); vector already_appended; bool append_failed = false; // now append the entries to the indices indexes.Scan([&](Index &index_to_append) { if (!index_to_append.IsBound()) { - throw InternalException("unbound index in DataTable::AppendToIndexes"); + error = ErrorData("Unbound index found in DataTable::AppendToIndexes"); + append_failed = true; + return true; } auto &index = index_to_append.Cast(); - - // Find the matching delete index. - optional_ptr delete_index; - if (index.IsUnique()) { - if (delete_indexes) { - delete_index = delete_indexes->Find(index.name); - } - } - try { - error = index.AppendWithDeleteIndex(chunk, row_ids, delete_index); + error = index.Append(chunk, row_identifiers); } catch (std::exception &ex) { error = ErrorData(ex); } - if (error.HasError()) { append_failed = true; return true; @@ -1169,15 +1064,15 @@ ErrorData DataTable::AppendToIndexes(TableIndexList &indexes, optional_ptr
Delete(chunk, row_ids); + index->Delete(chunk, row_identifiers); } } return error; } -ErrorData DataTable::AppendToIndexes(optional_ptr delete_indexes, DataChunk &chunk, row_t row_start) { +ErrorData DataTable::AppendToIndexes(DataChunk &chunk, row_t row_start) { D_ASSERT(is_root); - return AppendToIndexes(info->indexes, delete_indexes, chunk, row_start); + return AppendToIndexes(info->indexes, chunk, row_start); } void DataTable::RemoveFromIndexes(TableAppendState &state, DataChunk &chunk, row_t row_start) { @@ -1242,7 +1137,7 @@ void DataTable::VerifyDeleteConstraints(TableDeleteState &state, ClientContext & case ConstraintType::UNIQUE: break; case ConstraintType::FOREIGN_KEY: { - auto &bfk = constraint->Cast(); + auto &bfk = *reinterpret_cast(constraint.get()); if (bfk.info.type == ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE || bfk.info.type == ForeignKeyType::FK_TYPE_SELF_REFERENCE_TABLE) { VerifyDeleteForeignKeyConstraint(bfk, context, chunk); @@ -1267,7 +1162,7 @@ unique_ptr DataTable::InitializeDelete(TableCatalogEntry &tabl if (result->has_delete_constraints) { // initialize the chunk if there are any constraints to verify for (idx_t i = 0; i < column_definitions.size(); i++) { - result->col_ids.emplace_back(column_definitions[i].StorageOid()); + result->col_ids.push_back(column_definitions[i].StorageOid()); types.emplace_back(column_definitions[i].Type()); } result->verify_chunk.Initialize(Allocator::Get(context), types); @@ -1304,9 +1199,8 @@ idx_t DataTable::Delete(TableDeleteState &state, ClientContext &context, Vector idx_t current_count = pos - start; Vector offset_ids(row_identifiers, current_offset, pos); - - // This is a transaction-local DELETE. if (is_transaction_delete) { + // transaction-local delete if (state.has_delete_constraints) { // perform the constraint verification ColumnFetchState fetch_state; @@ -1315,17 +1209,16 @@ idx_t DataTable::Delete(TableDeleteState &state, ClientContext &context, Vector VerifyDeleteConstraints(state, context, state.verify_chunk); } delete_count += local_storage.Delete(*this, offset_ids, current_count); - continue; - } - - // This is a regular DELETE. - if (state.has_delete_constraints) { - // perform the constraint verification - ColumnFetchState fetch_state; - Fetch(transaction, state.verify_chunk, state.col_ids, offset_ids, current_count, fetch_state); - VerifyDeleteConstraints(state, context, state.verify_chunk); + } else { + // regular table delete + if (state.has_delete_constraints) { + // perform the constraint verification + ColumnFetchState fetch_state; + Fetch(transaction, state.verify_chunk, state.col_ids, offset_ids, current_count, fetch_state); + VerifyDeleteConstraints(state, context, state.verify_chunk); + } + delete_count += row_groups->Delete(transaction, *this, ids + current_offset, current_count); } - delete_count += row_groups->Delete(transaction, *this, ids + current_offset, current_count); } return delete_count; } @@ -1377,8 +1270,8 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c auto &constraint = bound_constraints[constr_idx]; switch (constraint->type) { case ConstraintType::NOT_NULL: { - auto &bound_not_null = constraint->Cast(); - auto ¬_null = base_constraint->Cast(); + auto &bound_not_null = *reinterpret_cast(constraint.get()); + auto ¬_null = *reinterpret_cast(base_constraint.get()); // check if the constraint is in the list of column_ids for (idx_t col_idx = 0; col_idx < column_ids.size(); col_idx++) { if (column_ids[col_idx] == bound_not_null.index) { @@ -1391,12 +1284,11 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c break; } case ConstraintType::CHECK: { - auto &check = base_constraint->Cast(); - auto &bound_check = constraint->Cast(); + auto &check = *reinterpret_cast(constraint.get()); DataChunk mock_chunk; - if (CreateMockChunk(table, column_ids, bound_check.bound_columns, chunk, mock_chunk)) { - VerifyCheckConstraint(context, table, *bound_check.expression, mock_chunk, check); + if (CreateMockChunk(table, column_ids, check.bound_columns, chunk, mock_chunk)) { + VerifyCheckConstraint(context, table, *check.expression, mock_chunk); } break; } @@ -1407,15 +1299,15 @@ void DataTable::VerifyUpdateConstraints(ConstraintState &state, ClientContext &c throw NotImplementedException("Constraint type not implemented!"); } } - + // update should not be called for indexed columns! + // instead update should have been rewritten to delete + update on higher layer #ifdef DEBUG - // Ensure that we never call UPDATE for indexed columns. - // Instead, we must rewrite these updates into DELETE + INSERT. info->indexes.Scan([&](Index &index) { D_ASSERT(index.IsBound()); D_ASSERT(!index.Cast().IndexIsUpdated(column_ids)); return false; }); + #endif } @@ -1517,10 +1409,6 @@ void DataTable::SetDistinct(column_t column_id, unique_ptr d row_groups->SetDistinct(column_id, std::move(distinct_stats)); } -unique_ptr DataTable::GetSample() { - return row_groups->GetSample(); -} - //===--------------------------------------------------------------------===// // Checkpoint //===--------------------------------------------------------------------===// @@ -1537,8 +1425,8 @@ void DataTable::Checkpoint(TableDataWriter &writer, Serializer &serializer) { TableStatistics global_stats; row_groups->CopyStats(global_stats); row_groups->Checkpoint(writer, global_stats); + // The row group payload data has been written. Now write: - // sample // column stats // row-group pointers // table pointer @@ -1571,39 +1459,11 @@ void DataTable::CommitDropTable() { } //===--------------------------------------------------------------------===// -// Column Segment Info +// GetColumnSegmentInfo //===--------------------------------------------------------------------===// vector DataTable::GetColumnSegmentInfo() { auto lock = GetSharedCheckpointLock(); return row_groups->GetColumnSegmentInfo(); } -//===--------------------------------------------------------------------===// -// Index Constraint Creation -//===--------------------------------------------------------------------===// -void DataTable::AddIndex(const ColumnList &columns, const vector &column_indexes, - const IndexConstraintType type, const IndexStorageInfo &index_info) { - if (!IsRoot()) { - throw TransactionException("cannot add an index to a table that has been altered!"); - } - - // Fetch the column types and create bound column reference expressions. - vector physical_ids; - vector> expressions; - - for (const auto column_index : column_indexes) { - auto binding = ColumnBinding(0, physical_ids.size()); - auto &col = columns.GetColumn(column_index); - auto ref = make_uniq(col.Name(), col.Type(), binding); - expressions.push_back(std::move(ref)); - physical_ids.push_back(col.Physical().index); - } - - // Create an ART around the expressions. - auto &io_manager = TableIOManager::Get(*this); - auto art = make_uniq(index_info.name, type, physical_ids, io_manager, std::move(expressions), db, nullptr, - index_info); - info->indexes.AddIndex(std::move(art)); -} - } // namespace duckdb diff --git a/src/duckdb/src/storage/local_storage.cpp b/src/duckdb/src/storage/local_storage.cpp index 71b20bd10..282eb349f 100644 --- a/src/duckdb/src/storage/local_storage.cpp +++ b/src/duckdb/src/storage/local_storage.cpp @@ -17,49 +17,36 @@ namespace duckdb { LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &table) : table_ref(table), allocator(Allocator::Get(table.db)), deleted_rows(0), optimistic_writer(table), merged_storage(false) { - auto types = table.GetTypes(); auto data_table_info = table.GetDataTableInfo(); - auto &io_manager = TableIOManager::Get(table); - row_groups = make_shared_ptr(data_table_info, io_manager, types, MAX_ROW_ID, 0); + row_groups = make_shared_ptr( + data_table_info, TableIOManager::Get(table).GetBlockManagerForRowData(), types, MAX_ROW_ID, 0); row_groups->InitializeEmpty(); data_table_info->GetIndexes().BindAndScan(context, *data_table_info, [&](ART &art) { - auto constraint_type = art.GetConstraintType(); - if (constraint_type == IndexConstraintType::NONE) { - return false; - } - - // UNIQUE constraint. - vector> expressions; - vector> delete_expressions; - for (auto &expr : art.unbound_expressions) { - expressions.push_back(expr->Copy()); - delete_expressions.push_back(expr->Copy()); + if (art.GetConstraintType() != IndexConstraintType::NONE) { + // unique index: create a local ART index that maintains the same unique constraint + vector> unbound_expressions; + unbound_expressions.reserve(art.unbound_expressions.size()); + for (auto &expr : art.unbound_expressions) { + unbound_expressions.push_back(expr->Copy()); + } + indexes.AddIndex(make_uniq(art.GetIndexName(), art.GetConstraintType(), art.GetColumnIds(), + art.table_io_manager, std::move(unbound_expressions), art.db)); } - - // Create a delete index and a local index. - auto delete_index = make_uniq(art.GetIndexName(), constraint_type, art.GetColumnIds(), - art.table_io_manager, std::move(delete_expressions), art.db); - delete_index->append_mode = ARTAppendMode::IGNORE_DUPLICATES; - delete_indexes.AddIndex(std::move(delete_index)); - - auto index = make_uniq(art.GetIndexName(), constraint_type, art.GetColumnIds(), art.table_io_manager, - std::move(expressions), art.db); - append_indexes.AddIndex(std::move(index)); return false; }); } LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_dt, LocalTableStorage &parent, idx_t changed_idx, const LogicalType &target_type, - const vector &bound_columns, Expression &cast_expr) + const vector &bound_columns, Expression &cast_expr) : table_ref(new_dt), allocator(Allocator::Get(new_dt.db)), deleted_rows(parent.deleted_rows), optimistic_writer(new_dt, parent.optimistic_writer), optimistic_writers(std::move(parent.optimistic_writers)), merged_storage(parent.merged_storage) { row_groups = parent.row_groups->AlterType(context, changed_idx, target_type, bound_columns, cast_expr); parent.row_groups.reset(); - append_indexes.Move(parent.append_indexes); + indexes.Move(parent.indexes); } LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &parent, idx_t drop_idx) @@ -68,7 +55,7 @@ LocalTableStorage::LocalTableStorage(DataTable &new_dt, LocalTableStorage &paren merged_storage(parent.merged_storage) { row_groups = parent.row_groups->RemoveColumn(drop_idx); parent.row_groups.reset(); - append_indexes.Move(parent.append_indexes); + indexes.Move(parent.indexes); } LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_dt, LocalTableStorage &parent, @@ -78,7 +65,7 @@ LocalTableStorage::LocalTableStorage(ClientContext &context, DataTable &new_dt, merged_storage(parent.merged_storage) { row_groups = parent.row_groups->AddColumn(context, new_column, default_executor); parent.row_groups.reset(); - append_indexes.Move(parent.append_indexes); + indexes.Move(parent.indexes); } LocalTableStorage::~LocalTableStorage() { @@ -104,7 +91,7 @@ idx_t LocalTableStorage::EstimatedSize() { // get the index size idx_t index_sizes = 0; - append_indexes.Scan([&](Index &index) { + indexes.Scan([&](Index &index) { D_ASSERT(index.IsBound()); index_sizes += index.Cast().GetInMemorySize(); return false; @@ -123,8 +110,7 @@ void LocalTableStorage::WriteNewRowGroup() { } void LocalTableStorage::FlushBlocks() { - const idx_t row_group_size = row_groups->GetRowGroupSize(); - if (!merged_storage && row_groups->GetTotalRows() > row_group_size) { + if (!merged_storage && row_groups->GetTotalRows() > Storage::ROW_GROUP_SIZE) { optimistic_writer.WriteLastRowGroup(*row_groups); } optimistic_writer.FinalFlush(); @@ -135,24 +121,19 @@ ErrorData LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, RowGr row_t &start_row) { // only need to scan for index append // figure out which columns we need to scan for the set of indexes - auto index_columns = index_list.GetRequiredColumns(); - vector required_columns; - for (auto &col : index_columns) { - required_columns.emplace_back(col); - } + auto columns = index_list.GetRequiredColumns(); // create an empty mock chunk that contains all the correct types for the table DataChunk mock_chunk; mock_chunk.InitializeEmpty(table_types); ErrorData error; - source.Scan(transaction, required_columns, [&](DataChunk &chunk) -> bool { + source.Scan(transaction, columns, [&](DataChunk &chunk) -> bool { // construct the mock chunk by referencing the required columns - for (idx_t i = 0; i < required_columns.size(); i++) { - auto col_id = required_columns[i].GetPrimaryIndex(); - mock_chunk.data[col_id].Reference(chunk.data[i]); + for (idx_t i = 0; i < columns.size(); i++) { + mock_chunk.data[columns[i]].Reference(chunk.data[i]); } mock_chunk.SetCardinality(chunk); // append this chunk to the indexes of the table - error = DataTable::AppendToIndexes(index_list, nullptr, mock_chunk, start_row); + error = DataTable::AppendToIndexes(index_list, mock_chunk, start_row); if (error.HasError()) { return false; } @@ -163,7 +144,7 @@ ErrorData LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, RowGr } void LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, TableAppendState &append_state, - bool append_to_table) { + idx_t append_count, bool append_to_table) { auto &table = table_ref.get(); if (append_to_table) { table.InitializeAppend(transaction, append_state); @@ -173,7 +154,7 @@ void LocalTableStorage::AppendToIndexes(DuckTransaction &transaction, TableAppen // appending: need to scan entire row_groups->Scan(transaction, [&](DataChunk &chunk) -> bool { // append this chunk to the indexes of the table - error = table.AppendToIndexes(delete_indexes, chunk, append_state.current_row); + error = table.AppendToIndexes(chunk, append_state.current_row); if (error.HasError()) { return false; } @@ -253,7 +234,7 @@ void LocalTableStorage::Rollback() { //===--------------------------------------------------------------------===// // LocalTableManager //===--------------------------------------------------------------------===// -optional_ptr LocalTableManager::GetStorage(DataTable &table) const { +optional_ptr LocalTableManager::GetStorage(DataTable &table) { lock_guard l(table_storage_lock); auto entry = table_storage.find(table); return entry == table_storage.end() ? nullptr : entry->second.get(); @@ -272,7 +253,7 @@ LocalTableStorage &LocalTableManager::GetOrCreateStorage(ClientContext &context, } } -bool LocalTableManager::IsEmpty() const { +bool LocalTableManager::IsEmpty() { lock_guard l(table_storage_lock); return table_storage.empty(); } @@ -293,7 +274,7 @@ reference_map_t> LocalTableManager::Mov return std::move(table_storage); } -idx_t LocalTableManager::EstimatedSize() const { +idx_t LocalTableManager::EstimatedSize() { lock_guard l(table_storage_lock); idx_t estimated_size = 0; for (auto &storage : table_storage) { @@ -342,7 +323,7 @@ void LocalStorage::InitializeScan(DataTable &table, CollectionScanState &state, storage->InitializeScan(state, table_filters); } -void LocalStorage::Scan(CollectionScanState &state, const vector &, DataChunk &result) { +void LocalStorage::Scan(CollectionScanState &state, const vector &column_ids, DataChunk &result) { state.Scan(transaction, result); } @@ -372,44 +353,19 @@ void LocalStorage::InitializeAppend(LocalAppendState &state, DataTable &table) { state.storage->row_groups->InitializeAppend(TransactionData(transaction), state.append_state); } -void LocalStorage::InitializeStorage(LocalAppendState &state, DataTable &table) { - table.InitializeIndexes(context); - state.storage = &table_manager.GetOrCreateStorage(context, table); -} - -void LocalTableStorage::AppendToDeleteIndexes(Vector &row_ids, DataChunk &delete_chunk) { - if (delete_chunk.size() == 0) { - return; - } - - delete_indexes.ScanBound([&](ART &art) { - if (!art.IsUnique()) { - return false; - } - auto result = art.Cast().Append(delete_chunk, row_ids); - if (result.HasError()) { - throw InternalException("unexpected constraint violation on delete ART: ", result.Message()); - } - return false; - }); -} - void LocalStorage::Append(LocalAppendState &state, DataChunk &chunk) { - // Append to any unique indexes. + // append to unique indices (if any) auto storage = state.storage; - auto offset = NumericCast(MAX_ROW_ID) + storage->row_groups->GetTotalRows(); - idx_t base_id = offset + state.append_state.total_append_count; - - auto error = DataTable::AppendToIndexes(storage->append_indexes, storage->delete_indexes, chunk, - NumericCast(base_id)); + idx_t base_id = + NumericCast(MAX_ROW_ID) + storage->row_groups->GetTotalRows() + state.append_state.total_append_count; + auto error = DataTable::AppendToIndexes(storage->indexes, chunk, NumericCast(base_id)); if (error.HasError()) { error.Throw(); } - // Append the chunk to the local storage. + //! Append the chunk to the local storage auto new_row_group = storage->row_groups->Append(chunk, state.append_state); - - // Check if we should pre-emptively flush blocks to disk. + //! Check if we should pre-emptively flush blocks to disk if (new_row_group) { storage->WriteNewRowGroup(); } @@ -421,11 +377,10 @@ void LocalStorage::FinalizeAppend(LocalAppendState &state) { void LocalStorage::LocalMerge(DataTable &table, RowGroupCollection &collection) { auto &storage = table_manager.GetOrCreateStorage(context, table); - if (!storage.append_indexes.Empty()) { + if (!storage.indexes.Empty()) { // append data to indexes if required row_t base_id = MAX_ROW_ID + NumericCast(storage.row_groups->GetTotalRows()); - auto error = - storage.AppendToIndexes(transaction, collection, storage.append_indexes, table.GetTypes(), base_id); + auto error = storage.AppendToIndexes(transaction, collection, storage.indexes, table.GetTypes(), base_id); if (error.HasError()) { error.Throw(); } @@ -461,8 +416,8 @@ idx_t LocalStorage::Delete(DataTable &table, Vector &row_ids, idx_t count) { D_ASSERT(storage); // delete from unique indices (if any) - if (!storage->append_indexes.Empty()) { - storage->row_groups->RemoveFromIndexes(storage->append_indexes, row_ids, count); + if (!storage->indexes.Empty()) { + storage->row_groups->RemoveFromIndexes(storage->indexes, row_ids, count); } auto ids = FlatVector::GetData(row_ids); @@ -491,14 +446,13 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ return; } idx_t append_count = storage.row_groups->GetTotalRows() - storage.deleted_rows; - table.InitializeIndexes(context); - const idx_t row_group_size = storage.row_groups->GetRowGroupSize(); + table.InitializeIndexes(context); TableAppendState append_state; table.AppendLock(append_state); transaction.PushAppend(table, NumericCast(append_state.row_start), append_count); - if ((append_state.row_start == 0 || storage.row_groups->GetTotalRows() >= row_group_size) && + if ((append_state.row_start == 0 || storage.row_groups->GetTotalRows() >= MERGE_THRESHOLD) && storage.deleted_rows == 0) { // table is currently empty OR we are bulk appending: move over the storage directly // first flush any outstanding blocks @@ -507,17 +461,17 @@ void LocalStorage::Flush(DataTable &table, LocalTableStorage &storage, optional_ // FIXME: we should be able to merge the transaction-local index directly into the main table index // as long we just rewrite some row-ids if (table.HasIndexes()) { - storage.AppendToIndexes(transaction, append_state, false); + storage.AppendToIndexes(transaction, append_state, append_count, false); } // finally move over the row groups - table.MergeStorage(*storage.row_groups, storage.append_indexes, commit_state); + table.MergeStorage(*storage.row_groups, storage.indexes, commit_state); } else { // check if we have written data // if we have, we cannot merge to disk after all // so we need to revert the data we have already written storage.Rollback(); // append to the indexes and append to the base table - storage.AppendToIndexes(transaction, append_state, true); + storage.AppendToIndexes(transaction, append_state, append_count, true); } // possibly vacuum any excess index data @@ -560,14 +514,6 @@ idx_t LocalStorage::AddedRows(DataTable &table) { return storage->row_groups->GetTotalRows() - storage->deleted_rows; } -vector LocalStorage::GetPartitionStats(DataTable &table) const { - auto storage = table_manager.GetStorage(table); - if (!storage) { - return vector(); - } - return storage->row_groups->GetPartitionStats(); -} - void LocalStorage::DropTable(DataTable &table) { auto storage = table_manager.GetStorage(table); if (!storage) { @@ -609,7 +555,7 @@ void LocalStorage::DropColumn(DataTable &old_dt, DataTable &new_dt, idx_t remove } void LocalStorage::ChangeType(DataTable &old_dt, DataTable &new_dt, idx_t changed_idx, const LogicalType &target_type, - const vector &bound_columns, Expression &cast_expr) { + const vector &bound_columns, Expression &cast_expr) { // check if there are any pending appends for the old version of the table auto storage = table_manager.MoveEntry(old_dt); if (!storage) { @@ -620,7 +566,7 @@ void LocalStorage::ChangeType(DataTable &old_dt, DataTable &new_dt, idx_t change table_manager.InsertEntry(new_dt, std::move(new_storage)); } -void LocalStorage::FetchChunk(DataTable &table, Vector &row_ids, idx_t count, const vector &col_ids, +void LocalStorage::FetchChunk(DataTable &table, Vector &row_ids, idx_t count, const vector &col_ids, DataChunk &chunk, ColumnFetchState &fetch_state) { auto storage = table_manager.GetStorage(table); if (!storage) { @@ -635,11 +581,7 @@ TableIndexList &LocalStorage::GetIndexes(DataTable &table) { if (!storage) { throw InternalException("LocalStorage::GetIndexes - local storage not found"); } - return storage->append_indexes; -} - -optional_ptr LocalStorage::GetStorage(DataTable &table) { - return table_manager.GetStorage(table); + return storage->indexes; } void LocalStorage::VerifyNewConstraint(DataTable &parent, const BoundConstraint &constraint) { diff --git a/src/duckdb/src/storage/metadata/metadata_manager.cpp b/src/duckdb/src/storage/metadata/metadata_manager.cpp index 04987e653..79e5bbd98 100644 --- a/src/duckdb/src/storage/metadata/metadata_manager.cpp +++ b/src/duckdb/src/storage/metadata/metadata_manager.cpp @@ -185,7 +185,7 @@ void MetadataManager::Flush() { D_ASSERT(kv.first == block.block_id); if (block.block->BlockId() >= MAXIMUM_BLOCK) { // temporary block - convert to persistent - block.block = block_manager.ConvertToPersistent(kv.first, std::move(block.block), std::move(handle)); + block.block = block_manager.ConvertToPersistent(kv.first, std::move(block.block)); } else { // already a persistent block - only need to write it D_ASSERT(block.block->BlockId() == block.block_id); diff --git a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp index 9288cec21..d8a4d83b5 100644 --- a/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp +++ b/src/duckdb/src/storage/serialization/serialize_logical_operator.cpp @@ -330,14 +330,12 @@ void LogicalCreateIndex::Serialize(Serializer &serializer) const { LogicalOperator::Serialize(serializer); serializer.WritePropertyWithDefault>(200, "info", info); serializer.WritePropertyWithDefault>>(201, "unbound_expressions", unbound_expressions); - serializer.WritePropertyWithDefault>(202, "alter_table_info", alter_table_info); } unique_ptr LogicalCreateIndex::Deserialize(Deserializer &deserializer) { auto info = deserializer.ReadPropertyWithDefault>(200, "info"); auto unbound_expressions = deserializer.ReadPropertyWithDefault>>(201, "unbound_expressions"); - auto alter_table_info = deserializer.ReadPropertyWithDefault>(202, "alter_table_info"); - auto result = duckdb::unique_ptr(new LogicalCreateIndex(deserializer.Get(), std::move(info), std::move(unbound_expressions), std::move(alter_table_info))); + auto result = duckdb::unique_ptr(new LogicalCreateIndex(deserializer.Get(), std::move(info), std::move(unbound_expressions))); return std::move(result); } @@ -508,7 +506,6 @@ void LogicalInsert::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(215, "columns_to_fetch", columns_to_fetch); serializer.WritePropertyWithDefault>(216, "source_columns", source_columns); serializer.WritePropertyWithDefault>>(217, "expressions", expressions); - serializer.WritePropertyWithDefault(218, "update_is_del_and_insert", update_is_del_and_insert, false); } unique_ptr LogicalInsert::Deserialize(Deserializer &deserializer) { @@ -531,7 +528,6 @@ unique_ptr LogicalInsert::Deserialize(Deserializer &deserialize deserializer.ReadPropertyWithDefault>(215, "columns_to_fetch", result->columns_to_fetch); deserializer.ReadPropertyWithDefault>(216, "source_columns", result->source_columns); deserializer.ReadPropertyWithDefault>>(217, "expressions", result->expressions); - deserializer.ReadPropertyWithExplicitDefault(218, "update_is_del_and_insert", result->update_is_del_and_insert, false); return std::move(result); } @@ -566,13 +562,13 @@ unique_ptr LogicalMaterializedCTE::Deserialize(Deserializer &de void LogicalOrder::Serialize(Serializer &serializer) const { LogicalOperator::Serialize(serializer); serializer.WritePropertyWithDefault>(200, "orders", orders); - serializer.WritePropertyWithDefault>(201, "projections", projection_map); + serializer.WritePropertyWithDefault>(201, "projections", projections); } unique_ptr LogicalOrder::Deserialize(Deserializer &deserializer) { auto orders = deserializer.ReadPropertyWithDefault>(200, "orders"); auto result = duckdb::unique_ptr(new LogicalOrder(std::move(orders))); - deserializer.ReadPropertyWithDefault>(201, "projections", result->projection_map); + deserializer.ReadPropertyWithDefault>(201, "projections", result->projections); return std::move(result); } diff --git a/src/duckdb/src/storage/serialization/serialize_nodes.cpp b/src/duckdb/src/storage/serialization/serialize_nodes.cpp index 6c0bc4ab1..7e6f7174a 100644 --- a/src/duckdb/src/storage/serialization/serialize_nodes.cpp +++ b/src/duckdb/src/storage/serialization/serialize_nodes.cpp @@ -32,9 +32,7 @@ #include "duckdb/function/scalar/strftime_format.hpp" #include "duckdb/function/table/read_csv.hpp" #include "duckdb/common/types/interval.hpp" -#include "duckdb/parser/qualified_name.hpp" #include "duckdb/parser/parsed_data/exported_table_data.hpp" -#include "duckdb/common/column_index.hpp" namespace duckdb { @@ -174,7 +172,7 @@ void CSVReaderOptions::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(102, "null_str", null_str); serializer.WriteProperty(103, "compression", compression); serializer.WritePropertyWithDefault(104, "allow_quoted_nulls", allow_quoted_nulls); - serializer.WriteProperty>(105, "maximum_line_size", maximum_line_size); + serializer.WritePropertyWithDefault(105, "maximum_line_size", maximum_line_size); serializer.WritePropertyWithDefault(106, "normalize_names", normalize_names); serializer.WritePropertyWithDefault>(107, "force_not_null", force_not_null); serializer.WritePropertyWithDefault(108, "all_varchar", all_varchar); @@ -183,21 +181,21 @@ void CSVReaderOptions::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(111, "file_path", file_path); serializer.WritePropertyWithDefault(112, "decimal_separator", decimal_separator); serializer.WritePropertyWithDefault(113, "null_padding", null_padding); - /* [Deleted] (idx_t) "buffer_size" */ + serializer.WritePropertyWithDefault(114, "buffer_size", buffer_size); serializer.WriteProperty(115, "file_options", file_options); serializer.WritePropertyWithDefault>(116, "force_quote", force_quote); serializer.WritePropertyWithDefault(117, "rejects_table_name", rejects_table_name, "reject_errors"); serializer.WritePropertyWithDefault(118, "rejects_limit", rejects_limit); /* [Deleted] (vector) "rejects_recovery_columns" */ /* [Deleted] (vector) "rejects_recovery_column_ids" */ - serializer.WriteProperty>(121, "delimiter", GetSingleByteDelimiter()); - serializer.WriteProperty>(122, "quote", dialect_options.state_machine_options.quote); - serializer.WriteProperty>(123, "escape", dialect_options.state_machine_options.escape); - serializer.WriteProperty>(124, "header", dialect_options.header); - serializer.WritePropertyWithDefault(125, "num_cols", dialect_options.num_cols); - serializer.WriteProperty>(126, "new_line", dialect_options.state_machine_options.new_line); - serializer.WriteProperty>(127, "skip_rows", dialect_options.skip_rows); - serializer.WriteProperty>>(128, "date_format", dialect_options.date_format); + serializer.WriteProperty>(121, "dialect_options.state_machine_options.delimiter", dialect_options.state_machine_options.delimiter); + serializer.WriteProperty>(122, "dialect_options.state_machine_options.quote", dialect_options.state_machine_options.quote); + serializer.WriteProperty>(123, "dialect_options.state_machine_options.escape", dialect_options.state_machine_options.escape); + serializer.WriteProperty>(124, "dialect_options.header", dialect_options.header); + serializer.WritePropertyWithDefault(125, "dialect_options.num_cols", dialect_options.num_cols); + serializer.WriteProperty>(126, "dialect_options.state_machine_options.new_line", dialect_options.state_machine_options.new_line); + serializer.WriteProperty>(127, "dialect_options.skip_rows", dialect_options.skip_rows); + serializer.WriteProperty>>(128, "dialect_options.date_format", dialect_options.date_format); serializer.WritePropertyWithDefault(129, "sniffer_user_mismatch_error", sniffer_user_mismatch_error); serializer.WritePropertyWithDefault(130, "parallel", parallel); serializer.WritePropertyWithDefault>(131, "was_type_manually_set", was_type_manually_set); @@ -206,98 +204,51 @@ void CSVReaderOptions::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(134, "sql_type_list", sql_type_list); serializer.WritePropertyWithDefault>(135, "sql_types_per_column", sql_types_per_column); serializer.WritePropertyWithDefault(136, "columns_set", columns_set, false); - serializer.WritePropertyWithDefault>(137, "comment", dialect_options.state_machine_options.comment, CSVOption('\0')); - serializer.WritePropertyWithDefault(138, "rows_until_header", dialect_options.rows_until_header); - serializer.WritePropertyWithDefault(139, "encoding", encoding); - serializer.WriteProperty>(140, "rfc_4180", dialect_options.state_machine_options.rfc_4180); - serializer.WriteProperty>(141, "multi_byte_delimiter", GetMultiByteDelimiter()); - serializer.WritePropertyWithDefault(142, "multi_file_reader", multi_file_reader); - serializer.WriteProperty>(143, "buffer_size_option", buffer_size_option); + serializer.WritePropertyWithDefault>(137, "dialect_options.state_machine_options.comment", dialect_options.state_machine_options.comment, CSVOption('\0')); + serializer.WritePropertyWithDefault(138, "dialect_options.rows_until_header", dialect_options.rows_until_header); } CSVReaderOptions CSVReaderOptions::Deserialize(Deserializer &deserializer) { - auto ignore_errors = deserializer.ReadPropertyWithExplicitDefault(100, "ignore_errors", false); - auto buffer_sample_size = deserializer.ReadPropertyWithDefault(101, "buffer_sample_size"); - auto null_str = deserializer.ReadPropertyWithDefault>(102, "null_str"); - auto compression = deserializer.ReadProperty(103, "compression"); - auto allow_quoted_nulls = deserializer.ReadPropertyWithDefault(104, "allow_quoted_nulls"); - auto maximum_line_size = deserializer.ReadProperty>(105, "maximum_line_size"); - auto normalize_names = deserializer.ReadPropertyWithDefault(106, "normalize_names"); - auto force_not_null = deserializer.ReadPropertyWithDefault>(107, "force_not_null"); - auto all_varchar = deserializer.ReadPropertyWithDefault(108, "all_varchar"); - auto sample_size_chunks = deserializer.ReadPropertyWithDefault(109, "sample_size_chunks"); - auto auto_detect = deserializer.ReadPropertyWithDefault(110, "auto_detect"); - auto file_path = deserializer.ReadPropertyWithDefault(111, "file_path"); - auto decimal_separator = deserializer.ReadPropertyWithDefault(112, "decimal_separator"); - auto null_padding = deserializer.ReadPropertyWithDefault(113, "null_padding"); - deserializer.ReadDeletedProperty(114, "buffer_size"); - auto file_options = deserializer.ReadProperty(115, "file_options"); - auto force_quote = deserializer.ReadPropertyWithDefault>(116, "force_quote"); - auto rejects_table_name = deserializer.ReadPropertyWithExplicitDefault(117, "rejects_table_name", "reject_errors"); - auto rejects_limit = deserializer.ReadPropertyWithDefault(118, "rejects_limit"); + CSVReaderOptions result; + deserializer.ReadPropertyWithExplicitDefault(100, "ignore_errors", result.ignore_errors, false); + deserializer.ReadPropertyWithDefault(101, "buffer_sample_size", result.buffer_sample_size); + deserializer.ReadPropertyWithDefault>(102, "null_str", result.null_str); + deserializer.ReadProperty(103, "compression", result.compression); + deserializer.ReadPropertyWithDefault(104, "allow_quoted_nulls", result.allow_quoted_nulls); + deserializer.ReadPropertyWithDefault(105, "maximum_line_size", result.maximum_line_size); + deserializer.ReadPropertyWithDefault(106, "normalize_names", result.normalize_names); + deserializer.ReadPropertyWithDefault>(107, "force_not_null", result.force_not_null); + deserializer.ReadPropertyWithDefault(108, "all_varchar", result.all_varchar); + deserializer.ReadPropertyWithDefault(109, "sample_size_chunks", result.sample_size_chunks); + deserializer.ReadPropertyWithDefault(110, "auto_detect", result.auto_detect); + deserializer.ReadPropertyWithDefault(111, "file_path", result.file_path); + deserializer.ReadPropertyWithDefault(112, "decimal_separator", result.decimal_separator); + deserializer.ReadPropertyWithDefault(113, "null_padding", result.null_padding); + deserializer.ReadPropertyWithDefault(114, "buffer_size", result.buffer_size); + deserializer.ReadProperty(115, "file_options", result.file_options); + deserializer.ReadPropertyWithDefault>(116, "force_quote", result.force_quote); + deserializer.ReadPropertyWithExplicitDefault(117, "rejects_table_name", result.rejects_table_name, "reject_errors"); + deserializer.ReadPropertyWithDefault(118, "rejects_limit", result.rejects_limit); deserializer.ReadDeletedProperty>(119, "rejects_recovery_columns"); deserializer.ReadDeletedProperty>(120, "rejects_recovery_column_ids"); - auto dialect_options_state_machine_options_delimiter = deserializer.ReadProperty>(121, "delimiter"); - auto dialect_options_state_machine_options_quote = deserializer.ReadProperty>(122, "quote"); - auto dialect_options_state_machine_options_escape = deserializer.ReadProperty>(123, "escape"); - auto dialect_options_header = deserializer.ReadProperty>(124, "header"); - auto dialect_options_num_cols = deserializer.ReadPropertyWithDefault(125, "num_cols"); - auto dialect_options_state_machine_options_new_line = deserializer.ReadProperty>(126, "new_line"); - auto dialect_options_skip_rows = deserializer.ReadProperty>(127, "skip_rows"); - auto dialect_options_date_format = deserializer.ReadProperty>>(128, "date_format"); - auto sniffer_user_mismatch_error = deserializer.ReadPropertyWithDefault(129, "sniffer_user_mismatch_error"); - auto parallel = deserializer.ReadPropertyWithDefault(130, "parallel"); - auto was_type_manually_set = deserializer.ReadPropertyWithDefault>(131, "was_type_manually_set"); - auto rejects_scan_name = deserializer.ReadPropertyWithExplicitDefault>(132, "rejects_scan_name", {"reject_scans"}); - auto name_list = deserializer.ReadPropertyWithDefault>(133, "name_list"); - auto sql_type_list = deserializer.ReadPropertyWithDefault>(134, "sql_type_list"); - auto sql_types_per_column = deserializer.ReadPropertyWithDefault>(135, "sql_types_per_column"); - auto columns_set = deserializer.ReadPropertyWithExplicitDefault(136, "columns_set", false); - auto dialect_options_state_machine_options_comment = deserializer.ReadPropertyWithExplicitDefault>(137, "comment", CSVOption('\0')); - auto dialect_options_rows_until_header = deserializer.ReadPropertyWithDefault(138, "rows_until_header"); - auto encoding = deserializer.ReadPropertyWithDefault(139, "encoding"); - auto dialect_options_state_machine_options_rfc_4180 = deserializer.ReadProperty>(140, "rfc_4180"); - auto multi_byte_delimiter = deserializer.ReadProperty>(141, "multi_byte_delimiter"); - CSVReaderOptions result(dialect_options_state_machine_options_delimiter, multi_byte_delimiter); - result.ignore_errors = ignore_errors; - result.buffer_sample_size = buffer_sample_size; - result.null_str = std::move(null_str); - result.compression = compression; - result.allow_quoted_nulls = allow_quoted_nulls; - result.maximum_line_size = maximum_line_size; - result.normalize_names = normalize_names; - result.force_not_null = std::move(force_not_null); - result.all_varchar = all_varchar; - result.sample_size_chunks = sample_size_chunks; - result.auto_detect = auto_detect; - result.file_path = std::move(file_path); - result.decimal_separator = std::move(decimal_separator); - result.null_padding = null_padding; - result.file_options = file_options; - result.force_quote = std::move(force_quote); - result.rejects_table_name = std::move(rejects_table_name); - result.rejects_limit = rejects_limit; - result.dialect_options.state_machine_options.quote = dialect_options_state_machine_options_quote; - result.dialect_options.state_machine_options.escape = dialect_options_state_machine_options_escape; - result.dialect_options.header = dialect_options_header; - result.dialect_options.num_cols = dialect_options_num_cols; - result.dialect_options.state_machine_options.new_line = dialect_options_state_machine_options_new_line; - result.dialect_options.skip_rows = dialect_options_skip_rows; - result.dialect_options.date_format = dialect_options_date_format; - result.sniffer_user_mismatch_error = std::move(sniffer_user_mismatch_error); - result.parallel = parallel; - result.was_type_manually_set = std::move(was_type_manually_set); - result.rejects_scan_name = rejects_scan_name; - result.name_list = std::move(name_list); - result.sql_type_list = std::move(sql_type_list); - result.sql_types_per_column = std::move(sql_types_per_column); - result.columns_set = columns_set; - result.dialect_options.state_machine_options.comment = dialect_options_state_machine_options_comment; - result.dialect_options.rows_until_header = dialect_options_rows_until_header; - result.encoding = std::move(encoding); - result.dialect_options.state_machine_options.rfc_4180 = dialect_options_state_machine_options_rfc_4180; - deserializer.ReadPropertyWithDefault(142, "multi_file_reader", result.multi_file_reader); - deserializer.ReadProperty>(143, "buffer_size_option", result.buffer_size_option); + deserializer.ReadProperty>(121, "dialect_options.state_machine_options.delimiter", result.dialect_options.state_machine_options.delimiter); + deserializer.ReadProperty>(122, "dialect_options.state_machine_options.quote", result.dialect_options.state_machine_options.quote); + deserializer.ReadProperty>(123, "dialect_options.state_machine_options.escape", result.dialect_options.state_machine_options.escape); + deserializer.ReadProperty>(124, "dialect_options.header", result.dialect_options.header); + deserializer.ReadPropertyWithDefault(125, "dialect_options.num_cols", result.dialect_options.num_cols); + deserializer.ReadProperty>(126, "dialect_options.state_machine_options.new_line", result.dialect_options.state_machine_options.new_line); + deserializer.ReadProperty>(127, "dialect_options.skip_rows", result.dialect_options.skip_rows); + deserializer.ReadProperty>>(128, "dialect_options.date_format", result.dialect_options.date_format); + deserializer.ReadPropertyWithDefault(129, "sniffer_user_mismatch_error", result.sniffer_user_mismatch_error); + deserializer.ReadPropertyWithDefault(130, "parallel", result.parallel); + deserializer.ReadPropertyWithDefault>(131, "was_type_manually_set", result.was_type_manually_set); + deserializer.ReadPropertyWithExplicitDefault>(132, "rejects_scan_name", result.rejects_scan_name, {"reject_scans"}); + deserializer.ReadPropertyWithDefault>(133, "name_list", result.name_list); + deserializer.ReadPropertyWithDefault>(134, "sql_type_list", result.sql_type_list); + deserializer.ReadPropertyWithDefault>(135, "sql_types_per_column", result.sql_types_per_column); + deserializer.ReadPropertyWithExplicitDefault(136, "columns_set", result.columns_set, false); + deserializer.ReadPropertyWithExplicitDefault>(137, "dialect_options.state_machine_options.comment", result.dialect_options.state_machine_options.comment, CSVOption('\0')); + deserializer.ReadPropertyWithDefault(138, "dialect_options.rows_until_header", result.dialect_options.rows_until_header); return result; } @@ -347,18 +298,6 @@ ColumnDefinition ColumnDefinition::Deserialize(Deserializer &deserializer) { return result; } -void ColumnIndex::Serialize(Serializer &serializer) const { - serializer.WritePropertyWithDefault(1, "index", index); - serializer.WritePropertyWithDefault>(2, "child_indexes", child_indexes); -} - -ColumnIndex ColumnIndex::Deserialize(Deserializer &deserializer) { - ColumnIndex result; - deserializer.ReadPropertyWithDefault(1, "index", result.index); - deserializer.ReadPropertyWithDefault>(2, "child_indexes", result.child_indexes); - return result; -} - void ColumnInfo::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(100, "names", names); serializer.WritePropertyWithDefault>(101, "types", types); @@ -549,22 +488,6 @@ PivotColumnEntry PivotColumnEntry::Deserialize(Deserializer &deserializer) { return result; } -void QualifiedColumnName::Serialize(Serializer &serializer) const { - serializer.WritePropertyWithDefault(100, "catalog", catalog); - serializer.WritePropertyWithDefault(101, "schema", schema); - serializer.WritePropertyWithDefault(102, "table", table); - serializer.WritePropertyWithDefault(103, "column", column); -} - -QualifiedColumnName QualifiedColumnName::Deserialize(Deserializer &deserializer) { - QualifiedColumnName result; - deserializer.ReadPropertyWithDefault(100, "catalog", result.catalog); - deserializer.ReadPropertyWithDefault(101, "schema", result.schema); - deserializer.ReadPropertyWithDefault(102, "table", result.table); - deserializer.ReadPropertyWithDefault(103, "column", result.column); - return result; -} - void ReadCSVData::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(100, "files", files); serializer.WritePropertyWithDefault>(101, "csv_types", csv_types); @@ -599,8 +522,8 @@ void ReservoirSample::Serialize(Serializer &serializer) const { unique_ptr ReservoirSample::Deserialize(Deserializer &deserializer) { auto sample_count = deserializer.ReadPropertyWithDefault(200, "sample_count"); - auto reservoir_chunk = deserializer.ReadPropertyWithDefault>(201, "reservoir_chunk"); - auto result = duckdb::unique_ptr(new ReservoirSample(sample_count, std::move(reservoir_chunk))); + auto result = duckdb::unique_ptr(new ReservoirSample(sample_count)); + deserializer.ReadPropertyWithDefault>(201, "reservoir_chunk", result->reservoir_chunk); return std::move(result); } @@ -621,18 +544,15 @@ void SampleOptions::Serialize(Serializer &serializer) const { serializer.WriteProperty(100, "sample_size", sample_size); serializer.WritePropertyWithDefault(101, "is_percentage", is_percentage); serializer.WriteProperty(102, "method", method); - serializer.WritePropertyWithDefault(103, "seed", GetSeed()); + serializer.WritePropertyWithDefault(103, "seed", seed); } unique_ptr SampleOptions::Deserialize(Deserializer &deserializer) { - auto sample_size = deserializer.ReadProperty(100, "sample_size"); - auto is_percentage = deserializer.ReadPropertyWithDefault(101, "is_percentage"); - auto method = deserializer.ReadProperty(102, "method"); - auto seed = deserializer.ReadPropertyWithDefault(103, "seed"); - auto result = duckdb::unique_ptr(new SampleOptions(seed)); - result->sample_size = sample_size; - result->is_percentage = is_percentage; - result->method = method; + auto result = duckdb::unique_ptr(new SampleOptions()); + deserializer.ReadProperty(100, "sample_size", result->sample_size); + deserializer.ReadPropertyWithDefault(101, "is_percentage", result->is_percentage); + deserializer.ReadProperty(102, "method", result->method); + deserializer.ReadPropertyWithDefault(103, "seed", result->seed); return result; } diff --git a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp index ccf98a0ce..e68acf36b 100644 --- a/src/duckdb/src/storage/serialization/serialize_parse_info.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parse_info.cpp @@ -130,9 +130,6 @@ unique_ptr AlterTableInfo::Deserialize(Deserializer &deserializer) { case AlterTableType::ADD_COLUMN: result = AddColumnInfo::Deserialize(deserializer); break; - case AlterTableType::ADD_CONSTRAINT: - result = AddConstraintInfo::Deserialize(deserializer); - break; case AlterTableType::ALTER_COLUMN_TYPE: result = ChangeColumnTypeInfo::Deserialize(deserializer); break; @@ -194,17 +191,6 @@ unique_ptr AddColumnInfo::Deserialize(Deserializer &deserializer return std::move(result); } -void AddConstraintInfo::Serialize(Serializer &serializer) const { - AlterTableInfo::Serialize(serializer); - serializer.WritePropertyWithDefault>(400, "constraint", constraint); -} - -unique_ptr AddConstraintInfo::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new AddConstraintInfo()); - deserializer.ReadPropertyWithDefault>(400, "constraint", result->constraint); - return std::move(result); -} - void AlterForeignKeyInfo::Serialize(Serializer &serializer) const { AlterTableInfo::Serialize(serializer); serializer.WritePropertyWithDefault(400, "fk_table", fk_table); diff --git a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp index a5c79b3d9..146aa7feb 100644 --- a/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +++ b/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp @@ -288,30 +288,21 @@ unique_ptr PositionalReferenceExpression::Deserialize(Deserial void StarExpression::Serialize(Serializer &serializer) const { ParsedExpression::Serialize(serializer); serializer.WritePropertyWithDefault(200, "relation_name", relation_name); - serializer.WriteProperty(201, "exclude_list", SerializedExcludeList()); + serializer.WriteProperty(201, "exclude_list", exclude_list); serializer.WritePropertyWithDefault>>(202, "replace_list", replace_list); serializer.WritePropertyWithDefault(203, "columns", columns); serializer.WritePropertyWithDefault>(204, "expr", expr); serializer.WritePropertyWithDefault(205, "unpacked", unpacked, false); - serializer.WritePropertyWithDefault(206, "qualified_exclude_list", SerializedQualifiedExcludeList(), qualified_column_set_t()); - serializer.WritePropertyWithDefault>(207, "rename_list", rename_list, qualified_column_map_t()); } unique_ptr StarExpression::Deserialize(Deserializer &deserializer) { - auto relation_name = deserializer.ReadPropertyWithDefault(200, "relation_name"); - auto exclude_list = deserializer.ReadProperty(201, "exclude_list"); - auto replace_list = deserializer.ReadPropertyWithDefault>>(202, "replace_list"); - auto columns = deserializer.ReadPropertyWithDefault(203, "columns"); - auto expr = deserializer.ReadPropertyWithDefault>(204, "expr"); - auto unpacked = deserializer.ReadPropertyWithExplicitDefault(205, "unpacked", false); - auto qualified_exclude_list = deserializer.ReadPropertyWithExplicitDefault(206, "qualified_exclude_list", qualified_column_set_t()); - auto result = duckdb::unique_ptr(new StarExpression(exclude_list, qualified_exclude_list)); - result->relation_name = std::move(relation_name); - result->replace_list = std::move(replace_list); - result->columns = columns; - result->expr = std::move(expr); - result->unpacked = unpacked; - deserializer.ReadPropertyWithExplicitDefault>(207, "rename_list", result->rename_list, qualified_column_map_t()); + auto result = duckdb::unique_ptr(new StarExpression()); + deserializer.ReadPropertyWithDefault(200, "relation_name", result->relation_name); + deserializer.ReadProperty(201, "exclude_list", result->exclude_list); + deserializer.ReadPropertyWithDefault>>(202, "replace_list", result->replace_list); + deserializer.ReadPropertyWithDefault(203, "columns", result->columns); + deserializer.ReadPropertyWithDefault>(204, "expr", result->expr); + deserializer.ReadPropertyWithExplicitDefault(205, "unpacked", result->unpacked, false); return std::move(result); } @@ -350,7 +341,6 @@ void WindowExpression::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(213, "filter_expr", filter_expr); serializer.WritePropertyWithDefault(214, "exclude_clause", exclude_clause, WindowExcludeMode::NO_OTHER); serializer.WritePropertyWithDefault(215, "distinct", distinct); - serializer.WritePropertyWithDefault>(216, "arg_orders", arg_orders); } unique_ptr WindowExpression::Deserialize(Deserializer &deserializer) { @@ -371,7 +361,6 @@ unique_ptr WindowExpression::Deserialize(Deserializer &deseria deserializer.ReadPropertyWithDefault>(213, "filter_expr", result->filter_expr); deserializer.ReadPropertyWithExplicitDefault(214, "exclude_clause", result->exclude_clause, WindowExcludeMode::NO_OTHER); deserializer.ReadPropertyWithDefault(215, "distinct", result->distinct); - deserializer.ReadPropertyWithDefault>(216, "arg_orders", result->arg_orders); return std::move(result); } diff --git a/src/duckdb/src/storage/serialization/serialize_statement.cpp b/src/duckdb/src/storage/serialization/serialize_statement.cpp index 9c61db6e3..235ffd1e8 100644 --- a/src/duckdb/src/storage/serialization/serialize_statement.cpp +++ b/src/duckdb/src/storage/serialization/serialize_statement.cpp @@ -11,13 +11,11 @@ namespace duckdb { void SelectStatement::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault>(100, "node", node); - serializer.WritePropertyWithDefault>(101, "named_param_map", named_param_map); } unique_ptr SelectStatement::Deserialize(Deserializer &deserializer) { auto result = duckdb::unique_ptr(new SelectStatement()); deserializer.ReadPropertyWithDefault>(100, "node", result->node); - deserializer.ReadPropertyWithDefault>(101, "named_param_map", result->named_param_map); return result; } diff --git a/src/duckdb/src/storage/serialization/serialize_table_filter.cpp b/src/duckdb/src/storage/serialization/serialize_table_filter.cpp index 24682aecb..550905eef 100644 --- a/src/duckdb/src/storage/serialization/serialize_table_filter.cpp +++ b/src/duckdb/src/storage/serialization/serialize_table_filter.cpp @@ -10,9 +10,6 @@ #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" -#include "duckdb/planner/filter/in_filter.hpp" -#include "duckdb/planner/filter/dynamic_filter.hpp" namespace duckdb { @@ -33,21 +30,12 @@ unique_ptr TableFilter::Deserialize(Deserializer &deserializer) { case TableFilterType::CONSTANT_COMPARISON: result = ConstantFilter::Deserialize(deserializer); break; - case TableFilterType::DYNAMIC_FILTER: - result = DynamicFilter::Deserialize(deserializer); - break; - case TableFilterType::IN_FILTER: - result = InFilter::Deserialize(deserializer); - break; case TableFilterType::IS_NOT_NULL: result = IsNotNullFilter::Deserialize(deserializer); break; case TableFilterType::IS_NULL: result = IsNullFilter::Deserialize(deserializer); break; - case TableFilterType::OPTIONAL_FILTER: - result = OptionalFilter::Deserialize(deserializer); - break; case TableFilterType::STRUCT_EXTRACT: result = StructFilter::Deserialize(deserializer); break; @@ -92,26 +80,6 @@ unique_ptr ConstantFilter::Deserialize(Deserializer &deserializer) return std::move(result); } -void DynamicFilter::Serialize(Serializer &serializer) const { - TableFilter::Serialize(serializer); -} - -unique_ptr DynamicFilter::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new DynamicFilter()); - return std::move(result); -} - -void InFilter::Serialize(Serializer &serializer) const { - TableFilter::Serialize(serializer); - serializer.WritePropertyWithDefault>(200, "values", values); -} - -unique_ptr InFilter::Deserialize(Deserializer &deserializer) { - auto values = deserializer.ReadPropertyWithDefault>(200, "values"); - auto result = duckdb::unique_ptr(new InFilter(std::move(values))); - return std::move(result); -} - void IsNotNullFilter::Serialize(Serializer &serializer) const { TableFilter::Serialize(serializer); } @@ -130,17 +98,6 @@ unique_ptr IsNullFilter::Deserialize(Deserializer &deserializer) { return std::move(result); } -void OptionalFilter::Serialize(Serializer &serializer) const { - TableFilter::Serialize(serializer); - serializer.WritePropertyWithDefault>(200, "child_filter", child_filter); -} - -unique_ptr OptionalFilter::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new OptionalFilter()); - deserializer.ReadPropertyWithDefault>(200, "child_filter", result->child_filter); - return std::move(result); -} - void StructFilter::Serialize(Serializer &serializer) const { TableFilter::Serialize(serializer); serializer.WritePropertyWithDefault(200, "child_idx", child_idx); diff --git a/src/duckdb/src/storage/serialization/serialize_types.cpp b/src/duckdb/src/storage/serialization/serialize_types.cpp index 6f5e811ef..dbbd0d455 100644 --- a/src/duckdb/src/storage/serialization/serialize_types.cpp +++ b/src/duckdb/src/storage/serialization/serialize_types.cpp @@ -5,7 +5,6 @@ #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/common/extension_type_info.hpp" #include "duckdb/common/extra_type_info.hpp" namespace duckdb { @@ -13,15 +12,13 @@ namespace duckdb { void ExtraTypeInfo::Serialize(Serializer &serializer) const { serializer.WriteProperty(100, "type", type); serializer.WritePropertyWithDefault(101, "alias", alias); - /* [Deleted] (vector) "modifiers" */ - serializer.WritePropertyWithDefault>(103, "extension_info", extension_info); + serializer.WritePropertyWithDefault>(102, "modifiers", modifiers, vector()); } shared_ptr ExtraTypeInfo::Deserialize(Deserializer &deserializer) { auto type = deserializer.ReadProperty(100, "type"); auto alias = deserializer.ReadPropertyWithDefault(101, "alias"); - deserializer.ReadDeletedProperty>(102, "modifiers"); - auto extension_info = deserializer.ReadPropertyWithDefault>(103, "extension_info"); + auto modifiers = deserializer.ReadPropertyWithExplicitDefault>(102, "modifiers", vector()); shared_ptr result; switch (type) { case ExtraTypeInfoType::AGGREGATE_STATE_TYPE_INFO: @@ -63,7 +60,7 @@ shared_ptr ExtraTypeInfo::Deserialize(Deserializer &deserializer) throw SerializationException("Unsupported type for deserialization of ExtraTypeInfo!"); } result->alias = std::move(alias); - result->extension_info = std::move(extension_info); + result->modifiers = std::move(modifiers); return result; } @@ -121,18 +118,6 @@ shared_ptr DecimalTypeInfo::Deserialize(Deserializer &deserialize return std::move(result); } -void ExtensionTypeInfo::Serialize(Serializer &serializer) const { - serializer.WritePropertyWithDefault>(100, "modifiers", modifiers); - serializer.WritePropertyWithDefault>(101, "properties", properties, unordered_map()); -} - -unique_ptr ExtensionTypeInfo::Deserialize(Deserializer &deserializer) { - auto result = duckdb::unique_ptr(new ExtensionTypeInfo()); - deserializer.ReadPropertyWithDefault>(100, "modifiers", result->modifiers); - deserializer.ReadPropertyWithExplicitDefault>(101, "properties", result->properties, unordered_map()); - return result; -} - void IntegerLiteralTypeInfo::Serialize(Serializer &serializer) const { ExtraTypeInfo::Serialize(serializer); serializer.WriteProperty(200, "constant_value", constant_value); @@ -155,18 +140,6 @@ shared_ptr ListTypeInfo::Deserialize(Deserializer &deserializer) return std::move(result); } -void LogicalTypeModifier::Serialize(Serializer &serializer) const { - serializer.WriteProperty(100, "value", value); - serializer.WritePropertyWithDefault(101, "label", label); -} - -LogicalTypeModifier LogicalTypeModifier::Deserialize(Deserializer &deserializer) { - auto value = deserializer.ReadProperty(100, "value"); - LogicalTypeModifier result(value); - deserializer.ReadPropertyWithDefault(101, "label", result.label); - return result; -} - void StringTypeInfo::Serialize(Serializer &serializer) const { ExtraTypeInfo::Serialize(serializer); serializer.WritePropertyWithDefault(200, "collation", collation); @@ -194,7 +167,7 @@ void UserTypeInfo::Serialize(Serializer &serializer) const { serializer.WritePropertyWithDefault(200, "user_type_name", user_type_name); serializer.WritePropertyWithDefault(201, "catalog", catalog, string()); serializer.WritePropertyWithDefault(202, "schema", schema, string()); - serializer.WritePropertyWithDefault>(203, "user_type_modifiers", user_type_modifiers); + serializer.WritePropertyWithDefault>(203, "user_type_modifiers", user_type_modifiers, vector()); } shared_ptr UserTypeInfo::Deserialize(Deserializer &deserializer) { @@ -202,7 +175,7 @@ shared_ptr UserTypeInfo::Deserialize(Deserializer &deserializer) deserializer.ReadPropertyWithDefault(200, "user_type_name", result->user_type_name); deserializer.ReadPropertyWithExplicitDefault(201, "catalog", result->catalog, string()); deserializer.ReadPropertyWithExplicitDefault(202, "schema", result->schema, string()); - deserializer.ReadPropertyWithDefault>(203, "user_type_modifiers", result->user_type_modifiers); + deserializer.ReadPropertyWithExplicitDefault>(203, "user_type_modifiers", result->user_type_modifiers, vector()); return std::move(result); } diff --git a/src/duckdb/src/storage/single_file_block_manager.cpp b/src/duckdb/src/storage/single_file_block_manager.cpp index 2b63fa247..20f97ea92 100644 --- a/src/duckdb/src/storage/single_file_block_manager.cpp +++ b/src/duckdb/src/storage/single_file_block_manager.cpp @@ -179,7 +179,7 @@ void SingleFileBlockManager::CreateNewDatabase() { MainHeader main_header; main_header.version_number = VERSION_NUMBER; - memset(main_header.flags, 0, sizeof(uint64_t) * MainHeader::FLAG_COUNT); + memset(main_header.flags, 0, sizeof(uint64_t) * 4); SerializeHeaderStructure(main_header, header_buffer.buffer); // now write the header to the file @@ -265,7 +265,7 @@ void SingleFileBlockManager::ReadAndChecksum(FileBuffer &block, uint64_t locatio // compute the checksum auto stored_checksum = Load(block.InternalBuffer()); - auto computed_checksum = Checksum(block.buffer, block.Size()); + auto computed_checksum = Checksum(block.buffer, block.size); // verify the checksum if (stored_checksum != computed_checksum) { @@ -277,7 +277,7 @@ void SingleFileBlockManager::ReadAndChecksum(FileBuffer &block, uint64_t locatio void SingleFileBlockManager::ChecksumAndWrite(FileBuffer &block, uint64_t location) const { // compute the checksum and write it to the start of the buffer (if not temp buffer) - uint64_t checksum = Checksum(block.buffer, block.Size()); + uint64_t checksum = Checksum(block.buffer, block.size); Store(checksum, block.InternalBuffer()); // now write the buffer block.Write(*handle, location); @@ -672,9 +672,11 @@ void SingleFileBlockManager::WriteHeader(DatabaseHeader header) { throw FatalException("Checkpoint aborted after free list write because of PRAGMA checkpoint_abort flag"); } - // We need to fsync BEFORE we write the header to ensure that all the previous blocks are written as well - handle->Sync(); - + if (!options.use_direct_io) { + // if we are not using Direct IO we need to fsync BEFORE we write the header to ensure that all the previous + // blocks are written as well + handle->Sync(); + } // set the header inside the buffer header_buffer.Clear(); MemoryStream serializer; diff --git a/src/duckdb/src/storage/standard_buffer_manager.cpp b/src/duckdb/src/storage/standard_buffer_manager.cpp index c23ba16e0..da10afce2 100644 --- a/src/duckdb/src/storage/standard_buffer_manager.cpp +++ b/src/duckdb/src/storage/standard_buffer_manager.cpp @@ -15,14 +15,8 @@ namespace duckdb { #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS -static void WriteGarbageIntoBuffer(BlockLock &lock, BlockHandle &block) { - auto &buffer = block.GetBuffer(lock); - memset(buffer->buffer, 0xa5, buffer->size); // 0xa5 is default memory in debug mode -} - -static void WriteGarbageIntoBuffer(BlockHandle &block) { - auto lock = block.GetLock(); - WriteGarbageIntoBuffer(lock, block); +static void WriteGarbageIntoBuffer(FileBuffer &buffer) { + memset(buffer.buffer, 0xa5, buffer.size); // 0xa5 is default memory in debug mode } #endif @@ -36,9 +30,6 @@ struct BufferAllocatorData : PrivateAllocatorData { unique_ptr StandardBufferManager::ConstructManagedBuffer(idx_t size, unique_ptr &&source, FileBufferType type) { unique_ptr result; - if (type == FileBufferType::BLOCK) { - throw InternalException("ConstructManagedBuffer cannot be used to construct blocks"); - } if (source) { auto tmp = std::move(source); D_ASSERT(tmp->AllocSize() == BufferManager::GetAllocSize(size)); @@ -132,26 +123,27 @@ shared_ptr StandardBufferManager::RegisterTransientMemory(const idx // Otherwise, any non-default block size would register as small memory, causing problems when // trying to convert that memory to consistent blocks later on. if (size < block_size) { - return RegisterSmallMemory(MemoryTag::IN_MEMORY_TABLE, size); + return RegisterSmallMemory(size); } auto buffer_handle = Allocate(MemoryTag::IN_MEMORY_TABLE, size, false); return buffer_handle.GetBlockHandle(); } -shared_ptr StandardBufferManager::RegisterSmallMemory(MemoryTag tag, const idx_t size) { +shared_ptr StandardBufferManager::RegisterSmallMemory(const idx_t size) { D_ASSERT(size < GetBlockSize()); - auto reservation = EvictBlocksOrThrow(tag, size, nullptr, "could not allocate block of size %s%s", + auto reservation = EvictBlocksOrThrow(MemoryTag::BASE_TABLE, size, nullptr, "could not allocate block of size %s%s", StringUtil::BytesToHumanReadableString(size)); auto buffer = ConstructManagedBuffer(size, nullptr, FileBufferType::TINY_BUFFER); // Create a new block pointer for this block. - auto result = make_shared_ptr(*temp_block_manager, ++temporary_id, tag, std::move(buffer), - DestroyBufferUpon::BLOCK, size, std::move(reservation)); + auto result = + make_shared_ptr(*temp_block_manager, ++temporary_id, MemoryTag::BASE_TABLE, std::move(buffer), + DestroyBufferUpon::BLOCK, size, std::move(reservation)); #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS // Initialize the memory with garbage data - WriteGarbageIntoBuffer(*result); + WriteGarbageIntoBuffer(*result->buffer); #endif return result; } @@ -176,22 +168,20 @@ BufferHandle StandardBufferManager::Allocate(MemoryTag tag, idx_t block_size, bo #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS // Initialize the memory with garbage data - WriteGarbageIntoBuffer(*block); + WriteGarbageIntoBuffer(*block->buffer); #endif return Pin(block); } void StandardBufferManager::ReAllocate(shared_ptr &handle, idx_t block_size) { D_ASSERT(block_size >= GetBlockSize()); - auto lock = handle->GetLock(); + unique_lock lock(handle->lock); + D_ASSERT(handle->state == BlockState::BLOCK_LOADED); + D_ASSERT(handle->memory_usage == handle->buffer->AllocSize()); + D_ASSERT(handle->memory_usage == handle->memory_charge.size); - auto handle_memory_usage = handle->GetMemoryUsage(); - D_ASSERT(handle->GetState() == BlockState::BLOCK_LOADED); - D_ASSERT(handle_memory_usage == handle->GetBuffer(lock)->AllocSize()); - D_ASSERT(handle_memory_usage == handle->GetMemoryCharge(lock).size); - - auto req = handle->GetBuffer(lock)->CalculateMemory(block_size); - int64_t memory_delta = NumericCast(req.alloc_size) - NumericCast(handle_memory_usage); + auto req = handle->buffer->CalculateMemory(block_size); + int64_t memory_delta = NumericCast(req.alloc_size) - NumericCast(handle->memory_usage); if (memory_delta == 0) { return; @@ -199,20 +189,20 @@ void StandardBufferManager::ReAllocate(shared_ptr &handle, idx_t bl // evict blocks until we have space to resize this block // unlock the handle lock during the call to EvictBlocksOrThrow lock.unlock(); - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), NumericCast(memory_delta), nullptr, + auto reservation = EvictBlocksOrThrow(handle->tag, NumericCast(memory_delta), nullptr, "failed to resize block from %s to %s%s", - StringUtil::BytesToHumanReadableString(handle_memory_usage), + StringUtil::BytesToHumanReadableString(handle->memory_usage), StringUtil::BytesToHumanReadableString(req.alloc_size)); lock.lock(); // EvictBlocks decrements 'current_memory' for us. - handle->MergeMemoryReservation(lock, std::move(reservation)); + handle->memory_charge.Merge(std::move(reservation)); } else { // no need to evict blocks, but we do need to decrement 'current_memory'. - handle->ResizeMemory(lock, req.alloc_size); + handle->memory_charge.Resize(req.alloc_size); } - handle->ResizeBuffer(lock, block_size, memory_delta); + handle->ResizeBuffer(block_size, memory_delta); } void StandardBufferManager::BatchRead(vector> &handles, const map &load_map, @@ -241,25 +231,27 @@ void StandardBufferManager::BatchRead(vector> &handles, auto &handle = handles[entry->second]; // reserve memory for the block - idx_t required_memory = handle->GetMemoryUsage(); + idx_t required_memory = handle->memory_usage; unique_ptr reusable_buffer; - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), required_memory, &reusable_buffer, - "failed to pin block of size %s%s", - StringUtil::BytesToHumanReadableString(required_memory)); + auto reservation = + EvictBlocksOrThrow(handle->tag, required_memory, &reusable_buffer, "failed to pin block of size %s%s", + StringUtil::BytesToHumanReadableString(required_memory)); // now load the block from the buffer // note that we discard the buffer handle - we do not keep it around // the prefetching relies on the block handle being pinned again during the actual read before it is evicted BufferHandle buf; { - auto lock = handle->GetLock(); - if (handle->GetState() == BlockState::BLOCK_LOADED) { + lock_guard lock(handle->lock); + if (handle->state == BlockState::BLOCK_LOADED) { // the block is loaded already by another thread - free up the reservation and continue reservation.Resize(0); continue; } auto block_ptr = intermediate_buffer.GetFileBuffer().InternalBuffer() + block_idx * block_manager.GetBlockAllocSize(); - buf = handle->LoadFromBuffer(lock, block_ptr, std::move(reusable_buffer), std::move(reservation)); + buf = handle->LoadFromBuffer(block_ptr, std::move(reusable_buffer)); + handle->readers = 1; + handle->memory_charge = std::move(reservation); } } } @@ -269,7 +261,8 @@ void StandardBufferManager::Prefetch(vector> &handles) { map to_be_loaded; for (idx_t block_idx = 0; block_idx < handles.size(); block_idx++) { auto &handle = handles[block_idx]; - if (handle->GetState() != BlockState::BLOCK_LOADED) { + lock_guard lock(handle->lock); + if (handle->state != BlockState::BLOCK_LOADED) { // need to load this block - add it to the map to_be_loaded.insert(make_pair(handle->BlockId(), block_idx)); } @@ -312,13 +305,14 @@ BufferHandle StandardBufferManager::Pin(shared_ptr &handle) { idx_t required_memory; { // lock the block - auto lock = handle->GetLock(); + lock_guard lock(handle->lock); // check if the block is already loaded - if (handle->GetState() == BlockState::BLOCK_LOADED) { + if (handle->state == BlockState::BLOCK_LOADED) { // the block is loaded, increment the reader count and set the BufferHandle + handle->readers++; buf = handle->Load(); } - required_memory = handle->GetMemoryUsage(); + required_memory = handle->memory_usage; } if (buf.IsValid()) { @@ -326,30 +320,33 @@ BufferHandle StandardBufferManager::Pin(shared_ptr &handle) { } else { // evict blocks until we have space for the current block unique_ptr reusable_buffer; - auto reservation = EvictBlocksOrThrow(handle->GetMemoryTag(), required_memory, &reusable_buffer, - "failed to pin block of size %s%s", - StringUtil::BytesToHumanReadableString(required_memory)); + auto reservation = + EvictBlocksOrThrow(handle->tag, required_memory, &reusable_buffer, "failed to pin block of size %s%s", + StringUtil::BytesToHumanReadableString(required_memory)); // lock the handle again and repeat the check (in case anybody loaded in the meantime) - auto lock = handle->GetLock(); + lock_guard lock(handle->lock); // check if the block is already loaded - if (handle->GetState() == BlockState::BLOCK_LOADED) { + if (handle->state == BlockState::BLOCK_LOADED) { // the block is loaded, increment the reader count and return a pointer to the handle + handle->readers++; reservation.Resize(0); buf = handle->Load(); } else { // now we can actually load the current block - D_ASSERT(handle->Readers() == 0); + D_ASSERT(handle->readers == 0); buf = handle->Load(std::move(reusable_buffer)); - auto &memory_charge = handle->GetMemoryCharge(lock); - memory_charge = std::move(reservation); + handle->readers = 1; + handle->memory_charge = std::move(reservation); // in the case of a variable sized block, the buffer may be smaller than a full block. - int64_t delta = NumericCast(handle->GetBuffer(lock)->AllocSize()) - - NumericCast(handle->GetMemoryUsage()); + int64_t delta = + NumericCast(handle->buffer->AllocSize()) - NumericCast(handle->memory_usage); if (delta) { - handle->ChangeMemoryUsage(lock, delta); + D_ASSERT(delta < 0); + handle->memory_usage += static_cast(delta); + handle->memory_charge.Resize(handle->memory_usage); } - D_ASSERT(handle->GetMemoryUsage() == handle->GetBuffer(lock)->AllocSize()); + D_ASSERT(handle->memory_usage == handle->buffer->AllocSize()); } } @@ -359,54 +356,46 @@ BufferHandle StandardBufferManager::Pin(shared_ptr &handle) { return buf; } -void StandardBufferManager::PurgeQueue(const BlockHandle &handle) { - buffer_pool.PurgeQueue(handle); +void StandardBufferManager::PurgeQueue(FileBufferType type) { + buffer_pool.PurgeQueue(type); } void StandardBufferManager::AddToEvictionQueue(shared_ptr &handle) { buffer_pool.AddToEvictionQueue(handle); } -void StandardBufferManager::VerifyZeroReaders(BlockLock &lock, shared_ptr &handle) { +void StandardBufferManager::VerifyZeroReaders(shared_ptr &handle) { #ifdef DUCKDB_DEBUG_DESTROY_BLOCKS - unique_ptr replacement_buffer; - auto &allocator = Allocator::Get(db); - auto alloc_size = handle->GetMemoryUsage() - Storage::DEFAULT_BLOCK_HEADER_SIZE; - auto &buffer = handle->GetBuffer(lock); - if (handle->GetBufferType() == FileBufferType::BLOCK) { - auto block = reinterpret_cast(buffer.get()); - replacement_buffer = make_uniq(allocator, block->id, alloc_size); - } else { - replacement_buffer = make_uniq(allocator, buffer->GetBufferType(), alloc_size); - } - memcpy(replacement_buffer->buffer, buffer->buffer, buffer->size); - WriteGarbageIntoBuffer(lock, *handle); - buffer = std::move(replacement_buffer); + auto replacement_buffer = make_uniq(Allocator::Get(db), handle->buffer->type, + handle->memory_usage - Storage::DEFAULT_BLOCK_HEADER_SIZE); + memcpy(replacement_buffer->buffer, handle->buffer->buffer, handle->buffer->size); + WriteGarbageIntoBuffer(*handle->buffer); + handle->buffer = std::move(replacement_buffer); #endif } void StandardBufferManager::Unpin(shared_ptr &handle) { bool purge = false; { - auto lock = handle->GetLock(); - if (!handle->GetBuffer(lock) || handle->GetBufferType() == FileBufferType::TINY_BUFFER) { + lock_guard lock(handle->lock); + if (!handle->buffer || handle->buffer->type == FileBufferType::TINY_BUFFER) { return; } - D_ASSERT(handle->Readers() > 0); - auto new_readers = handle->DecrementReaders(); - if (new_readers == 0) { - VerifyZeroReaders(lock, handle); + D_ASSERT(handle->readers > 0); + handle->readers--; + if (handle->readers == 0) { + VerifyZeroReaders(handle); if (handle->MustAddToEvictionQueue()) { purge = buffer_pool.AddToEvictionQueue(handle); } else { - handle->Unload(lock); + handle->Unload(); } } } // We do not have to keep the handle locked while purging. if (purge) { - PurgeQueue(*handle); + PurgeQueue(handle->buffer->type); } } @@ -469,15 +458,15 @@ void StandardBufferManager::WriteTemporaryBuffer(MemoryTag tag, block_id_t block RequireTemporaryDirectory(); // Append to a few grouped files. - if (buffer.AllocSize() == GetBlockAllocSize()) { - evicted_data_per_tag[uint8_t(tag)] += GetBlockAllocSize(); + if (buffer.size == GetBlockSize()) { + evicted_data_per_tag[uint8_t(tag)] += GetBlockSize(); temporary_directory.handle->GetTempFile().WriteTemporaryBuffer(block_id, buffer); return; } // Get the path to write to. auto path = GetTemporaryPath(block_id); - evicted_data_per_tag[uint8_t(tag)] += buffer.AllocSize(); + evicted_data_per_tag[uint8_t(tag)] += buffer.size; // Create the file and write the size followed by the buffer contents. auto &fs = FileSystem::GetFileSystem(db); @@ -528,7 +517,7 @@ void StandardBufferManager::DeleteTemporaryFile(BlockHandle &block) { } // check if we should delete the file from the shared pool of files, or from the general file system if (temporary_directory.handle->GetTempFile().HasTemporaryBuffer(id)) { - evicted_data_per_tag[uint8_t(block.GetMemoryTag())] -= GetBlockAllocSize(); + evicted_data_per_tag[uint8_t(block.GetMemoryTag())] -= GetBlockSize(); temporary_directory.handle->GetTempFile().DeleteTemporaryBuffer(id); return; } diff --git a/src/duckdb/src/storage/statistics/column_statistics.cpp b/src/duckdb/src/storage/statistics/column_statistics.cpp index 19784bc91..7a1de53d5 100644 --- a/src/duckdb/src/storage/statistics/column_statistics.cpp +++ b/src/duckdb/src/storage/statistics/column_statistics.cpp @@ -44,12 +44,12 @@ void ColumnStatistics::SetDistinct(unique_ptr distinct) { this->distinct_stats = std::move(distinct); } -void ColumnStatistics::UpdateDistinctStatistics(Vector &v, idx_t count, Vector &hashes) { +void ColumnStatistics::UpdateDistinctStatistics(Vector &v, idx_t count) { if (!distinct_stats) { return; } - // we use a sample to update the distinct statistics for performance reasons - distinct_stats->UpdateSample(v, count, hashes); + // We sample for non-integral types to save cost, and because integers are more likely to be join keys + distinct_stats->Update(v, count); } shared_ptr ColumnStatistics::Copy() const { diff --git a/src/duckdb/src/storage/statistics/distinct_statistics.cpp b/src/duckdb/src/storage/statistics/distinct_statistics.cpp index ddadc997e..6e5088cb3 100644 --- a/src/duckdb/src/storage/statistics/distinct_statistics.cpp +++ b/src/duckdb/src/storage/statistics/distinct_statistics.cpp @@ -15,6 +15,7 @@ DistinctStatistics::DistinctStatistics(unique_ptr log, idx_t sample } unique_ptr DistinctStatistics::Copy() const { + lock_guard guard(lock); return make_uniq(log->Copy(), sample_count, total_count); } @@ -24,28 +25,26 @@ void DistinctStatistics::Merge(const DistinctStatistics &other) { total_count += other.total_count; } -void DistinctStatistics::UpdateSample(Vector &new_data, idx_t count, Vector &hashes) { +void DistinctStatistics::Update(Vector &v, idx_t count, bool sample) { total_count += count; - const auto original_count = count; - const auto sample_rate = new_data.GetType().IsIntegral() ? INTEGRAL_SAMPLE_RATE : BASE_SAMPLE_RATE; - // Sample up to 'sample_rate' of STANDARD_VECTOR_SIZE of this vector (at least 1) - count = MaxValue(LossyNumericCast(sample_rate * static_cast(STANDARD_VECTOR_SIZE)), 1); - // But never more than the original count - count = MinValue(count, original_count); - - UpdateInternal(new_data, count, hashes); -} + if (sample) { + const auto original_count = count; + const auto sample_rate = v.GetType().IsIntegral() ? INTEGRAL_SAMPLE_RATE : BASE_SAMPLE_RATE; + // Sample up to 'sample_rate' of STANDARD_VECTOR_SIZE of this vector (at least 1) + count = MaxValue(LossyNumericCast(sample_rate * static_cast(STANDARD_VECTOR_SIZE)), 1); + // But never more than the original count + count = MinValue(count, original_count); + } + sample_count += count; -void DistinctStatistics::Update(Vector &new_data, idx_t count, Vector &hashes) { - total_count += count; - UpdateInternal(new_data, count, hashes); -} + lock_guard guard(lock); + Vector hash_vec(LogicalType::HASH, count); + VectorOperations::Hash(v, hash_vec, count); -void DistinctStatistics::UpdateInternal(Vector &new_data, idx_t count, Vector &hashes) { - sample_count += count; - VectorOperations::Hash(new_data, hashes, count); + UnifiedVectorFormat vdata; + v.ToUnifiedFormat(count, vdata); - log->Update(new_data, hashes, count); + log->Update(v, hash_vec, count); } string DistinctStatistics::ToString() const { diff --git a/src/duckdb/src/storage/statistics/numeric_stats.cpp b/src/duckdb/src/storage/statistics/numeric_stats.cpp index a93798122..29d89a513 100644 --- a/src/duckdb/src/storage/statistics/numeric_stats.cpp +++ b/src/duckdb/src/storage/statistics/numeric_stats.cpp @@ -143,8 +143,11 @@ bool ConstantValueInRange(T min, T max, T constant) { } template -FilterPropagateResult CheckZonemapTemplated(const BaseStatistics &stats, ExpressionType comparison_type, T min_value, - T max_value, T constant) { +FilterPropagateResult CheckZonemapTemplated(const BaseStatistics &stats, ExpressionType comparison_type, + const Value &constant_value) { + T min_value = NumericStats::GetMinUnsafe(stats); + T max_value = NumericStats::GetMaxUnsafe(stats); + T constant = constant_value.GetValueUnsafe(); switch (comparison_type) { case ExpressionType::COMPARE_EQUAL: if (ConstantExactRange(min_value, max_value, constant)) { @@ -211,55 +214,40 @@ FilterPropagateResult CheckZonemapTemplated(const BaseStatistics &stats, Express } } -template -FilterPropagateResult CheckZonemapTemplated(const BaseStatistics &stats, ExpressionType comparison_type, - array_ptr constants) { - T min_value = NumericStats::GetMinUnsafe(stats); - T max_value = NumericStats::GetMaxUnsafe(stats); - for (auto &constant_value : constants) { - D_ASSERT(constant_value.type() == stats.GetType()); - D_ASSERT(!constant_value.IsNull()); - T constant = constant_value.GetValueUnsafe(); - auto prune_result = CheckZonemapTemplated(stats, comparison_type, min_value, max_value, constant); - if (prune_result == FilterPropagateResult::NO_PRUNING_POSSIBLE) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } else if (prune_result == FilterPropagateResult::FILTER_ALWAYS_TRUE) { - return FilterPropagateResult::FILTER_ALWAYS_TRUE; - } - } - return FilterPropagateResult::FILTER_ALWAYS_FALSE; -} - FilterPropagateResult NumericStats::CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type, - array_ptr constants) { + const Value &constant) { + D_ASSERT(constant.type() == stats.GetType()); + if (constant.IsNull()) { + return FilterPropagateResult::FILTER_ALWAYS_FALSE; + } if (!NumericStats::HasMinMax(stats)) { return FilterPropagateResult::NO_PRUNING_POSSIBLE; } switch (stats.GetType().InternalType()) { case PhysicalType::INT8: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::INT16: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::INT32: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::INT64: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::UINT8: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::UINT16: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::UINT32: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::UINT64: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::INT128: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::UINT128: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::FLOAT: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); case PhysicalType::DOUBLE: - return CheckZonemapTemplated(stats, comparison_type, constants); + return CheckZonemapTemplated(stats, comparison_type, constant); default: throw InternalException("Unsupported type for NumericStats::CheckZonemap"); } diff --git a/src/duckdb/src/storage/statistics/string_stats.cpp b/src/duckdb/src/storage/statistics/string_stats.cpp index 691bae090..c3994b54f 100644 --- a/src/duckdb/src/storage/statistics/string_stats.cpp +++ b/src/duckdb/src/storage/statistics/string_stats.cpp @@ -184,21 +184,10 @@ void StringStats::Merge(BaseStatistics &stats, const BaseStatistics &other) { } FilterPropagateResult StringStats::CheckZonemap(const BaseStatistics &stats, ExpressionType comparison_type, - array_ptr constants) { + const string &constant) { auto &string_data = StringStats::GetDataUnsafe(stats); - for (auto &constant_value : constants) { - D_ASSERT(constant_value.type() == stats.GetType()); - D_ASSERT(!constant_value.IsNull()); - auto &constant = StringValue::Get(constant_value); - auto prune_result = CheckZonemap(string_data.min, StringStatsData::MAX_STRING_MINMAX_SIZE, string_data.max, - StringStatsData::MAX_STRING_MINMAX_SIZE, comparison_type, constant); - if (prune_result == FilterPropagateResult::NO_PRUNING_POSSIBLE) { - return FilterPropagateResult::NO_PRUNING_POSSIBLE; - } else if (prune_result == FilterPropagateResult::FILTER_ALWAYS_TRUE) { - return FilterPropagateResult::FILTER_ALWAYS_TRUE; - } - } - return FilterPropagateResult::FILTER_ALWAYS_FALSE; + return CheckZonemap(string_data.min, StringStatsData::MAX_STRING_MINMAX_SIZE, string_data.max, + StringStatsData::MAX_STRING_MINMAX_SIZE, comparison_type, constant); } FilterPropagateResult StringStats::CheckZonemap(const_data_ptr_t min_data, idx_t min_len, const_data_ptr_t max_data, diff --git a/src/duckdb/src/storage/storage_info.cpp b/src/duckdb/src/storage/storage_info.cpp index b814fdc34..61939c46a 100644 --- a/src/duckdb/src/storage/storage_info.cpp +++ b/src/duckdb/src/storage/storage_info.cpp @@ -19,85 +19,23 @@ struct SerializationVersionInfo { // These sections are automatically generated by scripts/generate_storage_info.py // Do not edit them manually, your changes will be overwritten -// clang-format off + // START OF STORAGE VERSION INFO -const uint64_t DEFAULT_STORAGE_VERSION_INFO = 64; static const StorageVersionInfo storage_version_info[] = { - {"v0.0.4", 1}, - {"v0.1.0", 1}, - {"v0.1.1", 1}, - {"v0.1.2", 1}, - {"v0.1.3", 1}, - {"v0.1.4", 1}, - {"v0.1.5", 1}, - {"v0.1.6", 1}, - {"v0.1.7", 1}, - {"v0.1.8", 1}, - {"v0.1.9", 1}, - {"v0.2.0", 1}, - {"v0.2.1", 1}, - {"v0.2.2", 4}, - {"v0.2.3", 6}, - {"v0.2.4", 11}, - {"v0.2.5", 13}, - {"v0.2.6", 15}, - {"v0.2.7", 17}, - {"v0.2.8", 18}, - {"v0.2.9", 21}, - {"v0.3.0", 25}, - {"v0.3.1", 27}, - {"v0.3.2", 31}, - {"v0.3.3", 33}, - {"v0.3.4", 33}, - {"v0.3.5", 33}, - {"v0.4.0", 33}, - {"v0.5.0", 38}, - {"v0.5.1", 38}, - {"v0.6.0", 39}, - {"v0.6.1", 39}, - {"v0.7.0", 43}, - {"v0.7.1", 43}, - {"v0.8.0", 51}, - {"v0.8.1", 51}, - {"v0.9.0", 64}, - {"v0.9.1", 64}, - {"v0.9.2", 64}, - {"v0.10.0", 64}, - {"v0.10.1", 64}, - {"v0.10.2", 64}, - {"v0.10.3", 64}, - {"v1.0.0", 64}, - {"v1.1.0", 64}, - {"v1.1.1", 64}, - {"v1.1.2", 64}, - {"v1.1.3", 64}, - {nullptr, 0} -}; + {"v0.0.4", 1}, {"v0.1.0", 1}, {"v0.1.1", 1}, {"v0.1.2", 1}, {"v0.1.3", 1}, {"v0.1.4", 1}, {"v0.1.5", 1}, + {"v0.1.6", 1}, {"v0.1.7", 1}, {"v0.1.8", 1}, {"v0.1.9", 1}, {"v0.2.0", 1}, {"v0.2.1", 1}, {"v0.2.2", 4}, + {"v0.2.3", 6}, {"v0.2.4", 11}, {"v0.2.5", 13}, {"v0.2.6", 15}, {"v0.2.7", 17}, {"v0.2.8", 18}, {"v0.2.9", 21}, + {"v0.3.0", 25}, {"v0.3.1", 27}, {"v0.3.2", 31}, {"v0.3.3", 33}, {"v0.3.4", 33}, {"v0.3.5", 33}, {"v0.4.0", 33}, + {"v0.5.0", 38}, {"v0.5.1", 38}, {"v0.6.0", 39}, {"v0.6.1", 39}, {"v0.7.0", 43}, {"v0.7.1", 43}, {"v0.8.0", 51}, + {"v0.8.1", 51}, {"v0.9.0", 64}, {"v0.9.1", 64}, {"v0.9.2", 64}, {"v0.10.0", 64}, {"v0.10.1", 64}, {"v0.10.2", 64}, + {"v0.10.3", 64}, {"v1.0.0", 64}, {"v1.1.0", 64}, {"v1.1.1", 64}, {"v1.1.2", 64}, {"v1.1.3", 64}, {nullptr, 0}}; // END OF STORAGE VERSION INFO -static_assert(DEFAULT_STORAGE_VERSION_INFO == VERSION_NUMBER, "Check on VERSION_INFO"); // START OF SERIALIZATION VERSION INFO -const uint64_t LATEST_SERIALIZATION_VERSION_INFO = 4; -const uint64_t DEFAULT_SERIALIZATION_VERSION_INFO = 1; static const SerializationVersionInfo serialization_version_info[] = { - {"v0.10.0", 1}, - {"v0.10.1", 1}, - {"v0.10.2", 1}, - {"v0.10.3", 2}, - {"v1.0.0", 2}, - {"v1.1.0", 3}, - {"v1.1.1", 3}, - {"v1.1.2", 3}, - {"v1.1.3", 3}, - {"v1.2.0", 4}, - {"latest", 4}, - {nullptr, 0} -}; + {"v0.10.0", 1}, {"v0.10.1", 1}, {"v0.10.2", 1}, {"v0.10.3", 2}, {"v1.0.0", 2}, {"v1.1.0", 3}, + {"v1.1.1", 3}, {"v1.1.2", 3}, {"v1.1.3", 3}, {"latest", 3}, {nullptr, 0}}; // END OF SERIALIZATION VERSION INFO -// clang-format on - -static_assert(DEFAULT_SERIALIZATION_VERSION_INFO <= LATEST_SERIALIZATION_VERSION_INFO, - "Check on SERIALIZATION_VERSION_INFO"); optional_idx GetStorageVersion(const char *version_string) { for (idx_t i = 0; storage_version_info[i].version_name; i++) { diff --git a/src/duckdb/src/storage/storage_manager.cpp b/src/duckdb/src/storage/storage_manager.cpp index 2f340251b..456cd2261 100644 --- a/src/duckdb/src/storage/storage_manager.cpp +++ b/src/duckdb/src/storage/storage_manager.cpp @@ -56,19 +56,36 @@ ObjectCache &ObjectCache::GetObjectCache(ClientContext &context) { return context.db->GetObjectCache(); } +bool ObjectCache::ObjectCacheEnabled(ClientContext &context) { + return context.db->config.options.object_cache_enable; +} + idx_t StorageManager::GetWALSize() { - return wal->GetWALSize(); + auto wal_ptr = GetWAL(); + if (!wal_ptr) { + return 0; + } + return wal_ptr->GetWALSize(); } optional_ptr StorageManager::GetWAL() { if (InMemory() || read_only || !load_complete) { return nullptr; } + + if (!wal) { + auto wal_path = GetWALPath(); + wal = make_uniq(db, wal_path); + } return wal.get(); } void StorageManager::ResetWAL() { - wal->Delete(); + auto wal_ptr = GetWAL(); + if (wal_ptr) { + wal_ptr->Delete(); + } + wal.reset(); } string StorageManager::GetWALPath() { @@ -92,25 +109,23 @@ bool StorageManager::InMemory() { return path == IN_MEMORY_PATH; } -void StorageManager::Initialize(StorageOptions options) { +void StorageManager::Initialize(const optional_idx block_alloc_size) { bool in_memory = InMemory(); if (in_memory && read_only) { throw CatalogException("Cannot launch in-memory database in read-only mode!"); } // Create or load the database from disk, if not in-memory mode. - LoadDatabase(options); + LoadDatabase(block_alloc_size); } /////////////////////////////////////////////////////////////////////////// class SingleFileTableIOManager : public TableIOManager { public: - explicit SingleFileTableIOManager(BlockManager &block_manager, idx_t row_group_size) - : block_manager(block_manager), row_group_size(row_group_size) { + explicit SingleFileTableIOManager(BlockManager &block_manager) : block_manager(block_manager) { } BlockManager &block_manager; - idx_t row_group_size; public: BlockManager &GetIndexBlockManager() override { @@ -122,43 +137,32 @@ class SingleFileTableIOManager : public TableIOManager { MetadataManager &GetMetadataManager() override { return block_manager.GetMetadataManager(); } - idx_t GetRowGroupSize() const override { - return row_group_size; - } }; SingleFileStorageManager::SingleFileStorageManager(AttachedDatabase &db, string path, bool read_only) : StorageManager(db, std::move(path), read_only) { } -void SingleFileStorageManager::LoadDatabase(StorageOptions storage_options) { +void SingleFileStorageManager::LoadDatabase(const optional_idx block_alloc_size) { if (InMemory()) { block_manager = make_uniq(BufferManager::GetBufferManager(db), DEFAULT_BLOCK_ALLOC_SIZE); - table_io_manager = make_uniq(*block_manager, DEFAULT_ROW_GROUP_SIZE); + table_io_manager = make_uniq(*block_manager); return; } auto &fs = FileSystem::Get(db); auto &config = DBConfig::Get(db); + if (!config.options.enable_external_access) { + if (!db.IsInitialDatabase()) { + throw PermissionException("Attaching on-disk databases is disabled through configuration"); + } + } StorageManagerOptions options; options.read_only = read_only; options.use_direct_io = config.options.use_direct_io; options.debug_initialize = config.options.debug_initialize; - idx_t row_group_size = DEFAULT_ROW_GROUP_SIZE; - if (storage_options.row_group_size.IsValid()) { - row_group_size = storage_options.row_group_size.GetIndex(); - if (row_group_size == 0) { - throw NotImplementedException("Invalid row group size: %llu - row group size must be bigger than 0", - row_group_size); - } - if (row_group_size % STANDARD_VECTOR_SIZE != 0) { - throw NotImplementedException( - "Invalid row group size: %llu - row group size must be divisible by the vector size (%llu)", - row_group_size, STANDARD_VECTOR_SIZE); - } - } // Check if the database file already exists. // Note: a file can also exist if there was a ROLLBACK on a previous transaction creating that file. if (!read_only && !fs.FileExists(path)) { @@ -174,10 +178,9 @@ void SingleFileStorageManager::LoadDatabase(StorageOptions storage_options) { } // Set the block allocation size for the new database file. - if (storage_options.block_alloc_size.IsValid()) { + if (block_alloc_size.IsValid()) { // Use the option provided by the user. - Storage::VerifyBlockAllocSize(storage_options.block_alloc_size.GetIndex()); - options.block_alloc_size = storage_options.block_alloc_size; + options.block_alloc_size = block_alloc_size; } else { // No explicit option provided: use the default option. options.block_alloc_size = config.options.default_block_alloc_size; @@ -187,8 +190,8 @@ void SingleFileStorageManager::LoadDatabase(StorageOptions storage_options) { auto sf_block_manager = make_uniq(db, path, options); sf_block_manager->CreateNewDatabase(); block_manager = std::move(sf_block_manager); - table_io_manager = make_uniq(*block_manager, row_group_size); - wal = make_uniq(db, wal_path); + table_io_manager = make_uniq(*block_manager); + } else { // Either the file exists, or we are in read-only mode, so we // try to read the existing file on disk. @@ -199,24 +202,27 @@ void SingleFileStorageManager::LoadDatabase(StorageOptions storage_options) { auto sf_block_manager = make_uniq(db, path, options); sf_block_manager->LoadExistingDatabase(); block_manager = std::move(sf_block_manager); - table_io_manager = make_uniq(*block_manager, row_group_size); - - if (storage_options.block_alloc_size.IsValid()) { - // user-provided block alloc size - idx_t block_alloc_size = storage_options.block_alloc_size.GetIndex(); - if (block_alloc_size != block_manager->GetBlockAllocSize()) { - throw InvalidInputException( - "block size parameter does not match the file's block size, got %llu, expected %llu", - storage_options.block_alloc_size.GetIndex(), block_manager->GetBlockAllocSize()); - } + table_io_manager = make_uniq(*block_manager); + + if (block_alloc_size.IsValid() && block_alloc_size.GetIndex() != block_manager->GetBlockAllocSize()) { + throw InvalidInputException( + "block size parameter does not match the file's block size, got %llu, expected %llu", + block_alloc_size.GetIndex(), block_manager->GetBlockAllocSize()); } // load the db from storage auto checkpoint_reader = SingleFileCheckpointReader(*this); checkpoint_reader.LoadFromStorage(); + // check if the WAL file exists auto wal_path = GetWALPath(); - wal = WriteAheadLog::Replay(fs, db, wal_path); + auto handle = fs.OpenFile(wal_path, FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_NULL_IF_NOT_EXISTS); + if (handle) { + // replay the WAL + if (WriteAheadLog::Replay(db, std::move(handle))) { + fs.RemoveFile(wal_path); + } + } } load_complete = true; diff --git a/src/duckdb/src/storage/table/array_column_data.cpp b/src/duckdb/src/storage/table/array_column_data.cpp index 148f3fd84..95ba4df38 100644 --- a/src/duckdb/src/storage/table/array_column_data.cpp +++ b/src/duckdb/src/storage/table/array_column_data.cpp @@ -114,13 +114,7 @@ void ArrayColumnData::InitializeAppend(ColumnAppendState &state) { } void ArrayColumnData::Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count) { - if (vector.GetVectorType() != VectorType::FLAT_VECTOR) { - Vector append_vector(vector); - append_vector.Flatten(count); - Append(stats, state, append_vector, count); - return; - } - + vector.Flatten(count); // Append validity validity.Append(stats, state.child_appends[0], vector, count); // Append child column diff --git a/src/duckdb/src/storage/table/column_checkpoint_state.cpp b/src/duckdb/src/storage/table/column_checkpoint_state.cpp index a67daa060..7bb1d5a90 100644 --- a/src/duckdb/src/storage/table/column_checkpoint_state.cpp +++ b/src/duckdb/src/storage/table/column_checkpoint_state.cpp @@ -112,12 +112,7 @@ void PartialBlockForCheckpoint::Clear() { segments.clear(); } -void ColumnCheckpointState::FlushSegment(unique_ptr segment, BufferHandle handle, idx_t segment_size) { - handle.Destroy(); - FlushSegmentInternal(std::move(segment), segment_size); -} - -void ColumnCheckpointState::FlushSegmentInternal(unique_ptr segment, idx_t segment_size) { +void ColumnCheckpointState::FlushSegment(unique_ptr segment, idx_t segment_size) { auto block_size = partial_block_manager.GetBlockManager().GetBlockSize(); D_ASSERT(segment_size <= block_size); @@ -171,6 +166,11 @@ void ColumnCheckpointState::FlushSegmentInternal(unique_ptr segme // Writer will decide whether to reuse this block. partial_block_manager.RegisterPartialBlock(std::move(allocation)); } else { + // constant block: no need to write anything to disk besides the stats + // set up the compression function to constant + auto &config = DBConfig::GetConfig(db); + segment->function = + *config.GetCompressionFunction(CompressionType::COMPRESSION_CONSTANT, segment->type.InternalType()); segment->ConvertToPersistent(nullptr, INVALID_BLOCK); } @@ -184,10 +184,9 @@ void ColumnCheckpointState::FlushSegmentInternal(unique_ptr segme data_pointer.row_start = last_pointer.row_start + last_pointer.tuple_count; } data_pointer.tuple_count = tuple_count; - auto &compression_function = segment->GetCompressionFunction(); - data_pointer.compression_type = compression_function.type; - if (compression_function.serialize_state) { - data_pointer.segment_state = compression_function.serialize_state(*segment); + data_pointer.compression_type = segment->function.get().type; + if (segment->function.get().serialize_state) { + data_pointer.segment_state = segment->function.get().serialize_state(*segment); } // append the segment to the new segment tree diff --git a/src/duckdb/src/storage/table/column_data.cpp b/src/duckdb/src/storage/table/column_data.cpp index 985a59415..7e778b868 100644 --- a/src/duckdb/src/storage/table/column_data.cpp +++ b/src/duckdb/src/storage/table/column_data.cpp @@ -24,7 +24,7 @@ namespace duckdb { ColumnData::ColumnData(BlockManager &block_manager, DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type_p, optional_ptr parent) : start(start_row), count(0), block_manager(block_manager), info(info), column_index(column_index), - type(std::move(type_p)), allocation_size(0), parent(parent) { + type(std::move(type_p)), parent(parent), allocation_size(0) { if (!parent) { stats = make_uniq(type); } @@ -63,16 +63,6 @@ bool ColumnData::HasUpdates() const { return updates.get(); } -bool ColumnData::HasChanges(idx_t start_row, idx_t end_row) const { - if (!updates) { - return false; - } - if (updates->HasUpdates(start_row, end_row)) { - return true; - } - return false; -} - void ColumnData::ClearUpdates() { lock_guard update_guard(update_lock); updates.reset(); @@ -146,7 +136,10 @@ void ColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanSta } } -void ColumnData::BeginScanVectorInternal(ColumnScanState &state) { +idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remaining, ScanVectorType scan_type) { + if (scan_type == ScanVectorType::SCAN_FLAT_VECTOR && result.GetVectorType() != VectorType::FLAT_VECTOR) { + throw InternalException("ScanVector called with SCAN_FLAT_VECTOR but result is not a flat vector"); + } state.previous_states.clear(); if (!state.initialized) { D_ASSERT(state.current); @@ -160,13 +153,6 @@ void ColumnData::BeginScanVectorInternal(ColumnScanState &state) { state.current->Skip(state); } D_ASSERT(state.current->type == type); -} - -idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remaining, ScanVectorType scan_type) { - if (scan_type == ScanVectorType::SCAN_FLAT_VECTOR && result.GetVectorType() != VectorType::FLAT_VECTOR) { - throw InternalException("ScanVector called with SCAN_FLAT_VECTOR but result is not a flat vector"); - } - BeginScanVectorInternal(state); idx_t initial_remaining = remaining; while (remaining > 0) { D_ASSERT(state.row_index >= state.current->start && @@ -205,36 +191,6 @@ idx_t ColumnData::ScanVector(ColumnScanState &state, Vector &result, idx_t remai return initial_remaining - remaining; } -void ColumnData::SelectVector(ColumnScanState &state, Vector &result, idx_t target_count, const SelectionVector &sel, - idx_t sel_count) { - BeginScanVectorInternal(state); - if (state.current->start + state.current->count - state.row_index < target_count) { - throw InternalException("ColumnData::SelectVector should be able to fetch everything from one segment"); - } - if (state.scan_options && state.scan_options->force_fetch_row) { - for (idx_t i = 0; i < sel_count; i++) { - auto source_idx = sel.get_index(i); - ColumnFetchState fetch_state; - state.current->FetchRow(fetch_state, UnsafeNumericCast(state.row_index + source_idx), result, i); - } - } else { - state.current->Select(state, target_count, result, sel, sel_count); - } - state.row_index += target_count; - state.internal_index = state.row_index; -} - -void ColumnData::FilterVector(ColumnScanState &state, Vector &result, idx_t target_count, SelectionVector &sel, - idx_t &sel_count, const TableFilter &filter) { - BeginScanVectorInternal(state); - if (state.current->start + state.current->count - state.row_index < target_count) { - throw InternalException("ColumnData::Filter should be able to fetch everything from one segment"); - } - state.current->Filter(state, target_count, result, sel, sel_count, filter); - state.row_index += target_count; - state.internal_index = state.row_index; -} - unique_ptr ColumnData::GetUpdateStatistics() { lock_guard update_guard(update_lock); return updates ? updates->GetStatistics() : nullptr; @@ -274,23 +230,26 @@ void ColumnData::UpdateInternal(TransactionData transaction, idx_t column_index, updates->Update(transaction, column_index, update_vector, row_ids, update_count, base_vector); } +template idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - idx_t target_scan, ScanVectorType scan_type, ScanVectorMode mode) { + idx_t target_scan) { + auto scan_type = GetVectorScanType(state, target_scan, result); auto scan_count = ScanVector(state, result, target_scan, scan_type); if (scan_type != ScanVectorType::SCAN_ENTIRE_VECTOR) { // if we are scanning an entire vector we cannot have updates - bool allow_updates = mode != ScanVectorMode::SCAN_COMMITTED_NO_UPDATES; - bool scan_committed = mode != ScanVectorMode::REGULAR_SCAN; - FetchUpdates(transaction, vector_index, result, scan_count, allow_updates, scan_committed); + FetchUpdates(transaction, vector_index, result, scan_count, ALLOW_UPDATES, SCAN_COMMITTED); } return scan_count; } -idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - idx_t target_scan, ScanVectorMode mode) { - auto scan_type = GetVectorScanType(state, target_scan, result); - return ScanVector(transaction, vector_index, state, result, target_scan, scan_type, mode); -} +template idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, + ColumnScanState &state, Vector &result, idx_t target_scan); +template idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, + ColumnScanState &state, Vector &result, idx_t target_scan); +template idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, + ColumnScanState &state, Vector &result, idx_t target_scan); +template idx_t ColumnData::ScanVector(TransactionData transaction, idx_t vector_index, + ColumnScanState &state, Vector &result, idx_t target_scan); idx_t ColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result) { auto target_count = GetVectorCount(vector_index); @@ -304,14 +263,16 @@ idx_t ColumnData::ScanCommitted(idx_t vector_index, ColumnScanState &state, Vect idx_t ColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, idx_t scan_count) { - return ScanVector(transaction, vector_index, state, result, scan_count, ScanVectorMode::REGULAR_SCAN); + return ScanVector(transaction, vector_index, state, result, scan_count); } idx_t ColumnData::ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates, idx_t scan_count) { - auto mode = allow_updates ? ScanVectorMode::SCAN_COMMITTED : ScanVectorMode::SCAN_COMMITTED_NO_UPDATES; - TransactionData commit_transaction(0, 0); - return ScanVector(commit_transaction, vector_index, state, result, scan_count, mode); + if (allow_updates) { + return ScanVector(TransactionData(0, 0), vector_index, state, result, scan_count); + } else { + return ScanVector(TransactionData(0, 0), vector_index, state, result, scan_count); + } } idx_t ColumnData::GetVectorCount(idx_t vector_index) const { @@ -340,7 +301,7 @@ idx_t ColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t scan_c return ScanVector(state, result, scan_count, ScanVectorType::SCAN_FLAT_VECTOR); } -void ColumnData::Filter(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, +void ColumnData::Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel, idx_t &s_count, const TableFilter &filter) { idx_t scan_count = Scan(transaction, vector_index, state, result); @@ -349,14 +310,14 @@ void ColumnData::Filter(TransactionData transaction, idx_t vector_index, ColumnS ColumnSegment::FilterSelection(sel, result, vdata, filter, scan_count, s_count); } -void ColumnData::Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t s_count) { +void ColumnData::FilterScan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, + SelectionVector &sel, idx_t s_count) { Scan(transaction, vector_index, state, result); result.Slice(sel, s_count); } -void ColumnData::SelectCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel, - idx_t s_count, bool allow_updates) { +void ColumnData::FilterScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel, + idx_t s_count, bool allow_updates) { ScanCommitted(vector_index, state, result, allow_updates); result.Slice(sel, s_count); } @@ -448,7 +409,7 @@ void ColumnData::InitializeAppend(ColumnAppendState &state) { AppendTransientSegment(l, start); } auto segment = data.GetLastSegment(l); - if (segment->segment_type == ColumnSegmentType::PERSISTENT || !segment->GetCompressionFunction().init_append) { + if (segment->segment_type == ColumnSegmentType::PERSISTENT || !segment->function.get().init_append) { // we cannot append to this segment - append a new segment auto total_rows = segment->start + segment->count; AppendTransientSegment(l, total_rows); @@ -459,7 +420,7 @@ void ColumnData::InitializeAppend(ColumnAppendState &state) { D_ASSERT(state.current->segment_type == ColumnSegmentType::TRANSIENT); state.current->InitializeAppend(state); - D_ASSERT(state.current->GetCompressionFunction().append); + D_ASSERT(state.current->function.get().append); } void ColumnData::AppendData(BaseStatistics &append_stats, ColumnAppendState &state, UnifiedVectorFormat &vdata, @@ -566,33 +527,8 @@ void ColumnData::AppendTransientSegment(SegmentLock &l, idx_t start_row) { // The segment size is bound by the block size, but can be smaller. idx_t segment_size = block_size < vector_segment_size ? block_size : vector_segment_size; allocation_size += segment_size; - - auto &db = GetDatabase(); - auto &config = DBConfig::GetConfig(db); - auto function = config.GetCompressionFunction(CompressionType::COMPRESSION_UNCOMPRESSED, type.InternalType()); - - auto new_segment = ColumnSegment::CreateTransientSegment(db, *function, type, start_row, segment_size, block_size); - AppendSegment(l, std::move(new_segment)); -} - -void ColumnData::UpdateCompressionFunction(SegmentLock &l, const CompressionFunction &function) { - if (!compression) { - // compression is empty... - // if we have no segments - we have not set it yet, so assign it - // if we have segments, the compression is mixed, so ignore it - if (data.GetSegmentCount(l) == 0) { - compression.set(function); - } - } else if (compression->type != function.type) { - // we already have compression set - and we are adding a segment with a different compression - // compression in the segment is mixed - clear the compression pointer - compression.reset(); - } -} - -void ColumnData::AppendSegment(SegmentLock &l, unique_ptr segment) { - UpdateCompressionFunction(l, segment->GetCompressionFunction()); - data.AppendSegment(l, std::move(segment)); + auto new_segment = ColumnSegment::CreateTransientSegment(GetDatabase(), type, start_row, segment_size, block_size); + data.AppendSegment(l, std::move(new_segment)); } void ColumnData::CommitDropColumn() { @@ -630,16 +566,20 @@ unique_ptr ColumnData::Checkpoint(RowGroup &row_group, Co auto checkpoint_state = CreateCheckpointState(row_group, checkpoint_info.info.manager); checkpoint_state->global_stats = BaseStatistics::CreateEmpty(type).ToUnique(); - auto &nodes = data.ReferenceSegments(); + auto l = data.Lock(); + auto nodes = data.MoveSegments(l); if (nodes.empty()) { // empty table: flush the empty list return checkpoint_state; } - vector> states {*checkpoint_state}; - ColumnDataCheckpointer checkpointer(states, GetDatabase(), row_group, checkpoint_info); - checkpointer.Checkpoint(); - checkpointer.FinalizeCheckpoint(); + ColumnDataCheckpointer checkpointer(*this, row_group, *checkpoint_state, checkpoint_info); + checkpointer.Checkpoint(std::move(nodes)); + + // replace the old tree with the new one + data.Replace(l, checkpoint_state->new_tree); + ClearUpdates(); + return checkpoint_state; } @@ -666,8 +606,7 @@ void ColumnData::InitializeColumn(PersistentColumnData &column_data, BaseStatist data_pointer.row_start, data_pointer.tuple_count, data_pointer.compression_type, std::move(data_pointer.statistics), std::move(data_pointer.segment_state)); - auto l = data.Lock(); - AppendSegment(l, std::move(segment)); + data.AppendSegment(std::move(segment)); } } @@ -875,7 +814,7 @@ void ColumnData::GetColumnSegmentInfo(idx_t row_group_index, vector col_p column_info.segment_type = type.ToString(); column_info.segment_start = segment->start; column_info.segment_count = segment->count; - column_info.compression_type = CompressionTypeToString(segment->GetCompressionFunction().type); + column_info.compression_type = CompressionTypeToString(segment->function.get().type); { lock_guard l(stats_lock); column_info.segment_stats = segment->stats.statistics.ToString(); @@ -894,7 +833,6 @@ void ColumnData::GetColumnSegmentInfo(idx_t row_group_index, vector col_p auto segment_state = segment->GetSegmentState(); if (segment_state) { column_info.segment_info = segment_state->GetSegmentInfo(); - column_info.additional_blocks = segment_state->GetAdditionalBlocks(); } result.emplace_back(column_info); diff --git a/src/duckdb/src/storage/table/column_data_checkpointer.cpp b/src/duckdb/src/storage/table/column_data_checkpointer.cpp index ae92a6972..fec8b3543 100644 --- a/src/duckdb/src/storage/table/column_data_checkpointer.cpp +++ b/src/duckdb/src/storage/table/column_data_checkpointer.cpp @@ -1,81 +1,48 @@ #include "duckdb/storage/table/column_data_checkpointer.hpp" #include "duckdb/main/config.hpp" #include "duckdb/storage/table/update_segment.hpp" -#include "duckdb/storage/compression/empty_validity.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/parser/column_definition.hpp" #include "duckdb/storage/table/scan_state.hpp" namespace duckdb { -//! ColumnDataCheckpointData - -CompressionFunction &ColumnDataCheckpointData::GetCompressionFunction(CompressionType compression_type) { - auto &db = col_data->GetDatabase(); - auto &column_type = col_data->type; - auto &config = DBConfig::GetConfig(db); - return *config.GetCompressionFunction(compression_type, column_type.InternalType()); -} - -DatabaseInstance &ColumnDataCheckpointData::GetDatabase() { - return col_data->GetDatabase(); -} - -const LogicalType &ColumnDataCheckpointData::GetType() const { - return col_data->type; +ColumnDataCheckpointer::ColumnDataCheckpointer(ColumnData &col_data_p, RowGroup &row_group_p, + ColumnCheckpointState &state_p, ColumnCheckpointInfo &checkpoint_info_p) + : col_data(col_data_p), row_group(row_group_p), state(state_p), + is_validity(GetType().id() == LogicalTypeId::VALIDITY), + intermediate(is_validity ? LogicalType::BOOLEAN : GetType(), true, is_validity), + checkpoint_info(checkpoint_info_p) { + + auto &config = DBConfig::GetConfig(GetDatabase()); + auto functions = config.GetCompressionFunctions(GetType().InternalType()); + for (auto &func : functions) { + compression_functions.push_back(&func.get()); + } } -ColumnData &ColumnDataCheckpointData::GetColumnData() { - return *col_data; +DatabaseInstance &ColumnDataCheckpointer::GetDatabase() { + return col_data.GetDatabase(); } -RowGroup &ColumnDataCheckpointData::GetRowGroup() { - return *row_group; +const LogicalType &ColumnDataCheckpointer::GetType() const { + return col_data.type; } -ColumnCheckpointState &ColumnDataCheckpointData::GetCheckpointState() { - return *checkpoint_state; +ColumnData &ColumnDataCheckpointer::GetColumnData() { + return col_data; } -//! ColumnDataCheckpointer - -static Vector CreateIntermediateVector(vector> &states) { - D_ASSERT(!states.empty()); - - auto &first_state = states[0]; - auto &col_data = first_state.get().column_data; - auto &type = col_data.type; - if (type.id() == LogicalTypeId::VALIDITY) { - return Vector(LogicalType::BOOLEAN, true, /* initialize_to_zero = */ true); - } - return Vector(type, true, false); +RowGroup &ColumnDataCheckpointer::GetRowGroup() { + return row_group; } -ColumnDataCheckpointer::ColumnDataCheckpointer(vector> &checkpoint_states, - DatabaseInstance &db, RowGroup &row_group, - ColumnCheckpointInfo &checkpoint_info) - : checkpoint_states(checkpoint_states), db(db), row_group(row_group), - intermediate(CreateIntermediateVector(checkpoint_states)), checkpoint_info(checkpoint_info) { - - auto &config = DBConfig::GetConfig(db); - compression_functions.resize(checkpoint_states.size()); - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - auto &col_data = checkpoint_states[i].get().column_data; - auto to_add = config.GetCompressionFunctions(col_data.type.InternalType()); - auto &functions = compression_functions[i]; - for (auto &func : to_add) { - functions.push_back(&func.get()); - } - } +ColumnCheckpointState &ColumnDataCheckpointer::GetCheckpointState() { + return state; } void ColumnDataCheckpointer::ScanSegments(const std::function &callback) { Vector scan_vector(intermediate.GetType(), nullptr); - auto &first_state = checkpoint_states[0]; - auto &col_data = first_state.get().column_data; - auto &nodes = col_data.data.ReferenceSegments(); - - // TODO: scan all the nodes from all segments, no need for CheckpointScan to virtualize this I think.. for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) { auto &segment = *nodes[segment_idx].node; ColumnScanState scan_state; @@ -89,6 +56,7 @@ void ColumnDataCheckpointer::ScanSegments(const std::function> &comp break; } } - if (!found) { - return CompressionType::COMPRESSION_AUTO; - } - // the force_compression method is available - // clear all other compression methods - // except the uncompressed method, so we can fall back on that - for (idx_t i = 0; i < compression_functions.size(); i++) { - auto &compression_function = *compression_functions[i]; - if (compression_function.type == CompressionType::COMPRESSION_UNCOMPRESSED) { - continue; - } - if (compression_function.type != compression_type) { - compression_functions[i] = nullptr; - } - } - return compression_type; -} - -void ColumnDataCheckpointer::InitAnalyze() { - analyze_states.resize(checkpoint_states.size()); - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { - continue; - } - - auto &functions = compression_functions[i]; - auto &states = analyze_states[i]; - auto &checkpoint_state = checkpoint_states[i]; - auto &coldata = checkpoint_state.get().column_data; - states.resize(functions.size()); - for (idx_t j = 0; j < functions.size(); j++) { - auto &func = functions[j]; - if (!func) { + if (found) { + // the force_compression method is available + // clear all other compression methods + // except the uncompressed method, so we can fall back on that + for (idx_t i = 0; i < compression_functions.size(); i++) { + auto &compression_function = *compression_functions[i]; + if (compression_function.type == CompressionType::COMPRESSION_UNCOMPRESSED) { continue; } - states[j] = func->init_analyze(coldata, coldata.type.InternalType()); + if (compression_function.type != compression_type) { + compression_functions[i] = nullptr; + } } } + return found ? compression_type : CompressionType::COMPRESSION_AUTO; } -vector ColumnDataCheckpointer::DetectBestCompressionMethod() { +unique_ptr ColumnDataCheckpointer::DetectBestCompressionMethod(idx_t &compression_idx) { D_ASSERT(!compression_functions.empty()); - auto &config = DBConfig::GetConfig(db); - vector forced_methods(checkpoint_states.size(), CompressionType::COMPRESSION_AUTO); + auto &config = DBConfig::GetConfig(GetDatabase()); + CompressionType forced_method = CompressionType::COMPRESSION_AUTO; auto compression_type = checkpoint_info.GetCompressionType(); - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - auto &functions = compression_functions[i]; - if (compression_type != CompressionType::COMPRESSION_AUTO) { - forced_methods[i] = ForceCompression(functions, compression_type); - } - if (compression_type == CompressionType::COMPRESSION_AUTO && - config.options.force_compression != CompressionType::COMPRESSION_AUTO) { - forced_methods[i] = ForceCompression(functions, config.options.force_compression); + if (compression_type != CompressionType::COMPRESSION_AUTO) { + forced_method = ForceCompression(compression_functions, compression_type); + } + if (compression_type == CompressionType::COMPRESSION_AUTO && + config.options.force_compression != CompressionType::COMPRESSION_AUTO) { + forced_method = ForceCompression(compression_functions, config.options.force_compression); + } + // set up the analyze states for each compression method + vector> analyze_states; + analyze_states.reserve(compression_functions.size()); + for (idx_t i = 0; i < compression_functions.size(); i++) { + if (!compression_functions[i]) { + analyze_states.push_back(nullptr); + continue; } + analyze_states.push_back(compression_functions[i]->init_analyze(col_data, col_data.type.InternalType())); } - InitAnalyze(); - // scan over all the segments and run the analyze step ScanSegments([&](Vector &scan_vector, idx_t count) { - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { + for (idx_t i = 0; i < compression_functions.size(); i++) { + if (!compression_functions[i]) { continue; } - - auto &functions = compression_functions[i]; - auto &states = analyze_states[i]; - for (idx_t j = 0; j < functions.size(); j++) { - auto &state = states[j]; - auto &func = functions[j]; - - if (!state) { - continue; - } - if (!func->analyze(*state, scan_vector, count)) { - state = nullptr; - func = nullptr; - } + bool success = false; + if (analyze_states[i]) { + success = compression_functions[i]->analyze(*analyze_states[i], scan_vector, count); + } + if (!success) { + // could not use this compression function on this data set + // erase it + compression_functions[i] = nullptr; + analyze_states[i].reset(); } } }); - vector result; - result.resize(checkpoint_states.size()); - - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { + // now that we have passed over all the data, we need to figure out the best method + // we do this using the final_analyze method + unique_ptr state; + compression_idx = DConstants::INVALID_INDEX; + idx_t best_score = NumericLimits::Maximum(); + for (idx_t i = 0; i < compression_functions.size(); i++) { + if (!compression_functions[i]) { continue; } - auto &functions = compression_functions[i]; - auto &states = analyze_states[i]; - auto &forced_method = forced_methods[i]; - - unique_ptr chosen_state; - idx_t best_score = NumericLimits::Maximum(); - idx_t compression_idx = DConstants::INVALID_INDEX; - - D_ASSERT(functions.size() == states.size()); - for (idx_t j = 0; j < functions.size(); j++) { - auto &function = functions[j]; - auto &state = states[j]; - - if (!state) { - continue; - } - - //! Check if the method type is the forced method (if forced is used) - bool forced_method_found = function->type == forced_method; - // now that we have passed over all the data, we need to figure out the best method - // we do this using the final_analyze method - auto score = function->final_analyze(*state); - - //! The finalize method can return this value from final_analyze to indicate it should not be used. - if (score == DConstants::INVALID_INDEX) { - continue; - } + if (!analyze_states[i]) { + continue; + } + //! Check if the method type is the forced method (if forced is used) + bool forced_method_found = compression_functions[i]->type == forced_method; + auto score = compression_functions[i]->final_analyze(*analyze_states[i]); - if (score < best_score || forced_method_found) { - compression_idx = j; - best_score = score; - chosen_state = std::move(state); - } - //! If we have found the forced method, we're done - if (forced_method_found) { - break; - } + //! The finalize method can return this value from final_analyze to indicate it should not be used. + if (score == DConstants::INVALID_INDEX) { + continue; } - if (!chosen_state) { - auto &checkpoint_state = checkpoint_states[i]; - auto &col_data = checkpoint_state.get().column_data; - throw FatalException("No suitable compression/storage method found to store column of type %s", - col_data.type.ToString()); + if (score < best_score || forced_method_found) { + compression_idx = i; + best_score = score; + state = std::move(analyze_states[i]); + } + //! If we have found the forced method, we're done + if (forced_method_found) { + break; } - D_ASSERT(compression_idx != DConstants::INVALID_INDEX); - result[i] = CheckpointAnalyzeResult(std::move(chosen_state), *functions[compression_idx]); } - return result; + return state; } -void ColumnDataCheckpointer::DropSegments() { +void ColumnDataCheckpointer::WriteToDisk() { + // there were changes or transient segments + // we need to rewrite the column segments to disk + // first we check the current segments // if there are any persistent segments, we will mark their old block ids as modified // since the segments will be rewritten their old on disk data is no longer required - - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { - continue; - } - - auto &state = checkpoint_states[i]; - auto &col_data = state.get().column_data; - auto &nodes = col_data.data.ReferenceSegments(); - - // Drop the segments, as we'll be replacing them with new ones, because there are changes - for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) { - auto segment = nodes[segment_idx].node.get(); - segment->CommitDropSegment(); - } + for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) { + auto segment = nodes[segment_idx].node.get(); + segment->CommitDropSegment(); } -} -bool ColumnDataCheckpointer::ValidityCoveredByBasedata(vector &result) { - if (result.size() != 2) { - return false; - } - if (!has_changes[0]) { - // The base data had no changes so it will not be rewritten - return false; - } - auto &base = result[0]; - D_ASSERT(base.function); - return base.function->validity == CompressionValidity::NO_VALIDITY_REQUIRED; -} + // now we need to write our segment + // we will first run an analyze step that determines which compression function to use + idx_t compression_idx; + auto analyze_state = DetectBestCompressionMethod(compression_idx); -void ColumnDataCheckpointer::WriteToDisk() { - DropSegments(); - - // Analyze the candidate functions to select one of them to use for compression - auto analyze_result = DetectBestCompressionMethod(); - if (ValidityCoveredByBasedata(analyze_result)) { - D_ASSERT(analyze_result.size() == 2); - auto &validity = analyze_result[1]; - auto &config = DBConfig::GetConfig(db); - // Override the function to the COMPRESSION_EMPTY - // turning the compression+final compress steps into a no-op, saving a single empty segment - validity.function = config.GetCompressionFunction(CompressionType::COMPRESSION_EMPTY, PhysicalType::BIT); + if (!analyze_state) { + throw FatalException("No suitable compression/storage method found to store column"); } - // Initialize the compression for the selected function - D_ASSERT(analyze_result.size() == checkpoint_states.size()); - vector checkpoint_data(checkpoint_states.size()); - vector> compression_states(checkpoint_states.size()); - for (idx_t i = 0; i < analyze_result.size(); i++) { - if (!has_changes[i]) { - continue; - } - auto &analyze_state = analyze_result[i].analyze_state; - auto &function = analyze_result[i].function; - - auto &checkpoint_state = checkpoint_states[i]; - auto &col_data = checkpoint_state.get().column_data; + // now that we have analyzed the compression functions we can start writing to disk + auto best_function = compression_functions[compression_idx]; + auto compress_state = best_function->init_compression(*this, std::move(analyze_state)); - checkpoint_data[i] = - ColumnDataCheckpointData(checkpoint_state, col_data, col_data.GetDatabase(), row_group, checkpoint_info); - compression_states[i] = function->init_compression(checkpoint_data[i], std::move(analyze_state)); - } - - // Scan over the existing segment + changes and compress the data - ScanSegments([&](Vector &scan_vector, idx_t count) { - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { - continue; - } - auto &function = analyze_result[i].function; - auto &compression_state = compression_states[i]; - function->compress(*compression_state, scan_vector, count); - } - }); + ScanSegments( + [&](Vector &scan_vector, idx_t count) { best_function->compress(*compress_state, scan_vector, count); }); + best_function->compress_finalize(*compress_state); - // Finalize the compression - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - if (!has_changes[i]) { - continue; - } - auto &function = analyze_result[i].function; - auto &compression_state = compression_states[i]; - function->compress_finalize(*compression_state); - } + nodes.clear(); } -bool ColumnDataCheckpointer::HasChanges(ColumnData &col_data) { - auto &nodes = col_data.data.ReferenceSegments(); +bool ColumnDataCheckpointer::HasChanges() { for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) { auto segment = nodes[segment_idx].node.get(); if (segment->segment_type == ColumnSegmentType::TRANSIENT) { // transient segment: always need to write to disk return true; - } - // persistent segment; check if there were any updates or deletions in this segment - idx_t start_row_idx = segment->start - row_group.start; - idx_t end_row_idx = start_row_idx + segment->count; - if (col_data.HasChanges(start_row_idx, end_row_idx)) { - return true; + } else { + // persistent segment; check if there were any updates or deletions in this segment + idx_t start_row_idx = segment->start - row_group.start; + idx_t end_row_idx = start_row_idx + segment->count; + if (col_data.updates && col_data.updates->HasUpdates(start_row_idx, end_row_idx)) { + return true; + } } } return false; } -void ColumnDataCheckpointer::WritePersistentSegments(ColumnCheckpointState &state) { +void ColumnDataCheckpointer::WritePersistentSegments() { // all segments are persistent and there are no updates // we only need to write the metadata - - auto &col_data = state.column_data; - auto nodes = col_data.data.MoveSegments(); - for (idx_t segment_idx = 0; segment_idx < nodes.size(); segment_idx++) { auto segment = nodes[segment_idx].node.get(); auto pointer = segment->GetDataPointer(); @@ -382,51 +240,24 @@ void ColumnDataCheckpointer::WritePersistentSegments(ColumnCheckpointState &stat } } -void ColumnDataCheckpointer::Checkpoint() { - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - auto &state = checkpoint_states[i]; - auto &col_data = state.get().column_data; - has_changes.push_back(HasChanges(col_data)); +void ColumnDataCheckpointer::Checkpoint(vector> nodes_p) { + D_ASSERT(!nodes_p.empty()); + this->nodes = std::move(nodes_p); + // first check if any of the segments have changes + if (!HasChanges()) { + // no changes: only need to write the metadata for this column + WritePersistentSegments(); + } else { + // there are changes: rewrite the set of columns); + WriteToDisk(); } - - bool any_has_changes = false; - for (idx_t i = 0; i < has_changes.size(); i++) { - if (has_changes[i]) { - any_has_changes = true; - break; - } - } - if (!any_has_changes) { - // Nothing has undergone any changes, no need to checkpoint - // just move on to finalizing - return; - } - - WriteToDisk(); } -void ColumnDataCheckpointer::FinalizeCheckpoint() { - for (idx_t i = 0; i < checkpoint_states.size(); i++) { - auto &state = checkpoint_states[i].get(); - auto &col_data = state.column_data; - if (has_changes[i]) { - // Move the existing segments out of the column data - // they will be destructed at the end of the scope - auto to_delete = col_data.data.MoveSegments(); - } else { - WritePersistentSegments(state); - } - - // reset the compression function - col_data.compression.reset(); - // replace the old tree with the new one - auto new_segments = state.new_tree.MoveSegments(); - auto l = col_data.data.Lock(); - for (auto &new_segment : new_segments) { - col_data.AppendSegment(l, std::move(new_segment.node)); - } - col_data.ClearUpdates(); - } +CompressionFunction &ColumnDataCheckpointer::GetCompressionFunction(CompressionType compression_type) { + auto &db = GetDatabase(); + auto &column_type = GetType(); + auto &config = DBConfig::GetConfig(db); + return *config.GetCompressionFunction(compression_type, column_type.InternalType()); } } // namespace duckdb diff --git a/src/duckdb/src/storage/table/column_segment.cpp b/src/duckdb/src/storage/table/column_segment.cpp index 207c663fa..ae73eef9e 100644 --- a/src/duckdb/src/storage/table/column_segment.cpp +++ b/src/duckdb/src/storage/table/column_segment.cpp @@ -4,7 +4,6 @@ #include "duckdb/common/types/null_value.hpp" #include "duckdb/common/types/vector.hpp" #include "duckdb/main/config.hpp" -#include "duckdb/main/database.hpp" #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/constant_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" @@ -45,15 +44,19 @@ unique_ptr ColumnSegment::CreatePersistentSegment(DatabaseInstanc std::move(statistics), block_id, offset, segment_size, std::move(segment_state)); } -unique_ptr ColumnSegment::CreateTransientSegment(DatabaseInstance &db, CompressionFunction &function, - const LogicalType &type, const idx_t start, - const idx_t segment_size, const idx_t block_size) { +unique_ptr ColumnSegment::CreateTransientSegment(DatabaseInstance &db, const LogicalType &type, + const idx_t start, const idx_t segment_size, + const idx_t block_size) { // Allocate a buffer for the uncompressed segment. auto &buffer_manager = BufferManager::GetBufferManager(db); auto block = buffer_manager.RegisterTransientMemory(segment_size, block_size); - return make_uniq(db, std::move(block), type, ColumnSegmentType::TRANSIENT, start, 0U, function, + // Get the segment compression function. + auto &config = DBConfig::GetConfig(db); + auto function = config.GetCompressionFunction(CompressionType::COMPRESSION_UNCOMPRESSED, type.InternalType()); + + return make_uniq(db, std::move(block), type, ColumnSegmentType::TRANSIENT, start, 0U, *function, BaseStatistics::CreateEmpty(type), INVALID_BLOCK, 0U, segment_size); } @@ -67,7 +70,7 @@ ColumnSegment::ColumnSegment(DatabaseInstance &db, shared_ptr block const unique_ptr segment_state_p) : SegmentBase(start, count), db(db), type(type), type_size(GetTypeIdSize(type.InternalType())), - segment_type(segment_type), stats(std::move(statistics)), block(std::move(block_p)), function(function_p), + segment_type(segment_type), function(function_p), stats(std::move(statistics)), block(std::move(block_p)), block_id(block_id_p), offset(offset), segment_size(segment_size_p) { if (function.get().init_segment) { @@ -81,8 +84,8 @@ ColumnSegment::ColumnSegment(DatabaseInstance &db, shared_ptr block ColumnSegment::ColumnSegment(ColumnSegment &other, const idx_t start) : SegmentBase(start, other.count.load()), db(other.db), type(std::move(other.type)), - type_size(other.type_size), segment_type(other.segment_type), stats(std::move(other.stats)), - block(std::move(other.block)), function(other.function), block_id(other.block_id), offset(other.offset), + type_size(other.type_size), segment_type(other.segment_type), function(other.function), + stats(std::move(other.stats)), block(std::move(other.block)), block_id(other.block_id), offset(other.offset), segment_size(other.segment_size), segment_state(std::move(other.segment_state)) { // For constant segments (CompressionType::COMPRESSION_CONSTANT) the block is a nullptr. @@ -123,22 +126,6 @@ void ColumnSegment::Scan(ColumnScanState &state, idx_t scan_count, Vector &resul } } -void ColumnSegment::Select(ColumnScanState &state, idx_t scan_count, Vector &result, const SelectionVector &sel, - idx_t sel_count) { - if (!function.get().select) { - throw InternalException("ColumnSegment::Select not implemented for this compression method"); - } - function.get().select(*this, state, scan_count, result, sel, sel_count); -} - -void ColumnSegment::Filter(ColumnScanState &state, idx_t scan_count, Vector &result, SelectionVector &sel, - idx_t &sel_count, const TableFilter &filter) { - if (!function.get().filter) { - throw InternalException("ColumnSegment::Filter not implemented for this compression method"); - } - function.get().filter(*this, state, scan_count, result, sel, sel_count, filter); -} - void ColumnSegment::Skip(ColumnScanState &state) { function.get().skip(*this, state, state.row_index - state.internal_index); state.internal_index = state.row_index; @@ -228,12 +215,8 @@ void ColumnSegment::ConvertToPersistent(optional_ptr block_manager offset = 0; if (block_id == INVALID_BLOCK) { - // constant block: no need to write anything to disk besides the stats - // set up the compression function to constant + // constant block: reset the block buffer D_ASSERT(stats.statistics.IsConstant()); - auto &config = DBConfig::GetConfig(db); - function = *config.GetCompressionFunction(CompressionType::COMPRESSION_CONSTANT, type.InternalType()); - // reset the block buffer block.reset(); } else { D_ASSERT(!stats.statistics.IsConstant()); @@ -409,9 +392,6 @@ static idx_t TemplatedNullSelection(UnifiedVectorFormat &vdata, SelectionVector idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &vector, UnifiedVectorFormat &vdata, const TableFilter &filter, idx_t scan_count, idx_t &approved_tuple_count) { switch (filter.filter_type) { - case TableFilterType::OPTIONAL_FILTER: { - return scan_count; - } case TableFilterType::CONJUNCTION_OR: { // similar to the CONJUNCTION_AND, but we need to take care of the SelectionVectors (OR all of them) idx_t count_total = 0; @@ -450,6 +430,7 @@ idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &vector, Unifi } case TableFilterType::CONSTANT_COMPARISON: { auto &constant_filter = filter.Cast(); + // the inplace loops take the result as the last parameter switch (vector.GetType().InternalType()) { case PhysicalType::UINT8: { auto predicate = UTinyIntValue::Get(constant_filter.constant); @@ -554,8 +535,4 @@ idx_t ColumnSegment::FilterSelection(SelectionVector &sel, Vector &vector, Unifi } } -const CompressionFunction &ColumnSegment::GetCompressionFunction() { - return function.get(); -} - } // namespace duckdb diff --git a/src/duckdb/src/storage/table/list_column_data.cpp b/src/duckdb/src/storage/table/list_column_data.cpp index 03d8de085..e95b3caae 100644 --- a/src/duckdb/src/storage/table/list_column_data.cpp +++ b/src/duckdb/src/storage/table/list_column_data.cpp @@ -233,15 +233,15 @@ void ListColumnData::Append(BaseStatistics &stats, ColumnAppendState &state, Vec vdata.sel = FlatVector::IncrementalSelectionVector(); vdata.data = data_ptr_cast(append_offsets.get()); - // append the child vector - if (child_count > 0) { - child_column->Append(ListStats::GetChildStats(stats), state.child_appends[1], child_vector, child_count); - } // append the list offsets ColumnData::AppendData(stats, state, vdata, count); // append the validity data vdata.validity = append_mask; validity.AppendData(stats, state.child_appends[0], vdata, count); + // append the child vector + if (child_count > 0) { + child_column->Append(ListStats::GetChildStats(stats), state.child_appends[1], child_vector, child_count); + } } void ListColumnData::RevertAppend(row_t start_row) { diff --git a/src/duckdb/src/storage/table/row_group.cpp b/src/duckdb/src/storage/table/row_group.cpp index 38e173e83..f05edb99c 100644 --- a/src/duckdb/src/storage/table/row_group.cpp +++ b/src/duckdb/src/storage/table/row_group.cpp @@ -21,7 +21,6 @@ #include "duckdb/common/serializer/binary_serializer.hpp" #include "duckdb/planner/filter/conjunction_filter.hpp" #include "duckdb/planner/filter/struct_filter.hpp" -#include "duckdb/planner/filter/optional_filter.hpp" #include "duckdb/execution/adaptive_filter.hpp" namespace duckdb { @@ -95,14 +94,6 @@ idx_t RowGroup::GetColumnCount() const { return columns.size(); } -idx_t RowGroup::GetRowGroupSize() const { - return collection.get().GetRowGroupSize(); -} - -ColumnData &RowGroup::GetColumn(const StorageIndex &c) { - return GetColumn(c.GetPrimaryIndex()); -} - ColumnData &RowGroup::GetColumn(storage_t c) { D_ASSERT(c < columns.size()); if (!is_loaded) { @@ -153,8 +144,7 @@ void RowGroup::InitializeEmpty(const vector &types) { } } -void ColumnScanState::Initialize(const LogicalType &type, const vector &children, - optional_ptr options) { +void ColumnScanState::Initialize(const LogicalType &type, optional_ptr options) { // Register the options in the state scan_options = options; @@ -166,23 +156,8 @@ void ColumnScanState::Initialize(const LogicalType &type, const vector options) { - vector children; - Initialize(type, children, options); -} - void CollectionScanState::Initialize(const vector &types) { auto &column_ids = GetColumnIds(); column_scans = make_unsafe_uniq_array(column_ids.size()); for (idx_t i = 0; i < column_ids.size(); i++) { - if (column_ids[i].IsRowIdColumn()) { + if (column_ids[i] == COLUMN_IDENTIFIER_ROW_ID) { continue; } - auto col_id = column_ids[i].GetPrimaryIndex(); - column_scans[i].Initialize(types[col_id], column_ids[i].GetChildIndexes(), &GetOptions()); + column_scans[i].Initialize(types[column_ids[i]], &GetOptions()); } } @@ -238,7 +207,7 @@ bool RowGroup::InitializeScanWithOffset(CollectionScanState &state, idx_t vector D_ASSERT(state.column_scans); for (idx_t i = 0; i < column_ids.size(); i++) { const auto &column = column_ids[i]; - if (!column.IsRowIdColumn()) { + if (column != COLUMN_IDENTIFIER_ROW_ID) { auto &column_data = GetColumn(column); column_data.InitializeScanWithOffset(state.column_scans[i], row_number); state.column_scans[i].scan_options = &state.GetOptions(); @@ -265,7 +234,7 @@ bool RowGroup::InitializeScan(CollectionScanState &state) { D_ASSERT(state.column_scans); for (idx_t i = 0; i < column_ids.size(); i++) { auto column = column_ids[i]; - if (!column.IsRowIdColumn()) { + if (column != COLUMN_IDENTIFIER_ROW_ID) { auto &column_data = GetColumn(column); column_data.InitializeScan(state.column_scans[i]); state.column_scans[i].scan_options = &state.GetOptions(); @@ -394,22 +363,14 @@ void RowGroup::NextVector(CollectionScanState &state) { const auto &column_ids = state.GetColumnIds(); for (idx_t i = 0; i < column_ids.size(); i++) { const auto &column = column_ids[i]; - if (column.IsRowIdColumn()) { + if (column == COLUMN_IDENTIFIER_ROW_ID) { continue; } + D_ASSERT(column < columns.size()); GetColumn(column).Skip(state.column_scans[i]); } } -static FilterPropagateResult CheckRowIdFilter(TableFilter &filter, idx_t beg_row, idx_t end_row) { - // RowId columns dont have a zonemap, but we can trivially create stats to check the filter against. - BaseStatistics dummy_stats = NumericStats::CreateEmpty(LogicalType::ROW_TYPE); - NumericStats::SetMin(dummy_stats, UnsafeNumericCast(beg_row)); - NumericStats::SetMax(dummy_stats, UnsafeNumericCast(end_row)); - - return filter.CheckStatistics(dummy_stats); -} - bool RowGroup::CheckZonemap(ScanFilterInfo &filters) { auto &filter_list = filters.GetFilterList(); // new row group - label all filters as up for grabs again @@ -418,15 +379,7 @@ bool RowGroup::CheckZonemap(ScanFilterInfo &filters) { auto &entry = filter_list[i]; auto &filter = entry.filter; auto base_column_index = entry.table_column_index; - - FilterPropagateResult prune_result; - - if (base_column_index == COLUMN_IDENTIFIER_ROW_ID) { - prune_result = CheckRowIdFilter(filter, this->start, this->start + this->count); - } else { - prune_result = GetColumn(base_column_index).CheckZonemap(filter); - } - + auto prune_result = GetColumn(base_column_index).CheckZonemap(filter); if (prune_result == FilterPropagateResult::FILTER_ALWAYS_FALSE) { return false; } @@ -435,14 +388,44 @@ bool RowGroup::CheckZonemap(ScanFilterInfo &filters) { // label the filter as always true so we don't need to check it anymore filters.SetFilterAlwaysTrue(i); } - if (filter.filter_type == TableFilterType::OPTIONAL_FILTER) { - // these are only for row group checking, set as always true so we don't check it - filters.SetFilterAlwaysTrue(i); - } } return true; } +static idx_t GetFilterScanCount(ColumnScanState &state, TableFilter &filter) { + switch (filter.filter_type) { + case TableFilterType::STRUCT_EXTRACT: { + auto &struct_filter = filter.Cast(); + auto &child_state = state.child_states[1 + struct_filter.child_idx]; // +1 for validity + auto &child_filter = struct_filter.child_filter; + return GetFilterScanCount(child_state, *child_filter); + } + case TableFilterType::CONJUNCTION_AND: { + auto &conjunction_state = filter.Cast(); + idx_t max_count = 0; + for (auto &child_filter : conjunction_state.child_filters) { + max_count = std::max(GetFilterScanCount(state, *child_filter), max_count); + } + return max_count; + } + case TableFilterType::CONJUNCTION_OR: { + auto &conjunction_state = filter.Cast(); + idx_t max_count = 0; + for (auto &child_filter : conjunction_state.child_filters) { + max_count = std::max(GetFilterScanCount(state, *child_filter), max_count); + } + return max_count; + } + case TableFilterType::IS_NULL: + case TableFilterType::IS_NOT_NULL: + case TableFilterType::CONSTANT_COMPARISON: + return state.current->start + state.current->count; + default: { + throw NotImplementedException("Unimplemented filter type for zonemap"); + } + } +} + bool RowGroup::CheckZonemapSegments(CollectionScanState &state) { auto &filters = state.GetFilterInfo(); for (auto &entry : filters.GetFilterList()) { @@ -454,25 +437,11 @@ bool RowGroup::CheckZonemapSegments(CollectionScanState &state) { auto base_column_idx = entry.table_column_index; auto &filter = entry.filter; - FilterPropagateResult prune_result; - if (base_column_idx == COLUMN_IDENTIFIER_ROW_ID) { - prune_result = CheckRowIdFilter(filter, this->start, this->start + this->count); - } else { - prune_result = GetColumn(base_column_idx).CheckZonemap(state.column_scans[column_idx], filter); - } - + auto prune_result = GetColumn(base_column_idx).CheckZonemap(state.column_scans[column_idx], filter); if (prune_result != FilterPropagateResult::FILTER_ALWAYS_FALSE) { continue; } - - // check zone map segment. - auto &column_scan_state = state.column_scans[column_idx]; - auto current_segment = column_scan_state.current; - if (!current_segment) { - // no segment to skip - continue; - } - idx_t target_row = current_segment->start + current_segment->count; + idx_t target_row = GetFilterScanCount(state.column_scans[column_idx], filter); if (target_row >= state.max_row) { target_row = state.max_row; } @@ -512,13 +481,6 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s idx_t current_row = state.vector_index * STANDARD_VECTOR_SIZE; auto max_count = MinValue(STANDARD_VECTOR_SIZE, state.max_row_group_row - current_row); - // check the sampling info if we have to sample this chunk - if (state.GetSamplingInfo().do_system_sample && - state.random.NextRandom() > state.GetSamplingInfo().sample_rate) { - NextVector(state); - continue; - } - //! first check the zonemap if we have to scan this partition if (!CheckZonemapSegments(state)) { continue; @@ -556,7 +518,7 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s PrefetchState prefetch_state; for (idx_t i = 0; i < column_ids.size(); i++) { const auto &column = column_ids[i]; - if (!column.IsRowIdColumn()) { + if (column != COLUMN_IDENTIFIER_ROW_ID) { GetColumn(column).InitializePrefetch(prefetch_state, state.column_scans[i], max_count); } } @@ -569,7 +531,7 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s // scan all vectors completely: full scan without deletions or table filters for (idx_t i = 0; i < column_ids.size(); i++) { const auto &column = column_ids[i]; - if (column.IsRowIdColumn()) { + if (column == COLUMN_IDENTIFIER_ROW_ID) { // scan row id D_ASSERT(result.data[i].GetType().InternalType() == ROW_TYPE); result.data[i].Sequence(UnsafeNumericCast(this->start + current_row), 1, count); @@ -606,48 +568,10 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s // this filter is always true - skip it continue; } - - const auto scan_idx = filter.scan_column_index; - const auto column_idx = filter.table_column_index; - - if (column_idx == COLUMN_IDENTIFIER_ROW_ID) { - - // We do another quick statistics scan for row ids here - const auto rowid_start = this->start + current_row; - const auto rowid_end = this->start + current_row + max_count; - const auto prune_result = CheckRowIdFilter(filter.filter, rowid_start, rowid_end); - if (prune_result == FilterPropagateResult::FILTER_ALWAYS_FALSE) { - // We can just break out of the loop here. - approved_tuple_count = 0; - break; - } - - // Generate row ids - // Create sequence for row ids - D_ASSERT(result.data[i].GetType().InternalType() == ROW_TYPE); - result.data[i].SetVectorType(VectorType::FLAT_VECTOR); - auto result_data = FlatVector::GetData(result.data[i]); - for (size_t sel_idx = 0; sel_idx < approved_tuple_count; sel_idx++) { - result_data[sel.get_index(sel_idx)] = - UnsafeNumericCast(this->start + current_row + sel.get_index(sel_idx)); - } - - // Was this filter always true? If so, we dont need to apply it - if (prune_result == FilterPropagateResult::FILTER_ALWAYS_TRUE) { - continue; - } - - // Now apply the filter - UnifiedVectorFormat vdata; - result.data[i].ToUnifiedFormat(approved_tuple_count, vdata); - ColumnSegment::FilterSelection(sel, result.data[i], vdata, filter.filter, approved_tuple_count, - approved_tuple_count); - - } else { - auto &col_data = GetColumn(filter.table_column_index); - col_data.Filter(transaction, state.vector_index, state.column_scans[scan_idx], - result.data[scan_idx], sel, approved_tuple_count, filter.filter); - } + auto scan_idx = filter.scan_column_index; + auto &col_data = GetColumn(filter.table_column_index); + col_data.Select(transaction, state.vector_index, state.column_scans[scan_idx], + result.data[scan_idx], sel, approved_tuple_count, filter.filter); } for (auto &table_filter : filter_list) { if (table_filter.IsAlwaysTrue()) { @@ -662,8 +586,8 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s result.Reset(); // skip this vector in all the scans that were not scanned yet for (idx_t i = 0; i < column_ids.size(); i++) { - auto &col_idx = column_ids[i]; - if (col_idx.IsRowIdColumn()) { + auto col_idx = column_ids[i]; + if (col_idx == COLUMN_IDENTIFIER_ROW_ID) { continue; } if (has_filters && filter_info.ColumnHasFilters(i)) { @@ -681,9 +605,9 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s // column has already been scanned as part of the filtering process continue; } - auto &column = column_ids[i]; - if (column.IsRowIdColumn()) { - D_ASSERT(result.data[i].GetType().InternalType() == ROW_TYPE); + auto column = column_ids[i]; + if (column == COLUMN_IDENTIFIER_ROW_ID) { + D_ASSERT(result.data[i].GetType().InternalType() == PhysicalType::INT64); result.data[i].SetVectorType(VectorType::FLAT_VECTOR); auto result_data = FlatVector::GetData(result.data[i]); for (size_t sel_idx = 0; sel_idx < approved_tuple_count; sel_idx++) { @@ -693,11 +617,11 @@ void RowGroup::TemplatedScan(TransactionData transaction, CollectionScanState &s } else { auto &col_data = GetColumn(column); if (TYPE == TableScanType::TABLE_SCAN_REGULAR) { - col_data.Select(transaction, state.vector_index, state.column_scans[i], result.data[i], sel, - approved_tuple_count); + col_data.FilterScan(transaction, state.vector_index, state.column_scans[i], result.data[i], sel, + approved_tuple_count); } else { - col_data.SelectCommitted(state.vector_index, state.column_scans[i], result.data[i], sel, - approved_tuple_count, ALLOW_UPDATES); + col_data.FilterScanCommitted(state.vector_index, state.column_scans[i], result.data[i], sel, + approved_tuple_count, ALLOW_UPDATES); } } } @@ -823,14 +747,14 @@ bool RowGroup::Fetch(TransactionData transaction, idx_t row) { return vinfo->Fetch(transaction, row); } -void RowGroup::FetchRow(TransactionData transaction, ColumnFetchState &state, const vector &column_ids, +void RowGroup::FetchRow(TransactionData transaction, ColumnFetchState &state, const vector &column_ids, row_t row_id, DataChunk &result, idx_t result_idx) { for (idx_t col_idx = 0; col_idx < column_ids.size(); col_idx++) { - auto &column = column_ids[col_idx]; + auto column = column_ids[col_idx]; auto &result_vector = result.data[col_idx]; D_ASSERT(result_vector.GetVectorType() == VectorType::FLAT_VECTOR); D_ASSERT(!FlatVector::IsNull(result_vector, result_idx)); - if (column.IsRowIdColumn()) { + if (column == COLUMN_IDENTIFIER_ROW_ID) { // row id column: fill in the row ids D_ASSERT(result_vector.GetType().InternalType() == PhysicalType::INT64); result_vector.SetVectorType(VectorType::FLAT_VECTOR); @@ -845,11 +769,10 @@ void RowGroup::FetchRow(TransactionData transaction, ColumnFetchState &state, co } void RowGroup::AppendVersionInfo(TransactionData transaction, idx_t count) { - const idx_t row_group_size = GetRowGroupSize(); idx_t row_group_start = this->count.load(); idx_t row_group_end = row_group_start + count; - if (row_group_end > row_group_size) { - row_group_end = row_group_size; + if (row_group_end > Storage::ROW_GROUP_SIZE) { + row_group_end = Storage::ROW_GROUP_SIZE; } // create the version_info if it doesn't exist yet auto &vinfo = GetOrCreateVersionInfo(); @@ -1113,22 +1036,6 @@ RowGroupPointer RowGroup::Deserialize(Deserializer &deserializer) { return result; } -//===--------------------------------------------------------------------===// -// GetPartitionStats -//===--------------------------------------------------------------------===// -PartitionStatistics RowGroup::GetPartitionStats() const { - PartitionStatistics result; - result.row_start = start; - result.count = count; - if (HasUnloadedDeletes() || version_info.load().get()) { - // we have version info - approx count - result.count_type = CountType::COUNT_APPROXIMATE; - } else { - result.count_type = CountType::COUNT_EXACT; - } - return result; -} - //===--------------------------------------------------------------------===// // GetColumnSegmentInfo //===--------------------------------------------------------------------===// diff --git a/src/duckdb/src/storage/table/row_group_collection.cpp b/src/duckdb/src/storage/table/row_group_collection.cpp index 90a7236ff..4dfb19492 100644 --- a/src/duckdb/src/storage/table/row_group_collection.cpp +++ b/src/duckdb/src/storage/table/row_group_collection.cpp @@ -1,4 +1,5 @@ #include "duckdb/storage/table/row_group_collection.hpp" + #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/execution/expression_executor.hpp" #include "duckdb/execution/index/bound_index.hpp" @@ -52,17 +53,10 @@ unique_ptr RowGroupSegmentTree::LoadSegment() { //===--------------------------------------------------------------------===// // Row Group Collection //===--------------------------------------------------------------------===// -RowGroupCollection::RowGroupCollection(shared_ptr info_p, TableIOManager &io_manager, - vector types_p, idx_t row_start, idx_t total_rows) - : RowGroupCollection(std::move(info_p), io_manager.GetBlockManagerForRowData(), std::move(types_p), row_start, - total_rows, io_manager.GetRowGroupSize()) { -} - RowGroupCollection::RowGroupCollection(shared_ptr info_p, BlockManager &block_manager, - vector types_p, idx_t row_start_p, idx_t total_rows_p, - idx_t row_group_size_p) - : block_manager(block_manager), row_group_size(row_group_size_p), total_rows(total_rows_p), info(std::move(info_p)), - types(std::move(types_p)), row_start(row_start_p), allocation_size(0) { + vector types_p, idx_t row_start_p, idx_t total_rows_p) + : block_manager(block_manager), total_rows(total_rows_p), info(std::move(info_p)), types(std::move(types_p)), + row_start(row_start_p), allocation_size(0) { row_groups = make_shared_ptr(*this); } @@ -140,7 +134,7 @@ void RowGroupCollection::Verify() { //===--------------------------------------------------------------------===// // Scan //===--------------------------------------------------------------------===// -void RowGroupCollection::InitializeScan(CollectionScanState &state, const vector &column_ids, +void RowGroupCollection::InitializeScan(CollectionScanState &state, const vector &column_ids, TableFilterSet *table_filters) { auto row_group = row_groups->GetRootSegment(); D_ASSERT(row_group); @@ -156,7 +150,7 @@ void RowGroupCollection::InitializeCreateIndexScan(CreateIndexScanState &state) state.segment_lock = row_groups->Lock(); } -void RowGroupCollection::InitializeScanWithOffset(CollectionScanState &state, const vector &column_ids, +void RowGroupCollection::InitializeScanWithOffset(CollectionScanState &state, const vector &column_ids, idx_t start_row, idx_t end_row) { auto row_group = row_groups->GetSegment(start_row); D_ASSERT(row_group); @@ -241,11 +235,11 @@ bool RowGroupCollection::NextParallelScan(ClientContext &context, ParallelCollec return false; } -bool RowGroupCollection::Scan(DuckTransaction &transaction, const vector &column_ids, +bool RowGroupCollection::Scan(DuckTransaction &transaction, const vector &column_ids, const std::function &fun) { vector scan_types; for (idx_t i = 0; i < column_ids.size(); i++) { - scan_types.push_back(types[column_ids[i].GetPrimaryIndex()]); + scan_types.push_back(types[column_ids[i]]); } DataChunk chunk; chunk.Initialize(GetAllocator(), scan_types); @@ -268,10 +262,10 @@ bool RowGroupCollection::Scan(DuckTransaction &transaction, const vector &fun) { - vector column_ids; + vector column_ids; column_ids.reserve(types.size()); for (idx_t i = 0; i < types.size(); i++) { - column_ids.emplace_back(i); + column_ids.push_back(i); } return Scan(transaction, column_ids, fun); } @@ -279,7 +273,7 @@ bool RowGroupCollection::Scan(DuckTransaction &transaction, const std::function< //===--------------------------------------------------------------------===// // Fetch //===--------------------------------------------------------------------===// -void RowGroupCollection::Fetch(TransactionData transaction, DataChunk &result, const vector &column_ids, +void RowGroupCollection::Fetch(TransactionData transaction, DataChunk &result, const vector &column_ids, const Vector &row_identifiers, idx_t fetch_count, ColumnFetchState &state) { // figure out which row_group to fetch from auto row_ids = FlatVector::GetData(row_identifiers); @@ -309,8 +303,7 @@ void RowGroupCollection::Fetch(TransactionData transaction, DataChunk &result, c // Append //===--------------------------------------------------------------------===// TableAppendState::TableAppendState() - : row_group_append_state(*this), total_append_count(0), start_row_group(nullptr), transaction(0, 0), - hashes(LogicalType::HASH) { + : row_group_append_state(*this), total_append_count(0), start_row_group(nullptr), transaction(0, 0) { } TableAppendState::~TableAppendState() { @@ -352,7 +345,6 @@ void RowGroupCollection::InitializeAppend(TableAppendState &state) { } bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { - const idx_t row_group_size = GetRowGroupSize(); D_ASSERT(chunk.ColumnCount() == types.size()); chunk.Verify(); @@ -364,7 +356,7 @@ bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { auto current_row_group = state.row_group_append_state.row_group; // check how much we can fit into the current row_group idx_t append_count = - MinValue(remaining, row_group_size - state.row_group_append_state.offset_in_row_group); + MinValue(remaining, Storage::ROW_GROUP_SIZE - state.row_group_append_state.offset_in_row_group); if (append_count > 0) { auto previous_allocation_size = current_row_group->GetAllocationSize(); current_row_group->Append(state.row_group_append_state, chunk, append_count); @@ -396,30 +388,18 @@ bool RowGroupCollection::Append(DataChunk &chunk, TableAppendState &state) { } } state.current_row += row_t(total_append_count); - auto local_stats_lock = state.stats.GetLock(); - for (idx_t col_idx = 0; col_idx < types.size(); col_idx++) { - auto &column_stats = state.stats.GetStats(*local_stats_lock, col_idx); - column_stats.UpdateDistinctStatistics(chunk.data[col_idx], chunk.size(), state.hashes); - } - - auto &table_sample = state.stats.GetTableSampleRef(*local_stats_lock); - if (!table_sample.destroyed) { - D_ASSERT(table_sample.type == SampleType::RESERVOIR_SAMPLE); - table_sample.AddToReservoir(chunk); + state.stats.GetStats(*local_stats_lock, col_idx).UpdateDistinctStatistics(chunk.data[col_idx], chunk.size()); } - return new_row_group; } void RowGroupCollection::FinalizeAppend(TransactionData transaction, TableAppendState &state) { - const idx_t row_group_size = GetRowGroupSize(); - auto remaining = state.total_append_count; auto row_group = state.start_row_group; while (remaining > 0) { - auto append_count = MinValue(remaining, row_group_size - row_group->count); + auto append_count = MinValue(remaining, Storage::ROW_GROUP_SIZE - row_group->count); row_group->AppendVersionInfo(transaction, append_count); remaining -= append_count; row_group = row_groups->GetNextSegment(row_group); @@ -429,8 +409,8 @@ void RowGroupCollection::FinalizeAppend(TransactionData transaction, TableAppend state.total_append_count = 0; state.start_row_group = nullptr; - auto local_stats_lock = state.stats.GetLock(); auto global_stats_lock = stats.GetLock(); + auto local_stats_lock = state.stats.GetLock(); for (idx_t col_idx = 0; col_idx < types.size(); col_idx++) { auto &global_stats = stats.GetStats(*global_stats_lock, col_idx); if (!global_stats.HasDistinctStats()) { @@ -443,22 +423,6 @@ void RowGroupCollection::FinalizeAppend(TransactionData transaction, TableAppend global_stats.DistinctStats().Merge(local_stats.DistinctStats()); } - auto local_sample = state.stats.GetTableSample(*local_stats_lock); - auto global_sample = stats.GetTableSample(*global_stats_lock); - - if (local_sample && global_sample) { - D_ASSERT(global_sample->type == SampleType::RESERVOIR_SAMPLE); - auto &reservoir_sample = global_sample->Cast(); - reservoir_sample.Merge(std::move(local_sample)); - // initialize the thread local sample again - auto new_local_sample = make_uniq(reservoir_sample.GetSampleCount()); - state.stats.SetTableSample(*local_stats_lock, std::move(new_local_sample)); - stats.SetTableSample(*global_stats_lock, std::move(global_sample)); - } else { - state.stats.SetTableSample(*local_stats_lock, std::move(local_sample)); - stats.SetTableSample(*global_stats_lock, std::move(global_sample)); - } - Verify(); } @@ -606,11 +570,6 @@ idx_t RowGroupCollection::Delete(TransactionData transaction, DataTable &table, } delete_count += row_group->Delete(transaction, table, ids + start, pos - start); } while (pos < count); - - // When deleting destroy the sample. - auto stats_guard = stats.GetLock(); - stats.DestroyTableSample(*stats_guard); - return delete_count; } @@ -648,9 +607,6 @@ void RowGroupCollection::Update(TransactionData transaction, row_t *ids, const v stats.MergeStats(*l, column_id.index, *row_group->GetStatistics(column_id.index)); } } while (pos < updates.size()); - // on update destroy the sample - auto stats_guard = stats.GetLock(); - stats.DestroyTableSample(*stats_guard); } void RowGroupCollection::RemoveFromIndexes(TableIndexList &indexes, Vector &row_identifiers, idx_t count) { @@ -659,10 +615,10 @@ void RowGroupCollection::RemoveFromIndexes(TableIndexList &indexes, Vector &row_ // initialize the fetch state // FIXME: we do not need to fetch all columns, only the columns required by the indices! TableScanState state; - vector column_ids; + vector column_ids; column_ids.reserve(types.size()); for (idx_t i = 0; i < types.size(); i++) { - column_ids.emplace_back(i); + column_ids.push_back(i); } state.Initialize(std::move(column_ids)); state.table_state.max_row = row_start + total_rows; @@ -802,7 +758,6 @@ class VacuumTask : public BaseCheckpointTask { void ExecuteTask() override { auto &collection = checkpoint_state.collection; - const idx_t row_group_size = collection.GetRowGroupSize(); auto &types = collection.GetTypes(); // create the new set of target row groups (initially empty) vector> new_row_groups; @@ -810,7 +765,7 @@ class VacuumTask : public BaseCheckpointTask { idx_t row_group_rows = merge_rows; idx_t start = row_start; for (idx_t target_idx = 0; target_idx < target_count; target_idx++) { - idx_t current_row_group_rows = MinValue(row_group_rows, row_group_size); + idx_t current_row_group_rows = MinValue(row_group_rows, Storage::ROW_GROUP_SIZE); auto new_row_group = make_uniq(collection, start, current_row_group_rows); new_row_group->InitializeEmpty(types); new_row_groups.push_back(std::move(new_row_group)); @@ -823,9 +778,9 @@ class VacuumTask : public BaseCheckpointTask { DataChunk scan_chunk; scan_chunk.Initialize(Allocator::DefaultAllocator(), types); - vector column_ids; + vector column_ids; for (idx_t c = 0; c < types.size(); c++) { - column_ids.emplace_back(c); + column_ids.push_back(c); } idx_t current_append_idx = 0; @@ -860,12 +815,13 @@ class VacuumTask : public BaseCheckpointTask { scan_chunk.Flatten(); idx_t remaining = scan_chunk.size(); while (remaining > 0) { - idx_t append_count = MinValue(remaining, row_group_size - append_counts[current_append_idx]); + idx_t append_count = + MinValue(remaining, Storage::ROW_GROUP_SIZE - append_counts[current_append_idx]); new_row_groups[current_append_idx]->Append(append_state.row_group_append_state, scan_chunk, append_count); append_counts[current_append_idx] += append_count; remaining -= append_count; - const bool row_group_full = append_counts[current_append_idx] == row_group_size; + const bool row_group_full = append_counts[current_append_idx] == Storage::ROW_GROUP_SIZE; const bool last_row_group = current_append_idx + 1 >= new_row_groups.size(); if (remaining > 0 || (row_group_full && !last_row_group)) { // move to the next row group @@ -961,9 +917,8 @@ bool RowGroupCollection::ScheduleVacuumTasks(CollectionCheckpointState &checkpoi // hence we target_count should be less than merge_count for a marge to be worth it // we greedily prefer to merge to the lowest target_count // i.e. we prefer to merge 2 row groups into 1, than 3 row groups into 2 - const idx_t row_group_size = GetRowGroupSize(); for (target_count = 1; target_count <= MAX_MERGE_COUNT; target_count++) { - auto total_target_size = target_count * row_group_size; + auto total_target_size = target_count * Storage::ROW_GROUP_SIZE; merge_count = 0; merge_rows = 0; for (next_idx = segment_idx; next_idx < checkpoint_state.segments.size(); next_idx++) { @@ -1014,38 +969,29 @@ void RowGroupCollection::Checkpoint(TableDataWriter &writer, TableStatistics &gl VacuumState vacuum_state; InitializeVacuumState(checkpoint_state, vacuum_state, segments); - - try { - // schedule tasks - idx_t total_vacuum_tasks = 0; - auto &config = DBConfig::GetConfig(writer.GetDatabase()); - - for (idx_t segment_idx = 0; segment_idx < segments.size(); segment_idx++) { - auto &entry = segments[segment_idx]; - auto vacuum_tasks = ScheduleVacuumTasks(checkpoint_state, vacuum_state, segment_idx, - total_vacuum_tasks < config.options.max_vacuum_tasks); - if (vacuum_tasks) { - // vacuum tasks were scheduled - don't schedule a checkpoint task yet - total_vacuum_tasks++; - continue; - } - if (!entry.node) { - // row group was vacuumed/dropped - skip - continue; - } - // schedule a checkpoint task for this row group - entry.node->MoveToCollection(*this, vacuum_state.row_start); - auto checkpoint_task = GetCheckpointTask(checkpoint_state, segment_idx); - checkpoint_state.executor.ScheduleTask(std::move(checkpoint_task)); - vacuum_state.row_start += entry.node->count; + // schedule tasks + idx_t total_vacuum_tasks = 0; + auto &config = DBConfig::GetConfig(writer.GetDatabase()); + for (idx_t segment_idx = 0; segment_idx < segments.size(); segment_idx++) { + auto &entry = segments[segment_idx]; + auto vacuum_tasks = ScheduleVacuumTasks(checkpoint_state, vacuum_state, segment_idx, + total_vacuum_tasks < config.options.max_vacuum_tasks); + if (vacuum_tasks) { + // vacuum tasks were scheduled - don't schedule a checkpoint task yet + total_vacuum_tasks++; + continue; } - } catch (const std::exception &e) { - ErrorData error(e); - checkpoint_state.executor.PushError(std::move(error)); - checkpoint_state.executor.WorkOnTasks(); // ensure all tasks have completed first before rethrowing - throw; + if (!entry.node) { + // row group was vacuumed/dropped - skip + continue; + } + // schedule a checkpoint task for this row group + entry.node->MoveToCollection(*this, vacuum_state.row_start); + auto checkpoint_task = GetCheckpointTask(checkpoint_state, segment_idx); + checkpoint_state.executor.ScheduleTask(std::move(checkpoint_task)); + vacuum_state.row_start += entry.node->count; } - // all tasks have been successfully scheduled - execute tasks until we are done + // all tasks have been scheduled - execute tasks until we are done checkpoint_state.executor.WorkOnTasks(); // no errors - finalize the row groups @@ -1085,17 +1031,6 @@ void RowGroupCollection::CommitDropTable() { } } -//===--------------------------------------------------------------------===// -// GetPartitionStats -//===--------------------------------------------------------------------===// -vector RowGroupCollection::GetPartitionStats() const { - vector result; - for (auto &row_group : row_groups->Segments()) { - result.push_back(row_group.GetPartitionStats()); - } - return result; -} - //===--------------------------------------------------------------------===// // GetColumnSegmentInfo //===--------------------------------------------------------------------===// @@ -1115,8 +1050,8 @@ shared_ptr RowGroupCollection::AddColumn(ClientContext &cont idx_t new_column_idx = types.size(); auto new_types = types; new_types.push_back(new_column.GetType()); - auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, - total_rows.load(), row_group_size); + auto result = + make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); DataChunk dummy_chunk; Vector default_vector(new_column.GetType()); @@ -1134,9 +1069,6 @@ shared_ptr RowGroupCollection::AddColumn(ClientContext &cont result->row_groups->AppendSegment(std::move(new_row_group)); } - // When adding a column destroy the sample - stats.DestroyTableSample(*lock); - return result; } @@ -1145,13 +1077,10 @@ shared_ptr RowGroupCollection::RemoveColumn(idx_t col_idx) { auto new_types = types; new_types.erase_at(col_idx); - auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, - total_rows.load(), row_group_size); + auto result = + make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); result->stats.InitializeRemoveColumn(stats, col_idx); - auto result_lock = result->stats.GetLock(); - result->stats.DestroyTableSample(*result_lock); - for (auto ¤t_row_group : row_groups->Segments()) { auto new_row_group = current_row_group.RemoveColumn(*result, col_idx); result->row_groups->AppendSegment(std::move(new_row_group)); @@ -1161,22 +1090,21 @@ shared_ptr RowGroupCollection::RemoveColumn(idx_t col_idx) { shared_ptr RowGroupCollection::AlterType(ClientContext &context, idx_t changed_idx, const LogicalType &target_type, - vector bound_columns, - Expression &cast_expr) { + vector bound_columns, Expression &cast_expr) { D_ASSERT(changed_idx < types.size()); auto new_types = types; new_types[changed_idx] = target_type; - auto result = make_shared_ptr(info, block_manager, std::move(new_types), row_start, - total_rows.load(), row_group_size); + auto result = + make_shared_ptr(info, block_manager, std::move(new_types), row_start, total_rows.load()); result->stats.InitializeAlterType(stats, changed_idx, target_type); vector scan_types; for (idx_t i = 0; i < bound_columns.size(); i++) { - if (bound_columns[i].IsRowIdColumn()) { + if (bound_columns[i] == COLUMN_IDENTIFIER_ROW_ID) { scan_types.emplace_back(LogicalType::ROW_TYPE); } else { - scan_types.push_back(types[bound_columns[i].GetPrimaryIndex()]); + scan_types.push_back(types[bound_columns[i]]); } } DataChunk scan_chunk; @@ -1198,6 +1126,7 @@ shared_ptr RowGroupCollection::AlterType(ClientContext &cont new_row_group->MergeIntoStatistics(changed_idx, changed_stats.Statistics()); result->row_groups->AppendSegment(std::move(new_row_group)); } + return result; } @@ -1205,46 +1134,40 @@ void RowGroupCollection::VerifyNewConstraint(DataTable &parent, const BoundConst if (total_rows == 0) { return; } - - // Scan the original table for NULL values. + // scan the original table, check if there's any null value auto ¬_null_constraint = constraint.Cast(); vector scan_types; auto physical_index = not_null_constraint.index.index; D_ASSERT(physical_index < types.size()); - scan_types.push_back(types[physical_index]); DataChunk scan_chunk; scan_chunk.Initialize(GetAllocator(), scan_types); - vector column_ids; - column_ids.emplace_back(physical_index); - - // Use SCAN_COMMITTED to scan the latest data. CreateIndexScanState state; - auto scan_type = TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED; - state.Initialize(column_ids, nullptr); - InitializeScan(state.table_state, column_ids, nullptr); - + vector cids; + cids.push_back(physical_index); + // Use ScanCommitted to scan the latest committed data + state.Initialize(cids, nullptr); + InitializeScan(state.table_state, cids, nullptr); InitializeCreateIndexScan(state); - while (true) { scan_chunk.Reset(); - state.table_state.ScanCommitted(scan_chunk, state.segment_lock, scan_type); + state.table_state.ScanCommitted(scan_chunk, state.segment_lock, + TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED); if (scan_chunk.size() == 0) { break; } - - // Verify the NOT NULL constraint. + // Check constraint if (VectorOperations::HasNull(scan_chunk.data[0], scan_chunk.size())) { - auto name = parent.Columns()[physical_index].GetName(); - throw ConstraintException("NOT NULL constraint failed: %s.%s", info->GetTableName(), name); + throw ConstraintException("NOT NULL constraint failed: %s.%s", info->GetTableName(), + parent.Columns()[physical_index].GetName()); } } } //===--------------------------------------------------------------------===// // Statistics -//===---------------------------------------------------------------r-----===// +//===--------------------------------------------------------------------===// void RowGroupCollection::CopyStats(TableStatistics &other_stats) { stats.CopyStats(other_stats); } @@ -1253,18 +1176,6 @@ unique_ptr RowGroupCollection::CopyStats(column_t column_id) { return stats.CopyStats(column_id); } -unique_ptr RowGroupCollection::GetSample() { - auto lock = stats.GetLock(); - auto &sample = stats.GetTableSampleRef(*lock); - if (!sample.destroyed) { - D_ASSERT(sample.type == SampleType::RESERVOIR_SAMPLE); - auto ret = sample.Copy(); - ret->Cast().EvictOverBudgetSamples(); - return ret; - } - return nullptr; -} - void RowGroupCollection::SetDistinct(column_t column_id, unique_ptr distinct_stats) { D_ASSERT(column_id != COLUMN_IDENTIFIER_ROW_ID); auto stats_lock = stats.GetLock(); diff --git a/src/duckdb/src/storage/table/row_version_manager.cpp b/src/duckdb/src/storage/table/row_version_manager.cpp index a3b47a56e..4a166f059 100644 --- a/src/duckdb/src/storage/table/row_version_manager.cpp +++ b/src/duckdb/src/storage/table/row_version_manager.cpp @@ -14,9 +14,9 @@ void RowVersionManager::SetStart(idx_t new_start) { lock_guard l(version_lock); this->start = new_start; idx_t current_start = start; - for (auto &info : vector_info) { - if (info) { - info->start = current_start; + for (idx_t i = 0; i < Storage::ROW_GROUP_VECTOR_COUNT; i++) { + if (vector_info[i]) { + vector_info[i]->start = current_start; } current_start += STANDARD_VECTOR_SIZE; } @@ -26,7 +26,7 @@ idx_t RowVersionManager::GetCommittedDeletedCount(idx_t count) { lock_guard l(version_lock); idx_t deleted_count = 0; for (idx_t r = 0, i = 0; r < count; r += STANDARD_VECTOR_SIZE, i++) { - if (i >= vector_info.size() || !vector_info[i]) { + if (!vector_info[i]) { continue; } idx_t max_count = MinValue(STANDARD_VECTOR_SIZE, count - r); @@ -39,9 +39,6 @@ idx_t RowVersionManager::GetCommittedDeletedCount(idx_t count) { } optional_ptr RowVersionManager::GetChunkInfo(idx_t vector_idx) { - if (vector_idx >= vector_info.size()) { - return nullptr; - } return vector_info[vector_idx].get(); } @@ -75,27 +72,12 @@ bool RowVersionManager::Fetch(TransactionData transaction, idx_t row) { return info->Fetch(transaction, UnsafeNumericCast(row - vector_index * STANDARD_VECTOR_SIZE)); } -void RowVersionManager::FillVectorInfo(idx_t vector_idx) { - if (vector_idx < vector_info.size()) { - return; - } - vector_info.reserve(vector_idx + 1); - for (idx_t i = vector_info.size(); i <= vector_idx; i++) { - vector_info.emplace_back(); - } -} - void RowVersionManager::AppendVersionInfo(TransactionData transaction, idx_t count, idx_t row_group_start, idx_t row_group_end) { lock_guard lock(version_lock); has_changes = true; idx_t start_vector_idx = row_group_start / STANDARD_VECTOR_SIZE; idx_t end_vector_idx = (row_group_end - 1) / STANDARD_VECTOR_SIZE; - - // fill-up vector_info - FillVectorInfo(end_vector_idx); - - // insert the version info nodes for (idx_t vector_idx = start_vector_idx; vector_idx <= end_vector_idx; vector_idx++) { idx_t vector_start = vector_idx == start_vector_idx ? row_group_start - start_vector_idx * STANDARD_VECTOR_SIZE : 0; @@ -161,7 +143,7 @@ void RowVersionManager::CleanupAppend(transaction_t lowest_active_transaction, i // not written fully - skip continue; } - if (vector_idx >= vector_info.size() || !vector_info[vector_idx]) { + if (!vector_info[vector_idx]) { // already vacuumed - skip continue; } @@ -178,14 +160,12 @@ void RowVersionManager::CleanupAppend(transaction_t lowest_active_transaction, i void RowVersionManager::RevertAppend(idx_t start_row) { lock_guard lock(version_lock); idx_t start_vector_idx = (start_row + (STANDARD_VECTOR_SIZE - 1)) / STANDARD_VECTOR_SIZE; - for (idx_t vector_idx = start_vector_idx; vector_idx < vector_info.size(); vector_idx++) { + for (idx_t vector_idx = start_vector_idx; vector_idx < Storage::ROW_GROUP_VECTOR_COUNT; vector_idx++) { vector_info[vector_idx].reset(); } } ChunkVectorInfo &RowVersionManager::GetVectorInfo(idx_t vector_idx) { - FillVectorInfo(vector_idx); - if (!vector_info[vector_idx]) { // no info yet: create it vector_info[vector_idx] = make_uniq(start + vector_idx * STANDARD_VECTOR_SIZE); @@ -226,7 +206,7 @@ vector RowVersionManager::Checkpoint(MetadataManager &manager) } // first count how many ChunkInfo's we need to deserialize vector>> to_serialize; - for (idx_t vector_idx = 0; vector_idx < vector_info.size(); vector_idx++) { + for (idx_t vector_idx = 0; vector_idx < Storage::ROW_GROUP_VECTOR_COUNT; vector_idx++) { auto chunk_info = vector_info[vector_idx].get(); if (!chunk_info) { continue; @@ -268,13 +248,10 @@ shared_ptr RowVersionManager::Deserialize(MetaBlockPointer de D_ASSERT(chunk_count > 0); for (idx_t i = 0; i < chunk_count; i++) { idx_t vector_index = source.Read(); - if (vector_index * STANDARD_VECTOR_SIZE >= Storage::MAX_ROW_GROUP_SIZE) { - throw IOException("In DeserializeDeletes, vector_index %llu is out of range for the max row group size of " - "%llu. Corrupted file?", - vector_index, Storage::MAX_ROW_GROUP_SIZE); + if (vector_index >= Storage::ROW_GROUP_VECTOR_COUNT) { + throw InternalException( + "In DeserializeDeletes, vector_index is out of range for the row group. Corrupted file?"); } - - version_info->FillVectorInfo(vector_index); version_info->vector_info[vector_index] = ChunkInfo::Read(source); } version_info->has_changes = false; diff --git a/src/duckdb/src/storage/table/scan_state.cpp b/src/duckdb/src/storage/table/scan_state.cpp index adeccde91..5eb0adf74 100644 --- a/src/duckdb/src/storage/table/scan_state.cpp +++ b/src/duckdb/src/storage/table/scan_state.cpp @@ -16,19 +16,14 @@ TableScanState::TableScanState() : table_state(*this), local_state(*this) { TableScanState::~TableScanState() { } -void TableScanState::Initialize(vector column_ids_p, optional_ptr table_filters, - optional_ptr table_sampling) { +void TableScanState::Initialize(vector column_ids_p, optional_ptr table_filters) { this->column_ids = std::move(column_ids_p); if (table_filters) { filters.Initialize(*table_filters, column_ids); } - if (table_sampling) { - sampling_info.do_system_sample = table_sampling->method == SampleMethod::SYSTEM_SAMPLE; - sampling_info.sample_rate = table_sampling->sample_size.GetValue() / 100.0; - } } -const vector &TableScanState::GetColumnIds() { +const vector &TableScanState::GetColumnIds() { D_ASSERT(!column_ids.empty()); return column_ids; } @@ -40,16 +35,11 @@ ScanFilterInfo &TableScanState::GetFilterInfo() { return filters; } -ScanSamplingInfo &TableScanState::GetSamplingInfo() { - return sampling_info; -} - -ScanFilter::ScanFilter(idx_t index, const vector &column_ids, TableFilter &filter) - : scan_column_index(index), table_column_index(column_ids[index].GetPrimaryIndex()), filter(filter), - always_true(false) { +ScanFilter::ScanFilter(idx_t index, const vector &column_ids, TableFilter &filter) + : scan_column_index(index), table_column_index(column_ids[index]), filter(filter), always_true(false) { } -void ScanFilterInfo::Initialize(TableFilterSet &filters, const vector &column_ids) { +void ScanFilterInfo::Initialize(TableFilterSet &filters, const vector &column_ids) { D_ASSERT(!filters.filters.empty()); table_filters = &filters; adaptive_filter = make_uniq(filters); @@ -143,7 +133,7 @@ void ColumnScanState::Next(idx_t count) { } } -const vector &CollectionScanState::GetColumnIds() { +const vector &CollectionScanState::GetColumnIds() { return parent.GetColumnIds(); } @@ -153,10 +143,6 @@ ScanFilterInfo &CollectionScanState::GetFilterInfo() { return parent.GetFilterInfo(); } -ScanSamplingInfo &CollectionScanState::GetSamplingInfo() { - return parent.GetSamplingInfo(); -} - TableScanOptions &CollectionScanState::GetOptions() { return parent.options; } @@ -167,7 +153,7 @@ ParallelCollectionScanState::ParallelCollectionScanState() CollectionScanState::CollectionScanState(TableScanState &parent_p) : row_group(nullptr), vector_index(0), max_row_group_row(0), row_groups(nullptr), max_row(0), batch_index(0), - valid_sel(STANDARD_VECTOR_SIZE), random(-1), parent(parent_p) { + valid_sel(STANDARD_VECTOR_SIZE), parent(parent_p) { } bool CollectionScanState::Scan(DuckTransaction &transaction, DataChunk &result) { diff --git a/src/duckdb/src/storage/table/standard_column_data.cpp b/src/duckdb/src/storage/table/standard_column_data.cpp index 6b6311c3d..1ef5da3c7 100644 --- a/src/duckdb/src/storage/table/standard_column_data.cpp +++ b/src/duckdb/src/storage/table/standard_column_data.cpp @@ -7,7 +7,6 @@ #include "duckdb/storage/table/column_checkpoint_state.hpp" #include "duckdb/common/serializer/serializer.hpp" #include "duckdb/common/serializer/deserializer.hpp" -#include "duckdb/storage/table/column_data_checkpointer.hpp" namespace duckdb { @@ -58,10 +57,8 @@ void StandardColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t idx_t StandardColumnData::Scan(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, idx_t target_count) { D_ASSERT(state.row_index == state.child_states[0].row_index); - auto scan_type = GetVectorScanType(state, target_count, result); - auto mode = ScanVectorMode::REGULAR_SCAN; - auto scan_count = ScanVector(transaction, vector_index, state, result, target_count, scan_type, mode); - validity.ScanVector(transaction, vector_index, state.child_states[0], result, target_count, scan_type, mode); + auto scan_count = ColumnData::Scan(transaction, vector_index, state, result, target_count); + validity.Scan(transaction, vector_index, state.child_states[0], result, target_count); return scan_count; } @@ -79,47 +76,6 @@ idx_t StandardColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_ return scan_count; } -void StandardColumnData::Filter(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t &count, const TableFilter &filter) { - // check if we can do a specialized select - // the compression functions need to support this - auto compression = GetCompressionFunction(); - bool has_filter = compression && compression->filter; - auto validity_compression = validity.GetCompressionFunction(); - bool validity_has_filter = validity_compression && validity_compression->filter; - auto target_count = GetVectorCount(vector_index); - auto scan_type = GetVectorScanType(state, target_count, result); - bool scan_entire_vector = scan_type == ScanVectorType::SCAN_ENTIRE_VECTOR; - bool verify_fetch_row = state.scan_options && state.scan_options->force_fetch_row; - if (!has_filter || !validity_has_filter || !scan_entire_vector || verify_fetch_row) { - // we are not scanning an entire vector - this can have several causes (updates, etc) - ColumnData::Filter(transaction, vector_index, state, result, sel, count, filter); - return; - } - FilterVector(state, result, target_count, sel, count, filter); - validity.FilterVector(state.child_states[0], result, target_count, sel, count, filter); -} - -void StandardColumnData::Select(TransactionData transaction, idx_t vector_index, ColumnScanState &state, Vector &result, - SelectionVector &sel, idx_t sel_count) { - // check if we can do a specialized select - // the compression functions need to support this - auto compression = GetCompressionFunction(); - bool has_select = compression && compression->select; - auto validity_compression = validity.GetCompressionFunction(); - bool validity_has_select = validity_compression && validity_compression->select; - auto target_count = GetVectorCount(vector_index); - auto scan_type = GetVectorScanType(state, target_count, result); - bool scan_entire_vector = scan_type == ScanVectorType::SCAN_ENTIRE_VECTOR; - if (!has_select || !validity_has_select || !scan_entire_vector) { - // we are not scanning an entire vector - this can have several causes (updates, etc) - ColumnData::Select(transaction, vector_index, state, result, sel, sel_count); - return; - } - SelectVector(state, result, target_count, sel, sel_count); - validity.SelectVector(state.child_states[0], result, target_count, sel, sel_count); -} - void StandardColumnData::InitializeAppend(ColumnAppendState &state) { ColumnData::InitializeAppend(state); ColumnAppendState child_append; @@ -232,29 +188,10 @@ unique_ptr StandardColumnData::Checkpoint(RowGroup &row_g // to prevent reading the validity data immediately after it is checkpointed we first checkpoint the main column // this is necessary for concurrent checkpointing as due to the partial block manager checkpointed data might be // flushed to disk by a different thread than the one that wrote it, causing a data race - auto base_state = CreateCheckpointState(row_group, checkpoint_info.info.manager); - base_state->global_stats = BaseStatistics::CreateEmpty(type).ToUnique(); - auto validity_state_p = validity.CreateCheckpointState(row_group, checkpoint_info.info.manager); - validity_state_p->global_stats = BaseStatistics::CreateEmpty(validity.type).ToUnique(); - - auto &validity_state = *validity_state_p; + auto base_state = ColumnData::Checkpoint(row_group, checkpoint_info); + auto validity_state = validity.Checkpoint(row_group, checkpoint_info); auto &checkpoint_state = base_state->Cast(); - checkpoint_state.validity_state = std::move(validity_state_p); - - auto &nodes = data.ReferenceSegments(); - if (nodes.empty()) { - // empty table: flush the empty list - return base_state; - } - - vector> checkpoint_states; - checkpoint_states.emplace_back(checkpoint_state); - checkpoint_states.emplace_back(validity_state); - - ColumnDataCheckpointer checkpointer(checkpoint_states, GetDatabase(), row_group, checkpoint_info); - checkpointer.Checkpoint(); - checkpointer.FinalizeCheckpoint(); - + checkpoint_state.validity_state = std::move(validity_state); return base_state; } diff --git a/src/duckdb/src/storage/table/struct_column_data.cpp b/src/duckdb/src/storage/table/struct_column_data.cpp index 5d1506b5c..9ac2b0c0f 100644 --- a/src/duckdb/src/storage/table/struct_column_data.cpp +++ b/src/duckdb/src/storage/table/struct_column_data.cpp @@ -43,9 +43,6 @@ idx_t StructColumnData::GetMaxEntry() { void StructColumnData::InitializePrefetch(PrefetchState &prefetch_state, ColumnScanState &scan_state, idx_t rows) { validity.InitializePrefetch(prefetch_state, scan_state.child_states[0], rows); for (idx_t i = 0; i < sub_columns.size(); i++) { - if (!scan_state.scan_child_column[i]) { - continue; - } sub_columns[i]->InitializePrefetch(prefetch_state, scan_state.child_states[i + 1], rows); } } @@ -60,9 +57,6 @@ void StructColumnData::InitializeScan(ColumnScanState &state) { // initialize the sub-columns for (idx_t i = 0; i < sub_columns.size(); i++) { - if (!state.scan_child_column[i]) { - continue; - } sub_columns[i]->InitializeScan(state.child_states[i + 1]); } } @@ -77,9 +71,6 @@ void StructColumnData::InitializeScanWithOffset(ColumnScanState &state, idx_t ro // initialize the sub-columns for (idx_t i = 0; i < sub_columns.size(); i++) { - if (!state.scan_child_column[i]) { - continue; - } sub_columns[i]->InitializeScanWithOffset(state.child_states[i + 1], row_idx); } } @@ -89,14 +80,7 @@ idx_t StructColumnData::Scan(TransactionData transaction, idx_t vector_index, Co auto scan_count = validity.Scan(transaction, vector_index, state.child_states[0], result, target_count); auto &child_entries = StructVector::GetEntries(result); for (idx_t i = 0; i < sub_columns.size(); i++) { - auto &target_vector = *child_entries[i]; - if (!state.scan_child_column[i]) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - continue; - } - sub_columns[i]->Scan(transaction, vector_index, state.child_states[i + 1], target_vector, target_count); + sub_columns[i]->Scan(transaction, vector_index, state.child_states[i + 1], *child_entries[i], target_count); } return scan_count; } @@ -106,14 +90,7 @@ idx_t StructColumnData::ScanCommitted(idx_t vector_index, ColumnScanState &state auto scan_count = validity.ScanCommitted(vector_index, state.child_states[0], result, allow_updates, target_count); auto &child_entries = StructVector::GetEntries(result); for (idx_t i = 0; i < sub_columns.size(); i++) { - auto &target_vector = *child_entries[i]; - if (!state.scan_child_column[i]) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - continue; - } - sub_columns[i]->ScanCommitted(vector_index, state.child_states[i + 1], target_vector, allow_updates, + sub_columns[i]->ScanCommitted(vector_index, state.child_states[i + 1], *child_entries[i], allow_updates, target_count); } return scan_count; @@ -123,14 +100,7 @@ idx_t StructColumnData::ScanCount(ColumnScanState &state, Vector &result, idx_t auto scan_count = validity.ScanCount(state.child_states[0], result, count); auto &child_entries = StructVector::GetEntries(result); for (idx_t i = 0; i < sub_columns.size(); i++) { - auto &target_vector = *child_entries[i]; - if (!state.scan_child_column[i]) { - // if we are not scanning this vector - set it to NULL - target_vector.SetVectorType(VectorType::CONSTANT_VECTOR); - ConstantVector::SetNull(target_vector, true); - continue; - } - sub_columns[i]->ScanCount(state.child_states[i + 1], target_vector, count); + sub_columns[i]->ScanCount(state.child_states[i + 1], *child_entries[i], count); } return scan_count; } @@ -140,9 +110,6 @@ void StructColumnData::Skip(ColumnScanState &state, idx_t count) { // skip inside the sub-columns for (idx_t child_idx = 0; child_idx < sub_columns.size(); child_idx++) { - if (!state.scan_child_column[child_idx]) { - continue; - } sub_columns[child_idx]->Skip(state.child_states[child_idx + 1], count); } } @@ -160,12 +127,7 @@ void StructColumnData::InitializeAppend(ColumnAppendState &state) { } void StructColumnData::Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count) { - if (vector.GetVectorType() != VectorType::FLAT_VECTOR) { - Vector append_vector(vector); - append_vector.Flatten(count); - Append(stats, state, append_vector, count); - return; - } + vector.Flatten(count); // append the null values validity.Append(stats, state.child_appends[0], vector, count); diff --git a/src/duckdb/src/storage/table/table_statistics.cpp b/src/duckdb/src/storage/table/table_statistics.cpp index e56f98440..b51c445d0 100644 --- a/src/duckdb/src/storage/table/table_statistics.cpp +++ b/src/duckdb/src/storage/table/table_statistics.cpp @@ -1,23 +1,16 @@ #include "duckdb/storage/table/table_statistics.hpp" - -#include "duckdb/common/serializer/deserializer.hpp" +#include "duckdb/storage/table/persistent_table_data.hpp" #include "duckdb/common/serializer/serializer.hpp" +#include "duckdb/common/serializer/deserializer.hpp" #include "duckdb/execution/reservoir_sample.hpp" -#include "duckdb/storage/table/persistent_table_data.hpp" namespace duckdb { void TableStatistics::Initialize(const vector &types, PersistentTableData &data) { D_ASSERT(Empty()); - D_ASSERT(!table_sample); stats_lock = make_shared_ptr(); column_stats = std::move(data.table_stats.column_stats); - if (data.table_stats.table_sample) { - table_sample = std::move(data.table_stats.table_sample); - } else { - table_sample = make_uniq(static_cast(FIXED_SAMPLE_SIZE)); - } if (column_stats.size() != types.size()) { // LCOV_EXCL_START throw IOException("Table statistics column count is not aligned with table column count. Corrupt file?"); } // LCOV_EXCL_STOP @@ -25,10 +18,8 @@ void TableStatistics::Initialize(const vector &types, PersistentTab void TableStatistics::InitializeEmpty(const vector &types) { D_ASSERT(Empty()); - D_ASSERT(!table_sample); stats_lock = make_shared_ptr(); - table_sample = make_uniq(static_cast(FIXED_SAMPLE_SIZE)); for (auto &type : types) { column_stats.push_back(ColumnStatistics::CreateEmptyStats(type)); } @@ -44,12 +35,6 @@ void TableStatistics::InitializeAddColumn(TableStatistics &parent, const Logical column_stats.push_back(parent.column_stats[i]); } column_stats.push_back(ColumnStatistics::CreateEmptyStats(new_column_type)); - if (parent.table_sample) { - table_sample = std::move(parent.table_sample); - } - if (table_sample) { - table_sample->Destroy(); - } } void TableStatistics::InitializeRemoveColumn(TableStatistics &parent, idx_t removed_column) { @@ -63,12 +48,6 @@ void TableStatistics::InitializeRemoveColumn(TableStatistics &parent, idx_t remo column_stats.push_back(parent.column_stats[i]); } } - if (parent.table_sample) { - table_sample = std::move(parent.table_sample); - } - if (table_sample) { - table_sample->Destroy(); - } } void TableStatistics::InitializeAlterType(TableStatistics &parent, idx_t changed_idx, const LogicalType &new_type) { @@ -84,12 +63,6 @@ void TableStatistics::InitializeAlterType(TableStatistics &parent, idx_t changed column_stats.push_back(parent.column_stats[i]); } } - if (parent.table_sample) { - table_sample = std::move(parent.table_sample); - } - if (table_sample) { - table_sample->Destroy(); - } } void TableStatistics::InitializeAddConstraint(TableStatistics &parent) { @@ -106,21 +79,6 @@ void TableStatistics::InitializeAddConstraint(TableStatistics &parent) { void TableStatistics::MergeStats(TableStatistics &other) { auto l = GetLock(); D_ASSERT(column_stats.size() == other.column_stats.size()); - if (table_sample) { - if (other.table_sample) { - D_ASSERT(table_sample->type == SampleType::RESERVOIR_SAMPLE); - auto &this_reservoir = table_sample->Cast(); - D_ASSERT(other.table_sample->type == SampleType::RESERVOIR_SAMPLE); - this_reservoir.Merge(std::move(other.table_sample)); - } - // if no other.table sample, do nothig - } else { - if (other.table_sample) { - auto &other_reservoir = other.table_sample->Cast(); - auto other_table_sample_copy = other_reservoir.Copy(); - table_sample = std::move(other_table_sample_copy); - } - } for (idx_t i = 0; i < column_stats.size(); i++) { if (column_stats[i]) { D_ASSERT(other.column_stats[i]); @@ -142,25 +100,6 @@ ColumnStatistics &TableStatistics::GetStats(TableStatisticsLock &lock, idx_t i) return *column_stats[i]; } -BlockingSample &TableStatistics::GetTableSampleRef(TableStatisticsLock &lock) { - D_ASSERT(table_sample); - return *table_sample; -} - -unique_ptr TableStatistics::GetTableSample(TableStatisticsLock &lock) { - return std::move(table_sample); -} - -void TableStatistics::SetTableSample(TableStatisticsLock &lock, unique_ptr sample) { - table_sample = std::move(sample); -} - -void TableStatistics::DestroyTableSample(TableStatisticsLock &lock) const { - if (table_sample) { - table_sample->Destroy(); - } -} - unique_ptr TableStatistics::CopyStats(idx_t i) { lock_guard l(*stats_lock); auto result = column_stats[i]->Statistics().Copy(); @@ -181,25 +120,11 @@ void TableStatistics::CopyStats(TableStatisticsLock &lock, TableStatistics &othe for (auto &stats : column_stats) { other.column_stats.push_back(stats->Copy()); } - - if (table_sample) { - D_ASSERT(table_sample->type == SampleType::RESERVOIR_SAMPLE); - auto &res = table_sample->Cast(); - other.table_sample = res.Copy(); - } } void TableStatistics::Serialize(Serializer &serializer) const { serializer.WriteProperty(100, "column_stats", column_stats); - unique_ptr to_serialize = nullptr; - if (table_sample) { - D_ASSERT(table_sample->type == SampleType::RESERVOIR_SAMPLE); - auto &reservoir_sample = table_sample->Cast(); - to_serialize = unique_ptr_cast(reservoir_sample.Copy()); - auto &res_serialize = to_serialize->Cast(); - res_serialize.EvictOverBudgetSamples(); - } - serializer.WritePropertyWithDefault>(101, "table_sample", to_serialize, nullptr); + serializer.WritePropertyWithDefault>(101, "table_sample", table_sample, nullptr); } void TableStatistics::Deserialize(Deserializer &deserializer, ColumnList &columns) { @@ -217,19 +142,8 @@ void TableStatistics::Deserialize(Deserializer &deserializer, ColumnList &column deserializer.Unset(); }); - table_sample = deserializer.ReadPropertyWithDefault>(101, "table_sample"); - if (table_sample) { - D_ASSERT(table_sample->type == SampleType::RESERVOIR_SAMPLE); -#ifdef DEBUG - if (table_sample) { - auto &reservoir_sample = table_sample->Cast(); - reservoir_sample.Verify(); - } -#endif - } else { - table_sample = make_uniq(static_cast(FIXED_SAMPLE_SIZE)); - table_sample->Destroy(); - } + table_sample = + deserializer.ReadPropertyWithExplicitDefault>(101, "table_sample", nullptr); } unique_ptr TableStatistics::GetLock() { diff --git a/src/duckdb/src/storage/table/update_segment.cpp b/src/duckdb/src/storage/table/update_segment.cpp index ddee92ceb..1c7518b2c 100644 --- a/src/duckdb/src/storage/table/update_segment.cpp +++ b/src/duckdb/src/storage/table/update_segment.cpp @@ -6,7 +6,6 @@ #include "duckdb/storage/table/column_data.hpp" #include "duckdb/transaction/duck_transaction.hpp" #include "duckdb/transaction/update_info.hpp" -#include "duckdb/transaction/undo_buffer.hpp" #include @@ -47,7 +46,6 @@ UpdateSegment::~UpdateSegment() { Value UpdateInfo::GetValue(idx_t index) { auto &type = segment->column_data.type; - auto tuple_data = GetValues(); switch (type.id()) { case LogicalTypeId::VALIDITY: return Value::BOOLEAN(reinterpret_cast(tuple_data)[index]); @@ -66,53 +64,17 @@ string UpdateInfo::ToString() { auto &type = segment->column_data.type; string result = "Update Info [" + type.ToString() + ", Count: " + to_string(N) + ", Transaction Id: " + to_string(version_number) + "]\n"; - auto tuples = GetTuples(); for (idx_t i = 0; i < N; i++) { result += to_string(tuples[i]) + ": " + GetValue(i).ToString() + "\n"; } - if (HasNext()) { - auto next_pin = next.Pin(); - result += "\nChild Segment: " + Get(next_pin).ToString(); + if (next) { + result += "\nChild Segment: " + next->ToString(); } return result; } -sel_t *UpdateInfo::GetTuples() { - return reinterpret_cast(data_ptr_cast(this) + sizeof(UpdateInfo)); -} - -data_ptr_t UpdateInfo::GetValues() { - return reinterpret_cast(data_ptr_cast(this) + sizeof(UpdateInfo) + sizeof(sel_t) * max); -} - -UpdateInfo &UpdateInfo::Get(UndoBufferReference &entry) { - auto update_info = reinterpret_cast(entry.Ptr()); - return *update_info; -} - -bool UpdateInfo::HasPrev() const { - return prev.entry; -} - -bool UpdateInfo::HasNext() const { - return next.entry; -} - -idx_t UpdateInfo::GetAllocSize(idx_t type_size) { - return AlignValue(sizeof(UpdateInfo) + (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); -} - -void UpdateInfo::Initialize(UpdateInfo &info, transaction_t transaction_id) { - info.max = STANDARD_VECTOR_SIZE; - info.version_number = transaction_id; - info.segment = nullptr; - info.prev.entry = nullptr; - info.next.entry = nullptr; -} - void UpdateInfo::Verify() { #ifdef DEBUG - auto tuples = GetTuples(); for (idx_t i = 1; i < N; i++) { D_ASSERT(tuples[i] > tuples[i - 1] && tuples[i] < STANDARD_VECTOR_SIZE); } @@ -122,42 +84,40 @@ void UpdateInfo::Verify() { //===--------------------------------------------------------------------===// // Update Fetch //===--------------------------------------------------------------------===// -static void MergeValidityInfo(UpdateInfo ¤t, ValidityMask &result_mask) { - auto tuples = current.GetTuples(); - auto info_data = current.GetData(); - for (idx_t i = 0; i < current.N; i++) { - result_mask.Set(tuples[i], info_data[i]); +static void MergeValidityInfo(UpdateInfo *current, ValidityMask &result_mask) { + auto info_data = reinterpret_cast(current->tuple_data); + for (idx_t i = 0; i < current->N; i++) { + result_mask.Set(current->tuples[i], info_data[i]); } } -static void UpdateMergeValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, +static void UpdateMergeValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, Vector &result) { auto &result_mask = FlatVector::Validity(result); UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, - [&](UpdateInfo ¤t) { MergeValidityInfo(current, result_mask); }); + [&](UpdateInfo *current) { MergeValidityInfo(current, result_mask); }); } template -static void MergeUpdateInfo(UpdateInfo ¤t, T *result_data) { - auto tuples = current.GetTuples(); - auto info_data = current.GetData(); - if (current.N == STANDARD_VECTOR_SIZE) { +static void MergeUpdateInfo(UpdateInfo *current, T *result_data) { + auto info_data = reinterpret_cast(current->tuple_data); + if (current->N == STANDARD_VECTOR_SIZE) { // special case: update touches ALL tuples of this vector // in this case we can just memcpy the data // since the layout of the update info is guaranteed to be [0, 1, 2, 3, ...] - memcpy(result_data, info_data, sizeof(T) * current.N); + memcpy(result_data, info_data, sizeof(T) * current->N); } else { - for (idx_t i = 0; i < current.N; i++) { - result_data[tuples[i]] = info_data[i]; + for (idx_t i = 0; i < current->N; i++) { + result_data[current->tuples[i]] = info_data[i]; } } } template -static void UpdateMergeFetch(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, Vector &result) { +static void UpdateMergeFetch(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, Vector &result) { auto result_data = FlatVector::GetData(result); UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, - [&](UpdateInfo ¤t) { MergeUpdateInfo(current, result_data); }); + [&](UpdateInfo *current) { MergeUpdateInfo(current, result_data); }); } static UpdateSegment::fetch_update_function_t GetFetchUpdateFunction(PhysicalType type) { @@ -198,44 +158,31 @@ static UpdateSegment::fetch_update_function_t GetFetchUpdateFunction(PhysicalTyp } } -UndoBufferPointer UpdateSegment::GetUpdateNode(idx_t vector_idx) const { - if (!root) { - return UndoBufferPointer(); - } - if (vector_idx >= root->info.size()) { - return UndoBufferPointer(); - } - return root->info[vector_idx]; -} - void UpdateSegment::FetchUpdates(TransactionData transaction, idx_t vector_index, Vector &result) { auto lock_handle = lock.GetSharedLock(); - auto node = GetUpdateNode(vector_index); - if (!node.IsSet()) { + if (!root) { + return; + } + if (!root->info[vector_index]) { return; } // FIXME: normalify if this is not the case... need to pass in count? D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - auto pin = node.Pin(); - fetch_update_function(transaction.start_time, transaction.transaction_id, UpdateInfo::Get(pin), result); -} - -UpdateNode::UpdateNode(BufferManager &manager) : allocator(manager) { -} -UpdateNode::~UpdateNode() { + fetch_update_function(transaction.start_time, transaction.transaction_id, root->info[vector_index]->info.get(), + result); } //===--------------------------------------------------------------------===// // Fetch Committed //===--------------------------------------------------------------------===// -static void FetchCommittedValidity(UpdateInfo &info, Vector &result) { +static void FetchCommittedValidity(UpdateInfo *info, Vector &result) { auto &result_mask = FlatVector::Validity(result); MergeValidityInfo(info, result_mask); } template -static void TemplatedFetchCommitted(UpdateInfo &info, Vector &result) { +static void TemplatedFetchCommitted(UpdateInfo *info, Vector &result) { auto result_data = FlatVector::GetData(result); MergeUpdateInfo(info, result_data); } @@ -280,25 +227,27 @@ static UpdateSegment::fetch_committed_function_t GetFetchCommittedFunction(Physi void UpdateSegment::FetchCommitted(idx_t vector_index, Vector &result) { auto lock_handle = lock.GetSharedLock(); - auto node = GetUpdateNode(vector_index); - if (!node.IsSet()) { + + if (!root) { + return; + } + if (!root->info[vector_index]) { return; } // FIXME: normalify if this is not the case... need to pass in count? D_ASSERT(result.GetVectorType() == VectorType::FLAT_VECTOR); - auto pin = node.Pin(); - fetch_committed_function(UpdateInfo::Get(pin), result); + + fetch_committed_function(root->info[vector_index]->info.get(), result); } //===--------------------------------------------------------------------===// // Fetch Range //===--------------------------------------------------------------------===// -static void MergeUpdateInfoRangeValidity(UpdateInfo ¤t, idx_t start, idx_t end, idx_t result_offset, +static void MergeUpdateInfoRangeValidity(UpdateInfo *current, idx_t start, idx_t end, idx_t result_offset, ValidityMask &result_mask) { - auto tuples = current.GetTuples(); - auto info_data = current.GetData(); - for (idx_t i = 0; i < current.N; i++) { - auto tuple_idx = tuples[i]; + auto info_data = reinterpret_cast(current->tuple_data); + for (idx_t i = 0; i < current->N; i++) { + auto tuple_idx = current->tuples[i]; if (tuple_idx < start) { continue; } else if (tuple_idx >= end) { @@ -309,17 +258,16 @@ static void MergeUpdateInfoRangeValidity(UpdateInfo ¤t, idx_t start, idx_t } } -static void FetchCommittedRangeValidity(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { +static void FetchCommittedRangeValidity(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { auto &result_mask = FlatVector::Validity(result); MergeUpdateInfoRangeValidity(info, start, end, result_offset, result_mask); } template -static void MergeUpdateInfoRange(UpdateInfo ¤t, idx_t start, idx_t end, idx_t result_offset, T *result_data) { - auto tuples = current.GetTuples(); - auto info_data = current.GetData(); - for (idx_t i = 0; i < current.N; i++) { - auto tuple_idx = tuples[i]; +static void MergeUpdateInfoRange(UpdateInfo *current, idx_t start, idx_t end, idx_t result_offset, T *result_data) { + auto info_data = reinterpret_cast(current->tuple_data); + for (idx_t i = 0; i < current->N; i++) { + auto tuple_idx = current->tuples[i]; if (tuple_idx < start) { continue; } else if (tuple_idx >= end) { @@ -331,7 +279,7 @@ static void MergeUpdateInfoRange(UpdateInfo ¤t, idx_t start, idx_t end, id } template -static void TemplatedFetchCommittedRange(UpdateInfo &info, idx_t start, idx_t end, idx_t result_offset, +static void TemplatedFetchCommittedRange(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset, Vector &result) { auto result_data = FlatVector::GetData(result); MergeUpdateInfoRange(info, start, end, result_offset, result_data); @@ -386,38 +334,37 @@ void UpdateSegment::FetchCommittedRange(idx_t start_row, idx_t count, Vector &re idx_t start_vector = start_row / STANDARD_VECTOR_SIZE; idx_t end_vector = (end_row - 1) / STANDARD_VECTOR_SIZE; D_ASSERT(start_vector <= end_vector); + D_ASSERT(end_vector < Storage::ROW_GROUP_VECTOR_COUNT); for (idx_t vector_idx = start_vector; vector_idx <= end_vector; vector_idx++) { - auto entry = GetUpdateNode(vector_idx); - if (!entry.IsSet()) { + if (!root->info[vector_idx]) { continue; } - auto pin = entry.Pin(); idx_t start_in_vector = vector_idx == start_vector ? start_row - start_vector * STANDARD_VECTOR_SIZE : 0; idx_t end_in_vector = vector_idx == end_vector ? end_row - end_vector * STANDARD_VECTOR_SIZE : STANDARD_VECTOR_SIZE; D_ASSERT(start_in_vector < end_in_vector); D_ASSERT(end_in_vector > 0 && end_in_vector <= STANDARD_VECTOR_SIZE); idx_t result_offset = ((vector_idx * STANDARD_VECTOR_SIZE) + start_in_vector) - start_row; - fetch_committed_range(UpdateInfo::Get(pin), start_in_vector, end_in_vector, result_offset, result); + fetch_committed_range(root->info[vector_idx]->info.get(), start_in_vector, end_in_vector, result_offset, + result); } } //===--------------------------------------------------------------------===// // Fetch Row //===--------------------------------------------------------------------===// -static void FetchRowValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, idx_t row_idx, +static void FetchRowValidity(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, idx_t row_idx, Vector &result, idx_t result_idx) { auto &result_mask = FlatVector::Validity(result); - UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo ¤t) { - auto info_data = current.GetData(); - auto tuples = current.GetTuples(); + UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo *current) { + auto info_data = reinterpret_cast(current->tuple_data); // FIXME: we could do a binary search in here - for (idx_t i = 0; i < current.N; i++) { - if (tuples[i] == row_idx) { + for (idx_t i = 0; i < current->N; i++) { + if (current->tuples[i] == row_idx) { result_mask.Set(result_idx, info_data[i]); break; - } else if (tuples[i] > row_idx) { + } else if (current->tuples[i] > row_idx) { break; } } @@ -425,18 +372,17 @@ static void FetchRowValidity(transaction_t start_time, transaction_t transaction } template -static void TemplatedFetchRow(transaction_t start_time, transaction_t transaction_id, UpdateInfo &info, idx_t row_idx, +static void TemplatedFetchRow(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info, idx_t row_idx, Vector &result, idx_t result_idx) { auto result_data = FlatVector::GetData(result); - UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo ¤t) { - auto info_data = current.GetData(); - auto tuples = current.GetTuples(); + UpdateInfo::UpdatesForTransaction(info, start_time, transaction_id, [&](UpdateInfo *current) { + auto info_data = (T *)current->tuple_data; // FIXME: we could do a binary search in here - for (idx_t i = 0; i < current.N; i++) { - if (tuples[i] == row_idx) { + for (idx_t i = 0; i < current->N; i++) { + if (current->tuples[i] == row_idx) { result_data[result_idx] = info_data[i]; break; - } else if (tuples[i] > row_idx) { + } else if (current->tuples[i] > row_idx) { break; } } @@ -482,15 +428,16 @@ static UpdateSegment::fetch_row_function_t GetFetchRowFunction(PhysicalType type } void UpdateSegment::FetchRow(TransactionData transaction, idx_t row_id, Vector &result, idx_t result_idx) { + if (!root) { + return; + } idx_t vector_index = (row_id - column_data.start) / STANDARD_VECTOR_SIZE; - auto entry = GetUpdateNode(vector_index); - if (!entry.IsSet()) { + if (!root->info[vector_index]) { return; } idx_t row_in_vector = (row_id - column_data.start) - vector_index * STANDARD_VECTOR_SIZE; - auto pin = entry.Pin(); - fetch_row_function(transaction.start_time, transaction.transaction_id, UpdateInfo::Get(pin), row_in_vector, result, - result_idx); + fetch_row_function(transaction.start_time, transaction.transaction_id, root->info[vector_index]->info.get(), + row_in_vector, result, result_idx); } //===--------------------------------------------------------------------===// @@ -498,14 +445,12 @@ void UpdateSegment::FetchRow(TransactionData transaction, idx_t row_id, Vector & //===--------------------------------------------------------------------===// template static void RollbackUpdate(UpdateInfo &base_info, UpdateInfo &rollback_info) { - auto base_data = base_info.GetData(); - auto base_tuples = base_info.GetTuples(); - auto rollback_data = rollback_info.GetData(); - auto rollback_tuples = rollback_info.GetTuples(); + auto base_data = (T *)base_info.tuple_data; + auto rollback_data = (T *)rollback_info.tuple_data; idx_t base_offset = 0; for (idx_t i = 0; i < rollback_info.N; i++) { - auto id = rollback_tuples[i]; - while (base_tuples[base_offset] < id) { + auto id = rollback_info.tuples[i]; + while (base_info.tuples[base_offset] < id) { base_offset++; D_ASSERT(base_offset < base_info.N); } @@ -556,12 +501,10 @@ void UpdateSegment::RollbackUpdate(UpdateInfo &info) { auto lock_handle = lock.GetExclusiveLock(); // move the data from the UpdateInfo back into the base info - auto entry = GetUpdateNode(info.vector_index); - if (!entry.IsSet()) { + if (!root->info[info.vector_index]) { return; } - auto pin = entry.Pin(); - rollback_update_function(UpdateInfo::Get(pin), info); + rollback_update_function(*root->info[info.vector_index]->info, info); // clean up the update chain CleanupUpdateInternal(*lock_handle, info); @@ -571,18 +514,11 @@ void UpdateSegment::RollbackUpdate(UpdateInfo &info) { // Cleanup Update //===--------------------------------------------------------------------===// void UpdateSegment::CleanupUpdateInternal(const StorageLockKey &lock, UpdateInfo &info) { - D_ASSERT(info.HasPrev()); + D_ASSERT(info.prev); auto prev = info.prev; - { - auto pin = prev.Pin(); - auto &prev_info = UpdateInfo::Get(pin); - prev_info.next = info.next; - } - if (info.HasNext()) { - auto next = info.next; - auto next_pin = next.Pin(); - auto &next_info = UpdateInfo::Get(next_pin); - next_info.prev = prev; + prev->next = info.next; + if (prev->next) { + prev->next->prev = prev; } } @@ -595,40 +531,38 @@ void UpdateSegment::CleanupUpdate(UpdateInfo &info) { //===--------------------------------------------------------------------===// // Check for conflicts in update //===--------------------------------------------------------------------===// -static void CheckForConflicts(UndoBufferPointer next_ptr, TransactionData transaction, row_t *ids, - const SelectionVector &sel, idx_t count, row_t offset, UndoBufferReference &node_ref) { - while (next_ptr.IsSet()) { - auto pin = next_ptr.Pin(); - auto &info = UpdateInfo::Get(pin); - if (info.version_number == transaction.transaction_id) { - // this UpdateInfo belongs to the current transaction, set it in the node - node_ref = std::move(pin); - } else if (info.version_number > transaction.start_time) { - // potential conflict, check that tuple ids do not conflict - // as both ids and info->tuples are sorted, this is similar to a merge join - idx_t i = 0, j = 0; - auto tuples = info.GetTuples(); - while (true) { - auto id = ids[sel.get_index(i)] - offset; - if (id == tuples[j]) { - throw TransactionException("Conflict on update!"); - } else if (id < tuples[j]) { - // id < the current tuple in info, move to next id - i++; - if (i == count) { - break; - } - } else { - // id > the current tuple, move to next tuple in info - j++; - if (j == info.N) { - break; - } +static void CheckForConflicts(UpdateInfo *info, TransactionData transaction, row_t *ids, const SelectionVector &sel, + idx_t count, row_t offset, UpdateInfo *&node) { + if (!info) { + return; + } + if (info->version_number == transaction.transaction_id) { + // this UpdateInfo belongs to the current transaction, set it in the node + node = info; + } else if (info->version_number > transaction.start_time) { + // potential conflict, check that tuple ids do not conflict + // as both ids and info->tuples are sorted, this is similar to a merge join + idx_t i = 0, j = 0; + while (true) { + auto id = ids[sel.get_index(i)] - offset; + if (id == info->tuples[j]) { + throw TransactionException("Conflict on update!"); + } else if (id < info->tuples[j]) { + // id < the current tuple in info, move to next id + i++; + if (i == count) { + break; + } + } else { + // id > the current tuple, move to next tuple in info + j++; + if (j == info->N) { + break; } } } - next_ptr = info.next; } + CheckForConflicts(info->next, transaction, ids, sel, count, offset, node); } //===--------------------------------------------------------------------===// @@ -638,45 +572,43 @@ void UpdateSegment::InitializeUpdateInfo(UpdateInfo &info, row_t *ids, const Sel idx_t vector_index, idx_t vector_offset) { info.segment = this; info.vector_index = vector_index; - info.prev = UndoBufferPointer(); - info.next = UndoBufferPointer(); + info.prev = nullptr; + info.next = nullptr; // set up the tuple ids info.N = UnsafeNumericCast(count); - auto tuples = info.GetTuples(); for (idx_t i = 0; i < count; i++) { auto idx = sel.get_index(i); auto id = ids[idx]; D_ASSERT(idx_t(id) >= vector_offset && idx_t(id) < vector_offset + STANDARD_VECTOR_SIZE); - tuples[i] = NumericCast(NumericCast(id) - vector_offset); + info.tuples[i] = NumericCast(NumericCast(id) - vector_offset); }; } -static void InitializeUpdateValidity(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, +static void InitializeUpdateValidity(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, const SelectionVector &sel) { auto &update_mask = FlatVector::Validity(update); - auto tuple_data = update_info.GetData(); + auto tuple_data = reinterpret_cast(update_info->tuple_data); if (!update_mask.AllValid()) { - for (idx_t i = 0; i < update_info.N; i++) { + for (idx_t i = 0; i < update_info->N; i++) { auto idx = sel.get_index(i); tuple_data[i] = update_mask.RowIsValidUnsafe(idx); } } else { - for (idx_t i = 0; i < update_info.N; i++) { + for (idx_t i = 0; i < update_info->N; i++) { tuple_data[i] = true; } } auto &base_mask = FlatVector::Validity(base_data); - auto base_tuple_data = base_info.GetData(); - auto base_tuples = base_info.GetTuples(); + auto base_tuple_data = reinterpret_cast(base_info->tuple_data); if (!base_mask.AllValid()) { - for (idx_t i = 0; i < base_info.N; i++) { - base_tuple_data[i] = base_mask.RowIsValidUnsafe(base_tuples[i]); + for (idx_t i = 0; i < base_info->N; i++) { + base_tuple_data[i] = base_mask.RowIsValidUnsafe(base_info->tuples[i]); } } else { - for (idx_t i = 0; i < base_info.N; i++) { + for (idx_t i = 0; i < base_info->N; i++) { base_tuple_data[i] = true; } } @@ -684,37 +616,36 @@ static void InitializeUpdateValidity(UpdateInfo &base_info, Vector &base_data, U struct UpdateSelectElement { template - static T Operation(UpdateSegment &segment, T element) { + static T Operation(UpdateSegment *segment, T element) { return element; } }; template <> -string_t UpdateSelectElement::Operation(UpdateSegment &segment, string_t element) { - return element.IsInlined() ? element : segment.GetStringHeap().AddBlob(element); +string_t UpdateSelectElement::Operation(UpdateSegment *segment, string_t element) { + return element.IsInlined() ? element : segment->GetStringHeap().AddBlob(element); } template -static void InitializeUpdateData(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, +static void InitializeUpdateData(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, const SelectionVector &sel) { auto update_data = FlatVector::GetData(update); - auto tuple_data = update_info.GetData(); + auto tuple_data = (T *)update_info->tuple_data; - for (idx_t i = 0; i < update_info.N; i++) { + for (idx_t i = 0; i < update_info->N; i++) { auto idx = sel.get_index(i); tuple_data[i] = update_data[idx]; } auto base_array_data = FlatVector::GetData(base_data); auto &base_validity = FlatVector::Validity(base_data); - auto base_tuple_data = base_info.GetData(); - auto base_tuples = base_info.GetTuples(); - for (idx_t i = 0; i < base_info.N; i++) { - auto base_idx = base_tuples[i]; + auto base_tuple_data = (T *)base_info->tuple_data; + for (idx_t i = 0; i < base_info->N; i++) { + auto base_idx = base_info->tuples[i]; if (!base_validity.RowIsValid(base_idx)) { continue; } - base_tuple_data[i] = UpdateSelectElement::Operation(*base_info.segment, base_array_data[base_idx]); + base_tuple_data[i] = UpdateSelectElement::Operation(base_info->segment, base_array_data[base_idx]); } } @@ -810,9 +741,9 @@ struct ExtractValidityEntry { }; template -static void MergeUpdateLoopInternal(UpdateInfo &base_info, V *base_table_data, UpdateInfo &update_info, +static void MergeUpdateLoopInternal(UpdateInfo *base_info, V *base_table_data, UpdateInfo *update_info, V *update_vector_data, row_t *ids, idx_t count, const SelectionVector &sel) { - auto base_id = base_info.segment->column_data.start + base_info.vector_index * STANDARD_VECTOR_SIZE; + auto base_id = base_info->segment->column_data.start + base_info->vector_index * STANDARD_VECTOR_SIZE; #ifdef DEBUG // all of these should be sorted, otherwise the below algorithm does not work for (idx_t i = 1; i < count; i++) { @@ -828,10 +759,8 @@ static void MergeUpdateLoopInternal(UpdateInfo &base_info, V *base_table_data, U // and potentially, this transaction already has updates present (update_info) // we need to merge these all together so that the latest updates get merged into base_info // and the "old" values (fetched from EITHER base_info OR from base_data) get placed into update_info - auto base_info_data = base_info.GetData(); - auto base_tuples = base_info.GetTuples(); - auto update_info_data = update_info.GetData(); - auto update_tuples = update_info.GetTuples(); + auto base_info_data = (T *)base_info->tuple_data; + auto update_info_data = (T *)update_info->tuple_data; // we first do the merging of the old values // what we are trying to do here is update the "update_info" of this transaction with all the old data we require @@ -850,45 +779,45 @@ static void MergeUpdateLoopInternal(UpdateInfo &base_info, V *base_table_data, U // we have to merge the info for "ids[i]" auto update_id = UnsafeNumericCast(ids[idx]) - base_id; - while (update_info_offset < update_info.N && update_tuples[update_info_offset] < update_id) { + while (update_info_offset < update_info->N && update_info->tuples[update_info_offset] < update_id) { // old id comes before the current id: write it result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_tuples[update_info_offset]; + result_ids[result_offset++] = update_info->tuples[update_info_offset]; update_info_offset++; } // write the new id - if (update_info_offset < update_info.N && update_tuples[update_info_offset] == update_id) { + if (update_info_offset < update_info->N && update_info->tuples[update_info_offset] == update_id) { // we have an id that is equivalent in the current update info: write the update info result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_tuples[update_info_offset]; + result_ids[result_offset++] = update_info->tuples[update_info_offset]; update_info_offset++; continue; } /// now check if we have the current update_id in the base_info, or if we should fetch it from the base data - while (base_info_offset < base_info.N && base_tuples[base_info_offset] < update_id) { + while (base_info_offset < base_info->N && base_info->tuples[base_info_offset] < update_id) { base_info_offset++; } - if (base_info_offset < base_info.N && base_tuples[base_info_offset] == update_id) { + if (base_info_offset < base_info->N && base_info->tuples[base_info_offset] == update_id) { // it is! we have to move the tuple from base_info->ids[base_info_offset] to update_info result_values[result_offset] = base_info_data[base_info_offset]; } else { // it is not! we have to move base_table_data[update_id] to update_info result_values[result_offset] = UpdateSelectElement::Operation( - *base_info.segment, OP::template Extract(base_table_data, update_id)); + base_info->segment, OP::template Extract(base_table_data, update_id)); } result_ids[result_offset++] = UnsafeNumericCast(update_id); } // write any remaining entries from the old updates - while (update_info_offset < update_info.N) { + while (update_info_offset < update_info->N) { result_values[result_offset] = update_info_data[update_info_offset]; - result_ids[result_offset++] = update_tuples[update_info_offset]; + result_ids[result_offset++] = update_info->tuples[update_info_offset]; update_info_offset++; } // now copy them back - update_info.N = UnsafeNumericCast(result_offset); + update_info->N = UnsafeNumericCast(result_offset); memcpy(update_info_data, result_values, result_offset * sizeof(T)); - memcpy(update_tuples, result_ids, result_offset * sizeof(sel_t)); + memcpy(update_info->tuples, result_ids, result_offset * sizeof(sel_t)); // now we merge the new values into the base_info result_offset = 0; @@ -906,14 +835,14 @@ static void MergeUpdateLoopInternal(UpdateInfo &base_info, V *base_table_data, U auto merge = [&](idx_t id, idx_t aidx, idx_t bidx, idx_t count) { pick_new(id, aidx, count); }; - MergeLoop(ids, base_tuples, count, base_info.N, base_id, merge, pick_new, pick_old, sel); + MergeLoop(ids, base_info->tuples, count, base_info->N, base_id, merge, pick_new, pick_old, sel); - base_info.N = UnsafeNumericCast(result_offset); + base_info->N = UnsafeNumericCast(result_offset); memcpy(base_info_data, result_values, result_offset * sizeof(T)); - memcpy(base_tuples, result_ids, result_offset * sizeof(sel_t)); + memcpy(base_info->tuples, result_ids, result_offset * sizeof(sel_t)); } -static void MergeValidityLoop(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, +static void MergeValidityLoop(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel) { auto &base_validity = FlatVector::Validity(base_data); auto &update_validity = FlatVector::Validity(update); @@ -922,7 +851,7 @@ static void MergeValidityLoop(UpdateInfo &base_info, Vector &base_data, UpdateIn } template -static void MergeUpdateLoop(UpdateInfo &base_info, Vector &base_data, UpdateInfo &update_info, Vector &update, +static void MergeUpdateLoop(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info, Vector &update, row_t *ids, idx_t count, const SelectionVector &sel) { auto base_table_data = FlatVector::GetData(base_data); auto update_vector_data = FlatVector::GetData(update); @@ -1133,26 +1062,16 @@ static idx_t SortSelectionVector(SelectionVector &sel, idx_t count, row_t *ids) UpdateInfo *CreateEmptyUpdateInfo(TransactionData transaction, idx_t type_size, idx_t count, unsafe_unique_array &data) { - data = make_unsafe_uniq_array_uninitialized(UpdateInfo::GetAllocSize(type_size)); + data = make_unsafe_uniq_array_uninitialized(sizeof(UpdateInfo) + + (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); auto update_info = reinterpret_cast(data.get()); - UpdateInfo::Initialize(*update_info, transaction.transaction_id); + update_info->max = STANDARD_VECTOR_SIZE; + update_info->tuples = reinterpret_cast((data_ptr_cast(update_info)) + sizeof(UpdateInfo)); + update_info->tuple_data = (data_ptr_cast(update_info)) + sizeof(UpdateInfo) + sizeof(sel_t) * update_info->max; + update_info->version_number = transaction.transaction_id; return update_info; } -void UpdateSegment::InitializeUpdateInfo(idx_t vector_idx) { - // create the versions for this segment, if there are none yet - if (!root) { - root = make_uniq(column_data.block_manager.buffer_manager); - } - if (vector_idx < root->info.size()) { - return; - } - root->info.reserve(vector_idx + 1); - for (idx_t i = root->info.size(); i <= vector_idx; i++) { - root->info.emplace_back(); - } -} - void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vector &update, row_t *ids, idx_t count, Vector &base_data) { // obtain an exclusive lock @@ -1177,35 +1096,45 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect count = SortSelectionVector(sel, count, ids); D_ASSERT(count > 0); + // create the versions for this segment, if there are none yet + if (!root) { + root = make_uniq(); + } + // get the vector index based on the first id // we assert that all updates must be part of the same vector auto first_id = ids[sel.get_index(0)]; idx_t vector_index = (UnsafeNumericCast(first_id) - column_data.start) / STANDARD_VECTOR_SIZE; idx_t vector_offset = column_data.start + vector_index * STANDARD_VECTOR_SIZE; - InitializeUpdateInfo(vector_index); D_ASSERT(idx_t(first_id) >= column_data.start); + D_ASSERT(vector_index < Storage::ROW_GROUP_VECTOR_COUNT); + + // first check the version chain + UpdateInfo *node = nullptr; - if (root->info[vector_index].IsSet()) { + if (root->info[vector_index]) { // there is already a version here, check if there are any conflicts and search for the node that belongs to // this transaction in the version chain - auto root_pointer = root->info[vector_index]; - auto root_pin = root_pointer.Pin(); - auto &base_info = UpdateInfo::Get(root_pin); - - UndoBufferReference node_ref; - CheckForConflicts(base_info.next, transaction, ids, sel, count, UnsafeNumericCast(vector_offset), - node_ref); - - // there are no conflicts - continue with the update + auto base_info = root->info[vector_index]->info.get(); + CheckForConflicts(base_info->next, transaction, ids, sel, count, UnsafeNumericCast(vector_offset), node); + + // there are no conflicts + // first, check if this thread has already done any updates + auto node = base_info->next; + while (node) { + if (node->version_number == transaction.transaction_id) { + // it has! use this node + break; + } + node = node->next; + } unsafe_unique_array update_info_data; - optional_ptr node; - if (!node_ref.IsSet()) { + if (!node) { // no updates made yet by this transaction: initially the update info to empty if (transaction.transaction) { auto &dtransaction = transaction.transaction->Cast(); - node_ref = dtransaction.CreateUpdateInfo(type_size, count); - node = &UpdateInfo::Get(node_ref); + node = dtransaction.CreateUpdateInfo(type_size, count); } else { node = CreateEmptyUpdateInfo(transaction, type_size, count, update_info_data); } @@ -1215,44 +1144,39 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect node->column_index = column_index; // insert the new node into the chain - node->next = base_info.next; - if (node->next.IsSet()) { - auto next_pin = node->next.Pin(); - auto &next_info = UpdateInfo::Get(next_pin); - next_info.prev = node_ref.GetBufferPointer(); + node->next = base_info->next; + if (node->next) { + node->next->prev = node; } - node->prev = root_pointer; - base_info.next = transaction.transaction ? node_ref.GetBufferPointer() : UndoBufferPointer(); - } else { - // we already had updates made to this transaction - node = &UpdateInfo::Get(node_ref); + node->prev = base_info; + base_info->next = transaction.transaction ? node : nullptr; } - base_info.Verify(); + base_info->Verify(); node->Verify(); // now we are going to perform the merge - merge_update_function(base_info, base_data, *node, update, ids, count, sel); + merge_update_function(base_info, base_data, node, update, ids, count, sel); - base_info.Verify(); + base_info->Verify(); node->Verify(); } else { // there is no version info yet: create the top level update info and fill it with the updates - // allocate space for the UpdateInfo in the allocator - idx_t alloc_size = UpdateInfo::GetAllocSize(type_size); - auto handle = root->allocator.Allocate(alloc_size); - auto &update_info = UpdateInfo::Get(handle); - UpdateInfo::Initialize(update_info, TRANSACTION_ID_START - 1); - update_info.column_index = column_index; + auto result = make_uniq(); - InitializeUpdateInfo(update_info, ids, sel, count, vector_index, vector_offset); + result->info = make_uniq(); + result->tuples = make_unsafe_uniq_array_uninitialized(STANDARD_VECTOR_SIZE); + result->tuple_data = make_unsafe_uniq_array_uninitialized(STANDARD_VECTOR_SIZE * type_size); + result->info->tuples = result->tuples.get(); + result->info->tuple_data = result->tuple_data.get(); + result->info->version_number = TRANSACTION_ID_START - 1; + result->info->column_index = column_index; + InitializeUpdateInfo(*result->info, ids, sel, count, vector_index, vector_offset); // now create the transaction level update info in the undo log unsafe_unique_array update_info_data; - UndoBufferReference node_ref; - optional_ptr transaction_node; + UpdateInfo *transaction_node; if (transaction.transaction) { - node_ref = transaction.transaction->CreateUpdateInfo(type_size, count); - transaction_node = &UpdateInfo::Get(node_ref); + transaction_node = transaction.transaction->CreateUpdateInfo(type_size, count); } else { transaction_node = CreateEmptyUpdateInfo(transaction, type_size, count, update_info_data); } @@ -1260,18 +1184,18 @@ void UpdateSegment::Update(TransactionData transaction, idx_t column_index, Vect InitializeUpdateInfo(*transaction_node, ids, sel, count, vector_index, vector_offset); // we write the updates in the update node data, and write the updates in the info - initialize_update_function(*transaction_node, base_data, update_info, update, sel); + initialize_update_function(transaction_node, base_data, result->info.get(), update, sel); - update_info.next = transaction.transaction ? node_ref.GetBufferPointer() : UndoBufferPointer(); - update_info.prev = UndoBufferPointer(); - transaction_node->next = UndoBufferPointer(); - transaction_node->prev = handle.GetBufferPointer(); + result->info->next = transaction.transaction ? transaction_node : nullptr; + result->info->prev = nullptr; + transaction_node->next = nullptr; + transaction_node->prev = result->info.get(); transaction_node->column_index = column_index; transaction_node->Verify(); - update_info.Verify(); + result->info->Verify(); - root->info[vector_index] = handle.GetBufferPointer(); + root->info[vector_index] = std::move(result); } } @@ -1280,34 +1204,33 @@ bool UpdateSegment::HasUpdates() const { } bool UpdateSegment::HasUpdates(idx_t vector_index) const { - auto read_lock = lock.GetSharedLock(); - return GetUpdateNode(vector_index).IsSet(); + if (!HasUpdates()) { + return false; + } + return root->info[vector_index].get(); } bool UpdateSegment::HasUncommittedUpdates(idx_t vector_index) { - auto read_lock = lock.GetSharedLock(); - auto entry = GetUpdateNode(vector_index); - if (!entry.IsSet()) { + if (!HasUpdates(vector_index)) { return false; } - auto pin = entry.Pin(); - auto &info = UpdateInfo::Get(pin); - if (info.HasNext()) { + auto read_lock = lock.GetSharedLock(); + auto entry = root->info[vector_index].get(); + if (entry->info->next) { return true; } return false; } bool UpdateSegment::HasUpdates(idx_t start_row_index, idx_t end_row_index) { - auto read_lock = lock.GetSharedLock(); - if (!root) { + if (!HasUpdates()) { return false; } + auto read_lock = lock.GetSharedLock(); idx_t base_vector_index = start_row_index / STANDARD_VECTOR_SIZE; idx_t end_vector_index = end_row_index / STANDARD_VECTOR_SIZE; for (idx_t i = base_vector_index; i <= end_vector_index; i++) { - auto entry = GetUpdateNode(i); - if (entry.IsSet()) { + if (root->info[i]) { return true; } } diff --git a/src/duckdb/src/storage/table_index_list.cpp b/src/duckdb/src/storage/table_index_list.cpp index 010162e84..c505d0a05 100644 --- a/src/duckdb/src/storage/table_index_list.cpp +++ b/src/duckdb/src/storage/table_index_list.cpp @@ -1,17 +1,16 @@ #include "duckdb/storage/table/table_index_list.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/common/types/conflict_manager.hpp" #include "duckdb/execution/index/index_type_set.hpp" #include "duckdb/execution/index/unbound_index.hpp" #include "duckdb/main/config.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/planner/expression_binder/index_binder.hpp" #include "duckdb/storage/data_table.hpp" #include "duckdb/storage/table/data_table_info.hpp" +#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" +#include "duckdb/planner/expression_binder/index_binder.hpp" namespace duckdb { - void TableIndexList::AddIndex(unique_ptr index) { D_ASSERT(index); lock_guard lock(indexes_lock); @@ -21,10 +20,11 @@ void TableIndexList::AddIndex(unique_ptr index) { void TableIndexList::RemoveIndex(const string &name) { lock_guard lock(indexes_lock); - for (idx_t i = 0; i < indexes.size(); i++) { - auto &index = indexes[i]; - if (index->GetIndexName() == name) { - indexes.erase_at(i); + for (idx_t index_idx = 0; index_idx < indexes.size(); index_idx++) { + auto &index_entry = indexes[index_idx]; + + if (index_entry->GetIndexName() == name) { + indexes.erase_at(index_idx); break; } } @@ -33,9 +33,10 @@ void TableIndexList::RemoveIndex(const string &name) { void TableIndexList::CommitDrop(const string &name) { lock_guard lock(indexes_lock); - for (auto &index : indexes) { - if (index->GetIndexName() == name) { - index->CommitDrop(); + for (idx_t index_idx = 0; index_idx < indexes.size(); index_idx++) { + auto &index_entry = indexes[index_idx]; + if (index_entry->GetIndexName() == name) { + index_entry->CommitDrop(); } } } @@ -43,24 +44,17 @@ void TableIndexList::CommitDrop(const string &name) { bool TableIndexList::NameIsUnique(const string &name) { lock_guard lock(indexes_lock); - // Only covers PK, FK, and UNIQUE indexes. - for (const auto &index : indexes) { - if (index->IsPrimary() || index->IsForeign() || index->IsUnique()) { - if (index->GetIndexName() == name) { + // only cover PK, FK, and UNIQUE, which are not (yet) catalog entries + for (idx_t index_idx = 0; index_idx < indexes.size(); index_idx++) { + auto &index_entry = indexes[index_idx]; + if (index_entry->IsPrimary() || index_entry->IsForeign() || index_entry->IsUnique()) { + if (index_entry->GetIndexName() == name) { return false; } } } - return true; -} -optional_ptr TableIndexList::Find(const string &name) { - for (auto &index : indexes) { - if (index->GetIndexName() == name) { - return index->Cast(); - } - } - return nullptr; + return true; } void TableIndexList::InitializeIndexes(ClientContext &context, DataTableInfo &table_info, const char *index_type) { @@ -79,13 +73,11 @@ void TableIndexList::InitializeIndexes(ClientContext &context, DataTableInfo &ta return; } - // Get the table from the catalog, so we can add it to the binder. + // Get the table from the catalog so we can add it to the binder auto &catalog = table_info.GetDB().GetCatalog(); - auto schema = table_info.GetSchemaName(); - auto table_name = table_info.GetTableName(); - auto &table_entry = catalog.GetEntry(context, CatalogType::TABLE_ENTRY, schema, table_name); - auto &table = table_entry.Cast(); - + auto &table = + catalog.GetEntry(context, CatalogType::TABLE_ENTRY, table_info.GetSchemaName(), table_info.GetTableName()) + .Cast(); vector column_types; vector column_names; for (auto &col : table.GetColumns().Logical()) { @@ -96,17 +88,19 @@ void TableIndexList::InitializeIndexes(ClientContext &context, DataTableInfo &ta lock_guard lock(indexes_lock); for (auto &index : indexes) { if (!index->IsBound() && (index_type == nullptr || index->GetIndexType() == index_type)) { - // Create a binder to bind this index. + // Create a binder to bind this index (we cant reuse this binder for other indexes) auto binder = Binder::CreateBinder(context); - // Add the table to the binder. - vector dummy_column_ids; - binder->bind_context.AddBaseTable(0, string(), column_names, column_types, dummy_column_ids, table); + // Add the table to the binder + // We're not interested in the column_ids here, so just pass a dummy vector + vector dummy_column_ids; + binder->bind_context.AddBaseTable(0, table_info.GetTableName(), column_names, column_types, + dummy_column_ids, &table); // Create an IndexBinder to bind the index IndexBinder idx_binder(*binder, context); - // Replace the unbound index with a bound index. + // Replace the unbound index with a bound index auto bound_idx = idx_binder.BindIndex(index->Cast()); index = std::move(bound_idx); } @@ -128,13 +122,15 @@ void TableIndexList::Move(TableIndexList &other) { indexes = std::move(other.indexes); } -Index *TableIndexList::FindForeignKeyIndex(const vector &fk_keys, const ForeignKeyType fk_type) { - for (auto &index : indexes) { - if (DataTable::IsForeignKeyIndex(fk_keys, *index, fk_type)) { - return &(*index); +Index *TableIndexList::FindForeignKeyIndex(const vector &fk_keys, ForeignKeyType fk_type) { + Index *result = nullptr; + Scan([&](Index &index) { + if (DataTable::IsForeignKeyIndex(fk_keys, index, fk_type)) { + result = &index; } - } - return nullptr; + return false; + }); + return result; } void TableIndexList::VerifyForeignKey(const vector &fk_keys, DataChunk &chunk, @@ -143,7 +139,7 @@ void TableIndexList::VerifyForeignKey(const vector &fk_keys, Data ? ForeignKeyType::FK_TYPE_PRIMARY_KEY_TABLE : ForeignKeyType::FK_TYPE_FOREIGN_KEY_TABLE; - // Check whether the chunk can be inserted or deleted into the referenced table storage. + // check whether the chunk can be inserted or deleted into the referenced table storage auto index = FindForeignKeyIndex(fk_keys, fk_type); if (!index) { throw InternalException("Internal Foreign Key error: could not find index to verify..."); @@ -151,36 +147,43 @@ void TableIndexList::VerifyForeignKey(const vector &fk_keys, Data if (!index->IsBound()) { throw InternalException("Internal Foreign Key error: trying to verify an unbound index..."); } - index->Cast().VerifyConstraint(chunk, nullptr, conflict_manager); + conflict_manager.SetIndexCount(1); + index->Cast().CheckConstraintsForChunk(chunk, conflict_manager); } -unordered_set TableIndexList::GetRequiredColumns() { +vector TableIndexList::GetRequiredColumns() { lock_guard lock(indexes_lock); - unordered_set column_ids; + set unique_indexes; for (auto &index : indexes) { - for (auto col_id : index->GetColumnIds()) { - column_ids.insert(col_id); + for (auto col_index : index->GetColumnIds()) { + unique_indexes.insert(col_index); } } - return column_ids; + vector result; + result.reserve(unique_indexes.size()); + for (auto column_index : unique_indexes) { + result.emplace_back(column_index); + } + return result; } vector TableIndexList::GetStorageInfos(const case_insensitive_map_t &options) { - vector infos; + + vector index_storage_infos; for (auto &index : indexes) { if (index->IsBound()) { - auto info = index->Cast().GetStorageInfo(options, false); - D_ASSERT(info.IsValid() && !info.name.empty()); - infos.push_back(info); + auto index_storage_info = index->Cast().GetStorageInfo(options, false); + D_ASSERT(index_storage_info.IsValid() && !index_storage_info.name.empty()); + index_storage_infos.push_back(index_storage_info); continue; } - auto info = index->Cast().GetStorageInfo(); - D_ASSERT(info.IsValid() && !info.name.empty()); - infos.push_back(info); + auto index_storage_info = index->Cast().GetStorageInfo(); + D_ASSERT(index_storage_info.IsValid() && !index_storage_info.name.empty()); + index_storage_infos.push_back(index_storage_info); } - return infos; + return index_storage_infos; } } // namespace duckdb diff --git a/src/duckdb/src/storage/temporary_file_manager.cpp b/src/duckdb/src/storage/temporary_file_manager.cpp index 478f5e338..845f295e0 100644 --- a/src/duckdb/src/storage/temporary_file_manager.cpp +++ b/src/duckdb/src/storage/temporary_file_manager.cpp @@ -1,104 +1,26 @@ #include "duckdb/storage/temporary_file_manager.hpp" - -#include "duckdb/common/chrono.hpp" -#include "duckdb/common/enum_util.hpp" -#include "duckdb/parallel/task_scheduler.hpp" #include "duckdb/storage/buffer/temporary_file_information.hpp" #include "duckdb/storage/standard_buffer_manager.hpp" -#include "zstd.h" namespace duckdb { //===--------------------------------------------------------------------===// -// TemporaryBufferSize -//===--------------------------------------------------------------------===// -bool TemporaryBufferSizeIsValid(const TemporaryBufferSize size) { - switch (size) { - case TemporaryBufferSize::S32K: - case TemporaryBufferSize::S64K: - case TemporaryBufferSize::S96K: - case TemporaryBufferSize::S128K: - case TemporaryBufferSize::S160K: - case TemporaryBufferSize::S192K: - case TemporaryBufferSize::S224K: - case TemporaryBufferSize::DEFAULT: - return true; - default: - return false; - } -} - -static TemporaryBufferSize SizeToTemporaryBufferSize(const idx_t size) { - D_ASSERT(size != 0 && size % TEMPORARY_BUFFER_SIZE_GRANULARITY == 0); - const auto res = static_cast(size); - D_ASSERT(TemporaryBufferSizeIsValid(res)); - return res; -} - -static idx_t TemporaryBufferSizeToSize(const TemporaryBufferSize size) { - D_ASSERT(TemporaryBufferSizeIsValid(size)); - return static_cast(size); -} - -static TemporaryBufferSize RoundUpSizeToTemporaryBufferSize(const idx_t size) { - return SizeToTemporaryBufferSize(AlignValue(size)); -} - -static const vector TemporaryBufferSizes() { - return {TemporaryBufferSize::S32K, TemporaryBufferSize::S64K, TemporaryBufferSize::S96K, - TemporaryBufferSize::S128K, TemporaryBufferSize::S160K, TemporaryBufferSize::S192K, - TemporaryBufferSize::S224K, TemporaryBufferSize::DEFAULT}; -} - -static TemporaryBufferSize MinimumCompressedTemporaryBufferSize() { - return TemporaryBufferSize::S32K; -} - -static TemporaryBufferSize MaximumCompressedTemporaryBufferSize() { - return TemporaryBufferSize::S224K; -} - -//===--------------------------------------------------------------------===// -// TemporaryFileIdentifier/TemporaryFileIndex +// BlockIndexManager //===--------------------------------------------------------------------===// -TemporaryFileIdentifier::TemporaryFileIdentifier() : size(TemporaryBufferSize::INVALID) { -} - -TemporaryFileIdentifier::TemporaryFileIdentifier(TemporaryBufferSize size_p, idx_t file_index_p) - : size(size_p), file_index(file_index_p) { -} - -bool TemporaryFileIdentifier::IsValid() const { - return size != TemporaryBufferSize::INVALID && file_index.IsValid(); -} - -TemporaryFileIndex::TemporaryFileIndex() { -} - -TemporaryFileIndex::TemporaryFileIndex(TemporaryFileIdentifier identifier_p, idx_t block_index_p) - : identifier(identifier_p), block_index(block_index_p) { -} -bool TemporaryFileIndex::IsValid() const { - return identifier.IsValid() && block_index.IsValid(); +BlockIndexManager::BlockIndexManager(TemporaryFileManager &manager) : max_index(0), manager(&manager) { } -//===--------------------------------------------------------------------===// -// BlockIndexManager -//===--------------------------------------------------------------------===// BlockIndexManager::BlockIndexManager() : max_index(0), manager(nullptr) { } -BlockIndexManager::BlockIndexManager(TemporaryFileManager &manager) : max_index(0), manager(&manager) { -} - -idx_t BlockIndexManager::GetNewBlockIndex(const TemporaryBufferSize size) { - auto index = GetNewBlockIndexInternal(size); +idx_t BlockIndexManager::GetNewBlockIndex() { + auto index = GetNewBlockIndexInternal(); indexes_in_use.insert(index); return index; } -bool BlockIndexManager::RemoveIndex(idx_t index, const TemporaryBufferSize size) { +bool BlockIndexManager::RemoveIndex(idx_t index) { // remove this block from the set of blocks auto entry = indexes_in_use.find(index); if (entry == indexes_in_use.end()) { @@ -113,9 +35,9 @@ bool BlockIndexManager::RemoveIndex(idx_t index, const TemporaryBufferSize size) if (max_index_in_use < max_index) { // max index in use is lower than the max_index // reduce the max_index - SetMaxIndex(max_index_in_use, size); + SetMaxIndex(max_index_in_use); // we can remove any free_indexes that are larger than the current max_index - while (HasFreeBlocks()) { + while (!free_indexes.empty()) { auto max_entry = *free_indexes.rbegin(); if (max_entry < max_index) { break; @@ -127,41 +49,28 @@ bool BlockIndexManager::RemoveIndex(idx_t index, const TemporaryBufferSize size) return false; } -idx_t BlockIndexManager::GetMaxIndex() const { +idx_t BlockIndexManager::GetMaxIndex() { return max_index; } -bool BlockIndexManager::HasFreeBlocks() const { +bool BlockIndexManager::HasFreeBlocks() { return !free_indexes.empty(); } -idx_t BlockIndexManager::GetNewBlockIndexInternal(const TemporaryBufferSize size) { - if (!HasFreeBlocks()) { - auto new_index = max_index; - SetMaxIndex(max_index + 1, size); - return new_index; - } - auto entry = free_indexes.begin(); - auto index = *entry; - free_indexes.erase(entry); - return index; -} - -void BlockIndexManager::SetMaxIndex(const idx_t new_index, const TemporaryBufferSize size) { - const auto temp_file_block_size = - size == TemporaryBufferSize::DEFAULT ? DEFAULT_BLOCK_ALLOC_SIZE : TemporaryBufferSizeToSize(size); +void BlockIndexManager::SetMaxIndex(idx_t new_index) { + static constexpr idx_t TEMP_FILE_BLOCK_SIZE = DEFAULT_BLOCK_ALLOC_SIZE; if (!manager) { max_index = new_index; } else { auto old = max_index; if (new_index < old) { max_index = new_index; - const auto difference = old - new_index; - const auto size_on_disk = difference * temp_file_block_size; + auto difference = old - new_index; + auto size_on_disk = difference * TEMP_FILE_BLOCK_SIZE; manager->DecreaseSizeOnDisk(size_on_disk); } else if (new_index > old) { - const auto difference = new_index - old; - const auto size_on_disk = difference * temp_file_block_size; + auto difference = new_index - old; + auto size_on_disk = difference * TEMP_FILE_BLOCK_SIZE; manager->IncreaseSizeOnDisk(size_on_disk); // Increase can throw, so this is only updated after it was successfully updated max_index = new_index; @@ -169,13 +78,27 @@ void BlockIndexManager::SetMaxIndex(const idx_t new_index, const TemporaryBuffer } } +idx_t BlockIndexManager::GetNewBlockIndexInternal() { + if (free_indexes.empty()) { + auto new_index = max_index; + SetMaxIndex(max_index + 1); + return new_index; + } + auto entry = free_indexes.begin(); + auto index = *entry; + free_indexes.erase(entry); + return index; +} + //===--------------------------------------------------------------------===// // TemporaryFileHandle //===--------------------------------------------------------------------===// -TemporaryFileHandle::TemporaryFileHandle(TemporaryFileManager &manager, TemporaryFileIdentifier identifier_p, - idx_t temp_file_count) - : db(manager.db), identifier(identifier_p), max_allowed_index((1 << temp_file_count) * MAX_ALLOWED_INDEX_BASE), - path(manager.CreateTemporaryFileName(identifier)), index_manager(manager) { + +TemporaryFileHandle::TemporaryFileHandle(idx_t temp_file_count, DatabaseInstance &db, const string &temp_directory, + idx_t index, TemporaryFileManager &manager) + : max_allowed_index((1 << temp_file_count) * MAX_ALLOWED_INDEX_BASE), db(db), file_index(index), + path(FileSystem::GetFileSystem(db).JoinPath(temp_directory, "duckdb_temp_storage-" + to_string(index) + ".tmp")), + index_manager(manager) { } TemporaryFileHandle::TemporaryFileLock::TemporaryFileLock(mutex &mutex) : lock(mutex) { @@ -190,47 +113,21 @@ TemporaryFileIndex TemporaryFileHandle::TryGetBlockIndex() { // open the file handle if it does not yet exist CreateFileIfNotExists(lock); // fetch a new block index to write to - auto block_index = index_manager.GetNewBlockIndex(identifier.size); - return TemporaryFileIndex(identifier, block_index); + auto block_index = index_manager.GetNewBlockIndex(); + return TemporaryFileIndex(file_index, block_index); } -unique_ptr TemporaryFileHandle::ReadTemporaryBuffer(idx_t block_index, - unique_ptr reusable_buffer) const { - auto &buffer_manager = BufferManager::GetBufferManager(db); - if (identifier.size == TemporaryBufferSize::DEFAULT) { - return StandardBufferManager::ReadTemporaryBufferInternal( - buffer_manager, *handle, GetPositionInFile(block_index), buffer_manager.GetBlockSize(), - std::move(reusable_buffer)); - } - - // Read compressed buffer - auto compressed_buffer = Allocator::Get(db).Allocate(TemporaryBufferSizeToSize(identifier.size)); - handle->Read(compressed_buffer.get(), compressed_buffer.GetSize(), GetPositionInFile(block_index)); - - // Decompress into buffer - auto buffer = buffer_manager.ConstructManagedBuffer(buffer_manager.GetBlockSize(), std::move(reusable_buffer)); - - const auto compressed_size = Load(compressed_buffer.get()); - D_ASSERT(!duckdb_zstd::ZSTD_isError(compressed_size)); - const auto decompressed_size = duckdb_zstd::ZSTD_decompress( - buffer->InternalBuffer(), buffer->AllocSize(), compressed_buffer.get() + sizeof(idx_t), compressed_size); - (void)decompressed_size; - D_ASSERT(!duckdb_zstd::ZSTD_isError(decompressed_size)); - - D_ASSERT(decompressed_size == buffer->AllocSize()); - return buffer; +void TemporaryFileHandle::WriteTemporaryFile(FileBuffer &buffer, TemporaryFileIndex index) { + // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. + D_ASSERT(buffer.size == BufferManager::GetBufferManager(db).GetBlockSize()); + buffer.Write(*handle, GetPositionInFile(index.block_index)); } -void TemporaryFileHandle::WriteTemporaryBuffer(FileBuffer &buffer, const idx_t block_index, - AllocatedData &compressed_buffer) const { - // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. - D_ASSERT(buffer.AllocSize() == BufferManager::GetBufferManager(db).GetBlockAllocSize()); - if (identifier.size == TemporaryBufferSize::DEFAULT) { - buffer.Write(*handle, GetPositionInFile(block_index)); - } else { - handle->Write(compressed_buffer.get(), TemporaryBufferSizeToSize(identifier.size), - GetPositionInFile(block_index)); - } +unique_ptr TemporaryFileHandle::ReadTemporaryBuffer(idx_t block_index, + unique_ptr reusable_buffer) { + return StandardBufferManager::ReadTemporaryBufferInternal( + BufferManager::GetBufferManager(db), *handle, GetPositionInFile(block_index), + BufferManager::GetBufferManager(db).GetBlockSize(), std::move(reusable_buffer)); } void TemporaryFileHandle::EraseBlockIndex(block_id_t block_index) { @@ -272,7 +169,7 @@ void TemporaryFileHandle::CreateFileIfNotExists(TemporaryFileLock &) { void TemporaryFileHandle::RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) { // remove the block index from the index manager - if (index_manager.RemoveIndex(index, identifier.size)) { + if (index_manager.RemoveIndex(index)) { // the max_index that is currently in use has decreased // as a result we can truncate the file #ifndef WIN32 // this ended up causing issues when sorting @@ -283,165 +180,113 @@ void TemporaryFileHandle::RemoveTempBlockIndex(TemporaryFileLock &, idx_t index) } } -idx_t TemporaryFileHandle::GetPositionInFile(const idx_t index) const { - return index * static_cast(identifier.size); +idx_t TemporaryFileHandle::GetPositionInFile(idx_t index) { + return index * BufferManager::GetBufferManager(db).GetBlockAllocSize(); } //===--------------------------------------------------------------------===// -// TemporaryFileMap +// TemporaryDirectoryHandle //===--------------------------------------------------------------------===// -TemporaryFileMap::TemporaryFileMap(TemporaryFileManager &manager_p) : manager(manager_p) { -} - -void TemporaryFileMap::Clear() { - files.clear(); -} - -TemporaryFileMap::temporary_file_map_t &TemporaryFileMap::GetMapForSize(const TemporaryBufferSize size) { - D_ASSERT(TemporaryBufferSizeIsValid(size)); - return files[size]; -} -optional_ptr TemporaryFileMap::GetFile(const TemporaryFileIdentifier &identifier) { - D_ASSERT(identifier.IsValid()); - auto &map = GetMapForSize(identifier.size); - const auto it = map.find(identifier.file_index.GetIndex()); - return it == map.end() ? nullptr : it->second.get(); +TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space) + : db(db), temp_directory(std::move(path_p)), temp_file(make_uniq(db, temp_directory)) { + auto &fs = FileSystem::GetFileSystem(db); + D_ASSERT(!temp_directory.empty()); + if (!fs.DirectoryExists(temp_directory)) { + fs.CreateDirectory(temp_directory); + created_directory = true; + } + temp_file->SetMaxSwapSpace(max_swap_space); } -TemporaryFileHandle &TemporaryFileMap::CreateFile(const TemporaryFileIdentifier &identifier) { - D_ASSERT(identifier.IsValid()); - D_ASSERT(!GetFile(identifier)); - auto &map = GetMapForSize(identifier.size); - const auto res = - map.emplace(identifier.file_index.GetIndex(), make_uniq(manager, identifier, map.size())); - D_ASSERT(res.second); - return *res.first->second; +TemporaryDirectoryHandle::~TemporaryDirectoryHandle() { + // first release any temporary files + temp_file.reset(); + // then delete the temporary file directory + auto &fs = FileSystem::GetFileSystem(db); + if (!temp_directory.empty()) { + bool delete_directory = created_directory; + vector files_to_delete; + if (!created_directory) { + bool deleted_everything = true; + fs.ListFiles(temp_directory, [&](const string &path, bool isdir) { + if (isdir) { + deleted_everything = false; + return; + } + if (!StringUtil::StartsWith(path, "duckdb_temp_")) { + deleted_everything = false; + return; + } + files_to_delete.push_back(path); + }); + } + if (delete_directory) { + // we want to remove all files in the directory + fs.RemoveDirectory(temp_directory); + } else { + for (auto &file : files_to_delete) { + fs.RemoveFile(fs.JoinPath(temp_directory, file)); + } + } + } } -void TemporaryFileMap::EraseFile(const TemporaryFileIdentifier &identifier) { - D_ASSERT(identifier.IsValid()); - D_ASSERT(GetFile(identifier)); - GetMapForSize(identifier.size).erase(identifier.file_index.GetIndex()); +TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() { + return *temp_file; } //===--------------------------------------------------------------------===// -// TemporaryFileCompressionLevel/TemporaryFileCompressionAdaptivity +// TemporaryFileIndex //===--------------------------------------------------------------------===// -TemporaryFileCompressionAdaptivity::TemporaryFileCompressionAdaptivity() : last_uncompressed_write_ns(INITIAL_NS) { - for (idx_t i = 0; i < LEVELS; i++) { - last_compressed_writes_ns[i] = INITIAL_NS; - } -} -int64_t TemporaryFileCompressionAdaptivity::GetCurrentTimeNanos() { - return duration_cast(high_resolution_clock::now().time_since_epoch()).count(); +TemporaryFileIndex::TemporaryFileIndex(idx_t file_index, idx_t block_index) + : file_index(file_index), block_index(block_index) { } -TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::IndexToLevel(const idx_t index) { - return static_cast(NumericCast(index) * 2 - 5); -} - -idx_t TemporaryFileCompressionAdaptivity::LevelToIndex(const TemporaryCompressionLevel level) { - return NumericCast((static_cast(level) + 5) / 2); -} - -TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::MinimumCompressionLevel() { - return IndexToLevel(0); -} - -TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::MaximumCompressionLevel() { - return IndexToLevel(LEVELS - 1); +bool TemporaryFileIndex::IsValid() const { + return block_index != DConstants::INVALID_INDEX; } -TemporaryCompressionLevel TemporaryFileCompressionAdaptivity::GetCompressionLevel() { - idx_t min_compression_idx = 0; - TemporaryCompressionLevel level; - - double ratio; - bool should_compress; - - bool should_deviate; - bool deviate_uncompressed; - { - lock_guard guard(random_engine.lock); - - auto min_compressed_time = last_compressed_writes_ns[min_compression_idx]; - for (idx_t compression_idx = 1; compression_idx < LEVELS; compression_idx++) { - const auto time = last_compressed_writes_ns[compression_idx]; - if (time < min_compressed_time) { - min_compression_idx = compression_idx; - min_compressed_time = time; - } - } - level = IndexToLevel(min_compression_idx); - - ratio = static_cast(min_compressed_time) / static_cast(last_uncompressed_write_ns); - should_compress = ratio < DURATION_RATIO_THRESHOLD; - - should_deviate = random_engine.NextRandom() < COMPRESSION_DEVIATION; - deviate_uncompressed = random_engine.NextRandom() < 0.5; // Coin flip to deviate with just uncompressed - } +//===--------------------------------------------------------------------===// +// TemporaryFileManager +//===--------------------------------------------------------------------===// - TemporaryCompressionLevel result; - if (!should_deviate) { - result = should_compress ? level : TemporaryCompressionLevel::UNCOMPRESSED; // Don't deviate - } else if (!should_compress) { - result = MinimumCompressionLevel(); // Deviate from uncompressed -> go to fastest level - } else if (deviate_uncompressed) { - result = TemporaryCompressionLevel::UNCOMPRESSED; - } else if (level == MaximumCompressionLevel()) { - result = IndexToLevel(min_compression_idx - 1); // At highest level, go down one - } else if (ratio < 1.0) { // Compressed writes are faster, try increasing the compression level - result = IndexToLevel(min_compression_idx + 1); - } else { // Compressed writes are slower, try decreasing the compression level - result = level == MinimumCompressionLevel() - ? TemporaryCompressionLevel::UNCOMPRESSED // Already lowest level, go to uncompressed - : IndexToLevel(min_compression_idx - 1); +static idx_t GetDefaultMax(const string &path) { + D_ASSERT(!path.empty()); + auto disk_space = FileSystem::GetAvailableDiskSpace(path); + // Use the available disk space + // We have made sure that the file exists before we call this, it shouldn't fail + if (!disk_space.IsValid()) { + // But if it does (i.e because the system call is not implemented) + // we don't cap the available swap space + return DConstants::INVALID_INDEX - 1; } - return result; -} - -void TemporaryFileCompressionAdaptivity::Update(const TemporaryCompressionLevel level, const int64_t time_before_ns) { - const auto duration = GetCurrentTimeNanos() - time_before_ns; - auto &last_write_ns = level == TemporaryCompressionLevel::UNCOMPRESSED - ? last_uncompressed_write_ns - : last_compressed_writes_ns[LevelToIndex(level)]; - lock_guard guard(random_engine.lock); - last_write_ns = (last_write_ns * (WEIGHT - 1) + duration) / WEIGHT; + // Only use 90% of the available disk space + return static_cast(static_cast(disk_space.GetIndex()) * 0.9); } -//===--------------------------------------------------------------------===// -// TemporaryFileManager -//===--------------------------------------------------------------------===// TemporaryFileManager::TemporaryFileManager(DatabaseInstance &db, const string &temp_directory_p) - : db(db), temp_directory(temp_directory_p), files(*this), size_on_disk(0), max_swap_space(0) { + : db(db), temp_directory(temp_directory_p), size_on_disk(0), max_swap_space(0) { } TemporaryFileManager::~TemporaryFileManager() { - files.Clear(); + files.clear(); } -TemporaryFileManager::TemporaryFileManagerLock::TemporaryFileManagerLock(mutex &mutex) : lock(mutex) { +TemporaryFileManager::TemporaryManagerLock::TemporaryManagerLock(mutex &mutex) : lock(mutex) { } void TemporaryFileManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer &buffer) { // We group DEFAULT_BLOCK_ALLOC_SIZE blocks into the same file. - D_ASSERT(buffer.AllocSize() == BufferManager::GetBufferManager(db).GetBlockAllocSize()); - - const auto adaptivity_idx = TaskScheduler::GetEstimatedCPUId() % COMPRESSION_ADAPTIVITIES; - auto &compression_adaptivity = compression_adaptivities[adaptivity_idx]; - - const auto time_before_ns = TemporaryFileCompressionAdaptivity::GetCurrentTimeNanos(); - AllocatedData compressed_buffer; - const auto compression_result = CompressBuffer(compression_adaptivity, buffer, compressed_buffer); - + D_ASSERT(buffer.size == BufferManager::GetBufferManager(db).GetBlockSize()); TemporaryFileIndex index; - optional_ptr handle; + TemporaryFileHandle *handle = nullptr; + { - TemporaryFileManagerLock lock(manager_lock); + TemporaryManagerLock lock(manager_lock); // first check if we can write to an open existing file - for (auto &entry : files.GetMapForSize(compression_result.size)) { + for (auto &entry : files) { auto &temp_file = entry.second; index = temp_file->TryGetBlockIndex(); if (index.IsValid()) { @@ -451,51 +296,19 @@ void TemporaryFileManager::WriteTemporaryBuffer(block_id_t block_id, FileBuffer } if (!handle) { // no existing handle to write to; we need to create & open a new file - auto &size = compression_result.size; - const TemporaryFileIdentifier identifier(size, index_managers[size].GetNewBlockIndex(size)); - auto &new_file = files.CreateFile(identifier); - index = new_file.TryGetBlockIndex(); - handle = &new_file; + auto new_file_index = index_manager.GetNewBlockIndex(); + auto new_file = make_uniq(files.size(), db, temp_directory, new_file_index, *this); + handle = new_file.get(); + files[new_file_index] = std::move(new_file); + + index = handle->TryGetBlockIndex(); } D_ASSERT(used_blocks.find(block_id) == used_blocks.end()); used_blocks[block_id] = index; } D_ASSERT(handle); D_ASSERT(index.IsValid()); - - handle->WriteTemporaryBuffer(buffer, index.block_index.GetIndex(), compressed_buffer); - - compression_adaptivity.Update(compression_result.level, time_before_ns); -} - -TemporaryFileManager::CompressionResult -TemporaryFileManager::CompressBuffer(TemporaryFileCompressionAdaptivity &compression_adaptivity, FileBuffer &buffer, - AllocatedData &compressed_buffer) { - if (buffer.AllocSize() <= TemporaryBufferSizeToSize(MinimumCompressedTemporaryBufferSize())) { - // Buffer size is less or equal to the minimum compressed size - no point compressing - return {TemporaryBufferSize::DEFAULT, TemporaryCompressionLevel::UNCOMPRESSED}; - } - - const auto level = compression_adaptivity.GetCompressionLevel(); - if (level == TemporaryCompressionLevel::UNCOMPRESSED) { - return {TemporaryBufferSize::DEFAULT, TemporaryCompressionLevel::UNCOMPRESSED}; - } - - const auto compression_level = static_cast(level); - D_ASSERT(compression_level >= duckdb_zstd::ZSTD_minCLevel() && compression_level <= duckdb_zstd::ZSTD_maxCLevel()); - const auto zstd_bound = duckdb_zstd::ZSTD_compressBound(buffer.AllocSize()); - compressed_buffer = Allocator::Get(db).Allocate(sizeof(idx_t) + zstd_bound); - const auto zstd_size = duckdb_zstd::ZSTD_compress(compressed_buffer.get() + sizeof(idx_t), zstd_bound, - buffer.InternalBuffer(), buffer.AllocSize(), compression_level); - D_ASSERT(!duckdb_zstd::ZSTD_isError(zstd_size)); - Store(zstd_size, compressed_buffer.get()); - const auto compressed_size = sizeof(idx_t) + zstd_size; - - if (compressed_size > TemporaryBufferSizeToSize(MaximumCompressedTemporaryBufferSize())) { - return {TemporaryBufferSize::DEFAULT, level}; // Use default size if compression ratio is bad - } - - return {RoundUpSizeToTemporaryBufferSize(compressed_size), level}; + handle->WriteTemporaryFile(buffer, index); } bool TemporaryFileManager::HasTemporaryBuffer(block_id_t block_id) { @@ -503,7 +316,7 @@ bool TemporaryFileManager::HasTemporaryBuffer(block_id_t block_id) { return used_blocks.find(block_id) != used_blocks.end(); } -idx_t TemporaryFileManager::GetTotalUsedSpaceInBytes() const { +idx_t TemporaryFileManager::GetTotalUsedSpaceInBytes() { return size_on_disk.load(); } @@ -511,20 +324,6 @@ optional_idx TemporaryFileManager::GetMaxSwapSpace() const { return max_swap_space; } -static idx_t GetDefaultMax(const string &path) { - D_ASSERT(!path.empty()); - auto disk_space = FileSystem::GetAvailableDiskSpace(path); - // Use the available disk space - // We have made sure that the file exists before we call this, it shouldn't fail - if (!disk_space.IsValid()) { - // But if it does (i.e because the system call is not implemented) - // we don't cap the available swap space - return DConstants::INVALID_INDEX - 1; - } - // Only use 90% of the available disk space - return static_cast(static_cast(disk_space.GetIndex()) * 0.9); -} - void TemporaryFileManager::SetMaxSwapSpace(optional_idx limit) { idx_t new_limit; if (limit.IsValid()) { @@ -533,7 +332,7 @@ void TemporaryFileManager::SetMaxSwapSpace(optional_idx limit) { new_limit = GetDefaultMax(temp_directory); } - auto current_size_on_disk = GetTotalUsedSpaceInBytes(); + auto current_size_on_disk = size_on_disk.load(); if (current_size_on_disk > new_limit) { auto used = StringUtil::BytesToHumanReadableString(current_size_on_disk); auto max = StringUtil::BytesToHumanReadableString(new_limit); @@ -548,7 +347,7 @@ To get usage information of the temp_directory, use 'CALL duckdb_temporary_files } void TemporaryFileManager::IncreaseSizeOnDisk(idx_t bytes) { - auto current_size_on_disk = GetTotalUsedSpaceInBytes(); + auto current_size_on_disk = size_on_disk.load(); if (current_size_on_disk + bytes > max_swap_space) { auto used = StringUtil::BytesToHumanReadableString(current_size_on_disk); auto max = StringUtil::BytesToHumanReadableString(max_swap_space); @@ -569,125 +368,63 @@ void TemporaryFileManager::DecreaseSizeOnDisk(idx_t bytes) { unique_ptr TemporaryFileManager::ReadTemporaryBuffer(block_id_t id, unique_ptr reusable_buffer) { TemporaryFileIndex index; - optional_ptr handle; + TemporaryFileHandle *handle; { - TemporaryFileManagerLock lock(manager_lock); + TemporaryManagerLock lock(manager_lock); index = GetTempBlockIndex(lock, id); - handle = GetFileHandle(lock, index.identifier); + handle = GetFileHandle(lock, index.file_index); } - - auto buffer = handle->ReadTemporaryBuffer(index.block_index.GetIndex(), std::move(reusable_buffer)); + auto buffer = handle->ReadTemporaryBuffer(index.block_index, std::move(reusable_buffer)); { // remove the block (and potentially erase the temp file) - TemporaryFileManagerLock lock(manager_lock); - EraseUsedBlock(lock, id, *handle, index); + TemporaryManagerLock lock(manager_lock); + EraseUsedBlock(lock, id, handle, index); } return buffer; } void TemporaryFileManager::DeleteTemporaryBuffer(block_id_t id) { - TemporaryFileManagerLock lock(manager_lock); + TemporaryManagerLock lock(manager_lock); auto index = GetTempBlockIndex(lock, id); - auto handle = GetFileHandle(lock, index.identifier); - EraseUsedBlock(lock, id, *handle, index); + auto handle = GetFileHandle(lock, index.file_index); + EraseUsedBlock(lock, id, handle, index); } vector TemporaryFileManager::GetTemporaryFiles() { lock_guard lock(manager_lock); vector result; - for (auto &size : TemporaryBufferSizes()) { - for (const auto &file : files.GetMapForSize(size)) { - result.push_back(file.second->GetTemporaryFile()); - } + for (auto &file : files) { + result.push_back(file.second->GetTemporaryFile()); } return result; } -void TemporaryFileManager::EraseUsedBlock(TemporaryFileManagerLock &lock, block_id_t id, TemporaryFileHandle &handle, +void TemporaryFileManager::EraseUsedBlock(TemporaryManagerLock &lock, block_id_t id, TemporaryFileHandle *handle, TemporaryFileIndex index) { auto entry = used_blocks.find(id); if (entry == used_blocks.end()) { throw InternalException("EraseUsedBlock - Block %llu not found in used blocks", id); } used_blocks.erase(entry); - handle.EraseBlockIndex(NumericCast(index.block_index.GetIndex())); - if (handle.DeleteIfEmpty()) { - EraseFileHandle(lock, index.identifier); + handle->EraseBlockIndex(NumericCast(index.block_index)); + if (handle->DeleteIfEmpty()) { + EraseFileHandle(lock, index.file_index); } } -string TemporaryFileManager::CreateTemporaryFileName(const TemporaryFileIdentifier &identifier) const { - return FileSystem::GetFileSystem(db).JoinPath( - temp_directory, StringUtil::Format("duckdb_temp_storage_%s-%llu.tmp", EnumUtil::ToString(identifier.size), - identifier.file_index.GetIndex())); +// FIXME: returning a raw pointer??? +TemporaryFileHandle *TemporaryFileManager::GetFileHandle(TemporaryManagerLock &, idx_t index) { + return files[index].get(); } -optional_ptr TemporaryFileManager::GetFileHandle(TemporaryFileManagerLock &, - const TemporaryFileIdentifier &identifier) { - D_ASSERT(identifier.IsValid()); - return files.GetFile(identifier); -} - -TemporaryFileIndex TemporaryFileManager::GetTempBlockIndex(TemporaryFileManagerLock &, block_id_t id) { +TemporaryFileIndex TemporaryFileManager::GetTempBlockIndex(TemporaryManagerLock &, block_id_t id) { D_ASSERT(used_blocks.find(id) != used_blocks.end()); return used_blocks[id]; } -void TemporaryFileManager::EraseFileHandle(TemporaryFileManagerLock &, const TemporaryFileIdentifier &identifier) { - D_ASSERT(identifier.IsValid()); - files.EraseFile(identifier); - index_managers[identifier.size].RemoveIndex(identifier.file_index.GetIndex(), identifier.size); -} - -//===--------------------------------------------------------------------===// -// TemporaryDirectoryHandle -//===--------------------------------------------------------------------===// -TemporaryDirectoryHandle::TemporaryDirectoryHandle(DatabaseInstance &db, string path_p, optional_idx max_swap_space) - : db(db), temp_directory(std::move(path_p)), temp_file(make_uniq(db, temp_directory)) { - auto &fs = FileSystem::GetFileSystem(db); - D_ASSERT(!temp_directory.empty()); - if (!fs.DirectoryExists(temp_directory)) { - fs.CreateDirectory(temp_directory); - created_directory = true; - } - temp_file->SetMaxSwapSpace(max_swap_space); -} - -TemporaryDirectoryHandle::~TemporaryDirectoryHandle() { - // first release any temporary files - temp_file.reset(); - // then delete the temporary file directory - auto &fs = FileSystem::GetFileSystem(db); - if (!temp_directory.empty()) { - bool delete_directory = created_directory; - vector files_to_delete; - if (!created_directory) { - bool deleted_everything = true; - fs.ListFiles(temp_directory, [&](const string &path, bool isdir) { - if (isdir) { - deleted_everything = false; - return; - } - if (!StringUtil::StartsWith(path, "duckdb_temp_")) { - deleted_everything = false; - return; - } - files_to_delete.push_back(path); - }); - } - if (delete_directory) { - // we want to remove all files in the directory - fs.RemoveDirectory(temp_directory); - } else { - for (auto &file : files_to_delete) { - fs.RemoveFile(fs.JoinPath(temp_directory, file)); - } - } - } -} - -TemporaryFileManager &TemporaryDirectoryHandle::GetTempFile() const { - return *temp_file; +void TemporaryFileManager::EraseFileHandle(TemporaryManagerLock &, idx_t file_index) { + files.erase(file_index); + index_manager.RemoveIndex(file_index); } } // namespace duckdb diff --git a/src/duckdb/src/storage/wal_replay.cpp b/src/duckdb/src/storage/wal_replay.cpp index eefe70ef6..6d77b071f 100644 --- a/src/duckdb/src/storage/wal_replay.cpp +++ b/src/duckdb/src/storage/wal_replay.cpp @@ -162,29 +162,13 @@ class WriteAheadLogDeserializer { //===--------------------------------------------------------------------===// // Replay //===--------------------------------------------------------------------===// -unique_ptr WriteAheadLog::Replay(FileSystem &fs, AttachedDatabase &db, const string &wal_path) { - auto handle = fs.OpenFile(wal_path, FileFlags::FILE_FLAGS_READ | FileFlags::FILE_FLAGS_NULL_IF_NOT_EXISTS); - if (!handle) { - // WAL does not exist - instantiate an empty WAL - return make_uniq(db, wal_path); - } - auto wal_handle = ReplayInternal(db, std::move(handle)); - if (wal_handle) { - return wal_handle; - } - // replay returning NULL indicates we can nuke the WAL entirely - but only if this is not a read-only connection - if (!db.IsReadOnly()) { - fs.RemoveFile(wal_path); - } - return make_uniq(db, wal_path); -} -unique_ptr WriteAheadLog::ReplayInternal(AttachedDatabase &database, unique_ptr handle) { +bool WriteAheadLog::Replay(AttachedDatabase &database, unique_ptr handle) { Connection con(database.GetDatabase()); auto wal_path = handle->GetPath(); BufferedFileReader reader(FileSystem::Get(database), std::move(handle)); if (reader.Finished()) { - // WAL file exists but it is empty - we can delete the file - return nullptr; + // WAL is empty + return false; } con.BeginTransaction(); @@ -219,7 +203,7 @@ unique_ptr WriteAheadLog::ReplayInternal(AttachedDatabase &databa if (manager.IsCheckpointClean(checkpoint_state.checkpoint_id)) { // the contents of the WAL have already been checkpointed // we can safely truncate the WAL and ignore its contents - return nullptr; + return true; } } @@ -232,19 +216,15 @@ unique_ptr WriteAheadLog::ReplayInternal(AttachedDatabase &databa // replay the WAL // note that everything is wrapped inside a try/catch block here // there can be errors in WAL replay because of a corrupt WAL file - idx_t successful_offset = 0; - bool all_succeeded = false; try { while (true) { // read the current entry auto deserializer = WriteAheadLogDeserializer::Open(state, reader); if (deserializer.ReplayEntry()) { con.Commit(); - successful_offset = reader.offset; // check if the file is exhausted if (reader.Finished()) { // we finished reading the file: break - all_succeeded = true; break; } con.BeginTransaction(); @@ -266,8 +246,7 @@ unique_ptr WriteAheadLog::ReplayInternal(AttachedDatabase &databa con.Query("ROLLBACK"); throw; } // LCOV_EXCL_STOP - auto init_state = all_succeeded ? WALInitState::UNINITIALIZED : WALInitState::UNINITIALIZED_REQUIRES_TRUNCATE; - return make_uniq(database, wal_path, successful_offset, init_state); + return false; } //===--------------------------------------------------------------------===// @@ -391,103 +370,12 @@ void WriteAheadLogDeserializer::ReplayDropTable() { catalog.DropEntry(context, info); } -void ReplayWithoutIndex(ClientContext &context, Catalog &catalog, AlterInfo &info, const bool only_deserialize) { - if (only_deserialize) { - return; - } - catalog.Alter(context, info); -} - -void ReplayIndexData(AttachedDatabase &db, BinaryDeserializer &deserializer, IndexStorageInfo &info, - const bool deserialize_only) { - D_ASSERT(info.IsValid() && !info.name.empty()); - - auto &storage_manager = db.GetStorageManager(); - auto &single_file_sm = storage_manager.Cast(); - auto &block_manager = single_file_sm.block_manager; - auto &buffer_manager = block_manager->buffer_manager; - - deserializer.ReadList(103, "index_storage", [&](Deserializer::List &list, idx_t i) { - auto &data_info = info.allocator_infos[i]; - - // Read the data into buffer handles and convert them to blocks on disk. - for (idx_t j = 0; j < data_info.allocation_sizes.size(); j++) { - - // Read the data into a buffer handle. - auto buffer_handle = buffer_manager.Allocate(MemoryTag::ART_INDEX, block_manager->GetBlockSize(), false); - auto block_handle = buffer_handle.GetBlockHandle(); - auto data_ptr = buffer_handle.Ptr(); - - list.ReadElement(data_ptr, data_info.allocation_sizes[j]); - - // Convert the buffer handle to a persistent block and store the block id. - if (!deserialize_only) { - auto block_id = block_manager->GetFreeBlockId(); - block_manager->ConvertToPersistent(block_id, std::move(block_handle), std::move(buffer_handle)); - data_info.block_pointers[j].block_id = block_id; - } - } - }); -} - void WriteAheadLogDeserializer::ReplayAlter() { auto info = deserializer.ReadProperty>(101, "info"); auto &alter_info = info->Cast(); - if (!alter_info.IsAddPrimaryKey()) { - return ReplayWithoutIndex(context, catalog, alter_info, DeserializeOnly()); - } - - auto index_storage_info = deserializer.ReadProperty(102, "index_storage_info"); - ReplayIndexData(db, deserializer, index_storage_info, DeserializeOnly()); if (DeserializeOnly()) { return; } - - auto &table_info = alter_info.Cast(); - auto &constraint_info = table_info.Cast(); - auto &unique_info = constraint_info.constraint->Cast(); - - auto &table = - catalog.GetEntry(context, table_info.schema, table_info.name).Cast(); - auto &column_list = table.GetColumns(); - - // Add the table to the bind context to bind the parsed expressions. - auto binder = Binder::CreateBinder(context); - vector column_types; - vector column_names; - for (auto &col : column_list.Logical()) { - column_types.push_back(col.Type()); - column_names.push_back(col.Name()); - } - - // Create a binder to bind the parsed expressions. - vector column_indexes; - binder->bind_context.AddBaseTable(0, string(), column_names, column_types, column_indexes, table); - IndexBinder idx_binder(*binder, context); - - // Bind the parsed expressions to create unbound expressions. - vector> unbound_expressions; - auto logical_indexes = unique_info.GetLogicalIndexes(column_list); - for (const auto &logical_index : logical_indexes) { - auto &col = column_list.GetColumn(logical_index); - unique_ptr parsed = make_uniq(col.GetName(), table_info.name); - unbound_expressions.push_back(idx_binder.Bind(parsed)); - } - - vector column_ids; - for (auto &column_index : column_indexes) { - column_ids.push_back(column_index.GetPrimaryIndex()); - } - - auto &storage = table.GetStorage(); - CreateIndexInput input(TableIOManager::Get(storage), storage.db, IndexConstraintType::PRIMARY, - index_storage_info.name, column_ids, unbound_expressions, index_storage_info, - index_storage_info.options); - - auto index_type = context.db->config.GetIndexTypes().FindByName(ART::TYPE_NAME); - auto index_instance = index_type->create_instance(input); - storage.AddIndex(std::move(index_instance)); - catalog.Alter(context, alter_info); } @@ -651,15 +539,40 @@ void WriteAheadLogDeserializer::ReplayDropTableMacro() { void WriteAheadLogDeserializer::ReplayCreateIndex() { auto create_info = deserializer.ReadProperty>(101, "index_catalog_entry"); auto index_info = deserializer.ReadProperty(102, "index_storage_info"); + D_ASSERT(index_info.IsValid() && !index_info.name.empty()); + + auto &storage_manager = db.GetStorageManager(); + auto &single_file_sm = storage_manager.Cast(); + auto &block_manager = single_file_sm.block_manager; + auto &buffer_manager = block_manager->buffer_manager; + + deserializer.ReadList(103, "index_storage", [&](Deserializer::List &list, idx_t i) { + auto &data_info = index_info.allocator_infos[i]; + + // read the data into buffer handles and convert them to blocks on disk + // then, update the block pointer + for (idx_t j = 0; j < data_info.allocation_sizes.size(); j++) { + + // read the data into a buffer handle + auto buffer_handle = buffer_manager.Allocate(MemoryTag::ART_INDEX, block_manager->GetBlockSize(), false); + auto block_handle = buffer_handle.GetBlockHandle(); + auto data_ptr = buffer_handle.Ptr(); + + list.ReadElement(data_ptr, data_info.allocation_sizes[j]); + + // now convert the buffer handle to a persistent block and remember the block id + auto block_id = block_manager->GetFreeBlockId(); + block_manager->ConvertToPersistent(block_id, std::move(block_handle)); + data_info.block_pointers[j].block_id = block_id; + } + }); - ReplayIndexData(db, deserializer, index_info, DeserializeOnly()); if (DeserializeOnly()) { return; } - auto &info = create_info->Cast(); - // Ensure that the index type exists. + // Ensure the index type exists if (info.index_type.empty()) { info.index_type = ART::TYPE_NAME; } @@ -669,11 +582,11 @@ void WriteAheadLogDeserializer::ReplayCreateIndex() { throw InternalException("Index type \"%s\" not recognized", info.index_type); } - // Create the index in the catalog. + // create the index in the catalog auto &table = catalog.GetEntry(context, create_info->schema, info.table).Cast(); auto &index = table.schema.CreateIndex(context, info, table)->Cast(); - // Add the table to the bind context to bind the parsed expressions. + // add the table to the bind context to bind the parsed expressions auto binder = Binder::CreateBinder(context); vector column_types; vector column_names; @@ -683,22 +596,25 @@ void WriteAheadLogDeserializer::ReplayCreateIndex() { } // create a binder to bind the parsed expressions - vector column_ids; - binder->bind_context.AddBaseTable(0, string(), column_names, column_types, column_ids, table); + vector column_ids; + binder->bind_context.AddBaseTable(0, info.table, column_names, column_types, column_ids, &table); IndexBinder idx_binder(*binder, context); - // Bind the parsed expressions to create unbound expressions. + // bind the parsed expressions to create unbound expressions vector> unbound_expressions; + unbound_expressions.reserve(index.parsed_expressions.size()); for (auto &expr : index.parsed_expressions) { auto copy = expr->Copy(); unbound_expressions.push_back(idx_binder.Bind(copy)); } - auto &storage = table.GetStorage(); - CreateIndexInput input(TableIOManager::Get(storage), storage.db, info.constraint_type, info.index_name, + auto &data_table = table.GetStorage(); + + CreateIndexInput input(TableIOManager::Get(data_table), data_table.db, info.constraint_type, info.index_name, info.column_ids, unbound_expressions, index_info, info.options); + auto index_instance = index_type->create_instance(input); - storage.AddIndex(std::move(index_instance)); + data_table.AddIndex(std::move(index_instance)); } void WriteAheadLogDeserializer::ReplayDropIndex() { @@ -735,10 +651,10 @@ void WriteAheadLogDeserializer::ReplayInsert() { throw InternalException("Corrupt WAL: insert without table"); } - // Append to the current table without constraint verification. + // append to the current table + // we don't do any constraint verification here vector> bound_constraints; - auto &storage = state.current_table->GetStorage(); - storage.LocalAppend(*state.current_table, context, chunk, bound_constraints); + state.current_table->GetStorage().LocalAppend(*state.current_table, context, chunk, bound_constraints); } static void MarkBlocksAsUsed(BlockManager &manager, const PersistentColumnData &col_data) { @@ -783,7 +699,7 @@ void WriteAheadLogDeserializer::ReplayRowGroupData() { } auto &storage = state.current_table->GetStorage(); auto &table_info = storage.GetDataTableInfo(); - RowGroupCollection new_row_groups(table_info, table_info->GetIOManager(), storage.GetTypes(), 0); + RowGroupCollection new_row_groups(table_info, block_manager, storage.GetTypes(), 0); new_row_groups.Initialize(data); TableIndexList index_list; storage.MergeStorage(new_row_groups, index_list, nullptr); diff --git a/src/duckdb/src/storage/write_ahead_log.cpp b/src/duckdb/src/storage/write_ahead_log.cpp index 1a1b4250d..ba9db9eee 100644 --- a/src/duckdb/src/storage/write_ahead_log.cpp +++ b/src/duckdb/src/storage/write_ahead_log.cpp @@ -1,39 +1,35 @@ #include "duckdb/storage/write_ahead_log.hpp" #include "duckdb/catalog/catalog_entry/duck_index_entry.hpp" -#include "duckdb/catalog/catalog_entry/duck_table_entry.hpp" #include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" -#include "duckdb/common/checksum.hpp" #include "duckdb/common/serializer/binary_serializer.hpp" -#include "duckdb/common/serializer/memory_stream.hpp" -#include "duckdb/execution/index/bound_index.hpp" #include "duckdb/main/database.hpp" -#include "duckdb/parser/constraints/unique_constraint.hpp" #include "duckdb/parser/parsed_data/alter_table_info.hpp" -#include "duckdb/storage/data_table.hpp" #include "duckdb/storage/index.hpp" -#include "duckdb/storage/table/column_data.hpp" +#include "duckdb/execution/index/bound_index.hpp" #include "duckdb/storage/table/data_table_info.hpp" #include "duckdb/storage/table_io_manager.hpp" +#include "duckdb/common/checksum.hpp" +#include "duckdb/common/serializer/memory_stream.hpp" +#include "duckdb/storage/table/column_data.hpp" namespace duckdb { -constexpr uint64_t WAL_VERSION_NUMBER = 2; +const uint64_t WAL_VERSION_NUMBER = 2; -WriteAheadLog::WriteAheadLog(AttachedDatabase &database, const string &wal_path, idx_t wal_size, - WALInitState init_state) - : database(database), wal_path(wal_path), wal_size(wal_size), init_state(init_state) { +WriteAheadLog::WriteAheadLog(AttachedDatabase &database, const string &wal_path) + : database(database), wal_path(wal_path), wal_size(0), initialized(false) { } WriteAheadLog::~WriteAheadLog() { } BufferedFileWriter &WriteAheadLog::Initialize() { - if (Initialized()) { + if (initialized) { return *writer; } lock_guard lock(wal_lock); @@ -41,22 +37,25 @@ BufferedFileWriter &WriteAheadLog::Initialize() { writer = make_uniq(FileSystem::Get(database), wal_path, FileFlags::FILE_FLAGS_WRITE | FileFlags::FILE_FLAGS_FILE_CREATE | FileFlags::FILE_FLAGS_APPEND); - if (init_state == WALInitState::UNINITIALIZED_REQUIRES_TRUNCATE) { - writer->Truncate(wal_size); - } wal_size = writer->GetFileSize(); - init_state = WALInitState::INITIALIZED; + initialized = true; } return *writer; } //! Gets the total bytes written to the WAL since startup -idx_t WriteAheadLog::GetWALSize() const { - D_ASSERT(init_state != WALInitState::NO_WAL || wal_size == 0); +idx_t WriteAheadLog::GetWALSize() { + if (!Initialized()) { + auto &fs = FileSystem::Get(database); + if (!fs.FileExists(wal_path)) { + return 0; + } + Initialize(); + } return wal_size; } -idx_t WriteAheadLog::GetTotalWritten() const { +idx_t WriteAheadLog::GetTotalWritten() { if (!Initialized()) { return 0; } @@ -64,32 +63,20 @@ idx_t WriteAheadLog::GetTotalWritten() const { } void WriteAheadLog::Truncate(idx_t size) { - if (init_state == WALInitState::NO_WAL) { - // no WAL to truncate - return; - } if (!Initialized()) { - init_state = WALInitState::UNINITIALIZED_REQUIRES_TRUNCATE; - wal_size = size; return; } writer->Truncate(size); wal_size = writer->GetFileSize(); } -bool WriteAheadLog::Initialized() const { - return init_state == WALInitState::INITIALIZED; -} - void WriteAheadLog::Delete() { - if (init_state == WALInitState::NO_WAL) { - // no WAL to delete + if (!Initialized()) { return; } writer.reset(); auto &fs = FileSystem::Get(database); fs.RemoveFile(wal_path); - init_state = WALInitState::NO_WAL; wal_size = 0; } @@ -272,42 +259,44 @@ void WriteAheadLog::WriteDropTableMacro(const TableMacroCatalogEntry &entry) { // Indexes //===--------------------------------------------------------------------===// -void SerializeIndex(AttachedDatabase &db, WriteAheadLogSerializer &serializer, TableIndexList &list, - const string &name) { - const auto &db_options = db.GetDatabase().config.options; +void SerializeIndexToWAL(WriteAheadLogSerializer &serializer, Index &index, + const case_insensitive_map_t &options) { + + // We will never write an index to the WAL that is not bound + D_ASSERT(index.IsBound()); + const auto index_storage_info = index.Cast().GetStorageInfo(options, true); + serializer.WriteProperty(102, "index_storage_info", index_storage_info); + + serializer.WriteList(103, "index_storage", index_storage_info.buffers.size(), [&](Serializer::List &list, idx_t i) { + auto &buffers = index_storage_info.buffers[i]; + for (auto buffer : buffers) { + list.WriteElement(buffer.buffer_ptr, buffer.allocation_size); + } + }); +} + +void WriteAheadLog::WriteCreateIndex(const IndexCatalogEntry &entry) { + WriteAheadLogSerializer serializer(*this, WALType::CREATE_INDEX); + serializer.WriteProperty(101, "index_catalog_entry", &entry); + + auto db_options = database.GetDatabase().config.options; auto v1_0_0_storage = db_options.serialization_compatibility.serialization_version < 3; case_insensitive_map_t options; if (!v1_0_0_storage) { options.emplace("v1_0_0_storage", v1_0_0_storage); } - list.Scan([&](Index &index) { - if (name == index.GetIndexName()) { - // We never write an unbound index to the WAL. - D_ASSERT(index.IsBound()); - - const auto &info = index.Cast().GetStorageInfo(options, true); - serializer.WriteProperty(102, "index_storage_info", info); - serializer.WriteList(103, "index_storage", info.buffers.size(), [&](Serializer::List &list, idx_t i) { - auto &buffers = info.buffers[i]; - for (auto buffer : buffers) { - list.WriteElement(buffer.buffer_ptr, buffer.allocation_size); - } - }); + // now serialize the index data to the persistent storage and write the index metadata + auto &duck_index_entry = entry.Cast(); + auto &table_idx_list = duck_index_entry.GetDataTableInfo().GetIndexes(); + + table_idx_list.Scan([&](Index &index) { + if (duck_index_entry.name == index.GetIndexName()) { + SerializeIndexToWAL(serializer, index, options); return true; } return false; }); -} - -void WriteAheadLog::WriteCreateIndex(const IndexCatalogEntry &entry) { - WriteAheadLogSerializer serializer(*this, WALType::CREATE_INDEX); - serializer.WriteProperty(101, "index_catalog_entry", &entry); - - // Serialize the index data to the persistent storage and write the metadata. - auto &index_entry = entry.Cast(); - auto &list = index_entry.GetDataTableInfo().GetIndexes(); - SerializeIndex(database, serializer, list, index_entry.name); serializer.End(); } @@ -411,25 +400,9 @@ void WriteAheadLog::WriteUpdate(DataChunk &chunk, const vector &column //===--------------------------------------------------------------------===// // Write ALTER Statement //===--------------------------------------------------------------------===// -void WriteAheadLog::WriteAlter(CatalogEntry &entry, const AlterInfo &info) { +void WriteAheadLog::WriteAlter(const AlterInfo &info) { WriteAheadLogSerializer serializer(*this, WALType::ALTER_INFO); serializer.WriteProperty(101, "info", &info); - - if (!info.IsAddPrimaryKey()) { - return serializer.End(); - } - - auto &table_info = info.Cast(); - auto &constraint_info = table_info.Cast(); - auto &unique = constraint_info.constraint->Cast(); - - auto &table_entry = entry.Cast(); - auto &parent = table_entry.Parent().Cast(); - auto &parent_info = parent.GetStorage().GetDataTableInfo(); - auto &list = parent_info->GetIndexes(); - - auto name = unique.GetName(parent.name); - SerializeIndex(database, serializer, list, name); serializer.End(); } diff --git a/src/duckdb/src/transaction/cleanup_state.cpp b/src/duckdb/src/transaction/cleanup_state.cpp index f9a17f265..2b2c33bb9 100644 --- a/src/duckdb/src/transaction/cleanup_state.cpp +++ b/src/duckdb/src/transaction/cleanup_state.cpp @@ -54,6 +54,7 @@ void CleanupState::CleanupEntry(UndoFlags type, data_ptr_t data) { void CleanupState::CleanupUpdate(UpdateInfo &info) { // remove the update info from the update chain + // first obtain an exclusive lock on the segment info.segment->CleanupUpdate(info); } diff --git a/src/duckdb/src/transaction/commit_state.cpp b/src/duckdb/src/transaction/commit_state.cpp index d4b934d58..821522cb6 100644 --- a/src/duckdb/src/transaction/commit_state.cpp +++ b/src/duckdb/src/transaction/commit_state.cpp @@ -5,7 +5,6 @@ #include "duckdb/catalog/catalog_entry/scalar_macro_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/type_catalog_entry.hpp" #include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp" -#include "duckdb/catalog/catalog_entry/dependency/dependency_entry.hpp" #include "duckdb/catalog/duck_catalog.hpp" #include "duckdb/common/serializer/binary_deserializer.hpp" #include "duckdb/common/serializer/memory_stream.hpp" @@ -17,12 +16,10 @@ #include "duckdb/transaction/append_info.hpp" #include "duckdb/transaction/delete_info.hpp" #include "duckdb/transaction/update_info.hpp" -#include "duckdb/transaction/duck_transaction.hpp" namespace duckdb { -CommitState::CommitState(DuckTransaction &transaction_p, transaction_t commit_id) - : transaction(transaction_p), commit_id(commit_id) { +CommitState::CommitState(transaction_t commit_id) : commit_id(commit_id) { } void CommitState::CommitEntryDrop(CatalogEntry &entry, data_ptr_t dataptr) { @@ -136,30 +133,24 @@ void CommitState::CommitEntryDrop(CatalogEntry &entry, data_ptr_t dataptr) { void CommitState::CommitEntry(UndoFlags type, data_ptr_t data) { switch (type) { case UndoFlags::CATALOG_ENTRY: { - auto &old_entry = *Load(data); - D_ASSERT(old_entry.HasParent()); + // set the commit timestamp of the catalog entry to the given id + auto catalog_entry = Load(data); + D_ASSERT(catalog_entry->HasParent()); - auto &catalog = old_entry.ParentCatalog(); + auto &catalog = catalog_entry->ParentCatalog(); D_ASSERT(catalog.IsDuckCatalog()); - auto &new_entry = old_entry.Parent(); - if (new_entry.type == CatalogType::DEPENDENCY_ENTRY) { - auto &dep = new_entry.Cast(); - if (dep.Side() == DependencyEntryType::SUBJECT) { - new_entry.set->VerifyExistenceOfDependency(commit_id, new_entry); - } - } else if (new_entry.type == CatalogType::DELETED_ENTRY && old_entry.set) { - old_entry.set->CommitDrop(commit_id, transaction.start_time, old_entry); - } // Grab a write lock on the catalog auto &duck_catalog = catalog.Cast(); lock_guard write_lock(duck_catalog.GetWriteLock()); - lock_guard read_lock(old_entry.set->GetCatalogLock()); - // Set the timestamp of the catalog entry to the given commit_id, marking it as committed - CatalogSet::UpdateTimestamp(old_entry.Parent(), commit_id); + lock_guard read_lock(catalog_entry->set->GetCatalogLock()); + catalog_entry->set->UpdateTimestamp(catalog_entry->Parent(), commit_id); + if (!StringUtil::CIEquals(catalog_entry->name, catalog_entry->Parent().name)) { + catalog_entry->set->UpdateTimestamp(*catalog_entry, commit_id); + } // drop any blocks associated with the catalog entry if possible (e.g. in case of a DROP or ALTER) - CommitEntryDrop(old_entry, data + sizeof(CatalogEntry *)); + CommitEntryDrop(*catalog_entry, data + sizeof(CatalogEntry *)); break; } case UndoFlags::INSERT_TUPLE: { @@ -197,16 +188,16 @@ void CommitState::RevertCommit(UndoFlags type, data_ptr_t data) { // set the commit timestamp of the catalog entry to the given id auto catalog_entry = Load(data); D_ASSERT(catalog_entry->HasParent()); - CatalogSet::UpdateTimestamp(catalog_entry->Parent(), transaction_id); + catalog_entry->set->UpdateTimestamp(catalog_entry->Parent(), transaction_id); if (catalog_entry->name != catalog_entry->Parent().name) { - CatalogSet::UpdateTimestamp(*catalog_entry, transaction_id); + catalog_entry->set->UpdateTimestamp(*catalog_entry, transaction_id); } break; } case UndoFlags::INSERT_TUPLE: { auto info = reinterpret_cast(data); // revert this append - info->table->RevertAppend(transaction, info->start_row, info->count); + info->table->RevertAppend(info->start_row, info->count); break; } case UndoFlags::DELETE_TUPLE: { diff --git a/src/duckdb/src/transaction/duck_transaction.cpp b/src/duckdb/src/transaction/duck_transaction.cpp index 273f256b6..d47aee655 100644 --- a/src/duckdb/src/transaction/duck_transaction.cpp +++ b/src/duckdb/src/transaction/duck_transaction.cpp @@ -32,8 +32,8 @@ TransactionData::TransactionData(transaction_t transaction_id_p, transaction_t s DuckTransaction::DuckTransaction(DuckTransactionManager &manager, ClientContext &context_p, transaction_t start_time, transaction_t transaction_id, idx_t catalog_version_p) : Transaction(manager, context_p), start_time(start_time), transaction_id(transaction_id), commit_id(0), - highest_active_query(0), catalog_version(catalog_version_p), transaction_manager(manager), - undo_buffer(*this, context_p), storage(make_uniq(context_p, *this)) { + highest_active_query(0), catalog_version(catalog_version_p), transaction_manager(manager), undo_buffer(context_p), + storage(make_uniq(context_p, *this)) { } DuckTransaction::~DuckTransaction() { @@ -61,18 +61,17 @@ void DuckTransaction::PushCatalogEntry(CatalogEntry &entry, data_ptr_t extra_dat alloc_size += extra_data_size + sizeof(idx_t); } - auto undo_entry = undo_buffer.CreateEntry(UndoFlags::CATALOG_ENTRY, alloc_size); - auto ptr = undo_entry.Ptr(); + auto baseptr = undo_buffer.CreateEntry(UndoFlags::CATALOG_ENTRY, alloc_size); // store the pointer to the catalog entry - Store(&entry, ptr); + Store(&entry, baseptr); if (extra_data_size > 0) { // copy the extra data behind the catalog entry pointer (if any) - ptr += sizeof(CatalogEntry *); + baseptr += sizeof(CatalogEntry *); // first store the extra data size - Store(extra_data_size, ptr); - ptr += sizeof(idx_t); + Store(extra_data_size, baseptr); + baseptr += sizeof(idx_t); // then copy over the actual data - memcpy(ptr, extra_data, extra_data_size); + memcpy(baseptr, extra_data, extra_data_size); } } @@ -92,8 +91,7 @@ void DuckTransaction::PushDelete(DataTable &table, RowVersionManager &info, idx_ alloc_size += sizeof(uint16_t) * count; } - auto undo_entry = undo_buffer.CreateEntry(UndoFlags::DELETE_TUPLE, alloc_size); - auto delete_info = reinterpret_cast(undo_entry.Ptr()); + auto delete_info = reinterpret_cast(undo_buffer.CreateEntry(UndoFlags::DELETE_TUPLE, alloc_size)); delete_info->version_info = &info; delete_info->vector_idx = vector_idx; delete_info->table = &table; @@ -110,27 +108,30 @@ void DuckTransaction::PushDelete(DataTable &table, RowVersionManager &info, idx_ } void DuckTransaction::PushAppend(DataTable &table, idx_t start_row, idx_t row_count) { - auto undo_entry = undo_buffer.CreateEntry(UndoFlags::INSERT_TUPLE, sizeof(AppendInfo)); - auto append_info = reinterpret_cast(undo_entry.Ptr()); + auto append_info = + reinterpret_cast(undo_buffer.CreateEntry(UndoFlags::INSERT_TUPLE, sizeof(AppendInfo))); append_info->table = &table; append_info->start_row = start_row; append_info->count = row_count; } -UndoBufferReference DuckTransaction::CreateUpdateInfo(idx_t type_size, idx_t entries) { - idx_t alloc_size = UpdateInfo::GetAllocSize(type_size); - auto undo_entry = undo_buffer.CreateEntry(UndoFlags::UPDATE_TUPLE, alloc_size); - auto &update_info = UpdateInfo::Get(undo_entry); - UpdateInfo::Initialize(update_info, transaction_id); - return undo_entry; +UpdateInfo *DuckTransaction::CreateUpdateInfo(idx_t type_size, idx_t entries) { + data_ptr_t base_info = undo_buffer.CreateEntry( + UndoFlags::UPDATE_TUPLE, sizeof(UpdateInfo) + (sizeof(sel_t) + type_size) * STANDARD_VECTOR_SIZE); + auto update_info = reinterpret_cast(base_info); + update_info->max = STANDARD_VECTOR_SIZE; + update_info->tuples = reinterpret_cast(base_info + sizeof(UpdateInfo)); + update_info->tuple_data = base_info + sizeof(UpdateInfo) + sizeof(sel_t) * update_info->max; + update_info->version_number = transaction_id; + return update_info; } void DuckTransaction::PushSequenceUsage(SequenceCatalogEntry &sequence, const SequenceData &data) { lock_guard l(sequence_lock); auto entry = sequence_usage.find(sequence); if (entry == sequence_usage.end()) { - auto undo_entry = undo_buffer.CreateEntry(UndoFlags::SEQUENCE_VALUE, sizeof(SequenceValue)); - auto sequence_info = reinterpret_cast(undo_entry.Ptr()); + auto sequence_ptr = undo_buffer.CreateEntry(UndoFlags::SEQUENCE_VALUE, sizeof(SequenceValue)); + auto sequence_info = reinterpret_cast(sequence_ptr); sequence_info->entry = &sequence; sequence_info->usage_count = data.usage_count; sequence_info->counter = data.counter; @@ -247,14 +248,9 @@ ErrorData DuckTransaction::Commit(AttachedDatabase &db, transaction_t new_commit } } -ErrorData DuckTransaction::Rollback() { - try { - storage->Rollback(); - undo_buffer.Rollback(); - return ErrorData(); - } catch (std::exception &ex) { - return ErrorData(ex); - } +void DuckTransaction::Rollback() noexcept { + storage->Rollback(); + undo_buffer.Rollback(); } void DuckTransaction::Cleanup(transaction_t lowest_active_transaction) { diff --git a/src/duckdb/src/transaction/duck_transaction_manager.cpp b/src/duckdb/src/transaction/duck_transaction_manager.cpp index 15248dabd..83558ffa7 100644 --- a/src/duckdb/src/transaction/duck_transaction_manager.cpp +++ b/src/duckdb/src/transaction/duck_transaction_manager.cpp @@ -173,8 +173,9 @@ void DuckTransactionManager::Checkpoint(ClientContext &context, bool force) { lock = checkpoint_lock.TryGetExclusiveLock(); if (!lock) { // we could not manage to get the lock - cancel - throw TransactionException("Cannot CHECKPOINT: there are other write transactions active. Try using FORCE " - "CHECKPOINT to wait until all active transactions are finished"); + throw TransactionException( + "Cannot CHECKPOINT: there are other write transactions active. Use FORCE CHECKPOINT to abort " + "the other transactions and force a checkpoint"); } } else { @@ -261,11 +262,7 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran // commit unsuccessful: rollback the transaction instead checkpoint_decision = CheckpointDecision(error.Message()); transaction.commit_id = 0; - auto rollback_error = transaction.Rollback(); - if (rollback_error.HasError()) { - throw FatalException("Failed to rollback transaction. Cannot continue operation.\nError: %s", - rollback_error.Message()); - } + transaction.Rollback(); } else { // check if catalog changes were made if (transaction.catalog_version >= TRANSACTION_ID_START) { @@ -281,8 +278,7 @@ ErrorData DuckTransactionManager::CommitTransaction(ClientContext &context, Tran // commit successful: remove the transaction id from the list of active transactions // potentially resulting in garbage collection - bool store_transaction = undo_properties.has_updates || undo_properties.has_index_deletes || - undo_properties.has_catalog_changes || error.HasError(); + bool store_transaction = undo_properties.has_updates || undo_properties.has_catalog_changes || error.HasError(); RemoveTransaction(transaction, store_transaction); // now perform a checkpoint if (1) we are able to checkpoint, and (2) the WAL has reached sufficient size to // checkpoint @@ -306,15 +302,11 @@ void DuckTransactionManager::RollbackTransaction(Transaction &transaction_p) { lock_guard lock(transaction_lock); // rollback the transaction - auto error = transaction.Rollback(); + transaction.Rollback(); // remove the transaction id from the list of active transactions // potentially resulting in garbage collection RemoveTransaction(transaction); - - if (error.HasError()) { - throw FatalException("Failed to rollback transaction. Cannot continue operation.\nError: %s", error.Message()); - } } void DuckTransactionManager::RemoveTransaction(DuckTransaction &transaction) noexcept { @@ -422,10 +414,6 @@ idx_t DuckTransactionManager::GetCatalogVersion(Transaction &transaction_p) { void DuckTransactionManager::PushCatalogEntry(Transaction &transaction_p, duckdb::CatalogEntry &entry, duckdb::data_ptr_t extra_data, duckdb::idx_t extra_data_size) { auto &transaction = transaction_p.Cast(); - if (!db.IsSystem() && !db.IsTemporary() && transaction.IsReadOnly()) { - throw InternalException("Attempting to do catalog changes on a transaction that is read-only - " - "this should not be possible"); - } transaction.catalog_version = ++last_uncommitted_catalog_version; transaction.PushCatalogEntry(entry, extra_data, extra_data_size); } diff --git a/src/duckdb/src/transaction/rollback_state.cpp b/src/duckdb/src/transaction/rollback_state.cpp index 335c35eff..f7d1410c7 100644 --- a/src/duckdb/src/transaction/rollback_state.cpp +++ b/src/duckdb/src/transaction/rollback_state.cpp @@ -13,13 +13,10 @@ namespace duckdb { -RollbackState::RollbackState(DuckTransaction &transaction_p) : transaction(transaction_p) { -} - void RollbackState::RollbackEntry(UndoFlags type, data_ptr_t data) { switch (type) { case UndoFlags::CATALOG_ENTRY: { - // Load and undo the catalog entry. + // undo this catalog entry auto catalog_entry = Load(data); D_ASSERT(catalog_entry->set); catalog_entry->set->Undo(*catalog_entry); @@ -28,7 +25,7 @@ void RollbackState::RollbackEntry(UndoFlags type, data_ptr_t data) { case UndoFlags::INSERT_TUPLE: { auto info = reinterpret_cast(data); // revert the append in the base table - info->table->RevertAppend(transaction, info->start_row, info->count); + info->table->RevertAppend(info->start_row, info->count); break; } case UndoFlags::DELETE_TUPLE: { diff --git a/src/duckdb/src/transaction/transaction_context.cpp b/src/duckdb/src/transaction/transaction_context.cpp index 67f8cfec4..9fc36814c 100644 --- a/src/duckdb/src/transaction/transaction_context.cpp +++ b/src/duckdb/src/transaction/transaction_context.cpp @@ -74,19 +74,11 @@ void TransactionContext::Rollback(optional_ptr error) { } auto transaction = std::move(current_transaction); ClearTransaction(); - ErrorData rollback_error; - try { - transaction->Rollback(); - } catch (std::exception &ex) { - rollback_error = ErrorData(ex); - } + transaction->Rollback(); // Notify any registered state of transaction rollback for (auto const &s : context.registered_state->States()) { s->TransactionRollback(*transaction, context, error); } - if (rollback_error.HasError()) { - rollback_error.Throw(); - } } void TransactionContext::ClearTransaction() { diff --git a/src/duckdb/src/transaction/undo_buffer.cpp b/src/duckdb/src/transaction/undo_buffer.cpp index e352ff473..1e61bd9cc 100644 --- a/src/duckdb/src/transaction/undo_buffer.cpp +++ b/src/duckdb/src/transaction/undo_buffer.cpp @@ -13,36 +13,32 @@ #include "duckdb/execution/index/bound_index.hpp" #include "duckdb/transaction/wal_write_state.hpp" #include "duckdb/transaction/delete_info.hpp" -#include "duckdb/storage/buffer_manager.hpp" namespace duckdb { constexpr uint32_t UNDO_ENTRY_HEADER_SIZE = sizeof(UndoFlags) + sizeof(uint32_t); -UndoBuffer::UndoBuffer(DuckTransaction &transaction_p, ClientContext &context_p) - : transaction(transaction_p), allocator(BufferManager::GetBufferManager(context_p)) { +UndoBuffer::UndoBuffer(ClientContext &context_p) : allocator(BufferAllocator::Get(context_p)) { } -UndoBufferReference UndoBuffer::CreateEntry(UndoFlags type, idx_t len) { - idx_t alloc_len = AlignValue(len + UNDO_ENTRY_HEADER_SIZE); - auto handle = allocator.Allocate(alloc_len); - auto data = handle.Ptr(); - // write the undo entry metadata +data_ptr_t UndoBuffer::CreateEntry(UndoFlags type, idx_t len) { + D_ASSERT(len <= NumericLimits::Maximum()); + len = AlignValue(len); + idx_t needed_space = len + UNDO_ENTRY_HEADER_SIZE; + auto data = allocator.Allocate(needed_space); Store(type, data); data += sizeof(UndoFlags); - Store(UnsafeNumericCast(alloc_len - UNDO_ENTRY_HEADER_SIZE), data); - // increment the position of the header past the undo entry metadata - handle.position += UNDO_ENTRY_HEADER_SIZE; - return handle; + Store(UnsafeNumericCast(len), data); + data += sizeof(uint32_t); + return data; } template void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, T &&callback) { // iterate in insertion order: start with the tail - state.current = allocator.tail.get(); + state.current = allocator.GetTail(); while (state.current) { - state.handle = allocator.buffer_manager.Pin(state.current->block); - state.start = state.handle.Ptr(); - state.end = state.start + state.current->position; + state.start = state.current->data.get(); + state.end = state.start + state.current->current_position; while (state.start < state.end) { UndoFlags type = Load(state.start); state.start += sizeof(UndoFlags); @@ -59,11 +55,11 @@ void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, T &&callback) template void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, UndoBuffer::IteratorState &end_state, T &&callback) { // iterate in insertion order: start with the tail - state.current = allocator.tail.get(); + state.current = allocator.GetTail(); while (state.current) { - state.handle = allocator.buffer_manager.Pin(state.current->block); - state.start = state.handle.Ptr(); - state.end = state.current == end_state.current ? end_state.start : state.start + state.current->position; + state.start = state.current->data.get(); + state.end = + state.current == end_state.current ? end_state.start : state.start + state.current->current_position; while (state.start < state.end) { auto type = Load(state.start); state.start += sizeof(UndoFlags); @@ -83,11 +79,10 @@ void UndoBuffer::IterateEntries(UndoBuffer::IteratorState &state, UndoBuffer::It template void UndoBuffer::ReverseIterateEntries(T &&callback) { // iterate in reverse insertion order: start with the head - auto current = allocator.head.get(); + auto current = allocator.GetHead(); while (current) { - auto handle = allocator.buffer_manager.Pin(current->block); - data_ptr_t start = handle.Ptr(); - data_ptr_t end = start + current->position; + data_ptr_t start = current->data.get(); + data_ptr_t end = start + current->current_position; // create a vector with all nodes in this chunk vector> nodes; while (start < end) { @@ -108,7 +103,7 @@ void UndoBuffer::ReverseIterateEntries(T &&callback) { bool UndoBuffer::ChangesMade() { // we need to search for any index creation entries - return allocator.head.get(); + return !allocator.IsEmpty(); } UndoBufferProperties UndoBuffer::GetProperties() { @@ -116,9 +111,9 @@ UndoBufferProperties UndoBuffer::GetProperties() { if (!ChangesMade()) { return properties; } - auto node = allocator.head.get(); + auto node = allocator.GetHead(); while (node) { - properties.estimated_size += node->position; + properties.estimated_size += node->current_position; node = node->next.get(); } @@ -134,9 +129,6 @@ UndoBufferProperties UndoBuffer::GetProperties() { if (info->is_consecutive) { properties.estimated_size += sizeof(row_t) * info->count; } - if (info->table->HasIndexes()) { - properties.has_index_deletes = true; - } properties.has_deletes = true; break; } @@ -186,25 +178,25 @@ void UndoBuffer::Cleanup(transaction_t lowest_active_transaction) { } void UndoBuffer::WriteToWAL(WriteAheadLog &wal, optional_ptr commit_state) { - WALWriteState state(transaction, wal, commit_state); + WALWriteState state(wal, commit_state); UndoBuffer::IteratorState iterator_state; IterateEntries(iterator_state, [&](UndoFlags type, data_ptr_t data) { state.CommitEntry(type, data); }); } void UndoBuffer::Commit(UndoBuffer::IteratorState &iterator_state, transaction_t commit_id) { - CommitState state(transaction, commit_id); + CommitState state(commit_id); IterateEntries(iterator_state, [&](UndoFlags type, data_ptr_t data) { state.CommitEntry(type, data); }); } void UndoBuffer::RevertCommit(UndoBuffer::IteratorState &end_state, transaction_t transaction_id) { - CommitState state(transaction, transaction_id); + CommitState state(transaction_id); UndoBuffer::IteratorState start_state; IterateEntries(start_state, end_state, [&](UndoFlags type, data_ptr_t data) { state.RevertCommit(type, data); }); } -void UndoBuffer::Rollback() { +void UndoBuffer::Rollback() noexcept { // rollback needs to be performed in reverse - RollbackState state(transaction); + RollbackState state; ReverseIterateEntries([&](UndoFlags type, data_ptr_t data) { state.RollbackEntry(type, data); }); } } // namespace duckdb diff --git a/src/duckdb/src/transaction/undo_buffer_allocator.cpp b/src/duckdb/src/transaction/undo_buffer_allocator.cpp deleted file mode 100644 index 20e3bdf19..000000000 --- a/src/duckdb/src/transaction/undo_buffer_allocator.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "duckdb/transaction/undo_buffer_allocator.hpp" -#include "duckdb/storage/buffer_manager.hpp" - -namespace duckdb { - -UndoBufferEntry::~UndoBufferEntry() { - if (next) { - auto current_next = std::move(next); - while (current_next) { - current_next = std::move(current_next->next); - } - } -} -UndoBufferPointer UndoBufferReference::GetBufferPointer() { - return UndoBufferPointer(*entry, position); -} - -UndoBufferReference UndoBufferPointer::Pin() const { - if (!entry) { - throw InternalException("UndoBufferPointer::Pin called but no entry was found"); - } - D_ASSERT(entry->capacity >= position); - auto handle = entry->buffer_manager.Pin(entry->block); - return UndoBufferReference(*entry, std::move(handle), position); -} - -UndoBufferAllocator::UndoBufferAllocator(BufferManager &buffer_manager) : buffer_manager(buffer_manager) { -} - -UndoBufferReference UndoBufferAllocator::Allocate(idx_t alloc_len) { - D_ASSERT(!head || head->position <= head->capacity); - BufferHandle handle; - if (!head || head->position + alloc_len > head->capacity) { - // no space in current head - allocate a new block - auto block_size = buffer_manager.GetBlockSize(); - ; - idx_t capacity; - if (!head && alloc_len <= 4096) { - capacity = 4096; - } else { - capacity = block_size; - } - if (capacity < alloc_len) { - capacity = NextPowerOfTwo(alloc_len); - } - auto entry = make_uniq(buffer_manager); - if (capacity < block_size) { - entry->block = buffer_manager.RegisterSmallMemory(MemoryTag::TRANSACTION, capacity); - handle = buffer_manager.Pin(entry->block); - } else { - handle = buffer_manager.Allocate(MemoryTag::TRANSACTION, capacity, false); - entry->block = handle.GetBlockHandle(); - } - entry->capacity = capacity; - entry->position = 0; - // add block to the chain - if (head) { - head->prev = entry.get(); - entry->next = std::move(head); - } else { - tail = entry.get(); - } - head = std::move(entry); - } else { - handle = buffer_manager.Pin(head->block); - } - idx_t current_position = head->position; - head->position += alloc_len; - return UndoBufferReference(*head, std::move(handle), current_position); -} - -} // namespace duckdb diff --git a/src/duckdb/src/transaction/wal_write_state.cpp b/src/duckdb/src/transaction/wal_write_state.cpp index 275a12571..b700005ef 100644 --- a/src/duckdb/src/transaction/wal_write_state.cpp +++ b/src/duckdb/src/transaction/wal_write_state.cpp @@ -22,9 +22,8 @@ namespace duckdb { -WALWriteState::WALWriteState(DuckTransaction &transaction_p, WriteAheadLog &log, - optional_ptr commit_state) - : transaction(transaction_p), log(log), commit_state(commit_state), current_table_info(nullptr) { +WALWriteState::WALWriteState(WriteAheadLog &log, optional_ptr commit_state) + : log(log), commit_state(commit_state), current_table_info(nullptr) { } void WALWriteState::SwitchTable(DataTableInfo *table_info, UndoFlags new_op) { @@ -64,7 +63,7 @@ void WALWriteState::WriteCatalogEntry(CatalogEntry &entry, data_ptr_t dataptr) { deserializer.End(); auto &alter_info = parse_info->Cast(); - log.WriteAlter(entry, alter_info); + log.WriteAlter(alter_info); } else { switch (parent.type) { case CatalogType::TABLE_ENTRY: @@ -218,28 +217,27 @@ void WALWriteState::WriteUpdate(UpdateInfo &info) { // write the row ids into the chunk auto row_ids = FlatVector::GetData(update_chunk->data[1]); idx_t start = column_data.start + info.vector_index * STANDARD_VECTOR_SIZE; - auto tuples = info.GetTuples(); for (idx_t i = 0; i < info.N; i++) { - row_ids[tuples[i]] = UnsafeNumericCast(start + tuples[i]); + row_ids[info.tuples[i]] = UnsafeNumericCast(start + info.tuples[i]); } if (column_data.type.id() == LogicalTypeId::VALIDITY) { // zero-initialize the booleans // FIXME: this is only required because of NullValue in Vector::Serialize... auto booleans = FlatVector::GetData(update_chunk->data[0]); for (idx_t i = 0; i < info.N; i++) { - auto idx = tuples[i]; + auto idx = info.tuples[i]; booleans[idx] = false; } } - SelectionVector sel(tuples); + SelectionVector sel(info.tuples); update_chunk->Slice(sel, info.N); // construct the column index path vector column_indexes; - reference current_column_data = column_data; - while (current_column_data.get().HasParent()) { + reference current_column_data = column_data; + while (current_column_data.get().parent) { column_indexes.push_back(current_column_data.get().column_index); - current_column_data = current_column_data.get().Parent(); + current_column_data = *current_column_data.get().parent; } column_indexes.push_back(info.column_index); std::reverse(column_indexes.begin(), column_indexes.end()); @@ -261,7 +259,7 @@ void WALWriteState::CommitEntry(UndoFlags type, data_ptr_t data) { // append: auto info = reinterpret_cast(data); if (!info->table->IsTemporary()) { - info->table->WriteToLog(transaction, log, info->start_row, info->count, commit_state.get()); + info->table->WriteToLog(log, info->start_row, info->count, commit_state.get()); } break; } diff --git a/src/duckdb/src/verification/copied_statement_verifier.cpp b/src/duckdb/src/verification/copied_statement_verifier.cpp index ff7825bd5..6b603f3bb 100644 --- a/src/duckdb/src/verification/copied_statement_verifier.cpp +++ b/src/duckdb/src/verification/copied_statement_verifier.cpp @@ -2,15 +2,12 @@ namespace duckdb { -CopiedStatementVerifier::CopiedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters) - : StatementVerifier(VerificationType::COPIED, "Copied", std::move(statement_p), parameters) { +CopiedStatementVerifier::CopiedStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::COPIED, "Copied", std::move(statement_p)) { } -unique_ptr -CopiedStatementVerifier::Create(const SQLStatement &statement, - optional_ptr> parameters) { - return make_uniq(statement.Copy(), parameters); +unique_ptr CopiedStatementVerifier::Create(const SQLStatement &statement) { + return make_uniq(statement.Copy()); } } // namespace duckdb diff --git a/src/duckdb/src/verification/deserialized_statement_verifier.cpp b/src/duckdb/src/verification/deserialized_statement_verifier.cpp index a841d64bb..dcbc1780b 100644 --- a/src/duckdb/src/verification/deserialized_statement_verifier.cpp +++ b/src/duckdb/src/verification/deserialized_statement_verifier.cpp @@ -5,22 +5,20 @@ #include "duckdb/common/serializer/memory_stream.hpp" namespace duckdb { -DeserializedStatementVerifier::DeserializedStatementVerifier( - unique_ptr statement_p, optional_ptr> parameters) - : StatementVerifier(VerificationType::DESERIALIZED, "Deserialized", std::move(statement_p), parameters) { +DeserializedStatementVerifier::DeserializedStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::DESERIALIZED, "Deserialized", std::move(statement_p)) { } -unique_ptr -DeserializedStatementVerifier::Create(const SQLStatement &statement, - optional_ptr> parameters) { +unique_ptr DeserializedStatementVerifier::Create(const SQLStatement &statement) { auto &select_stmt = statement.Cast(); + MemoryStream stream; BinarySerializer::Serialize(select_stmt, stream); stream.Rewind(); auto result = BinaryDeserializer::Deserialize(stream); - return make_uniq(std::move(result), parameters); + return make_uniq(std::move(result)); } } // namespace duckdb diff --git a/src/duckdb/src/verification/external_statement_verifier.cpp b/src/duckdb/src/verification/external_statement_verifier.cpp index 0d3e40da3..5e9655d55 100644 --- a/src/duckdb/src/verification/external_statement_verifier.cpp +++ b/src/duckdb/src/verification/external_statement_verifier.cpp @@ -2,15 +2,12 @@ namespace duckdb { -ExternalStatementVerifier::ExternalStatementVerifier( - unique_ptr statement_p, optional_ptr> parameters) - : StatementVerifier(VerificationType::EXTERNAL, "External", std::move(statement_p), parameters) { +ExternalStatementVerifier::ExternalStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::EXTERNAL, "External", std::move(statement_p)) { } -unique_ptr -ExternalStatementVerifier::Create(const SQLStatement &statement, - optional_ptr> parameters) { - return make_uniq(statement.Copy(), parameters); +unique_ptr ExternalStatementVerifier::Create(const SQLStatement &statement) { + return make_uniq(statement.Copy()); } } // namespace duckdb diff --git a/src/duckdb/src/verification/fetch_row_verifier.cpp b/src/duckdb/src/verification/fetch_row_verifier.cpp index 5a4d4ba23..a3be8111c 100644 --- a/src/duckdb/src/verification/fetch_row_verifier.cpp +++ b/src/duckdb/src/verification/fetch_row_verifier.cpp @@ -2,15 +2,12 @@ namespace duckdb { -FetchRowVerifier::FetchRowVerifier(unique_ptr statement_p, - optional_ptr> parameters) - : StatementVerifier(VerificationType::FETCH_ROW_AS_SCAN, "FetchRow as Scan", std::move(statement_p), parameters) { +FetchRowVerifier::FetchRowVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::FETCH_ROW_AS_SCAN, "FetchRow as Scan", std::move(statement_p)) { } -unique_ptr -FetchRowVerifier::Create(const SQLStatement &statement_p, - optional_ptr> parameters) { - return make_uniq(statement_p.Copy(), parameters); +unique_ptr FetchRowVerifier::Create(const SQLStatement &statement_p) { + return make_uniq(statement_p.Copy()); } } // namespace duckdb diff --git a/src/duckdb/src/verification/no_operator_caching_verifier.cpp b/src/duckdb/src/verification/no_operator_caching_verifier.cpp index 0ca57036f..105409317 100644 --- a/src/duckdb/src/verification/no_operator_caching_verifier.cpp +++ b/src/duckdb/src/verification/no_operator_caching_verifier.cpp @@ -2,16 +2,12 @@ namespace duckdb { -NoOperatorCachingVerifier::NoOperatorCachingVerifier( - unique_ptr statement_p, optional_ptr> parameters) - : StatementVerifier(VerificationType::NO_OPERATOR_CACHING, "No operator caching", std::move(statement_p), - parameters) { +NoOperatorCachingVerifier::NoOperatorCachingVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::NO_OPERATOR_CACHING, "No operator caching", std::move(statement_p)) { } -unique_ptr -NoOperatorCachingVerifier::Create(const SQLStatement &statement_p, - optional_ptr> parameters) { - return make_uniq(statement_p.Copy(), parameters); +unique_ptr NoOperatorCachingVerifier::Create(const SQLStatement &statement_p) { + return make_uniq(statement_p.Copy()); } } // namespace duckdb diff --git a/src/duckdb/src/verification/parsed_statement_verifier.cpp b/src/duckdb/src/verification/parsed_statement_verifier.cpp index ff9075dc4..a47141f94 100644 --- a/src/duckdb/src/verification/parsed_statement_verifier.cpp +++ b/src/duckdb/src/verification/parsed_statement_verifier.cpp @@ -4,14 +4,11 @@ namespace duckdb { -ParsedStatementVerifier::ParsedStatementVerifier(unique_ptr statement_p, - optional_ptr> parameters) - : StatementVerifier(VerificationType::PARSED, "Parsed", std::move(statement_p), parameters) { +ParsedStatementVerifier::ParsedStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::PARSED, "Parsed", std::move(statement_p)) { } -unique_ptr -ParsedStatementVerifier::Create(const SQLStatement &statement, - optional_ptr> parameters) { +unique_ptr ParsedStatementVerifier::Create(const SQLStatement &statement) { auto query_str = statement.ToString(); Parser parser; try { @@ -21,7 +18,7 @@ ParsedStatementVerifier::Create(const SQLStatement &statement, } D_ASSERT(parser.statements.size() == 1); D_ASSERT(parser.statements[0]->type == StatementType::SELECT_STATEMENT); - return make_uniq(std::move(parser.statements[0]), parameters); + return make_uniq(std::move(parser.statements[0])); } } // namespace duckdb diff --git a/src/duckdb/src/verification/prepared_statement_verifier.cpp b/src/duckdb/src/verification/prepared_statement_verifier.cpp index 2458d4714..15a11d561 100644 --- a/src/duckdb/src/verification/prepared_statement_verifier.cpp +++ b/src/duckdb/src/verification/prepared_statement_verifier.cpp @@ -9,15 +9,12 @@ namespace duckdb { -PreparedStatementVerifier::PreparedStatementVerifier( - unique_ptr statement_p, optional_ptr> parameters) - : StatementVerifier(VerificationType::PREPARED, "Prepared", std::move(statement_p), parameters) { +PreparedStatementVerifier::PreparedStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::PREPARED, "Prepared", std::move(statement_p)) { } -unique_ptr -PreparedStatementVerifier::Create(const SQLStatement &statement, - optional_ptr> parameters) { - return make_uniq(statement.Copy(), parameters); +unique_ptr PreparedStatementVerifier::Create(const SQLStatement &statement) { + return make_uniq(statement.Copy()); } void PreparedStatementVerifier::Extract() { @@ -48,10 +45,10 @@ void PreparedStatementVerifier::Extract() { } void PreparedStatementVerifier::ConvertConstants(unique_ptr &child) { - if (child->GetExpressionType() == ExpressionType::VALUE_CONSTANT) { + if (child->type == ExpressionType::VALUE_CONSTANT) { // constant: extract the constant value - auto alias = child->GetAlias(); - child->ClearAlias(); + auto alias = child->alias; + child->alias = string(); // check if the value already exists idx_t index = values.size(); auto identifier = std::to_string(index + 1); @@ -69,7 +66,7 @@ void PreparedStatementVerifier::ConvertConstants(unique_ptr &c // replace it with an expression auto parameter = make_uniq(); parameter->identifier = identifier; - parameter->SetAlias(alias); + parameter->alias = alias; child = std::move(parameter); return; } @@ -79,19 +76,18 @@ void PreparedStatementVerifier::ConvertConstants(unique_ptr &c bool PreparedStatementVerifier::Run( ClientContext &context, const string &query, - const std::function(const string &, unique_ptr, - optional_ptr>)> &run) { + const std::function(const string &, unique_ptr)> &run) { bool failed = false; // verify that we can extract all constants from the query and run the query as a prepared statement // create the PREPARE and EXECUTE statements Extract(); // execute the prepared statements try { - auto prepare_result = run(string(), std::move(prepare_statement), parameters); + auto prepare_result = run(string(), std::move(prepare_statement)); if (prepare_result->HasError()) { prepare_result->ThrowError("Failed prepare during verify: "); } - auto execute_result = run(string(), std::move(execute_statement), parameters); + auto execute_result = run(string(), std::move(execute_statement)); if (execute_result->HasError()) { execute_result->ThrowError("Failed execute during verify: "); } @@ -103,7 +99,7 @@ bool PreparedStatementVerifier::Run( } failed = true; } - run(string(), std::move(dealloc_statement), parameters); + run(string(), std::move(dealloc_statement)); context.interrupted = false; return failed; diff --git a/src/duckdb/src/verification/statement_verifier.cpp b/src/duckdb/src/verification/statement_verifier.cpp index fb8fc71ac..c3c971588 100644 --- a/src/duckdb/src/verification/statement_verifier.cpp +++ b/src/duckdb/src/verification/statement_verifier.cpp @@ -14,41 +14,37 @@ namespace duckdb { -StatementVerifier::StatementVerifier(VerificationType type, string name, unique_ptr statement_p, - optional_ptr> parameters_p) +StatementVerifier::StatementVerifier(VerificationType type, string name, unique_ptr statement_p) : type(type), name(std::move(name)), - statement(unique_ptr_cast(std::move(statement_p))), parameters(parameters_p), + statement(unique_ptr_cast(std::move(statement_p))), select_list(statement->node->GetSelectList()) { } -StatementVerifier::StatementVerifier(unique_ptr statement_p, - optional_ptr> parameters) - : StatementVerifier(VerificationType::ORIGINAL, "Original", std::move(statement_p), parameters) { +StatementVerifier::StatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::ORIGINAL, "Original", std::move(statement_p)) { } StatementVerifier::~StatementVerifier() noexcept { } -unique_ptr -StatementVerifier::Create(VerificationType type, const SQLStatement &statement_p, - optional_ptr> parameters) { +unique_ptr StatementVerifier::Create(VerificationType type, const SQLStatement &statement_p) { switch (type) { case VerificationType::COPIED: - return CopiedStatementVerifier::Create(statement_p, parameters); + return CopiedStatementVerifier::Create(statement_p); case VerificationType::DESERIALIZED: - return DeserializedStatementVerifier::Create(statement_p, parameters); + return DeserializedStatementVerifier::Create(statement_p); case VerificationType::PARSED: - return ParsedStatementVerifier::Create(statement_p, parameters); + return ParsedStatementVerifier::Create(statement_p); case VerificationType::UNOPTIMIZED: - return UnoptimizedStatementVerifier::Create(statement_p, parameters); + return UnoptimizedStatementVerifier::Create(statement_p); case VerificationType::NO_OPERATOR_CACHING: - return NoOperatorCachingVerifier::Create(statement_p, parameters); + return NoOperatorCachingVerifier::Create(statement_p); case VerificationType::PREPARED: - return PreparedStatementVerifier::Create(statement_p, parameters); + return PreparedStatementVerifier::Create(statement_p); case VerificationType::EXTERNAL: - return ExternalStatementVerifier::Create(statement_p, parameters); + return ExternalStatementVerifier::Create(statement_p); case VerificationType::FETCH_ROW_AS_SCAN: - return FetchRowVerifier::Create(statement_p, parameters); + return FetchRowVerifier::Create(statement_p); case VerificationType::INVALID: default: throw InternalException("Invalid statement verification type!"); @@ -108,8 +104,7 @@ void StatementVerifier::CheckExpressions() const { bool StatementVerifier::Run( ClientContext &context, const string &query, - const std::function(const string &, unique_ptr, - optional_ptr>)> &run) { + const std::function(const string &, unique_ptr)> &run) { bool failed = false; context.interrupted = false; @@ -118,7 +113,7 @@ bool StatementVerifier::Run( context.config.force_external = ForceExternal(); context.config.force_fetch_row = ForceFetchRow(); try { - auto result = run(query, std::move(statement), parameters); + auto result = run(query, std::move(statement)); if (result->HasError()) { failed = true; } diff --git a/src/duckdb/src/verification/unoptimized_statement_verifier.cpp b/src/duckdb/src/verification/unoptimized_statement_verifier.cpp index fd2dd1f72..b0f274026 100644 --- a/src/duckdb/src/verification/unoptimized_statement_verifier.cpp +++ b/src/duckdb/src/verification/unoptimized_statement_verifier.cpp @@ -2,15 +2,12 @@ namespace duckdb { -UnoptimizedStatementVerifier::UnoptimizedStatementVerifier( - unique_ptr statement_p, optional_ptr> parameters) - : StatementVerifier(VerificationType::UNOPTIMIZED, "Unoptimized", std::move(statement_p), parameters) { +UnoptimizedStatementVerifier::UnoptimizedStatementVerifier(unique_ptr statement_p) + : StatementVerifier(VerificationType::UNOPTIMIZED, "Unoptimized", std::move(statement_p)) { } -unique_ptr -UnoptimizedStatementVerifier::Create(const SQLStatement &statement_p, - optional_ptr> parameters) { - return make_uniq(statement_p.Copy(), parameters); +unique_ptr UnoptimizedStatementVerifier::Create(const SQLStatement &statement_p) { + return make_uniq(statement_p.Copy()); } } // namespace duckdb diff --git a/src/duckdb/third_party/httplib/httplib.hpp b/src/duckdb/third_party/httplib/httplib.hpp index 6432d5d1a..4cfbbfe3d 100644 --- a/src/duckdb/third_party/httplib/httplib.hpp +++ b/src/duckdb/third_party/httplib/httplib.hpp @@ -237,6 +237,7 @@ using socket_t = int; #include #include #include +#include #include #include #include @@ -245,8 +246,9 @@ using socket_t = int; #include #include #include +#include + #include "duckdb/common/re2_regex.hpp" -#include "duckdb/common/random_engine.hpp" #ifdef CPPHTTPLIB_OPENSSL_SUPPORT #ifdef _WIN32 @@ -2078,7 +2080,8 @@ namespace detail { std::string encode_query_param(const std::string &value); -std::string decode_url(const std::string &s, bool convert_plus_to_space, const std::set &exclude = {}); +std::string decode_url(const std::string &s, bool convert_plus_to_space); + void read_file(const std::string &path, std::string &out); std::string trim_copy(const std::string &s); @@ -2492,8 +2495,7 @@ inline std::string encode_url(const std::string &s) { } inline std::string decode_url(const std::string &s, - bool convert_plus_to_space, - const std::set &exclude) { + bool convert_plus_to_space) { std::string result; for (size_t i = 0; i < s.size(); i++) { @@ -2512,12 +2514,8 @@ inline std::string decode_url(const std::string &s, } else { auto val = 0; if (from_hex_to_i(s, i + 1, 2, val)) { - const auto converted = static_cast(val); - if (exclude.count(converted) == 0) { - result += converted; - } else { - result.append(s, i, 3); - } + // 2 digits hex codes + result += static_cast(val); i += 2; // '00' } else { result += s[i]; @@ -4644,10 +4642,19 @@ inline std::string make_multipart_data_boundary() { static const char data[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + // std::random_device might actually be deterministic on some + // platforms, but due to lack of support in the c++ standard library, + // doing better requires either some ugly hacks or breaking portability. + std::random_device seed_gen; + + // Request 128 bits of entropy for initialization + std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()}; + std::mt19937 engine(seed_sequence); + std::string result = "--cpp-httplib-multipart-data-"; - duckdb::RandomEngine engine; + for (auto i = 0; i < 16; i++) { - result += data[engine.NextRandomInteger32(0,sizeof(data) - 1)]; + result += data[engine() % (sizeof(data) - 1)]; } return result; @@ -7098,9 +7105,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { if (next_scheme.empty()) { next_scheme = scheme; } if (next_host.empty()) { next_host = host_; } if (next_path.empty()) { next_path = "/"; } - - auto path = detail::decode_url(next_path, true, std::set {'/'}) + next_query; - + + auto path = detail::decode_url(next_path, true) + next_query; + if (next_scheme == scheme && next_host == host_ && next_port == port_) { return detail::redirect(*this, req, res, path, location, error); } else { diff --git a/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp b/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp index 2fbf2cf75..a5aa55c36 100644 --- a/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +++ b/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp @@ -317,7 +317,6 @@ typedef struct PGAStar { PGNode *expr; /* optional: the expression (regex or list) to select columns */ PGList *except_list; /* optional: EXCLUDE list */ PGList *replace_list; /* optional: REPLACE list */ - PGList *rename_list; /* optional: RENAME list */ bool columns; /* whether or not this is a columns list */ bool unpacked; /* whether or not the columns list is unpacked */ int location; @@ -1575,8 +1574,7 @@ typedef struct PGVariableSetStmt { */ typedef struct PGVariableShowStmt { PGNodeTag type; - PGRangeVar *relation; /* relation to describe (if any) */ - char *set; /* set to describe (e.g. set when using SHOW ALL TABLES) */ + char *name; int is_summary; // whether or not this is a DESCRIBE or a SUMMARIZE } PGVariableShowStmt; @@ -2103,7 +2101,7 @@ typedef struct PGIntervalConstant { typedef struct PGSampleSize { PGNodeTag type; bool is_percentage; /* whether or not the sample size is expressed in row numbers or a percentage */ - PGNode *sample_size; /* sample size */ + PGValue sample_size; /* sample size */ } PGSampleSize; typedef struct PGSampleOptions { diff --git a/src/duckdb/third_party/libpg_query/pg_functions.cpp b/src/duckdb/third_party/libpg_query/pg_functions.cpp index 3b7a7515e..8719b11a1 100644 --- a/src/duckdb/third_party/libpg_query/pg_functions.cpp +++ b/src/duckdb/third_party/libpg_query/pg_functions.cpp @@ -111,8 +111,9 @@ void pg_parser_parse(const char *query, parse_result *res) { } catch (std::exception &ex) { res->success = false; res->error_message = ex.what(); - res->error_location = pg_parser_state.pg_err_pos; } + res->error_message = pg_parser_state.pg_err_msg; + res->error_location = pg_parser_state.pg_err_pos; } void pg_parser_cleanup() { @@ -127,7 +128,8 @@ void pg_parser_cleanup() { } int ereport(int code, ...) { - throw std::runtime_error(pg_parser_state.pg_err_msg); + std::string err = "parser error : " + std::string(pg_parser_state.pg_err_msg); + throw std::runtime_error(err); } void elog(int code, const char *fmt, ...) { throw std::runtime_error("elog NOT IMPLEMENTED"); diff --git a/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp b/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp index 71ed8b023..8da0cbf89 100644 --- a/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +++ b/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp @@ -1277,7 +1277,7 @@ static PGNode *makeStringConstCast(char *str, int location, PGTypeName *tpname); static PGNode *makeIntervalNode(char *str, int location, PGList *typmods); static PGNode *makeIntervalNode(int val, int location, PGList *typmods); static PGNode *makeIntervalNode(PGNode *arg, int location, PGList *typmods); -static PGNode *makeSampleSize(PGNode *sample_size, bool is_percentage); +static PGNode *makeSampleSize(PGValue *sample_size, bool is_percentage); static PGNode *makeSampleOptions(PGNode *sample_size, char *method, int *seed, int location); static PGNode *makeIntConst(int val, int location); static PGNode *makeFloatConst(char *str, int location); @@ -1624,18 +1624,18 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 874 +#define YYFINAL 873 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 74510 +#define YYLAST 72916 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 529 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 483 +#define YYNNTS 474 /* YYNRULES -- Number of rules. */ -#define YYNRULES 2176 +#define YYNRULES 2155 /* YYNRULES -- Number of states. */ -#define YYNSTATES 3617 +#define YYNSTATES 3579 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -1650,16 +1650,16 @@ static const yytype_uint16 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 526, 525, 513, 2, 2, + 2, 2, 2, 2, 2, 524, 525, 513, 2, 2, 518, 519, 511, 509, 522, 510, 520, 512, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 523, 521, - 505, 507, 506, 524, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 528, 521, + 505, 507, 506, 523, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 516, 2, 517, 514, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 527, 2, 528, 2, 2, 2, 2, + 2, 2, 2, 526, 2, 527, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1794,181 +1794,179 @@ static const yytype_uint16 yyprhs[] = 2138, 2141, 2143, 2149, 2151, 2152, 2155, 2158, 2159, 2161, 2162, 2166, 2172, 2174, 2178, 2183, 2187, 2189, 2191, 2192, 2195, 2198, 2199, 2202, 2205, 2207, 2209, 2211, 2212, 2215, - 2220, 2226, 2231, 2234, 2238, 2240, 2242, 2244, 2247, 2250, - 2252, 2255, 2259, 2260, 2262, 2263, 2269, 2271, 2276, 2283, - 2286, 2288, 2289, 2294, 2295, 2297, 2299, 2302, 2305, 2308, - 2310, 2312, 2315, 2318, 2320, 2322, 2324, 2326, 2328, 2330, - 2334, 2338, 2339, 2341, 2345, 2347, 2350, 2352, 2354, 2356, - 2358, 2360, 2363, 2368, 2373, 2379, 2381, 2383, 2386, 2387, - 2390, 2391, 2393, 2397, 2399, 2400, 2402, 2405, 2409, 2412, - 2417, 2420, 2424, 2427, 2428, 2430, 2433, 2434, 2439, 2445, - 2447, 2450, 2453, 2454, 2456, 2460, 2462, 2465, 2468, 2472, - 2476, 2480, 2484, 2488, 2492, 2496, 2500, 2504, 2506, 2511, - 2516, 2526, 2536, 2540, 2541, 2544, 2547, 2548, 2554, 2558, - 2560, 2562, 2566, 2572, 2576, 2578, 2581, 2583, 2587, 2593, - 2595, 2598, 2602, 2607, 2613, 2618, 2624, 2629, 2636, 2642, - 2647, 2653, 2659, 2665, 2668, 2673, 2675, 2677, 2678, 2680, - 2685, 2691, 2696, 2697, 2700, 2703, 2706, 2708, 2710, 2712, - 2714, 2715, 2720, 2723, 2725, 2728, 2731, 2736, 2739, 2746, - 2749, 2751, 2755, 2760, 2761, 2764, 2765, 2768, 2769, 2771, - 2775, 2779, 2782, 2783, 2786, 2791, 2793, 2795, 2797, 2798, - 2801, 2805, 2811, 2818, 2821, 2825, 2827, 2833, 2839, 2845, - 2849, 2853, 2857, 2862, 2863, 2865, 2867, 2869, 2871, 2873, - 2876, 2881, 2883, 2885, 2887, 2889, 2892, 2896, 2897, 2899, - 2901, 2903, 2905, 2907, 2910, 2913, 2916, 2919, 2922, 2924, - 2928, 2929, 2931, 2933, 2935, 2937, 2943, 2946, 2948, 2950, - 2952, 2954, 2959, 2961, 2964, 2967, 2969, 2973, 2977, 2980, - 2982, 2983, 2989, 2992, 2998, 3001, 3003, 3007, 3011, 3012, - 3014, 3016, 3018, 3020, 3022, 3024, 3026, 3028, 3030, 3032, - 3034, 3036, 3038, 3040, 3042, 3044, 3046, 3048, 3050, 3052, - 3054, 3056, 3058, 3060, 3062, 3064, 3066, 3068, 3070, 3072, - 3074, 3076, 3078, 3080, 3082, 3084, 3086, 3088, 3090, 3094, - 3098, 3102, 3106, 3110, 3114, 3118, 3119, 3121, 3125, 3129, - 3135, 3138, 3141, 3145, 3149, 3153, 3157, 3161, 3165, 3169, - 3173, 3177, 3181, 3185, 3189, 3193, 3197, 3201, 3204, 3207, - 3211, 3215, 3218, 3221, 3225, 3229, 3235, 3240, 3247, 3251, - 3257, 3262, 3269, 3274, 3281, 3287, 3295, 3299, 3302, 3307, - 3311, 3314, 3318, 3322, 3326, 3330, 3335, 3339, 3344, 3348, - 3353, 3359, 3366, 3373, 3381, 3388, 3396, 3403, 3411, 3415, - 3420, 3425, 3432, 3434, 3440, 3445, 3450, 3457, 3459, 3463, - 3466, 3469, 3473, 3477, 3481, 3485, 3489, 3493, 3497, 3501, - 3505, 3509, 3513, 3517, 3521, 3525, 3529, 3532, 3535, 3541, - 3548, 3555, 3563, 3565, 3568, 3570, 3572, 3574, 3577, 3580, - 3585, 3589, 3591, 3593, 3595, 3597, 3600, 3602, 3604, 3606, - 3608, 3610, 3612, 3614, 3617, 3622, 3625, 3629, 3633, 3638, - 3642, 3648, 3655, 3663, 3673, 3681, 3689, 3695, 3697, 3699, - 3701, 3707, 3714, 3721, 3726, 3731, 3736, 3741, 3748, 3754, - 3760, 3766, 3771, 3778, 3783, 3785, 3793, 3803, 3809, 3810, - 3816, 3821, 3822, 3824, 3825, 3828, 3829, 3831, 3835, 3839, - 3842, 3845, 3846, 3853, 3855, 3856, 3860, 3861, 3865, 3869, - 3873, 3874, 3876, 3881, 3884, 3887, 3890, 3893, 3896, 3900, - 3903, 3906, 3910, 3911, 3916, 3920, 3922, 3928, 3932, 3934, - 3938, 3940, 3943, 3947, 3949, 3953, 3955, 3958, 3960, 3961, - 3963, 3965, 3967, 3969, 3971, 3973, 3975, 3977, 3979, 3981, - 3983, 3985, 3987, 3989, 3991, 3993, 3995, 3997, 3999, 4001, - 4006, 4008, 4013, 4015, 4020, 4022, 4025, 4027, 4030, 4032, - 4035, 4037, 4041, 4043, 4047, 4049, 4052, 4054, 4058, 4060, - 4063, 4065, 4066, 4068, 4072, 4074, 4078, 4082, 4084, 4088, - 4092, 4093, 4095, 4097, 4099, 4101, 4103, 4105, 4107, 4109, - 4111, 4113, 4115, 4117, 4119, 4121, 4123, 4128, 4132, 4135, - 4139, 4140, 4144, 4148, 4151, 4154, 4156, 4157, 4160, 4163, - 4167, 4170, 4172, 4174, 4178, 4180, 4182, 4188, 4190, 4193, - 4198, 4201, 4202, 4204, 4205, 4207, 4211, 4213, 4215, 4218, - 4222, 4228, 4236, 4244, 4246, 4247, 4248, 4251, 4252, 4255, - 4259, 4263, 4267, 4273, 4281, 4289, 4290, 4293, 4295, 4296, - 4298, 4299, 4301, 4305, 4307, 4310, 4314, 4317, 4319, 4323, - 4328, 4331, 4333, 4337, 4339, 4343, 4345, 4348, 4350, 4351, - 4355, 4357, 4361, 4363, 4366, 4371, 4374, 4375, 4379, 4381, - 4385, 4387, 4390, 4395, 4398, 4399, 4401, 4405, 4407, 4411, - 4413, 4416, 4418, 4422, 4424, 4426, 4429, 4431, 4433, 4436, - 4438, 4440, 4443, 4451, 4454, 4460, 4464, 4468, 4470, 4472, - 4474, 4476, 4478, 4480, 4482, 4484, 4486, 4488, 4490, 4492, - 4494, 4496, 4499, 4502, 4506, 4510, 4511, 4513, 4515, 4517, - 4523, 4527, 4528, 4530, 4532, 4534, 4536, 4538, 4540, 4545, - 4553, 4560, 4563, 4564, 4566, 4568, 4570, 4572, 4586, 4603, - 4605, 4608, 4609, 4611, 4612, 4614, 4615, 4618, 4619, 4621, - 4622, 4629, 4638, 4645, 4654, 4661, 4670, 4674, 4677, 4679, - 4680, 4687, 4694, 4696, 4698, 4700, 4702, 4704, 4706, 4709, - 4711, 4713, 4715, 4717, 4719, 4724, 4731, 4735, 4738, 4743, - 4747, 4753, 4755, 4756, 4758, 4760, 4761, 4763, 4765, 4767, - 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, - 4789, 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, - 4809, 4811, 4813, 4815, 4817, 4819, 4821, 4823, 4825, 4827, - 4829, 4831, 4833, 4835, 4839, 4841, 4843, 4845, 4847, 4849, - 4851, 4854, 4856, 4858, 4861, 4865, 4869, 4873, 4877, 4879, - 4883, 4887, 4890, 4894, 4898, 4900, 4902, 4904, 4908, 4914, - 4916, 4918, 4920, 4922, 4926, 4929, 4934, 4941, 4948, 4949, - 4951, 4953, 4955, 4956, 4959, 4962, 4967, 4974, 4980, 4985, - 4992, 4994, 4996, 4998, 5000, 5002, 5004, 5005, 5007, 5011, - 5013, 5014, 5022, 5026, 5028, 5031, 5035, 5038, 5039, 5042, - 5043, 5046, 5051, 5057, 5066, 5069, 5073, 5079, 5081, 5082, - 5085, 5086, 5089, 5093, 5097, 5101, 5105, 5107, 5109, 5111, - 5114, 5118, 5121, 5124, 5127, 5130, 5134, 5139, 5143, 5145, - 5147, 5149, 5151, 5153, 5155, 5156, 5158, 5162, 5165, 5175, - 5188, 5200, 5213, 5228, 5232, 5237, 5242, 5243, 5251, 5262, - 5272, 5275, 5279, 5280, 5285, 5287, 5289, 5291, 5293, 5295, - 5297, 5299, 5301, 5303, 5305, 5307, 5309, 5311, 5313, 5315, - 5317, 5319, 5321, 5323, 5325, 5327, 5329, 5331, 5333, 5335, - 5337, 5339, 5341, 5343, 5345, 5347, 5349, 5351, 5353, 5355, - 5357, 5359, 5361, 5363, 5365, 5367, 5369, 5371, 5373, 5375, - 5377, 5379, 5381, 5383, 5385, 5387, 5389, 5391, 5393, 5395, - 5397, 5399, 5401, 5403, 5405, 5407, 5409, 5411, 5413, 5415, - 5417, 5419, 5421, 5423, 5425, 5427, 5429, 5431, 5433, 5435, - 5437, 5439, 5441, 5443, 5445, 5447, 5449, 5451, 5453, 5455, - 5457, 5459, 5461, 5463, 5465, 5467, 5469, 5471, 5473, 5475, - 5477, 5479, 5481, 5483, 5485, 5487, 5489, 5491, 5493, 5495, - 5497, 5499, 5501, 5503, 5505, 5507, 5509, 5511, 5513, 5515, - 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, 5533, 5535, - 5537, 5539, 5541, 5543, 5545, 5547, 5549, 5551, 5553, 5555, - 5557, 5559, 5561, 5563, 5565, 5567, 5569, 5571, 5573, 5575, - 5577, 5579, 5581, 5583, 5585, 5587, 5589, 5591, 5593, 5595, - 5597, 5599, 5601, 5603, 5605, 5607, 5609, 5611, 5613, 5615, - 5617, 5619, 5621, 5623, 5625, 5627, 5629, 5631, 5633, 5635, - 5637, 5639, 5641, 5643, 5645, 5647, 5649, 5651, 5653, 5655, - 5657, 5659, 5661, 5663, 5665, 5667, 5669, 5671, 5673, 5675, - 5677, 5679, 5681, 5683, 5685, 5687, 5689, 5691, 5693, 5695, - 5697, 5699, 5701, 5703, 5705, 5707, 5709, 5711, 5713, 5715, - 5717, 5719, 5721, 5723, 5725, 5727, 5729, 5731, 5733, 5735, - 5737, 5739, 5741, 5743, 5745, 5747, 5749, 5751, 5753, 5755, - 5757, 5759, 5761, 5763, 5765, 5767, 5769, 5771, 5773, 5775, - 5777, 5779, 5781, 5783, 5785, 5787, 5789, 5791, 5793, 5795, - 5797, 5799, 5801, 5803, 5805, 5807, 5809, 5811, 5813, 5815, - 5817, 5819, 5821, 5823, 5825, 5827, 5829, 5831, 5833, 5835, - 5837, 5839, 5841, 5843, 5845, 5847, 5849, 5851, 5853, 5855, - 5857, 5859, 5861, 5863, 5865, 5867, 5869, 5871, 5873, 5875, - 5877, 5879, 5881, 5883, 5885, 5887, 5889, 5891, 5893, 5895, - 5897, 5899, 5901, 5903, 5905, 5907, 5909, 5911, 5913, 5915, - 5917, 5919, 5921, 5923, 5925, 5927, 5929, 5931, 5933, 5935, - 5937, 5939, 5941, 5943, 5945, 5947, 5949, 5951, 5953, 5955, - 5957, 5959, 5961, 5963, 5965, 5967, 5969, 5971, 5973, 5975, - 5977, 5979, 5981, 5983, 5985, 5987, 5989, 5991, 5993, 5995, - 5997, 5999, 6001, 6003, 6005, 6007, 6009, 6011, 6013, 6015, - 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, 6033, 6035, - 6037, 6039, 6041, 6043, 6045, 6047, 6049, 6051, 6053, 6055, - 6057, 6059, 6061, 6063, 6065, 6067, 6069, 6071, 6073, 6075, - 6077, 6079, 6081, 6083, 6085, 6087, 6089, 6091, 6093, 6095, - 6097, 6099, 6101, 6103, 6105, 6107, 6109, 6111, 6113, 6115, - 6117, 6119, 6121, 6123, 6125, 6127, 6129, 6131, 6133, 6135, - 6137, 6139, 6141, 6143, 6145, 6147, 6149, 6151, 6153, 6155, - 6157, 6159, 6161, 6163, 6165, 6167, 6169, 6171, 6173, 6175, - 6177, 6179, 6181, 6183, 6185, 6187, 6189, 6191, 6193, 6195, - 6197, 6199, 6201, 6203, 6205, 6207, 6209, 6211, 6213, 6215, - 6217, 6219, 6221, 6223, 6225, 6227, 6229, 6231, 6233, 6235, - 6237, 6239, 6241, 6243, 6245, 6247, 6249, 6251, 6253, 6255, - 6257, 6259, 6261, 6263, 6265, 6267, 6269, 6271, 6273, 6275, - 6277, 6279, 6281, 6283, 6285, 6287, 6289, 6291, 6293, 6295, - 6297, 6299, 6301, 6303, 6305, 6307, 6309, 6311, 6313, 6315, - 6317, 6319, 6321, 6323, 6325, 6327, 6329, 6331, 6333, 6335, - 6337, 6339, 6341, 6343, 6345, 6347, 6349, 6351, 6353, 6355, - 6357, 6359, 6361, 6363, 6365, 6367, 6369, 6371, 6373, 6375, - 6377, 6379, 6381, 6383, 6385, 6387, 6389, 6391, 6393, 6395, - 6397, 6399, 6401, 6403, 6405, 6407, 6409, 6411, 6413, 6415, - 6417, 6419, 6421, 6423, 6425, 6427, 6429, 6431, 6433, 6435, - 6437, 6439, 6441, 6443, 6445, 6447, 6449, 6451, 6453, 6455, - 6457, 6459, 6461, 6463, 6465, 6467, 6469, 6471, 6473, 6475, - 6477, 6479, 6481, 6483, 6485, 6487, 6489, 6491, 6493, 6495, - 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, 6513, 6515, - 6517, 6519, 6521, 6523, 6525, 6527, 6529 + 2220, 2226, 2231, 2234, 2238, 2241, 2244, 2247, 2250, 2252, + 2255, 2259, 2260, 2262, 2263, 2269, 2271, 2276, 2283, 2286, + 2288, 2289, 2294, 2295, 2297, 2299, 2302, 2305, 2308, 2310, + 2312, 2315, 2318, 2320, 2322, 2324, 2326, 2328, 2330, 2334, + 2338, 2339, 2341, 2345, 2347, 2350, 2352, 2354, 2356, 2358, + 2360, 2363, 2368, 2373, 2379, 2381, 2383, 2386, 2387, 2390, + 2391, 2393, 2397, 2399, 2400, 2402, 2405, 2409, 2412, 2417, + 2420, 2424, 2427, 2428, 2430, 2433, 2434, 2439, 2445, 2447, + 2450, 2453, 2454, 2456, 2460, 2462, 2465, 2469, 2473, 2477, + 2481, 2485, 2489, 2491, 2496, 2506, 2516, 2520, 2521, 2524, + 2527, 2528, 2534, 2538, 2540, 2542, 2546, 2552, 2556, 2558, + 2561, 2563, 2567, 2573, 2575, 2578, 2582, 2587, 2593, 2598, + 2604, 2609, 2616, 2622, 2627, 2633, 2639, 2645, 2648, 2653, + 2655, 2657, 2658, 2660, 2665, 2671, 2676, 2677, 2680, 2683, + 2686, 2688, 2690, 2692, 2694, 2695, 2700, 2703, 2705, 2708, + 2711, 2716, 2719, 2726, 2729, 2731, 2735, 2740, 2741, 2744, + 2745, 2748, 2749, 2751, 2755, 2759, 2762, 2763, 2766, 2771, + 2773, 2775, 2777, 2778, 2781, 2785, 2791, 2798, 2801, 2805, + 2807, 2813, 2819, 2825, 2829, 2833, 2837, 2842, 2843, 2845, + 2847, 2849, 2851, 2853, 2856, 2861, 2863, 2865, 2867, 2869, + 2872, 2876, 2877, 2879, 2881, 2883, 2885, 2887, 2890, 2893, + 2896, 2899, 2902, 2904, 2908, 2909, 2911, 2913, 2915, 2917, + 2923, 2926, 2928, 2930, 2932, 2934, 2939, 2941, 2944, 2947, + 2949, 2953, 2957, 2960, 2962, 2963, 2969, 2972, 2978, 2981, + 2983, 2987, 2991, 2992, 2994, 2996, 2998, 3000, 3002, 3004, + 3006, 3008, 3010, 3012, 3014, 3016, 3018, 3020, 3022, 3024, + 3026, 3028, 3030, 3032, 3034, 3036, 3038, 3040, 3042, 3044, + 3046, 3048, 3050, 3052, 3054, 3056, 3058, 3060, 3062, 3064, + 3066, 3068, 3070, 3074, 3078, 3082, 3086, 3090, 3094, 3098, + 3099, 3101, 3105, 3109, 3115, 3118, 3121, 3125, 3129, 3133, + 3137, 3141, 3145, 3149, 3153, 3157, 3161, 3165, 3169, 3173, + 3177, 3181, 3184, 3187, 3191, 3195, 3198, 3201, 3205, 3209, + 3215, 3220, 3227, 3231, 3237, 3242, 3249, 3254, 3261, 3267, + 3275, 3279, 3282, 3287, 3291, 3294, 3298, 3302, 3306, 3310, + 3315, 3319, 3324, 3328, 3333, 3339, 3346, 3353, 3361, 3368, + 3376, 3383, 3391, 3395, 3400, 3405, 3412, 3414, 3420, 3425, + 3429, 3435, 3437, 3441, 3444, 3447, 3451, 3455, 3459, 3463, + 3467, 3471, 3475, 3479, 3483, 3487, 3491, 3495, 3499, 3503, + 3507, 3510, 3513, 3519, 3526, 3533, 3541, 3543, 3546, 3548, + 3550, 3552, 3555, 3558, 3563, 3567, 3569, 3571, 3573, 3575, + 3577, 3579, 3581, 3583, 3585, 3587, 3590, 3595, 3598, 3601, + 3605, 3609, 3614, 3618, 3625, 3633, 3643, 3651, 3659, 3665, + 3667, 3669, 3671, 3677, 3684, 3691, 3696, 3701, 3706, 3711, + 3718, 3724, 3730, 3736, 3741, 3748, 3753, 3755, 3763, 3773, + 3779, 3780, 3786, 3791, 3792, 3794, 3795, 3798, 3799, 3801, + 3805, 3809, 3812, 3815, 3816, 3823, 3825, 3826, 3830, 3831, + 3835, 3839, 3843, 3844, 3846, 3851, 3854, 3857, 3860, 3863, + 3866, 3870, 3873, 3876, 3880, 3881, 3886, 3890, 3892, 3898, + 3902, 3904, 3908, 3910, 3913, 3917, 3919, 3923, 3925, 3928, + 3930, 3931, 3933, 3935, 3937, 3939, 3941, 3943, 3945, 3947, + 3949, 3951, 3953, 3955, 3957, 3959, 3961, 3963, 3965, 3967, + 3969, 3971, 3976, 3978, 3983, 3985, 3990, 3992, 3995, 3997, + 4000, 4002, 4005, 4007, 4011, 4013, 4017, 4019, 4022, 4024, + 4028, 4030, 4033, 4035, 4036, 4038, 4042, 4044, 4048, 4052, + 4054, 4058, 4062, 4063, 4065, 4067, 4069, 4071, 4073, 4075, + 4077, 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, 4098, + 4102, 4105, 4109, 4110, 4114, 4118, 4121, 4124, 4126, 4127, + 4130, 4133, 4137, 4140, 4142, 4144, 4148, 4150, 4152, 4158, + 4160, 4163, 4168, 4171, 4172, 4174, 4175, 4177, 4181, 4183, + 4185, 4188, 4192, 4198, 4206, 4214, 4216, 4217, 4218, 4221, + 4222, 4225, 4229, 4233, 4237, 4243, 4251, 4259, 4260, 4263, + 4265, 4266, 4268, 4269, 4271, 4275, 4277, 4280, 4284, 4287, + 4289, 4294, 4297, 4299, 4300, 4304, 4306, 4310, 4312, 4315, + 4320, 4323, 4324, 4326, 4330, 4332, 4336, 4338, 4341, 4343, + 4347, 4349, 4351, 4354, 4356, 4358, 4361, 4363, 4365, 4368, + 4376, 4379, 4385, 4389, 4393, 4395, 4397, 4399, 4401, 4403, + 4405, 4407, 4409, 4411, 4413, 4415, 4417, 4419, 4421, 4424, + 4427, 4431, 4435, 4436, 4438, 4440, 4442, 4448, 4452, 4453, + 4455, 4457, 4459, 4461, 4463, 4465, 4470, 4478, 4485, 4488, + 4489, 4491, 4493, 4495, 4497, 4511, 4528, 4530, 4533, 4534, + 4536, 4537, 4539, 4540, 4543, 4544, 4546, 4547, 4554, 4563, + 4570, 4579, 4586, 4595, 4599, 4602, 4604, 4605, 4612, 4619, + 4621, 4623, 4625, 4627, 4629, 4631, 4634, 4636, 4638, 4640, + 4642, 4644, 4649, 4656, 4660, 4663, 4668, 4672, 4678, 4680, + 4681, 4683, 4685, 4686, 4688, 4690, 4692, 4694, 4696, 4698, + 4700, 4702, 4704, 4706, 4708, 4710, 4712, 4714, 4716, 4718, + 4720, 4722, 4724, 4726, 4728, 4730, 4732, 4734, 4736, 4738, + 4740, 4742, 4744, 4746, 4748, 4750, 4752, 4754, 4756, 4758, + 4760, 4764, 4766, 4768, 4770, 4772, 4774, 4776, 4779, 4781, + 4783, 4786, 4790, 4794, 4798, 4802, 4804, 4808, 4812, 4815, + 4819, 4823, 4825, 4827, 4829, 4833, 4839, 4841, 4843, 4845, + 4847, 4851, 4854, 4859, 4866, 4873, 4874, 4876, 4878, 4880, + 4881, 4884, 4887, 4892, 4899, 4905, 4910, 4917, 4919, 4921, + 4923, 4925, 4927, 4929, 4930, 4932, 4936, 4938, 4939, 4947, + 4951, 4953, 4956, 4960, 4963, 4964, 4967, 4968, 4971, 4976, + 4982, 4991, 4994, 4998, 5004, 5006, 5007, 5010, 5011, 5014, + 5018, 5022, 5026, 5030, 5032, 5034, 5036, 5039, 5043, 5046, + 5049, 5052, 5055, 5059, 5064, 5068, 5070, 5072, 5074, 5076, + 5078, 5080, 5081, 5083, 5087, 5089, 5093, 5096, 5106, 5119, + 5131, 5144, 5159, 5163, 5168, 5173, 5174, 5182, 5193, 5203, + 5206, 5210, 5211, 5216, 5218, 5220, 5222, 5224, 5226, 5228, + 5230, 5232, 5234, 5236, 5238, 5240, 5242, 5244, 5246, 5248, + 5250, 5252, 5254, 5256, 5258, 5260, 5262, 5264, 5266, 5268, + 5270, 5272, 5274, 5276, 5278, 5280, 5282, 5284, 5286, 5288, + 5290, 5292, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, + 5310, 5312, 5314, 5316, 5318, 5320, 5322, 5324, 5326, 5328, + 5330, 5332, 5334, 5336, 5338, 5340, 5342, 5344, 5346, 5348, + 5350, 5352, 5354, 5356, 5358, 5360, 5362, 5364, 5366, 5368, + 5370, 5372, 5374, 5376, 5378, 5380, 5382, 5384, 5386, 5388, + 5390, 5392, 5394, 5396, 5398, 5400, 5402, 5404, 5406, 5408, + 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, 5426, 5428, + 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, + 5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, + 5470, 5472, 5474, 5476, 5478, 5480, 5482, 5484, 5486, 5488, + 5490, 5492, 5494, 5496, 5498, 5500, 5502, 5504, 5506, 5508, + 5510, 5512, 5514, 5516, 5518, 5520, 5522, 5524, 5526, 5528, + 5530, 5532, 5534, 5536, 5538, 5540, 5542, 5544, 5546, 5548, + 5550, 5552, 5554, 5556, 5558, 5560, 5562, 5564, 5566, 5568, + 5570, 5572, 5574, 5576, 5578, 5580, 5582, 5584, 5586, 5588, + 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604, 5606, 5608, + 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, + 5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, + 5650, 5652, 5654, 5656, 5658, 5660, 5662, 5664, 5666, 5668, + 5670, 5672, 5674, 5676, 5678, 5680, 5682, 5684, 5686, 5688, + 5690, 5692, 5694, 5696, 5698, 5700, 5702, 5704, 5706, 5708, + 5710, 5712, 5714, 5716, 5718, 5720, 5722, 5724, 5726, 5728, + 5730, 5732, 5734, 5736, 5738, 5740, 5742, 5744, 5746, 5748, + 5750, 5752, 5754, 5756, 5758, 5760, 5762, 5764, 5766, 5768, + 5770, 5772, 5774, 5776, 5778, 5780, 5782, 5784, 5786, 5788, + 5790, 5792, 5794, 5796, 5798, 5800, 5802, 5804, 5806, 5808, + 5810, 5812, 5814, 5816, 5818, 5820, 5822, 5824, 5826, 5828, + 5830, 5832, 5834, 5836, 5838, 5840, 5842, 5844, 5846, 5848, + 5850, 5852, 5854, 5856, 5858, 5860, 5862, 5864, 5866, 5868, + 5870, 5872, 5874, 5876, 5878, 5880, 5882, 5884, 5886, 5888, + 5890, 5892, 5894, 5896, 5898, 5900, 5902, 5904, 5906, 5908, + 5910, 5912, 5914, 5916, 5918, 5920, 5922, 5924, 5926, 5928, + 5930, 5932, 5934, 5936, 5938, 5940, 5942, 5944, 5946, 5948, + 5950, 5952, 5954, 5956, 5958, 5960, 5962, 5964, 5966, 5968, + 5970, 5972, 5974, 5976, 5978, 5980, 5982, 5984, 5986, 5988, + 5990, 5992, 5994, 5996, 5998, 6000, 6002, 6004, 6006, 6008, + 6010, 6012, 6014, 6016, 6018, 6020, 6022, 6024, 6026, 6028, + 6030, 6032, 6034, 6036, 6038, 6040, 6042, 6044, 6046, 6048, + 6050, 6052, 6054, 6056, 6058, 6060, 6062, 6064, 6066, 6068, + 6070, 6072, 6074, 6076, 6078, 6080, 6082, 6084, 6086, 6088, + 6090, 6092, 6094, 6096, 6098, 6100, 6102, 6104, 6106, 6108, + 6110, 6112, 6114, 6116, 6118, 6120, 6122, 6124, 6126, 6128, + 6130, 6132, 6134, 6136, 6138, 6140, 6142, 6144, 6146, 6148, + 6150, 6152, 6154, 6156, 6158, 6160, 6162, 6164, 6166, 6168, + 6170, 6172, 6174, 6176, 6178, 6180, 6182, 6184, 6186, 6188, + 6190, 6192, 6194, 6196, 6198, 6200, 6202, 6204, 6206, 6208, + 6210, 6212, 6214, 6216, 6218, 6220, 6222, 6224, 6226, 6228, + 6230, 6232, 6234, 6236, 6238, 6240, 6242, 6244, 6246, 6248, + 6250, 6252, 6254, 6256, 6258, 6260, 6262, 6264, 6266, 6268, + 6270, 6272, 6274, 6276, 6278, 6280, 6282, 6284, 6286, 6288, + 6290, 6292, 6294, 6296, 6298, 6300, 6302, 6304, 6306, 6308, + 6310, 6312, 6314, 6316, 6318, 6320, 6322, 6324, 6326, 6328, + 6330, 6332, 6334, 6336, 6338, 6340, 6342, 6344, 6346, 6348, + 6350, 6352, 6354, 6356, 6358, 6360, 6362, 6364, 6366, 6368, + 6370, 6372, 6374, 6376, 6378, 6380, 6382, 6384, 6386, 6388, + 6390, 6392, 6394, 6396, 6398, 6400, 6402, 6404, 6406, 6408, + 6410, 6412, 6414, 6416, 6418, 6420, 6422, 6424, 6426, 6428, + 6430, 6432, 6434, 6436, 6438, 6440, 6442, 6444, 6446, 6448, + 6450, 6452, 6454, 6456, 6458, 6460 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 530, 0, -1, 531, -1, 531, 521, 532, -1, 532, - -1, 948, -1, 591, -1, 533, -1, 986, -1, 987, - -1, 999, -1, 949, -1, 951, -1, 668, -1, 1002, - -1, 658, -1, 938, -1, 582, -1, 580, -1, 604, - -1, 576, -1, 544, -1, 982, -1, 988, -1, 598, - -1, 652, -1, 587, -1, 956, -1, 954, -1, 955, - -1, 941, -1, 555, -1, 973, -1, 579, -1, 935, + -1, 938, -1, 591, -1, 533, -1, 976, -1, 977, + -1, 990, -1, 939, -1, 941, -1, 668, -1, 993, + -1, 658, -1, 928, -1, 582, -1, 580, -1, 604, + -1, 576, -1, 544, -1, 972, -1, 978, -1, 598, + -1, 652, -1, 587, -1, 946, -1, 944, -1, 945, + -1, 931, -1, 555, -1, 963, -1, 579, -1, 925, -1, 553, -1, 686, -1, 600, -1, 586, -1, 667, - -1, 603, -1, 977, -1, 991, -1, 967, -1, 994, - -1, 1000, -1, -1, 32, 419, 775, 541, -1, 32, - 419, 192, 152, 775, 541, -1, 32, 203, 545, 541, + -1, 603, -1, 967, -1, 981, -1, 957, -1, 984, + -1, 991, -1, -1, 32, 419, 773, 541, -1, 32, + 419, 192, 152, 773, 541, -1, 32, 203, 545, 541, -1, 32, 203, 192, 152, 545, 541, -1, 32, 384, 545, 541, -1, 32, 384, 192, 152, 545, 541, -1, 32, 470, 545, 541, -1, 32, 470, 192, 152, 545, - 541, -1, 536, -1, 534, 536, -1, 389, 117, 824, + 541, -1, 536, -1, 534, 536, -1, 389, 117, 822, -1, 137, 117, -1, 359, -1, 359, 593, 594, -1, 389, 595, -1, 389, 176, 651, -1, 540, -1, 537, 522, 540, -1, 26, 631, -1, 26, 192, 275, 152, @@ -1982,72 +1980,72 @@ static const yytype_int16 yyrhs[] = 546, 534, -1, 32, 554, 546, 137, 191, -1, 32, 554, 546, 137, 191, 192, 152, -1, 137, 554, 192, 152, 546, 656, -1, 137, 554, 546, 656, -1, 32, - 554, 546, 543, 442, 787, 784, 539, -1, 32, 554, - 546, 542, -1, 26, 621, -1, 32, 93, 923, 605, - -1, 460, 93, 923, -1, 137, 93, 192, 152, 923, - 656, -1, 137, 93, 923, 656, -1, 389, 245, -1, + 554, 546, 543, 442, 786, 782, 539, -1, 32, 554, + 546, 542, -1, 26, 621, -1, 32, 93, 913, 605, + -1, 460, 93, 913, -1, 137, 93, 192, 152, 913, + 656, -1, 137, 93, 913, 656, -1, 389, 245, -1, 389, 451, -1, 389, 619, -1, 357, 619, -1, 542, - -1, 457, 824, -1, -1, 615, -1, 389, 615, -1, + -1, 457, 822, -1, -1, 615, -1, 389, 615, -1, 26, 615, -1, 137, 629, -1, 538, -1, 541, 522, 538, -1, 294, 518, 537, 519, -1, 389, 107, -1, - 389, -1, -1, 111, 923, -1, 111, 326, 923, -1, + 389, -1, -1, 111, 913, -1, 111, 326, 913, -1, 111, 30, -1, 111, 326, 30, -1, 547, -1, 546, - 549, -1, 3, -1, 1005, -1, 1006, -1, 546, -1, + 549, -1, 3, -1, 996, -1, 997, -1, 546, -1, 5, -1, 5, -1, 550, -1, 549, 550, -1, 520, - 551, -1, 552, -1, 3, -1, 1009, -1, 1005, -1, - 1011, -1, 32, 373, 923, 353, 431, 923, -1, 32, - 419, 775, 353, 431, 923, -1, 32, 419, 192, 152, - 775, 353, 431, 923, -1, 32, 384, 545, 353, 431, - 923, -1, 32, 384, 192, 152, 545, 353, 431, 923, - -1, 32, 470, 545, 353, 431, 923, -1, 32, 470, - 192, 152, 545, 353, 431, 923, -1, 32, 203, 545, - 353, 431, 923, -1, 32, 203, 192, 152, 545, 353, - 431, 923, -1, 32, 419, 775, 353, 554, 923, 431, - 923, -1, 32, 419, 192, 152, 775, 353, 554, 923, - 431, 923, -1, 32, 419, 775, 353, 93, 923, 431, - 923, -1, 32, 419, 192, 152, 775, 353, 93, 923, - 431, 923, -1, 82, -1, -1, 560, 213, 563, 220, + 551, -1, 552, -1, 3, -1, 1000, -1, 996, -1, + 1002, -1, 32, 373, 913, 353, 431, 913, -1, 32, + 419, 773, 353, 431, 913, -1, 32, 419, 192, 152, + 773, 353, 431, 913, -1, 32, 384, 545, 353, 431, + 913, -1, 32, 384, 192, 152, 545, 353, 431, 913, + -1, 32, 470, 545, 353, 431, 913, -1, 32, 470, + 192, 152, 545, 353, 431, 913, -1, 32, 203, 545, + 353, 431, 913, -1, 32, 203, 192, 152, 545, 353, + 431, 913, -1, 32, 419, 773, 353, 554, 913, 431, + 913, -1, 32, 419, 192, 152, 773, 353, 554, 913, + 431, 913, -1, 32, 419, 773, 353, 93, 913, 431, + 913, -1, 32, 419, 192, 152, 773, 353, 93, 913, + 431, 913, -1, 82, -1, -1, 560, 213, 563, 220, 557, 558, 556, 564, 566, -1, 686, -1, 304, 567, 462, 686, -1, 518, 571, 519, 686, -1, 518, 571, 519, 304, 567, 462, 686, -1, 117, 463, -1, 545, -1, 545, 40, 546, -1, 59, 266, -1, 59, 321, - -1, -1, 518, 574, 519, 781, -1, 290, 93, 923, - -1, -1, 698, -1, -1, 546, 897, -1, 575, 507, - 824, -1, 518, 568, 519, 507, 824, -1, 295, 355, + -1, -1, 518, 574, 519, 779, -1, 290, 93, 913, + -1, -1, 698, -1, -1, 546, 894, -1, 575, 507, + 822, -1, 518, 568, 519, 507, 822, -1, 295, 355, -1, 295, 193, -1, -1, 290, 91, 559, 133, 454, - 389, 573, 781, -1, 290, 91, 559, 133, 276, -1, - -1, 546, 569, 570, 714, 715, -1, 836, 569, 570, - 714, 715, -1, 518, 824, 519, 569, 570, 714, 715, - -1, 361, 903, -1, -1, 456, -1, 418, -1, 575, - -1, 568, 522, 575, -1, 80, 930, -1, -1, 930, + 389, 573, 779, -1, 290, 91, 559, 133, 276, -1, + -1, 546, 569, 570, 714, 715, -1, 833, 569, 570, + 714, 715, -1, 518, 822, 519, 569, 570, 714, 715, + -1, 361, 900, -1, -1, 456, -1, 418, -1, 575, + -1, 568, 522, 575, -1, 80, 920, -1, -1, 920, -1, -1, 561, -1, 571, 522, 561, -1, 562, -1, 572, 522, 562, -1, 572, -1, 572, 522, -1, 565, - -1, 574, 522, 565, -1, 546, 897, -1, 100, 442, + -1, 574, 522, 565, -1, 546, 894, -1, 100, 442, 545, 40, 144, 687, -1, 100, 442, 545, 40, 144, - 518, 577, 519, -1, 100, 442, 545, 40, 788, -1, + 518, 577, 519, -1, 100, 442, 545, 40, 786, -1, 578, -1, -1, 548, -1, 578, 522, 548, -1, 323, - 546, -1, 323, 546, 507, 972, -1, 323, 546, 518, - 875, 519, -1, 100, 650, 384, 545, 581, -1, 100, + 546, -1, 323, 546, 507, 962, -1, 323, 546, 518, + 872, 519, -1, 100, 650, 384, 545, 581, -1, 100, 650, 384, 192, 275, 152, 545, 581, -1, 100, 295, 355, 650, 384, 545, 581, -1, 592, -1, -1, 100, 584, 380, 583, 585, 518, 685, 519, -1, 100, 584, 380, 192, 275, 152, 583, 585, 518, 685, 519, -1, 100, 295, 355, 584, 380, 583, 585, 518, 685, 519, -1, -1, 546, -1, -1, 425, -1, 314, -1, -1, - 199, 3, -1, 560, 454, 157, 639, -1, 151, 923, - 590, -1, 100, 650, 419, 1004, 40, 151, 923, 590, - 1003, -1, 100, 650, 419, 192, 275, 152, 1004, 40, - 151, 923, 590, 1003, -1, 824, -1, 933, 13, 824, + 199, 3, -1, 560, 454, 157, 639, -1, 151, 913, + 590, -1, 100, 650, 419, 995, 40, 151, 913, 590, + 994, -1, 100, 650, 419, 192, 275, 152, 995, 40, + 151, 913, 590, 994, -1, 822, -1, 923, 13, 822, -1, 588, -1, 589, 522, 588, -1, 518, 589, 519, -1, -1, 32, 384, 545, 592, -1, 32, 384, 192, 152, 545, 592, -1, 595, -1, 592, 595, -1, 480, -1, 504, -1, -1, 4, -1, 509, 4, -1, 510, - 4, -1, 597, -1, 40, 791, -1, 60, 594, -1, + 4, -1, 597, -1, 40, 789, -1, 60, 594, -1, 106, -1, 273, 106, -1, 202, 596, 594, -1, 251, 594, -1, 261, 594, -1, 273, 251, -1, 273, 261, - -1, 305, 59, 930, -1, 384, 266, 930, -1, 403, + -1, 305, 59, 920, -1, 384, 266, 920, -1, 403, 593, 594, -1, 359, -1, 359, 593, 594, -1, 59, - -1, -1, 926, -1, 509, 926, -1, 510, 926, -1, + -1, -1, 916, -1, 509, 916, -1, 510, 916, -1, 137, 584, 380, 546, 599, -1, 137, 584, 380, 192, 152, 546, 599, -1, -1, 172, 3, -1, 22, 601, -1, 52, 601, 602, -1, 403, 601, 602, -1, 86, @@ -2057,21 +2055,21 @@ static const yytype_int16 yyrhs[] = 626, 618, -1, 100, 650, 419, 192, 275, 152, 545, 518, 637, 519, 626, 618, -1, 100, 295, 355, 650, 419, 545, 518, 637, 519, 626, 618, -1, -1, 605, - 630, -1, 645, -1, 1011, -1, 867, -1, 594, -1, + 630, -1, 645, -1, 1002, -1, 864, -1, 594, -1, 548, -1, 274, -1, 518, 592, 519, -1, -1, 548, -1, 273, 25, -1, 360, -1, 63, -1, 389, 280, - -1, 389, 117, -1, 93, 923, 611, -1, 611, -1, - 625, -1, 80, 930, -1, 275, 280, -1, 280, -1, - 448, 636, -1, 329, 227, 636, -1, 74, 518, 824, - 519, 620, -1, 457, 88, 923, -1, 117, 825, -1, + -1, 389, 117, -1, 93, 913, 611, -1, 611, -1, + 625, -1, 80, 920, -1, 275, 280, -1, 280, -1, + 448, 636, -1, 329, 227, 636, -1, 74, 518, 822, + 519, 620, -1, 457, 88, 913, -1, 117, 823, -1, 347, 545, 639, 648, 617, -1, 472, -1, 409, -1, 612, -1, -1, 176, 651, 40, 191, 607, -1, 176, - 651, 40, 518, 824, 519, 613, -1, 40, 518, 824, + 651, 40, 518, 822, 519, 613, -1, 40, 518, 822, 519, 613, -1, 629, 608, -1, 290, 454, 609, -1, 616, -1, 641, -1, 616, 641, -1, 641, 616, -1, -1, 290, 86, 137, -1, 290, 86, 122, 369, -1, 290, 86, 328, 369, -1, -1, 518, 623, 519, -1, - 273, 205, -1, -1, 93, 923, 646, -1, 646, -1, + 273, 205, -1, -1, 93, 913, 646, -1, 646, -1, 85, -1, 94, -1, 118, -1, 191, -1, 204, -1, 405, -1, 408, -1, 30, -1, 642, -1, 623, 522, 642, -1, 457, 203, 633, -1, 119, -1, 275, 119, @@ -2080,7 +2078,7 @@ static const yytype_int16 yyrhs[] = -1, 628, 201, 622, -1, 628, 149, 622, -1, -1, 552, -1, 275, 119, -1, 119, -1, 207, 195, -1, 207, 120, -1, 275, 459, -1, 273, 205, -1, 546, - 788, 640, -1, 546, 787, 614, 640, -1, 635, -1, + 786, 640, -1, 546, 785, 614, 640, -1, 635, -1, 632, 522, 635, -1, 546, -1, 631, -1, 649, -1, 621, -1, 552, 507, 606, -1, 552, -1, 480, 627, -1, -1, 647, -1, 647, 522, -1, -1, 546, -1, @@ -2088,8 +2086,8 @@ static const yytype_int16 yyrhs[] = 122, 609, -1, 552, 507, 606, -1, 552, -1, 552, 520, 552, 507, 606, -1, 552, 520, 552, -1, 638, -1, 643, 522, 638, -1, 643, -1, 643, 522, -1, - 788, -1, 927, 931, 513, 442, -1, 390, 927, 931, - 513, 442, -1, 74, 518, 824, 519, 605, -1, 448, + 786, -1, 917, 921, 513, 442, -1, 390, 917, 921, + 513, 442, -1, 74, 518, 822, 519, 605, -1, 448, 518, 644, 519, 636, 605, -1, 448, 624, 605, -1, 329, 227, 518, 644, 519, 636, 605, -1, 329, 227, 624, 605, -1, 169, 227, 518, 644, 519, 347, 545, @@ -2099,16 +2097,16 @@ static const yytype_int16 yyrhs[] = 425, -1, 241, 423, -1, 178, 425, -1, 178, 423, -1, 451, -1, -1, 33, -1, 59, 117, -1, 137, 653, 192, 152, 655, 656, -1, 137, 653, 655, 656, - -1, 137, 654, 192, 152, 920, 656, -1, 137, 654, - 920, 656, -1, 137, 657, 923, 290, 930, 656, -1, - 137, 657, 192, 152, 923, 290, 930, 656, -1, 419, + -1, 137, 654, 192, 152, 910, 656, -1, 137, 654, + 910, 656, -1, 137, 657, 913, 290, 920, 656, -1, + 137, 657, 192, 152, 913, 290, 920, 656, -1, 419, -1, 384, -1, 174, -1, 246, -1, 246, 419, -1, 470, -1, 250, 470, -1, 203, -1, 169, 419, -1, 81, -1, 97, -1, 373, -1, 405, -1, 426, 377, 308, -1, 426, 377, 129, -1, 426, 377, 424, -1, 426, 377, 90, -1, 442, -1, 24, 252, -1, 146, 436, -1, 156, -1, 169, 107, 484, -1, 335, -1, - 387, -1, 930, -1, 655, 522, 930, -1, 63, -1, + 387, -1, 920, -1, 655, 522, 920, -1, 63, -1, 360, -1, -1, 320, -1, 370, -1, 436, -1, 100, 650, 665, 545, 662, -1, 100, 650, 665, 192, 275, 152, 545, 662, -1, 100, 295, 355, 650, 665, 545, @@ -2116,508 +2114,501 @@ static const yytype_int16 yyrhs[] = 665, 192, 275, 152, 545, 664, -1, 100, 295, 355, 650, 665, 545, 664, -1, 666, 40, 419, 688, -1, 666, 40, 419, 687, -1, 660, -1, 661, 522, 660, - -1, 659, -1, 661, -1, 666, 40, 824, -1, 663, + -1, 659, -1, 661, -1, 666, 40, 822, -1, 663, -1, 664, 522, 663, -1, 174, -1, 246, -1, 518, - 519, -1, 518, 875, 519, -1, 560, 454, 983, 389, - 573, 754, 984, 566, -1, 98, 681, 545, 639, 679, + 519, -1, 518, 872, 519, -1, 560, 454, 973, 389, + 573, 753, 974, 566, -1, 98, 681, 545, 639, 679, 670, 675, 684, 671, 593, 676, -1, 98, 518, 686, 519, 431, 675, 684, 593, 676, -1, 98, 172, 108, 546, 431, 546, 669, -1, -1, 518, 373, 519, -1, 518, 107, 519, -1, 172, -1, 431, -1, 673, 124, 548, -1, -1, 683, -1, 672, 522, 683, -1, 457, -1, -1, 40, -1, -1, 334, -1, -1, 680, -1, - 518, 685, 519, -1, 964, -1, 594, -1, 831, -1, - 511, -1, 518, 672, 519, -1, 832, -1, 833, -1, + 518, 685, 519, -1, 954, -1, 594, -1, 828, -1, + 511, -1, 518, 672, 519, -1, 829, -1, 830, -1, -1, 552, 677, -1, 480, 288, -1, -1, 680, 682, -1, -1, 55, -1, -1, 55, -1, 288, -1, 171, -1, 123, 674, 548, -1, 280, 674, 548, -1, 102, -1, 187, -1, 339, 674, 548, -1, 145, 674, 548, -1, 168, 339, 643, -1, 168, 339, 511, -1, 310, 59, 643, -1, 310, 59, 511, -1, 168, 275, 280, - 643, -1, 168, 280, 643, -1, 141, 548, -1, 964, + 643, -1, 168, 280, 643, -1, 141, 548, -1, 954, -1, 548, -1, 406, -1, 407, -1, 3, 520, 546, -1, 3, -1, 678, -1, 685, 522, 678, -1, 688, -1, 687, -1, 518, 688, 519, -1, 518, 687, 519, - -1, 518, 994, 519, -1, 691, -1, 689, 711, -1, - 689, 710, 745, 717, -1, 689, 710, 716, 746, -1, + -1, 518, 984, 519, -1, 691, -1, 689, 711, -1, + 689, 710, 744, 717, -1, 689, 710, 716, 745, -1, 698, 689, -1, 698, 689, 711, -1, 698, 689, 710, - 745, 717, -1, 698, 689, 710, 716, 746, -1, 691, - -1, 687, -1, 382, 708, 902, -1, -1, 382, 708, - 902, 702, 754, 781, 734, 743, 843, 744, 722, -1, - 382, 707, 904, 702, 754, 781, 734, 743, 843, 744, - 722, -1, 172, 755, 690, 702, 781, 734, 743, 843, - 744, 722, -1, 172, 755, 382, 707, 904, 702, 781, - 734, 743, 843, 744, 722, -1, 753, -1, 419, 775, + 744, 717, -1, 698, 689, 710, 716, 745, -1, 691, + -1, 687, -1, 382, 708, 899, -1, -1, 382, 708, + 899, 702, 753, 779, 733, 742, 840, 743, 721, -1, + 382, 707, 901, 702, 753, 779, 733, 742, 840, 743, + 721, -1, 172, 754, 690, 702, 779, 733, 742, 840, + 743, 721, -1, 172, 754, 382, 707, 901, 702, 779, + 733, 742, 840, 743, 721, -1, 752, -1, 419, 773, -1, 689, 447, 705, 706, 689, -1, 689, 447, 705, 689, -1, 689, 218, 705, 689, -1, 689, 147, 705, - 689, -1, 693, 758, 457, 904, -1, 693, 758, 457, - 904, 181, 59, 922, -1, 693, 758, 181, 59, 922, - -1, 693, 758, 290, 697, -1, 693, 758, 290, 697, - 181, 59, 922, -1, 693, 758, 290, 697, 457, 904, - -1, 693, 758, 290, 697, 457, 904, 181, 59, 922, - -1, 694, 758, 290, 904, 220, 266, 923, 692, 922, - -1, 694, 758, 290, 904, -1, 462, -1, 463, -1, - 315, -1, 317, -1, 452, -1, 316, -1, 825, -1, - 825, 199, 518, 688, 519, -1, 761, -1, 695, -1, + 689, -1, 693, 756, 457, 901, -1, 693, 756, 457, + 901, 181, 59, 912, -1, 693, 756, 181, 59, 912, + -1, 693, 756, 290, 697, -1, 693, 756, 290, 697, + 181, 59, 912, -1, 693, 756, 290, 697, 457, 901, + -1, 693, 756, 290, 697, 457, 901, 181, 59, 912, + -1, 694, 756, 290, 901, 220, 266, 913, 692, 912, + -1, 694, 756, 290, 901, -1, 462, -1, 463, -1, + 315, -1, 317, -1, 452, -1, 316, -1, 823, -1, + 823, 199, 518, 688, 519, -1, 759, -1, 695, -1, 696, 522, 695, -1, 696, -1, 696, 522, -1, 480, 699, -1, 504, 699, -1, 480, 345, 699, -1, 700, - -1, 699, 522, 700, -1, 923, 932, 40, 701, 518, - 937, 519, -1, 250, -1, 275, 250, -1, -1, 220, + -1, 699, 522, 700, -1, 913, 922, 40, 701, 518, + 927, 519, -1, 250, -1, 275, 250, -1, -1, 220, 703, -1, -1, 425, 704, 545, -1, 423, 704, 545, -1, 241, 425, 704, 545, -1, 241, 423, 704, 545, -1, 178, 425, 704, 545, -1, 178, 423, 704, 545, -1, 451, 704, 545, -1, 419, 545, -1, 545, -1, 419, -1, -1, 30, -1, 132, -1, -1, 59, 266, - -1, 132, -1, 132, 290, 518, 873, 519, -1, 30, + -1, 132, -1, 132, 290, 518, 870, 519, -1, 30, -1, -1, 193, 282, -1, 358, 282, -1, -1, 711, -1, -1, 296, 59, 712, -1, 296, 59, 30, 714, - 715, -1, 713, -1, 712, 522, 713, -1, 824, 457, - 867, 715, -1, 824, 714, 715, -1, 41, -1, 126, + 715, -1, 713, -1, 712, 522, 713, -1, 822, 457, + 864, 715, -1, 822, 714, 715, -1, 41, -1, 126, -1, -1, 503, 164, -1, 503, 231, -1, -1, 718, 719, -1, 719, 718, -1, 718, -1, 719, -1, 716, - -1, -1, 238, 728, -1, 238, 728, 522, 729, -1, - 162, 733, 730, 732, 291, -1, 162, 733, 732, 291, - -1, 287, 729, -1, 287, 730, 732, -1, 4, -1, - 9, -1, 829, -1, 720, 513, -1, 720, 313, -1, - 720, -1, 720, 369, -1, 457, 371, 724, -1, -1, - 546, -1, -1, 723, 518, 721, 519, 727, -1, 721, - -1, 721, 518, 546, 519, -1, 721, 518, 546, 522, - 9, 519, -1, 421, 724, -1, 725, -1, -1, 354, - 518, 9, 519, -1, -1, 824, -1, 30, -1, 824, - 513, -1, 4, 313, -1, 9, 313, -1, 824, -1, - 826, -1, 509, 731, -1, 510, 731, -1, 926, -1, + -1, -1, 238, 727, -1, 238, 727, 522, 728, -1, + 162, 732, 729, 731, 291, -1, 162, 732, 731, 291, + -1, 287, 728, -1, 287, 729, 731, -1, 4, 513, + -1, 9, 513, -1, 4, 313, -1, 9, 313, -1, + 9, -1, 9, 369, -1, 457, 371, 723, -1, -1, + 546, -1, -1, 722, 518, 720, 519, 726, -1, 720, + -1, 720, 518, 546, 519, -1, 720, 518, 546, 522, + 9, 519, -1, 421, 723, -1, 724, -1, -1, 354, + 518, 9, 519, -1, -1, 822, -1, 30, -1, 822, + 513, -1, 4, 313, -1, 9, 313, -1, 822, -1, + 824, -1, 509, 730, -1, 510, 730, -1, 916, -1, 4, -1, 368, -1, 369, -1, 164, -1, 272, -1, - 181, 59, 736, -1, 181, 59, 30, -1, -1, 737, - -1, 735, 522, 737, -1, 735, -1, 735, 522, -1, - 824, -1, 738, -1, 740, -1, 739, -1, 741, -1, - 518, 519, -1, 367, 518, 873, 519, -1, 103, 518, - 873, 519, -1, 182, 391, 518, 736, 519, -1, 182, - -1, 183, -1, 186, 824, -1, -1, 336, 824, -1, - -1, 747, -1, 167, 341, 291, -1, 745, -1, -1, - 748, -1, 747, 748, -1, 749, 750, 751, -1, 167, + 181, 59, 735, -1, 181, 59, 30, -1, -1, 736, + -1, 734, 522, 736, -1, 734, -1, 734, 522, -1, + 822, -1, 737, -1, 739, -1, 738, -1, 740, -1, + 518, 519, -1, 367, 518, 870, 519, -1, 103, 518, + 870, 519, -1, 182, 391, 518, 735, 519, -1, 182, + -1, 183, -1, 186, 822, -1, -1, 336, 822, -1, + -1, 746, -1, 167, 341, 291, -1, 744, -1, -1, + 747, -1, 746, 747, -1, 748, 749, 750, -1, 167, 454, -1, 167, 273, 227, 454, -1, 167, 392, -1, - 167, 227, 392, -1, 285, 919, -1, -1, 279, -1, - 396, 244, -1, -1, 463, 518, 873, 519, -1, 752, - 522, 518, 873, 519, -1, 752, -1, 752, 522, -1, - 172, 756, -1, -1, 758, -1, 755, 522, 758, -1, - 755, -1, 755, 522, -1, 547, 523, -1, 775, 770, - 726, -1, 757, 775, 726, -1, 776, 771, 726, -1, - 757, 776, 726, -1, 753, 769, 726, -1, 232, 776, - 771, -1, 687, 770, 726, -1, 757, 687, 726, -1, - 232, 687, 770, -1, 768, -1, 518, 768, 519, 769, - -1, 757, 518, 768, 519, -1, 758, 315, 518, 904, - 167, 764, 759, 519, 770, -1, 758, 452, 760, 518, - 765, 167, 767, 519, 770, -1, 181, 59, 921, -1, - -1, 200, 282, -1, 148, 282, -1, -1, 825, 199, - 518, 904, 519, -1, 825, 199, 547, -1, 827, -1, - 830, -1, 518, 871, 519, -1, 762, 199, 518, 904, - 519, -1, 762, 199, 547, -1, 763, -1, 764, 763, - -1, 547, -1, 518, 921, 519, -1, 765, 199, 518, - 904, 519, -1, 766, -1, 767, 766, -1, 518, 768, - 519, -1, 758, 101, 225, 758, -1, 758, 772, 225, - 758, 774, -1, 758, 225, 758, 774, -1, 758, 269, - 772, 225, 758, -1, 758, 269, 225, 758, -1, 758, - 42, 772, 225, 758, 774, -1, 758, 42, 225, 758, - 774, -1, 758, 322, 225, 758, -1, 758, 37, 225, - 758, 774, -1, 758, 383, 225, 758, 774, -1, 40, - 547, 518, 921, 519, -1, 40, 547, -1, 546, 518, - 921, 519, -1, 546, -1, 769, -1, -1, 769, -1, - 40, 518, 782, 519, -1, 40, 547, 518, 782, 519, - -1, 546, 518, 782, 519, -1, -1, 173, 773, -1, - 235, 773, -1, 364, 773, -1, 383, -1, 37, -1, - 209, -1, 300, -1, -1, 457, 518, 921, 519, -1, - 290, 824, -1, 545, -1, 545, 511, -1, 291, 545, - -1, 291, 518, 545, 519, -1, 836, 780, -1, 369, - 172, 518, 778, 519, 780, -1, 836, 779, -1, 777, - -1, 778, 522, 777, -1, 40, 518, 782, 519, -1, - -1, 504, 297, -1, -1, 477, 824, -1, -1, 783, - -1, 782, 522, 783, -1, 547, 788, 784, -1, 80, - 930, -1, -1, 546, 788, -1, 785, 522, 546, 788, - -1, 368, -1, 412, -1, 788, -1, -1, 791, 790, - -1, 390, 791, 790, -1, 791, 39, 516, 926, 517, - -1, 390, 791, 39, 516, 926, 517, -1, 791, 39, - -1, 390, 791, 39, -1, 789, -1, 786, 518, 785, - 519, 790, -1, 247, 518, 877, 519, 790, -1, 447, - 518, 785, 519, 790, -1, 3, 520, 3, -1, 789, - 520, 3, -1, 790, 516, 517, -1, 790, 516, 926, - 517, -1, -1, 793, -1, 795, -1, 797, -1, 801, - -1, 807, -1, 808, 823, -1, 808, 518, 926, 519, - -1, 795, -1, 798, -1, 802, -1, 807, -1, 929, - 794, -1, 518, 874, 519, -1, -1, 216, -1, 217, - -1, 397, -1, 54, -1, 342, -1, 165, 796, -1, - 136, 325, -1, 115, 794, -1, 112, 794, -1, 283, - 794, -1, 57, -1, 518, 926, 519, -1, -1, 799, - -1, 800, -1, 799, -1, 800, -1, 56, 806, 518, - 873, 519, -1, 56, 806, -1, 803, -1, 804, -1, - 803, -1, 804, -1, 805, 518, 926, 519, -1, 805, - -1, 72, 806, -1, 71, 806, -1, 464, -1, 268, - 72, 806, -1, 268, 71, 806, -1, 270, 806, -1, - 467, -1, -1, 430, 518, 926, 519, 809, -1, 430, - 809, -1, 429, 518, 926, 519, 809, -1, 429, 809, + 167, 227, 392, -1, 285, 909, -1, -1, 279, -1, + 396, 244, -1, -1, 463, 518, 870, 519, -1, 751, + 522, 518, 870, 519, -1, 751, -1, 751, 522, -1, + 172, 755, -1, -1, 756, -1, 754, 522, 756, -1, + 754, -1, 754, 522, -1, 773, 768, 725, -1, 774, + 769, 725, -1, 752, 767, 725, -1, 232, 774, 769, + -1, 687, 768, 725, -1, 232, 687, 768, -1, 766, + -1, 518, 766, 519, 767, -1, 756, 315, 518, 901, + 167, 762, 757, 519, 768, -1, 756, 452, 758, 518, + 763, 167, 765, 519, 768, -1, 181, 59, 911, -1, + -1, 200, 282, -1, 148, 282, -1, -1, 823, 199, + 518, 901, 519, -1, 823, 199, 547, -1, 825, -1, + 827, -1, 518, 868, 519, -1, 760, 199, 518, 901, + 519, -1, 760, 199, 547, -1, 761, -1, 762, 761, + -1, 547, -1, 518, 911, 519, -1, 763, 199, 518, + 901, 519, -1, 764, -1, 765, 764, -1, 518, 766, + 519, -1, 756, 101, 225, 756, -1, 756, 770, 225, + 756, 772, -1, 756, 225, 756, 772, -1, 756, 269, + 770, 225, 756, -1, 756, 269, 225, 756, -1, 756, + 42, 770, 225, 756, 772, -1, 756, 42, 225, 756, + 772, -1, 756, 322, 225, 756, -1, 756, 37, 225, + 756, 772, -1, 756, 383, 225, 756, 772, -1, 40, + 547, 518, 911, 519, -1, 40, 547, -1, 546, 518, + 911, 519, -1, 546, -1, 767, -1, -1, 767, -1, + 40, 518, 780, 519, -1, 40, 547, 518, 780, 519, + -1, 546, 518, 780, 519, -1, -1, 173, 771, -1, + 235, 771, -1, 364, 771, -1, 383, -1, 37, -1, + 209, -1, 300, -1, -1, 457, 518, 911, 519, -1, + 290, 822, -1, 545, -1, 545, 511, -1, 291, 545, + -1, 291, 518, 545, 519, -1, 833, 778, -1, 369, + 172, 518, 776, 519, 778, -1, 833, 777, -1, 775, + -1, 776, 522, 775, -1, 40, 518, 780, 519, -1, + -1, 504, 297, -1, -1, 477, 822, -1, -1, 781, + -1, 780, 522, 781, -1, 547, 786, 782, -1, 80, + 920, -1, -1, 546, 786, -1, 783, 522, 546, 786, + -1, 368, -1, 412, -1, 786, -1, -1, 789, 788, + -1, 390, 789, 788, -1, 789, 39, 516, 916, 517, + -1, 390, 789, 39, 516, 916, 517, -1, 789, 39, + -1, 390, 789, 39, -1, 787, -1, 784, 518, 783, + 519, 788, -1, 247, 518, 874, 519, 788, -1, 447, + 518, 783, 519, 788, -1, 3, 520, 3, -1, 787, + 520, 3, -1, 788, 516, 517, -1, 788, 516, 916, + 517, -1, -1, 791, -1, 793, -1, 795, -1, 799, + -1, 805, -1, 806, 821, -1, 806, 518, 916, 519, + -1, 793, -1, 796, -1, 800, -1, 805, -1, 919, + 792, -1, 518, 871, 519, -1, -1, 216, -1, 217, + -1, 397, -1, 54, -1, 342, -1, 165, 794, -1, + 136, 325, -1, 115, 792, -1, 112, 792, -1, 283, + 792, -1, 57, -1, 518, 916, 519, -1, -1, 797, + -1, 798, -1, 797, -1, 798, -1, 56, 804, 518, + 870, 519, -1, 56, 804, -1, 801, -1, 802, -1, + 801, -1, 802, -1, 803, 518, 916, 519, -1, 803, + -1, 72, 804, -1, 71, 804, -1, 464, -1, 268, + 72, 804, -1, 268, 71, 804, -1, 270, 804, -1, + 467, -1, -1, 430, 518, 916, 519, 807, -1, 430, + 807, -1, 429, 518, 916, 519, 807, -1, 429, 807, -1, 219, -1, 504, 429, 501, -1, 482, 429, 501, -1, -1, 498, -1, 499, -1, 263, -1, 264, -1, 109, -1, 110, -1, 189, -1, 190, -1, 259, -1, 260, -1, 378, -1, 379, -1, 257, -1, 258, -1, 253, -1, 254, -1, 474, -1, 475, -1, 337, -1, 338, -1, 113, -1, 114, -1, 69, -1, 68, -1, - 256, -1, 255, -1, 810, -1, 811, -1, 812, -1, - 813, -1, 814, -1, 815, -1, 816, -1, 817, -1, - 818, -1, 819, -1, 820, -1, 821, -1, 822, -1, - 810, 431, 811, -1, 812, 431, 813, -1, 812, 431, - 814, -1, 812, 431, 815, -1, 813, 431, 814, -1, - 813, 431, 815, -1, 814, 431, 815, -1, -1, 826, - -1, 824, 11, 788, -1, 824, 80, 930, -1, 824, - 46, 429, 501, 824, -1, 509, 824, -1, 510, 824, - -1, 824, 509, 824, -1, 824, 510, 824, -1, 824, - 511, 824, -1, 824, 512, 824, -1, 824, 15, 824, - -1, 824, 513, 824, -1, 824, 514, 824, -1, 824, - 16, 824, -1, 824, 505, 824, -1, 824, 506, 824, - -1, 824, 507, 824, -1, 824, 19, 824, -1, 824, - 20, 824, -1, 824, 21, 824, -1, 824, 866, 824, - -1, 866, 824, -1, 824, 866, -1, 824, 36, 824, - -1, 824, 295, 824, -1, 275, 824, -1, 502, 824, - -1, 824, 177, 824, -1, 824, 237, 824, -1, 824, - 237, 824, 145, 824, -1, 824, 502, 237, 824, -1, - 824, 502, 237, 824, 145, 824, -1, 824, 194, 824, - -1, 824, 194, 824, 145, 824, -1, 824, 502, 194, - 824, -1, 824, 502, 194, 824, 145, 824, -1, 824, - 394, 431, 824, -1, 824, 394, 431, 824, 145, 824, - -1, 824, 502, 394, 431, 824, -1, 824, 502, 394, - 431, 824, 145, 824, -1, 824, 222, 280, -1, 824, - 223, -1, 824, 222, 275, 280, -1, 824, 275, 280, - -1, 824, 278, -1, 824, 17, 824, -1, 824, 18, - 824, -1, 855, 302, 855, -1, 824, 222, 438, -1, - 824, 222, 275, 438, -1, 824, 222, 160, -1, 824, - 222, 275, 160, -1, 824, 222, 449, -1, 824, 222, - 275, 449, -1, 824, 222, 132, 172, 824, -1, 824, - 222, 275, 132, 172, 824, -1, 824, 222, 285, 518, - 877, 519, -1, 824, 222, 275, 285, 518, 877, 519, - -1, 824, 53, 901, 825, 36, 824, -1, 824, 502, - 53, 901, 825, 36, 824, -1, 824, 53, 416, 825, - 36, 824, -1, 824, 502, 53, 416, 825, 36, 824, - -1, 824, 199, 887, -1, 824, 502, 199, 887, -1, - 824, 868, 863, 687, -1, 824, 868, 863, 518, 824, - 519, -1, 117, -1, 511, 83, 518, 824, 519, -1, - 83, 518, 824, 519, -1, 511, 910, 914, 918, -1, - 546, 520, 511, 910, 914, 918, -1, 826, -1, 825, - 11, 788, -1, 509, 825, -1, 510, 825, -1, 825, - 509, 825, -1, 825, 510, 825, -1, 825, 511, 825, - -1, 825, 512, 825, -1, 825, 15, 825, -1, 825, - 513, 825, -1, 825, 514, 825, -1, 825, 16, 825, - -1, 825, 505, 825, -1, 825, 506, 825, -1, 825, - 507, 825, -1, 825, 19, 825, -1, 825, 20, 825, - -1, 825, 21, 825, -1, 825, 866, 825, -1, 866, - 825, -1, 825, 866, -1, 825, 222, 132, 172, 825, - -1, 825, 222, 275, 132, 172, 825, -1, 825, 222, - 285, 518, 877, 519, -1, 825, 222, 275, 285, 518, - 877, 519, -1, 827, -1, 828, 900, -1, 895, -1, - 925, -1, 687, -1, 687, 549, -1, 152, 687, -1, - 742, 518, 873, 519, -1, 518, 824, 519, -1, 830, - -1, 855, -1, 524, -1, 10, -1, 525, 552, -1, - 829, -1, 832, -1, 833, -1, 835, -1, 888, -1, - 831, -1, 839, -1, 39, 687, -1, 39, 516, 874, - 517, -1, 526, 9, -1, 516, 874, 517, -1, 527, - 858, 528, -1, 247, 527, 862, 528, -1, 924, 518, - 519, -1, 924, 518, 711, 709, 519, -1, 924, 518, - 875, 710, 709, 519, -1, 924, 518, 466, 876, 710, - 709, 519, -1, 924, 518, 875, 522, 466, 876, 710, - 709, 519, -1, 924, 518, 30, 875, 710, 709, 519, - -1, 924, 518, 132, 875, 710, 709, 519, -1, 834, - 840, 841, 842, 846, -1, 837, -1, 834, -1, 837, - -1, 81, 167, 518, 824, 519, -1, 66, 518, 824, - 40, 788, 519, -1, 441, 518, 824, 40, 788, 519, - -1, 159, 518, 878, 519, -1, 303, 518, 880, 519, - -1, 321, 518, 882, 519, -1, 414, 518, 883, 519, - -1, 435, 518, 824, 40, 788, 519, -1, 437, 518, - 58, 886, 519, -1, 437, 518, 233, 886, 519, -1, - 437, 518, 432, 886, 519, -1, 437, 518, 886, 519, - -1, 281, 518, 824, 522, 824, 519, -1, 79, 518, - 873, 519, -1, 893, -1, 516, 824, 167, 838, 199, - 824, 517, -1, 516, 824, 167, 838, 199, 826, 192, - 824, 517, -1, 481, 181, 518, 711, 519, -1, -1, - 163, 518, 477, 824, 519, -1, 163, 518, 824, 519, - -1, -1, 155, -1, -1, 479, 844, -1, -1, 845, - -1, 844, 522, 845, -1, 546, 40, 847, -1, 301, - 847, -1, 301, 546, -1, -1, 518, 848, 849, 710, - 850, 519, -1, 546, -1, -1, 310, 59, 872, -1, - -1, 340, 851, 853, -1, 369, 851, 853, -1, 184, - 851, 853, -1, -1, 852, -1, 53, 852, 36, 852, + 256, -1, 255, -1, 808, -1, 809, -1, 810, -1, + 811, -1, 812, -1, 813, -1, 814, -1, 815, -1, + 816, -1, 817, -1, 818, -1, 819, -1, 820, -1, + 808, 431, 809, -1, 810, 431, 811, -1, 810, 431, + 812, -1, 810, 431, 813, -1, 811, 431, 812, -1, + 811, 431, 813, -1, 812, 431, 813, -1, -1, 824, + -1, 822, 11, 786, -1, 822, 80, 920, -1, 822, + 46, 429, 501, 822, -1, 509, 822, -1, 510, 822, + -1, 822, 509, 822, -1, 822, 510, 822, -1, 822, + 511, 822, -1, 822, 512, 822, -1, 822, 15, 822, + -1, 822, 513, 822, -1, 822, 514, 822, -1, 822, + 16, 822, -1, 822, 505, 822, -1, 822, 506, 822, + -1, 822, 507, 822, -1, 822, 19, 822, -1, 822, + 20, 822, -1, 822, 21, 822, -1, 822, 863, 822, + -1, 863, 822, -1, 822, 863, -1, 822, 36, 822, + -1, 822, 295, 822, -1, 275, 822, -1, 502, 822, + -1, 822, 177, 822, -1, 822, 237, 822, -1, 822, + 237, 822, 145, 822, -1, 822, 502, 237, 822, -1, + 822, 502, 237, 822, 145, 822, -1, 822, 194, 822, + -1, 822, 194, 822, 145, 822, -1, 822, 502, 194, + 822, -1, 822, 502, 194, 822, 145, 822, -1, 822, + 394, 431, 822, -1, 822, 394, 431, 822, 145, 822, + -1, 822, 502, 394, 431, 822, -1, 822, 502, 394, + 431, 822, 145, 822, -1, 822, 222, 280, -1, 822, + 223, -1, 822, 222, 275, 280, -1, 822, 275, 280, + -1, 822, 278, -1, 822, 17, 822, -1, 822, 18, + 822, -1, 852, 302, 852, -1, 822, 222, 438, -1, + 822, 222, 275, 438, -1, 822, 222, 160, -1, 822, + 222, 275, 160, -1, 822, 222, 449, -1, 822, 222, + 275, 449, -1, 822, 222, 132, 172, 822, -1, 822, + 222, 275, 132, 172, 822, -1, 822, 222, 285, 518, + 874, 519, -1, 822, 222, 275, 285, 518, 874, 519, + -1, 822, 53, 898, 823, 36, 822, -1, 822, 502, + 53, 898, 823, 36, 822, -1, 822, 53, 416, 823, + 36, 822, -1, 822, 502, 53, 416, 823, 36, 822, + -1, 822, 199, 884, -1, 822, 502, 199, 884, -1, + 822, 865, 860, 687, -1, 822, 865, 860, 518, 822, + 519, -1, 117, -1, 511, 83, 518, 822, 519, -1, + 83, 518, 822, 519, -1, 511, 904, 908, -1, 546, + 520, 511, 904, 908, -1, 824, -1, 823, 11, 786, + -1, 509, 823, -1, 510, 823, -1, 823, 509, 823, + -1, 823, 510, 823, -1, 823, 511, 823, -1, 823, + 512, 823, -1, 823, 15, 823, -1, 823, 513, 823, + -1, 823, 514, 823, -1, 823, 16, 823, -1, 823, + 505, 823, -1, 823, 506, 823, -1, 823, 507, 823, + -1, 823, 19, 823, -1, 823, 20, 823, -1, 823, + 21, 823, -1, 823, 863, 823, -1, 863, 823, -1, + 823, 863, -1, 823, 222, 132, 172, 823, -1, 823, + 222, 275, 132, 172, 823, -1, 823, 222, 285, 518, + 874, 519, -1, 823, 222, 275, 285, 518, 874, 519, + -1, 825, -1, 826, 897, -1, 892, -1, 915, -1, + 687, -1, 687, 549, -1, 152, 687, -1, 741, 518, + 870, 519, -1, 518, 822, 519, -1, 827, -1, 852, + -1, 523, -1, 10, -1, 829, -1, 830, -1, 832, + -1, 885, -1, 828, -1, 836, -1, 39, 687, -1, + 39, 516, 871, 517, -1, 524, 9, -1, 525, 552, + -1, 516, 871, 517, -1, 526, 855, 527, -1, 247, + 526, 859, 527, -1, 914, 518, 519, -1, 914, 518, + 872, 710, 709, 519, -1, 914, 518, 466, 873, 710, + 709, 519, -1, 914, 518, 872, 522, 466, 873, 710, + 709, 519, -1, 914, 518, 30, 872, 710, 709, 519, + -1, 914, 518, 132, 872, 710, 709, 519, -1, 831, + 837, 838, 839, 843, -1, 834, -1, 831, -1, 834, + -1, 81, 167, 518, 822, 519, -1, 66, 518, 822, + 40, 786, 519, -1, 441, 518, 822, 40, 786, 519, + -1, 159, 518, 875, 519, -1, 303, 518, 877, 519, + -1, 321, 518, 879, 519, -1, 414, 518, 880, 519, + -1, 435, 518, 822, 40, 786, 519, -1, 437, 518, + 58, 883, 519, -1, 437, 518, 233, 883, 519, -1, + 437, 518, 432, 883, 519, -1, 437, 518, 883, 519, + -1, 281, 518, 822, 522, 822, 519, -1, 79, 518, + 870, 519, -1, 890, -1, 516, 822, 167, 835, 199, + 822, 517, -1, 516, 822, 167, 835, 199, 824, 192, + 822, 517, -1, 481, 181, 518, 711, 519, -1, -1, + 163, 518, 477, 822, 519, -1, 163, 518, 822, 519, + -1, -1, 155, -1, -1, 479, 841, -1, -1, 842, + -1, 841, 522, 842, -1, 546, 40, 844, -1, 301, + 844, -1, 301, 546, -1, -1, 518, 845, 846, 710, + 847, 519, -1, 546, -1, -1, 310, 59, 869, -1, + -1, 340, 848, 850, -1, 369, 848, 850, -1, 184, + 848, 850, -1, -1, 849, -1, 53, 849, 36, 849, -1, 444, 324, -1, 444, 166, -1, 104, 368, -1, - 824, 324, -1, 824, 166, -1, 148, 104, 368, -1, + 822, 324, -1, 822, 166, -1, 148, 104, 368, -1, 148, 181, -1, 148, 428, -1, 148, 273, 298, -1, - -1, 368, 518, 873, 519, -1, 368, 518, 519, -1, - 854, -1, 518, 872, 522, 824, 519, -1, 547, 523, - 824, -1, 856, -1, 857, 522, 856, -1, 857, -1, - 857, 522, -1, 824, 523, 824, -1, 859, -1, 860, - 522, 859, -1, 860, -1, 860, 522, -1, 861, -1, - -1, 38, -1, 399, -1, 30, -1, 8, -1, 865, + -1, 368, 518, 870, 519, -1, 368, 518, 519, -1, + 851, -1, 518, 869, 522, 822, 519, -1, 547, 528, + 822, -1, 853, -1, 854, 522, 853, -1, 854, -1, + 854, 522, -1, 822, 528, 822, -1, 856, -1, 857, + 522, 856, -1, 857, -1, 857, 522, -1, 858, -1, + -1, 38, -1, 399, -1, 30, -1, 8, -1, 862, -1, 509, -1, 510, -1, 511, -1, 512, -1, 15, -1, 513, -1, 514, -1, 16, -1, 505, -1, 506, -1, 507, -1, 19, -1, 20, -1, 21, -1, 8, - -1, 292, 518, 869, 519, -1, 864, -1, 292, 518, - 869, 519, -1, 864, -1, 292, 518, 869, 519, -1, + -1, 292, 518, 866, 519, -1, 861, -1, 292, 518, + 866, 519, -1, 861, -1, 292, 518, 866, 519, -1, 237, -1, 502, 237, -1, 177, -1, 502, 177, -1, - 194, -1, 502, 194, -1, 864, -1, 546, 520, 869, - -1, 826, -1, 870, 522, 826, -1, 870, -1, 870, - 522, -1, 824, -1, 872, 522, 824, -1, 872, -1, - 872, 522, -1, 873, -1, -1, 876, -1, 875, 522, - 876, -1, 824, -1, 933, 13, 824, -1, 933, 14, - 824, -1, 788, -1, 877, 522, 788, -1, 879, 172, - 824, -1, -1, 3, -1, 810, -1, 811, -1, 812, - -1, 813, -1, 814, -1, 815, -1, 816, -1, 817, - -1, 818, -1, 819, -1, 820, -1, 821, -1, 822, - -1, 548, -1, 824, 881, 884, 885, -1, 824, 881, - 884, -1, 318, 824, -1, 825, 199, 825, -1, -1, - 824, 884, 885, -1, 824, 885, 884, -1, 824, 884, - -1, 824, 885, -1, 872, -1, -1, 172, 824, -1, - 167, 824, -1, 824, 172, 873, -1, 172, 873, -1, - 873, -1, 687, -1, 518, 873, 519, -1, 895, -1, - 830, -1, 65, 892, 889, 891, 143, -1, 890, -1, - 889, 890, -1, 476, 824, 427, 824, -1, 139, 824, - -1, -1, 824, -1, -1, 894, -1, 893, 522, 894, - -1, 546, -1, 546, -1, 546, 549, -1, 516, 824, - 517, -1, 516, 896, 523, 896, 517, -1, 516, 896, - 523, 896, 523, 896, 517, -1, 516, 896, 523, 510, - 523, 896, 517, -1, 824, -1, -1, -1, 897, 550, - -1, -1, 518, 519, -1, 518, 875, 519, -1, 520, - 551, 898, -1, 516, 824, 517, -1, 516, 896, 523, - 896, 517, -1, 516, 896, 523, 896, 523, 896, 517, - -1, 516, 896, 523, 510, 523, 896, 517, -1, -1, - 900, 899, -1, 45, -1, -1, 904, -1, -1, 905, - -1, 903, 522, 905, -1, 903, -1, 903, 522, -1, - 824, 40, 934, -1, 824, 3, -1, 824, -1, 546, - 523, 824, -1, 148, 518, 909, 519, -1, 148, 907, - -1, 547, -1, 907, 520, 547, -1, 907, -1, 908, - 522, 907, -1, 908, -1, 908, 522, -1, 906, -1, - -1, 824, 40, 546, -1, 911, -1, 912, 522, 911, - -1, 912, -1, 912, 522, -1, 355, 518, 913, 519, - -1, 355, 911, -1, -1, 907, 40, 546, -1, 915, - -1, 916, 522, 915, -1, 916, -1, 916, 522, -1, - 353, 518, 917, 519, -1, 353, 915, -1, -1, 545, - -1, 919, 522, 545, -1, 923, -1, 920, 522, 923, - -1, 920, -1, 920, 522, -1, 921, -1, 518, 921, - 519, -1, 547, -1, 928, -1, 546, 549, -1, 926, - -1, 4, -1, 548, 897, -1, 6, -1, 7, -1, - 924, 548, -1, 924, 518, 875, 710, 709, 519, 548, - -1, 792, 548, -1, 808, 518, 824, 519, 823, -1, - 808, 926, 823, -1, 808, 548, 823, -1, 438, -1, - 160, -1, 280, -1, 9, -1, 3, -1, 1005, -1, - 1010, -1, 3, -1, 1005, -1, 1007, -1, 3, -1, - 1005, -1, 1008, -1, 546, -1, 546, 931, -1, 520, - 551, -1, 931, 520, 551, -1, 518, 921, 519, -1, - -1, 927, -1, 552, -1, 5, -1, 326, 923, 936, - 40, 937, -1, 518, 877, 519, -1, -1, 686, -1, - 555, -1, 667, -1, 668, -1, 982, -1, 994, -1, - 100, 373, 545, 939, -1, 100, 373, 192, 275, 152, - 545, 939, -1, 100, 295, 355, 373, 545, 939, -1, - 939, 940, -1, -1, 604, -1, 941, -1, 580, -1, - 1000, -1, 100, 947, 203, 944, 945, 290, 545, 943, - 518, 574, 519, 946, 781, -1, 100, 947, 203, 944, - 192, 275, 152, 633, 290, 545, 943, 518, 574, 519, - 946, 781, -1, 546, -1, 457, 942, -1, -1, 89, - -1, -1, 633, -1, -1, 480, 619, -1, -1, 448, - -1, -1, 32, 419, 775, 389, 373, 923, -1, 32, - 419, 192, 152, 775, 389, 373, 923, -1, 32, 384, - 545, 389, 373, 923, -1, 32, 384, 192, 152, 545, - 389, 373, 923, -1, 32, 470, 545, 389, 373, 923, - -1, 32, 470, 192, 152, 545, 389, 373, 923, -1, - 168, 75, 950, -1, 75, 950, -1, 546, -1, -1, - 84, 290, 953, 545, 222, 952, -1, 84, 290, 82, - 824, 222, 952, -1, 548, -1, 280, -1, 419, -1, - 384, -1, 174, -1, 246, -1, 246, 419, -1, 470, - -1, 108, -1, 203, -1, 373, -1, 442, -1, 154, - 108, 548, 676, -1, 154, 108, 546, 431, 548, 676, - -1, 198, 108, 548, -1, 153, 959, -1, 153, 963, - 957, 959, -1, 153, 468, 959, -1, 153, 518, 962, - 519, 959, -1, 468, -1, -1, 964, -1, 594, -1, - -1, 948, -1, 591, -1, 533, -1, 999, -1, 949, - -1, 668, -1, 1002, -1, 658, -1, 938, -1, 580, - -1, 604, -1, 576, -1, 544, -1, 982, -1, 652, - -1, 587, -1, 941, -1, 555, -1, 973, -1, 579, - -1, 935, -1, 553, -1, 686, -1, 600, -1, 667, - -1, 586, -1, 977, -1, 991, -1, 967, -1, 994, - -1, 1000, -1, 3, -1, 1005, -1, 1009, -1, 960, - -1, 548, -1, 965, -1, 962, 522, 965, -1, 35, - -1, 34, -1, 438, -1, 160, -1, 290, -1, 961, - -1, 966, 958, -1, 960, -1, 963, -1, 389, 968, - -1, 389, 241, 968, -1, 389, 388, 968, -1, 389, - 178, 968, -1, 389, 465, 968, -1, 969, -1, 998, - 172, 104, -1, 429, 501, 971, -1, 373, 548, -1, - 998, 431, 972, -1, 998, 507, 972, -1, 824, -1, - 548, -1, 3, -1, 808, 548, 823, -1, 808, 518, - 926, 519, 548, -1, 594, -1, 117, -1, 241, -1, - 970, -1, 972, 522, 970, -1, 240, 975, -1, 974, - 214, 975, 976, -1, 974, 214, 975, 172, 546, 976, - -1, 974, 214, 975, 172, 548, 976, -1, -1, 168, - -1, 548, -1, 546, -1, -1, 469, 548, -1, 469, - 546, -1, 458, 979, 981, 957, -1, 458, 979, 981, - 957, 545, 932, -1, 458, 979, 981, 957, 986, -1, - 458, 518, 980, 519, -1, 458, 518, 980, 519, 545, - 932, -1, 963, -1, 468, -1, 171, -1, 173, -1, - 3, -1, 173, -1, -1, 978, -1, 980, 522, 978, - -1, 171, -1, -1, 560, 122, 172, 983, 985, 984, - 566, -1, 439, 704, 983, -1, 775, -1, 775, 546, - -1, 775, 40, 546, -1, 477, 824, -1, -1, 457, - 756, -1, -1, 963, 957, -1, 963, 957, 545, 932, - -1, 47, 989, 548, 990, 676, -1, 47, 192, 275, - 152, 989, 548, 990, 676, -1, 128, 552, -1, 128, - 108, 552, -1, 128, 108, 192, 152, 552, -1, 108, - -1, -1, 40, 546, -1, -1, 357, 993, -1, 357, - 241, 993, -1, 357, 388, 993, -1, 357, 178, 993, - -1, 357, 465, 993, -1, 998, -1, 30, -1, 992, - -1, 429, 501, -1, 433, 224, 236, -1, 996, 686, - -1, 415, 686, -1, 415, 545, -1, 996, 545, -1, - 996, 429, 501, -1, 996, 433, 224, 236, -1, 996, - 30, 997, -1, 996, -1, 127, -1, 126, -1, 393, - -1, 995, -1, 420, -1, -1, 546, -1, 998, 520, - 546, -1, 61, 834, -1, 100, 650, 470, 545, 639, - 946, 40, 686, 1001, -1, 100, 650, 470, 192, 275, - 152, 545, 639, 946, 40, 686, 1001, -1, 100, 295, - 355, 650, 470, 545, 639, 946, 40, 686, 1001, -1, - 100, 650, 345, 470, 545, 518, 643, 519, 946, 40, - 686, 1001, -1, 100, 295, 355, 650, 345, 470, 545, - 518, 643, 519, 946, 40, 686, 1001, -1, 480, 74, - 293, -1, 480, 64, 74, 293, -1, 480, 241, 74, - 293, -1, -1, 100, 650, 419, 1004, 40, 686, 1003, - -1, 100, 650, 419, 192, 275, 152, 1004, 40, 686, - 1003, -1, 100, 295, 355, 650, 419, 1004, 40, 686, - 1003, -1, 480, 107, -1, 480, 273, 107, -1, -1, - 545, 639, 626, 618, -1, 22, -1, 23, -1, 24, - -1, 25, -1, 26, -1, 27, -1, 28, -1, 29, - -1, 31, -1, 32, -1, 33, -1, 43, -1, 44, - -1, 46, -1, 47, -1, 48, -1, 50, -1, 51, - -1, 52, -1, 59, -1, 60, -1, 61, -1, 62, - -1, 63, -1, 64, -1, 67, -1, 68, -1, 69, - -1, 70, -1, 73, -1, 75, -1, 76, -1, 77, - -1, 78, -1, 84, -1, 85, -1, 86, -1, 87, - -1, 88, -1, 90, -1, 91, -1, 92, -1, 94, - -1, 95, -1, 96, -1, 97, -1, 98, -1, 99, - -1, 102, -1, 103, -1, 104, -1, 105, -1, 106, - -1, 107, -1, 108, -1, 109, -1, 110, -1, 111, - -1, 113, -1, 114, -1, 116, -1, 118, -1, 120, - -1, 121, -1, 122, -1, 123, -1, 124, -1, 125, - -1, 128, -1, 129, -1, 130, -1, 131, -1, 134, - -1, 135, -1, 136, -1, 137, -1, 138, -1, 140, - -1, 141, -1, 142, -1, 144, -1, 145, -1, 146, - -1, 148, -1, 149, -1, 150, -1, 151, -1, 153, - -1, 154, -1, 155, -1, 156, -1, 157, -1, 158, - -1, 161, -1, 163, -1, 164, -1, 166, -1, 168, - -1, 170, -1, 174, -1, 175, -1, 178, -1, 180, - -1, 184, -1, 185, -1, 187, -1, 188, -1, 189, - -1, 190, -1, 191, -1, 192, -1, 193, -1, 195, - -1, 196, -1, 197, -1, 198, -1, 200, -1, 201, - -1, 202, -1, 203, -1, 204, -1, 205, -1, 206, - -1, 208, -1, 211, -1, 212, -1, 213, -1, 214, - -1, 215, -1, 221, -1, 224, -1, 226, -1, 227, - -1, 228, -1, 229, -1, 230, -1, 231, -1, 234, - -1, 236, -1, 239, -1, 240, -1, 241, -1, 242, - -1, 243, -1, 244, -1, 245, -1, 246, -1, 248, - -1, 249, -1, 250, -1, 251, -1, 252, -1, 253, - -1, 254, -1, 255, -1, 256, -1, 257, -1, 258, - -1, 259, -1, 260, -1, 261, -1, 262, -1, 263, - -1, 264, -1, 265, -1, 266, -1, 267, -1, 271, - -1, 272, -1, 273, -1, 276, -1, 277, -1, 279, - -1, 282, -1, 284, -1, 285, -1, 286, -1, 288, - -1, 289, -1, 292, -1, 293, -1, 294, -1, 297, - -1, 298, -1, 301, -1, 304, -1, 305, -1, 306, - -1, 307, -1, 308, -1, 309, -1, 310, -1, 311, - -1, 312, -1, 313, -1, 314, -1, 319, -1, 320, - -1, 323, -1, 324, -1, 326, -1, 327, -1, 328, - -1, 330, -1, 331, -1, 332, -1, 333, -1, 334, - -1, 335, -1, 337, -1, 338, -1, 339, -1, 340, - -1, 341, -1, 343, -1, 344, -1, 345, -1, 346, - -1, 348, -1, 349, -1, 350, -1, 351, -1, 352, - -1, 353, -1, 354, -1, 355, -1, 356, -1, 357, - -1, 358, -1, 359, -1, 360, -1, 362, -1, 363, - -1, 365, -1, 366, -1, 367, -1, 369, -1, 370, - -1, 371, -1, 372, -1, 373, -1, 374, -1, 375, - -1, 376, -1, 377, -1, 378, -1, 379, -1, 380, - -1, 381, -1, 384, -1, 385, -1, 386, -1, 387, - -1, 388, -1, 389, -1, 391, -1, 392, -1, 395, - -1, 396, -1, 398, -1, 400, -1, 401, -1, 402, - -1, 403, -1, 404, -1, 405, -1, 406, -1, 407, - -1, 408, -1, 409, -1, 410, -1, 411, -1, 413, - -1, 417, -1, 418, -1, 420, -1, 422, -1, 423, - -1, 424, -1, 425, -1, 426, -1, 428, -1, 433, - -1, 434, -1, 436, -1, 439, -1, 440, -1, 442, - -1, 443, -1, 444, -1, 445, -1, 446, -1, 449, - -1, 450, -1, 451, -1, 453, -1, 454, -1, 455, - -1, 456, -1, 458, -1, 459, -1, 460, -1, 461, - -1, 462, -1, 465, -1, 467, -1, 469, -1, 470, - -1, 471, -1, 472, -1, 473, -1, 474, -1, 475, - -1, 478, -1, 481, -1, 482, -1, 483, -1, 484, - -1, 485, -1, 486, -1, 498, -1, 499, -1, 500, - -1, 501, -1, 53, -1, 54, -1, 56, -1, 57, - -1, 71, -1, 72, -1, 79, -1, 83, -1, 112, - -1, 115, -1, 152, -1, 159, -1, 165, -1, 176, - -1, 182, -1, 183, -1, 210, -1, 216, -1, 217, - -1, 219, -1, 247, -1, 268, -1, 270, -1, 274, - -1, 281, -1, 283, -1, 299, -1, 303, -1, 321, - -1, 325, -1, 342, -1, 368, -1, 390, -1, 397, - -1, 412, -1, 414, -1, 429, -1, 430, -1, 435, - -1, 437, -1, 441, -1, 463, -1, 464, -1, 487, - -1, 488, -1, 489, -1, 490, -1, 491, -1, 492, - -1, 493, -1, 494, -1, 495, -1, 496, -1, 497, - -1, 42, -1, 49, -1, 55, -1, 81, -1, 89, - -1, 101, -1, 171, -1, 173, -1, 176, -1, 177, - -1, 194, -1, 209, -1, 222, -1, 223, -1, 225, - -1, 235, -1, 237, -1, 247, -1, 269, -1, 278, - -1, 300, -1, 302, -1, 322, -1, 364, -1, 394, - -1, 412, -1, 421, -1, 468, -1, 37, -1, 42, - -1, 49, -1, 55, -1, 81, -1, 83, -1, 89, - -1, 101, -1, 171, -1, 173, -1, 177, -1, 194, - -1, 209, -1, 222, -1, 223, -1, 225, -1, 235, - -1, 237, -1, 269, -1, 278, -1, 300, -1, 302, - -1, 322, -1, 364, -1, 383, -1, 394, -1, 421, - -1, 441, -1, 468, -1, 37, -1, 42, -1, 49, - -1, 53, -1, 54, -1, 55, -1, 56, -1, 57, - -1, 72, -1, 71, -1, 79, -1, 81, -1, 83, - -1, 89, -1, 101, -1, 112, -1, 115, -1, 152, - -1, 159, -1, 165, -1, 171, -1, 173, -1, 176, - -1, 177, -1, 182, -1, 183, -1, 194, -1, 209, - -1, 210, -1, 217, -1, 219, -1, 216, -1, 222, - -1, 223, -1, 225, -1, 235, -1, 237, -1, 247, - -1, 268, -1, 269, -1, 270, -1, 274, -1, 278, - -1, 281, -1, 283, -1, 300, -1, 299, -1, 302, - -1, 303, -1, 321, -1, 322, -1, 325, -1, 342, - -1, 364, -1, 368, -1, 383, -1, 390, -1, 394, - -1, 397, -1, 412, -1, 414, -1, 421, -1, 429, - -1, 430, -1, 435, -1, 437, -1, 441, -1, 463, - -1, 464, -1, 468, -1, 487, -1, 488, -1, 489, - -1, 490, -1, 491, -1, 492, -1, 493, -1, 494, - -1, 495, -1, 496, -1, 497, -1, 37, -1, 42, - -1, 49, -1, 55, -1, 81, -1, 83, -1, 89, - -1, 101, -1, 171, -1, 173, -1, 176, -1, 177, - -1, 194, -1, 209, -1, 222, -1, 223, -1, 225, - -1, 235, -1, 237, -1, 247, -1, 269, -1, 278, - -1, 300, -1, 302, -1, 322, -1, 364, -1, 383, - -1, 394, -1, 412, -1, 421, -1, 441, -1, 468, - -1, 30, -1, 34, -1, 35, -1, 36, -1, 38, - -1, 39, -1, 40, -1, 41, -1, 45, -1, 58, - -1, 65, -1, 66, -1, 74, -1, 80, -1, 82, - -1, 93, -1, 100, -1, 117, -1, 119, -1, 126, - -1, 127, -1, 132, -1, 133, -1, 139, -1, 143, - -1, 147, -1, 160, -1, 162, -1, 167, -1, 169, - -1, 172, -1, 179, -1, 181, -1, 186, -1, 199, - -1, 207, -1, 218, -1, 220, -1, 232, -1, 233, - -1, 238, -1, 275, -1, 280, -1, 287, -1, 290, - -1, 291, -1, 295, -1, 296, -1, 315, -1, 316, - -1, 317, -1, 318, -1, 329, -1, 336, -1, 347, - -1, 361, -1, 382, -1, 393, -1, 399, -1, 415, - -1, 416, -1, 419, -1, 427, -1, 431, -1, 432, - -1, 438, -1, 447, -1, 448, -1, 452, -1, 457, - -1, 466, -1, 476, -1, 477, -1, 479, -1, 480, - -1 + 194, -1, 502, 194, -1, 861, -1, 546, 520, 866, + -1, 824, -1, 867, 522, 824, -1, 867, -1, 867, + 522, -1, 822, -1, 869, 522, 822, -1, 869, -1, + 869, 522, -1, 870, -1, -1, 873, -1, 872, 522, + 873, -1, 822, -1, 923, 13, 822, -1, 923, 14, + 822, -1, 786, -1, 874, 522, 786, -1, 876, 172, + 822, -1, -1, 3, -1, 808, -1, 809, -1, 810, + -1, 811, -1, 812, -1, 813, -1, 814, -1, 815, + -1, 816, -1, 817, -1, 818, -1, 819, -1, 820, + -1, 548, -1, 822, 878, 881, 882, -1, 822, 878, + 881, -1, 318, 822, -1, 823, 199, 823, -1, -1, + 822, 881, 882, -1, 822, 882, 881, -1, 822, 881, + -1, 822, 882, -1, 869, -1, -1, 172, 822, -1, + 167, 822, -1, 822, 172, 870, -1, 172, 870, -1, + 870, -1, 687, -1, 518, 870, 519, -1, 892, -1, + 827, -1, 65, 889, 886, 888, 143, -1, 887, -1, + 886, 887, -1, 476, 822, 427, 822, -1, 139, 822, + -1, -1, 822, -1, -1, 891, -1, 890, 522, 891, + -1, 546, -1, 546, -1, 546, 549, -1, 516, 822, + 517, -1, 516, 893, 528, 893, 517, -1, 516, 893, + 528, 893, 528, 893, 517, -1, 516, 893, 528, 510, + 528, 893, 517, -1, 822, -1, -1, -1, 894, 550, + -1, -1, 518, 519, -1, 518, 872, 519, -1, 520, + 551, 895, -1, 516, 822, 517, -1, 516, 893, 528, + 893, 517, -1, 516, 893, 528, 893, 528, 893, 517, + -1, 516, 893, 528, 510, 528, 893, 517, -1, -1, + 897, 896, -1, 45, -1, -1, 901, -1, -1, 902, + -1, 900, 522, 902, -1, 900, -1, 900, 522, -1, + 822, 40, 924, -1, 822, 3, -1, 822, -1, 148, + 518, 911, 519, -1, 148, 546, -1, 903, -1, -1, + 822, 40, 546, -1, 905, -1, 906, 522, 905, -1, + 906, -1, 906, 522, -1, 355, 518, 907, 519, -1, + 355, 905, -1, -1, 545, -1, 909, 522, 545, -1, + 913, -1, 910, 522, 913, -1, 910, -1, 910, 522, + -1, 911, -1, 518, 911, 519, -1, 547, -1, 918, + -1, 546, 549, -1, 916, -1, 4, -1, 548, 894, + -1, 6, -1, 7, -1, 914, 548, -1, 914, 518, + 872, 710, 709, 519, 548, -1, 790, 548, -1, 806, + 518, 822, 519, 821, -1, 806, 916, 821, -1, 806, + 548, 821, -1, 438, -1, 160, -1, 280, -1, 9, + -1, 3, -1, 996, -1, 1001, -1, 3, -1, 996, + -1, 998, -1, 3, -1, 996, -1, 999, -1, 546, + -1, 546, 921, -1, 520, 551, -1, 921, 520, 551, + -1, 518, 911, 519, -1, -1, 917, -1, 552, -1, + 5, -1, 326, 913, 926, 40, 927, -1, 518, 874, + 519, -1, -1, 686, -1, 555, -1, 667, -1, 668, + -1, 972, -1, 984, -1, 100, 373, 545, 929, -1, + 100, 373, 192, 275, 152, 545, 929, -1, 100, 295, + 355, 373, 545, 929, -1, 929, 930, -1, -1, 604, + -1, 931, -1, 580, -1, 991, -1, 100, 937, 203, + 934, 935, 290, 545, 933, 518, 574, 519, 936, 779, + -1, 100, 937, 203, 934, 192, 275, 152, 633, 290, + 545, 933, 518, 574, 519, 936, 779, -1, 546, -1, + 457, 932, -1, -1, 89, -1, -1, 633, -1, -1, + 480, 619, -1, -1, 448, -1, -1, 32, 419, 773, + 389, 373, 913, -1, 32, 419, 192, 152, 773, 389, + 373, 913, -1, 32, 384, 545, 389, 373, 913, -1, + 32, 384, 192, 152, 545, 389, 373, 913, -1, 32, + 470, 545, 389, 373, 913, -1, 32, 470, 192, 152, + 545, 389, 373, 913, -1, 168, 75, 940, -1, 75, + 940, -1, 546, -1, -1, 84, 290, 943, 545, 222, + 942, -1, 84, 290, 82, 822, 222, 942, -1, 548, + -1, 280, -1, 419, -1, 384, -1, 174, -1, 246, + -1, 246, 419, -1, 470, -1, 108, -1, 203, -1, + 373, -1, 442, -1, 154, 108, 548, 676, -1, 154, + 108, 546, 431, 548, 676, -1, 198, 108, 548, -1, + 153, 949, -1, 153, 953, 947, 949, -1, 153, 468, + 949, -1, 153, 518, 952, 519, 949, -1, 468, -1, + -1, 954, -1, 594, -1, -1, 938, -1, 591, -1, + 533, -1, 990, -1, 939, -1, 668, -1, 993, -1, + 658, -1, 928, -1, 580, -1, 604, -1, 576, -1, + 544, -1, 972, -1, 652, -1, 587, -1, 931, -1, + 555, -1, 963, -1, 579, -1, 925, -1, 553, -1, + 686, -1, 600, -1, 667, -1, 586, -1, 967, -1, + 981, -1, 957, -1, 984, -1, 991, -1, 3, -1, + 996, -1, 1000, -1, 950, -1, 548, -1, 955, -1, + 952, 522, 955, -1, 35, -1, 34, -1, 438, -1, + 160, -1, 290, -1, 951, -1, 956, 948, -1, 950, + -1, 953, -1, 389, 958, -1, 389, 241, 958, -1, + 389, 388, 958, -1, 389, 178, 958, -1, 389, 465, + 958, -1, 959, -1, 988, 172, 104, -1, 429, 501, + 961, -1, 373, 548, -1, 988, 431, 962, -1, 988, + 507, 962, -1, 822, -1, 548, -1, 3, -1, 806, + 548, 821, -1, 806, 518, 916, 519, 548, -1, 594, + -1, 117, -1, 241, -1, 960, -1, 962, 522, 960, + -1, 240, 965, -1, 964, 214, 965, 966, -1, 964, + 214, 965, 172, 546, 966, -1, 964, 214, 965, 172, + 548, 966, -1, -1, 168, -1, 548, -1, 546, -1, + -1, 469, 548, -1, 469, 546, -1, 458, 969, 971, + 947, -1, 458, 969, 971, 947, 545, 922, -1, 458, + 969, 971, 947, 976, -1, 458, 518, 970, 519, -1, + 458, 518, 970, 519, 545, 922, -1, 953, -1, 468, + -1, 171, -1, 173, -1, 3, -1, 173, -1, -1, + 968, -1, 970, 522, 968, -1, 171, -1, -1, 560, + 122, 172, 973, 975, 974, 566, -1, 439, 704, 973, + -1, 773, -1, 773, 546, -1, 773, 40, 546, -1, + 477, 822, -1, -1, 457, 755, -1, -1, 953, 947, + -1, 953, 947, 545, 922, -1, 47, 979, 548, 980, + 676, -1, 47, 192, 275, 152, 979, 548, 980, 676, + -1, 128, 552, -1, 128, 108, 552, -1, 128, 108, + 192, 152, 552, -1, 108, -1, -1, 40, 546, -1, + -1, 357, 983, -1, 357, 241, 983, -1, 357, 388, + 983, -1, 357, 178, 983, -1, 357, 465, 983, -1, + 988, -1, 30, -1, 982, -1, 429, 501, -1, 433, + 224, 236, -1, 986, 686, -1, 415, 686, -1, 415, + 989, -1, 986, 989, -1, 986, 429, 501, -1, 986, + 433, 224, 236, -1, 986, 30, 987, -1, 986, -1, + 127, -1, 126, -1, 393, -1, 985, -1, 420, -1, + -1, 546, -1, 988, 520, 546, -1, 546, -1, 989, + 520, 546, -1, 61, 831, -1, 100, 650, 470, 545, + 639, 936, 40, 686, 992, -1, 100, 650, 470, 192, + 275, 152, 545, 639, 936, 40, 686, 992, -1, 100, + 295, 355, 650, 470, 545, 639, 936, 40, 686, 992, + -1, 100, 650, 345, 470, 545, 518, 643, 519, 936, + 40, 686, 992, -1, 100, 295, 355, 650, 345, 470, + 545, 518, 643, 519, 936, 40, 686, 992, -1, 480, + 74, 293, -1, 480, 64, 74, 293, -1, 480, 241, + 74, 293, -1, -1, 100, 650, 419, 995, 40, 686, + 994, -1, 100, 650, 419, 192, 275, 152, 995, 40, + 686, 994, -1, 100, 295, 355, 650, 419, 995, 40, + 686, 994, -1, 480, 107, -1, 480, 273, 107, -1, + -1, 545, 639, 626, 618, -1, 22, -1, 23, -1, + 24, -1, 25, -1, 26, -1, 27, -1, 28, -1, + 29, -1, 31, -1, 32, -1, 33, -1, 43, -1, + 44, -1, 46, -1, 47, -1, 48, -1, 50, -1, + 51, -1, 52, -1, 59, -1, 60, -1, 61, -1, + 62, -1, 63, -1, 64, -1, 67, -1, 68, -1, + 69, -1, 70, -1, 73, -1, 75, -1, 76, -1, + 77, -1, 78, -1, 84, -1, 85, -1, 86, -1, + 87, -1, 88, -1, 90, -1, 91, -1, 92, -1, + 94, -1, 95, -1, 96, -1, 97, -1, 98, -1, + 99, -1, 102, -1, 103, -1, 104, -1, 105, -1, + 106, -1, 107, -1, 108, -1, 109, -1, 110, -1, + 111, -1, 113, -1, 114, -1, 116, -1, 118, -1, + 120, -1, 121, -1, 122, -1, 123, -1, 124, -1, + 125, -1, 128, -1, 129, -1, 130, -1, 131, -1, + 134, -1, 135, -1, 136, -1, 137, -1, 138, -1, + 140, -1, 141, -1, 142, -1, 144, -1, 145, -1, + 146, -1, 148, -1, 149, -1, 150, -1, 151, -1, + 153, -1, 154, -1, 155, -1, 156, -1, 157, -1, + 158, -1, 161, -1, 163, -1, 164, -1, 166, -1, + 168, -1, 170, -1, 174, -1, 175, -1, 178, -1, + 180, -1, 184, -1, 185, -1, 187, -1, 188, -1, + 189, -1, 190, -1, 191, -1, 192, -1, 193, -1, + 195, -1, 196, -1, 197, -1, 198, -1, 200, -1, + 201, -1, 202, -1, 203, -1, 204, -1, 205, -1, + 206, -1, 208, -1, 211, -1, 212, -1, 213, -1, + 214, -1, 215, -1, 221, -1, 224, -1, 226, -1, + 227, -1, 228, -1, 229, -1, 230, -1, 231, -1, + 234, -1, 236, -1, 239, -1, 240, -1, 241, -1, + 242, -1, 243, -1, 244, -1, 245, -1, 246, -1, + 248, -1, 249, -1, 250, -1, 251, -1, 252, -1, + 253, -1, 254, -1, 255, -1, 256, -1, 257, -1, + 258, -1, 259, -1, 260, -1, 261, -1, 262, -1, + 263, -1, 264, -1, 265, -1, 266, -1, 267, -1, + 271, -1, 272, -1, 273, -1, 276, -1, 277, -1, + 279, -1, 282, -1, 284, -1, 285, -1, 286, -1, + 288, -1, 289, -1, 292, -1, 293, -1, 294, -1, + 297, -1, 298, -1, 301, -1, 304, -1, 305, -1, + 306, -1, 307, -1, 308, -1, 309, -1, 310, -1, + 311, -1, 312, -1, 313, -1, 314, -1, 319, -1, + 320, -1, 323, -1, 324, -1, 326, -1, 327, -1, + 328, -1, 330, -1, 331, -1, 332, -1, 333, -1, + 334, -1, 335, -1, 337, -1, 338, -1, 339, -1, + 340, -1, 341, -1, 343, -1, 344, -1, 345, -1, + 346, -1, 348, -1, 349, -1, 350, -1, 351, -1, + 352, -1, 353, -1, 354, -1, 355, -1, 356, -1, + 357, -1, 358, -1, 359, -1, 360, -1, 362, -1, + 363, -1, 365, -1, 366, -1, 367, -1, 369, -1, + 370, -1, 371, -1, 372, -1, 373, -1, 374, -1, + 375, -1, 376, -1, 377, -1, 378, -1, 379, -1, + 380, -1, 381, -1, 384, -1, 385, -1, 386, -1, + 387, -1, 388, -1, 389, -1, 391, -1, 392, -1, + 395, -1, 396, -1, 398, -1, 400, -1, 401, -1, + 402, -1, 403, -1, 404, -1, 405, -1, 406, -1, + 407, -1, 408, -1, 409, -1, 410, -1, 411, -1, + 413, -1, 417, -1, 418, -1, 420, -1, 422, -1, + 423, -1, 424, -1, 425, -1, 426, -1, 428, -1, + 433, -1, 434, -1, 436, -1, 439, -1, 440, -1, + 442, -1, 443, -1, 444, -1, 445, -1, 446, -1, + 449, -1, 450, -1, 451, -1, 453, -1, 454, -1, + 455, -1, 456, -1, 458, -1, 459, -1, 460, -1, + 461, -1, 462, -1, 465, -1, 467, -1, 469, -1, + 470, -1, 471, -1, 472, -1, 473, -1, 474, -1, + 475, -1, 478, -1, 481, -1, 482, -1, 483, -1, + 484, -1, 485, -1, 486, -1, 498, -1, 499, -1, + 500, -1, 501, -1, 53, -1, 54, -1, 56, -1, + 57, -1, 71, -1, 72, -1, 79, -1, 83, -1, + 112, -1, 115, -1, 152, -1, 159, -1, 165, -1, + 176, -1, 182, -1, 183, -1, 210, -1, 216, -1, + 217, -1, 219, -1, 247, -1, 268, -1, 270, -1, + 274, -1, 281, -1, 283, -1, 299, -1, 303, -1, + 321, -1, 325, -1, 342, -1, 368, -1, 390, -1, + 397, -1, 412, -1, 414, -1, 429, -1, 430, -1, + 435, -1, 437, -1, 441, -1, 463, -1, 464, -1, + 487, -1, 488, -1, 489, -1, 490, -1, 491, -1, + 492, -1, 493, -1, 494, -1, 495, -1, 496, -1, + 497, -1, 42, -1, 49, -1, 55, -1, 81, -1, + 89, -1, 101, -1, 171, -1, 173, -1, 176, -1, + 177, -1, 194, -1, 209, -1, 222, -1, 223, -1, + 225, -1, 235, -1, 237, -1, 247, -1, 269, -1, + 278, -1, 300, -1, 302, -1, 322, -1, 364, -1, + 394, -1, 412, -1, 421, -1, 468, -1, 37, -1, + 42, -1, 49, -1, 55, -1, 81, -1, 83, -1, + 89, -1, 101, -1, 171, -1, 173, -1, 177, -1, + 194, -1, 209, -1, 222, -1, 223, -1, 225, -1, + 235, -1, 237, -1, 269, -1, 278, -1, 300, -1, + 302, -1, 322, -1, 364, -1, 383, -1, 394, -1, + 421, -1, 441, -1, 468, -1, 37, -1, 42, -1, + 49, -1, 53, -1, 54, -1, 55, -1, 56, -1, + 57, -1, 72, -1, 71, -1, 79, -1, 81, -1, + 83, -1, 89, -1, 101, -1, 112, -1, 115, -1, + 152, -1, 159, -1, 165, -1, 171, -1, 173, -1, + 176, -1, 177, -1, 182, -1, 183, -1, 194, -1, + 209, -1, 210, -1, 217, -1, 219, -1, 216, -1, + 222, -1, 223, -1, 225, -1, 235, -1, 237, -1, + 247, -1, 268, -1, 269, -1, 270, -1, 274, -1, + 278, -1, 281, -1, 283, -1, 300, -1, 299, -1, + 302, -1, 303, -1, 321, -1, 322, -1, 325, -1, + 342, -1, 364, -1, 368, -1, 383, -1, 390, -1, + 394, -1, 397, -1, 412, -1, 414, -1, 421, -1, + 429, -1, 430, -1, 435, -1, 437, -1, 441, -1, + 463, -1, 464, -1, 468, -1, 487, -1, 488, -1, + 489, -1, 490, -1, 491, -1, 492, -1, 493, -1, + 494, -1, 495, -1, 496, -1, 497, -1, 37, -1, + 42, -1, 49, -1, 55, -1, 81, -1, 83, -1, + 89, -1, 101, -1, 171, -1, 173, -1, 176, -1, + 177, -1, 194, -1, 209, -1, 222, -1, 223, -1, + 225, -1, 235, -1, 237, -1, 247, -1, 269, -1, + 278, -1, 300, -1, 302, -1, 322, -1, 364, -1, + 383, -1, 394, -1, 412, -1, 421, -1, 441, -1, + 468, -1, 30, -1, 34, -1, 35, -1, 36, -1, + 38, -1, 39, -1, 40, -1, 41, -1, 45, -1, + 58, -1, 65, -1, 66, -1, 74, -1, 80, -1, + 82, -1, 93, -1, 100, -1, 117, -1, 119, -1, + 126, -1, 127, -1, 132, -1, 133, -1, 139, -1, + 143, -1, 147, -1, 160, -1, 162, -1, 167, -1, + 169, -1, 172, -1, 179, -1, 181, -1, 186, -1, + 199, -1, 207, -1, 218, -1, 220, -1, 232, -1, + 233, -1, 238, -1, 275, -1, 280, -1, 287, -1, + 290, -1, 291, -1, 295, -1, 296, -1, 315, -1, + 316, -1, 317, -1, 318, -1, 329, -1, 336, -1, + 347, -1, 361, -1, 382, -1, 393, -1, 399, -1, + 415, -1, 416, -1, 419, -1, 427, -1, 431, -1, + 432, -1, 438, -1, 447, -1, 448, -1, 452, -1, + 457, -1, 466, -1, 476, -1, 477, -1, 479, -1, + 480, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 509, 509, 525, 537, 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, 588, 9, 18, 27, + 0, 508, 508, 524, 536, 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, 587, 9, 18, 27, 36, 45, 54, 63, 72, 85, 87, 93, 94, 99, 103, 107, 118, 126, 130, 139, 148, 157, 166, 175, 184, 192, 200, 209, 218, 227, 236, 253, 262, 271, @@ -2676,99 +2667,97 @@ static const yytype_uint16 yyrline[] = 563, 570, 571, 575, 576, 580, 581, 582, 586, 587, 591, 592, 608, 609, 612, 621, 632, 633, 634, 637, 638, 639, 643, 644, 645, 646, 650, 651, 655, 657, - 673, 675, 680, 683, 688, 692, 696, 703, 707, 711, - 715, 722, 727, 734, 735, 739, 744, 748, 752, 760, - 767, 768, 773, 774, 778, 779, 784, 786, 788, 793, - 813, 814, 816, 821, 822, 826, 827, 830, 831, 856, - 857, 862, 866, 867, 871, 872, 876, 877, 878, 879, - 880, 884, 897, 904, 911, 918, 919, 923, 924, 928, - 929, 933, 934, 938, 939, 943, 944, 948, 959, 960, - 961, 962, 966, 967, 972, 973, 974, 983, 989, 998, - 999, 1012, 1013, 1017, 1018, 1022, 1023, 1027, 1038, 1044, - 1050, 1058, 1066, 1076, 1084, 1093, 1102, 1111, 1115, 1120, - 1125, 1136, 1150, 1151, 1154, 1155, 1156, 1159, 1167, 1177, - 1178, 1179, 1182, 1190, 1199, 1203, 1210, 1211, 1215, 1224, - 1228, 1253, 1257, 1270, 1284, 1299, 1311, 1324, 1338, 1352, - 1365, 1380, 1399, 1405, 1410, 1416, 1423, 1424, 1432, 1436, - 1440, 1446, 1453, 1458, 1459, 1460, 1461, 1462, 1463, 1467, - 1468, 1480, 1481, 1486, 1493, 1500, 1507, 1539, 1550, 1563, - 1568, 1569, 1572, 1573, 1576, 1577, 1582, 1583, 1588, 1592, - 1598, 1619, 1627, 1641, 1644, 1648, 1648, 1651, 1652, 1654, - 1659, 1666, 1671, 1677, 1682, 1688, 1692, 1699, 1706, 1716, - 1717, 1721, 1723, 1726, 1730, 1731, 1732, 1733, 1734, 1735, - 1740, 1760, 1761, 1762, 1763, 1774, 1788, 1789, 1795, 1800, - 1805, 1810, 1815, 1820, 1825, 1830, 1836, 1842, 1848, 1855, - 1877, 1886, 1890, 1898, 1902, 1910, 1922, 1943, 1947, 1953, - 1957, 1970, 1978, 1988, 1990, 1992, 1994, 1996, 1998, 2003, - 2004, 2011, 2020, 2028, 2037, 2048, 2056, 2057, 2058, 2062, - 2062, 2065, 2065, 2068, 2068, 2071, 2071, 2074, 2074, 2077, - 2077, 2080, 2080, 2083, 2083, 2086, 2086, 2089, 2089, 2092, - 2092, 2095, 2095, 2098, 2098, 2101, 2103, 2105, 2107, 2109, - 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2132, - 2137, 2143, 2150, 2155, 2161, 2167, 2198, 2200, 2202, 2210, - 2225, 2227, 2229, 2231, 2233, 2235, 2237, 2239, 2241, 2243, - 2245, 2247, 2249, 2251, 2253, 2255, 2258, 2260, 2262, 2265, - 2267, 2269, 2271, 2273, 2278, 2283, 2290, 2295, 2302, 2307, - 2314, 2319, 2327, 2335, 2343, 2351, 2369, 2377, 2385, 2393, - 2401, 2409, 2417, 2421, 2437, 2445, 2453, 2461, 2469, 2477, - 2485, 2489, 2493, 2497, 2501, 2509, 2517, 2525, 2533, 2553, - 2575, 2586, 2593, 2607, 2616, 2624, 2633, 2654, 2656, 2658, - 2660, 2662, 2664, 2666, 2668, 2670, 2672, 2674, 2676, 2678, - 2680, 2682, 2684, 2686, 2688, 2690, 2692, 2694, 2696, 2700, - 2704, 2708, 2722, 2723, 2737, 2738, 2739, 2750, 2774, 2785, - 2795, 2799, 2803, 2810, 2814, 2821, 2828, 2829, 2830, 2831, - 2832, 2833, 2834, 2835, 2846, 2851, 2860, 2866, 2873, 2893, - 2897, 2904, 2911, 2919, 2927, 2938, 2958, 2994, 3005, 3006, - 3013, 3019, 3021, 3023, 3027, 3036, 3041, 3048, 3063, 3070, - 3074, 3078, 3082, 3086, 3096, 3104, 3113, 3135, 3136, 3140, - 3141, 3142, 3146, 3147, 3154, 3155, 3159, 3160, 3165, 3173, - 3175, 3189, 3192, 3219, 3220, 3223, 3224, 3232, 3240, 3248, - 3257, 3267, 3285, 3331, 3340, 3349, 3358, 3367, 3379, 3380, - 3381, 3382, 3383, 3397, 3398, 3401, 3402, 3406, 3416, 3417, - 3421, 3422, 3426, 3433, 3434, 3439, 3440, 3445, 3446, 3449, - 3450, 3451, 3454, 3455, 3458, 3459, 3460, 3461, 3462, 3463, - 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3474, 3476, - 3481, 3483, 3488, 3490, 3492, 3494, 3496, 3498, 3500, 3502, - 3516, 3518, 3523, 3527, 3534, 3539, 3545, 3549, 3556, 3561, - 3568, 3573, 3581, 3585, 3591, 3595, 3604, 3615, 3616, 3620, - 3624, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, - 3640, 3641, 3642, 3643, 3644, 3645, 3655, 3659, 3666, 3673, - 3674, 3690, 3694, 3699, 3703, 3718, 3723, 3727, 3730, 3733, - 3734, 3735, 3738, 3745, 3746, 3747, 3757, 3771, 3772, 3776, - 3787, 3788, 3791, 3792, 3796, 3797, 3800, 3806, 3810, 3817, - 3825, 3833, 3841, 3851, 3852, 3857, 3858, 3862, 3863, 3864, - 3868, 3877, 3885, 3893, 3902, 3917, 3918, 3923, 3924, 3934, - 3935, 3939, 3940, 3944, 3945, 3948, 3964, 3972, 3980, 3990, - 3991, 3995, 3999, 4005, 4007, 4012, 4013, 4017, 4018, 4021, - 4025, 4026, 4030, 4031, 4034, 4035, 4036, 4039, 4043, 4044, - 4048, 4049, 4051, 4052, 4053, 4063, 4064, 4068, 4070, 4076, - 4077, 4081, 4082, 4085, 4096, 4099, 4110, 4114, 4118, 4130, - 4134, 4143, 4150, 4188, 4192, 4196, 4200, 4204, 4208, 4212, - 4218, 4235, 4236, 4237, 4240, 4241, 4242, 4245, 4246, 4247, - 4250, 4251, 4254, 4256, 4261, 4262, 4265, 4269, 4270, 7, - 18, 19, 23, 24, 25, 26, 27, 28, 7, 26, - 50, 73, 80, 85, 86, 87, 88, 8, 33, 62, - 66, 67, 72, 73, 78, 79, 83, 84, 89, 90, - 7, 16, 25, 34, 43, 52, 5, 12, 22, 23, - 7, 15, 26, 27, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 7, 19, 33, 9, 16, 26, - 33, 44, 45, 50, 51, 52, 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, 91, 92, 93, - 98, 99, 104, 108, 116, 117, 122, 123, 124, 130, - 135, 143, 144, 10, 16, 22, 28, 34, 44, 45, - 53, 64, 76, 84, 95, 101, 105, 109, 124, 131, - 132, 133, 137, 138, 7, 17, 26, 35, 46, 47, - 49, 50, 53, 54, 55, 8, 22, 36, 48, 56, - 70, 71, 72, 73, 74, 87, 88, 93, 94, 98, - 99, 7, 18, 31, 35, 42, 53, 54, 60, 61, - 9, 19, 7, 16, 28, 35, 42, 51, 52, 56, - 57, 2, 7, 12, 17, 22, 31, 38, 48, 49, - 56, 3, 10, 17, 24, 31, 38, 45, 52, 61, - 61, 63, 63, 65, 65, 67, 68, 6, 8, 21, - 34, 47, 65, 87, 88, 89, 90, 11, 24, 37, - 54, 55, 56, 61, 74, 74, 74, 74, 74, 74, + 673, 675, 680, 683, 691, 695, 699, 703, 707, 711, + 718, 723, 730, 731, 735, 740, 744, 748, 756, 763, + 764, 769, 770, 774, 775, 780, 782, 784, 789, 809, + 810, 812, 817, 818, 822, 823, 826, 827, 852, 853, + 858, 862, 863, 867, 868, 872, 873, 874, 875, 876, + 880, 893, 900, 907, 914, 915, 919, 920, 924, 925, + 929, 930, 934, 935, 939, 940, 944, 955, 956, 957, + 958, 962, 963, 968, 969, 970, 979, 985, 994, 995, + 1008, 1009, 1013, 1014, 1018, 1019, 1025, 1031, 1039, 1048, + 1056, 1065, 1074, 1078, 1083, 1094, 1108, 1109, 1112, 1113, + 1114, 1117, 1125, 1135, 1136, 1137, 1140, 1148, 1157, 1161, + 1168, 1169, 1173, 1182, 1186, 1211, 1215, 1228, 1242, 1257, + 1269, 1282, 1296, 1310, 1323, 1338, 1357, 1363, 1368, 1374, + 1381, 1382, 1390, 1394, 1398, 1404, 1411, 1416, 1417, 1418, + 1419, 1420, 1421, 1425, 1426, 1438, 1439, 1444, 1451, 1458, + 1465, 1497, 1508, 1521, 1526, 1527, 1530, 1531, 1534, 1535, + 1540, 1541, 1546, 1550, 1556, 1577, 1585, 1598, 1601, 1605, + 1605, 1608, 1609, 1611, 1616, 1623, 1628, 1634, 1639, 1645, + 1649, 1656, 1663, 1673, 1674, 1678, 1680, 1683, 1687, 1688, + 1689, 1690, 1691, 1692, 1697, 1717, 1718, 1719, 1720, 1731, + 1745, 1746, 1752, 1757, 1762, 1767, 1772, 1777, 1782, 1787, + 1793, 1799, 1805, 1812, 1834, 1843, 1847, 1855, 1859, 1867, + 1879, 1900, 1904, 1910, 1914, 1927, 1935, 1945, 1947, 1949, + 1951, 1953, 1955, 1960, 1961, 1968, 1977, 1985, 1994, 2005, + 2013, 2014, 2015, 2019, 2019, 2022, 2022, 2025, 2025, 2028, + 2028, 2031, 2031, 2034, 2034, 2037, 2037, 2040, 2040, 2043, + 2043, 2046, 2046, 2049, 2049, 2052, 2052, 2055, 2055, 2058, + 2060, 2062, 2064, 2066, 2068, 2070, 2072, 2074, 2076, 2078, + 2080, 2082, 2084, 2089, 2094, 2100, 2107, 2112, 2118, 2124, + 2155, 2157, 2159, 2167, 2182, 2184, 2186, 2188, 2190, 2192, + 2194, 2196, 2198, 2200, 2202, 2204, 2206, 2208, 2210, 2212, + 2215, 2217, 2219, 2222, 2224, 2226, 2228, 2230, 2235, 2240, + 2247, 2252, 2259, 2264, 2271, 2276, 2284, 2292, 2300, 2308, + 2326, 2334, 2342, 2350, 2358, 2366, 2374, 2378, 2394, 2402, + 2410, 2418, 2426, 2434, 2442, 2446, 2450, 2454, 2458, 2466, + 2474, 2482, 2490, 2510, 2532, 2543, 2550, 2564, 2573, 2581, + 2589, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, 2625, + 2627, 2629, 2631, 2633, 2635, 2637, 2639, 2641, 2643, 2645, + 2647, 2649, 2651, 2655, 2659, 2663, 2677, 2678, 2692, 2693, + 2694, 2705, 2729, 2740, 2750, 2754, 2758, 2765, 2769, 2776, + 2780, 2784, 2788, 2790, 2793, 2796, 2807, 2812, 2819, 2825, + 2831, 2838, 2858, 2862, 2869, 2877, 2885, 2896, 2916, 2952, + 2963, 2964, 2971, 2977, 2979, 2981, 2985, 2994, 2999, 3006, + 3021, 3028, 3032, 3036, 3040, 3044, 3054, 3062, 3071, 3093, + 3094, 3098, 3099, 3100, 3104, 3105, 3112, 3113, 3117, 3118, + 3123, 3131, 3133, 3147, 3150, 3177, 3178, 3181, 3182, 3190, + 3198, 3206, 3215, 3225, 3243, 3289, 3298, 3307, 3316, 3325, + 3337, 3338, 3339, 3340, 3341, 3355, 3356, 3359, 3360, 3364, + 3374, 3375, 3379, 3380, 3384, 3391, 3392, 3397, 3398, 3403, + 3404, 3407, 3408, 3409, 3412, 3413, 3416, 3417, 3418, 3419, + 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, + 3432, 3434, 3439, 3441, 3446, 3448, 3450, 3452, 3454, 3456, + 3458, 3460, 3474, 3476, 3481, 3485, 3492, 3497, 3503, 3507, + 3514, 3519, 3526, 3531, 3539, 3543, 3549, 3553, 3562, 3573, + 3574, 3578, 3582, 3589, 3590, 3591, 3592, 3593, 3594, 3595, + 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3613, 3617, + 3624, 3631, 3632, 3648, 3652, 3657, 3661, 3676, 3681, 3685, + 3688, 3691, 3692, 3693, 3696, 3703, 3704, 3705, 3715, 3729, + 3730, 3734, 3745, 3746, 3749, 3750, 3754, 3755, 3758, 3764, + 3768, 3775, 3783, 3791, 3799, 3809, 3810, 3815, 3816, 3820, + 3821, 3822, 3826, 3835, 3843, 3851, 3860, 3875, 3876, 3881, + 3882, 3892, 3893, 3897, 3898, 3902, 3903, 3906, 3922, 3930, + 3940, 3941, 3944, 3945, 3948, 3952, 3953, 3957, 3958, 3961, + 3962, 3963, 3973, 3974, 3978, 3980, 3986, 3987, 3991, 3992, + 3995, 4006, 4009, 4020, 4024, 4028, 4040, 4044, 4053, 4060, + 4098, 4102, 4106, 4110, 4114, 4118, 4122, 4128, 4145, 4146, + 4147, 4150, 4151, 4152, 4155, 4156, 4157, 4160, 4161, 4164, + 4166, 4171, 4172, 4175, 4179, 4180, 7, 18, 19, 23, + 24, 25, 26, 27, 28, 7, 26, 50, 73, 80, + 85, 86, 87, 88, 8, 33, 62, 66, 67, 72, + 73, 78, 79, 83, 84, 89, 90, 7, 16, 25, + 34, 43, 52, 5, 12, 22, 23, 7, 15, 26, + 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 7, 19, 33, 9, 16, 26, 33, 44, 45, + 50, 51, 52, 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, 91, 92, 93, 98, 99, 104, + 108, 116, 117, 122, 123, 124, 130, 135, 143, 144, + 10, 16, 22, 28, 34, 44, 45, 53, 64, 76, + 84, 95, 101, 105, 109, 124, 131, 132, 133, 137, + 138, 7, 17, 26, 35, 46, 47, 49, 50, 53, + 54, 55, 8, 22, 36, 48, 56, 70, 71, 72, + 73, 74, 87, 88, 93, 94, 98, 99, 7, 18, + 31, 35, 42, 53, 54, 60, 61, 9, 19, 7, + 16, 28, 35, 42, 51, 52, 56, 57, 2, 7, + 12, 17, 22, 31, 38, 48, 49, 56, 3, 10, + 17, 24, 31, 38, 45, 52, 61, 61, 63, 63, + 65, 65, 67, 68, 72, 73, 6, 8, 21, 34, + 47, 65, 87, 88, 89, 90, 11, 24, 37, 54, + 55, 56, 61, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, @@ -2800,19 +2789,18 @@ static const yytype_uint16 yyrline[] = 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, + 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 75, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 77, 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, @@ -2820,17 +2808,18 @@ static const yytype_uint16 yyrline[] = 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, + 79, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80 + 80, 80, 80, 80, 80, 80 }; #endif @@ -2921,8 +2910,8 @@ static const char *const yytname[] = "XMLROOT", "XMLSERIALIZE", "XMLTABLE", "YEAR_P", "YEARS_P", "YES_P", "ZONE", "NOT_LA", "NULLS_LA", "WITH_LA", "'<'", "'>'", "'='", "POSTFIXOP", "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "UMINUS", "'['", - "']'", "'('", "')'", "'.'", "';'", "','", "':'", "'?'", "'$'", "'#'", - "'{'", "'}'", "$accept", "stmtblock", "stmtmulti", "stmt", + "']'", "'('", "')'", "'.'", "';'", "','", "'?'", "'#'", "'$'", "'{'", + "'}'", "':'", "$accept", "stmtblock", "stmtmulti", "stmt", "AlterTableStmt", "alter_identity_column_option_list", "alter_column_default", "alter_identity_column_option", "alter_generic_option_list", "alter_table_cmd", "alter_using", @@ -2976,19 +2965,18 @@ static const char *const yytname[] = "by_name", "distinct_clause", "opt_all_clause", "opt_ignore_nulls", "opt_sort_clause", "sort_clause", "sortby_list", "sortby", "opt_asc_desc", "opt_nulls_order", "select_limit", "opt_select_limit", - "limit_clause", "offset_clause", "sample_value", "sample_count", - "sample_clause", "opt_sample_func", "tablesample_entry", - "tablesample_clause", "opt_tablesample_clause", "opt_repeatable_clause", - "select_limit_value", "select_offset_value", "select_fetch_first_value", - "I_or_F_const", "row_or_rows", "first_or_next", "group_clause", - "group_by_list", "group_by_list_opt_comma", "group_by_item", - "empty_grouping_set", "rollup_clause", "cube_clause", - "grouping_sets_clause", "grouping_or_grouping_id", "having_clause", - "qualify_clause", "for_locking_clause", "opt_for_locking_clause", - "for_locking_items", "for_locking_item", "for_locking_strength", - "locked_rels_list", "opt_nowait_or_skip", "values_clause", - "values_clause_opt_comma", "from_clause", "from_list", - "from_list_opt_comma", "alias_prefix_colon_clause", "table_ref", + "limit_clause", "offset_clause", "sample_count", "sample_clause", + "opt_sample_func", "tablesample_entry", "tablesample_clause", + "opt_tablesample_clause", "opt_repeatable_clause", "select_limit_value", + "select_offset_value", "select_fetch_first_value", "I_or_F_const", + "row_or_rows", "first_or_next", "group_clause", "group_by_list", + "group_by_list_opt_comma", "group_by_item", "empty_grouping_set", + "rollup_clause", "cube_clause", "grouping_sets_clause", + "grouping_or_grouping_id", "having_clause", "qualify_clause", + "for_locking_clause", "opt_for_locking_clause", "for_locking_items", + "for_locking_item", "for_locking_strength", "locked_rels_list", + "opt_nowait_or_skip", "values_clause", "values_clause_opt_comma", + "from_clause", "from_list", "from_list_opt_comma", "table_ref", "opt_pivot_group_by", "opt_include_nulls", "single_pivot_value", "pivot_header", "pivot_value", "pivot_value_list", "unpivot_header", "unpivot_value", "unpivot_value_list", "joined_table", "alias_clause", @@ -3007,8 +2995,8 @@ static const char *const yytname[] = "millisecond_keyword", "microsecond_keyword", "week_keyword", "quarter_keyword", "decade_keyword", "century_keyword", "millennium_keyword", "opt_interval", "a_expr", "b_expr", "c_expr", - "d_expr", "indirection_expr_or_a_expr", "param_expr", "indirection_expr", - "list_expr", "struct_expr", "map_expr", "func_application", "func_expr", + "d_expr", "indirection_expr_or_a_expr", "indirection_expr", "list_expr", + "struct_expr", "map_expr", "func_application", "func_expr", "func_expr_windowless", "func_expr_common_subexpr", "list_comprehension_lhs", "list_comprehension", "within_group_clause", "filter_clause", "export_clause", "window_clause", @@ -3030,16 +3018,13 @@ static const char *const yytname[] = "opt_func_arguments", "extended_indirection_el", "opt_extended_indirection", "opt_asymmetric", "opt_target_list_opt_comma", "target_list", "target_list_opt_comma", - "target_el", "except_list", "except_name", "except_name_list", - "except_name_list_opt_comma", "opt_except_list", "replace_list_el", + "target_el", "except_list", "opt_except_list", "replace_list_el", "replace_list", "replace_list_opt_comma", "opt_replace_list", - "rename_list_el", "rename_list", "rename_list_opt_comma", - "opt_rename_list", "qualified_name_list", "name_list", - "name_list_opt_comma", "name_list_opt_comma_opt_bracket", "name", - "func_name", "AexprConst", "Iconst", "type_function_name", - "function_name_token", "type_name_token", "any_name", "attrs", - "opt_name_list", "param_name", "ColLabelOrString", "PrepareStmt", - "prep_type_clause", "PreparableStmt", "CreateSchemaStmt", + "qualified_name_list", "name_list", "name_list_opt_comma", + "name_list_opt_comma_opt_bracket", "name", "func_name", "AexprConst", + "Iconst", "type_function_name", "function_name_token", "type_name_token", + "any_name", "attrs", "opt_name_list", "param_name", "ColLabelOrString", + "PrepareStmt", "prep_type_clause", "PreparableStmt", "CreateSchemaStmt", "OptSchemaEltList", "schema_stmt", "IndexStmt", "access_method", "access_method_clause", "opt_concurrently", "opt_index_name", "opt_reloptions", "opt_unique", "AlterObjectSchemaStmt", @@ -3056,10 +3041,11 @@ static const char *const yytname[] = "AnalyzeStmt", "AttachStmt", "DetachStmt", "opt_database", "opt_database_alias", "VariableResetStmt", "generic_reset", "reset_rest", "VariableShowStmt", "describe_or_desc", "show_or_describe", "opt_tables", - "var_name", "CallStmt", "ViewStmt", "opt_check_option", "CreateAsStmt", - "opt_with_data", "create_as_target", "unreserved_keyword", - "col_name_keyword", "func_name_keyword", "type_name_keyword", - "other_keyword", "type_func_name_keyword", "reserved_keyword", 0 + "var_name", "table_id", "CallStmt", "ViewStmt", "opt_check_option", + "CreateAsStmt", "opt_with_data", "create_as_target", + "unreserved_keyword", "col_name_keyword", "func_name_keyword", + "type_name_keyword", "other_keyword", "type_func_name_keyword", + "reserved_keyword", 0 }; #endif @@ -3120,7 +3106,7 @@ static const yytype_uint16 yytoknum[] = 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 60, 62, 61, 760, 43, 45, 42, 47, 37, 94, 761, 91, 93, 40, 41, - 46, 59, 44, 58, 63, 36, 35, 123, 125 + 46, 59, 44, 63, 35, 36, 123, 125, 58 }; # endif @@ -3190,161 +3176,159 @@ static const yytype_uint16 yyr1[] = 706, 707, 707, 708, 708, 709, 709, 709, 710, 710, 711, 711, 712, 712, 713, 713, 714, 714, 714, 715, 715, 715, 716, 716, 716, 716, 717, 717, 718, 718, - 718, 718, 719, 719, 720, 720, 720, 721, 721, 721, - 721, 722, 722, 723, 723, 724, 724, 724, 724, 725, - 726, 726, 727, 727, 728, 728, 728, 728, 728, 729, - 730, 730, 730, 731, 731, 732, 732, 733, 733, 734, - 734, 734, 735, 735, 736, 736, 737, 737, 737, 737, - 737, 738, 739, 740, 741, 742, 742, 743, 743, 744, - 744, 745, 745, 746, 746, 747, 747, 748, 749, 749, - 749, 749, 750, 750, 751, 751, 751, 752, 752, 753, - 753, 754, 754, 755, 755, 756, 756, 757, 758, 758, - 758, 758, 758, 758, 758, 758, 758, 758, 758, 758, - 758, 758, 759, 759, 760, 760, 760, 761, 761, 762, - 762, 762, 763, 763, 764, 764, 765, 765, 766, 767, - 767, 768, 768, 768, 768, 768, 768, 768, 768, 768, - 768, 768, 769, 769, 769, 769, 770, 770, 771, 771, - 771, 771, 771, 772, 772, 772, 772, 772, 772, 773, - 773, 774, 774, 775, 775, 775, 775, 776, 776, 777, - 778, 778, 779, 779, 780, 780, 781, 781, 782, 782, - 783, 784, 784, 785, 785, 786, 786, 787, 787, 788, - 788, 788, 788, 788, 788, 788, 788, 788, 788, 789, - 789, 790, 790, 790, 791, 791, 791, 791, 791, 791, - 791, 792, 792, 792, 792, 793, 794, 794, 795, 795, - 795, 795, 795, 795, 795, 795, 795, 795, 795, 796, - 796, 797, 797, 798, 798, 799, 800, 801, 801, 802, - 802, 803, 804, 805, 805, 805, 805, 805, 805, 806, - 806, 807, 807, 807, 807, 808, 809, 809, 809, 810, - 810, 811, 811, 812, 812, 813, 813, 814, 814, 815, - 815, 816, 816, 817, 817, 818, 818, 819, 819, 820, - 820, 821, 821, 822, 822, 823, 823, 823, 823, 823, + 718, 718, 719, 719, 720, 720, 720, 720, 720, 720, + 721, 721, 722, 722, 723, 723, 723, 723, 724, 725, + 725, 726, 726, 727, 727, 727, 727, 727, 728, 729, + 729, 729, 730, 730, 731, 731, 732, 732, 733, 733, + 733, 734, 734, 735, 735, 736, 736, 736, 736, 736, + 737, 738, 739, 740, 741, 741, 742, 742, 743, 743, + 744, 744, 745, 745, 746, 746, 747, 748, 748, 748, + 748, 749, 749, 750, 750, 750, 751, 751, 752, 752, + 753, 753, 754, 754, 755, 755, 756, 756, 756, 756, + 756, 756, 756, 756, 756, 756, 757, 757, 758, 758, + 758, 759, 759, 760, 760, 760, 761, 761, 762, 762, + 763, 763, 764, 765, 765, 766, 766, 766, 766, 766, + 766, 766, 766, 766, 766, 766, 767, 767, 767, 767, + 768, 768, 769, 769, 769, 769, 769, 770, 770, 770, + 770, 770, 770, 771, 771, 772, 772, 773, 773, 773, + 773, 774, 774, 775, 776, 776, 777, 777, 778, 778, + 779, 779, 780, 780, 781, 782, 782, 783, 783, 784, + 784, 785, 785, 786, 786, 786, 786, 786, 786, 786, + 786, 786, 786, 787, 787, 788, 788, 788, 789, 789, + 789, 789, 789, 789, 789, 790, 790, 790, 790, 791, + 792, 792, 793, 793, 793, 793, 793, 793, 793, 793, + 793, 793, 793, 794, 794, 795, 795, 796, 796, 797, + 798, 799, 799, 800, 800, 801, 802, 803, 803, 803, + 803, 803, 803, 804, 804, 805, 805, 805, 805, 806, + 807, 807, 807, 808, 808, 809, 809, 810, 810, 811, + 811, 812, 812, 813, 813, 814, 814, 815, 815, 816, + 816, 817, 817, 818, 818, 819, 819, 820, 820, 821, + 821, 821, 821, 821, 821, 821, 821, 821, 821, 821, + 821, 821, 821, 821, 821, 821, 821, 821, 821, 821, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, 822, 822, 822, + 822, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, - 823, 823, 823, 823, 823, 823, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 825, 825, 825, - 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, - 825, 825, 825, 825, 825, 825, 825, 825, 825, 825, - 825, 825, 826, 826, 827, 827, 827, 827, 827, 827, - 828, 828, 828, 829, 829, 829, 830, 830, 830, 830, - 830, 830, 830, 830, 830, 830, 831, 832, 833, 834, - 834, 834, 834, 834, 834, 834, 835, 835, 836, 836, - 837, 837, 837, 837, 837, 837, 837, 837, 837, 837, - 837, 837, 837, 837, 838, 839, 839, 840, 840, 841, - 841, 841, 842, 842, 843, 843, 844, 844, 845, 846, - 846, 846, 847, 848, 848, 849, 849, 850, 850, 850, - 850, 851, 851, 852, 852, 852, 852, 852, 853, 853, - 853, 853, 853, 854, 854, 855, 855, 856, 857, 857, - 858, 858, 859, 860, 860, 861, 861, 862, 862, 863, + 823, 823, 823, 823, 823, 823, 824, 824, 825, 825, + 825, 825, 825, 825, 826, 826, 826, 827, 827, 827, + 827, 827, 827, 827, 827, 827, 827, 827, 827, 828, + 829, 830, 831, 831, 831, 831, 831, 831, 832, 832, + 833, 833, 834, 834, 834, 834, 834, 834, 834, 834, + 834, 834, 834, 834, 834, 834, 835, 836, 836, 837, + 837, 838, 838, 838, 839, 839, 840, 840, 841, 841, + 842, 843, 843, 843, 844, 845, 845, 846, 846, 847, + 847, 847, 847, 848, 848, 849, 849, 849, 849, 849, + 850, 850, 850, 850, 850, 851, 851, 852, 852, 853, + 854, 854, 855, 855, 856, 857, 857, 858, 858, 859, + 859, 860, 860, 860, 861, 861, 862, 862, 862, 862, + 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 863, 863, 864, 864, 865, 865, 865, 865, 865, 865, - 865, 865, 865, 865, 865, 865, 865, 865, 866, 866, - 867, 867, 868, 868, 868, 868, 868, 868, 868, 868, - 869, 869, 870, 870, 871, 871, 872, 872, 873, 873, - 874, 874, 875, 875, 876, 876, 876, 877, 877, 878, - 878, 879, 879, 879, 879, 879, 879, 879, 879, 879, - 879, 879, 879, 879, 879, 879, 880, 880, 881, 882, - 882, 883, 883, 883, 883, 883, 883, 884, 885, 886, - 886, 886, 887, 887, 887, 887, 888, 889, 889, 890, - 891, 891, 892, 892, 893, 893, 894, 895, 895, 550, - 550, 550, 550, 896, 896, 897, 897, 898, 898, 898, - 899, 899, 899, 899, 899, 900, 900, 901, 901, 902, - 902, 903, 903, 904, 904, 905, 905, 905, 905, 906, - 906, 907, 907, 908, 908, 909, 909, 910, 910, 911, - 912, 912, 913, 913, 914, 914, 914, 915, 916, 916, - 917, 917, 918, 918, 918, 919, 919, 920, 920, 921, - 921, 922, 922, 923, 924, 924, 925, 925, 925, 925, - 925, 925, 925, 925, 925, 925, 925, 925, 925, 925, - 926, 927, 927, 927, 928, 928, 928, 929, 929, 929, - 930, 930, 931, 931, 932, 932, 933, 934, 934, 935, - 936, 936, 937, 937, 937, 937, 937, 937, 938, 938, - 938, 939, 939, 940, 940, 940, 940, 941, 941, 942, - 943, 943, 944, 944, 945, 945, 946, 946, 947, 947, - 948, 948, 948, 948, 948, 948, 949, 949, 950, 950, - 951, 951, 952, 952, 953, 953, 953, 953, 953, 953, - 953, 953, 953, 953, 954, 954, 955, 956, 956, 956, - 956, 957, 957, 958, 958, 958, 959, 959, 959, 959, - 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, - 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, - 959, 959, 959, 959, 959, 959, 959, 960, 960, 960, - 961, 961, 962, 962, 963, 963, 964, 964, 964, 964, - 965, 966, 966, 967, 967, 967, 967, 967, 968, 968, - 968, 968, 969, 969, 970, 971, 971, 971, 971, 971, - 971, 971, 972, 972, 973, 973, 973, 973, 974, 974, - 975, 975, 976, 976, 976, 977, 977, 977, 977, 977, - 978, 978, 978, 978, 978, 979, 979, 980, 980, 981, - 981, 982, 982, 983, 983, 983, 984, 984, 985, 985, - 986, 986, 987, 987, 988, 988, 988, 989, 989, 990, - 990, 991, 991, 991, 991, 991, 992, 992, 993, 993, - 993, 994, 994, 994, 994, 994, 994, 994, 994, 995, - 995, 996, 996, 997, 997, 998, 998, 999, 1000, 1000, - 1000, 1000, 1000, 1001, 1001, 1001, 1001, 1002, 1002, 1002, - 1003, 1003, 1003, 1004, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1006, 1006, - 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, - 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, - 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, - 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, - 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, - 1006, 1006, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, - 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, - 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, - 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, - 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, - 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, - 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, - 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, - 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, - 1010, 1010, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, - 1011, 1011, 1011, 1011, 1011, 1011, 1011 + 865, 865, 866, 866, 867, 867, 868, 868, 869, 869, + 870, 870, 871, 871, 872, 872, 873, 873, 873, 874, + 874, 875, 875, 876, 876, 876, 876, 876, 876, 876, + 876, 876, 876, 876, 876, 876, 876, 876, 877, 877, + 878, 879, 879, 880, 880, 880, 880, 880, 880, 881, + 882, 883, 883, 883, 884, 884, 884, 884, 885, 886, + 886, 887, 888, 888, 889, 889, 890, 890, 891, 892, + 892, 550, 550, 550, 550, 893, 893, 894, 894, 895, + 895, 895, 896, 896, 896, 896, 896, 897, 897, 898, + 898, 899, 899, 900, 900, 901, 901, 902, 902, 902, + 903, 903, 904, 904, 905, 906, 906, 907, 907, 908, + 908, 908, 909, 909, 910, 910, 911, 911, 912, 912, + 913, 914, 914, 915, 915, 915, 915, 915, 915, 915, + 915, 915, 915, 915, 915, 915, 915, 916, 917, 917, + 917, 918, 918, 918, 919, 919, 919, 920, 920, 921, + 921, 922, 922, 923, 924, 924, 925, 926, 926, 927, + 927, 927, 927, 927, 927, 928, 928, 928, 929, 929, + 930, 930, 930, 930, 931, 931, 932, 933, 933, 934, + 934, 935, 935, 936, 936, 937, 937, 938, 938, 938, + 938, 938, 938, 939, 939, 940, 940, 941, 941, 942, + 942, 943, 943, 943, 943, 943, 943, 943, 943, 943, + 943, 944, 944, 945, 946, 946, 946, 946, 947, 947, + 948, 948, 948, 949, 949, 949, 949, 949, 949, 949, + 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, + 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, + 949, 949, 949, 949, 950, 950, 950, 951, 951, 952, + 952, 953, 953, 954, 954, 954, 954, 955, 956, 956, + 957, 957, 957, 957, 957, 958, 958, 958, 958, 959, + 959, 960, 961, 961, 961, 961, 961, 961, 961, 962, + 962, 963, 963, 963, 963, 964, 964, 965, 965, 966, + 966, 966, 967, 967, 967, 967, 967, 968, 968, 968, + 968, 968, 969, 969, 970, 970, 971, 971, 972, 972, + 973, 973, 973, 974, 974, 975, 975, 976, 976, 977, + 977, 978, 978, 978, 979, 979, 980, 980, 981, 981, + 981, 981, 981, 982, 982, 983, 983, 983, 984, 984, + 984, 984, 984, 984, 984, 984, 985, 985, 986, 986, + 987, 987, 988, 988, 989, 989, 990, 991, 991, 991, + 991, 991, 992, 992, 992, 992, 993, 993, 993, 994, + 994, 994, 995, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 996, 996, 996, + 996, 996, 996, 996, 996, 996, 996, 997, 997, 997, + 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, + 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, + 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, + 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, + 997, 997, 997, 997, 997, 997, 997, 997, 997, 997, + 997, 998, 998, 998, 998, 998, 998, 998, 998, 998, + 998, 998, 998, 998, 998, 998, 998, 998, 998, 998, + 998, 998, 998, 998, 998, 998, 998, 998, 998, 999, + 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, + 999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1001, + 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, + 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, + 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, + 1001, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -3413,99 +3397,97 @@ static const yytype_uint8 yyr2[] = 2, 1, 5, 1, 0, 2, 2, 0, 1, 0, 3, 5, 1, 3, 4, 3, 1, 1, 0, 2, 2, 0, 2, 2, 1, 1, 1, 0, 2, 4, - 5, 4, 2, 3, 1, 1, 1, 2, 2, 1, - 2, 3, 0, 1, 0, 5, 1, 4, 6, 2, - 1, 0, 4, 0, 1, 1, 2, 2, 2, 1, - 1, 2, 2, 1, 1, 1, 1, 1, 1, 3, - 3, 0, 1, 3, 1, 2, 1, 1, 1, 1, - 1, 2, 4, 4, 5, 1, 1, 2, 0, 2, - 0, 1, 3, 1, 0, 1, 2, 3, 2, 4, - 2, 3, 2, 0, 1, 2, 0, 4, 5, 1, - 2, 2, 0, 1, 3, 1, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 1, 4, 4, - 9, 9, 3, 0, 2, 2, 0, 5, 3, 1, - 1, 3, 5, 3, 1, 2, 1, 3, 5, 1, - 2, 3, 4, 5, 4, 5, 4, 6, 5, 4, - 5, 5, 5, 2, 4, 1, 1, 0, 1, 4, - 5, 4, 0, 2, 2, 2, 1, 1, 1, 1, - 0, 4, 2, 1, 2, 2, 4, 2, 6, 2, - 1, 3, 4, 0, 2, 0, 2, 0, 1, 3, - 3, 2, 0, 2, 4, 1, 1, 1, 0, 2, - 3, 5, 6, 2, 3, 1, 5, 5, 5, 3, - 3, 3, 4, 0, 1, 1, 1, 1, 1, 2, - 4, 1, 1, 1, 1, 2, 3, 0, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 1, 3, - 0, 1, 1, 1, 1, 5, 2, 1, 1, 1, - 1, 4, 1, 2, 2, 1, 3, 3, 2, 1, - 0, 5, 2, 5, 2, 1, 3, 3, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 5, 4, 2, 3, 2, 2, 2, 2, 1, 2, + 3, 0, 1, 0, 5, 1, 4, 6, 2, 1, + 0, 4, 0, 1, 1, 2, 2, 2, 1, 1, + 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, + 0, 1, 3, 1, 2, 1, 1, 1, 1, 1, + 2, 4, 4, 5, 1, 1, 2, 0, 2, 0, + 1, 3, 1, 0, 1, 2, 3, 2, 4, 2, + 3, 2, 0, 1, 2, 0, 4, 5, 1, 2, + 2, 0, 1, 3, 1, 2, 3, 3, 3, 3, + 3, 3, 1, 4, 9, 9, 3, 0, 2, 2, + 0, 5, 3, 1, 1, 3, 5, 3, 1, 2, + 1, 3, 5, 1, 2, 3, 4, 5, 4, 5, + 4, 6, 5, 4, 5, 5, 5, 2, 4, 1, + 1, 0, 1, 4, 5, 4, 0, 2, 2, 2, + 1, 1, 1, 1, 0, 4, 2, 1, 2, 2, + 4, 2, 6, 2, 1, 3, 4, 0, 2, 0, + 2, 0, 1, 3, 3, 2, 0, 2, 4, 1, + 1, 1, 0, 2, 3, 5, 6, 2, 3, 1, + 5, 5, 5, 3, 3, 3, 4, 0, 1, 1, + 1, 1, 1, 2, 4, 1, 1, 1, 1, 2, + 3, 0, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 1, 3, 0, 1, 1, 1, 1, 5, + 2, 1, 1, 1, 1, 4, 1, 2, 2, 1, + 3, 3, 2, 1, 0, 5, 2, 5, 2, 1, + 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 3, 0, 1, 3, 3, 5, - 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, - 3, 2, 2, 3, 3, 5, 4, 6, 3, 5, - 4, 6, 4, 6, 5, 7, 3, 2, 4, 3, - 2, 3, 3, 3, 3, 4, 3, 4, 3, 4, - 5, 6, 6, 7, 6, 7, 6, 7, 3, 4, - 4, 6, 1, 5, 4, 4, 6, 1, 3, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 5, 6, - 6, 7, 1, 2, 1, 1, 1, 2, 2, 4, - 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 2, 4, 2, 3, 3, 4, 3, - 5, 6, 7, 9, 7, 7, 5, 1, 1, 1, - 5, 6, 6, 4, 4, 4, 4, 6, 5, 5, - 5, 4, 6, 4, 1, 7, 9, 5, 0, 5, - 4, 0, 1, 0, 2, 0, 1, 3, 3, 2, - 2, 0, 6, 1, 0, 3, 0, 3, 3, 3, - 0, 1, 4, 2, 2, 2, 2, 2, 3, 2, - 2, 3, 0, 4, 3, 1, 5, 3, 1, 3, - 1, 2, 3, 1, 3, 1, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, - 1, 4, 1, 4, 1, 2, 1, 2, 1, 2, - 1, 3, 1, 3, 1, 2, 1, 3, 1, 2, - 1, 0, 1, 3, 1, 3, 3, 1, 3, 3, + 1, 1, 3, 3, 3, 3, 3, 3, 3, 0, + 1, 3, 3, 5, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 2, 2, 3, 3, 2, 2, 3, 3, 5, + 4, 6, 3, 5, 4, 6, 4, 6, 5, 7, + 3, 2, 4, 3, 2, 3, 3, 3, 3, 4, + 3, 4, 3, 4, 5, 6, 6, 7, 6, 7, + 6, 7, 3, 4, 4, 6, 1, 5, 4, 3, + 5, 1, 3, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 5, 6, 6, 7, 1, 2, 1, 1, + 1, 2, 2, 4, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 4, 2, 2, 3, + 3, 4, 3, 6, 7, 9, 7, 7, 5, 1, + 1, 1, 5, 6, 6, 4, 4, 4, 4, 6, + 5, 5, 5, 4, 6, 4, 1, 7, 9, 5, + 0, 5, 4, 0, 1, 0, 2, 0, 1, 3, + 3, 2, 2, 0, 6, 1, 0, 3, 0, 3, + 3, 3, 0, 1, 4, 2, 2, 2, 2, 2, + 3, 2, 2, 3, 0, 4, 3, 1, 5, 3, + 1, 3, 1, 2, 3, 1, 3, 1, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 4, 3, 2, 3, - 0, 3, 3, 2, 2, 1, 0, 2, 2, 3, - 2, 1, 1, 3, 1, 1, 5, 1, 2, 4, - 2, 0, 1, 0, 1, 3, 1, 1, 2, 3, - 5, 7, 7, 1, 0, 0, 2, 0, 2, 3, - 3, 3, 5, 7, 7, 0, 2, 1, 0, 1, - 0, 1, 3, 1, 2, 3, 2, 1, 3, 4, - 2, 1, 3, 1, 3, 1, 2, 1, 0, 3, - 1, 3, 1, 2, 4, 2, 0, 3, 1, 3, - 1, 2, 4, 2, 0, 1, 3, 1, 3, 1, - 2, 1, 3, 1, 1, 2, 1, 1, 2, 1, - 1, 2, 7, 2, 5, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 3, 3, 0, 1, 1, 1, 5, - 3, 0, 1, 1, 1, 1, 1, 1, 4, 7, - 6, 2, 0, 1, 1, 1, 1, 13, 16, 1, - 2, 0, 1, 0, 1, 0, 2, 0, 1, 0, - 6, 8, 6, 8, 6, 8, 3, 2, 1, 0, - 6, 6, 1, 1, 1, 1, 1, 1, 2, 1, - 1, 1, 1, 1, 4, 6, 3, 2, 4, 3, - 5, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 1, 4, 1, 4, 1, 4, 1, 2, 1, 2, + 1, 2, 1, 3, 1, 3, 1, 2, 1, 3, + 1, 2, 1, 0, 1, 3, 1, 3, 3, 1, + 3, 3, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 3, + 2, 3, 0, 3, 3, 2, 2, 1, 0, 2, + 2, 3, 2, 1, 1, 3, 1, 1, 5, 1, + 2, 4, 2, 0, 1, 0, 1, 3, 1, 1, + 2, 3, 5, 7, 7, 1, 0, 0, 2, 0, + 2, 3, 3, 3, 5, 7, 7, 0, 2, 1, + 0, 1, 0, 1, 3, 1, 2, 3, 2, 1, + 4, 2, 1, 0, 3, 1, 3, 1, 2, 4, + 2, 0, 1, 3, 1, 3, 1, 2, 1, 3, + 1, 1, 2, 1, 1, 2, 1, 1, 2, 7, + 2, 5, 3, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 3, 3, 0, 1, 1, 1, 5, 3, 0, 1, + 1, 1, 1, 1, 1, 4, 7, 6, 2, 0, + 1, 1, 1, 1, 13, 16, 1, 2, 0, 1, + 0, 1, 0, 2, 0, 1, 0, 6, 8, 6, + 8, 6, 8, 3, 2, 1, 0, 6, 6, 1, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 4, 6, 3, 2, 4, 3, 5, 1, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, - 2, 1, 1, 2, 3, 3, 3, 3, 1, 3, - 3, 2, 3, 3, 1, 1, 1, 3, 5, 1, - 1, 1, 1, 3, 2, 4, 6, 6, 0, 1, - 1, 1, 0, 2, 2, 4, 6, 5, 4, 6, - 1, 1, 1, 1, 1, 1, 0, 1, 3, 1, - 0, 7, 3, 1, 2, 3, 2, 0, 2, 0, - 2, 4, 5, 8, 2, 3, 5, 1, 0, 2, - 0, 2, 3, 3, 3, 3, 1, 1, 1, 2, - 3, 2, 2, 2, 2, 3, 4, 3, 1, 1, - 1, 1, 1, 1, 0, 1, 3, 2, 9, 12, - 11, 12, 14, 3, 4, 4, 0, 7, 10, 9, - 2, 3, 0, 4, 1, 1, 1, 1, 1, 1, + 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, + 2, 3, 3, 3, 3, 1, 3, 3, 2, 3, + 3, 1, 1, 1, 3, 5, 1, 1, 1, 1, + 3, 2, 4, 6, 6, 0, 1, 1, 1, 0, + 2, 2, 4, 6, 5, 4, 6, 1, 1, 1, + 1, 1, 1, 0, 1, 3, 1, 0, 7, 3, + 1, 2, 3, 2, 0, 2, 0, 2, 4, 5, + 8, 2, 3, 5, 1, 0, 2, 0, 2, 3, + 3, 3, 3, 1, 1, 1, 2, 3, 2, 2, + 2, 2, 3, 4, 3, 1, 1, 1, 1, 1, + 1, 0, 1, 3, 1, 3, 2, 9, 12, 11, + 12, 14, 3, 4, 4, 0, 7, 10, 9, 2, + 3, 0, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -3567,7 +3549,7 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1 + 1, 1, 1, 1, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -3575,4132 +3557,5813 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 156, 265, 0, 1435, 1434, 1508, 265, 0, 1369, 0, - 265, 501, 406, 0, 1530, 1529, 0, 208, 265, 0, - 156, 0, 1469, 0, 0, 0, 564, 567, 565, 0, - 0, 0, 265, 604, 0, 1531, 265, 0, 0, 596, - 566, 0, 1486, 0, 0, 0, 0, 0, 2, 4, + 156, 265, 0, 1412, 1411, 1485, 265, 0, 1346, 0, + 265, 501, 406, 0, 1507, 1506, 0, 208, 265, 0, + 156, 0, 1446, 0, 0, 0, 564, 567, 565, 0, + 0, 0, 265, 604, 0, 1508, 265, 0, 0, 596, + 566, 0, 1463, 0, 0, 0, 0, 0, 2, 4, 7, 21, 35, 31, 0, 20, 33, 18, 17, 38, 26, 6, 24, 37, 40, 19, 25, 15, 39, 13, - 36, 540, 526, 609, 539, 0, 0, 155, 709, 547, - 34, 16, 30, 5, 11, 12, 28, 29, 27, 1392, + 36, 540, 526, 609, 539, 0, 0, 155, 708, 547, + 34, 16, 30, 5, 11, 12, 28, 29, 27, 1369, 43, 32, 0, 41, 22, 8, 9, 23, 42, 44, - 1532, 1528, 10, 45, 14, 264, 263, 257, 0, 0, - 0, 0, 0, 1507, 0, 0, 268, 112, 1554, 1555, - 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1932, - 1565, 1566, 1567, 1568, 1569, 1933, 1570, 1571, 1572, 1878, - 1879, 1934, 1880, 1881, 1573, 1574, 1575, 1576, 1577, 1578, - 1579, 1580, 1581, 1582, 1882, 1883, 1583, 1584, 1585, 1586, - 1587, 1884, 1935, 1885, 1588, 1589, 1590, 1591, 1592, 1936, - 1593, 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1937, - 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, - 1886, 1612, 1613, 1887, 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, 1888, 1641, 1642, 1643, 1644, 1645, 1646, 1889, 1647, - 1648, 1649, 1890, 1650, 1651, 1652, 1938, 1939, 1653, 1654, - 1891, 1941, 1655, 1656, 1892, 1893, 1657, 1658, 1659, 1660, - 1661, 1662, 1663, 1664, 1665, 1942, 1666, 1667, 1668, 1669, - 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1943, 1894, - 1678, 1679, 1680, 1681, 1682, 1895, 1896, 1897, 1683, 1944, - 1945, 1684, 1946, 1685, 1686, 1687, 1688, 1689, 1690, 1691, - 1947, 1692, 1948, 1693, 1694, 1695, 1696, 1697, 1698, 1699, - 1700, 1898, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, - 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, - 1719, 1720, 1899, 1950, 1900, 1721, 1722, 1723, 1901, 1724, - 1725, 1951, 1726, 1902, 1727, 1903, 1728, 1729, 1730, 1731, - 1732, 1733, 1734, 1735, 1736, 1737, 1904, 1952, 1738, 1953, - 1905, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, - 1748, 1749, 1750, 1751, 1906, 1954, 1752, 1753, 1907, 1754, - 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, - 1765, 1766, 1767, 1908, 1768, 1769, 1770, 1771, 1772, 1773, - 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, - 1784, 1785, 1786, 1955, 1787, 1788, 1789, 1909, 1790, 1791, - 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, - 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1910, 1809, 1810, - 1956, 1811, 1812, 1911, 1813, 1814, 1815, 1816, 1817, 1818, - 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1912, 1826, 1913, - 1827, 1828, 1829, 1958, 1830, 1831, 1832, 1833, 1834, 1835, - 1914, 1915, 1836, 1837, 1916, 1838, 1917, 1839, 1840, 1918, - 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, - 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1919, 1920, 1858, - 1859, 1959, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, - 1868, 1869, 1870, 1871, 1872, 1873, 1921, 1922, 1923, 1924, - 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1874, 1875, 1876, - 1877, 0, 1537, 0, 1294, 113, 114, 1316, 112, 1891, - 1898, 1912, 1368, 1367, 113, 0, 260, 500, 0, 0, - 0, 0, 0, 0, 210, 0, 400, 399, 0, 1358, - 405, 0, 0, 0, 116, 108, 1754, 115, 1293, 106, - 122, 2102, 2103, 2104, 2105, 1989, 2106, 2107, 2108, 2109, - 1990, 2110, 1991, 1992, 1993, 1994, 1995, 1996, 2111, 2112, - 2113, 1998, 1997, 2114, 1999, 2115, 2000, 2116, 2001, 2002, - 2117, 2118, 2003, 1608, 2004, 2005, 2119, 2120, 2121, 2122, - 2123, 2124, 2125, 2126, 2127, 2006, 2007, 2128, 2129, 2008, - 2130, 2131, 2009, 2132, 2010, 2011, 2012, 2133, 2134, 2013, - 2014, 2135, 2015, 2136, 2137, 2016, 2017, 2020, 2018, 2138, - 2019, 2139, 2021, 2022, 2023, 2140, 2141, 2024, 2025, 2142, - 2026, 2027, 2028, 2029, 2030, 2143, 2031, 2144, 2032, 2033, - 2145, 2146, 2147, 2148, 2149, 2035, 2034, 2036, 2037, 2150, - 2151, 2152, 2153, 2038, 2039, 2040, 2154, 2155, 2041, 2156, - 2157, 2042, 2043, 2158, 2044, 2045, 2159, 2046, 2047, 2160, - 2048, 2049, 2161, 2162, 2163, 2050, 2164, 2051, 2052, 2165, - 2166, 2053, 2054, 2167, 2055, 2168, 2169, 2170, 2171, 2056, - 2057, 2172, 2058, 2173, 2174, 2175, 2176, 2059, 2060, 2061, - 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 1504, 124, + 1509, 1505, 10, 45, 14, 264, 263, 257, 0, 0, + 0, 0, 0, 1484, 0, 0, 268, 112, 1533, 1534, + 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1911, + 1544, 1545, 1546, 1547, 1548, 1912, 1549, 1550, 1551, 1857, + 1858, 1913, 1859, 1860, 1552, 1553, 1554, 1555, 1556, 1557, + 1558, 1559, 1560, 1561, 1861, 1862, 1562, 1563, 1564, 1565, + 1566, 1863, 1914, 1864, 1567, 1568, 1569, 1570, 1571, 1915, + 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1916, + 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, + 1865, 1591, 1592, 1866, 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, 1867, 1620, 1621, 1622, 1623, 1624, 1625, 1868, 1626, + 1627, 1628, 1869, 1629, 1630, 1631, 1917, 1918, 1632, 1633, + 1870, 1920, 1634, 1635, 1871, 1872, 1636, 1637, 1638, 1639, + 1640, 1641, 1642, 1643, 1644, 1921, 1645, 1646, 1647, 1648, + 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1922, 1873, + 1657, 1658, 1659, 1660, 1661, 1874, 1875, 1876, 1662, 1923, + 1924, 1663, 1925, 1664, 1665, 1666, 1667, 1668, 1669, 1670, + 1926, 1671, 1927, 1672, 1673, 1674, 1675, 1676, 1677, 1678, + 1679, 1877, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, + 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, + 1698, 1699, 1878, 1929, 1879, 1700, 1701, 1702, 1880, 1703, + 1704, 1930, 1705, 1881, 1706, 1882, 1707, 1708, 1709, 1710, + 1711, 1712, 1713, 1714, 1715, 1716, 1883, 1931, 1717, 1932, + 1884, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1725, 1726, + 1727, 1728, 1729, 1730, 1885, 1933, 1731, 1732, 1886, 1733, + 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, + 1744, 1745, 1746, 1887, 1747, 1748, 1749, 1750, 1751, 1752, + 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, + 1763, 1764, 1765, 1934, 1766, 1767, 1768, 1888, 1769, 1770, + 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, + 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1889, 1788, 1789, + 1935, 1790, 1791, 1890, 1792, 1793, 1794, 1795, 1796, 1797, + 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1891, 1805, 1892, + 1806, 1807, 1808, 1937, 1809, 1810, 1811, 1812, 1813, 1814, + 1893, 1894, 1815, 1816, 1895, 1817, 1896, 1818, 1819, 1897, + 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, + 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1898, 1899, 1837, + 1838, 1938, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, + 1847, 1848, 1849, 1850, 1851, 1852, 1900, 1901, 1902, 1903, + 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1853, 1854, 1855, + 1856, 0, 1516, 0, 1271, 113, 114, 1293, 112, 1870, + 1877, 1891, 1345, 1344, 113, 0, 260, 500, 0, 0, + 0, 0, 0, 0, 210, 0, 400, 399, 0, 1335, + 405, 0, 0, 0, 116, 108, 1733, 115, 1270, 106, + 122, 2081, 2082, 2083, 2084, 1968, 2085, 2086, 2087, 2088, + 1969, 2089, 1970, 1971, 1972, 1973, 1974, 1975, 2090, 2091, + 2092, 1977, 1976, 2093, 1978, 2094, 1979, 2095, 1980, 1981, + 2096, 2097, 1982, 1587, 1983, 1984, 2098, 2099, 2100, 2101, + 2102, 2103, 2104, 2105, 2106, 1985, 1986, 2107, 2108, 1987, + 2109, 2110, 1988, 2111, 1989, 1990, 1991, 2112, 2113, 1992, + 1993, 2114, 1994, 2115, 2116, 1995, 1996, 1999, 1997, 2117, + 1998, 2118, 2000, 2001, 2002, 2119, 2120, 2003, 2004, 2121, + 2005, 2006, 2007, 2008, 2009, 2122, 2010, 2123, 2011, 2012, + 2124, 2125, 2126, 2127, 2128, 2014, 2013, 2015, 2016, 2129, + 2130, 2131, 2132, 2017, 2018, 2019, 2133, 2134, 2020, 2135, + 2136, 2021, 2022, 2137, 2023, 2024, 2138, 2025, 2026, 2139, + 2027, 2028, 2140, 2141, 2142, 2029, 2143, 2030, 2031, 2144, + 2145, 2032, 2033, 2146, 2034, 2147, 2148, 2149, 2150, 2035, + 2036, 2151, 2037, 2152, 2153, 2154, 2155, 2038, 2039, 2040, + 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 1481, 124, 123, 125, 0, 424, 425, 0, 435, 0, 417, 422, 418, 0, 444, 437, 445, 426, 416, 438, 427, 415, 209, 0, 446, 432, 420, 0, 0, 0, 0, 261, - 222, 406, 0, 156, 0, 1398, 1408, 1417, 1413, 1407, - 1415, 1405, 1421, 1411, 1397, 1419, 1406, 1410, 1403, 1420, - 1401, 1418, 1416, 1404, 1412, 1396, 1400, 1387, 1392, 1424, - 1414, 1422, 1409, 1423, 1425, 1399, 1426, 1402, 0, 1369, - 0, 1884, 1935, 1889, 0, 1902, 0, 1905, 1906, 1790, - 1913, 1916, 1917, 1918, 1919, 0, 783, 115, 110, 767, - 0, 542, 0, 713, 727, 767, 772, 1058, 795, 1059, - 0, 117, 1471, 1470, 1464, 195, 1331, 1517, 1655, 1695, - 1807, 1914, 1836, 1858, 1535, 1518, 1511, 1516, 262, 603, - 601, 0, 1250, 1655, 1695, 1794, 1807, 1914, 1858, 1443, - 1448, 0, 268, 1523, 115, 110, 1522, 0, 548, 595, - 0, 269, 1485, 0, 1490, 0, 1770, 575, 578, 1325, - 576, 540, 0, 0, 1, 156, 0, 162, 0, 599, - 599, 0, 599, 0, 532, 0, 0, 540, 535, 539, - 710, 1391, 1500, 0, 1534, 1914, 1836, 1524, 1521, 1664, - 0, 0, 1664, 0, 1664, 0, 1664, 0, 0, 1510, - 0, 258, 1234, 0, 1295, 118, 0, 0, 1380, 1376, - 1381, 1377, 1382, 1375, 1374, 1383, 1379, 0, 0, 0, - 371, 404, 403, 402, 401, 406, 1664, 1342, 0, 206, - 462, 463, 0, 0, 0, 0, 0, 1353, 109, 107, - 1664, 1505, 433, 434, 0, 423, 419, 421, 0, 0, - 1664, 1320, 443, 439, 1664, 443, 1287, 1664, 0, 0, - 214, 0, 399, 1389, 1427, 2056, 1441, 0, 1442, 1432, - 1395, 1428, 1429, 156, 0, 499, 1366, 0, 0, 0, - 1180, 767, 772, 0, 0, 785, 0, 1200, 0, 1206, - 0, 0, 0, 767, 547, 0, 727, 784, 111, 717, - 0, 765, 766, 651, 651, 604, 0, 585, 0, 651, - 651, 651, 777, 0, 0, 780, 778, 0, 780, 0, - 0, 0, 780, 776, 736, 0, 651, 0, 765, 768, - 651, 0, 787, 1386, 0, 0, 0, 0, 1514, 1512, - 1513, 1519, 0, 1515, 0, 0, 1297, 1299, 1300, 1148, - 1310, 1034, 0, 1879, 1880, 1881, 1223, 1882, 1883, 1885, - 1886, 1887, 992, 1628, 1888, 1308, 1890, 1892, 1893, 1895, - 1896, 1897, 1898, 1899, 1900, 0, 1309, 1903, 1733, 1908, - 1909, 1911, 1914, 1915, 1307, 1920, 0, 0, 0, 1268, - 1171, 0, 1033, 0, 0, 0, 1227, 1235, 1026, 0, - 0, 831, 832, 853, 854, 833, 859, 860, 862, 834, - 0, 1257, 926, 1022, 1245, 1036, 1031, 1041, 1037, 1038, - 1078, 1039, 1057, 1042, 1115, 1032, 0, 1040, 1024, 1253, - 585, 1251, 0, 1025, 1296, 585, 1249, 1446, 1444, 1451, - 1445, 0, 1447, 0, 0, 0, 259, 111, 1493, 1492, - 1484, 1482, 1483, 1481, 1480, 1487, 0, 1489, 1392, 1227, - 1166, 1168, 0, 577, 0, 0, 0, 529, 528, 530, - 3, 0, 0, 0, 1645, 0, 597, 598, 0, 0, - 0, 0, 0, 0, 0, 0, 694, 624, 625, 627, - 691, 695, 703, 0, 0, 0, 0, 0, 536, 0, - 1325, 1472, 1533, 1527, 1525, 0, 0, 0, 140, 140, - 0, 0, 0, 0, 0, 100, 49, 93, 0, 0, - 0, 0, 236, 249, 0, 0, 0, 0, 0, 246, - 0, 0, 229, 51, 223, 225, 0, 140, 0, 47, - 0, 0, 0, 53, 1508, 0, 499, 266, 267, 1233, - 0, 120, 121, 119, 112, 0, 2070, 1932, 1933, 1934, - 1935, 1885, 1936, 1937, 0, 1938, 1939, 1891, 1941, 1942, - 1943, 1944, 1945, 1946, 1947, 1948, 1898, 1950, 1951, 1952, - 1953, 1954, 1955, 2096, 1956, 1912, 1958, 1918, 0, 1959, - 1049, 607, 1174, 609, 1172, 1326, 0, 113, 1313, 0, - 1378, 0, 0, 0, 0, 497, 0, 0, 0, 0, - 1338, 0, 1664, 207, 211, 0, 1664, 202, 1664, 371, - 0, 1664, 371, 1664, 0, 1352, 1355, 0, 436, 431, - 429, 428, 430, 1664, 255, 0, 0, 1321, 441, 442, - 0, 410, 0, 0, 412, 0, 0, 219, 0, 217, - 0, 406, 156, 0, 230, 1437, 1438, 1436, 0, 0, - 1431, 1394, 233, 250, 1440, 1430, 1439, 1393, 1388, 0, - 0, 1384, 485, 0, 0, 0, 1181, 902, 901, 883, - 884, 899, 900, 885, 886, 893, 894, 904, 903, 891, - 892, 887, 888, 881, 882, 897, 898, 889, 890, 895, - 896, 879, 880, 1195, 1182, 1183, 1184, 1185, 1186, 1187, - 1188, 1189, 1190, 1191, 1192, 1193, 1194, 0, 0, 726, - 723, 0, 0, 0, 0, 0, 0, 1227, 0, 997, - 1032, 0, 0, 0, 1166, 1205, 0, 0, 0, 0, - 0, 0, 1166, 1211, 0, 0, 751, 763, 0, 644, - 650, 724, 722, 0, 1250, 714, 0, 797, 727, 725, - 719, 721, 0, 777, 0, 776, 0, 0, 779, 773, - 0, 774, 0, 0, 0, 0, 775, 0, 0, 0, - 0, 0, 718, 0, 763, 0, 720, 794, 1454, 1462, - 196, 0, 1317, 1960, 1961, 1962, 841, 1963, 870, 848, - 870, 870, 1964, 1965, 1966, 1967, 837, 837, 850, 1968, - 1969, 1970, 1971, 1972, 838, 839, 875, 1973, 1974, 1975, - 1976, 1977, 0, 0, 1978, 870, 1979, 837, 1980, 1981, - 1982, 842, 1983, 805, 1984, 0, 1985, 840, 806, 1986, - 878, 878, 1987, 0, 865, 1988, 0, 1177, 815, 823, - 824, 825, 826, 851, 852, 827, 857, 858, 828, 925, - 0, 837, 1318, 1319, 156, 1520, 1536, 0, 1171, 1043, - 869, 856, 1222, 0, 864, 863, 0, 1171, 846, 845, - 844, 1028, 0, 843, 1128, 870, 870, 868, 951, 847, - 0, 0, 0, 0, 0, 874, 0, 872, 952, 930, - 931, 0, 0, 1267, 1276, 1166, 1170, 0, 1026, 1166, - 0, 1035, 1045, 0, 1118, 1120, 0, 0, 0, 1228, - 1298, 1027, 0, 1303, 0, 0, 925, 925, 1256, 1148, - 0, 1138, 1141, 0, 0, 1145, 1146, 1147, 0, 0, - 0, 1248, 0, 1156, 1158, 0, 0, 967, 1154, 0, - 970, 0, 0, 0, 0, 1142, 1143, 1144, 1134, 1135, - 1136, 1137, 1139, 1140, 1152, 1133, 948, 0, 1023, 0, - 1081, 0, 947, 1254, 712, 0, 1301, 712, 1456, 1460, - 1461, 1455, 1459, 0, 1450, 1449, 1452, 1453, 0, 1494, - 1478, 0, 1475, 1169, 707, 579, 1289, 0, 583, 1499, - 161, 160, 0, 213, 0, 552, 551, 618, 610, 612, - 618, 0, 550, 0, 667, 668, 0, 0, 0, 0, - 700, 698, 1297, 1310, 655, 628, 654, 0, 0, 632, - 0, 659, 926, 693, 534, 622, 623, 626, 533, 0, - 696, 0, 706, 0, 571, 573, 556, 570, 568, 553, - 561, 694, 627, 0, 1501, 0, 0, 1465, 1526, 0, - 0, 0, 0, 0, 1664, 0, 0, 808, 84, 65, - 323, 139, 0, 0, 0, 0, 0, 0, 0, 92, - 89, 90, 91, 0, 0, 0, 0, 1317, 234, 235, - 248, 0, 239, 240, 237, 241, 242, 0, 0, 227, - 228, 0, 0, 0, 0, 226, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1509, 1502, 1229, 1234, 609, - 609, 609, 0, 0, 0, 0, 607, 608, 0, 0, - 0, 0, 0, 484, 369, 379, 0, 0, 0, 1342, - 206, 0, 0, 0, 0, 0, 0, 406, 1345, 1343, - 1341, 1344, 1346, 1634, 190, 0, 0, 0, 0, 0, - 198, 201, 0, 368, 342, 0, 0, 1357, 0, 0, - 457, 455, 458, 447, 460, 450, 0, 1664, 358, 1354, - 0, 1506, 0, 0, 253, 443, 1322, 0, 440, 443, - 1288, 0, 443, 221, 0, 0, 1390, 1433, 231, 251, - 232, 252, 499, 494, 524, 0, 502, 507, 482, 0, - 482, 0, 504, 508, 482, 503, 0, 482, 498, 0, - 1073, 0, 1063, 0, 0, 786, 0, 0, 1064, 999, - 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1017, - 1016, 1065, 790, 0, 793, 0, 0, 1203, 1204, 0, - 1066, 0, 0, 1210, 0, 0, 0, 1071, 0, 728, - 0, 0, 634, 635, 643, 639, 646, 0, 649, 636, - 585, 541, 1655, 1695, 0, 596, 596, 596, 594, 584, - 0, 671, 729, 0, 0, 0, 752, 0, 0, 754, - 756, 0, 0, 759, 0, 735, 734, 0, 0, 0, - 0, 798, 0, 1293, 0, 0, 197, 0, 0, 0, - 823, 0, 0, 0, 813, 809, 0, 905, 906, 907, - 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, - 829, 1330, 0, 835, 1333, 0, 1334, 1335, 1332, 1329, - 1336, 1337, 0, 0, 0, 0, 1221, 1217, 0, 0, - 0, 0, 1123, 1125, 1127, 0, 867, 866, 1132, 1138, - 1141, 1145, 1146, 1147, 1142, 1143, 1144, 1134, 1135, 1136, - 1137, 1139, 1140, 0, 1160, 0, 1114, 0, 0, 0, - 0, 0, 0, 0, 1261, 1260, 0, 1284, 0, 1046, - 1030, 0, 0, 1121, 1047, 1268, 1258, 1236, 0, 0, - 0, 1306, 1305, 927, 936, 939, 971, 972, 943, 944, - 945, 949, 1328, 1327, 1255, 0, 1247, 0, 0, 928, - 953, 958, 0, 1212, 1215, 988, 1214, 0, 976, 0, - 966, 0, 974, 978, 954, 969, 0, 950, 0, 1248, - 1157, 1159, 0, 1155, 0, 940, 941, 942, 932, 933, - 934, 935, 937, 938, 946, 1131, 1129, 1130, 0, 1234, - 0, 1246, 0, 0, 1083, 0, 0, 973, 1252, 0, - 797, 609, 797, 0, 925, 1495, 1325, 1488, 1325, 1477, - 1167, 1290, 1324, 581, 0, 0, 0, 1497, 147, 151, - 0, 1235, 181, 183, 712, 0, 616, 617, 621, 0, - 0, 621, 600, 549, 1909, 1790, 0, 0, 0, 0, - 660, 701, 0, 692, 657, 658, 0, 656, 1297, 661, - 1296, 662, 665, 666, 633, 1285, 702, 704, 0, 697, - 0, 1291, 555, 574, 0, 0, 0, 0, 0, 538, - 537, 708, 1472, 1472, 1474, 1473, 0, 50, 0, 1664, + 222, 406, 0, 156, 0, 1375, 1385, 1394, 1390, 1384, + 1392, 1382, 1398, 1388, 1374, 1396, 1383, 1387, 1380, 1397, + 1378, 1395, 1393, 1381, 1389, 1373, 1377, 1364, 1369, 1401, + 1391, 1399, 1386, 1400, 1402, 1376, 1403, 1379, 0, 1346, + 0, 1863, 1914, 1868, 0, 1881, 0, 1884, 1885, 1769, + 1892, 1895, 1896, 1897, 1898, 0, 777, 115, 110, 761, + 0, 542, 712, 722, 761, 766, 1050, 789, 1051, 0, + 117, 1448, 1447, 1441, 195, 1308, 1494, 1634, 1674, 1786, + 1893, 1815, 1837, 1512, 1495, 1488, 1493, 262, 603, 601, + 0, 1242, 1634, 1674, 1773, 1786, 1893, 1837, 1420, 1425, + 0, 268, 1514, 1499, 0, 1500, 115, 548, 595, 0, + 269, 1462, 0, 1467, 0, 1749, 575, 578, 1302, 576, + 540, 0, 0, 1, 156, 0, 162, 0, 599, 599, + 0, 599, 0, 532, 0, 0, 540, 535, 539, 709, + 1368, 1477, 0, 1511, 1893, 1815, 1498, 1501, 1643, 0, + 0, 1643, 0, 1643, 0, 1643, 0, 0, 1487, 0, + 258, 1226, 0, 1272, 118, 0, 0, 1357, 1353, 1358, + 1354, 1359, 1352, 1351, 1360, 1356, 0, 0, 0, 371, + 404, 403, 402, 401, 406, 1643, 1319, 0, 206, 462, + 463, 0, 0, 0, 0, 0, 1330, 109, 107, 1643, + 1482, 433, 434, 0, 423, 419, 421, 0, 0, 1643, + 1297, 443, 439, 1643, 443, 1264, 1643, 0, 0, 214, + 0, 399, 1366, 1404, 2035, 1418, 0, 1419, 1409, 1372, + 1405, 1406, 156, 0, 499, 1343, 0, 0, 0, 1172, + 761, 766, 0, 0, 779, 0, 1192, 0, 1198, 0, + 0, 0, 761, 547, 0, 722, 778, 111, 0, 759, + 760, 650, 650, 604, 0, 585, 771, 0, 0, 774, + 772, 0, 774, 0, 0, 0, 774, 770, 730, 0, + 650, 0, 759, 762, 650, 0, 781, 1363, 0, 0, + 0, 0, 1491, 1489, 1490, 1496, 0, 1492, 0, 0, + 1274, 1276, 1277, 1140, 1287, 1028, 0, 1858, 1859, 1860, + 1215, 1861, 1862, 1864, 1865, 1866, 986, 1607, 1867, 1285, + 1869, 1871, 1872, 1874, 1875, 1876, 1877, 1878, 1879, 0, + 1286, 1882, 1712, 1887, 1888, 1890, 1893, 1894, 1284, 1899, + 0, 0, 0, 1253, 1163, 0, 1027, 0, 0, 0, + 1219, 1227, 1020, 0, 0, 825, 826, 847, 848, 827, + 853, 854, 856, 828, 0, 1249, 920, 1016, 1237, 1025, + 1033, 1029, 1030, 1070, 1031, 1049, 1034, 1107, 1026, 0, + 1032, 1018, 1245, 585, 1243, 0, 1019, 1273, 585, 1241, + 1423, 1421, 1428, 1422, 0, 1424, 0, 0, 0, 259, + 0, 111, 1470, 1469, 1461, 1459, 1460, 1458, 1457, 1464, + 0, 1466, 1369, 1158, 1160, 0, 577, 0, 0, 0, + 529, 528, 530, 3, 0, 0, 0, 1624, 0, 597, + 598, 0, 0, 0, 0, 0, 0, 0, 0, 693, + 624, 625, 627, 690, 694, 702, 0, 0, 0, 0, + 0, 536, 0, 1302, 1449, 1510, 1504, 1502, 0, 0, + 0, 140, 140, 0, 0, 0, 0, 0, 100, 49, + 93, 0, 0, 0, 0, 236, 249, 0, 0, 0, + 0, 0, 246, 0, 0, 229, 51, 223, 225, 0, + 140, 0, 47, 0, 0, 0, 53, 1485, 0, 499, + 266, 267, 1225, 0, 120, 121, 119, 112, 0, 2049, + 1911, 1912, 1913, 1914, 1864, 1915, 1916, 0, 1917, 1918, + 1870, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1877, + 1929, 1930, 1931, 1932, 1933, 1934, 2075, 1935, 1891, 1937, + 1897, 0, 1938, 1042, 1166, 609, 1164, 1303, 0, 113, + 1290, 0, 1355, 0, 0, 0, 0, 497, 0, 0, + 0, 0, 1315, 0, 1643, 207, 211, 0, 1643, 202, + 1643, 371, 0, 1643, 371, 1643, 0, 1329, 1332, 0, + 436, 431, 429, 428, 430, 1643, 255, 0, 0, 1298, + 441, 442, 0, 410, 0, 0, 412, 0, 0, 219, + 0, 217, 0, 406, 156, 0, 230, 1414, 1415, 1413, + 0, 0, 1408, 1371, 233, 250, 1417, 1407, 1416, 1370, + 1365, 0, 0, 1361, 485, 0, 0, 0, 1173, 896, + 895, 877, 878, 893, 894, 879, 880, 887, 888, 898, + 897, 885, 886, 881, 882, 875, 876, 891, 892, 883, + 884, 889, 890, 873, 874, 1187, 1174, 1175, 1176, 1177, + 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 0, + 0, 721, 719, 0, 0, 0, 0, 0, 0, 1219, + 0, 991, 1026, 0, 0, 0, 1158, 1197, 0, 0, + 0, 0, 0, 0, 1158, 1203, 0, 0, 745, 757, + 0, 643, 649, 720, 718, 0, 1242, 713, 0, 791, + 0, 771, 0, 770, 0, 0, 773, 767, 0, 768, + 0, 0, 0, 0, 769, 0, 0, 0, 0, 0, + 716, 0, 757, 0, 717, 788, 1431, 1439, 196, 0, + 1294, 1939, 1940, 1941, 835, 1942, 864, 842, 864, 864, + 1943, 1944, 1945, 1946, 831, 831, 844, 1947, 1948, 1949, + 1950, 1951, 832, 833, 869, 1952, 1953, 1954, 1955, 1956, + 0, 0, 1957, 864, 1958, 831, 1959, 1960, 1961, 836, + 1962, 799, 1963, 0, 1964, 834, 800, 1965, 872, 872, + 1966, 0, 859, 1967, 0, 1169, 809, 817, 818, 819, + 820, 845, 846, 821, 851, 852, 822, 919, 0, 831, + 1295, 1296, 156, 1497, 1513, 0, 1163, 1035, 863, 850, + 1214, 0, 858, 857, 0, 1163, 840, 839, 838, 1022, + 0, 837, 1120, 864, 864, 862, 945, 841, 0, 0, + 0, 0, 0, 868, 0, 866, 946, 924, 925, 0, + 0, 1252, 1261, 1158, 1162, 0, 1020, 1158, 0, 1037, + 1038, 0, 1110, 1112, 0, 0, 1220, 1275, 1021, 0, + 1280, 0, 0, 919, 919, 1248, 1140, 0, 1130, 1133, + 0, 0, 1137, 1138, 1139, 0, 0, 0, 1240, 0, + 1148, 1150, 0, 0, 961, 1146, 0, 964, 0, 0, + 0, 0, 1134, 1135, 1136, 1126, 1127, 1128, 1129, 1131, + 1132, 1144, 1125, 942, 0, 1017, 0, 1073, 0, 941, + 1246, 711, 0, 1278, 711, 1433, 1437, 1438, 1432, 1436, + 0, 1427, 1426, 1429, 1430, 1515, 0, 1471, 1455, 0, + 1452, 1161, 706, 579, 1266, 0, 583, 1476, 161, 160, + 0, 213, 0, 552, 551, 618, 610, 612, 618, 0, + 550, 0, 666, 667, 0, 0, 0, 0, 699, 697, + 1274, 1287, 654, 628, 653, 0, 0, 632, 0, 658, + 920, 692, 534, 622, 623, 626, 533, 0, 695, 0, + 705, 0, 571, 573, 556, 570, 568, 553, 561, 693, + 627, 0, 1478, 0, 0, 1442, 1503, 0, 0, 0, + 0, 0, 1643, 0, 0, 802, 84, 65, 323, 139, + 0, 0, 0, 0, 0, 0, 0, 92, 89, 90, + 91, 0, 0, 0, 0, 1294, 234, 235, 248, 0, + 239, 240, 237, 241, 242, 0, 0, 227, 228, 0, + 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1486, 1479, 1221, 1226, 609, 609, 609, + 0, 607, 608, 0, 0, 0, 0, 0, 484, 369, + 379, 0, 0, 0, 1319, 206, 0, 0, 0, 0, + 0, 0, 406, 1322, 1320, 1318, 1321, 1323, 1613, 190, + 0, 0, 0, 0, 0, 198, 201, 0, 368, 342, + 0, 0, 1334, 0, 0, 457, 455, 458, 447, 460, + 450, 0, 1643, 358, 1331, 0, 1483, 0, 0, 253, + 443, 1299, 0, 440, 443, 1265, 0, 443, 221, 0, + 0, 1367, 1410, 231, 251, 232, 252, 499, 494, 524, + 0, 502, 507, 482, 0, 482, 0, 504, 508, 482, + 503, 0, 482, 498, 0, 1065, 0, 1055, 0, 0, + 780, 0, 0, 1056, 993, 994, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1011, 1010, 1057, 784, 0, 787, + 0, 0, 1195, 1196, 0, 1058, 0, 0, 1202, 0, + 0, 0, 1063, 0, 723, 0, 0, 0, 638, 642, + 645, 0, 648, 585, 541, 1634, 1674, 0, 596, 596, + 596, 594, 584, 0, 670, 0, 0, 0, 746, 0, + 0, 748, 750, 0, 0, 753, 0, 729, 728, 0, + 0, 0, 0, 792, 0, 1270, 0, 0, 197, 0, + 0, 0, 817, 0, 0, 0, 807, 803, 0, 899, + 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, + 910, 911, 823, 1307, 0, 829, 1310, 0, 1311, 1312, + 1309, 1306, 1313, 1314, 0, 0, 0, 0, 1213, 1209, + 0, 0, 0, 0, 1115, 1117, 1119, 0, 861, 860, + 1124, 1130, 1133, 1137, 1138, 1139, 1134, 1135, 1136, 1126, + 1127, 1128, 1129, 1131, 1132, 0, 1152, 0, 1106, 0, + 0, 0, 0, 0, 0, 0, 1251, 0, 989, 0, + 1039, 1024, 0, 0, 1113, 1040, 1253, 1228, 0, 0, + 0, 1283, 1282, 921, 930, 933, 965, 966, 937, 938, + 939, 943, 1305, 1304, 1247, 0, 1239, 0, 0, 922, + 947, 952, 0, 1204, 1207, 982, 1206, 0, 970, 0, + 960, 0, 968, 972, 948, 963, 0, 944, 0, 1240, + 1149, 1151, 0, 1147, 0, 934, 935, 936, 926, 927, + 928, 929, 931, 932, 940, 1123, 1121, 1122, 0, 1226, + 0, 1238, 0, 0, 1075, 0, 0, 967, 1244, 0, + 791, 609, 791, 0, 919, 1472, 1302, 1465, 1302, 1454, + 1159, 1267, 1301, 581, 0, 0, 0, 1474, 147, 151, + 0, 1227, 181, 183, 711, 0, 616, 617, 621, 0, + 0, 621, 600, 549, 1888, 1769, 0, 0, 0, 0, + 659, 700, 0, 691, 656, 657, 0, 655, 1274, 660, + 1273, 661, 664, 665, 633, 1262, 701, 703, 0, 696, + 0, 1268, 555, 574, 0, 0, 0, 0, 0, 538, + 537, 707, 1449, 1449, 1451, 1450, 0, 50, 0, 1643, 67, 0, 0, 0, 0, 0, 0, 273, 0, 373, - 273, 105, 1664, 443, 1664, 443, 1558, 1629, 1808, 0, + 273, 105, 1643, 443, 1643, 443, 1537, 1608, 1787, 0, 63, 347, 96, 0, 133, 376, 0, 332, 86, 101, 126, 0, 0, 52, 224, 238, 243, 129, 247, 244, - 1362, 245, 140, 0, 48, 0, 127, 0, 1360, 0, - 0, 54, 131, 1364, 1510, 0, 1233, 0, 607, 607, - 607, 605, 606, 1050, 0, 1173, 0, 1175, 1176, 966, - 1372, 1371, 1373, 1370, 470, 483, 0, 370, 0, 496, - 473, 474, 484, 1340, 211, 0, 202, 371, 0, 371, - 0, 1342, 0, 0, 192, 188, 206, 212, 0, 0, - 0, 0, 0, 369, 361, 359, 392, 0, 366, 360, - 0, 0, 318, 0, 1552, 0, 0, 0, 0, 464, - 0, 0, 0, 0, 0, 0, 255, 256, 409, 1323, - 411, 0, 413, 220, 218, 1385, 2026, 490, 1171, 0, - 488, 495, 489, 492, 493, 487, 486, 0, 481, 0, - 517, 0, 0, 0, 0, 0, 0, 0, 0, 1060, - 1179, 0, 1198, 1197, 998, 1005, 1008, 1012, 1013, 1014, - 1199, 0, 0, 0, 1009, 1010, 1011, 1001, 1002, 1003, - 1004, 1006, 1007, 1015, 795, 0, 0, 789, 1208, 1207, - 1201, 1202, 0, 1068, 1069, 1070, 1209, 0, 0, 764, - 638, 640, 637, 0, 0, 797, 596, 596, 596, 596, - 593, 0, 0, 0, 796, 0, 688, 760, 758, 0, - 782, 0, 755, 0, 761, 0, 746, 0, 753, 802, - 769, 0, 0, 771, 1463, 819, 0, 814, 810, 0, - 0, 0, 820, 0, 0, 0, 0, 0, 0, 0, - 1178, 0, 602, 1044, 0, 0, 0, 1218, 0, 994, - 836, 849, 0, 1126, 1048, 0, 1149, 1113, 877, 876, - 878, 878, 0, 1263, 1265, 0, 0, 0, 0, 1275, - 0, 995, 1226, 0, 1074, 1224, 1167, 1117, 1119, 1276, - 1029, 861, 925, 0, 0, 0, 0, 0, 0, 0, - 977, 968, 0, 975, 979, 0, 0, 0, 962, 0, - 0, 960, 989, 956, 0, 0, 990, 1233, 0, 1237, - 0, 0, 1082, 1091, 715, 711, 671, 607, 671, 0, - 1457, 1479, 1476, 582, 156, 1498, 0, 170, 0, 0, - 0, 0, 173, 187, 184, 1497, 0, 0, 611, 613, - 0, 1150, 621, 615, 664, 663, 0, 631, 699, 629, - 0, 705, 0, 572, 0, 558, 0, 738, 0, 0, - 1466, 1467, 0, 0, 0, 322, 0, 0, 0, 273, - 0, 381, 0, 388, 0, 0, 373, 354, 85, 0, - 0, 0, 59, 104, 77, 69, 55, 83, 0, 0, - 88, 0, 81, 98, 99, 97, 102, 0, 283, 308, - 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 499, 1234, 1230, 1234, 0, 0, - 0, 609, 1051, 0, 469, 523, 520, 521, 519, 229, - 380, 0, 0, 0, 200, 368, 0, 1357, 449, 452, - 1339, 406, 0, 193, 0, 191, 211, 0, 0, 202, - 371, 0, 346, 342, 367, 340, 339, 341, 0, 1553, - 222, 0, 1547, 371, 1356, 0, 0, 465, 456, 0, - 461, 0, 0, 459, 0, 1351, 254, 443, 0, 477, - 518, 525, 505, 510, 0, 516, 512, 511, 506, 514, - 513, 509, 1061, 1072, 1196, 0, 0, 0, 0, 788, - 791, 0, 1067, 1062, 762, 0, 0, 671, 0, 0, - 0, 0, 587, 586, 592, 0, 0, 1085, 757, 0, - 0, 0, 744, 733, 739, 740, 0, 0, 0, 800, - 799, 770, 823, 0, 803, 823, 0, 823, 0, 821, - 0, 830, 918, 919, 920, 921, 922, 923, 924, 855, - 0, 1220, 1216, 1122, 1124, 1161, 873, 871, 993, 1266, - 1259, 1262, 1166, 1270, 1272, 0, 0, 0, 0, 1283, - 0, 0, 1116, 1284, 1304, 929, 0, 0, 959, 1213, - 980, 0, 0, 0, 955, 1149, 0, 0, 0, 0, - 0, 964, 0, 1241, 1234, 0, 1240, 0, 0, 0, - 0, 1056, 716, 688, 0, 688, 0, 0, 1496, 0, - 1491, 148, 149, 150, 0, 0, 0, 165, 142, 0, - 0, 182, 170, 158, 619, 620, 0, 614, 630, 1286, - 1292, 557, 0, 1026, 0, 0, 554, 0, 134, 273, - 0, 0, 66, 0, 390, 334, 382, 365, 349, 0, - 0, 0, 274, 0, 407, 0, 0, 355, 0, 0, - 0, 0, 335, 0, 0, 294, 0, 0, 365, 0, - 372, 290, 291, 0, 58, 78, 0, 74, 0, 103, - 0, 0, 0, 0, 0, 61, 73, 0, 56, 808, - 443, 443, 64, 1317, 1960, 1961, 1962, 1963, 1964, 1965, - 1966, 1967, 1968, 1969, 2080, 1970, 1971, 1972, 1973, 1974, - 1975, 1976, 1977, 2089, 1978, 280, 1979, 1733, 1980, 1981, - 1982, 1983, 1984, 0, 1985, 806, 1986, 1987, 2168, 1988, - 1134, 1135, 279, 278, 375, 275, 383, 277, 0, 1318, - 276, 378, 333, 130, 1363, 0, 128, 0, 1361, 137, - 135, 132, 1365, 1503, 0, 0, 1054, 1055, 1052, 607, - 0, 0, 0, 499, 476, 0, 0, 0, 1552, 0, - 0, 1664, 0, 189, 0, 0, 203, 1357, 199, 368, - 0, 398, 318, 393, 0, 1552, 1550, 0, 1357, 1546, - 448, 451, 0, 0, 540, 453, 0, 0, 0, 414, - 491, 0, 515, 1018, 0, 0, 0, 0, 647, 0, - 653, 688, 591, 590, 589, 588, 670, 1603, 1892, 1789, - 0, 674, 669, 672, 677, 679, 678, 680, 676, 687, - 0, 690, 781, 1162, 1164, 0, 0, 0, 0, 745, - 747, 0, 749, 0, 801, 817, 0, 818, 0, 816, - 811, 822, 1219, 1264, 1273, 1274, 1269, 1278, 1280, 0, - 0, 0, 926, 1225, 996, 986, 984, 981, 0, 982, - 963, 0, 0, 961, 957, 0, 991, 0, 0, 1238, - 0, 1077, 0, 1080, 1094, 1090, 1089, 1085, 1051, 1085, - 1458, 580, 169, 146, 172, 171, 0, 1235, 179, 0, - 0, 170, 0, 174, 466, 0, 0, 569, 737, 562, - 563, 0, 386, 68, 0, 365, 0, 273, 351, 350, - 353, 348, 352, 0, 408, 0, 0, 292, 0, 299, - 337, 338, 336, 293, 365, 371, 295, 0, 0, 0, - 70, 60, 57, 62, 71, 0, 0, 72, 75, 802, - 807, 87, 80, 1317, 2089, 2098, 0, 0, 0, 0, - 0, 1232, 1231, 0, 472, 471, 522, 468, 479, 229, - 0, 0, 0, 342, 1549, 0, 0, 0, 368, 194, - 0, 0, 0, 0, 1552, 0, 0, 270, 0, 315, - 0, 215, 1551, 0, 0, 1538, 0, 0, 1349, 1350, - 0, 478, 1019, 0, 1020, 792, 0, 0, 645, 1085, - 0, 0, 0, 681, 675, 0, 1084, 1086, 0, 642, - 1165, 741, 0, 743, 0, 767, 0, 767, 750, 812, - 804, 1271, 1281, 1282, 1277, 1075, 0, 983, 987, 985, - 965, 1234, 1242, 1234, 1239, 1079, 1093, 1096, 690, 1302, - 690, 0, 0, 157, 0, 0, 154, 141, 159, 1151, - 559, 560, 0, 273, 0, 364, 387, 304, 282, 0, - 0, 0, 289, 296, 397, 298, 0, 79, 95, 0, - 0, 377, 138, 136, 1053, 499, 0, 205, 1357, 318, - 1546, 0, 0, 0, 0, 342, 222, 1548, 331, 324, - 325, 326, 327, 328, 329, 330, 345, 344, 316, 317, - 0, 0, 0, 0, 454, 1351, 0, 176, 185, 0, - 176, 1021, 648, 0, 690, 0, 0, 0, 673, 0, - 0, 689, 0, 545, 1163, 0, 732, 730, 0, 731, - 1279, 0, 0, 0, 0, 609, 642, 642, 143, 0, - 144, 180, 0, 0, 0, 371, 389, 363, 0, 356, - 302, 301, 303, 307, 0, 305, 0, 321, 0, 314, - 282, 0, 82, 0, 384, 467, 475, 0, 272, 1540, - 368, 0, 204, 1546, 318, 1552, 1546, 0, 1543, 0, - 0, 0, 0, 178, 1357, 0, 178, 0, 642, 683, - 0, 682, 1088, 1087, 644, 742, 0, 1076, 1244, 1243, - 0, 1100, 544, 543, 0, 0, 0, 0, 397, 0, - 343, 0, 0, 304, 0, 297, 394, 395, 396, 0, - 310, 300, 311, 76, 94, 385, 0, 368, 1541, 271, - 216, 1539, 1544, 1545, 0, 176, 175, 618, 177, 797, - 186, 618, 652, 546, 684, 641, 748, 1095, 0, 0, - 0, 0, 0, 153, 797, 164, 0, 314, 362, 357, - 281, 306, 320, 0, 0, 0, 312, 0, 313, 1546, - 0, 178, 621, 1347, 621, 1878, 1604, 1843, 0, 1112, - 1101, 1112, 1112, 1092, 145, 152, 0, 273, 286, 0, - 285, 0, 374, 309, 1542, 1357, 618, 166, 167, 0, - 1105, 1104, 1103, 1107, 1106, 0, 1099, 1097, 1098, 797, - 391, 284, 288, 287, 797, 621, 0, 0, 1109, 0, - 1110, 163, 1348, 168, 1102, 1108, 1111 + 1339, 245, 140, 0, 48, 0, 127, 0, 1337, 0, + 0, 54, 131, 1341, 1487, 0, 1225, 0, 607, 607, + 607, 0, 1165, 0, 0, 0, 1167, 1168, 960, 1349, + 1348, 1350, 1347, 470, 483, 0, 370, 0, 496, 473, + 474, 484, 1317, 211, 0, 202, 371, 0, 371, 0, + 1319, 0, 0, 192, 188, 206, 212, 0, 0, 0, + 0, 0, 369, 361, 359, 392, 0, 366, 360, 0, + 0, 318, 0, 1531, 0, 0, 0, 0, 464, 0, + 0, 0, 0, 0, 0, 255, 256, 409, 1300, 411, + 0, 413, 220, 218, 1362, 2005, 490, 1163, 0, 488, + 495, 489, 492, 493, 487, 486, 0, 481, 0, 517, + 0, 0, 0, 0, 0, 0, 0, 0, 1052, 1171, + 0, 1190, 1189, 992, 999, 1002, 1006, 1007, 1008, 1191, + 0, 0, 0, 1003, 1004, 1005, 995, 996, 997, 998, + 1000, 1001, 1009, 789, 0, 0, 783, 1200, 1199, 1193, + 1194, 0, 1060, 1061, 1062, 1201, 0, 0, 758, 636, + 634, 637, 639, 635, 0, 0, 791, 596, 596, 596, + 596, 593, 0, 0, 0, 790, 0, 687, 754, 752, + 0, 776, 0, 749, 0, 755, 0, 740, 0, 747, + 796, 763, 0, 0, 765, 1440, 813, 0, 808, 804, + 0, 0, 0, 814, 0, 0, 0, 0, 0, 0, + 0, 1170, 0, 602, 1036, 0, 0, 0, 1210, 0, + 988, 830, 843, 0, 1118, 1041, 0, 1141, 1105, 871, + 870, 872, 872, 0, 0, 0, 0, 1260, 1218, 0, + 1066, 1216, 1159, 1109, 1111, 1261, 1023, 855, 919, 0, + 0, 0, 0, 0, 0, 0, 971, 962, 0, 969, + 973, 0, 0, 0, 956, 0, 0, 954, 983, 950, + 0, 0, 984, 1225, 0, 1229, 0, 0, 1074, 1083, + 714, 710, 670, 607, 670, 0, 1434, 1456, 1453, 582, + 156, 1475, 0, 170, 0, 0, 0, 0, 173, 187, + 184, 1474, 0, 0, 611, 613, 0, 1142, 621, 615, + 663, 662, 0, 631, 698, 629, 0, 704, 0, 572, + 0, 558, 0, 732, 0, 0, 1443, 1444, 0, 0, + 0, 322, 0, 0, 0, 273, 0, 381, 0, 388, + 0, 0, 373, 354, 85, 0, 0, 0, 59, 104, + 77, 69, 55, 83, 0, 0, 88, 0, 81, 98, + 99, 97, 102, 0, 283, 308, 0, 0, 319, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 499, 1226, 1222, 1226, 0, 0, 0, 609, 605, 606, + 1043, 0, 469, 523, 520, 521, 519, 229, 380, 0, + 0, 0, 200, 368, 0, 1334, 449, 452, 1316, 406, + 0, 193, 0, 191, 211, 0, 0, 202, 371, 0, + 346, 342, 367, 340, 339, 341, 0, 1532, 222, 0, + 1526, 371, 1333, 0, 0, 465, 456, 0, 461, 0, + 0, 459, 0, 1328, 254, 443, 0, 477, 518, 525, + 505, 510, 0, 516, 512, 511, 506, 514, 513, 509, + 1053, 1064, 1188, 0, 0, 0, 0, 782, 785, 0, + 1059, 1054, 756, 0, 0, 670, 0, 0, 0, 0, + 587, 586, 592, 0, 0, 1077, 751, 0, 0, 0, + 738, 727, 733, 734, 0, 0, 0, 794, 793, 764, + 817, 0, 797, 817, 0, 817, 0, 815, 0, 824, + 912, 913, 914, 915, 916, 917, 918, 849, 0, 1212, + 1208, 1114, 1116, 1153, 867, 865, 987, 1250, 1158, 1255, + 1257, 0, 0, 0, 0, 1108, 990, 1281, 923, 0, + 0, 953, 1205, 974, 0, 0, 0, 949, 1141, 0, + 0, 0, 0, 0, 958, 0, 1233, 1226, 0, 1232, + 0, 0, 0, 0, 1048, 715, 687, 0, 687, 0, + 0, 1473, 0, 1468, 148, 149, 150, 0, 0, 0, + 165, 142, 0, 0, 182, 170, 158, 619, 620, 0, + 614, 630, 1263, 1269, 557, 0, 1020, 0, 0, 554, + 0, 134, 273, 0, 0, 66, 0, 390, 334, 382, + 365, 349, 0, 0, 0, 274, 0, 407, 0, 0, + 355, 0, 0, 0, 0, 335, 0, 0, 294, 0, + 0, 365, 0, 372, 290, 291, 0, 58, 78, 0, + 74, 0, 103, 0, 0, 0, 0, 0, 61, 73, + 0, 56, 0, 443, 443, 64, 1294, 1939, 1940, 1941, + 1942, 1943, 1944, 1945, 1946, 1947, 1948, 2059, 1949, 1950, + 1951, 1952, 1953, 1954, 1955, 1956, 2068, 1957, 280, 1958, + 1712, 1959, 1960, 1961, 1962, 1963, 0, 1964, 800, 1965, + 1966, 2147, 1967, 1126, 1127, 279, 278, 375, 275, 383, + 277, 0, 1295, 276, 378, 333, 130, 1340, 0, 128, + 0, 1338, 137, 135, 132, 1342, 1480, 0, 0, 1046, + 1047, 1044, 607, 0, 0, 0, 499, 476, 0, 0, + 0, 1531, 0, 0, 1643, 0, 189, 0, 0, 203, + 1334, 199, 368, 0, 398, 318, 393, 0, 1531, 1529, + 0, 1334, 1525, 448, 451, 0, 0, 540, 453, 0, + 0, 0, 414, 491, 0, 515, 1012, 0, 0, 0, + 0, 646, 0, 652, 687, 591, 590, 589, 588, 669, + 1582, 1871, 1768, 0, 673, 668, 671, 676, 678, 677, + 679, 675, 686, 0, 689, 775, 1154, 1156, 0, 0, + 0, 0, 739, 741, 0, 743, 0, 795, 811, 0, + 812, 0, 810, 805, 816, 1211, 1258, 1259, 1254, 0, + 920, 1217, 980, 978, 975, 0, 976, 957, 0, 0, + 955, 951, 0, 985, 0, 0, 1230, 0, 1069, 0, + 1072, 1086, 1082, 1081, 1077, 1043, 1077, 1435, 580, 169, + 146, 172, 171, 0, 1227, 179, 0, 0, 170, 0, + 174, 466, 0, 0, 569, 731, 562, 563, 0, 386, + 68, 0, 365, 0, 273, 351, 350, 353, 348, 352, + 0, 408, 0, 0, 292, 0, 299, 337, 338, 336, + 293, 365, 371, 295, 0, 0, 0, 70, 60, 57, + 62, 71, 0, 0, 72, 75, 796, 87, 80, 1294, + 2068, 2077, 0, 0, 0, 0, 0, 1224, 1223, 0, + 472, 471, 522, 468, 479, 229, 0, 0, 0, 342, + 1528, 0, 0, 0, 368, 194, 0, 0, 0, 0, + 1531, 0, 0, 270, 0, 315, 0, 215, 1530, 0, + 0, 1517, 0, 0, 1326, 1327, 0, 478, 1013, 0, + 1014, 786, 0, 0, 644, 1077, 0, 0, 0, 680, + 674, 0, 1076, 1078, 0, 641, 1157, 735, 0, 737, + 0, 761, 0, 761, 744, 806, 798, 1256, 1067, 0, + 977, 981, 979, 959, 1226, 1234, 1226, 1231, 1071, 1085, + 1088, 689, 1279, 689, 0, 0, 157, 0, 0, 154, + 141, 159, 1143, 559, 560, 0, 273, 0, 364, 387, + 304, 282, 0, 0, 0, 289, 296, 397, 298, 0, + 79, 95, 0, 0, 377, 138, 136, 1045, 499, 0, + 205, 1334, 318, 1525, 0, 0, 0, 0, 342, 222, + 1527, 331, 324, 325, 326, 327, 328, 329, 330, 345, + 344, 316, 317, 0, 0, 0, 0, 454, 1328, 0, + 176, 185, 0, 176, 1015, 647, 0, 689, 0, 0, + 0, 672, 0, 0, 688, 0, 545, 1155, 0, 726, + 724, 0, 725, 0, 0, 0, 0, 609, 641, 641, + 143, 0, 144, 180, 0, 0, 0, 371, 389, 363, + 0, 356, 302, 301, 303, 307, 0, 305, 0, 321, + 0, 314, 282, 0, 82, 0, 384, 467, 475, 0, + 272, 1519, 368, 0, 204, 1525, 318, 1531, 1525, 0, + 1522, 0, 0, 0, 0, 178, 1334, 0, 178, 0, + 641, 682, 0, 681, 1080, 1079, 643, 736, 0, 1068, + 1236, 1235, 0, 1092, 544, 543, 0, 0, 0, 0, + 397, 0, 343, 0, 0, 304, 0, 297, 394, 395, + 396, 0, 310, 300, 311, 76, 94, 385, 0, 368, + 1520, 271, 216, 1518, 1523, 1524, 0, 176, 175, 618, + 177, 791, 186, 618, 651, 546, 683, 640, 742, 1087, + 0, 0, 0, 0, 0, 153, 791, 164, 0, 314, + 362, 357, 281, 306, 320, 0, 0, 0, 312, 0, + 313, 1525, 0, 178, 621, 1324, 621, 1857, 1583, 1822, + 0, 1104, 1093, 1104, 1104, 1084, 145, 152, 0, 273, + 286, 0, 285, 0, 374, 309, 1521, 1334, 618, 166, + 167, 0, 1097, 1096, 1095, 1099, 1098, 0, 1091, 1089, + 1090, 791, 391, 284, 288, 287, 791, 621, 0, 0, + 1101, 0, 1102, 163, 1325, 168, 1094, 1100, 1103 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 47, 48, 49, 755, 2664, 2665, 2666, 2289, 1225, - 3452, 2290, 1226, 1227, 2668, 756, 806, 1169, 855, 1107, - 1629, 915, 1261, 1262, 757, 1783, 758, 2897, 2209, 2610, - 3434, 54, 3178, 2212, 1183, 3181, 3398, 2890, 3176, 2611, - 3473, 3527, 3179, 2213, 2214, 3399, 2215, 759, 2724, 2725, - 760, 761, 1870, 58, 1324, 551, 1867, 762, 763, 1357, - 1358, 970, 764, 1871, 1811, 3013, 1245, 1801, 1372, 62, - 1894, 765, 107, 911, 64, 766, 2653, 3014, 3445, 2679, - 3582, 2950, 2951, 3442, 3443, 2656, 2292, 3510, 3511, 2739, - 1792, 3505, 2374, 3386, 2296, 2277, 2952, 2382, 3345, 3061, - 2293, 2932, 2375, 3438, 1889, 2376, 3439, 3197, 2377, 1845, - 1874, 2657, 3512, 2297, 1846, 2652, 3015, 1780, 2378, 3449, - 2379, 552, 2936, 767, 746, 747, 962, 1351, 748, 768, - 1880, 1881, 1882, 1883, 1884, 1885, 946, 1886, 769, 770, - 2704, 2352, 3249, 2758, 3250, 2419, 2346, 1381, 2411, 1914, - 1848, 1382, 540, 1928, 2759, 2709, 1915, 771, 1108, 72, - 73, 1017, 74, 3191, 75, 76, 1754, 1755, 1756, 857, - 867, 868, 2205, 1467, 1999, 860, 1188, 1723, 841, 842, - 1834, 883, 1837, 1718, 1719, 2218, 2618, 1747, 1748, 1197, - 1198, 1985, 1986, 3413, 1987, 1988, 1460, 1461, 3288, 1735, - 1739, 1740, 2239, 2229, 1726, 2486, 3101, 3102, 3103, 3104, - 3105, 3106, 3107, 1109, 2797, 3299, 1743, 1744, 1200, 1201, - 1202, 1752, 2249, 78, 79, 2190, 2594, 2595, 812, 813, - 3118, 1490, 1757, 2801, 2802, 2803, 3121, 3122, 3123, 814, - 1012, 1013, 1040, 1035, 1479, 2009, 815, 816, 1962, 1963, - 2457, 1042, 2001, 2020, 2021, 2809, 2510, 1556, 2278, 1557, - 1558, 2035, 1559, 1110, 1560, 1588, 1111, 1593, 1562, 1112, - 1113, 1114, 1565, 1115, 1116, 1117, 1118, 1581, 1119, 1120, - 1605, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, - 2046, 2047, 2048, 2049, 2050, 1170, 1758, 1122, 1123, 1124, - 1125, 1126, 1127, 1128, 1129, 1130, 1131, 818, 1132, 2553, - 1133, 1680, 2184, 2593, 3111, 3296, 3297, 2881, 3166, 3327, - 3425, 3541, 3569, 3570, 3596, 1134, 1135, 1624, 1625, 1626, - 2072, 2073, 2074, 2075, 2178, 1674, 1675, 1136, 3017, 1677, - 2095, 3114, 3115, 1171, 1453, 1617, 1303, 1304, 1570, 1427, - 1428, 1434, 1937, 1442, 1446, 1967, 1968, 1454, 2145, 1137, - 2066, 2067, 2528, 1583, 2554, 2555, 1138, 1260, 1630, 2876, - 2181, 1678, 2138, 1145, 1139, 1146, 1141, 1613, 2848, 2544, - 2545, 1614, 2549, 2844, 2845, 2107, 2849, 3138, 3139, 2551, - 2246, 1706, 2251, 2252, 966, 1142, 1143, 1144, 1305, 524, - 1571, 3528, 1347, 1176, 1306, 2134, 772, 1047, 2059, 773, - 1320, 1860, 774, 3279, 3078, 1336, 1890, 2387, 553, 775, - 776, 533, 85, 2341, 927, 86, 87, 88, 892, 1374, - 777, 1375, 1376, 977, 89, 2760, 979, 980, 779, 849, - 850, 1499, 1694, 1500, 780, 92, 824, 1767, 781, 1165, - 864, 1166, 1168, 782, 1185, 2607, 2207, 95, 96, 97, - 115, 1256, 783, 835, 836, 873, 100, 101, 1213, 837, - 785, 786, 3275, 787, 2742, 1330, 534, 526, 527, 1573, - 720, 1308, 721 + -1, 47, 48, 49, 755, 2640, 2641, 2642, 2269, 1218, + 3414, 2270, 1219, 1220, 2644, 756, 806, 1100, 808, 1101, + 1618, 914, 1254, 1255, 757, 1771, 758, 2870, 2189, 2586, + 3396, 54, 3145, 2192, 1176, 3148, 3361, 2863, 3143, 2587, + 3435, 3489, 3146, 2193, 2194, 3362, 2195, 759, 2702, 2703, + 760, 761, 1855, 58, 1316, 551, 1852, 762, 763, 1349, + 1350, 969, 764, 1856, 1799, 2986, 1238, 1789, 1364, 62, + 1879, 765, 107, 910, 64, 766, 2629, 2987, 3407, 2655, + 3544, 2923, 2924, 3404, 3405, 2632, 2272, 3472, 3473, 2717, + 1780, 3467, 2353, 3349, 2276, 2257, 2925, 2361, 3308, 3034, + 2273, 2905, 2354, 3400, 1874, 2355, 3401, 3164, 2356, 1830, + 1859, 2633, 3474, 2277, 1831, 2628, 2988, 1768, 2357, 3411, + 2358, 552, 2909, 767, 746, 747, 961, 1343, 748, 768, + 1865, 1866, 1867, 1868, 1869, 1870, 945, 1871, 769, 770, + 2682, 2331, 3215, 2736, 3216, 2398, 2325, 1373, 2390, 1899, + 1833, 1374, 540, 1913, 2737, 2687, 1900, 771, 1102, 72, + 73, 1015, 74, 3158, 75, 76, 1742, 1743, 1744, 854, + 866, 867, 2185, 1459, 1982, 859, 1181, 1711, 840, 841, + 2315, 882, 1822, 1706, 1707, 2198, 2594, 1735, 1736, 1190, + 1191, 1970, 3376, 1971, 1972, 1452, 1453, 3254, 1723, 1727, + 1728, 2219, 2209, 1714, 2467, 3074, 3075, 3076, 3077, 3078, + 3079, 3080, 1103, 2775, 3265, 1731, 1732, 1193, 1194, 1195, + 1740, 2229, 78, 79, 2170, 2570, 2571, 812, 3091, 1478, + 1745, 2779, 2780, 2781, 3094, 3095, 3096, 813, 1010, 1011, + 1034, 1029, 1467, 1991, 814, 815, 1947, 1948, 2436, 1036, + 1984, 2002, 2003, 2787, 2491, 1544, 2258, 1545, 1546, 2017, + 1547, 1104, 1548, 1576, 1105, 1581, 1550, 1106, 1107, 1108, + 1553, 1109, 1110, 1111, 1112, 1569, 1113, 1114, 1593, 2019, + 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, + 2030, 2031, 2032, 1163, 1746, 1116, 1117, 1118, 1119, 1120, + 1121, 1122, 1123, 1124, 817, 1125, 2529, 1126, 1667, 2164, + 2569, 3084, 3262, 3263, 2854, 3133, 3290, 3387, 3503, 3531, + 3532, 3558, 1127, 1128, 1612, 1613, 1614, 2054, 2055, 2056, + 2057, 2158, 1661, 1662, 1129, 2990, 1664, 2077, 3087, 3088, + 1164, 1445, 1605, 1295, 1296, 1558, 1419, 1420, 1426, 1922, + 1434, 1438, 1952, 1953, 1446, 2125, 1130, 2048, 2049, 2509, + 1571, 2530, 2531, 1131, 1253, 1617, 2849, 2161, 1665, 2118, + 1138, 1132, 1139, 1134, 1601, 1602, 2527, 2820, 2821, 2088, + 2226, 1694, 2231, 2232, 965, 1135, 1136, 1137, 1297, 524, + 1559, 3490, 1339, 1169, 1298, 2114, 772, 1041, 2041, 773, + 1312, 1845, 774, 3245, 3051, 1328, 1875, 2366, 553, 775, + 776, 533, 85, 2320, 926, 86, 87, 88, 891, 1366, + 777, 1367, 1368, 976, 89, 2738, 978, 979, 779, 848, + 849, 1487, 1681, 1488, 780, 92, 823, 1755, 781, 1159, + 863, 1160, 1162, 782, 1178, 2583, 2187, 95, 96, 97, + 115, 1249, 783, 834, 835, 872, 100, 101, 1206, 836, + 855, 785, 786, 3241, 787, 2720, 1322, 534, 526, 527, + 1561, 720, 1300, 721 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -3162 +#define YYPACT_NINF -3017 static const int yypact[] = { - 6054, 348, 823, -3162, -3162, 279, 348, 51623, 66578, 339, - 348, 118, 2095, 53619, -3162, -3162, 48130, 8709, 348, 56613, - 73974, 548, 689, 32620, 719, 57112, -3162, -3162, -3162, 66578, - 56613, 57611, 348, 359, 67077, -3162, 348, 35616, 54118, 453, - -3162, 56613, 47, 383, 58110, 56613, 3130, 946, 431, -3162, - -3162, -3162, -3162, -3162, 128, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, 159, -3162, 98, 174, 32620, 32620, 2484, 438, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 498, - -3162, -3162, 807, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, 35116, -3162, -3162, -3162, -3162, -3162, -3162, 58609, 56613, - 59108, 54617, 59607, -3162, 727, 1020, 705, 152, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - 170, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, 512, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, 182, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, 399, -3162, 535, -3162, 188, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, 1886, -3162, -3162, 961, 2952, - 56613, 715, 753, 724, -3162, 60106, -3162, 712, 56613, -3162, - -3162, 729, 1039, 901, -3162, -3162, 55116, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, 48629, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, 868, -3162, -3162, 688, -3162, 124, -3162, -3162, - 709, 686, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, 791, -3162, -3162, -3162, 805, 67576, 60605, 61104, -3162, - 674, 2617, 9200, 73992, 31620, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 498, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 57112, 66578, - 720, 731, 1013, 736, 33618, 771, 36116, 776, 802, 1032, - 810, 814, 824, 841, 383, 32120, 699, 399, 704, 61603, - 61603, -22, 33119, 3628, -3162, 61603, 62102, -3162, 798, -3162, - 1020, -3162, -3162, -3162, -3162, -99, 845, -3162, 62601, 62601, - 62601, 836, 1087, 62601, -3162, -3162, -3162, 878, -3162, -3162, - 1097, 20189, 20189, 68075, 68075, 1020, 68075, 916, 68075, -3162, - -3162, 76, 705, -3162, 399, -3162, -3162, 2484, -3162, -3162, - 54118, -3162, -3162, 270, 1250, 20189, 56613, 926, -3162, 920, - 926, 936, 949, 977, -3162, 6054, 1328, 1209, 55615, 369, - 369, 1467, 369, 662, 701, 2582, 2099, -3162, 1234, -3162, - 1015, -3162, 56613, 57112, 1116, 1042, 1323, -3162, -3162, 1400, - 786, 1204, 1423, 1991, 1431, 788, 1434, 1240, 1440, 1532, - 31, -3162, 20189, 49128, 399, -3162, 11264, 20189, -3162, -3162, - -3162, 1176, -3162, -3162, -3162, -3162, -3162, 56613, 66578, 1108, - 1132, -3162, -3162, -3162, -3162, 1530, 1377, -3162, 1614, 68574, - -3162, -3162, 1197, 63100, 63599, 64098, 64597, 1585, -3162, -3162, - 1525, -3162, -3162, -3162, 1199, -3162, -3162, -3162, 168, 69073, - 1534, 1168, 105, -3162, 1547, 119, -3162, 1562, 1426, 14939, - -3162, 1363, -3162, -3162, -3162, 383, -3162, 377, -3162, -3162, - 45231, -3162, -3162, 73992, 1293, 1210, -3162, 20189, 20189, 1214, - 6413, 61603, 62102, 20189, 56613, -3162, 20189, 24914, 1218, 20189, - 20189, 12314, 20189, 30622, 61603, 3628, 1207, -3162, 567, -3162, - 56613, 1225, -3162, 1324, 1324, 359, 32620, 1546, 32120, 1324, - 1324, 1324, -3162, 1035, 1539, 1452, -3162, 32620, 1452, 1502, - 1254, 1572, 1452, -3162, 261, 1579, 1324, 36615, 1262, -3162, - 1324, 1512, -3162, -3162, 20189, 14939, 71568, 1784, -3162, -3162, - -3162, -3162, 1591, -3162, 66578, 1318, -3162, -3162, -3162, -3162, - -3162, -3162, 772, 1845, 165, 1851, 20189, 165, 165, 1339, - 190, 190, -3162, 1538, 1341, -3162, 198, 1347, 1349, 1863, - 1864, 167, 147, 1028, 165, 20189, -3162, 190, 1352, 1866, - 1356, 1868, 197, 207, -3162, 201, 20189, 20189, 20189, 305, - 20189, 10214, -3162, 49128, 1867, 56613, 590, -3162, 399, 1359, - 1020, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 1360, -3162, - 185, 7096, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - 1394, -3162, -3162, -3162, -3162, 1577, 20189, -3162, -3162, 1358, - 1546, -3162, 205, -3162, -3162, 1546, -3162, -3162, -3162, -3162, - -3162, 218, -3162, 1779, 20189, 20189, -3162, 399, 69572, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, 536, -3162, 498, 515, - 46949, 1362, 1367, 926, 56613, 56613, 1847, -3162, -3162, -3162, - -3162, 54118, 144, 1668, 169, 1504, -3162, -3162, 2484, 2484, - 15464, 1290, 222, 549, 15989, 20714, 1724, 1607, 213, 600, - 1729, -3162, 1615, 1840, 24914, 20189, 20189, 662, 701, 20189, - 920, 122, -3162, -3162, -3162, 1665, 56613, 52122, 334, 778, - 1387, 1476, 1390, 91, 1816, -3162, 1389, -3162, 1482, 56613, - 73519, 226, -3162, 1856, 226, 226, 245, 1857, 1486, 233, - 1652, 67, -83, 1389, 4318, -3162, 54118, 150, 738, 1389, - 56613, 1488, 822, 1389, 1812, 66578, 1210, -3162, -3162, 42797, - 1398, -3162, -3162, -3162, 186, 14939, -3162, 971, 1202, 1208, - 367, 212, 1248, 1263, 14939, 1269, 1355, 200, 1361, 1380, - 1450, 1505, 1554, 1596, 1602, 1618, 134, 1643, 1666, 1680, - 1693, 1699, 1721, -3162, 1725, 202, 1727, 215, 14939, 1755, - -3162, 146, 46949, -1, -3162, -3162, 1761, 204, -3162, 47049, - -3162, 1701, 1493, 1494, 66578, 1448, 56613, 1550, 1422, 1780, - 1831, 72052, 1658, -3162, 1757, 56613, 1679, 4318, 1682, 1442, - 1921, 1688, 1132, 1691, 1449, -3162, 70071, 49128, -3162, -3162, - -3162, -3162, -3162, 1818, 1802, 66578, 49128, 1455, -3162, -3162, - 66578, -3162, 56613, 56613, -3162, 56613, 66578, -3162, 542, 46949, - 1963, 1022, 73992, 50625, -3162, -3162, -3162, -3162, 933, 939, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 1020, - 49128, -3162, 3393, 45852, 1458, 20189, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, 1461, 1811, -3162, - -3162, 6931, 1465, 46147, 1468, 24914, 24914, 399, 2469, -3162, - -3162, 24914, 1469, 51124, 45766, 1464, 1470, 46332, 16514, 20189, - 16514, 16514, 46398, -3162, 1471, 46487, 61603, 1473, 56613, 30118, - -3162, -3162, -3162, 20189, 20189, 3628, 56114, 1515, 1477, -3162, - -3162, -3162, 32620, -3162, 32620, -3162, 1770, 32620, -3162, -3162, - 3794, -3162, 32620, 1772, 20189, 32620, -3162, 32620, 1717, 1719, - 1485, 32620, -3162, 56613, 1487, 56613, -3162, -3162, 46949, -3162, - 1484, 586, 1489, -3162, -3162, -3162, -3162, -3162, 1541, -3162, - 1541, 1541, -3162, -3162, -3162, -3162, 1492, 1492, 1495, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, 1496, 1028, -3162, 1541, -3162, 1492, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, 73519, -3162, -3162, -3162, -3162, - -92, -79, -3162, 1497, -3162, -3162, 1501, -3162, 1506, 1985, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, 8118, - 687, 1492, -3162, -3162, 4489, -3162, -3162, 20189, 20189, -3162, - -3162, 1507, 46949, 1552, -3162, -3162, 20189, 20189, -3162, -3162, - -3162, -3162, 2020, -3162, 20189, 1541, 1541, -3162, 6264, -3162, - 41607, 17039, 1601, 1604, 2020, -3162, 2020, -3162, 6264, 2021, - 2021, 1517, 37114, -3162, 1681, 46696, -3162, 1523, 1555, 7666, - 1520, -3162, -3162, 1524, -3162, 1526, 1518, 43734, 20189, 178, - 399, 399, 20189, -3162, 2020, 20189, 9122, 9122, -3162, 224, - 71568, 20189, 20189, 20189, 20189, 20189, 20189, 20189, 20189, 47631, - 1621, 136, 66578, 20189, 20189, 29608, 984, -3162, 20189, 1782, - -3162, 1548, 20189, 1628, 253, 20189, 20189, 20189, 20189, 20189, - 20189, 20189, 20189, 20189, -3162, -3162, 28589, 308, 520, 1871, - 1901, -10, 538, 20189, 1893, 11264, -3162, 1893, -3162, -3162, - -3162, -3162, -3162, 206, -3162, -3162, 1484, 1484, 66578, -3162, - 56613, 270, 53120, 20189, -3162, -3162, 1545, 1549, 599, 1612, - -3162, -3162, 56613, -3162, 40108, 1852, -3162, 332, 1558, -3162, - 45727, 1806, 1852, 2484, -3162, -3162, 25964, 1684, 1854, 1791, - -3162, -3162, 1771, 1774, -3162, 1561, 47138, 21239, 21239, -3162, - 1409, 46949, 1414, -3162, -3162, -3162, -3162, -3162, -3162, 671, - -3162, 56613, 99, 37613, -3162, 1563, 164, -3162, 2765, 1909, - 1872, 1724, 600, 1574, -3162, 57112, 57112, -3162, -3162, 1255, - 1573, 70570, 56613, 1869, 1819, 1873, -64, 71568, -3162, -3162, - -3162, -3162, 56613, 66578, 65096, 71069, 49627, 56613, 49128, -3162, - -3162, -3162, -3162, 56613, 890, 56613, 3834, -3162, -3162, -3162, - -3162, 226, -3162, -3162, -3162, -3162, -3162, 66578, 56613, -3162, - -3162, 226, 66578, 56613, 226, -3162, 1260, 56613, 56613, 56613, - 56613, 1332, 56613, 56613, 1020, -3162, -3162, -3162, 21764, 37, - 37, 1805, 1821, 1824, 1588, 12839, 146, -3162, 20189, 20189, - 325, 295, 66578, 1777, -3162, -3162, 692, 1832, 109, -3162, - 66578, 1649, 56613, 56613, 56613, 56613, 56613, 2508, -3162, -3162, - -3162, -3162, -3162, 1605, -3162, 1969, 2119, 1606, 1609, 1977, - -3162, 4318, 1981, 52621, 866, 3367, 1982, 1659, 1986, 13364, - -3162, -3162, 1622, -3162, -3162, 1624, 2107, 1874, -3162, -3162, - 1862, -3162, 66578, 2150, -3162, 105, -3162, 49128, -3162, 119, - -3162, 1870, 214, -3162, 14939, 20189, -3162, -3162, -3162, -3162, - -3162, -3162, 1210, 29099, -3162, 713, -3162, -3162, 2118, 1020, - 2118, 497, -3162, -3162, 2118, -3162, 2102, 2118, -3162, 71568, - -3162, 8056, -3162, 20189, 20189, -3162, 20189, 1990, -3162, 2152, - 2152, 71568, 24914, 24914, 24914, 24914, 24914, 24914, 199, 1352, - 24914, 24914, 24914, 24914, 24914, 24914, 24914, 24914, 24914, 26489, - 622, -3162, -3162, 749, 2125, 20189, 20189, 1999, 1990, 20189, - -3162, 71568, 1650, -3162, 1655, 1657, 20189, -3162, 71568, -3162, - 56613, 1661, -3162, -3162, -3162, 48, 1653, 1663, -3162, -3162, - 1546, -3162, 1060, 1064, 56613, 1978, 3821, 4733, -3162, -3162, - 20189, 1987, -3162, 3794, 3794, 32620, -3162, 20189, 1667, -3162, - -3162, 32620, 2010, -3162, 3794, -3162, -3162, 38112, 3794, 71568, - 756, -3162, 56613, 71568, 777, 20189, -3162, 14939, 2180, 71568, - 2145, 66578, 66578, 2184, 1672, 1673, 2020, 1759, -3162, 1763, - 1764, 1767, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, 71568, -3162, -3162, 158, -3162, -3162, -3162, -3162, - -3162, -3162, 1683, 1675, 20189, 20189, 62, -3162, 8203, 1687, - 1690, 6565, -3162, 1685, -3162, 1686, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, -3162, 1697, -3162, 1694, -3162, 1700, 1702, 1709, - 1704, 1705, 20189, 56613, -3162, 1698, 22289, 1848, 66578, -3162, - -3162, 20189, 20189, 56613, -3162, 2072, 46949, -3162, 1706, 1707, - 8647, -3162, -3162, -3162, 252, 737, 6322, 538, 3743, 3743, - 3743, 6264, -3162, -3162, -3162, 1731, -3162, 24914, 24914, -3162, - 4673, 3933, 10214, -3162, -3162, -3162, -3162, 2056, -3162, 665, - -3162, 1716, -3162, -3162, 4655, -3162, 41607, 7006, 20189, 163, - -3162, 20189, 29608, 20189, 1804, 3743, 3743, 3743, 333, 333, - 252, 252, 252, 737, 538, -3162, -3162, -3162, 1718, 20189, - 49128, -3162, 1720, 1722, 2082, 1356, 20189, -3162, -3162, 32620, - 1515, -1, 1515, 2020, 9122, -3162, 920, -3162, 920, -3162, - 46949, 56613, -3162, -3162, 1993, 1723, 32620, 1768, 2207, 2190, - 66578, -3162, -3162, 1728, 1893, 1744, -3162, -3162, 1750, 20189, - 3187, 1750, -3162, 1852, 19, 1964, 1014, 1014, 1409, 1966, - -3162, -3162, 1800, -3162, -3162, -3162, 20189, 13889, 1416, -3162, - 1420, -3162, -3162, -3162, -3162, -3162, 1736, -3162, 2016, -3162, - 56613, -3162, -3162, 24914, 2203, 20189, 38611, 2204, 2000, -3162, - -3162, -3162, 1798, 1798, -3162, -3162, 1838, 1389, 20189, 1996, - -3162, 115, 1758, 2123, 298, 2079, 66578, -3162, 316, 329, - -3162, 166, 2131, 214, 2132, 214, 49128, 49128, 49128, 779, - -3162, -3162, -3162, 1020, -3162, 12, 784, -3162, -3162, -3162, - -3162, 1858, 892, 1389, 4318, -3162, -3162, -3162, -3162, -3162, - -3162, -3162, 156, 956, 1389, 1859, -3162, 1875, -3162, 1878, - 958, 1389, -3162, -3162, 1532, 17564, 46949, 394, 146, 146, - 146, -3162, -3162, -3162, 14939, -3162, 1775, 46949, 46949, 151, - -3162, -3162, -3162, -3162, 1769, -3162, 352, -3162, 66578, -3162, - -3162, -3162, 1777, 1831, 1757, 56613, 4318, 1781, 2253, 1132, - 1449, -3162, 1940, 23, 902, -3162, 66578, -3162, 49128, 66578, - 56613, 56613, 56613, 65595, -3162, -3162, -3162, 1778, 1793, -3162, - -6, 2013, 2014, 56613, 1823, 56613, 1390, 2273, 56613, -3162, - 793, 1449, 1449, 18089, 2164, 56613, 1802, -3162, -3162, -3162, - -3162, 66578, -3162, -3162, 46949, -3162, 1790, -3162, 20189, 50126, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, 49128, -3162, 1020, - -3162, 1020, 2039, 66578, 44233, 1020, 44732, 1020, 1803, -3162, - 46949, 8811, 46949, 1999, -3162, 230, 2152, 1603, 1603, 1603, - 1289, 2149, 528, 1807, 1603, 1603, 1603, 277, 277, 230, - 230, 230, 2152, 622, 798, 51124, 1808, -3162, 46949, 46949, - -3162, -3162, 1813, -3162, -3162, -3162, -3162, 1814, 1826, -3162, - -3162, -3162, -3162, 66578, 157, 1515, 453, 453, 453, 453, - -3162, 56613, 56613, 56613, 46949, 2264, 2144, -3162, -3162, 3794, - 46949, 56613, -3162, 27539, -3162, 56613, -3162, 2168, -3162, 2257, - -3162, 56613, 800, -3162, -3162, -3162, 819, 1822, 1673, 71568, - 833, 861, -3162, 2020, 145, 1830, 1527, 992, 1075, 1435, - -3162, 54118, -3162, -3162, 1834, 46753, 20189, -3162, 2197, -3162, - -3162, -3162, 20189, 20189, -3162, 41607, -3162, -3162, -3162, -3162, - 131, 131, 8900, 1698, 1820, 1844, 56613, 10214, 46840, -3162, - 39110, -3162, -3162, 2166, 1829, -3162, 8978, 46949, -3162, 1681, - -3162, -3162, 9122, 20189, 2794, 5118, 20189, 1850, 20189, 2198, - -3162, -3162, 1853, -3162, -3162, 71568, 20189, 1855, 5420, 24914, - 24914, 5942, -3162, 6836, 20189, 10214, -3162, 42884, 1865, 1877, - 1805, 18614, -3162, 2084, 1876, -3162, 1987, 146, 1987, 1881, - -3162, -3162, -3162, -3162, 4489, -3162, 20189, 2026, 66578, 505, - 2525, 867, -3162, 399, 40108, 1768, 20189, 553, -3162, -3162, - 1885, -3162, 1750, -3162, -3162, -3162, 2100, -3162, -3162, -3162, - 56613, -3162, 1887, -3162, 37613, 2215, 10739, -3162, 37613, 56613, - -3162, -3162, 56613, 42114, 2252, -3162, 66578, 66578, 66578, -3162, - 66578, 1883, 1888, 266, 1894, 721, -3162, 2619, 266, 2235, - 275, 1390, 233, 2821, 61, -3162, -3162, -3162, 1971, 56613, - -3162, 66578, -3162, -3162, -3162, -3162, -3162, 49627, -3162, -3162, - 41107, 49128, -3162, 49128, 56613, 56613, 56613, 56613, 56613, 56613, - 56613, 56613, 56613, 56613, 1210, 20189, -3162, 20189, 1896, 1898, - 1900, 1805, -3162, 221, -3162, 1903, -3162, -3162, -3162, -83, - -3162, 352, 1902, 1906, -3162, 52621, 2952, 1659, -3162, 1624, - 1831, 379, 66079, -3162, 1907, 1905, 1757, 881, 883, 4318, - 1910, 2390, -3162, 866, 52621, -3162, -3162, -3162, 2345, -3162, - 674, 194, -3162, 1132, -3162, 2952, 1449, -3162, -3162, 2393, - -3162, 2394, 2952, 46949, 66578, 1979, -3162, 214, 889, -3162, - -3162, -3162, -3162, -3162, 66578, 1915, -3162, 1915, -3162, -3162, - 1915, -3162, -3162, -3162, -3162, 24914, 2266, 1924, 71568, -3162, - -3162, 56613, -3162, -3162, -3162, 893, 1926, 1987, 56613, 56613, - 56613, 56613, -3162, -3162, -3162, 19139, 20189, 1967, -3162, 1928, - 11789, 2251, -3162, 27014, -3162, -3162, 1933, 38112, 66578, -3162, - -3162, -3162, -3162, 2020, -3162, -3162, 66578, -3162, 1936, -3162, - 1937, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - 20189, 46949, -3162, 46949, -3162, -3162, -3162, -3162, -3162, 56613, - -3162, -3162, 7517, -3162, 1934, 1941, 66578, 56613, 231, -3162, - 20189, 66578, -3162, 1848, -3162, 390, 20189, 20189, 4673, -3162, - 43162, 20189, 71568, 897, 4673, 353, 20189, 5250, 5349, 20189, - 20189, 7468, 42153, -3162, 22814, 14414, -3162, 1942, 20189, 42192, - 40607, -3162, 32620, 2144, 1943, 2144, 1020, 1945, 46949, 20189, - -3162, -3162, -3162, -3162, 2002, 452, 34616, 2169, -3162, 1959, - 66578, -3162, 2026, 46949, -3162, -3162, 41607, -3162, -3162, -3162, - -3162, -3162, 2408, 2615, 1950, 1951, -3162, 1357, -3162, -3162, - 66578, 1953, -3162, 1955, 266, -3162, 66578, 1998, -3162, 286, - 2274, 117, -3162, 20189, -3162, 2370, 2451, 2619, 1974, 66578, - 56613, 24914, -3162, 302, 223, -3162, 2268, 56613, 1998, 2412, - -3162, -3162, -3162, 721, -3162, 2304, 2221, -3162, 226, -3162, - 20189, 721, 2224, 149, 66578, -3162, -3162, 2171, -3162, 71568, - 214, 214, -3162, 1489, 1988, 1994, 1995, 1997, 2001, 2003, - 2004, 2008, 2009, 2011, -3162, 2012, 2018, 2019, 2022, 2024, - 2025, 2027, 2028, 1496, 2029, -3162, 2032, 1885, 2033, 2034, - 2037, 2038, 2042, 72536, 2043, 2044, 2045, 2046, 1497, 2047, - 933, 939, -3162, -3162, -3162, -3162, -3162, -3162, 1168, 2050, - -3162, 2006, -3162, -3162, -3162, 2074, -3162, 2075, -3162, -3162, - -3162, -3162, -3162, -3162, 2005, 2017, -3162, -3162, -3162, 146, - 1992, 2052, 66578, 1210, 154, 49128, 66578, 2057, 1823, 2493, - 458, 2261, 2062, -3162, 1020, 2064, -3162, 1659, -3162, 52621, - 3754, 636, 2014, -3162, 273, 1823, -3162, 2468, 1659, 2103, - -3162, 1624, 2167, 20189, 155, -3162, 2295, 66578, 2069, -3162, - -3162, 50126, 1915, 5813, 24914, 71568, 908, 913, -3162, 2579, - 2237, 2144, -3162, -3162, -3162, -3162, -3162, 2076, -29, 2080, - 9689, 2078, -3162, -3162, -3162, -3162, -3162, -3162, 46949, 46949, - 66578, 2267, -3162, -3162, 2083, 2085, 39609, 2538, 2087, -3162, - -3162, 2403, -3162, 31121, -3162, 1673, 2091, 1673, 71568, 1673, - -3162, -3162, 46949, 1698, 20189, -3162, -3162, -3162, 2088, 2092, - 66578, 43181, 2421, -3162, -3162, 4673, 4673, 43162, 918, -3162, - 4673, 20189, 20189, 4673, 4673, 20189, -3162, 19664, 413, -3162, - 927, -3162, 42240, -3162, 73020, -3162, -3162, 1967, 1020, 1967, - -3162, -3162, 2098, -3162, -3162, -3162, 2163, -3162, -3162, 960, - 2535, 2026, 20189, -3162, -3162, 2108, 37613, -3162, -3162, -3162, - -3162, 37613, 266, -3162, 2286, 1998, 2117, -3162, -3162, -3162, - -3162, -3162, -3162, 42279, -3162, 79, 20189, -3162, 1038, 1289, - -3162, -3162, -3162, -3162, 1998, 1132, -3162, 56613, 2596, 2489, - -3162, -3162, 46949, -3162, -3162, 2020, 2020, -3162, -3162, 2257, - -3162, -3162, -3162, 2124, -3162, -3162, 1168, 95, 41107, 56613, - 56613, -3162, -3162, 2126, -3162, -3162, -3162, -3162, -3162, -83, - 2524, 983, 994, 866, -3162, 2952, 56613, 2497, 52621, -3162, - 49128, 2611, 2133, 56613, 1823, 1156, 1156, -3162, 2288, -3162, - 2289, -3162, -3162, 2620, 290, -3162, 1341, 56613, -3162, -3162, - 34117, -3162, 5813, 995, -3162, -3162, 2136, 2141, -3162, 1967, - 20189, 2143, 20189, -3162, 23339, 2622, 2142, -3162, 20189, 2206, - 28064, -3162, 20189, -3162, 56613, 61603, 2148, 61603, -3162, -3162, - -3162, -3162, 56613, -3162, -3162, -3162, 20189, -3162, 4673, 4673, - 4673, 20189, -3162, 20189, -3162, -3162, -3162, 2357, 2267, -3162, - 2267, 20189, 2952, 399, 4497, 66578, 18, -3162, 46949, -3162, - -3162, -3162, 56613, -3162, 49128, -3162, 266, -4, 2151, 20189, - 42632, 2392, -3162, -3162, 2429, -3162, 2488, -3162, 2223, 344, - 2240, -3162, -3162, -3162, -3162, 1210, 1020, -3162, 1659, 2014, - 2103, 2174, 56613, 1009, 2952, 866, 674, -3162, -3162, -3162, - -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, -3162, - 2952, 2613, 2396, 2621, -3162, 1979, 20189, 108, -3162, 1029, - 2614, -3162, -3162, 2687, 2267, 2179, 23339, 2183, -3162, 2185, - 66578, 46949, 2335, -3162, -3162, 2194, -3162, -3162, 20189, -3162, - -3162, 43238, 2192, 2199, 2655, 1805, 2206, 2206, -3162, 452, - -3162, -3162, 2629, 34117, 2590, 1132, 266, 2208, 1041, -3162, - -3162, -3162, -3162, -3162, 4318, -3162, 42719, 2455, 129, 2439, - 2151, 20189, -3162, 2290, -3162, -3162, -3162, 2690, -3162, -3162, - 52621, 2213, -3162, 2103, 2014, 1823, 2103, 2440, -3162, 2441, - 2217, 42758, 66578, 66578, 1659, 34117, 66578, 2218, 2206, -3162, - 2220, -3162, -3162, -3162, 30118, -3162, 2225, -3162, -3162, -3162, - 20189, 140, -3162, -3162, 2278, 56613, 1043, 74, 2429, 41107, - -3162, 49128, 1783, -4, 2537, -3162, -3162, -3162, -3162, 102, - 2456, -3162, 2457, -3162, 46949, -3162, 2952, 52621, -3162, -3162, - -3162, -3162, -3162, -3162, 34117, 2614, -3162, 332, -3162, 1515, - -3162, 332, -3162, -3162, -3162, -3162, -3162, 1464, 23864, 23864, - 23864, 2229, 2952, -3162, 1515, -3162, 2361, 2439, -3162, -3162, - -3162, -3162, -3162, 209, 209, 2630, -3162, 2297, -3162, 2103, - 1047, 66578, 1750, -3162, 1750, 25439, 2386, 193, 45805, 2610, - -3162, 2610, 2610, -3162, -3162, -3162, 40108, -3162, -3162, 2732, - -3162, 203, -3162, -3162, -3162, 1659, 332, -3162, -3162, 2723, - -3162, -3162, -3162, -3162, -3162, 162, -3162, -3162, -3162, 1515, - 266, -3162, -3162, -3162, 1515, 1750, 24389, 2397, -3162, 2466, - -3162, -3162, -3162, -3162, -3162, -3162, -3162 + 6596, -26, 739, -3017, -3017, 275, -26, 49530, 64984, 350, + -26, 136, 2383, 51526, -3017, -3017, 46037, 3819, -26, 55019, + 72380, 321, 582, 31527, 552, 55518, -3017, -3017, -3017, 64984, + 55019, 56017, -26, 345, 65483, -3017, -26, 34022, 52025, 337, + -3017, 55019, 67, 313, 56516, 55019, 2833, 854, 346, -3017, + -3017, -3017, -3017, -3017, 168, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 156, -3017, 200, 166, 31527, 31527, 53, 376, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 396, + -3017, -3017, 709, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 33523, -3017, -3017, -3017, -3017, -3017, -3017, 57015, 55019, + 57514, 52524, 58013, -3017, 672, 936, 612, 194, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + 204, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 459, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, 206, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 666, -3017, 516, -3017, 209, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, 870, -3017, -3017, 998, 2691, + 55019, 950, 986, 775, -3017, 58512, -3017, 756, 55019, -3017, + -3017, 819, 741, 999, -3017, -3017, 53023, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, 46536, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, 1004, -3017, -3017, 831, -3017, 148, -3017, -3017, + 875, 820, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 923, -3017, -3017, -3017, 959, 65982, 59011, 59510, -3017, + 827, 1658, 7978, 72398, 30527, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 396, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 55518, 64984, + 833, 841, 1137, 850, 32026, 866, 34522, 873, 879, 1244, + 912, 919, 932, 957, 313, 31027, 935, 666, -3017, 60009, + 60009, -28, 3241, -3017, 60009, 60508, -3017, 992, -3017, 936, + -3017, -3017, -3017, -3017, 342, 970, -3017, 61007, 61007, 61007, + 1033, 1283, 61007, -3017, -3017, -3017, 1025, -3017, -3017, 1280, + 19682, 19682, 66481, 66481, 936, 66481, 1073, 66481, -3017, -3017, + 54, 612, -3017, -3017, 53, 1059, 666, -3017, -3017, 52025, + -3017, -3017, 316, 1423, 19682, 55019, 1076, -3017, 1086, 1076, + 1091, 1097, 1099, -3017, 6596, 1464, 1344, 53522, 724, 724, + 1582, 724, 1006, 1008, 5405, 2999, -3017, 196, -3017, 1125, + -3017, 55019, 55518, 1237, 1161, 1454, -3017, 1059, 1528, 147, + 1334, 1571, 6090, 1594, 184, 1601, 483, 1602, 1676, 40, + -3017, 19682, 47035, 666, -3017, 11841, 19682, -3017, -3017, -3017, + 1307, -3017, -3017, -3017, -3017, -3017, 55019, 64984, 1233, 1238, + -3017, -3017, -3017, -3017, 956, 1482, -3017, 1719, 66980, -3017, + -3017, 1290, 61506, 62005, 62504, 63003, 1674, -3017, -3017, 1609, + -3017, -3017, -3017, 1281, -3017, -3017, -3017, 195, 67479, 1612, + 1246, 119, -3017, 1616, 198, -3017, 1619, 1480, 15490, -3017, + 1417, -3017, -3017, -3017, 313, -3017, 284, -3017, -3017, 43138, + -3017, -3017, 72398, 1345, 1256, -3017, 19682, 19682, 1259, 8514, + 60009, 60508, 19682, 55019, -3017, 19682, 24398, 1260, 19682, 19682, + 12870, 19682, 29529, 60009, 3241, 1261, -3017, 791, 55019, 1264, + -3017, 1358, 1358, 345, 31527, 1561, -3017, 212, 1558, 1484, + -3017, 31527, 1484, 1030, 1268, 1562, 1484, -3017, 514, 1563, + 1358, 35021, 1273, -3017, 1358, 1493, -3017, -3017, 19682, 15490, + 69974, 1752, -3017, -3017, -3017, -3017, 1557, -3017, 64984, 1276, + -3017, -3017, -3017, -3017, -3017, -3017, 671, 1790, 175, 1791, + 19682, 175, 175, 1279, 210, 210, -3017, 1474, 1288, -3017, + 214, 1289, 1292, 1806, 1807, 176, 164, 1136, 175, 19682, + -3017, 210, 1296, 1810, 1302, 1816, 188, 222, -3017, 215, + 19682, 19682, 19682, 310, 19682, 10793, -3017, 1818, 47035, 55019, + 697, -3017, 666, 1310, 936, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, 1312, -3017, 179, 6769, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, 1351, -3017, -3017, -3017, -3017, 1523, 19682, + -3017, -3017, 1316, 1561, -3017, 218, -3017, -3017, 1561, -3017, + -3017, -3017, -3017, -3017, 249, -3017, 1731, 19682, 19682, -3017, + 64984, 666, 67978, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + 395, -3017, 396, 44856, 1319, 1318, 1076, 55019, 55019, 1803, + -3017, -3017, -3017, -3017, 52025, 118, 1626, 158, 1460, -3017, + -3017, 53, 53, 16014, 812, 216, 491, 16538, 20206, 1684, + 1565, 599, 614, 1686, -3017, 1573, 1800, 24398, 19682, 19682, + 1006, 1008, 19682, 1086, 135, -3017, -3017, -3017, 1627, 55019, + 50029, 787, 928, 1354, 1431, 1355, 262, 1775, -3017, 1352, + -3017, 1445, 55019, 71925, 273, -3017, 1819, 273, 273, 768, + 1821, 1453, 258, 1615, 30, 371, 1352, 3469, -3017, 52025, + 146, 141, 1352, 55019, 1456, 560, 1352, 1777, 64984, 1256, + -3017, -3017, 40704, 1360, -3017, -3017, -3017, 181, 15490, -3017, + 1105, 1272, 1313, 387, 189, 1443, 1466, 15490, 1502, 1539, + 187, 1564, 1572, 1574, 1576, 1579, 1583, 1586, 1589, 162, + 1593, 1600, 1618, 1641, 1647, 1653, -3017, 1657, 191, 1662, + 199, 15490, 1669, -3017, 44856, 24, -3017, -3017, 1672, 193, + -3017, 44956, -3017, 1667, 1459, 1461, 64984, 1413, 55019, 1514, + 843, 1744, 1797, 70458, 1623, -3017, 1701, 55019, 1629, 3469, + 1630, 1383, 1862, 1631, 1238, 1634, 1392, -3017, 68477, 47035, + -3017, -3017, -3017, -3017, -3017, 1766, 1755, 64984, 47035, 1420, + -3017, -3017, 64984, -3017, 55019, 55019, -3017, 55019, 64984, -3017, + 576, 44856, 1935, 937, 72398, 48532, -3017, -3017, -3017, -3017, + 1047, 1062, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, 936, 47035, -3017, 3598, 43759, 1438, 19682, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 1439, + 1793, -3017, -3017, 5541, 1447, 44054, 1448, 24398, 24398, 666, + 3938, -3017, -3017, 24398, 1449, 49031, 43673, 1428, 1451, 44239, + 17062, 19682, 17062, 17062, 44305, -3017, 1452, 44394, 60009, 1444, + 55019, 54021, -3017, -3017, -3017, 19682, 19682, 3241, 54520, 1492, + 31527, -3017, 31527, -3017, 1747, 31527, -3017, -3017, 6913, -3017, + 31527, 1750, 19682, 31527, -3017, 31527, 1697, 1699, 1465, 31527, + -3017, 55019, 1467, 55019, -3017, -3017, 44856, -3017, 1469, 632, + 1468, -3017, -3017, -3017, -3017, -3017, 1520, -3017, 1520, 1520, + -3017, -3017, -3017, -3017, 1475, 1475, 1477, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + 1481, 1136, -3017, 1520, -3017, 1475, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, 71925, -3017, -3017, -3017, -3017, 418, 620, + -3017, 1487, -3017, -3017, 1488, -3017, 1472, 1968, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, 41013, 644, 1475, + -3017, -3017, 5290, -3017, -3017, 19682, 19682, -3017, -3017, 1490, + 44856, 1534, -3017, -3017, 19682, 19682, -3017, -3017, -3017, -3017, + 2002, -3017, 19682, 1520, 1520, -3017, 43691, -3017, 39514, 17586, + 1587, 1588, 2002, -3017, 2002, -3017, 43691, 2001, 2001, 1500, + 37516, -3017, 1665, 44603, -3017, 1504, 1677, 7335, 1503, -3017, + -3017, 1494, -3017, 1506, 1499, 41641, 182, 666, 666, 19682, + -3017, 2002, 19682, 44045, 44045, -3017, 235, 69974, 19682, 19682, + 19682, 19682, 19682, 19682, 19682, 19682, 45538, 1604, 177, 64984, + 19682, 19682, 29024, 1239, -3017, 19682, 1749, -3017, 1512, 19682, + 1603, 902, 19682, 19682, 19682, 19682, 19682, 19682, 19682, 19682, + 19682, -3017, -3017, 28009, 240, 702, 1855, 1874, -12, 302, + 19682, 1870, 11841, -3017, 1870, -3017, -3017, -3017, -3017, -3017, + 219, -3017, -3017, 1469, 1469, -3017, 64984, -3017, 55019, 316, + 51027, 19682, -3017, -3017, 1521, 1533, 169, 1598, -3017, -3017, + 55019, -3017, 38015, 1838, -3017, 356, 1536, -3017, 43634, 1794, + 1838, 53, -3017, -3017, 25446, 1670, 1832, 1770, -3017, -3017, + 1751, 1753, -3017, 1543, 45045, 20730, 20730, -3017, 1332, 44856, + 1337, -3017, -3017, -3017, -3017, -3017, -3017, 528, -3017, 55019, + 117, 35520, -3017, 1545, 106, -3017, 4724, 1887, 1850, 1684, + 614, 1552, -3017, 55518, 55518, -3017, -3017, 1116, 1554, 68976, + 55019, 1846, 1799, 1848, 328, 69974, -3017, -3017, -3017, -3017, + 55019, 64984, 63502, 69475, 47534, 55019, 47035, -3017, -3017, -3017, + -3017, 55019, 1315, 55019, 7055, -3017, -3017, -3017, -3017, 273, + -3017, -3017, -3017, -3017, -3017, 64984, 55019, -3017, -3017, 273, + 64984, 55019, 273, -3017, 1248, 55019, 55019, 55019, 55019, 1585, + 55019, 55019, 936, -3017, -3017, -3017, 21254, 103, 103, 1780, + 13394, 160, -3017, 19682, 19682, 304, 263, 64984, 1745, -3017, + -3017, 706, 1796, 114, -3017, 64984, 1608, 55019, 55019, 55019, + 55019, 55019, 1854, -3017, -3017, -3017, -3017, -3017, 1570, -3017, + 1938, 2090, 1578, 1580, 1942, -3017, 3469, 1945, 50528, 786, + 1812, 1947, 1621, 1950, 13918, -3017, -3017, 1591, -3017, -3017, + 1592, 2064, 1830, -3017, -3017, 1826, -3017, 64984, 2105, -3017, + 119, -3017, 47035, -3017, 198, -3017, 1827, 220, -3017, 15490, + 19682, -3017, -3017, -3017, -3017, -3017, -3017, 1256, 28519, -3017, + 723, -3017, -3017, 2078, 936, 2078, 593, -3017, -3017, 2078, + -3017, 2060, 2078, -3017, 69974, -3017, 7532, -3017, 19682, 19682, + -3017, 19682, 1948, -3017, 2111, 2111, 69974, 24398, 24398, 24398, + 24398, 24398, 24398, 524, 1296, 24398, 24398, 24398, 24398, 24398, + 24398, 24398, 24398, 24398, 25970, 513, -3017, -3017, 779, 2083, + 19682, 19682, 1958, 1948, 19682, -3017, 69974, 1607, -3017, 1611, + 1613, 19682, -3017, 69974, -3017, 55019, 1620, 17, 26, -3017, + 1622, 1628, -3017, 1561, -3017, 1018, 1022, 55019, 3231, 3817, + 4493, -3017, -3017, 19682, 1956, 6913, 6913, 31527, -3017, 19682, + 1632, -3017, -3017, 31527, 1974, -3017, 6913, -3017, -3017, 36019, + 6913, 69974, 796, -3017, 55019, 69974, 801, 19682, -3017, 15490, + 2141, 69974, 2106, 64984, 64984, 2144, 1635, 1638, 2002, 1725, + -3017, 1726, 1729, 1730, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, 69974, -3017, -3017, 174, -3017, -3017, + -3017, -3017, -3017, -3017, 1644, 1648, 19682, 19682, 112, -3017, + 7927, 1645, 1650, 4610, -3017, 1649, -3017, 1643, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, -3017, -3017, 1654, -3017, 1656, -3017, 1659, + 1679, 1681, 1664, 1671, 19682, 55019, -3017, 21778, -3017, 64984, + -3017, -3017, 19682, 19682, 55019, -3017, 2025, -3017, 1680, 1682, + 8232, -3017, -3017, -3017, 230, 404, 7582, 302, 5399, 5399, + 5399, 43691, -3017, -3017, -3017, 1683, -3017, 24398, 24398, -3017, + 1225, 1709, 10793, -3017, -3017, -3017, -3017, 2005, -3017, 774, + -3017, 1668, -3017, -3017, 1944, -3017, 39514, 44153, 19682, 190, + -3017, 19682, 29024, 19682, 1764, 5399, 5399, 5399, 277, 277, + 230, 230, 230, 404, 302, -3017, -3017, -3017, 1685, 19682, + 47035, -3017, 1687, 1688, 2043, 1302, 19682, -3017, -3017, 31527, + 1492, 24, 1492, 2002, 44045, -3017, 1086, -3017, 1086, -3017, + 44856, 55019, -3017, -3017, 1954, 1689, 31527, 1723, 2172, 2154, + 64984, -3017, -3017, 1692, 1870, 1708, -3017, -3017, 1721, 19682, + 1185, 1721, -3017, 1838, 15, 1934, 1158, 1158, 1332, 1936, + -3017, -3017, 1776, -3017, -3017, -3017, 19682, 14442, 1341, -3017, + 1343, -3017, -3017, -3017, -3017, -3017, 1710, -3017, 1991, -3017, + 55019, -3017, -3017, 24398, 2179, 19682, 36518, 2180, 1977, -3017, + -3017, -3017, 1779, 1779, -3017, -3017, 1820, 1352, 19682, 1972, + -3017, 157, 1732, 2097, 343, 2050, 64984, -3017, 332, 344, + -3017, 776, 2103, 220, 2104, 220, 47035, 47035, 47035, 806, + -3017, -3017, -3017, 936, -3017, -87, 815, -3017, -3017, -3017, + -3017, 1834, 692, 1352, 3469, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, 221, 720, 1352, 1836, -3017, 1840, -3017, 1841, + 764, 1352, -3017, -3017, 1676, 9217, 44856, 535, 160, 160, + 160, 15490, -3017, 1976, 1981, 1754, 44856, 44856, 165, -3017, + -3017, -3017, -3017, 1758, -3017, 231, -3017, 64984, -3017, -3017, + -3017, 1745, 1797, 1701, 55019, 3469, 1760, 2240, 1238, 1392, + -3017, 1927, 913, 1851, -3017, 64984, -3017, 47035, 64984, 55019, + 55019, 55019, 64001, -3017, -3017, -3017, 1767, 1763, -3017, 13, + 2000, 1999, 55019, 1813, 55019, 1355, 2250, 55019, -3017, 824, + 1392, 1392, 18110, 2145, 55019, 1755, -3017, -3017, -3017, -3017, + 64984, -3017, -3017, 44856, -3017, 1773, -3017, 19682, 48033, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, 47035, -3017, 936, -3017, + 936, 2020, 64984, 42140, 936, 42639, 936, 1782, -3017, 44856, + 8322, 44856, 1958, -3017, 232, 2111, 536, 536, 536, 5906, + 2134, 363, 1789, 536, 536, 536, 283, 283, 232, 232, + 232, 2111, 513, 992, 49031, 1801, -3017, 44856, 44856, -3017, + -3017, 1798, -3017, -3017, -3017, -3017, 1802, 1804, -3017, -3017, + -3017, -3017, -3017, -3017, 64984, 1168, 1492, 337, 337, 337, + 337, -3017, 55019, 55019, 55019, 44856, 2249, 2123, -3017, -3017, + 6913, 44856, 55019, -3017, 26999, -3017, 55019, -3017, 2148, -3017, + 2238, -3017, 55019, 830, -3017, -3017, -3017, 834, 1817, 1638, + 69974, 836, 842, -3017, 2002, 151, 1809, 1450, 924, 570, + 1350, -3017, 52025, -3017, -3017, 1822, 44660, 19682, -3017, 2183, + -3017, -3017, -3017, 19682, 19682, -3017, 39514, -3017, -3017, -3017, + -3017, -55, -55, 8455, 1823, 10793, 44747, -3017, -3017, 2130, + 1824, -3017, 8678, 44856, -3017, 1665, -3017, -3017, 44045, 19682, + 2547, 5060, 19682, 1828, 19682, 2150, -3017, -3017, 1814, -3017, + -3017, 69974, 19682, 1829, 3859, 24398, 24398, 4710, -3017, 5386, + 19682, 10793, -3017, 40791, 1811, 1825, 1780, 18634, -3017, 2048, + 1831, -3017, 1956, 160, 1956, 1835, -3017, -3017, -3017, -3017, + 5290, -3017, 19682, 1989, 64984, 542, 1872, 844, -3017, 666, + 38015, 1723, 19682, 608, -3017, -3017, 1833, -3017, 1721, -3017, + -3017, -3017, 2065, -3017, -3017, -3017, 55019, -3017, 1839, -3017, + 35520, 2176, 11317, -3017, 35520, 55019, -3017, -3017, 55019, 40021, + 2207, -3017, 64984, 64984, 64984, -3017, 64984, 1842, 1843, 248, + 1845, 389, -3017, 2194, 248, 2184, 247, 1355, 258, 2907, + 461, -3017, -3017, -3017, 1919, 55019, -3017, 64984, -3017, -3017, + -3017, -3017, -3017, 47534, -3017, -3017, 39014, 47035, -3017, 47035, + 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, 55019, + 1256, 19682, -3017, 19682, 1847, 1849, 1852, 1780, -3017, -3017, + -3017, 282, -3017, 1859, -3017, -3017, -3017, 371, -3017, 231, + 1864, 1865, -3017, 50528, 2691, 1621, -3017, 1592, 1797, 680, + 64485, -3017, 1866, 1869, 1701, 855, 867, 3469, 1868, 2330, + -3017, 786, 50528, -3017, -3017, -3017, 2298, -3017, 827, 228, + -3017, 1238, -3017, 2691, 1392, -3017, -3017, 2347, -3017, 2348, + 2691, 44856, 64984, 1937, -3017, 220, 871, -3017, -3017, -3017, + -3017, -3017, 64984, 1871, -3017, 1871, -3017, -3017, 1871, -3017, + -3017, -3017, -3017, 24398, 2220, 1877, 69974, -3017, -3017, 55019, + -3017, -3017, -3017, 876, 1878, 1956, 55019, 55019, 55019, 55019, + -3017, -3017, -3017, 19158, 19682, 1917, -3017, 1881, 12365, 2203, + -3017, 26494, -3017, -3017, 1884, 36019, 64984, -3017, -3017, -3017, + -3017, 2002, -3017, -3017, 64984, -3017, 1888, -3017, 1894, -3017, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, 19682, 44856, + -3017, 44856, -3017, -3017, -3017, -3017, -3017, -3017, 7206, -3017, + 1882, 1893, 64984, 19682, 64984, -3017, -3017, -3017, 391, 19682, + 19682, 1225, -3017, 6514, 19682, 69974, 886, 1225, 267, 19682, + 5646, 6346, 19682, 19682, 5456, 40060, -3017, 22302, 14966, -3017, + 1897, 19682, 40099, 38514, -3017, 31527, 2123, 1898, 2123, 936, + 1899, 44856, 19682, -3017, -3017, -3017, -3017, 1957, -5, 33024, + 2129, -3017, 1906, 64984, -3017, 1989, 44856, -3017, -3017, 39514, + -3017, -3017, -3017, -3017, -3017, 2363, 1012, 1904, 1907, -3017, + 1269, -3017, -3017, 64984, 1909, -3017, 1912, 248, -3017, 64984, + 1952, -3017, 271, 2228, 111, -3017, 19682, -3017, 2308, 2394, + 2194, 1918, 64984, 55019, 24398, -3017, 285, 183, -3017, 2208, + 55019, 1952, 2349, -3017, -3017, -3017, 389, -3017, 2246, 2159, + -3017, 273, -3017, 19682, 389, 2160, 154, 64984, -3017, -3017, + 2370, -3017, 69974, 220, 220, -3017, 1468, 1921, 1922, 1923, + 1924, 1925, 1928, 1929, 1931, 1932, 1939, -3017, 1940, 1941, + 1943, 1946, 1953, 1955, 1961, 1966, 1481, 1967, -3017, 1970, + 1833, 1973, 1975, 1978, 1982, 1983, 70942, 1984, 1985, 1992, + 1993, 1487, 1994, 1047, 1062, -3017, -3017, -3017, -3017, -3017, + -3017, 1246, 1995, -3017, 1990, -3017, -3017, -3017, 2016, -3017, + 2031, -3017, -3017, -3017, -3017, -3017, -3017, 1951, 1960, -3017, + -3017, -3017, 160, 1997, 2003, 64984, 1256, 121, 47035, 64984, + 2006, 1813, 2425, 1211, 2217, 2008, -3017, 936, 2009, -3017, + 1621, -3017, 50528, 2482, 268, 1999, -3017, 323, 1813, -3017, + 2389, 1621, 2021, -3017, 1592, 2100, 19682, 150, -3017, 2219, + 64984, 2010, -3017, -3017, 48033, 1871, 6153, 24398, 69974, 896, + 920, -3017, 2511, 2167, 2123, -3017, -3017, -3017, -3017, -3017, + 2011, 20, 2013, 10269, 2012, -3017, -3017, -3017, -3017, -3017, + -3017, 44856, 44856, 64984, 2188, -3017, -3017, 2014, 2019, 37017, + 2474, 2024, -3017, -3017, 2340, -3017, 30028, -3017, 1638, 2023, + 1638, 69974, 1638, -3017, -3017, 44856, 19682, -3017, -3017, 41088, + 2358, -3017, 1225, 1225, 6514, 942, -3017, 1225, 19682, 19682, + 1225, 1225, 19682, -3017, 9743, 540, -3017, 948, -3017, 40147, + -3017, 71426, -3017, -3017, 1917, 936, 1917, -3017, -3017, 2029, + -3017, -3017, -3017, 2094, -3017, -3017, 952, 2461, 1989, 19682, + -3017, -3017, 2038, 35520, -3017, -3017, -3017, -3017, 35520, 248, + -3017, 2212, 1952, 2046, -3017, -3017, -3017, -3017, -3017, -3017, + 40186, -3017, 113, 19682, -3017, 944, 5906, -3017, -3017, -3017, + -3017, 1952, 1238, -3017, 55019, 2525, 2417, -3017, -3017, 44856, + -3017, -3017, 2002, 2002, -3017, -3017, 2238, -3017, -3017, 2051, + -3017, -3017, 1246, 587, 39014, 55019, 55019, -3017, -3017, 2054, + -3017, -3017, -3017, -3017, -3017, 371, 2446, 971, 978, 786, + -3017, 2691, 55019, 2422, 50528, -3017, 47035, 2536, 2058, 55019, + 1813, 358, 358, -3017, 2209, -3017, 2210, -3017, -3017, 2540, + 291, -3017, 1288, 55019, -3017, -3017, 32525, -3017, 6153, 979, + -3017, -3017, 2063, 2066, -3017, 1917, 19682, 2074, 19682, -3017, + 22826, 2553, 2073, -3017, 19682, 2139, 27504, -3017, 19682, -3017, + 55019, 60009, 2085, 60009, -3017, -3017, -3017, -3017, -3017, 19682, + -3017, 1225, 1225, 1225, 19682, -3017, 19682, -3017, -3017, -3017, + 2297, 2188, -3017, 2188, 19682, 2691, 666, 3519, 64984, 35, + -3017, 44856, -3017, -3017, -3017, 55019, -3017, 47035, -3017, 248, + -11, 2095, 19682, 40539, 2328, -3017, -3017, 2365, -3017, 2426, + -3017, 2163, 597, 2174, -3017, -3017, -3017, -3017, 1256, 936, + -3017, 1621, 1999, 2021, 2109, 55019, 984, 2691, 786, 827, + -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, -3017, + -3017, -3017, -3017, 2691, 2549, 2335, 2555, -3017, 1937, 19682, + 94, -3017, 990, 2550, -3017, -3017, 2623, 2188, 2116, 22826, + 2117, -3017, 2119, 64984, 44856, 2267, -3017, -3017, 2120, -3017, + -3017, 19682, -3017, 41145, 2127, 2128, 2588, 1780, 2139, 2139, + -3017, -5, -3017, -3017, 2560, 32525, 2507, 1238, 248, 2151, + 1021, -3017, -3017, -3017, -3017, -3017, 3469, -3017, 40626, 2375, + 217, 2371, 2095, 19682, -3017, 2213, -3017, -3017, -3017, 2620, + -3017, -3017, 50528, 2147, -3017, 2021, 1999, 1813, 2021, 2369, + -3017, 2374, 2152, 40665, 64984, 64984, 1621, 32525, 64984, 2149, + 2139, -3017, 2153, -3017, -3017, -3017, 54021, -3017, 2157, -3017, + -3017, -3017, 19682, 735, -3017, -3017, 2201, 55019, 1028, 65, + 2365, 39014, -3017, 47035, 1442, -11, 2464, -3017, -3017, -3017, + -3017, 115, 2381, -3017, 2390, -3017, 44856, -3017, 2691, 50528, + -3017, -3017, -3017, -3017, -3017, -3017, 32525, 2550, -3017, 356, + -3017, 1492, -3017, 356, -3017, -3017, -3017, -3017, -3017, 1428, + 23350, 23350, 23350, 2164, 2691, -3017, 1492, -3017, 2284, 2371, + -3017, -3017, -3017, -3017, -3017, 269, 269, 2557, -3017, 2232, + -3017, 2021, 1035, 64984, 1721, -3017, 1721, 24922, 2320, 293, + 43712, 2548, -3017, 2548, 2548, -3017, -3017, -3017, 38015, -3017, + -3017, 2670, -3017, 260, -3017, -3017, -3017, 1621, 356, -3017, + -3017, 2662, -3017, -3017, -3017, -3017, -3017, 159, -3017, -3017, + -3017, 1492, 248, -3017, -3017, -3017, 1492, 1721, 23874, 2333, + -3017, 2408, -3017, -3017, -3017, -3017, -3017, -3017, -3017 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -3162, -3162, -3162, 1891, 78, -3162, -3162, 103, -3162, 975, - -3162, 106, -797, 489, -3162, 82, 3221, 2609, 4184, 1298, - -520, -890, -1248, 24, 84, -1138, 3, -3162, -3162, -3162, - -3162, -1516, -560, 173, -3162, -3162, -697, -2619, -650, -3162, - -3037, -3092, -3162, -3162, -786, -3061, -2089, 86, -3162, -3162, - 90, 4, -2178, -3162, -1700, 63, -2168, 93, 94, 888, - -3162, -2620, 96, -884, -1212, -917, -1202, -3162, -169, -3162, - 401, 100, 1828, 1946, -3162, 5, -2220, -2969, -646, -3162, - -748, -3162, -400, -3162, -692, -3162, -730, -700, -729, -2891, - -1155, -3162, 1599, -447, -3162, 547, -3162, -2602, -3162, -3162, - 537, -3162, -1176, -3162, -2268, 88, -676, -2435, -2604, -2212, - -908, 171, -682, 148, -2171, -1048, -3162, 561, -3162, -664, - -3162, -899, -2099, 101, -3162, -3162, 1490, -932, -3162, 104, - -3162, 445, -3162, -2176, 446, -2175, 1519, -562, 8, 10, - -3162, -3162, -3162, -3162, -3162, -691, 487, -1228, -3162, 427, - -3162, -3162, -3162, -3162, -236, 135, -2296, 27, 3629, -44, - -18, -3162, 2, -3162, -3162, -3162, 594, -3162, -3162, 14, - 58, 1674, -3162, -1043, -3162, -1670, 763, -3162, 1841, 1842, - -1782, -875, -55, -3162, 641, -1682, -2174, -639, 1102, 1671, - 1676, -3162, 396, -2574, -3162, -610, -3162, 797, -3162, -3162, - 640, 1152, -1582, -1578, -3162, -2277, -3162, -527, -414, -3162, - -3162, -3162, -3162, -3162, -2576, -2932, -627, 1122, -3162, 1689, - -3162, -3162, -3162, -3162, 50, -1547, 2861, 679, -3162, 68, - -3162, -3162, -3162, -3162, 87, -3162, 870, -232, -3162, -492, - -681, -795, 1904, -496, 13, -1739, -12, -380, 437, -3162, - -3162, 441, -2105, -1445, 400, -329, 873, -3162, -63, -1266, - -3162, -1877, -1198, -3162, -3162, -772, 652, -3162, -3162, -3162, - 1544, 2347, -3162, -3162, 2552, 2561, -3162, -904, 2808, -799, - -1049, 1918, -938, 1919, -941, -928, -915, 1920, 1923, 1925, - 1927, 1929, 1931, 1932, -1548, 5255, -196, 1160, -2204, -3162, - -1430, -1598, 1001, 1003, 1005, 38, -3162, -1422, 210, -3162, - -3162, -3162, -3162, -3162, -2802, -3162, -487, -3162, -484, -3162, - -3162, -3162, -1692, -3161, -1732, -3162, -793, 816, -3162, -3162, - 397, -3162, -3162, -3162, -3162, -1534, -3162, 6195, 717, -3162, - -2037, -3162, -3162, -974, -809, -711, -1014, -1233, -1959, -3162, - -3162, -3162, -3162, -3162, -3162, -1522, -1807, -655, 773, -3162, - -3162, 874, -3162, -3162, -3162, 92, -1436, -1777, -2135, -3162, - -3162, -3162, 780, 1481, 52, -829, -1640, -3162, -1559, -3162, - -3162, 834, -2413, -3162, -3162, 392, -2682, -3162, -3162, 110, - -3162, -623, -1129, -2489, 559, 16, -3162, 1773, -2585, -3162, - -3162, -731, -2722, -1136, -898, -3162, 107, -3162, 350, 112, - -1652, -3162, 6, -3162, -443, -3162, -3162, -2634, -3162, 116, - 130, 2172, -3162, 1114, -3162, -3162, -3162, -3162, -601, -3162, - -630, -632, -3162, -3162, 28, -903, 1594, -3162, 132, 227, - -3162, 935, -3162, 698, 133, -3162, 2065, -408, 137, 1266, - -3162, -3162, -3162, 11, -621, 354, -3162, 1268, -3162, -3162, - 1714, 647, 138, -3162, 289, 17, -3162, -3162, -3162, 83, - 141, 7, -3030, 142, -2808, -1707, -7, -3162, -3162, -3162, - -719, -3162, -2565 + -3017, -3017, -3017, 1837, 82, -3017, -3017, 68, -3017, 930, + -3017, 61, -789, 452, -3017, 86, 2920, 2581, 3525, 1263, + -518, -887, -1258, 28, 88, -1146, 10, -3017, -3017, -3017, + -3017, -1498, -583, 126, -3017, -3017, -720, -2539, -673, -3017, + -2953, -2678, -3017, -3017, -808, -3016, -2069, 90, -3017, -3017, + 95, 2, -2117, -3017, -1676, 64, -2104, 96, 97, 846, + -3017, -2620, 100, -895, -1200, -912, -1207, -3017, -205, -3017, + 357, 101, 1251, 1885, -3017, 4, -2197, -2867, -679, -3017, + -779, -3017, -437, -3017, -726, -3017, -947, -734, -768, -2858, + -1145, -3017, 1532, -489, -3017, 490, -3017, -2589, -3017, -3017, + 478, -3017, -1163, -3017, -2234, 36, -713, -2411, -2567, -2178, + -898, 120, -721, 98, -2131, -1255, -3017, 502, -3017, -705, + -3017, -891, -2495, 102, -3017, -3017, 1421, -930, -3017, 109, + -3017, 390, -3017, -2149, 388, -2106, 1455, -630, 19, 21, + -3017, -3017, -3017, -3017, -3017, -748, 430, -1216, -3017, 366, + -3017, -3017, -3017, -3017, -290, 79, -2268, 11, 3003, -31, + -37, -3017, -32, -3017, -3017, -3017, 537, -3017, -3017, 18, + 42, 1605, -3017, -1027, -3017, -1634, 690, -3017, 1762, 1768, + -2165, -879, -49, -3017, 577, -1671, -2144, -640, 1027, 1595, + 1590, 327, -2965, -3017, -663, -3017, 46, -3017, -3017, 568, + 1071, -1562, -1558, -3017, -2201, -3017, -582, -472, -3017, -3017, + -3017, -3017, -3017, -2529, -2138, -635, 1040, -3017, 1597, -3017, + -3017, -3017, -3017, 60, -1503, 2768, 606, -48, -3017, -3017, + -3017, -3017, 14, -3017, 794, -302, -3017, 2004, -669, -801, + 1805, -611, 237, -1705, -18, 2017, 368, -3017, -3017, 367, + -2062, -1421, 322, -391, 798, -3017, -3017, -1253, -3017, -1865, + -1191, -3017, -3017, -732, 1014, -3017, -3017, -3017, 1151, 1778, + -3017, -3017, 2774, 2790, -3017, -900, 3151, 1176, -1037, 1844, + -931, 1856, -933, -935, -938, 1857, 1858, 1860, 1861, 1863, + 1867, 1876, -1539, 4950, 1052, 945, -2215, -3017, -1583, 915, + 916, 917, 48, -3017, -1399, 76, -3017, -3017, -3017, -3017, + -3017, -2758, -3017, -563, -3017, -555, -3017, -3017, -3017, -1759, + -2749, -1789, -3017, 4393, 725, -3017, -3017, 306, -3017, -3017, + -3017, -3017, -1535, -3017, 5761, 621, -3017, -2017, -3017, -3017, + -981, -850, -731, -998, -1217, -1938, -3017, -3017, -3017, -3017, + -3017, -3017, -1513, -1780, -208, 682, -3017, -3017, 778, -3017, + -3017, -3017, 6, -1434, -1755, -2116, -3017, -3017, -3017, 698, + 1373, -19, -839, -1621, -3017, 755, -2371, -3017, -3017, 318, + -3017, -599, -1122, -2457, 59, 16, -3017, 689, -2551, -3017, + -3017, -740, -2691, -1138, -892, -3017, 116, -3017, 274, 127, + -1651, -3017, 5, -3017, -501, -3017, -3017, -2588, -3017, 128, + 129, 2069, -3017, 1034, -3017, -3017, -3017, -3017, -581, -3017, + -620, -614, -3017, -3017, 32, -902, 1511, -3017, 131, 434, + -3017, 852, -3017, 601, 132, -3017, 1969, -492, 134, 1178, + -3017, -3017, -3017, 29, -602, 278, -3017, 1180, -3017, -3017, + 1646, 564, 138, -3017, 420, 22, -3017, -3017, -3017, 84, + 2777, 139, 12, -2389, 142, -2800, -1683, -7, -3017, -3017, + -3017, -729, -3017, -2526 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -2102 +#define YYTABLE_NINF -2081 static const yytype_int16 yytable[] = { - 525, 914, 872, 53, 57, 65, 82, 103, 68, 719, - 69, 94, 1140, 1207, 77, 963, 525, 99, 884, 1244, - 1036, 1964, 1315, 523, 1263, 1445, 858, 70, 1826, 1989, - 1814, 1501, 1798, 1354, 77, 982, 1318, 784, 2221, 523, - 718, 1779, 1815, 2188, 1607, 522, 1707, 2623, 778, 1417, - 2024, 2327, 1415, 2105, 2336, 1864, 1172, 2144, 2055, 888, - 2658, 817, 1418, 1371, 856, 1831, 2094, 1789, 525, 525, - 2506, 1360, 2727, 810, 1764, 1419, 2613, 1377, 50, 889, - 745, 1785, 51, 3049, 52, 2596, 55, 2598, 2121, 2122, - 56, 523, 523, 59, 60, 3018, 61, 1684, 1896, 905, - 63, 66, 1687, 870, 67, 2651, 1243, 80, 1249, 1819, - 1253, 3047, 81, 817, 817, 3020, 83, 851, 1263, 2577, - 3065, 2612, 976, 973, 965, 810, 810, 1620, 898, 1014, - 84, 3062, 90, 91, 2843, 1039, 2710, 93, 98, -1949, - 2192, 102, 104, 885, 886, 2911, 2358, -2089, -2089, 2916, - 2354, -1373, -1949, 2508, 1060, -454, 2241, -1314, 1060, -527, - 2460, 1982, 2244, 1584, 1585, 3137, 1983, 1061, 1348, -371, - -870, 3267, -875, 537, -531, -1940, -875, 983, 2714, 1384, - 1597, 2136, 1348, -1295, 2718, 2719, 2712, -1957, 3472, 1770, - 821, -1314, 2659, -1315, 1060, -837, 1429, 2353, 2728, -1311, - -1311, 2526, -878, -850, 1440, -1940, -865, -1957, 2136, -1315, - 821, 821, -878, -2080, -2080, -2098, -2098, -1312, -1312, 2146, - 862, 1688, 1364, 821, 3553, -2075, -2075, 1060, -2100, -2100, - 1364, 954, 1781, 819, 1692, 1060, 3201, -229, 1781, 1159, - 3254, 1941, -229, 1817, 1196, 879, 1943, 1569, 1153, 2686, - 876, 1829, 2765, 2767, -1132, 2770, 1199, 3271, 1339, -527, - 1830, 982, -1132, 1640, 2487, 2488, 3607, 1263, 1642, 3361, - 3348, 3140, 3578, 1160, -531, 2494, 1713, 1348, -480, 2498, - 876, 2350, 2735, 3184, 1773, 819, 819, 1008, 1941, 2804, - 538, 1616, 1942, 1943, 1765, 881, 3237, 1340, 1650, 1589, - 821, 3066, 3506, 2660, 3, 4, 2159, 3167, 3432, 3169, - -665, 1039, 1790, 1006, 1799, 1599, 880, 1802, 1803, 2883, - 3602, 2885, 1257, 1014, 3538, 2481, 2482, 2483, 3040, 1981, - 821, 2441, 1652, 881, 1157, 1689, 1790, 1710, 2175, 1832, - 3459, 877, 3212, 3608, 1640, 2254, 2176, 2030, 1641, 1642, - 3545, 1804, 1693, 1378, 3391, 2705, 2654, 821, 2185, 3591, - 1015, 2470, 3291, 3476, 3392, 3328, 1981, 3330, 942, -807, - 2787, 877, 3496, 2216, 2123, 1192, 1759, 1760, 2247, 1650, - -2074, -2074, 2925, -1153, 3531, 2928, 1724, 113, 1611, 839, - 1602, -1153, 2954, 2275, 881, 3268, 3426, 1809, 3427, 1186, - 1763, 1640, 2588, 1602, 3589, 3440, 3198, 943, 1044, 1488, - 3269, 1440, 1603, 1652, 992, 2433, 1781, 2471, 3236, 1045, - 2662, 1810, 3210, 3261, 1877, 1603, 1604, 1782, 1836, 2924, - 2160, 1569, 1021, 3518, 3273, 3609, 3521, 1526, 3507, 1606, - 1813, 1161, 2722, 1162, 1775, 3614, 2461, 2161, 2907, -527, - 2967, 1194, 2162, 1612, 2276, 3262, 3377, 2147, 2217, 1690, - 1220, 1489, 1318, 3560, -531, 1349, 2955, 3067, 3441, 3586, - 1652, 114, 3478, 2929, 2442, 2651, 1341, 2651, 3458, 1349, - 3539, 3199, 3579, 3603, 2443, 2148, 3076, 3404, 3561, -685, - 2163, 840, 2655, 945, 1725, 2248, 1805, 3211, 2835, 1711, - 1016, 1187, 1607, 3213, 1833, -807, 1806, 1154, 2186, 3540, - 3091, 2279, 1788, 3216, 3359, 3289, 1258, 3592, 1791, 2680, - -527, 1835, 1569, 2661, 3508, 2662, 1468, 1476, 3546, 3584, - 3548, 3393, 2681, 1483, 989, -531, 3433, 1601, 2065, 2930, - 2351, 2931, 1791, 955, 2543, 882, 2698, 2699, 2700, 1640, - 2956, 3058, 2137, 1641, 1642, 2663, 3554, 541, 3055, 2027, - 1709, 2472, 3337, 1776, 2144, 863, 929, 1702, 1761, 3580, - 3070, 3071, 559, 3519, 1349, 2342, 3202, 2502, 750, 2579, - 1762, 1818, 878, 1155, 1650, 1788, 719, 2687, 1631, 826, - 3610, 1766, 1342, 3082, 3041, 2270, 1054, 3349, 3581, 2804, - 2149, 3270, 2335, 869, 869, 2339, 1584, 1585, 3360, 1788, - 2151, 3248, 2521, 1602, 963, 1897, 2863, 951, 1652, 1898, - 542, 2255, 2094, -1132, 912, 1902, 2774, 1350, 913, 535, - 3420, 1597, 1580, 1941, 1990, 1603, 539, 1942, 1943, -527, - 1973, 1353, 1440, 1440, 982, 2241, 2600, 2164, 1440, 2399, - 2626, 3369, -1949, 3018, -531, 2012, 788, 3520, 3225, 3226, - 2776, 1594, 2819, 2428, 2731, -1949, 2726, 2615, 901, 1815, - -1314, 2191, -1373, 3020, 1594, 2434, -454, -454, -527, 1602, - -527, 1102, 1103, -870, 2405, -875, 2621, 1314, -1940, 1602, - -371, 2076, 2077, -531, 912, -531, -1295, 3340, 913, 3192, - -1957, 1603, 3341, 1635, -1314, 2462, -1315, 2177, 1587, 2720, - 872, 1603, 2467, 1809, 2710, 1604, 1592, 2904, -1940, -865, - -1957, 3311, -1315, 1685, 2193, 1606, 2146, 1368, 1369, 1899, - 1586, 976, 1906, 1002, 3457, 1368, 1369, 1810, 1163, 1263, - 2117, 1263, -229, -229, 1958, 1589, 1569, 981, 1640, 3251, - 2798, 2546, -1153, 2499, 2934, 2275, 3465, 2499, 2706, 2707, - 3343, 872, 1192, 2152, 789, 1599, 1673, 77, 2062, 1616, - 784, 2892, 2422, 3464, 2153, 1979, 1727, 2423, 1616, 3353, - 2935, 105, 978, 1650, 2905, 3265, 2520, 525, 1955, 1956, - 1957, 1958, 2097, 1972, 2335, 1974, 1975, 2569, 525, 2053, - 1020, 1438, 546, 1851, 972, 525, 2788, 2789, 2790, 2791, - 523, 3183, 1217, 2777, 1217, 2884, 2648, 1652, 1218, 3086, - 1218, 523, 1728, 2118, 1192, 2570, 2893, 820, 523, 1193, - 550, 106, 817, 1208, 525, 525, 2424, 3266, 1194, 888, - 3529, 1569, 1852, 817, 1670, 1671, 1672, 1673, 1158, 2203, - 817, 2468, 3492, 3493, 3218, 1004, 3047, 3453, 525, 889, - 1781, 1301, 3223, -608, 1897, 2390, 1158, 2063, -608, 3185, - 3174, 1784, 859, 1005, 2204, 3252, 2069, 3256, 53, 57, - 65, 82, 103, 68, 2305, 69, 94, 1195, 2187, 77, - 1729, 1164, 99, 2468, 2308, 2805, 1362, 2311, 1727, 1363, - 1194, 865, 70, 3148, 3533, 525, 719, 821, 3175, 1307, - 525, 2696, 2304, 3262, 3018, 912, 1217, 2697, 3034, 913, - 3035, 2139, 1218, 1219, 1173, 1219, 851, 851, 1854, 851, - 3322, 851, 2589, 1440, 3020, 3125, 3323, 1908, 3127, -608, - 3129, 1730, 1060, 1910, 1728, 2571, 874, 2475, 1060, 1195, - 2572, 3604, 875, 50, 2328, 2329, 2330, 51, 2363, 52, - 890, 55, 1307, 2398, 3373, 56, 891, 2400, 59, 60, - 2402, 61, 2267, 981, 872, 63, 66, 3346, 1569, 67, - 525, 525, 80, 1790, -2071, -2071, 525, 81, -608, 525, - 525, 83, 525, 525, 525, 525, 2410, 77, 1317, 2303, - 784, 2094, 908, 1731, 819, 84, 1360, 90, 91, 525, - 2415, 525, 93, 98, 2854, 819, 102, 104, 2624, 2314, - 525, 893, 819, 1060, 2321, 821, 108, 1219, 14, 15, - -1949, 912, 523, 1964, 523, 1627, 2179, 525, 1307, 1572, - 2180, 1481, 3333, 523, 1989, 1486, 910, 1668, 1669, 1670, - 1671, 1672, 1673, 916, 817, 1700, 817, 872, 1701, 525, - 2601, 1903, 2602, 1730, 1904, 817, 810, 1790, 1004, 928, - 1147, 1148, 1473, 1150, 23, 1152, 2306, 810, 525, 935, - 1220, 2309, 1220, 912, 1465, -1295, 1005, 913, 2055, 525, - 525, 525, -209, 525, 525, 1480, 719, 3158, 1631, 1595, - 1596, 2701, 1815, 2573, 947, 2026, 912, 2279, 2027, 939, - 1627, 1820, 2938, 1628, 2574, 949, 2147, 1048, 1049, 1050, - 952, 2632, 1053, 3436, 953, 1731, 3283, 1621, 956, 525, - 1569, 1953, 1954, 1955, 1956, 1957, 1958, 1790, 931, 1221, - 932, 1247, 1569, 1222, 2148, 1222, 2621, 525, 525, 1440, - 1440, 1440, 1440, 1440, 1440, 2941, 957, 1440, 1440, 1440, - 1440, 1440, 1440, 1440, 1440, 1440, 1440, 2466, 958, 1158, - 1715, 1716, 1569, 1722, 2688, 1223, 933, 1248, 934, 1569, - 989, 1393, 1394, 525, 1220, 959, 3378, 525, 525, 1791, - 889, 889, 969, 889, 982, 1823, 109, 525, 525, 525, - 541, 1790, 525, 1790, 998, 2805, 2051, 110, 1025, 2052, - 1007, 2347, 1620, 940, 2348, -2072, -2072, 26, 27, 28, - 1569, -2073, -2073, 1572, 1569, 2736, 819, 1009, 819, 2421, - 1569, 2744, 2416, 2425, 1816, 2417, 2427, 819, 987, 1939, - 1940, 3379, 111, 2814, 1026, 1960, 1224, 1222, 1224, 988, - 3380, 1401, 1402, 1569, 990, 2524, 1788, 3243, 1307, 2149, - 1474, -2076, -2076, 542, 2150, 2685, 1217, 1307, 2454, 2151, - 1028, 2455, 1218, 1791, 3381, 2500, -2077, -2077, 2501, 1223, - 3133, 1217, -2078, -2078, 33, 941, 1217, 1218, 1578, 993, - 46, 1307, 1218, 112, 996, 35, 2503, 1059, 2676, 2501, - 1941, 2677, 1041, 2682, 1942, 1943, 2683, 968, 1944, 1945, - 1946, 1052, 2747, 3351, 1572, 2027, 2597, 37, 2945, 2811, - 997, 38, 2501, 823, 1858, 1859, 1861, 1862, 999, 2689, - 719, 2693, 1000, 2567, 1401, 1402, 3087, 1051, 2812, 719, - 1788, 2052, 1001, 1791, 1440, 1440, 2380, 3382, 2381, 1721, - 1224, 2670, 2815, 2672, 40, 2816, 981, 3600, 1217, 1002, - 3383, 1891, 2799, 1046, 1218, 43, 2806, 2946, -2079, -2079, - 1407, 1408, 2094, 719, -2081, -2081, 77, 1219, 525, 784, - 2817, 879, 44, 2816, 942, 2947, 2899, 1055, 3587, 2900, - 3588, 978, 1219, -2082, -2082, 1316, -609, 1219, 1054, 1032, - 3056, -609, 3057, 2417, 1913, 2348, 45, 1791, 3080, 1791, - 1788, 3081, 3088, 909, 3016, 3089, 3149, 1151, 1475, 2052, - 46, 1167, 2152, 943, 3563, 869, 2635, 3284, 525, 525, - 2052, 3613, 3285, 2153, 525, 2501, 525, 3317, 1175, 3575, - 2052, 525, 525, 525, 525, 546, 3324, 972, 1174, 2027, - 2958, 2717, 880, 1407, 1408, 1177, 525, 525, 944, 523, - 1440, 2965, 23, -2083, -2083, 525, 3033, 525, 1178, 1219, - 525, 2922, -609, 550, 1788, 525, 1788, 525, 525, 3334, - 525, 817, 3335, 2476, 525, 2477, 2948, 2478, 523, 2479, - 523, 2836, 2837, 523, 3611, 2949, 1179, 3043, 523, 3612, - 1181, 523, 3367, 523, 1182, 2417, 2957, 523, 2966, 945, - 817, 1948, 817, 3368, 3401, 817, 2348, 2052, -2084, -2084, - 817, -609, 810, 817, 810, 817, 1190, 810, 3462, 817, - 881, 2417, 810, 1209, 1220, 810, 1212, 810, 1572, 1473, - 2003, 810, 2004, 1214, 3422, 2006, 3423, 1215, 3474, 1220, - 2010, 3475, 1216, 2013, 1220, 2014, 2673, 1228, 2675, 2018, - 3500, 3384, 3544, 3501, 3385, 3475, 3585, -2085, -2085, 3475, - 525, 525, 1255, 1620, 1569, 1229, 2823, 2054, 2822, 525, - 525, 1949, 2056, 1246, 2057, 2060, 1250, 525, 77, 2824, - 2826, 2061, 1254, 1251, 525, 1310, 940, 1222, 2921, 1616, - 2923, 2058, 2825, 2827, 2828, 26, 27, 28, 2266, -2086, - -2086, 1059, 1222, 2312, 1941, -2087, -2087, 1222, 1942, 1943, - 719, 525, -2102, -2102, -2102, 525, 1220, 1313, 525, 1252, - 1301, -2088, -2088, 1572, 525, 525, 525, 525, 525, 525, - 525, 525, 719, 1189, 1223, 1191, 525, 525, 525, 2313, - 1314, 525, 1319, 819, 1321, 525, -2090, -2090, 525, 525, - 525, 525, 525, 525, 525, 525, 525, 1325, 941, 525, - 2757, 523, 33, 2133, 1335, 1025, 525, 1337, 1307, -2091, - -2091, 882, 819, 1338, 819, 2319, 1345, 819, 1346, 1222, - 982, 2188, 819, -2092, -2092, 819, 525, 819, 1561, 1352, - 1224, 819, -540, 3230, 2621, 2223, -2093, -2093, 541, 38, - 1569, 1026, -2094, -2094, 1355, 1224, 1356, -540, 1361, 525, - 1224, 2320, -540, 2117, 1379, 889, 1456, 1482, 1380, 1164, - 525, 525, 1385, 869, -2095, -2095, 1443, 1028, -2097, -2097, - -2099, -2099, 40, 1458, 3193, 1459, 2435, 2436, 2437, 2438, - 2439, 2440, 1478, 43, 2444, 2445, 2446, 2447, 2448, 2449, - 2450, 2451, 2452, 2453, 1477, 2965, 1466, 1851, -2101, -2101, - 1572, 542, 1484, -540, 1838, 1839, 1569, 2242, 2243, 719, - 1495, 719, -660, -660, -664, -664, 1440, 1440, -663, -663, - 1403, 1404, 1224, -540, 1950, 1951, 1952, 1485, 1953, 1954, - 1955, 1956, 1957, 1958, 1491, 2030, 1852, 2915, 46, 1497, - 2291, 1462, 2295, 1407, 1408, 3247, 1469, 1470, 1471, 3189, - 3190, 525, 3050, 1230, 1574, 3079, 3039, 1575, 1307, 2749, - 2751, 525, 525, 1492, 116, 3068, 1577, 1496, 536, 3597, - 3598, 1853, -540, 1231, 544, 3562, 749, 3571, 3572, 3564, - -841, -540, 1696, 1697, 2640, 2641, -848, 1586, 3400, 46, - 838, 3160, 3310, 1590, 852, -685, 1032, -686, -838, -839, - 1600, -842, 1307, -840, 1601, 1679, 1622, 1632, 1634, 1681, - 1683, 1569, 1561, 1695, 1703, 1475, 1704, 1708, 1712, 1232, - 719, 1193, 1854, 1714, 1195, 1949, 1749, 1307, 525, 1753, - 1751, 1768, 2384, 1316, 3605, 1786, 981, 1787, 1788, 1793, - -208, 1794, 1900, 1795, 1901, 1800, 1807, 1808, 1812, 1822, - 113, 1828, 1572, 1841, 1842, 1843, 525, 525, 1847, 525, - 1850, 1857, 1856, 1865, 1572, 525, 525, 525, 525, 525, - 525, 2564, 2565, 525, 525, 525, 525, 525, 525, 525, - 525, 525, 525, 546, 1869, 547, 1866, 1872, 525, 525, - 1873, 1875, 525, 1876, 1572, 2621, 1878, 1879, 917, 525, - 1892, 1572, 3016, 1561, 1893, 1897, 1905, 1930, -1831, 1569, - 1932, 550, 1440, 1933, 1935, 1233, 1969, 1938, 1961, 1970, - 1977, 1980, 2000, 525, 918, 2005, 2002, 2011, 525, 2015, - 525, 2016, -540, 2017, 525, 2022, 2025, 1440, 1580, 2028, - 1587, 3400, 1572, 1592, 2029, 2031, 1572, 1217, 525, 2032, - 1307, 523, 1572, 1218, 2034, 2064, 2033, 523, 2065, 1060, - 2098, 1230, 1640, 2099, 1234, 2102, 2106, 3365, 3231, 3232, - 2109, 3221, 2111, 817, 1235, 1572, 2114, 2112, 2113, 817, - 2135, 1231, 2182, 3400, 1989, 810, 1236, 525, 525, 2158, - 919, 810, 2155, 1569, 2183, 2189, 2156, 2201, 2202, 2206, - 880, 912, 2222, 2489, 1177, 913, 2231, 3124, -1831, 2492, - 2219, 2232, 2233, 2236, 2234, 2253, 985, 2235, 1237, 920, - 2257, 2268, 2258, 2261, 2273, 525, 2272, 1232, 872, 525, - 2274, 881, 3400, 2331, 525, 525, 2332, 2333, -2102, -2102, - -2102, 2345, 1953, 1954, 1955, 1956, 1957, 1958, 1043, 2355, - 2349, 2366, 2367, 2364, 2368, -1831, 1620, 2369, 1219, 2370, - 525, 525, 921, 2371, 2385, 525, 1022, 3455, 2388, 2386, - -1831, 1023, 1239, 1149, 2391, -1831, 2392, 2393, 1440, 2394, - -1831, 525, 2395, 2397, 525, 525, 525, 1439, 2418, -1831, - 2401, 2426, 1966, 1941, -1831, 2456, 1965, 1240, 2485, 2463, - 1569, 2473, 525, 719, 2464, 3416, 2465, 2493, 523, 525, - 2469, 2474, 525, 2505, 2507, 2491, 1242, 2512, 2513, 2514, - 2516, 823, 2523, 1233, 2517, 2518, -1831, 1561, 2519, 525, - 1024, 2550, 2522, 2538, 1569, 523, 2530, 2533, 3207, 2531, - 2539, 1230, 525, 2536, 2534, 819, -1831, 2535, 2546, 2537, - 1612, 819, 523, 2540, 2541, 2560, 2561, 817, 2568, 525, - 525, 1231, 2563, 3016, 2575, 2584, 2585, 2592, 2590, 810, - 2591, 2604, 1234, 2603, 817, 2606, 525, 2608, 525, 2609, - 2614, 2616, 1235, 2617, 2628, -666, 810, 2627, 2630, 922, - 2631, 525, 2634, 2638, 1236, -1831, 2639, 1766, -1831, 2642, - 923, 2644, 1025, 541, -1831, 2647, 2646, 1232, 1370, 719, - 719, 719, 2650, 2669, 2671, 1220, 1569, 2703, 1413, 2684, - 2690, 1440, 1561, 2716, 2702, 2721, 1237, 2733, -1359, 2715, - 1815, 2737, 3550, 2741, 2738, 924, 2691, 3354, 1026, 2692, - 2291, 2291, 2291, 2745, -1831, 2734, 2754, 1594, 525, 2764, - 872, 2775, 2772, 2795, 1027, 2778, 2781, 1307, 925, 1569, - 2796, 2271, 2782, 2783, 1028, 2807, 542, 2808, 2813, -1831, - 2832, 2280, 2839, 2283, 1238, 2784, 2294, 2961, 1222, 2821, - 1239, 2851, 2298, 2829, 2300, 1742, 926, 1858, 1859, 1861, - 1862, 719, 982, 2840, 1439, 2850, 1572, 2307, 1029, 2859, - 2861, 2862, 2310, 1233, 2865, 1240, 2315, 2316, 2317, 2318, - 1241, 2322, 2323, 2867, 2868, 2880, 525, 2889, 2874, 1206, - 543, 2908, 1913, 1631, 1242, 2875, 2912, 859, 2882, 819, - 2886, 525, 981, 2906, 2920, 2926, 2910, 2927, 1633, 544, - 719, 2953, 2933, 2969, 1030, 3036, 819, 3037, 1636, 3038, - 3045, 1031, 1234, 3042, 3046, -1831, 3053, 3054, 3059, 1561, - 3060, 3064, 1235, 3072, 3073, -1831, 3077, 2348, 3084, 1569, - 1686, 1913, 3085, 2117, 1236, 3090, 3110, 3112, 525, 1691, - 3116, 1224, 3120, 3130, 3131, -1831, 3134, -1831, -1831, 3180, - 3135, 3161, 3168, 1032, 3171, 3173, 3182, 3186, 545, 3187, - 3188, 523, 3194, 3415, 3195, -208, 1237, 1059, 3196, 3200, - 1941, 3405, 1033, 3407, 1942, 1943, 525, 3204, 1944, 1945, - 1946, 3205, 3206, 817, -1831, 3214, 3219, -1831, -1831, -1831, - 3217, 3220, 1572, 872, 3224, 3239, 3240, 1440, -2070, 1158, - 3417, 3244, 3419, 3238, -2071, -2072, 3537, -2073, 546, 525, - 547, -2074, 3241, -2075, -2076, 525, 525, 3498, -2077, -2078, - 1239, -2079, -2081, 3255, 3242, 2877, 3257, 548, -2082, -2083, - 525, 872, -2084, 549, -2085, -2086, 550, -2087, -2088, -2090, - 3491, 1034, -2091, -2092, -2093, 1240, 525, -2094, -2095, 525, - 3502, 525, -2096, -2097, -2098, -2099, -2100, -2101, 1572, 525, - -1312, 3245, 525, 525, 1242, 3272, 3253, 525, 525, 3083, - 3258, 1561, 3260, 3274, 525, 3277, 3276, 3280, 3286, 3486, - 1563, 3287, 2914, 1561, 3290, 1439, 1439, 3304, 3292, 525, - 3294, 1439, 3306, 3298, 3301, 3300, 3305, 2054, 3309, 525, - 3312, 3313, 2056, 3316, 2057, 2060, 521, 532, 77, 1022, - 3331, 2061, 557, 1561, 1023, 3332, 3336, 3339, 557, 525, - 1561, 2058, 807, 3342, 822, 3344, 3356, 2898, 825, 557, - 834, 3357, 2894, 834, -1311, 3364, 854, 854, 3366, 3372, - 854, 3374, 3375, 557, 557, 3402, 23, 3388, 3389, 3403, - 3390, 3406, 3409, 3412, 3410, 819, 3418, 3424, 1947, 3444, - 719, 1561, 3213, 3019, 719, 1561, 719, 1912, 3448, 3450, - 3451, 1561, 3454, 1024, 807, 807, 541, 3467, 525, 3468, - 525, 1948, 3460, 2938, 3472, 3469, 3477, 23, 3479, 2939, - 1569, 2291, 3481, 3164, 1561, 3021, 3484, 2295, 3075, 3488, - 854, -1359, 2940, 3485, 3490, 3499, 3489, 854, 557, 854, - 854, 854, 3495, 3497, 1858, 1859, 1861, 1862, 3504, 3509, - 3516, 3517, 3515, 3522, 3523, 3524, 2941, 3532, 2942, 3534, - 3542, 3526, 3552, 3048, 3536, 3209, 3555, 3557, 3573, 542, - 3576, 3554, 3553, 1373, 3590, 1025, 872, 3601, 3595, 3606, - 1900, 1949, -540, 1203, 3616, 3615, 1180, 2968, 525, 2299, - 2667, 1572, 3069, 1059, 1563, 3431, 1941, -540, 3530, 3494, - 1942, 1943, -540, 2972, 1944, 1945, 1946, 2901, 525, 525, - 3599, 1026, 2403, 525, 3227, 541, 525, 2756, 1156, 26, - 27, 28, 1059, 2362, 3513, 1941, 3583, 1027, 3352, 1942, - 1943, 3551, 3558, 1944, 1945, 1946, 1778, 1028, 3577, 3387, - -1359, 2649, 3063, 525, 2674, 3549, 2943, 2937, 3556, 2895, - 2856, 3022, 2645, -540, 3547, 1895, 2748, 1855, 2750, 2711, - 26, 27, 28, 525, 2761, 3281, 3044, 2633, 1705, 525, - 525, 1029, 872, -540, 525, 1572, 1463, 1464, 542, 525, - 2619, 1230, 525, 525, 2260, 1563, 33, 525, 1307, 1746, - 2786, 525, 1204, 1745, 3535, 525, 2629, 914, 2228, 3480, - 3408, 1231, 525, 2259, 811, 2605, 2230, 2497, 3282, 1750, - 3119, 3308, 2780, 1637, 2944, 2779, 1430, 1030, 523, 2945, - 3358, 2810, -540, 38, 1031, 2511, 3229, 33, 1414, 1416, - 1420, -540, 971, 1421, 2412, 1422, 2413, 1423, 2414, 1424, - 817, 1425, 1426, 3483, 1373, 3482, 525, 1232, 2959, 2558, - 2834, 546, 810, 972, 525, 2582, 40, 2622, 2960, 2580, - 2527, 3172, 2740, 3143, 38, 1991, 1032, 43, 2946, 2559, - 1465, 2853, 3470, 525, 2887, 2343, 549, 1907, 1211, 550, - 2504, 986, 1572, 3144, 2256, 1033, 2947, 2197, 1824, 2902, - 2199, 2694, 0, 0, 1950, 1951, 1952, 40, 1953, 1954, - 1955, 1956, 1957, 1958, 0, 0, 0, 1948, 43, 0, - 545, 2194, 0, 0, 0, 0, 3019, 2961, 0, 0, - 0, 0, 46, 0, 1373, 44, 0, 1373, 1373, 0, - 0, 0, 0, 0, 0, 0, 1948, 0, 0, 0, - 0, 0, 0, 1233, 0, 1561, 0, 0, 0, 45, - 0, 0, 0, 0, 1034, 0, 0, 0, 719, 1205, - 546, 0, 972, 2896, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 872, 1949, 0, 548, - 0, 0, -540, 2263, 2265, 549, 525, 2948, 550, 1913, - 0, 0, 1234, 0, 981, 0, 2949, 525, 1572, 0, - 0, 0, 1235, 0, 0, 0, 1949, 3264, 0, 1563, - 0, 0, 819, 525, 1236, 0, 2962, 0, 0, 0, - 0, 0, 1439, 1439, 1439, 1439, 1439, 1439, 0, 0, - 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, - 0, 1572, 2324, 0, 23, 0, 1237, 525, 0, 0, - 0, 912, 0, 0, 0, 913, 0, 0, 2340, 2340, - 0, 1909, 1911, 0, 525, 525, 0, 0, 525, 854, - 525, 0, 0, 0, 854, 0, 0, 854, 0, 0, - 0, 1561, 0, 0, 0, 557, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 525, 0, 0, 0, 0, - 1239, 0, 0, 0, 1563, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2078, 0, 0, 2917, 525, - 0, 2918, 2079, 2080, 0, 1240, 2081, 2082, 2083, 0, - 0, 1370, 0, 0, 0, 0, 0, 2420, 0, 0, - 0, 0, 0, 0, 1242, 0, 2963, 1561, 2970, 2964, - 0, 3019, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3023, 3024, 3025, 3026, 3027, 3028, 3029, - 3030, 3031, 3032, 719, 0, 0, 14, 15, 853, 0, - 0, 0, 861, 0, 0, 0, 0, 26, 27, 28, - 1950, 1951, 1952, 525, 1953, 1954, 1955, 1956, 1957, 1958, - 0, 0, 3370, 525, 1913, 525, 0, 525, 0, 0, - 0, 525, 0, 525, 0, 525, 523, 1439, 1439, 1950, - 1951, 1952, 23, 1953, 1954, 1955, 1956, 1957, 1958, 525, - 0, 0, 0, 0, 525, 0, 525, 0, 817, 0, - 0, 1563, 897, 0, 525, 0, 0, 0, 0, 900, - 0, 903, 1561, 907, 33, 0, 0, 719, 0, 1788, - 0, 0, 525, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 961, 557, 557, 0, 3428, - 0, 3430, 0, 0, 0, 2070, 0, 0, 3437, 0, - 0, 38, 0, 0, 0, 0, 0, 2100, 0, 2101, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 525, - 0, 0, 0, 1564, 0, 0, 0, 984, 532, 525, - 0, 3463, 0, 521, 40, 854, 0, 2119, 0, 0, - 0, 525, 0, 1439, 807, 43, 0, 3466, 1011, 1011, - 0, 807, 0, 0, 1011, 1038, 525, 0, 0, 0, - 1561, 0, 44, 0, 0, 0, 0, 834, 834, 834, - 0, 0, 834, 0, 525, 26, 27, 28, 1916, 523, - 1106, 1106, 834, 834, 0, 834, 45, 834, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 525, 854, - 46, 817, 0, 1563, 0, 557, 0, 0, 0, 2620, - 0, 0, 0, 525, 0, 1563, 0, 854, 0, 0, - 819, 523, 3019, 0, 719, 1917, 0, 0, 0, 3208, - 0, 854, 822, 0, 0, 0, 0, 0, 0, 0, - 2240, 2240, 33, 817, 1561, 1563, 1918, 525, 2383, 0, - 0, 0, 1563, 35, 0, 3437, 0, 0, 0, 0, - 0, 525, 525, 525, 1919, 0, 854, 1312, 1920, 23, - 523, 0, 0, 3559, 0, 37, 0, 0, 1323, 38, - 0, 0, 854, 854, 854, 854, 0, 0, 525, 0, - 0, 1921, 817, 1563, 1922, 0, 0, 1563, 1344, 3574, - 0, 0, 0, 1563, 1373, 0, 0, 1564, 0, 0, - 1923, 0, 40, 0, 1373, 0, 0, 1373, 0, 0, - 0, 2678, 0, 43, 0, 0, 1563, 0, 1566, 525, - 1011, 1038, 0, 854, 0, 0, 1437, 1567, 0, 0, - 44, 0, 1011, 1011, 0, 0, 0, 0, 0, 557, - 0, 1561, 0, 0, 0, 807, 0, 807, 0, 71, - 0, 0, 0, 0, 45, 0, 807, 0, 0, 0, - 0, 0, 0, 819, 2708, 0, 557, 0, 46, 71, - 0, 0, 809, 0, 0, 1561, 0, 0, 0, 0, - 0, 0, 2723, 1576, 0, 1022, 71, 0, 1564, 0, - 1023, 0, 0, 1924, 0, 871, 0, 0, 0, 0, - 0, 1925, 26, 27, 28, 819, 1373, 0, 0, 0, - 0, 0, 2084, 2085, 2086, 0, 2087, 2088, 2089, 2090, - 2091, 2092, 0, 1926, 809, 809, 887, 1370, 0, 0, - 0, 0, 0, 0, 557, 0, 0, 2762, 0, 2763, - 0, 0, 0, 2768, 0, 2771, 0, 0, 0, 1024, - 71, 0, 1927, 0, 819, 0, 0, 1561, 0, 1439, - 1439, 0, 0, 0, 0, 0, 0, 0, 0, 33, - 0, 1639, 0, 0, 1640, 0, 0, 0, 1641, 1642, - 0, 930, -2102, -2102, -2102, 0, 937, 1699, 0, 938, - 0, 0, 0, 0, 0, 0, 3355, 0, 0, 0, - 1561, 0, 1566, 557, 557, 0, 38, 0, 0, 1650, - 854, 1567, 0, 0, 0, 0, 1651, 0, 3362, 3363, - 0, 1025, 0, 0, 0, 0, 0, 0, 0, 2515, - 0, 0, 0, 1437, 1106, 1106, 0, 0, 0, 40, - 0, -1833, 3376, 1652, 0, 854, 1777, 0, 0, 0, - 43, 1022, 0, 0, 0, 0, 1023, 1026, 854, 0, - 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, - 0, 0, 0, 1027, 1568, 854, 0, 0, 0, 854, - 1217, 0, 0, 1028, 1825, 0, 1218, 0, 0, 0, - 0, 45, 0, 1566, 1230, 0, 0, 0, 0, 0, - 0, 0, 1567, 0, 0, 46, 0, 0, 0, 0, - 1561, 0, 1564, 0, 1231, 1024, 0, 1029, 0, 0, - 0, 0, 0, 0, 0, 3263, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1563, 0, 0, - 1653, -1833, 0, 1844, 0, 854, 23, 0, 0, 0, - 0, 0, 0, 0, 854, 1439, 0, 1654, 0, 0, - 1232, 1639, 1655, 1030, 1640, 1888, 0, 0, 1641, 1642, - 1031, 0, 0, 0, 961, 0, 0, 0, 0, 961, - 3113, 557, 557, 0, 557, 961, 2599, 1025, -1833, 0, - 0, 1219, 0, 0, 0, 0, 0, 0, 3012, 1650, - 1658, 0, 0, -1833, 0, 0, -2102, 1564, -1833, 0, - 0, 0, 1032, -1833, 0, 0, 0, 0, 0, 2625, - 2625, 0, -1833, 1026, 0, 0, 0, -1833, 0, 2708, - 3142, 1033, 0, 1652, 0, 0, 0, 995, 0, 1027, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1028, - 0, 0, 0, 0, 0, 1661, 1233, 0, 1568, -1833, - 0, 0, 0, 0, 1437, 1437, 0, 0, 0, 0, - 1437, 0, 521, 1563, 3543, 0, 0, 0, 0, -1833, - 0, 0, 0, 1029, 0, 1011, 0, 557, 1984, 26, - 27, 28, 1106, 1106, 0, 854, 0, 0, 2566, 0, - 1034, 807, 0, 807, 2007, 1234, 807, 0, 0, 0, - 0, 807, 0, 1106, 807, 1235, 807, 1566, 0, 0, - 807, 1439, 557, 0, 557, 0, 1567, 1236, -1833, 1030, - -2102, -1833, 0, 1210, 0, 0, 1031, -1833, 0, 1563, - 0, 0, 0, 0, 1564, 0, 0, -2102, 1220, 1568, - 0, 0, -2102, 0, 0, 0, 33, 1663, 0, 1237, - 0, 0, 0, 0, 0, 0, 0, 0, 1311, 0, - 0, 1561, 0, 0, 0, 0, 0, -1833, 1032, 0, - 0, 0, 0, 0, 1327, 1329, 1332, 1334, 71, 0, - -2102, 0, 0, 38, 0, 0, 0, 1033, 0, 0, - 0, 0, -1833, 0, 3170, 0, 0, 2301, 0, 0, - 0, 1222, 1566, 1239, 0, 0, 0, 558, 0, 0, - 0, 1567, 0, 558, 0, 0, 40, 808, 0, 2093, - 0, 0, 0, 0, 558, 1432, 0, 43, 1240, 0, - 0, 557, 0, 2302, 1563, 1661, 0, 0, 558, 558, - 0, 0, 0, 0, 44, 0, 0, 1242, 0, 0, - 859, 0, 0, 0, 1439, 1664, 1034, 0, -2102, -2102, - -2102, 2008, 1668, 1669, 1670, 1671, 1672, 1673, 45, 808, - 808, 961, 0, 0, 1437, 0, 0, 0, -1833, 0, - 0, 0, 46, 0, 0, 0, 1564, 0, -1833, 0, - 0, 0, 0, 0, 0, 0, 2818, 2820, 1564, 0, - 0, 0, 1106, 558, 1224, 0, 0, 0, -1833, 0, - -1833, -1833, 0, 0, 0, 0, 0, 2195, 0, 854, - 0, 854, 0, 0, 0, 0, 0, 0, 1564, 0, - 0, 854, 1563, 2211, 0, 1564, 0, -2102, 0, 1566, - 0, 0, 0, 0, 0, 1437, 0, -1833, 1567, 0, - -1833, -1833, -1833, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3259, 1568, 0, 0, 0, 0, 1230, 0, - 854, 0, 557, 0, 0, 0, 1564, 0, 0, 0, - 1564, 0, 0, 0, 2262, 2264, 1564, 0, 1231, 1370, - 1777, 557, 71, 871, 0, 0, 0, 0, 0, 0, - 0, 557, 2281, 557, 2285, 0, 557, 0, 0, 1564, - 0, 0, 557, 0, 557, 0, 1563, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 961, 557, 0, 0, - 0, 961, 557, 991, 1232, 0, 557, 557, 557, 557, - 0, 557, 557, 0, 1003, -2102, 0, 1769, 0, 0, - 0, 1019, 1668, 1669, 1670, 1671, 1672, 1673, 1568, 0, - 1796, 2344, 0, 1373, 0, 0, 0, 0, 0, 1323, - 3414, 854, 854, 854, 854, 854, 3329, 0, 0, 0, - 0, 1821, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1566, 2373, 0, 0, 0, 887, 0, 0, 0, - 1567, 0, 0, 1566, 0, 0, 0, 0, 0, 0, - 0, 2396, 1567, 0, 71, 0, 0, 0, 0, 0, - 0, 0, 0, 1563, 0, 0, 0, 0, 0, 0, - 1233, 0, 0, 1566, 0, 0, 0, 0, 0, 0, - 1566, 0, 1567, 0, 0, 0, 3012, 1849, 0, 1567, - 0, 0, 0, 0, 0, 0, 1868, 1563, 0, 0, - 0, 1437, 1437, 1437, 1437, 1437, 1437, 0, 0, 1437, - 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437, 1234, - 0, 1566, 0, 0, 0, 1566, 0, 0, 0, 1235, - 1567, 1566, 0, 0, 1567, 1568, 3126, 11, 0, 557, - 1567, 1236, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 854, 1566, 0, 0, 0, 0, 0, - 0, 0, 71, 1567, 807, 14, 15, 0, 0, 0, - 807, 0, 0, 1237, 0, 0, 557, 0, 0, 1563, - 0, 557, 0, 0, 0, 0, 0, 0, 0, 0, - 2509, 2509, 0, 0, 0, 809, 0, 1003, 0, 0, - 0, 0, 0, 0, 0, 0, 809, 0, 0, 0, - 0, 23, 0, 1639, 3456, 0, 1640, 0, 0, 23, - 1641, 1642, 1563, 0, 0, 0, 0, 1239, 0, 0, - 0, 1639, 0, 0, 1640, 0, 0, 1998, 1641, 1642, - 0, 1579, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1650, 1240, 1591, 0, 0, 0, 0, -2102, 0, - 0, 0, 557, 0, 0, 0, 0, 2552, 0, 1650, - 1564, 1242, 557, 0, 0, 0, -2102, 0, 0, 0, - 1618, 1373, 0, -1848, 0, 1652, 1373, 1568, 0, 0, - 558, 0, 0, 0, 0, 0, 1437, 1437, 0, 1568, - 0, 0, 0, 1652, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2093, 0, 0, 0, 0, - 0, 1437, 0, 0, 0, 0, 0, 0, 0, 1568, - 0, 0, 1563, 1909, 1911, 0, 1568, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3012, 807, 0, - 2576, 3429, 0, 0, 26, 27, 28, 0, 0, 0, - 557, 0, 26, 27, 28, 807, 0, 887, 887, 2211, - 887, 0, 0, 0, 0, 0, 0, 1568, 0, 0, - 0, 1568, -2102, -1848, 0, 0, 0, 1568, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -2102, - -2102, 0, 0, 0, -2102, 0, 1564, 0, 0, 557, - 1568, 0, 1437, 0, 1106, 557, 0, -2102, 0, 0, - 0, 33, -2102, 0, 0, 0, 0, 0, 0, 33, - -1848, 0, 35, 0, 0, 1844, 0, 0, 0, 0, - 0, 0, -2102, 0, 0, -1848, 0, 0, 0, 0, - -1848, 0, 0, 0, 37, -1848, 0, 0, 38, 0, - -2102, 0, 0, 0, -1848, 0, 38, 0, 0, -1848, - 0, 2196, 1564, 2198, 0, 1566, 0, 0, 39, 0, - 0, 558, 558, 2208, 1567, 0, 0, 0, 0, 0, - 0, 40, 0, 0, 0, 0, 0, 1661, 0, 40, - 0, -1848, 43, 0, 0, 0, 0, 1844, 0, 0, - 43, 0, 0, 0, 854, 1661, 0, 0, 0, 44, - 0, -1848, 2245, 0, 0, 1323, 0, 44, 1844, 854, - 854, 854, 0, 0, 0, 0, 0, 0, 0, 808, - 0, 71, 557, 45, 854, 0, 0, 854, 1909, 1911, - 0, 45, 0, 0, 854, 0, 0, 46, 0, 0, - 961, 1373, 0, 0, 0, 46, 0, 0, 0, 0, - -1848, 0, 0, -1848, 0, 0, 0, 1564, 0, -1848, - 0, 0, 1844, 1844, 0, 1844, 0, 0, 0, 0, - 0, 0, 0, 1563, 0, 0, 0, 0, 0, -2102, - 558, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1566, 0, 0, 521, 0, 0, -2102, 0, -1848, - 1567, 0, 0, 2356, 2357, 2359, 2360, 2361, 0, 0, - 0, 0, 2785, 0, 0, 0, 0, 0, 0, 0, - 854, 854, 854, 0, -1848, 0, 0, 0, 0, 0, - 557, 809, 1437, 809, 557, 0, 809, 0, 0, 0, - 557, 809, 0, 0, 809, 0, 809, 0, 0, 0, - 809, 0, 0, 0, 0, 1564, 1059, 1566, 0, 1941, - 854, 0, 0, 1942, 1943, 0, 1567, 1944, 1945, 1946, - 0, 0, 0, 0, 2093, 0, 0, 0, 0, 0, - 0, 0, 859, 0, 2857, 557, 0, -2102, 0, 557, - 0, 0, 0, 0, 1668, 1669, 1670, 1671, 1672, 1673, - 0, 0, 0, 0, 0, -2102, 0, 0, 0, 0, - -1848, 1568, 1668, 1669, 1670, 1671, 1672, 1673, 1437, 1437, - -1848, 0, 0, 0, 1457, 0, 0, 0, 0, 0, - 808, 0, 808, 71, 0, 0, 0, 0, 0, 1564, - -1848, 808, -1848, -1848, 0, 2480, 0, 2891, 0, 0, - 0, 1494, 0, 2211, 0, 0, 0, 0, 0, 0, - 0, 0, 1566, 0, 0, 0, 0, 0, 0, 854, - 0, 1567, 0, 557, 0, 1106, 0, 557, 557, -1848, - 0, 557, -1848, -1848, -1848, 1844, 1777, 1844, 1059, 1888, - 0, 1941, 0, 0, 0, 1942, 1943, 0, 0, 1944, - 1945, 1946, 1373, 0, 0, 0, 0, 0, 557, 0, - 2971, 0, 0, 0, 2143, 0, 3151, 0, 0, 1623, - 0, 0, 0, 557, 557, 557, 557, 557, 557, 557, - 557, 557, 557, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1564, 1568, 0, 0, - 0, 0, 0, 0, 2373, 0, 0, 0, 0, 0, - 1566, 854, 0, 0, 0, 0, 0, 0, 0, 1567, - 1948, 0, 0, 1777, 0, 0, 0, 0, 0, 0, - 1564, 0, 887, 0, 0, 0, 0, 1059, 558, 558, - 1941, 0, 0, 1888, 1942, 1943, 0, 0, 1944, 1945, - 1946, 0, 0, 1844, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1568, 1437, 3152, 0, 0, 0, 0, - 557, 0, 0, 0, 0, 0, 0, 854, 854, 854, - 854, 0, 0, 0, 0, 0, 0, 0, 0, 1437, - 1949, 0, 1437, 0, 1566, 0, 557, 961, 0, 0, - 0, 0, 0, 1567, 0, 3128, 0, 0, 1639, 0, - 0, 1640, 1564, 0, 0, 1641, 1642, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 557, 0, - 0, 0, 0, 0, 0, 3136, 557, 0, 0, 0, - 2552, 0, 0, 0, 0, 0, 1650, 0, 0, 0, - 0, 0, 1948, -2102, 0, 1564, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1568, 3165, - 0, 807, 2365, 0, 0, 0, 0, 0, 1106, 0, - 1652, 0, 0, 0, 71, 3177, 0, 0, 0, 2211, - 0, 0, 0, 0, 0, 2093, 0, 0, 0, 0, - 0, 1566, 0, 0, 0, 0, 0, 0, 0, 1777, - 1567, 0, 0, 0, 0, 1844, 558, 558, 0, 558, - 0, 0, 1949, 0, 0, 0, 0, 0, 961, 557, - 1437, 0, 0, 0, 0, 1566, 854, 0, 0, 0, - 0, 0, 0, 0, 1567, 2866, 0, 0, 0, 0, - 0, 1948, 0, 3228, 0, 0, 2713, 0, 0, 0, - 0, 0, 0, 0, 0, 1564, 1568, 0, 0, 0, - 0, 2729, 2730, 2732, 0, 0, 0, -2102, 0, 0, - 0, 0, 0, 0, 0, 0, 2743, 0, 0, 2746, - 0, 0, 0, 0, -2102, 0, 2755, 0, 0, -2102, - 0, 0, 0, 1950, 1951, 1952, 0, 1953, 1954, 1955, - 1956, 1957, 1958, 0, 809, 0, 0, 1566, 0, 0, - 809, 1949, 558, 0, 0, 0, 1567, 0, 0, 0, - 0, 3246, 0, 0, 0, 1844, 808, -2102, 808, 0, - 0, 808, 0, 0, 0, 0, 808, 0, 2373, 808, - 1568, 808, 0, 0, 0, 808, 0, 2019, 0, 2023, - 1566, 0, 0, 0, 0, 0, 3278, 0, 0, 1567, - 0, 0, 0, 1437, 0, 0, 0, 0, 0, 0, - 0, 0, 2792, 2793, 2794, 0, 0, 0, 0, 0, - 0, 0, 1661, 0, 0, 0, 0, 0, 0, 3295, - 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, + 525, 1133, 57, 913, 65, 82, 962, 1237, 1200, 719, + 53, 70, 103, 1030, 1165, 871, 525, 1437, 77, 68, + 857, 69, 99, 523, 883, 981, 1256, 884, 885, 94, + 1803, 1307, 1786, 1814, 1346, 1802, 1949, 2201, 77, 523, + 887, 1489, 784, 1310, 718, 888, 1695, 1767, 853, 2168, + 1595, 1411, 778, 2076, 1410, 522, 1409, 2599, 1407, 2124, + 1849, 2307, 2006, 2634, 2037, 1752, 1773, 1363, 525, 525, + 1777, 816, 559, 2487, 1819, 2589, 1352, 1369, 750, 2705, + 1881, 745, 50, 810, 2101, 2102, 51, 869, 52, 825, + 55, 523, 523, 904, 1807, 56, 59, 60, 3038, 818, + 61, 63, 66, 868, 868, 2991, 1671, 3022, 2572, 67, + 2574, 1674, 896, 1236, 1608, 1242, 80, 1246, 850, 2553, + 1256, 2588, 3035, 816, 816, 2627, 3020, 81, 83, 84, + 2993, 90, 91, 972, 93, 810, 810, 1376, 98, 102, + 975, 1012, 104, 2674, 2675, 2676, 1033, 2489, 964, 2688, + -454, 818, 818, 2884, 2819, 2337, -527, 2889, -371, 2333, + 1054, 1572, 1573, 1054, 2221, -1350, -531, -1928, 900, -1928, + 2224, 2172, 2439, 1210, 3434, -2068, -2068, 3233, 1585, 1211, + -864, -869, 1340, 2332, 820, -869, -1291, -1272, 1054, 1421, + 2696, 537, -1919, -872, -1288, -1288, -1936, 982, -1292, -1291, + -2059, -2059, -2054, -2054, -2077, -2077, -1289, -1289, 2126, -1919, + 1210, -1936, -2079, -2079, -1292, -831, 1211, 2706, 2692, -844, + -859, 3220, 2116, 820, 820, 23, 1146, -872, 1769, 2690, + 3168, 1758, 1679, 2697, 2683, 2116, 820, 3515, 3237, 1805, + 861, 1627, 1189, 1926, 1604, -480, 1629, 1192, 1928, 1461, + 981, 2507, 1675, 1356, 820, 953, -527, 1153, 1054, 2782, + 1817, 1340, -229, 3569, 1256, -1124, -531, -229, 820, 1818, + 2155, 2743, 2745, -1124, 2748, 1778, 1637, 1356, 2156, 1701, + 2468, 2469, 1054, 1340, 1212, 1331, 2329, 2234, 1627, 1007, + 875, 2475, 1628, 1629, 1926, 2479, 875, -1145, 1927, 1928, + 3203, 2713, 3179, 1769, 3311, -1145, -664, 1753, 538, 820, + 1639, 1698, 1787, 1627, 2662, 1790, 1791, 1628, 1629, 1154, + 880, 1212, 1033, 1637, 1332, 3394, 1761, 3134, 1966, 3136, + 2449, 1250, 3540, 1577, 1012, 3039, 3151, 3324, 1151, 2451, + 3570, 3507, 2012, 878, 2462, 2463, 2464, 878, 1637, 1587, + 3, 4, 1751, 2313, 1013, 3354, 2165, 1639, -609, 1747, + 1748, 1966, 1370, -609, 2927, 3355, 1676, 2901, 26, 27, + 28, 2856, 2630, 2858, 2103, 838, 3291, 3564, 3293, 3458, + 1712, 876, 1639, 113, -801, 1019, 1778, 876, 3341, 3013, + 3468, 3165, 2898, 1599, 2765, 2452, 2227, 2196, 3402, 880, + -2053, -2053, 1627, 1801, 2564, 3177, 1464, 105, 2857, 2412, + 3438, 3257, 1471, 3141, 879, 1627, 1821, 3231, 879, 2183, + 2656, 1020, 2907, 3454, 3455, 3202, 1862, 1590, 2897, 788, + 3340, 3185, 3571, 2657, -609, 33, 2127, 1462, 2928, 3190, + 2440, 1213, 3227, 3342, 2184, 3234, -527, 1022, 2908, 1591, + 1637, 3142, 3343, 3239, 2880, 2902, -531, 106, 1600, 3553, + 3235, 3403, 1310, 3180, 2128, 3228, 3166, 114, 1514, 3232, + 3522, 1639, 38, 1699, 3420, 3495, 3344, 839, 1213, 1341, + 3178, 1779, 2197, -609, 1639, 1147, 1763, 1155, 1713, 1156, + 1677, 2627, 880, 2627, 1014, 2754, 880, 3367, 3049, 2813, + 1214, 3040, 1595, 1333, 1215, 40, 2166, 1778, 2631, 1210, + 3183, 3322, 2259, 2228, 1808, 1211, 43, -527, 2314, 3508, + -801, 2903, 2929, 2904, 1926, 1251, 3469, -531, 1927, 1928, + 2450, 1776, 3356, 1589, 3523, 3255, 1216, 1240, -684, 2453, + 3565, 1215, 3541, 2321, 1053, 2330, 1820, 1926, 1776, 3345, + 928, 1927, 1928, 3395, 988, -2081, -2081, -2081, 1341, 2124, + 1749, 1148, 3346, 2235, 3064, 1750, 2782, 954, 3481, 3516, + 3169, 46, 1697, 1241, 1048, 3043, 1026, 1806, 3214, 2129, + 1341, 1690, 1616, 2483, 2318, 862, 719, 3572, 2047, 2131, + 3031, 1958, 1779, 2117, 3510, 1463, 2250, 962, 1572, 1573, + 3028, 2076, 1883, 2312, 1754, 1764, 2555, 1217, 1887, 3300, + 911, 3055, 3470, 2836, 912, 948, 1973, 3554, 3044, 1334, + 1212, 950, 877, 1585, 2378, 2009, 981, 3482, 2502, 3542, + 3332, 3312, 2752, 1994, -1124, 2576, -527, 2684, 2685, 2157, + 535, 1342, 1568, 881, 1217, 2221, -531, 881, 2755, 1803, + 2602, 3236, 2663, 2991, 539, 3014, 2420, 789, 3543, 1776, + 819, 2407, 1476, 3192, 3193, 2597, -1145, 2709, 2797, 2704, + 1590, -454, -454, 2413, 2171, -527, 1306, -527, 2993, -371, + -1928, 2384, -1928, 2058, 2059, -531, -1350, -531, 1582, 2698, + 1582, 2591, 1591, -864, -869, 3159, 3303, 1622, 911, -1291, + -1272, 3304, 912, 2441, 1590, -1919, 1592, 1574, 2126, -1936, + 2446, -1292, -1291, 1779, 1477, 2044, 1604, 1001, 1715, 3427, + 1345, 2688, -1919, 871, -1936, 1604, 1591, -1292, 1575, 1256, + 2097, 1256, 1580, -859, 1891, 3277, 1672, 2173, 1797, 2079, + 1594, 975, 2132, 3419, 1660, 1884, 1943, 980, 2480, 3426, + 3217, 3306, 2480, 2133, 1179, 1715, 858, 1004, 1360, 1361, + 3493, 1185, 1798, 3347, 1716, 2776, 3348, -229, -229, 2098, + 3316, 77, 2877, 1577, 871, 784, 1185, 1213, 3551, 1964, + 1776, 2501, 1360, 1361, 1157, 2255, 977, 525, 1657, 1658, + 1659, 1660, 2312, 1587, 1940, 1941, 1942, 1943, 525, 2421, + 2255, 1716, 2635, 1354, 3150, 1778, 1355, 967, 2865, 2422, + 523, 1655, 1656, 1657, 1658, 1659, 1660, 887, 3059, 3576, + 2638, 523, 888, 2766, 2767, 2768, 2769, 2035, 1934, 1393, + 1394, 864, 1717, 525, 525, 2045, 1244, 1187, 1201, 2878, + 1215, 1152, 816, 2447, 2051, 3548, 2256, 3209, 3491, 1038, + 2940, 1797, 1187, 816, 873, 3020, 1180, 525, 541, 1152, + 1039, 2624, 3152, 2866, 890, 1003, 2369, 874, 2401, 1769, + 818, 1709, 1245, 2402, 1792, 1798, 57, 2285, 65, 82, + 1770, 818, 2447, 1718, 53, 70, 103, 2288, 3218, 2284, + 2291, 2783, 77, 68, 1158, 69, 99, 3115, 889, 2119, + 1590, 1188, 2565, 94, 525, 719, 2545, 1166, 1299, 525, + 2991, 1616, 3228, 2636, 1688, 939, 3007, 1689, 3008, 3500, + 1718, 542, 1591, 892, 868, 3098, 850, 850, 3100, 850, + 3102, 850, 2403, 1811, 2546, 2993, 1592, 1778, 2308, 2309, + 2310, 820, 108, 1217, 3421, 1719, 2456, 907, 1399, 1400, + 2377, 2342, 916, 909, 2379, 2139, 50, 2381, 3336, 3566, + 51, 1299, 52, 2524, 55, 1778, 1457, 3309, 2247, 56, + 59, 60, 980, 1468, 61, 63, 66, -1928, 917, 525, + 525, 2076, 1719, 67, 23, 525, 2389, 940, 525, 525, + 80, 525, 525, 525, 525, 2283, 2394, 1352, 1309, 2827, + 77, 81, 83, 84, 784, 90, 91, 525, 93, 1778, + 1769, 1779, 98, 102, 525, 2294, 104, 939, 2911, 1793, + 2301, 1772, 1938, 1939, 1940, 1941, 1942, 1943, 3296, 1794, + 523, 525, 1299, 1560, 915, 1949, 3480, 523, 2577, 3483, + 2578, -2081, -2081, -2081, 918, 1938, 1939, 1940, 1941, 1942, + 1943, 1893, 2672, 525, 2547, 2286, 1054, 3285, 1454, 2548, + 2289, 2914, 816, 2673, 871, 2661, 1895, 1461, 3286, 816, + 1213, 1054, 525, 919, 810, 3501, 1480, 1803, 1776, 2140, + 1484, 810, 2037, 525, 525, 525, 941, 525, 525, 940, + 818, 719, 3125, 2665, 2677, 1888, 2141, 818, 1889, 2259, + 3323, 2142, 1590, 546, 3502, 971, 927, 1882, 2608, 3398, + 3415, 2445, 109, 1385, 1386, 541, 920, 1882, -2050, -2050, + 3249, 2597, 525, 110, 1591, 942, 1610, 26, 27, 28, + 934, 550, 3546, 2637, 541, 2638, -209, 2669, 1594, 2143, + 525, 525, 1210, 1779, 1703, 1704, 2664, 1710, 1211, 888, + 888, 2008, 888, 3388, 2009, 3389, 1152, 2400, 111, -540, + 943, 2404, 2600, 2033, 2406, 2639, 2034, 1054, 1185, 981, + -608, 1779, 1967, 1186, -540, -608, 525, 1968, 542, -540, + 525, 525, 911, 1393, 1394, 1608, 912, 1566, 1836, 46, + 525, 525, 525, 2060, 33, 525, 2505, 542, 2783, 938, + 2061, 2062, 946, 1019, 2063, 2064, 2065, 1583, 1584, 112, + 1776, 944, 2549, 911, 2714, 1779, 1560, 1615, 2159, 3314, + 2722, 1804, 2160, 2550, 2918, 2326, 868, 1837, 2327, 3440, + -540, 38, 1957, 1626, 1959, 1960, 1627, 2792, 1776, 1020, + 1628, 1629, 2395, 921, 1187, 2396, -608, 1042, 1043, 1044, + -540, 1299, 1047, 1212, 922, 1470, 951, 116, 941, 1469, + 1299, 536, 1838, 1474, 40, 1022, 2359, 952, 2360, 749, + 544, 1637, 2543, 2919, 1210, 43, 1140, 1141, -2081, 1143, + 1211, 1145, 1776, 837, 1299, -2051, -2051, 851, 822, 923, + 956, 2920, 2573, 1188, 955, -608, 2144, 942, 2433, -540, + 957, 2434, 1399, 1400, 988, 1639, 1560, 911, -540, -1272, + 1308, 912, 924, 1839, 1843, 2481, 1844, 1846, 2482, 2649, + 2484, 2651, 719, 2482, 1847, 2652, -2052, -2052, 2653, 1308, + 46, 719, 2700, 2646, 2658, 2648, -208, 2659, 3060, 958, + 925, 1210, 3562, 2725, 2076, 968, 2009, 1211, 980, 2789, + 2777, 986, 2482, 2790, 2784, 2793, 2034, 1876, 2794, 987, + 546, 2795, 971, 2872, 2794, 719, 2873, 2894, 989, 2896, + 525, 2127, 77, 930, 3029, 931, 784, 2396, 908, 546, + 3549, 547, 3550, 944, 992, 1212, 3030, 977, 550, 2327, + 3053, 995, 2921, 3054, 1026, 3061, 2611, 996, 3062, 2128, + 1898, 2922, -2081, 2989, 1885, 3116, 1886, 550, 2034, 932, + 1213, 933, 1985, 1463, 1986, 3250, 997, 1988, 2034, -2081, + 525, 525, 1992, 3575, -2081, 1995, 525, 1996, 525, 3525, + 998, 2000, 2938, 525, 525, 525, 525, 999, 2931, 3251, + 2695, 2457, 2482, 2458, 3537, 2459, 1006, 2460, 525, 525, + 1000, 523, 1212, 525, 3006, 525, -2055, -2055, 525, -540, + 2895, 3280, -2081, 525, 2034, 525, 525, 3287, 525, 2246, + 2009, 3297, 525, 1215, 3298, 1001, 523, 2596, 523, -2056, + -2056, 523, 1223, 816, 2814, 2815, 523, 3016, 1040, 523, + 3330, 523, 2930, 2396, 2939, 523, 1035, 3331, 3364, 3573, + 2327, 2034, 1224, 3424, 3574, 1216, 2396, 1046, 816, 3436, + 816, 818, 3437, 816, 2129, -2057, -2057, 1648, 816, 2130, + 810, 816, 810, 816, 2131, 810, 1560, 816, 911, 3384, + 810, 3385, 912, 810, 1045, 810, 818, 1604, 818, 810, + 3462, 818, 1213, 3463, 1608, 1048, 818, 3506, 1225, 818, + 3437, 818, -2058, -2058, 3547, 818, 1836, 3437, 525, 525, + 2803, 2805, 2806, 2802, 2804, 2801, 2800, 525, 525, 1182, + 1049, 1184, 2036, 2040, 1144, 525, 1217, -2060, -2060, 1150, + 77, 2038, 525, 2039, 2043, -2061, -2061, -2062, -2062, -2063, + -2063, 2042, -2064, -2064, 1161, 1837, -2065, -2065, 1167, -2066, + -2066, 2292, -2067, -2067, 1168, 1215, -2069, -2069, 719, 1213, + 1170, 1210, 525, -2070, -2070, 525, 1171, 1211, 1172, -2081, + 1560, 525, 525, 525, 525, 525, 525, 525, 525, 719, + 3222, -2071, -2071, 525, 525, 525, 1174, 2293, 525, 1175, + 2735, 1183, 525, 1202, 1226, 525, 525, 525, 525, 525, + 525, 525, 525, 525, -2072, -2072, 525, 1205, 523, 981, + -2073, -2073, 1207, 525, 2113, 1299, -2074, -2074, 1365, 2597, + -2076, -2076, 1215, 2168, 2203, -2078, -2078, 2132, 1208, 888, + 1209, 1839, -2080, -2080, 525, 1823, 1824, 1221, 2133, 3196, + 2066, 2067, 2068, 1227, 2069, 2070, 2071, 2072, 2073, 2074, + 2222, 2223, 2097, 1228, 1216, -659, -659, 525, 1217, -663, + -663, -662, -662, 1395, 1396, 1229, 1248, 1626, 525, 525, + 1627, 1158, 1212, 1222, 1628, 1629, 1302, -2081, 1399, 1400, + 3160, 3156, 3157, 2938, 1655, 1656, 1657, 1658, 1659, 1660, + 2727, 2729, 3533, 3534, 3559, 3560, 1239, 1230, 1683, 1684, + 2616, 2617, 1305, 1243, 1247, 1637, 1306, 1311, 1560, 1313, + 1317, 1329, -2081, 1327, 1337, 1330, 1338, 719, 1344, 719, + 1348, 1347, 1353, 2888, 1372, 1217, 1371, 1377, 1435, 1451, + 1448, 1458, 1450, 1465, 1466, 2012, 1472, 1473, 1479, 1639, + 1485, 1483, 1562, 1563, 1565, -835, -842, 1574, 3012, 1578, + 3213, 1232, 2271, 1624, 2275, 3052, 46, -684, 3023, 525, + -685, -832, -833, 1299, 1588, -836, 525, 525, 3524, 2251, + 1589, -834, 3526, 3041, -540, 1668, 1233, 1609, 1619, 2260, + 1621, 2263, 1666, 1365, 2274, 1682, 541, 1692, 1670, -540, + 2278, 1691, 2280, 1696, -540, 1235, 1700, 3363, 3276, 1702, + 3127, 1186, 1188, 1737, 2542, 2287, 820, 1299, 1739, 1741, + 2290, -1336, 1775, 1756, 2295, 2296, 2297, 2298, 1781, 2302, + 2303, 2363, 1774, 1776, 1782, 719, 1783, 3567, 1788, 1213, + 1795, 1800, 1299, 525, 1796, 113, -2081, 1810, 1816, 1826, + 1827, 980, 1828, 1832, 1835, -540, 1841, 1842, 1850, 542, + 1851, 1858, 1860, -2081, 1854, 1857, 1861, 1560, -2081, 1863, + 1864, 525, 525, 1365, 525, -540, 1365, 1365, 1877, 1560, + 525, 525, 525, 525, 525, 525, 2597, 1878, 525, 525, + 525, 525, 525, 525, 525, 525, 525, 525, 2299, 2470, + 1882, 1431, 1215, 525, 525, 2473, -2081, 525, 1890, 1560, + 1954, 2989, 1626, 970, 525, 1627, 1560, 1915, 1917, 1628, + 1629, 3512, 1965, 2362, -540, 1918, 1920, 1923, 1946, 1983, + 1955, 1962, 1987, -540, 2300, 1993, 525, 14, 15, 1997, + 525, 1998, 525, 1999, 23, 2004, 525, 1568, 2010, 2867, + 1637, 2007, 2015, 1575, 1560, 1580, 3363, -2081, 1560, 2011, + 525, 1648, 1299, 523, 1560, 2013, 2014, 2016, 2046, 523, + 2047, 1054, 1627, 3197, 3198, 3328, 2080, 2081, 2084, 3188, + 2087, 2090, 2093, 23, 1639, 2092, 2095, 1560, 2094, 2135, + 2136, 545, 541, 2115, 2138, 816, 2162, 2163, 3363, 525, + 525, 816, 2169, 2181, 23, 1217, 3097, 810, 1430, 1894, + 1896, 984, 2182, 810, 1549, 2186, 879, -1336, 2199, 2212, + 2202, 2213, 2211, 818, 2214, 2216, 2215, 2233, 2237, 818, + 2238, 2241, 2248, 2252, 2253, 2254, 880, 525, 2334, 2324, + 525, 546, 1037, 971, 2328, 525, 525, 3363, 2343, 2552, + 2345, 871, 1608, 2346, 2349, 542, 2347, 2350, 2348, 2364, + 548, 2365, 2367, -2081, 2372, 2373, 549, 1142, 2376, 550, + 525, 525, 3417, 2370, 2371, 525, 2374, 2380, 2397, 2405, + 1951, -2081, 1926, 2435, -540, 1950, 2442, 26, 27, 28, + 2443, 525, 2444, 1730, 525, 525, 525, 2466, -2081, 2448, + 2454, 2474, 1431, -2081, 2486, 2488, 2455, 2493, 3379, 2341, + 2472, 2494, 525, 719, 2495, 822, 2497, 2498, 523, 525, + 2499, 2500, 525, 2503, 2511, 2504, 26, 27, 28, 2512, + 2515, 2514, 3174, 1600, 2516, 2517, 2868, 2544, 2518, 525, + 2519, -2081, 2520, 2521, 2539, 523, 2551, 26, 27, 28, + 2522, 1551, 525, 911, 33, 2560, 1170, 912, 2568, 2536, + 2582, 2537, 523, 2561, 2579, 2566, 2567, 2580, 2989, 525, + 525, -2081, 2584, 2585, 2590, 2592, 1557, 816, 1655, 1656, + 1657, 1658, 1659, 1660, 2593, -665, 525, 2603, 525, 810, + 2604, 38, 2606, 33, 816, 2607, 1648, 1549, 2610, 2614, + 1885, 525, 1362, 2615, 35, 818, 810, 2620, 1754, 2623, + 2622, 2618, 1405, 2626, 33, 2645, 2647, 1803, 2678, 719, + 719, 719, 818, 2679, 40, 2660, 37, 2666, 2911, 2052, + 38, 2667, 2668, 2680, 2912, 43, 2681, 546, 2693, 971, + 2694, 2082, 2699, 2083, 3317, 2712, 2711, 2913, 2715, 2716, + 2723, 38, 44, 2719, 2271, 2271, 2271, 2732, 525, 1582, + 2742, 2750, 549, 40, 1299, 550, 2753, 2756, 2773, 2774, + 2099, 2914, 871, 2915, 43, 2785, 45, 2760, 2786, 2759, + 1680, 2761, 2834, 2762, 40, 981, 2810, 1549, 2799, 2823, + 46, 44, 2835, 2791, 1843, 43, 1844, 1846, -2081, 2847, + 719, 2807, 2817, 2848, 1847, 1560, 2824, 2832, 2838, 2853, + 2862, 2879, 44, 2855, 2859, 45, 2881, 2885, 2883, 2893, + 2926, 2942, 2900, 2906, 2899, 525, 3009, 1620, 3010, 46, + 3033, 3011, 1431, 1431, 1551, 1898, 45, 1623, 1431, 3015, + 525, 980, 3018, 3019, 3037, 3026, 3032, 3045, 3046, 719, + 2869, 3027, 3057, 2327, 3050, 3058, 3083, 3063, 1673, 1557, + 3085, 2916, 3089, 3093, 3106, 3103, 3368, 1678, 3370, 2097, + 1223, 3104, 3107, 3149, 2220, 2220, 3128, 3135, 3138, 3147, + 3140, 2718, 3153, 3154, 1898, 3171, 3155, 525, 3161, 3378, + 1224, 3162, 3163, 3167, 3172, 3181, 3173, 3184, 3186, 3187, + 3191, -2049, -2050, -2051, -2052, -2053, -2081, 3205, -2054, -2055, + 523, -2056, -2057, 1655, 1656, 1657, 1658, 1659, 1660, -2058, + -2060, -2061, 3206, -2062, 1551, 3221, -2063, 525, 3207, 2917, + 3380, 3499, 3382, -2064, 2918, -2065, 1225, 3208, 1365, 1924, + 1925, -2066, 816, 1560, 1152, 1945, -2067, -2069, 1365, 1557, + -2070, 1365, 3223, -2071, 871, -2072, 3238, 3204, -2073, 3460, + 525, 3240, -2074, -2075, -2076, -2077, 525, 525, 3453, 3243, + 818, 3464, -2078, -2079, -2080, -1289, 3210, 2850, 525, 3242, + 3252, 3253, 3211, 2919, 3264, 3219, 3224, 3226, 3246, 3256, + 871, 3258, 525, 3270, 3260, 525, 3266, 525, 3267, 3272, + 3275, 2920, 3448, 3271, 1560, 525, 2934, 1549, 525, 525, + 3279, 3294, 3299, 525, 525, 1053, 3295, 3302, 1926, 3305, + 525, 541, 1927, 1928, 3307, 3319, 1929, 1930, 1931, 3320, + 3329, -1288, 1226, 3327, 3335, 525, 3337, 3338, 3351, 3352, + 3353, 2887, 3365, 2829, 3366, 525, -1336, 1365, 521, 532, + 2036, 2040, 3369, 3372, 557, 3373, 3375, 2871, 77, 2038, + 557, 2039, 2043, 3381, 807, 525, 821, 3386, 3180, 2042, + 824, 557, 833, 3406, 3410, 833, 3416, 3412, 852, 856, + 3413, 1227, 856, 3429, 542, 557, 557, 3422, 3430, 3431, + 3434, 1228, 3439, 3229, 1897, 3441, 3443, 3131, 3446, 3447, + 3459, 1549, 2921, 1229, 3450, 3451, 719, 3452, 3466, 2992, + 719, 2922, 719, 3457, 23, 3477, 807, 807, 3461, 2210, + 3478, 3471, 3484, 3504, 525, 3479, 525, 3485, 3494, 3514, + 3486, 3517, 3496, 3538, 2890, 1230, 3498, 2891, 543, 3515, + 3519, 2271, 852, 3535, 1551, 2994, 3516, 2275, 3552, 856, + 557, 856, 856, 856, 3488, 3563, 3557, 544, 3568, 3048, + 1843, 3577, 1844, 1846, 2943, 3021, 3578, 2496, 2941, 1557, + 1847, 1173, 2279, 2643, 2945, 3393, 2874, 3492, 3456, 2996, + 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, 3005, 1232, + 3561, 3194, 2734, 3475, 3042, 2382, 1149, 3545, 3315, 3513, + 3520, 3539, 1766, 3350, 2625, 2650, 525, 871, 3036, 1560, + 3511, 3518, 2910, 2621, 1233, 3509, 545, 2995, 1880, 2728, + 2726, 2689, 2739, -208, 3247, 1840, 525, 525, 3017, 1933, + 2609, 525, 1693, 1235, 525, 1455, 2595, 2240, 1551, 1549, + 1733, 1456, 2764, 3497, 2605, 2208, 1734, 3442, 3371, 2239, + 1738, 811, 2581, 2478, 3274, 3092, 1422, 26, 27, 28, + 2757, 525, 2758, 1557, 2788, 3321, 546, 1457, 547, 1005, + 3445, 991, 2492, 2391, 2392, 2393, 525, 3444, 1552, 2534, + 2812, 2598, 525, 525, 2558, 548, 2508, 525, 1560, 1974, + 3111, 549, 525, 1406, 550, 525, 525, 2556, 871, 1934, + 525, 1299, 913, 3139, 525, 1408, 1412, 1413, 525, 1414, + 1415, 2535, 1416, 2826, 2860, 525, 1417, 3432, 985, 2485, + 2322, 1204, 2575, 23, 33, 1418, 1892, 2177, 2670, 2875, + 2179, 523, 1431, 1431, 1431, 1431, 1431, 1431, 897, 0, + 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, 1431, + 0, 0, 0, 1812, 0, 2601, 2601, 0, 0, 525, + 0, 38, 0, 816, 0, 0, 0, 525, 0, 0, + 0, 0, 0, 0, 0, 810, 1551, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 525, 0, 1549, 0, + 0, 818, 0, 0, 40, 1560, 0, 0, 0, 0, + 1549, 1557, 0, 2174, 0, 43, 0, 1223, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, + 15, 860, 44, 0, 0, 0, 0, 1224, 0, 2992, + 1549, 0, 3175, 0, 0, 0, 0, 1549, 0, 2414, + 2415, 2416, 2417, 2418, 2419, 0, 45, 2423, 2424, 2425, + 2426, 2427, 2428, 2429, 2430, 2431, 2432, 0, 0, 0, + 46, 1552, 0, 71, 0, 23, 26, 27, 28, 0, + 0, 719, 0, 1225, 2932, 1549, 2243, 2245, 0, 1549, + 0, 0, 0, 71, 2933, 1549, 809, 0, 899, 0, + 902, 0, 906, 0, 0, 0, 1016, 0, 0, 525, + 71, 1017, 871, 0, 3230, 0, 1898, 980, 1549, 870, + 525, 1560, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, + 1942, 1943, 1431, 1431, 0, 1551, 525, 0, 0, 0, + 0, 0, 0, 33, 0, 2304, 0, 1551, 809, 809, + 886, 0, 0, 2934, 0, 0, 0, 0, 2319, 2319, + 1557, 1552, 0, 0, 1560, 0, 0, 0, 0, 525, + 1018, 0, 1557, 0, 71, 0, 0, 1551, 0, 1226, + 38, 525, 525, 0, 1551, 525, 0, 525, 0, 0, + 0, 856, 0, 0, 0, 0, 856, 0, 0, 856, + 0, 0, 1557, 0, 0, 0, 0, 557, 0, 1557, + 0, 0, 525, 40, 0, 0, 0, 0, 26, 27, + 28, 0, 1551, 0, 43, 0, 1551, 0, 1227, 0, + 0, 1362, 1551, 0, 0, 0, 525, 2399, 1228, 2540, + 2541, 44, 1019, 0, 0, 0, 0, 1557, 1431, 0, + 1229, 1557, 2935, 2796, 2798, 1551, 0, 1557, 0, 0, + 0, 0, 0, 0, 0, 45, 0, 2992, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1020, 46, + 1557, 0, 1230, 0, 0, 33, 0, 0, 0, 719, + 0, 0, 0, 0, 1021, 0, 35, 0, 0, 0, + 0, -1810, 3333, 0, 1022, 0, 0, 0, 0, 525, + 0, 0, 0, 3318, 0, 0, 0, 0, 37, 525, + 0, 525, 38, 525, 1898, 0, 0, 525, 0, 525, + 0, 525, 523, 0, 3325, 3326, 1232, 0, 1023, 0, + 0, 0, 525, 0, 0, 0, 0, 525, 1016, 525, + 0, 0, 0, 1017, 0, 40, 0, 525, 3339, 1199, + 0, 1233, 0, 0, 816, 0, 43, 0, 0, 0, + 719, 0, 0, 0, 0, 525, 3390, 0, 3392, 0, + 1235, 1552, 2936, 44, 1024, 2937, 0, 0, 0, 0, + 0, 1025, 818, 0, 0, 0, 0, 960, 557, 557, + 0, -1810, 0, 0, 0, 3399, 0, 45, 0, 0, + 0, 0, 1018, 0, 0, 1365, 0, 0, 3425, 0, + 0, 46, 525, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 525, 1026, 3428, 0, 1549, 0, 0, 983, + 532, 0, 0, 0, 525, 521, 0, 856, -1810, 0, + 0, 0, 1027, 0, 0, 0, 807, 0, 525, 0, + 1009, 1009, 0, -1810, 0, 1009, 1032, 0, -1810, 0, + 0, 0, 0, -1810, 0, 1552, 525, 0, 833, 833, + 833, 523, -1810, 833, 1019, 0, 0, -1810, 0, 0, + 0, 0, 0, 833, 833, 1776, 833, 0, 833, 0, + 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 856, 0, 0, 816, 0, 525, 557, 0, 0, -1810, + 1020, 1028, 0, 523, 2992, 0, 719, 0, 856, 0, + 929, 0, 0, 0, 0, 936, 1021, 0, 937, -1810, + 0, 818, 856, 821, 0, 0, 1022, 0, 0, 525, + 3099, 0, 0, 0, 0, 816, 0, 0, 0, 3521, + 0, 3399, 0, 525, 525, 525, 0, 0, 0, 0, + 1431, 1431, 523, 1551, 1549, 0, 0, 856, 1304, 1223, + 1023, 0, 0, 818, 0, 3536, 3505, 0, -1810, 1315, + 525, -1810, 0, 856, 856, 856, 856, -1810, 1557, 1224, + 0, 0, 0, 0, 816, 0, 2654, 0, 558, 1336, + 0, 0, 71, 1552, 558, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 558, 1024, 0, 0, 0, + 0, 525, 818, 1025, 0, 1549, 0, -1810, 0, 558, + 558, 1009, 1032, 0, 856, 1225, 0, 1429, 0, 0, + 0, 0, 0, 1009, 1009, 0, 0, 0, 2686, 557, + 0, 0, -1810, 0, 0, 807, 0, 0, 0, 0, + 0, 0, 807, 0, 0, 1026, 2701, 2840, 2841, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3314, - 0, 0, 0, 0, 0, 1950, 1951, 1952, 0, 1953, - 1954, 1955, 1956, 1957, 1958, 0, 0, 0, 0, 0, - 0, 1618, 0, 3326, 0, 0, 0, 1568, 0, 0, + 1365, 0, 0, 0, 1027, 1365, 0, 0, 0, 1564, + 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, + 0, 1551, 0, 0, 0, 0, 0, 0, 0, 0, + 858, 1362, 0, 1901, 0, 0, 0, 0, 0, 0, + 0, 2740, 0, 2741, 0, 0, 1557, 2746, 0, 2749, + 1549, 1226, 1894, 1896, 0, 0, 0, 0, -1810, 0, + 557, 0, 0, 0, 0, 0, 0, 0, -1810, 0, + 0, 23, 1552, 1028, 0, 0, 0, 0, 1431, 0, + 1902, 0, 1551, 0, 1552, 0, 0, 0, -1810, 0, + -1810, -1810, 0, 0, 0, 0, 994, 0, 0, 0, + 1227, 1903, 0, 3086, 0, 0, 0, 1557, 0, 0, + 1228, 1685, 0, 1687, 1552, 0, 0, 0, 0, 1904, + 0, 1552, 1229, 1905, 0, 0, 0, -1810, 557, 557, + -1810, -1810, -1810, 0, 0, 856, 71, 870, 0, 0, + 0, 0, 0, 0, 0, 0, 1906, 0, 3110, 1907, + 1549, 0, 0, 0, 1230, 0, 0, 0, 1429, 1552, + 0, 0, 0, 1552, 0, 1908, 0, 0, 0, 1552, + 856, 1765, 0, 0, 0, 0, 0, 990, 0, 0, + 0, 0, 0, 856, 0, 3056, 0, 1551, 1002, 0, + 0, 1203, 1552, 0, 1554, 0, 0, -1812, 0, 0, + 856, 0, 0, 3391, 856, 0, 0, 0, 1232, 1813, + 1555, 0, 1557, 0, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 722, 0, 0, 1303, 0, 0, 1549, + 0, 0, 0, 1233, 0, 0, 0, 886, 0, 1431, + 0, 0, 1319, 1321, 1324, 1326, 0, 1626, 0, 0, + 1627, 0, 1235, 0, 1628, 1629, 0, 71, 1909, 0, + 0, 1894, 1896, 0, 0, 0, 1910, 1829, 0, 856, + 0, 0, 0, 1365, 0, 0, 0, 0, 856, 0, + 723, 33, 0, 0, 0, 1637, 0, 1551, 1911, 1873, + 0, 0, -2081, 1424, 0, 0, 724, -1812, 960, 2985, + 0, 0, 0, 960, 0, 557, 557, 0, 557, 960, + 0, 0, 1557, 0, 0, 0, 0, 1912, 38, 1639, + 0, 0, 0, 0, 0, 0, 1053, 0, 0, 1926, + 0, 0, 2686, 1927, 1928, 0, 1549, 1929, 1930, 1931, + 0, 0, 0, 0, -1812, 725, 3176, 0, 0, 0, + 0, 40, 0, 0, 0, 726, 0, 0, 0, -1812, + 0, 0, 43, 0, -1812, 71, 1551, 0, 727, -1812, + 1549, 0, 0, 728, 0, 0, 0, 1554, -1812, 44, + 0, 0, 1431, -1812, 2839, 0, 0, 0, 1429, 1429, + 0, 1557, 0, 1555, 1429, 0, 521, 809, 0, 0, + 0, 0, 729, 45, 809, 0, 0, 0, 0, 1009, + 0, 557, 1969, 0, 0, -1812, -2081, 46, 0, 856, + 0, 807, 0, 807, 0, 0, 807, 0, 0, 0, + 0, 807, 0, -2081, 807, -1812, 807, 0, -2081, 1567, + 807, 0, 557, 0, 557, 730, 0, 0, 0, 731, + 0, 1579, 1549, 0, 0, 0, 0, 0, 0, 0, + 0, 558, 0, 0, 0, 0, 0, 1554, 0, 0, + 0, 0, 0, 1551, 0, 0, -2081, 0, 1606, 0, + 0, 0, 0, 1555, -1812, 0, 0, -1812, 0, 3248, + 0, 0, 0, -1812, 0, 1549, 0, 0, 1557, 0, + 0, 0, 3137, 0, 0, 0, 0, 1551, 0, 1757, + 1552, 0, 0, 544, 0, 0, 0, 1932, 0, 732, + 0, 0, 1784, 0, 0, 0, 0, 0, 0, 0, + 1365, 1648, 1557, -1812, 733, 0, 0, 0, 0, 0, + 1933, 0, 0, 1809, 0, 0, 0, 0, 0, 2075, + 0, 0, 0, 0, 0, 0, 0, 0, -1812, 0, + 0, 2086, 0, 0, 886, 886, 0, 886, 0, 734, + 0, 1556, 735, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 736, 0, 0, 737, 0, 0, 1551, + 0, 3377, 0, 0, 0, 0, 0, 0, 1549, 0, + 960, 0, 0, 1429, 738, 0, 0, 0, 1834, 0, + 1934, 0, 0, 0, 1557, 0, 858, 1853, 739, 0, + 0, 0, 0, 0, 740, 741, 0, 0, 0, 0, + 0, 0, 1551, -2081, 0, 742, 0, 0, 0, 0, + 0, 743, 0, 0, -1812, 0, 0, 2175, 1552, 856, + 0, 856, 558, 558, -1812, 0, 0, 1557, 0, 0, + 0, 856, 0, 2191, 0, 0, 0, 0, 0, 744, + 3225, 0, 0, 0, -1812, 1429, -1812, -1812, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1554, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, + 856, 0, 557, 1555, 0, 0, 0, 0, 0, 1552, + 0, 0, 0, -1812, 2242, 2244, -1812, -1812, -1812, 0, + 1765, 557, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 557, 2261, 557, 2265, 1551, 557, 71, 0, 0, + 0, -2081, 557, 0, 557, 0, 0, 0, 1655, 1656, + 1657, 1658, 1659, 1660, 1556, 0, 960, 557, 1981, 0, + 1557, 960, 557, 0, 0, 0, 557, 557, 557, 557, + 558, 557, 557, 0, 0, 0, 0, 0, 3292, 0, + 0, 1554, 0, 0, 0, 0, 0, 0, 2323, 0, + 0, 0, 0, 0, 0, 0, 1315, 1555, 856, 856, + 856, 856, 856, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1552, 0, 0, 0, 0, 2352, + 0, 0, 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, + 1941, 1942, 1943, 0, 0, 0, 0, 0, 2375, 0, + 0, 0, 0, 809, 1556, 809, 0, 2985, 809, 0, + 0, 0, 0, 809, 0, 1549, 809, 0, 809, 0, + 0, 0, 809, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1827, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1429, 1429, + 1429, 1429, 1429, 1429, 0, 0, 1429, 1429, 1429, 1429, + 1429, 1429, 1429, 1429, 1429, 1429, 0, 0, 0, 0, + 0, 0, 0, 1449, 1552, 0, 0, 0, 0, 1554, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, + 0, 0, 0, 0, 0, 1555, 1482, 0, 856, 0, + 0, 0, 0, 0, 0, 71, 0, 0, 807, 0, + 0, 0, 0, 0, 807, 0, 0, 0, 0, 0, + 557, 0, 0, 0, 0, 557, 0, 0, 0, 0, + 0, 0, 3418, -1827, 2490, 2490, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2176, 0, + 2178, 0, 1551, 1552, 0, 0, 0, 0, 1626, 0, + 2188, 1627, 0, 0, 1611, 1628, 1629, 1630, 1631, 1632, + 1633, 1634, 0, 0, 0, 0, 0, 1557, 0, 0, + -1827, 0, 0, 0, 0, 2123, 1635, 0, 0, 0, + 0, 0, 0, 0, 0, -1827, 1637, 0, 0, 2225, + -1827, 0, 0, 1638, 0, -1827, 557, 0, 0, 0, + 2528, 0, 0, 0, -1827, 557, 0, 0, 0, -1827, + 0, 0, 0, 0, 1556, 0, 0, 0, 1554, 0, + 1639, 0, 558, 558, 0, 0, 0, 0, 1429, 1429, + 1554, 0, 0, 0, 1555, 0, 0, 0, 0, 0, + 0, -1827, 0, 0, 886, 0, 1555, 2075, 1626, 0, + 1552, 1627, 0, 1429, 2985, 1628, 1629, 0, 0, 0, + 1554, -1827, 1053, 0, 0, 1926, 0, 1554, 0, 1927, + 1928, 0, 0, 1929, 1930, 1931, 1555, 0, 0, 0, + 807, 0, 0, 1555, 1552, 0, 1637, 2335, 2336, 2338, + 2339, 2340, 557, -2081, 0, 0, 0, 807, 0, 0, + 0, 2191, 0, 0, 0, 1554, 0, 0, 1556, 1554, + -1827, 0, 0, -1827, 0, 1554, 0, 1640, 0, -1827, + 1639, 1555, 0, 0, 0, 1555, 0, 0, 0, 0, + 0, 1555, 0, 0, 1641, 0, 0, 0, 1554, 1642, + 0, 557, 0, 0, 1429, 0, 0, 557, 0, 0, + 0, 0, 0, 0, 1555, 0, 0, 0, 0, -1827, + 0, 0, 1643, 1644, 0, 0, 1552, 1829, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1645, 0, 0, + 0, 2344, 0, 0, -1827, 2842, 0, 0, 0, 0, + 0, 0, 0, 71, 0, 0, 0, 0, 0, 558, + 558, 0, 558, 0, 0, 0, 0, 0, 0, 1552, + 0, 0, 0, 0, 0, 1646, 0, -2081, 1647, 0, + 0, 0, 0, 0, 0, 0, 0, 2461, 0, 0, + 0, 0, 1648, 0, -2081, 1649, 0, 0, 1829, -2081, + 0, 0, 858, 0, 0, 856, 1556, 0, 0, 0, + 0, 0, 0, 2236, 0, 0, 1315, 0, 0, 1829, + 856, 856, 856, 0, 0, 0, 0, 0, 0, 0, + -1827, 0, 0, 557, 0, 856, 1933, -2081, 856, 0, + -1827, 0, 0, 0, 0, 856, 0, 0, 0, 0, + 0, 960, 0, 0, 0, 0, 0, 0, 0, 0, + -1827, 0, -1827, -1827, 0, 558, 0, 0, 0, 0, + 0, 0, 1552, 1829, 1829, 0, 1829, 0, 0, 0, + 809, 0, 0, 0, 0, 0, 809, 0, 0, 0, + 0, 0, 1648, 0, 1650, 0, 2001, 0, 2005, -1827, + 0, 0, -1827, -1827, -1827, 521, 1934, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1566, 2143, 0, 0, 0, 557, 2104, 0, 0, 1567, - 557, 0, 0, 0, 0, 0, 0, 2586, 0, 0, - 0, 1568, 0, 0, -2102, 0, 0, 0, 809, 0, - 0, 1059, 0, 0, 1941, 0, 557, 0, 1942, 1943, - 0, 0, 1944, 1945, 1946, 809, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1564, 0, 557, 557, - 0, 2909, 0, 0, 1950, 1951, 1952, 0, 1953, 1954, - 1955, 1956, 1957, 1958, 0, 854, 0, 1777, 0, 0, - 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 854, 0, 0, 3397, - 0, 0, 0, 1568, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1437, - 0, 1106, 0, 557, 1011, 0, 1011, 0, 0, 0, - 0, 557, -2102, 0, 0, 0, 0, 0, 0, 1668, - 1669, 1670, 1671, 1672, 1673, 0, 1568, 558, 0, 0, - 1106, 0, 0, 3052, 3177, 0, 0, 0, 0, 0, - 1639, 854, 0, 1640, 0, 0, 558, 1641, 1642, 0, - 0, 0, 0, 0, 0, 0, 558, 0, 558, 0, - 0, 558, 0, 0, 0, 0, 0, 558, 0, 558, - 0, 854, 0, 0, 0, 0, 0, 0, 1650, 0, - 0, 0, 558, 871, 0, -2102, 0, 558, 0, 0, - 0, 558, 558, 558, 558, 0, 558, 558, 0, 3092, - 3093, 3094, 3095, 0, 0, 0, 0, 0, 0, 3295, - 0, 0, 1652, 0, 0, 0, 0, 1106, 0, 0, - 0, 0, 0, 0, 0, -2102, 0, 0, 0, 0, - 0, 0, 3397, 0, 0, 0, 1568, 0, 0, 0, - 0, 1566, 0, 0, -46, 0, 0, 0, 0, 0, - 1567, 0, 0, 0, 0, 0, 0, 0, 0, 1777, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 961, 961, 0, 3397, 961, 2, 2869, 3, 4, - 0, 0, 0, 1984, 0, 0, 1121, 1121, 0, 0, - 0, 5, 0, 0, 557, 1949, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 0, 0, 0, -2102, - 0, 0, 0, 0, 0, 0, 1777, 0, 0, 8, - 0, 0, 0, 3397, 0, 0, -2102, 0, 9, 0, - 10, -2102, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, 0, 12, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 558, 13, 0, 1259, 3215, 0, - 961, 1302, 1309, 0, 0, 0, 1618, 0, 0, -2102, - 14, 15, 16, 0, 0, 2211, 0, 0, 0, 808, - 0, 17, 0, 0, 0, 808, 0, 18, 0, 0, - 0, 2496, 0, 0, 0, 19, 2023, 20, 21, 0, - 0, 0, 0, 0, 1618, 0, 0, 0, 0, 0, - 0, 0, 22, 0, 1359, 0, 23, 0, 0, 0, - 0, 0, 0, 71, 1661, 0, 0, 0, 0, 71, - 0, 0, 1383, 0, 0, 0, 0, 0, 1431, 0, - 0, 1433, 24, 0, 1444, 1447, 1452, 1455, 0, 0, - 0, 0, 0, 0, 0, 2913, 0, 0, -1468, 0, - 0, 0, 1639, 0, 0, 1640, 0, 0, 0, 1641, - 1642, 0, 0, 1645, 1646, 1647, 0, 2104, 0, 0, - 0, 0, 0, 0, 25, 0, 0, 1623, 0, 1498, - 1302, 0, 0, 0, 0, 0, 0, 1568, 0, 0, - 1650, 0, 0, 0, 0, 0, 0, 1651, 1950, 1951, - 1952, 1582, 1953, 1954, 1955, 1956, 1957, 1958, 0, 0, - 1639, 0, 0, 1640, 0, 0, -2102, 1641, 1642, 0, - 1598, 1645, 1646, 1647, 1652, 71, 0, 0, 0, 0, - 0, 1608, 1609, 1610, 0, 1615, 1619, 0, 1648, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1650, 26, - 27, 28, 0, 808, 71, 1651, 0, 29, 0, 0, - 30, 3074, 0, 0, 0, 558, 0, 0, 0, 0, - 808, 1682, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1652, 0, 0, 0, 0, 0, 0, 1498, - 1498, 31, 0, 0, 0, 0, 1386, 0, 821, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 1618, - 0, 0, 0, 0, 558, 0, 33, 0, 0, 0, - 2637, 1653, 0, 34, -2102, 1720, 0, 35, 0, 1736, - 1741, 1668, 1669, 1670, 1671, 1672, 1673, 36, 1654, 0, - 1121, 1121, 0, 1655, 0, 0, 0, 0, 0, 37, - 0, 0, 0, 38, 0, 0, 0, 3371, 0, 0, - 0, 1387, 1388, 0, 0, 0, 1656, 1657, 0, 0, - 0, 0, 0, 39, 0, 0, 0, 0, 3395, 1653, - 0, 1658, 0, 0, 0, 0, 40, 0, 0, 41, - 0, 809, 42, 0, 0, 0, 1654, 43, 0, 0, - 1302, 1655, 1389, 1390, 0, 871, 1391, 1392, 0, 1302, - 0, 0, 0, 0, 44, 0, 0, 0, 0, 1659, - 0, 0, 1660, 0, 1656, 1657, 0, 0, 0, 0, - 0, 0, 0, 1302, 0, 0, 1661, 0, 45, 1658, - 0, 0, 0, 3435, 0, 0, 0, 558, 0, 0, - 0, 0, 46, 1639, 0, -46, 1640, 0, 0, 0, - 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, 0, - 0, 0, 0, 3461, 0, 0, 0, 1659, 0, 0, - 1660, 1648, 1393, 1394, 0, 0, 0, 0, 0, 0, - 0, 1650, 0, 0, 1661, 0, 0, 1662, 1651, 0, + 0, 0, 0, 0, 0, 2763, 0, 0, 0, 0, + 0, 0, 0, 856, 856, 856, 0, 0, 0, 0, + 0, 0, 0, 557, 0, 1429, 0, 557, 0, 0, + 0, 0, 0, 557, 0, 1556, 0, 0, 1053, 0, + 0, 1926, 0, 0, 0, 1927, 1928, 1556, 0, 1929, + 1930, 1931, 0, 856, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2830, 2075, 0, 0, + 0, 0, 0, 0, -2081, 0, 0, 1556, 0, 0, + 0, 0, 1651, 0, 1556, 1652, 1653, 1654, 0, 1655, + 1656, 1657, 1658, 1659, 1660, 1606, 1554, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1429, 1429, 2513, 0, + 0, 0, 1555, 0, 0, 2123, 0, 0, 0, 0, + 0, 0, 1556, 0, 0, 0, 1556, 0, 0, 0, + 0, 2562, 1556, 0, 0, 2864, 0, 0, 0, 0, + 0, 2191, 809, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1556, 0, 856, 0, 809, + 0, 557, 0, 0, 0, 557, 557, 0, 0, 557, + 0, 0, 0, 1829, 1765, 1829, 0, 1873, 0, 0, + 0, 0, -2081, 0, 0, 0, 0, 0, 0, 1655, + 1656, 1657, 1658, 1659, 1660, 0, 557, 0, 2944, 1935, + 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, 1943, 1552, + 0, 557, 557, 557, 557, 557, 557, 557, 557, 557, + 557, 0, 0, 0, 2691, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1554, 0, 558, 0, 0, 2707, + 2708, 2710, 0, 0, 2352, 0, 0, 0, 0, 0, + 1555, 856, 1933, 0, 2721, 558, 0, 2724, 0, 0, + 0, 0, 0, 1765, 2733, 558, 0, 558, 0, 0, + 558, 0, 0, 0, 0, 0, 558, 0, 558, 0, + 0, 0, 0, 1873, 0, 0, 0, 0, 0, 0, + 0, 558, 0, 1829, 0, 1554, 558, 0, 0, 0, + 558, 558, 558, 558, 1429, 558, 558, 0, 0, 0, + 557, 1555, 0, 0, 0, 0, 870, 856, 856, 856, + 856, 0, 1934, 0, 0, 0, 0, 0, 0, 1429, + 0, 0, 1429, 0, 0, 0, 557, 960, 0, 0, + 0, 0, 0, 0, 0, 3101, 0, 0, 0, 0, + 0, 0, 2770, 2771, 2772, 0, 0, 0, 11, 1432, + 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, + 0, 1628, 1629, 3108, 0, 2528, 0, 1626, 0, 0, + 1627, 0, 0, 0, 1628, 1629, 14, 15, -2081, -2081, + -2081, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1554, 0, 1637, 0, 3132, 0, 807, 0, 0, -2081, + 0, 0, 1016, 0, 0, 1637, 1555, 1017, 0, 0, + 3144, 0, 1638, 0, 2191, 0, 0, 0, 0, 0, + 2075, 0, 23, 0, 1626, 0, 1639, 1627, 0, 0, + 0, 1628, 1629, 0, 1765, 0, 0, 0, 0, 1639, + 1829, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 558, 0, 0, 960, 557, 1429, 0, 0, 0, 0, + 0, 856, 1637, 1556, 0, 0, 1018, 0, 0, -2081, + 0, 0, 0, 0, 0, 0, 0, 0, 3195, 0, + 0, 0, 0, 0, 2477, 0, 2882, 0, 1606, 2005, + 1554, 2843, 0, 0, 0, 0, 1639, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1555, 0, 0, 1626, + 0, 0, 1627, 0, 0, 0, 1628, 1629, 1630, 1631, + 1632, 1633, 1634, -2081, 1606, 1935, 1936, 1937, 0, 1938, + 1939, 1940, 1941, 1942, 1943, 0, 1640, 1635, 1019, 0, + -2081, 0, 0, 71, 0, -2081, 1196, 1637, 0, 71, + 1432, 0, 0, 1641, 1638, 0, 3212, 0, 1642, 0, + 1829, 3122, 0, 0, 0, 26, 27, 28, 0, 1554, + 558, 0, 0, 2352, 1020, 2886, 0, 0, 0, 1611, + 3025, 1639, 0, -2081, 0, 1555, 0, 0, 0, 0, + 1021, 3244, 0, -2081, 0, 0, 1645, 0, 1429, 0, + 1022, 1556, 0, 0, 0, 0, 0, 0, 0, 0, + -2081, 0, 0, 0, 1053, -2081, 0, 1926, 0, 0, + 0, 1927, 1928, 0, 3261, 1929, 1930, 1931, 0, 0, + 557, 0, 33, 0, 1023, 0, 0, 557, 1648, 0, + 0, 0, 3118, 35, 0, 0, 3065, 3066, 3067, 3068, + 0, 1648, 0, -2081, 0, 1197, 0, 71, 0, 0, + 0, 0, 1556, 0, 0, 37, 558, 0, 0, 38, + 0, 0, 3289, 0, 0, 0, 1554, 0, 1640, 0, + 1024, 0, 0, 0, 0, 0, 71, 1025, 0, 39, + 0, 0, 1555, 3047, 557, 1641, 0, 0, 0, 557, + 1642, 0, 40, 0, 0, 0, 0, 0, 1648, 0, + 1554, 0, 0, 43, 0, 558, 0, 0, 0, 0, + 0, 2613, 0, 1643, 1644, 557, 1555, 0, 0, 1026, + 44, 0, 0, 0, 0, 0, 0, 0, 1645, 0, + -2081, 1606, 0, 0, 0, 0, 557, 557, 1027, 0, + 1115, 1115, 0, 1650, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 856, 0, 1765, 0, 1556, 46, 0, + 557, 0, 0, 0, 0, 0, 1646, 0, 0, 1647, + 1432, 1432, 0, 0, 856, 0, 1432, 3360, 0, 0, + 0, 0, 1554, 1648, 0, 0, 1649, 0, 0, 0, + 3182, 0, 0, 0, 0, 0, 0, 1429, 1555, 0, + -2081, 557, 1009, 0, 1009, 0, 0, 1028, 809, 0, + 0, 1252, 1198, 0, 0, 1294, 1301, 0, 1933, 0, + 0, 0, 870, 0, 0, 1554, 0, 0, 0, 3144, + 0, 0, 0, 0, 0, 0, 856, 558, -2081, 0, + 0, 1555, 0, 0, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 1651, 0, 0, -2081, -2081, -2081, 1556, 1655, 1656, + 1657, 1658, 1659, 1660, 1053, 0, 856, 1926, 1351, 0, + 0, 1927, 1928, 0, 0, 1929, 1930, 1931, 0, 0, + 0, 0, 0, 0, 0, 1650, 1375, 0, 1934, 0, + 0, 0, 1423, 0, 0, 1425, 0, 0, 1436, 1439, + 1444, 1447, 0, 0, 3261, 0, 0, 0, -2081, 0, + 0, 0, 0, 0, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 0, 0, 0, 0, 0, 3360, 0, 1554, 0, + 0, 0, 0, 0, 0, 0, 1556, 0, 1486, 1294, + 0, 0, 0, 0, 1555, 0, 0, 558, 0, 0, + 0, 558, 0, 1765, 0, 0, 0, 2001, 0, 0, + 1570, 0, 0, 0, 0, 960, 960, 0, 3360, 960, + 0, 0, 0, 0, 0, 0, 0, 1969, 0, 1586, + 0, 0, 0, 0, 0, 0, 71, 0, 557, 0, + 1596, 1597, 1598, 1651, 1603, 1607, 1652, 1653, 1654, 0, + 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 0, + 1765, 2167, 0, 1919, 0, 0, 0, 3360, 0, 0, + 0, 0, 0, 0, 0, 0, 1606, 0, 0, 1669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1556, 0, 0, 0, 1486, 1486, 0, + 0, 0, 0, 0, 960, 0, 0, 1432, 0, 0, + 0, 0, 0, 0, 0, 0, 1210, 0, 0, 2191, + 0, 0, 1211, 0, 0, 0, 0, 1556, 1933, 0, + 1223, 0, 0, 1708, 0, 558, 0, 1724, 1729, 558, + 558, 0, 3334, 558, 0, 0, 0, 0, 1115, 1115, + 1224, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, + 1943, 1053, 0, 3358, 1926, 0, 0, 0, 1927, 1928, + 558, 0, 1929, 1930, 1931, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 0, 1225, 0, 1934, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1294, 1556, + 0, 0, 0, 0, 0, 0, 0, 1294, 0, 0, + 0, 0, 0, 0, 71, 3397, 0, 1212, 0, 0, + 0, 0, 0, 0, 0, 1554, 0, 0, 0, 0, + 0, 1294, 0, 0, 0, 3357, 0, 0, 0, 0, + 0, 1555, 1556, 0, 0, 3423, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1931, 0, 0, 0, 0, 1652, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1663, 0, - 0, 0, 0, 0, 0, 0, 1395, 1396, 1397, 1398, - 1399, 1400, 1401, 1402, 0, 558, 1403, 1404, 0, 558, - 0, 0, 0, 0, 0, 2019, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1452, 0, 1452, 1452, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1663, 0, 1121, 1121, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1618, - 2841, 0, 0, 0, 2104, 0, 0, 0, 0, 1121, - 0, 0, 1653, 0, 0, 0, 0, 0, 0, 0, - 1405, 1406, 0, 0, 0, 0, 0, 0, 0, 1654, - 0, 0, 0, 0, 1655, 0, 1664, 0, 0, 1665, - 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, - 0, 0, 0, 0, 0, 0, 0, 1656, 1657, 0, - 0, 1407, 1408, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1658, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2001, 0, 0, 0, 0, 0, + 0, 0, 1226, 0, 0, 0, 0, 0, 71, 0, + 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2477, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1432, 1432, 1432, 1432, 1432, 1432, 0, 1916, 1432, 1432, + 1432, 1432, 1432, 1432, 1432, 1432, 1432, 1432, 0, 0, + 71, 1227, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1228, 0, 0, 1053, 1556, 71, 1926, 0, 0, + 0, 1927, 1928, 1229, 0, 1929, 1930, 1931, 0, 0, + 0, 0, 0, 0, 0, -2081, 0, 0, 0, 0, + 0, 0, 3119, 0, 1213, 0, 0, 0, 0, 0, + 1444, 0, 1444, 1444, 0, 1230, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1115, 1115, 0, 0, 0, + 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, + 1943, 0, 1115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 558, 0, - 0, 0, 558, 558, 1664, 0, 558, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, 0, - 1659, 2068, 0, 1660, 1639, 0, 0, 1640, 0, 2071, - 0, 1641, 1642, 558, 0, 0, 0, 1661, 0, 0, - 1662, 0, 0, 0, 0, 0, 0, 0, 558, 558, - 558, 558, 558, 558, 558, 558, 558, 558, 0, 0, - 0, 0, 1650, 2116, 71, 0, 0, 1409, 1410, -2102, - 2120, 0, 0, 0, 0, 0, 2124, 2125, 2126, 2127, - 2128, 2129, 2130, 2131, 0, 3394, 0, 0, 2140, 2141, - 0, 1411, 1412, 2154, 0, 0, 1652, 2157, 0, 0, - 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 0, - 0, 2174, 0, 0, 0, 0, 0, 0, 1121, 1639, - 1302, 0, 1640, 0, 0, 0, 1641, 1642, 1643, 1644, - 1645, 1646, 1647, 0, 0, 0, 0, 0, 2200, 1663, - 0, 71, 0, 71, 0, 2019, 0, 1648, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1650, 0, 0, - 0, 2870, 0, 0, 1651, 0, 0, 0, 0, 0, - 0, 2496, 1609, 1610, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, - 0, 1652, 0, -2102, 1639, 0, 0, 1640, 0, 71, - 0, 1641, 1642, 2104, 0, 1645, 1646, 1647, 0, 0, - -2102, 2104, 0, 0, 0, -2102, 0, 0, 0, 0, - 0, 0, 1648, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1650, 0, 0, 0, 0, 0, 0, 1651, - 0, 0, 0, 0, 0, 0, 808, 1664, 0, 0, - 1665, 1666, 1667, -2102, 1668, 1669, 1670, 1671, 1672, 1673, - 0, 0, 0, 2326, 0, 0, 1652, 0, 2532, 0, - 1302, 0, 0, 2337, 2338, 0, 0, 0, 0, 1638, - 0, 0, 0, 0, 1639, 0, 0, 1640, 1653, 0, - 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, - 0, 0, 0, 0, 558, 1654, 0, 0, 1661, 0, - 1655, 0, 1648, 0, 1302, 0, 1649, 0, 0, 0, - 0, 0, 1650, 0, 0, 71, 0, 0, 0, 1651, - 0, 0, 0, 1656, 1657, 0, 0, 0, 0, 1359, - 2404, 0, 0, 0, 0, 0, 0, 0, 1658, 0, - 0, 71, 0, 0, 0, 0, 1652, 0, 0, 0, - 0, 0, 0, 1653, 0, 0, 0, 0, 2430, 2431, - 0, 2432, 1441, 0, 0, 0, 0, 0, 0, 0, - 1654, 0, 0, 0, 0, 1655, 1659, 0, 0, 1660, + 0, 0, 0, 1231, 0, 1934, 0, 1215, 0, 1232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2458, 2459, 0, 1661, 2200, 0, 1662, 0, 1656, 1657, - -2102, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2484, 0, 0, 0, 0, - 0, 0, 2490, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1653, 0, 0, 0, 0, 0, 0, - 1498, 1659, 1302, 0, 1660, 0, 0, 0, 0, 0, - 1654, 0, 0, 0, 0, 1655, 0, 0, 1661, 0, - 3303, 0, 0, 0, 0, 0, 0, 2496, 0, 0, - 0, 0, 0, 0, 0, 0, 1676, 0, 1656, 1657, - 2525, 0, 0, 0, 0, 1663, 0, 0, 0, 0, - 0, 0, 0, 1658, 0, 0, 0, 0, -2102, 0, - 0, 0, 0, 0, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 0, 0, 0, 0, 0, 0, 2542, 0, 0, - 0, 2548, 0, 0, 0, 1676, 2556, 2557, 0, 0, - 558, 1659, 0, 0, 1660, 558, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1661, 0, - 0, 1662, 0, 0, 0, 0, 0, 0, 0, 1441, - 1663, 558, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2578, 0, 0, 2581, 0, 2583, 0, - 0, 0, 0, 558, 558, 0, 0, 0, 0, 0, - 0, 0, 0, 1664, 2587, 0, 1665, 1666, 1667, 0, - 1668, 1669, 1670, 1671, 1672, 1673, 0, 558, 0, 0, - 0, 0, 0, 1934, 1676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1720, 0, 1639, 0, 0, 1640, - 0, 0, 0, 1641, 1642, 0, 0, 0, 558, 0, - 1663, 1741, 2172, 0, 0, 0, 2104, 1676, 0, 0, - 0, 0, 0, 0, 1676, 0, 0, 0, 1664, 0, - 1121, 1665, 1666, 1667, 1650, 1668, 1669, 1670, 1671, 1672, - 1673, -2102, 0, 2643, 0, 1639, 0, 0, 1640, 0, - 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1652, 0, - 0, 0, 0, 1648, 1676, 0, 0, 2846, 0, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, - 1651, 0, 0, 0, 0, 0, 0, 0, 1676, 0, - 1610, 0, 0, 0, 0, 0, 0, 0, 0, 1302, - 0, 0, 0, 0, 0, 0, 0, 1652, 1664, 0, - 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 0, 0, 3155, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1676, 0, 1676, 0, - 1441, 1441, 0, 1959, 0, 0, 1441, 0, 0, 1676, - 0, 0, 1676, 0, 0, -2102, 0, 1676, 2753, 0, - 1676, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, -2102, 0, 0, 0, 0, -2102, 0, 0, - 0, 0, 0, 0, 1639, 0, 0, 1640, 0, 558, - 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, - 0, 0, 0, 1676, 1653, 0, 0, 0, 0, 0, - 0, 0, 1648, 0, 0, -2102, 0, 0, 0, 0, - 0, 1654, 1650, 0, 0, 0, 1655, 0, 0, 1651, + 0, 0, 0, 0, 1233, 0, 0, 0, 0, 1234, + 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1235, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, + 1432, 1432, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1626, 0, 2050, 1627, 0, 0, 0, 1628, + 1629, 0, 2053, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1656, - 1657, 0, 0, 0, 0, 0, 1652, 0, 0, 0, - 0, 0, 0, 0, 1658, 0, 0, 0, 0, 0, - 1661, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1676, 0, 0, - 0, 2831, 0, 0, 0, 0, 0, 2833, 2071, 0, - 0, 0, 1659, 1676, 0, 1660, 0, 0, 0, 0, - 0, 0, 2842, 1676, 1676, 1676, 0, 0, 0, 1661, - 1676, 0, 1662, 0, 1676, 0, 0, 0, 2855, 0, - 0, 2858, 0, 2860, 0, 0, 0, 0, 0, 0, - 0, 2864, 0, 0, 0, 0, 0, 0, 0, 2871, - 2872, 0, 0, 1653, 0, 0, 2879, 0, 0, 0, + 1217, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1637, 0, 0, 0, 0, 0, 0, 1638, 1933, 0, + 0, 0, 2100, 0, 0, 0, 0, 0, 2104, 2105, + 2106, 2107, 2108, 2109, 2110, 2111, 0, 0, 0, 0, + 2120, 2121, 0, 0, 1639, 2134, -46, 0, 0, 2137, + 0, 0, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, + 2153, 0, 1556, 2154, 3269, 0, 0, 0, 1, 0, + 1115, 2477, 1294, 0, 0, 0, 1432, 0, 2, 0, + 3, 4, 0, 0, 0, 0, 0, 0, 1934, 0, + 0, 2180, 0, 5, 0, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 1935, 1936, + 1937, 0, 1938, 1939, 1940, 1941, 1942, 1943, 0, 0, + 0, 8, 0, 0, 0, 1597, 1598, 0, 558, 0, + 9, 0, 10, 558, 0, 0, 0, 0, 0, 0, + 0, 1640, 0, 0, 11, 0, 12, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, 1641, 558, + 0, 0, 0, 1642, 0, 0, 0, 0, 0, 0, + 0, 0, 14, 15, 16, 0, 0, 0, 0, 0, + 558, 558, 0, 17, 0, 0, -2081, -2081, 0, 18, + 0, 0, 0, 0, 0, 0, 0, 19, 0, 20, + 21, 1645, 0, 0, 558, 0, 0, 1433, 0, 0, + 0, 0, 0, 0, 22, 0, 2306, 0, 23, 0, + 1294, 0, 1625, 2316, 2317, 0, 0, 1626, 0, 0, + 1627, 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, + 1634, 0, -2081, 0, 24, 558, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1635, 1648, 0, 0, 1636, + -1445, 0, 0, 0, 1294, 1637, 0, 0, 0, 0, + 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 25, 0, 0, 1351, + 2383, 0, 0, 0, 0, 0, 0, 0, 0, 1639, + 0, 1935, 1936, 1937, 0, 1938, 1939, 1940, 1941, 1942, + 1943, 0, 0, 0, 0, 0, 0, 0, 2409, 2410, + 0, 2411, 0, 0, 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1654, 2888, -2102, 0, 0, 1655, 0, 0, 0, 0, - 0, 2903, 0, 0, 0, 0, 0, 1676, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1656, 1657, - 0, 1121, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1658, 0, 0, 0, 0, 0, 0, - 0, 1663, 0, 0, 0, 1676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1676, 0, 0, 0, 0, 1676, 0, 0, 0, - 0, 1659, 0, 0, 1660, 0, 0, 0, 0, 0, - 2326, 0, 2326, 1959, 0, 0, 0, 0, 1661, 0, - 0, 1662, 0, 0, 0, 0, 0, 0, 0, 0, - -2102, 0, 0, 0, 0, 0, 0, 1668, 1669, 1670, - 1671, 1672, 1673, 0, 0, 0, 0, 0, 0, 0, + 2437, 2438, 0, 0, 2180, 0, 0, 0, 1650, 0, + 0, 26, 27, 28, 0, 0, 0, 0, 0, 29, + 0, 0, 30, 0, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 2465, 0, 0, 0, 0, 0, 2471, + 0, 0, 0, 0, 0, 0, 1640, 0, 1432, 1432, + 1016, 0, 0, 31, 0, 1017, 0, 1486, 1433, 1294, + 0, 0, 32, 1641, 0, 0, 0, 0, 1642, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 558, 0, 0, 34, 0, 0, 0, 35, + 0, 1643, 1644, 0, 0, 0, 0, 2506, 0, 36, + 0, 0, 0, 0, 0, 0, 1645, 0, 0, 0, + 0, 37, 0, 1663, 1018, 38, 1651, 0, 0, 1652, + 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, + 0, 0, 0, 0, 2523, 39, 0, 2526, 0, 0, + 0, 0, 2532, 2533, 1646, 0, 0, 1647, 40, 0, + 0, 41, 0, 0, 42, 1663, 0, 0, 0, 43, + 0, 1648, 1663, 0, 1649, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, + 0, 1210, 0, 0, 0, 0, 1019, 1211, 2554, 0, + 0, 2557, 0, 2559, 0, 1223, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 2563, + 0, 0, 1663, 0, 46, 1224, 0, -46, 0, 0, + 0, 0, 1020, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1663, 0, 1021, 0, + 0, 0, 0, 0, 0, 0, 1432, 0, 1022, 1708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1225, 0, 1650, 0, 0, 1729, 2152, 0, 0, + 0, 1432, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1023, 0, 1663, 1115, 1663, 0, 1433, 1433, + 0, 1944, 1212, 0, 1433, 0, 0, 1663, 2619, 0, + 1663, 0, 0, 1989, 0, 1663, 0, 0, 1663, 0, + 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, + 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1024, 0, + 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, + 0, 0, 1635, 0, 0, 0, 2822, 1663, 0, 0, + 0, 0, 1637, 0, 0, 1598, 0, 1226, 0, 1638, + 0, 1294, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1651, 0, 0, 1652, 1653, 1654, 1026, 1655, 1656, + 1657, 1658, 1659, 1660, 0, 0, 1639, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1027, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1227, 1432, 0, 0, + 0, 0, 0, 0, 0, 0, 1228, 0, 0, 0, + 0, 0, 2731, 0, 0, 0, 0, 0, 1229, 0, + 0, 1663, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1626, 0, 0, 1627, 1663, 0, 1213, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1663, 1663, 1663, + 1230, 0, 0, 0, 1663, 1028, 0, 0, 1663, 0, + 1990, 1635, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1637, 0, 1640, 0, 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1664, - 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, - 1672, 1673, 0, 0, 0, 0, 2110, 0, 0, 0, + 1641, 0, 0, 0, 0, 1642, 0, 0, 2281, 0, + 0, 0, 1215, 0, 1232, 1639, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, + 1663, 0, 0, 0, 0, 0, 0, 0, 0, 1233, + 0, 0, 0, 1645, 2282, 0, 0, 0, 0, 0, + 1432, 0, 0, 0, 0, 0, 0, 2809, 1235, 0, + 0, 0, 0, 2811, 2053, 0, 0, 0, 0, 1663, + 0, 0, 0, 0, 0, 2818, 0, 0, 0, 0, + 0, 1646, 0, 0, 1647, 1663, 0, 0, 0, 2828, + 1663, 0, 2831, 0, 2833, 0, 0, 0, 1648, 0, + 0, 1649, 2837, 0, 0, 0, 0, 1944, 0, 0, + 2844, 2845, 1640, 0, 0, 1217, 0, 2852, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, + 0, 0, 2861, 0, 1642, 0, 0, 0, 0, 0, + 1626, 0, 2876, 1627, 0, 0, 0, 1628, 1629, 1630, + 1631, 1632, 1633, 1634, 0, 0, 0, 1643, 1644, 0, + 0, 0, 1115, 0, 0, 0, 0, 0, 1635, 0, + 0, 0, 1645, 0, 0, 0, 0, 0, 1637, 0, + 0, 0, 0, 0, 0, 1638, 0, 0, 0, 0, + 1626, 0, 0, 1627, 0, 0, 0, 1628, 1629, 0, + 1650, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, + 1646, 0, 1639, 1647, 0, 0, 0, 0, 1635, 0, + 0, 2306, 0, 2306, 0, 0, 0, 1648, 1637, 0, + 1649, 0, 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3108, 3109, 0, 0, 0, 0, 0, 0, 0, 0, - 1663, 0, 0, 0, 1639, 0, 0, 1640, 0, 0, - 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, - 0, 0, 0, 0, 0, 3132, 0, 0, 0, 0, - 0, 0, 1648, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1650, 0, 0, 3141, 0, 0, 0, 1651, - 0, 3145, 3146, 0, 0, 0, 3147, 0, 0, 0, - 0, 3150, 0, 0, 3153, 3154, 1676, 0, 0, 2326, - 1302, 0, 0, 3162, 1959, 1959, 1652, 1441, 1441, 1441, - 1441, 1441, 1441, 0, 1121, 1441, 1441, 1441, 1441, 1441, - 1441, 1441, 1441, 1441, 1441, 1959, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1664, 0, - 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 0, 0, 0, 0, 2110, 1387, 1388, 3203, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1432, + 0, 0, 1639, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1663, 0, 0, + 0, 0, 0, 0, 0, 1944, 1944, 0, 1433, 1433, + 1433, 1433, 1433, 1433, 0, 0, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1433, 1944, 0, 1651, 1640, + 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 0, 0, 3081, 3082, 2091, 1641, 0, 0, 1650, + 0, 1642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1643, 1644, 0, 0, 3105, 1640, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1645, + 0, 0, 0, 3109, 0, 0, 1641, 0, 0, 3112, + 3113, 1642, 0, 0, 3114, 0, 0, 0, 0, 3117, + 0, 0, 3120, 3121, 0, 0, 0, 2306, 1294, 0, + 0, 3129, 0, 0, 1643, 1644, 0, 1646, 0, 0, + 1647, 1663, 1115, 0, 1663, 0, 0, 0, 0, 1645, + 0, 0, 0, 0, 1648, 0, 0, 1649, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1651, 0, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, + 0, 0, 0, 0, 2091, 0, 3170, 1646, 0, 0, + 1647, 1663, 0, 0, 0, 1663, 1663, 1663, 1663, 1663, + 1663, 1663, 1663, 0, 1648, 0, 0, 1649, 1433, 1433, + 0, 1663, 1663, 3189, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1663, 0, 0, 1663, 0, + 0, 0, 0, 0, 0, 0, 1663, 1663, 1663, 1663, + 1663, 1663, 1663, 1663, 1663, 1663, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1650, 0, 0, 0, + 0, 0, 0, 0, 0, 1626, 0, 0, 1627, 0, + 0, 1663, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1639, 0, 0, 1640, 3222, 0, 0, 1641, 1642, - 1643, 1644, 1645, 1646, 1647, 0, 0, 1389, 1390, 0, - 0, 1391, 1392, 1653, 0, 0, 0, 0, 0, 1648, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1650, - 1654, 0, 0, 0, 0, 1655, 1651, 0, 0, 0, - 0, 0, 0, 1676, 0, 0, 1676, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1656, 1657, - 0, 0, 0, 1652, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1393, 1394, 0, - 0, 1676, 0, 0, 0, 1676, 0, 0, 0, 1676, - 1676, 1676, 1676, 1676, 1676, 1676, 1676, 0, 2753, 0, - 0, 1659, 1441, 1441, 1660, 1676, 1676, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1661, 1676, - 0, 1662, 1676, 0, 0, 1619, 0, 0, 0, 0, - 1676, 1676, 1676, 1676, 1676, 1676, 1676, 1676, 1676, 1676, - 0, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 0, - 1653, 1403, 1404, 0, 0, 0, 0, 0, 0, 2548, - 0, 0, 0, 0, 0, 1676, 0, 1654, 0, 0, - 0, 0, 1655, 0, 0, 0, 3318, 3319, 0, 0, - 3320, 0, 1610, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1656, 1657, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3338, 0, 0, - 1658, 0, 0, 0, 0, 0, 0, 0, 1441, 0, - 1663, 0, 0, 0, 0, 1405, 1406, 0, 0, 0, - 0, 3350, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1659, 0, - 0, 1660, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1661, 1407, 1408, 1662, 0, + 0, 0, 0, 1635, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1637, 0, 0, 1650, 0, 0, 0, + 1638, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1433, 0, 2731, 0, 0, 0, + 0, 0, 722, 0, 0, 0, 0, 1639, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1607, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, + 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, + 0, 2408, 0, 0, 0, 0, 2526, 0, 0, 723, + 0, 0, 0, 0, 0, 0, 0, 1663, 3281, 3282, + 0, 0, 3283, 0, 1598, 724, 0, 1663, 1663, 0, + 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, + 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 3301, + 0, 0, 0, 0, 1640, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1641, 0, 3313, 725, 0, 1642, 0, 0, 0, + 0, 0, 0, 0, 726, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1663, 0, 0, 727, 0, 1643, + 1644, 0, 728, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1645, 0, 0, 0, 0, 0, + 1663, 1663, 1663, 0, 0, 1944, 1944, 1944, 1944, 1944, + 1944, 729, 0, 0, 1944, 1944, 1944, 1944, 1944, 1944, + 1944, 1944, 1944, 1944, 0, 0, 0, 0, 1663, 1663, + 0, 0, 1646, 0, 0, 1647, 0, 0, 0, 0, + 3081, 0, 0, 0, 3374, 0, 0, 0, 1115, 1648, + 0, 0, 1649, 0, 730, 0, 1663, 0, 731, 3383, + 0, 0, 1663, 0, 2306, 0, 2306, 0, 0, 0, + 1626, 0, 0, 1627, 1115, 0, 0, 1628, 1629, 1630, + 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, + 0, 0, 3408, 0, 0, 0, 0, 1663, 1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1637, 0, + 0, 0, 0, 0, 1663, 1638, 0, 1663, 0, 0, + 0, 0, 0, 1663, 1663, 0, 0, 0, 732, 0, + 0, 1944, 1944, 0, 0, 0, 0, 0, 0, 3433, + 0, 0, 1639, 733, 0, 1663, 1433, 1433, 1663, 3081, + 1663, 1650, 0, 0, 1663, 0, 0, 0, 0, 0, + 1626, 1115, 0, 1627, 0, 0, 0, 1628, 1629, 1630, + 1631, 1632, 1633, 1634, 0, 0, 0, 0, 734, 0, + 0, 735, 0, 0, 0, 0, 0, 0, 1635, 0, + 0, 0, 736, 3476, 0, 737, 0, 0, 1637, 0, + 0, 0, 0, 0, 0, 1638, 0, 0, 0, 0, + 1663, 0, 0, 738, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 739, 0, 0, + 0, 0, 1639, 0, 741, 0, 0, 0, 0, 1640, + 0, 0, 0, 0, 742, 0, 0, 0, 0, 0, + 743, 0, 0, 0, 0, 0, 1641, 0, 0, 1651, + 0, 1642, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, + 1659, 1660, 0, 0, 0, 0, 2510, 0, 744, 0, + 3530, 3530, 3530, 0, 1643, 1644, 0, 0, 0, 0, + 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 1645, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 3530, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1635, 1663, 0, 0, 0, 0, 0, 0, 1640, + 0, 1637, 0, 0, 0, 0, 0, 1646, 1638, 0, + 1647, 0, 0, 0, 1433, 0, 1641, 1378, 3530, 820, + 0, 1642, 0, 0, 1648, 0, 0, 1649, 0, 0, + 0, 0, 0, 0, 0, 1639, 0, 0, 0, 0, + 0, 0, 0, 0, 1643, 1644, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1645, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1663, 0, 1663, 0, 0, 0, 0, 0, 0, 1663, + 0, 0, 1379, 1380, 0, 0, 0, 0, 0, 1663, + 0, 0, 1663, 0, 1663, 0, 0, 1646, 1663, 0, + 1647, 1944, 1944, 0, 0, 1663, 1663, 0, 0, 0, + 0, 0, 0, 1663, 1648, 0, 0, 1649, 0, 0, + 0, 0, 1663, 1381, 1382, 0, 1650, 1383, 1384, 0, + 0, 0, 1640, 0, 0, 0, 0, 1663, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, + 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1433, 0, 1643, 1644, 0, + 0, 0, 0, 0, 0, 0, 1626, 0, 0, 1627, + 0, 0, 1645, 1628, 1629, 1630, 1631, 1632, 1633, 1634, + 0, 0, 0, 1385, 1386, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1635, 0, 1650, 0, 0, 0, + 0, 0, 0, 0, 1637, 0, 0, 0, 0, 0, + 1646, 1638, 0, 1647, 1651, 0, 0, 1652, 1653, 1654, + 0, 1655, 1656, 1657, 1658, 1659, 1660, 1648, 0, 0, + 1649, 2538, 0, 0, 0, 0, 0, 0, 1639, 0, + 0, 0, 0, 0, 0, 0, 0, 1387, 1388, 1389, + 1390, 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1676, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1676, 1676, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3108, - 0, 0, 0, 3411, 0, 0, 0, 1121, 1664, 0, - 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 3421, 0, 0, 0, 2429, 2326, 0, 2326, 0, - 0, 0, 0, 0, 0, 0, 1121, 0, 0, 0, - 0, 0, 1409, 1410, 0, 0, 0, 1663, 0, 1676, - 0, 0, 0, 0, 3446, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1411, 1412, 0, 0, - 0, 0, 0, 0, 0, 1676, 1676, 1676, 0, 0, - 1959, 1959, 1959, 1959, 1959, 1959, 2036, 0, 0, 1959, - 1959, 1959, 1959, 1959, 1959, 1959, 1959, 1959, 1959, 0, - 0, 3471, 0, 1676, 1676, 1639, 0, 0, 1640, 0, - 0, 3108, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, - 0, 0, 0, 1121, 0, 0, 0, 0, 0, 1676, - 0, 0, 0, 1648, 0, 1676, 0, 0, 0, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, - 1651, 0, 0, 0, 0, 1664, 3514, 0, 1665, 1666, - 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, - 1676, 0, 2529, 0, 0, 0, 0, 1652, 0, 0, - 0, 0, 0, 722, 0, 0, 0, 1676, 0, 0, - 0, 0, 0, 1676, 0, 0, 0, 0, 0, 0, - 0, 1676, 1676, 0, 0, 0, 0, 0, 0, 1959, - 1959, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1676, 1441, 1441, 1676, 0, 1676, 0, - 0, 0, 1676, 0, 0, 0, 0, 0, 0, 0, - 723, 0, 0, 3568, 3568, 3568, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 724, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1639, - 3568, 0, 1640, 0, 1653, 0, 1641, 1642, 1643, 1644, - 1645, 1646, 1647, 0, 0, 0, 0, 0, 1676, 0, - 0, 1654, 0, 0, 0, 0, 1655, 1648, 0, 0, - 0, 0, 0, 0, 0, 725, 0, 1650, 0, 0, - 0, 3568, 0, 0, 1651, 726, 0, 0, 0, 1656, - 1657, 0, 0, 0, 0, 0, 0, 0, 727, 0, - 0, 0, 0, 728, 1658, 0, 0, 0, 0, 0, - 0, 1652, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1639, 0, - 0, 1640, 729, 0, 0, 1641, 1642, 1643, 1644, 1645, - 1646, 1647, 1659, 0, 0, 1660, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1648, 0, 0, 1661, - 0, 0, 1662, 0, 0, 0, 1650, 0, 1676, 0, - 0, 0, 0, 1651, 0, 730, 0, 0, 0, 731, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1441, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1652, 0, 0, 0, 0, 0, 1639, 0, 1653, 1640, - 0, 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, - 0, 0, 0, 0, 0, 1654, 0, 0, 0, 0, - 1655, 0, 0, 0, 1648, 0, 0, 0, 0, 0, - 0, 0, 0, 544, 1650, 0, 1676, 0, 1676, 732, - 0, 1651, 0, 1656, 1657, 0, 0, 1676, 0, 0, - 0, 1663, 0, 0, 733, 0, 0, 0, 1658, 0, - 1676, 0, 0, 1676, 0, 1676, 0, 0, 1652, 1676, - 0, 0, 1959, 1959, 0, 0, 1676, 1676, 0, 0, - 0, 0, 0, 0, 1676, 0, 0, 1653, 0, 734, - 0, 0, 735, 1676, 0, 0, 1659, 0, 0, 1660, - 0, 0, 0, 736, 1654, 0, 737, 0, 1676, 1655, - 0, 0, 0, 1661, 0, 0, 1662, 0, 0, 0, - 0, 0, 0, 0, 738, 0, 0, 0, 0, 0, - 0, 0, 1656, 1657, 0, 0, 0, 0, 739, 0, - 0, 0, 0, 0, 740, 741, 1441, 1658, 0, 0, - 0, 0, 0, 0, 0, 742, 0, 0, 0, 1664, - 0, 743, 1665, 1666, 1667, 1653, 1668, 1669, 1670, 1671, - 1672, 1673, 0, 0, 0, 0, 2562, 0, 0, 0, - 0, 0, 1654, 0, 0, 1659, 0, 1655, 1660, 744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1387, 1388, 1661, 0, 0, 1662, 0, 0, 0, 0, - 1656, 1657, 0, 0, 0, 1663, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1658, 0, 0, 0, 0, - 0, 0, 0, 0, 722, 0, 0, 0, 0, 0, - 0, 1389, 1390, 0, 0, 1391, 1392, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1944, 1433, 0, + 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, + 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, + 0, 2751, 1663, 1663, 0, 0, 0, 0, 0, 1650, + 0, 1397, 1398, 0, 0, 1640, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1663, 0, 0, 0, + 1663, 0, 1641, 1663, 1663, 1663, 0, 1642, 1663, 0, + 0, 1663, 1663, 0, 0, 0, 0, 0, 0, 0, + 1663, 0, 1399, 1400, 0, 0, 0, 0, 0, 0, + 1643, 1644, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1645, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1663, 0, 0, 0, 0, 0, 1944, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1663, 0, 0, 1646, 0, 0, 1647, 1651, 0, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, + 1648, 0, 0, 1649, 2816, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1401, 1402, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1944, + 0, 0, 1403, 1404, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1663, 1663, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1650, 0, 1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1659, 0, 0, 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1661, 0, 0, 1662, 0, 0, 0, 0, 1959, 1441, - 0, 723, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1663, 0, 0, 724, 0, 0, - 0, 0, 0, 1676, 1676, 0, 0, 0, 0, 0, - 0, 1393, 1394, 1664, 0, 0, 1665, 1666, 1667, 0, - 1668, 1669, 1670, 1671, 1672, 1673, 0, 1676, 0, 0, - 2773, 0, 0, 0, 0, 0, 1676, 0, 0, 0, - 1676, 1676, 1676, 0, 0, 1676, 725, 0, 1676, 1676, - 0, 0, 0, 0, 0, 0, 726, 1676, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 727, - 0, 0, 1663, 0, 728, 1395, 1396, 1397, 1398, 1399, - 1400, 1401, 1402, 0, 0, 1403, 1404, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1676, 0, - 0, 0, 1664, 729, 1959, 1665, 1666, 1667, 0, 1668, - 1669, 1670, 1671, 1672, 1673, 0, 0, 1676, 0, 2838, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 730, 0, 0, 0, - 731, 0, 0, 0, 0, 0, 0, 0, 0, 1405, - 1406, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1959, 0, 0, - 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, - 1671, 1672, 1673, 0, 0, 0, 0, 2852, 0, 0, - 1407, 1408, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1676, 1676, 1676, 0, 0, 0, 0, - 732, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1676, 0, 733, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1676, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1663, 0, 0, 0, 0, + 0, 0, 0, 0, 1663, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1663, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, + 1658, 1659, 1660, 0, 1663, 0, 0, 2825, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 734, 0, 0, 735, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 736, 0, 0, 737, 0, 0, - 0, 0, 0, 0, 0, 0, 1409, 1410, 0, 0, - 0, 0, 0, 0, 0, 738, 1676, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1676, 0, 0, 739, - 1411, 1412, 0, 0, 0, 0, 741, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 742, 0, 0, 0, - 0, 1676, 743, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1676, 0, 0, 0, - 744, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1663, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, + 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, + 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, + 148, 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, + 156, 1663, 157, 158, 159, 160, 791, 0, 792, 0, + 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 1064, + 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 1068, + 222, 223, 224, 225, 226, 227, 793, 1069, 229, 0, + 230, 231, 1070, 233, 0, 234, 0, 235, 236, 0, + 237, 238, 239, 240, 241, 242, 0, 243, 0, 1071, + 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, + 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 1077, 323, 1078, 325, 326, + 327, 328, 1079, 329, 330, 331, 332, 1080, 795, 334, + 1081, 336, 337, 338, 0, 339, 340, 0, 0, 1082, + 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, + 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 1083, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 430, 431, 432, 1085, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, + 455, 456, 457, 458, 0, 459, 1086, 1087, 0, 0, + 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 1090, + 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, + 0, 0, 0, 1094, 0, 1095, 0, 0, 0, 0, + 1096, 1097, 1098, 1099, 0, 2671, 117, 1050, 820, 1051, + 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, + 133, 134, 135, 136, 137, 138, 139, 1057, 141, 1058, + 1059, 0, 144, 145, 146, 147, 148, 149, 1060, 790, + 150, 151, 152, 153, 1061, 1062, 156, 0, 157, 158, + 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 1064, 191, 192, 1065, 194, + 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 1067, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 1068, 222, 223, 224, 225, + 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, + 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, + 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 268, 269, 270, 271, 272, 273, 274, 1073, + 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, + 292, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, + 330, 331, 332, 1080, 795, 334, 1081, 336, 337, 338, + 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, + 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, + 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 0, 430, 431, 432, + 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, + 450, 451, 0, 452, 453, 454, 455, 456, 457, 458, + 0, 459, 1086, 1087, 0, 0, 462, 463, 801, 465, + 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 1090, 0, 0, 0, 0, + 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, + 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, + 0, 3284, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1676, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 1676, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, + 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, + 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, + 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, 14, 15, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, + 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, + 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, 23, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, + 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, + 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, + 315, 316, 317, 318, 319, 320, 321, 1077, 323, 1078, + 325, 326, 327, 328, 1079, 329, 330, 331, 332, 1080, + 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, + 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 26, 27, 28, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 35, 430, 431, 432, 1091, 434, 0, 435, + 428, 429, 35, 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 37, 0, 450, 451, 38, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, + 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, + 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 804, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 804, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 45, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 3293, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, + 520, 1090, 0, 45, 0, 0, 0, 0, 1091, 1092, + 1093, 0, 0, 0, 0, 1094, 0, 1095, 3259, 0, + 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, + 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, + 133, 134, 135, 136, 137, 138, 139, 1057, 141, 1058, + 1059, 0, 144, 145, 146, 147, 148, 149, 1060, 790, + 150, 151, 152, 153, 1061, 1062, 156, 0, 157, 158, + 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 1064, 191, 192, 1065, 194, + 1066, 195, 0, 196, 197, 198, 199, 200, 201, 14, + 15, 202, 203, 204, 205, 0, 0, 206, 207, 1067, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 1068, 222, 223, 224, 225, + 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, + 0, 234, 0, 235, 236, 23, 237, 238, 239, 240, + 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 268, 269, 270, 271, 272, 273, 274, 1073, + 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, + 292, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, + 330, 331, 332, 1080, 795, 334, 1081, 336, 337, 338, + 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, + 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 26, 27, + 28, 0, 362, 363, 798, 365, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, + 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 33, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 35, 430, 431, 432, + 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 447, 448, 800, 37, 0, + 450, 451, 38, 452, 453, 454, 455, 456, 457, 458, + 0, 459, 1086, 1087, 0, 0, 462, 463, 801, 465, + 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 40, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 804, 1089, 489, 0, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 1090, 0, 45, 0, 0, + 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, + 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, + 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, + 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, + 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, + 148, 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, + 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, + 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 1064, + 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 1068, + 222, 223, 224, 225, 226, 227, 793, 1069, 229, 0, + 230, 231, 1070, 233, 0, 234, 0, 235, 236, 23, + 237, 238, 239, 240, 241, 242, 0, 243, 0, 1071, + 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, + 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 1077, 323, 1078, 325, 326, + 327, 328, 1079, 329, 330, 331, 332, 1080, 795, 334, + 1081, 336, 337, 338, 0, 339, 340, 0, 0, 1082, + 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, + 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 26, 27, 28, 0, 362, 363, 798, 365, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 1083, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 430, 431, 432, 1085, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 800, 0, 0, 450, 451, 38, 452, 453, 454, + 455, 456, 457, 458, 0, 459, 1086, 1087, 0, 0, + 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 804, 1089, 489, 0, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 1090, + 0, 45, 0, 0, 0, 0, 1091, 1092, 1093, 0, + 0, 0, 0, 1094, 0, 1095, 0, 0, 0, 0, + 1096, 1097, 1098, 1099, 1257, 1050, 820, 1051, 1052, 1053, + 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 1258, 126, 127, 128, 0, 0, 0, 1259, 0, + 1056, 0, 0, 1260, 130, 131, 0, 132, 133, 134, + 1261, 136, 137, 138, 139, 1057, 1262, 1058, 1059, 0, + 144, 145, 146, 147, 148, 149, 1060, 790, 150, 151, + 152, 153, 1061, 1062, 156, 0, 157, 158, 159, 160, + 791, 0, 1263, 0, 1264, 164, 165, 166, 167, 168, + 1265, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 1266, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 1267, 0, 206, 207, 1067, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 1068, 222, 223, 224, 225, 226, 227, + 793, 1069, 229, 0, 230, 231, 1070, 233, 0, 234, + 0, 235, 1268, 0, 1269, 238, 239, 1270, 1271, 242, + 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 1272, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 1273, 269, 270, 271, 272, 273, 274, 1073, 1074, 0, + 1075, 0, 278, 1274, 1275, 281, 1276, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 1277, 291, 1278, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1279, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1077, + 1280, 1078, 325, 326, 327, 328, 1079, 329, 330, 1281, + 332, 1080, 795, 334, 1081, 336, 337, 338, 0, 339, + 340, 0, 0, 1082, 342, 343, 0, 0, 344, 345, + 346, 1282, 348, 1283, 797, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 798, 1284, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 1285, 404, 405, 406, 1084, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 1286, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 1287, 431, 432, 1085, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 1288, 448, 800, 0, 0, 450, 451, + 0, 452, 1289, 454, 455, 456, 457, 458, 0, 459, + 1086, 1087, 0, 0, 462, 463, 801, 465, 802, 1088, + 467, 468, 1290, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 1089, 489, 1291, 490, 1292, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 1090, 0, 0, 0, 0, 0, 0, + 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, + 1293, 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, + 820, 1051, 1052, 0, 1054, 1055, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 1056, 0, 0, 129, 130, 131, + 0, 132, 133, 134, 135, 136, 137, 138, 139, 1057, + 141, 1058, 1059, 0, 144, 145, 146, 147, 148, 149, + 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, 0, + 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 1064, 191, 192, + 1065, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 14, 15, 202, 203, 204, 205, 0, 0, 206, + 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 1068, 222, 223, + 224, 225, 226, 227, 793, 1069, 229, 0, 230, 231, + 1070, 233, 0, 234, 0, 235, 236, 23, 237, 238, + 239, 240, 241, 242, 0, 243, 0, 1071, 1072, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, + 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 1076, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 1077, 323, 1078, 325, 326, 327, 328, + 0, 329, 330, 331, 332, 1080, 795, 334, 1081, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 26, 27, 28, 0, 362, 363, 798, 365, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 1083, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, + 404, 405, 406, 1084, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 33, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 35, 430, + 431, 432, 1085, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, + 37, 0, 450, 451, 38, 452, 453, 454, 455, 456, + 457, 458, 0, 459, 1086, 1087, 0, 0, 462, 463, + 801, 465, 802, 1088, 467, 468, 803, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 40, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 804, 1089, + 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 44, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 0, 0, 45, + 0, 0, 0, 117, 1050, 820, 1051, 1052, 1053, 1054, + 1055, 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, + 1098, 1099, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 1057, 141, 1058, 1059, 1440, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 236, 1441, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 1442, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, + 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 1443, 462, 463, 801, 465, 802, 1088, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, + 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 1257, 1050, 820, + 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 1259, 0, 1056, 0, 0, 1260, 130, 131, 0, + 132, 133, 134, 1261, 136, 137, 138, 139, 1057, 1262, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 1263, 0, 1264, 164, 165, + 166, 167, 168, 1265, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 1266, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, + 233, 0, 234, 0, 235, 1268, 0, 1269, 238, 239, + 1270, 1271, 242, 0, 243, 0, 1071, 1072, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 1272, 256, + 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, + 266, 0, 267, 1273, 269, 270, 271, 272, 273, 274, + 1073, 1074, 0, 1075, 0, 278, 1274, 1275, 281, 1276, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 1277, + 291, 1278, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 1279, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 1077, 1280, 1078, 325, 326, 327, 328, 1079, + 329, 330, 1281, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, + 0, 344, 345, 346, 1282, 348, 1283, 797, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 798, 1284, 366, 367, 368, + 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, + 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 0, 401, 402, 1285, 404, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 1286, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 1287, 431, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 1288, 448, 800, 0, + 0, 450, 451, 0, 452, 1289, 454, 455, 456, 457, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 1290, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, + 2311, 490, 1292, 492, 493, 494, 495, 496, 497, 498, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, + 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 1257, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 1259, 0, 1056, 0, 0, + 1260, 130, 131, 0, 132, 133, 134, 1261, 136, 137, + 138, 139, 1057, 1262, 1058, 1059, 0, 144, 145, 146, + 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, + 1062, 156, 0, 157, 158, 159, 160, 791, 0, 1263, + 0, 1264, 164, 165, 166, 167, 168, 1265, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 1266, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, + 0, 230, 231, 1070, 233, 0, 234, 0, 235, 1268, + 0, 1269, 238, 239, 1270, 1271, 242, 0, 243, 0, + 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 1272, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 1273, 269, 270, + 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, + 1274, 1275, 281, 1276, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 1277, 291, 1278, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1279, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1077, 1280, 1078, 325, + 326, 327, 328, 1079, 329, 330, 1281, 332, 1080, 795, + 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, + 1082, 342, 343, 0, 0, 344, 345, 346, 1282, 348, + 1283, 797, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, + 1284, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 1285, 404, 405, 406, 1084, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 1286, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 1287, 431, 432, 1085, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 1288, 448, 800, 0, 0, 450, 451, 0, 452, 1289, + 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, + 0, 462, 463, 801, 465, 802, 1088, 467, 468, 1290, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 1089, 489, 0, 490, 1292, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, + 0, 0, 0, 0, 1094, 0, 1095, 2368, 0, 0, + 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, + 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, -1131, 126, 127, 128, 0, 0, 0, 0, + -1131, 1056, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, + 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, + 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, + 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, + 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, + 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, + 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, + 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, + 434, -1131, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, + 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, + 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, + 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 1257, + 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 1259, 0, 1056, 0, 0, 1260, 130, + 131, 0, 132, 133, 134, 1261, 136, 137, 138, 139, + 1057, 1262, 1058, 1059, 0, 144, 145, 146, 147, 148, + 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, + 0, 157, 158, 159, 160, 791, 0, 1263, 0, 1264, + 164, 165, 166, 167, 168, 1265, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 1266, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, + 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, + 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, + 231, 1070, 233, 0, 234, 0, 235, 1268, 0, 1269, + 238, 239, 1270, 1271, 242, 0, 243, 0, 1071, 1072, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 1272, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 1273, 269, 270, 271, 272, + 273, 274, 1073, 1074, 0, 1075, 0, 278, 1274, 1275, + 281, 1276, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 1277, 291, 1278, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1279, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1077, 1280, 1078, 325, 326, 327, + 328, 1079, 329, 330, 1281, 332, 1080, 795, 334, 1081, + 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 343, 0, 0, 344, 345, 346, 1282, 348, 1283, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 1284, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 1285, 404, 405, 406, 1084, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 1286, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 1287, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 1288, 448, + 800, 0, 0, 450, 451, 0, 452, 1289, 454, 455, + 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, + 463, 801, 465, 802, 1088, 467, 468, 1290, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1089, 489, 0, 490, 1292, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, + 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, + 0, 0, 1094, 0, 1095, 3126, 0, 0, 0, 1096, + 1097, 1098, 1099, 1257, 1050, 820, 1051, 1052, 1053, 1054, + 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 1259, 0, 1056, + 0, 0, 1260, 130, 131, 0, 132, 133, 134, 1261, + 136, 137, 138, 139, 1057, 1262, 1058, 1059, 0, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 1263, 0, 1264, 164, 165, 166, 167, 168, 1265, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 1266, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 1268, 0, 1269, 238, 239, 1270, 1271, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 1272, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 1273, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 1274, 1275, 281, 1276, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 1277, 291, 1278, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1279, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 1280, + 1078, 325, 326, 327, 328, 1079, 329, 330, 1281, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 1282, 348, 1283, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 1284, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 1285, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 1286, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 1287, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 1288, 448, 800, 0, 0, 450, 451, 0, + 452, 1289, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, + 468, 1290, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 1292, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, + 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, + 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 122, 123, 124, 125, 1705, 126, 127, 128, 0, 0, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 14, 15, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 23, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, + 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, + 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 26, - 27, 28, 0, 362, 363, 798, 365, 366, 367, 368, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 33, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 35, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 37, - 0, 450, 451, 38, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 40, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 804, 1095, 489, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, + 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 44, 500, 501, 502, 503, 504, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 45, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, + 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 117, 1720, 820, 1051, 1052, 1053, 1721, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 23, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 26, 27, 28, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 33, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 38, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 40, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 804, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 44, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 45, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 1264, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 1265, 126, 127, 128, 0, 0, - 0, 1266, 0, 1062, 0, 0, 1267, 130, 131, 0, - 132, 133, 134, 1268, 136, 137, 138, 139, 1063, 1269, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 1270, 0, 1271, 164, 165, - 166, 167, 168, 1272, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 1273, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 1274, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 1275, 0, 1276, 238, 239, - 1277, 1278, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 1279, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 1280, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 1281, 1282, 281, 1283, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 1284, - 291, 1285, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1286, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 1287, 1084, 325, 326, 327, 328, 1085, - 329, 330, 1288, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 881, 344, 345, 346, 1289, 348, 1290, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 1291, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 1292, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 1293, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 1294, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 1295, 448, 800, 0, - 0, 450, 451, 0, 452, 1296, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 1297, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 1298, 490, 1299, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 1300, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 0, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 14, 15, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 23, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 0, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 26, 27, 28, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 33, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 35, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 37, 0, 450, 451, 38, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 40, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 804, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 44, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 45, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 1722, 126, + 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, + 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, + 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, + 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, + 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, + 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, + 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, + 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, + 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, + 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, + 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, + 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, + 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, + 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, + 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, + 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, + 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, + 0, 0, 0, 0, 1094, 0, 1095, 0, 0, 0, + 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, + 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, + 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, + 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, + 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, + 234, 0, 235, 236, 1441, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, + 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, + 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, + 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, + 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, + 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, + 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, + 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, + 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, + 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, + 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, + 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, + 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, + 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, + 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, + 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, + 0, 0, 1094, 0, 1095, 2078, 0, 0, 0, 1096, + 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, + 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, + 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 2730, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, + 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, + 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 1448, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 1449, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, + 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, + 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 1450, 289, 290, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 1451, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 0, 2851, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 1264, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, + 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 1266, 0, 1062, 0, - 0, 1267, 130, 131, 0, 132, 133, 134, 1268, 136, - 137, 138, 139, 1063, 1269, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 1270, 0, 1271, 164, 165, 166, 167, 168, 1272, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 1273, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 1275, 0, 1276, 238, 239, 1277, 1278, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 1279, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 1280, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 1281, 1282, 281, 1283, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 1284, 291, 1285, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1286, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 1287, 1084, - 325, 326, 327, 328, 1085, 329, 330, 1288, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 1289, - 348, 1290, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 1291, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 1292, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 1293, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 1294, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 1295, 448, 800, 0, 0, 450, 451, 0, 452, - 1296, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 1297, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 2334, 490, 1299, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 1264, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 3069, 126, + 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, + 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, + 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, + 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, + 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, + 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 180, 3070, 182, 183, 184, 185, 186, 187, 188, 189, + 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, + 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, + 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, + 3071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, + 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, + 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, + 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, + 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, + 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, + 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 403, 404, 405, 3072, 1084, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, + 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, + 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, + 0, 0, 0, 0, 1094, 0, 3073, 0, 0, 0, + 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, + 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, + 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, + 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, + 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, + 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, + 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, + 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, + 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, + 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, + 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, + 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, + 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, + 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, + 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, + 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, + 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, + 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, + 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, + 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, + 0, 0, 0, 0, 0, 1725, 1726, 1093, 0, 0, + 0, 0, 1094, 0, 1095, 0, 0, 0, 0, 1096, + 1097, 1098, 1099, 117, 2218, 820, 1051, 1052, 1053, 1054, + 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, + 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, + 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, + 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 1266, 0, 1062, 0, 0, 1267, 130, 131, 0, - 132, 133, 134, 1268, 136, 137, 138, 139, 1063, 1269, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 1270, 0, 1271, 164, 165, - 166, 167, 168, 1272, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 1273, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 1275, 0, 1276, 238, 239, - 1277, 1278, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 1279, 256, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, + 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, + 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 1280, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 1281, 1282, 281, 1283, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 1284, - 291, 1285, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1286, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, + 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 1287, 1084, 325, 326, 327, 328, 1085, - 329, 330, 1288, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 1289, 348, 1290, 797, 351, 352, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, + 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 1291, 366, 367, 368, + 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 1292, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 1293, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 1294, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 1295, 448, 800, 0, - 0, 450, 451, 0, 452, 1296, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 1297, 470, 471, 472, 473, + 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, + 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 1299, 492, 493, 494, 495, 496, 497, 498, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, + 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 2389, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, + 0, 0, 0, 1091, 2305, 1093, 0, 0, 0, 0, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, -1139, - 126, 127, 128, 0, 0, 0, 0, -1139, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, -1139, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 1264, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, + 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, + 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, + 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, + 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, + 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, + 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, + 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, + 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, + 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, + 326, 327, 328, 1079, 329, 330, 331, 332, 1080, 795, + 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, + 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, + 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, + 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, + 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, + 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 1090, 0, 0, 0, 0, 0, 0, 1091, 1092, 1093, + 0, 0, 0, 0, 1094, 0, 2525, 0, 0, 0, + 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, + 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, 139, 1057, 141, 1058, 1059, + 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, + 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, + 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, + 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, + 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, + 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 1077, 323, 1078, 325, 326, 327, 328, 1079, 329, 330, + 331, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, + 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 430, 431, 432, 1085, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, + 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 1090, 0, 0, 0, 0, 0, + 0, 1091, 3124, 1093, 0, 0, 0, 0, 1094, 0, + 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, + 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, + 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 1063, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 3070, + 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, + 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, + 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, + 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 3071, 1072, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, + 328, 1079, 329, 330, 331, 332, 1080, 795, 334, 1081, + 336, 337, 338, 0, 339, 340, 0, 0, 1082, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 3072, 1084, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, + 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1090, 0, + 0, 0, 0, 0, 0, 1091, 1092, 1093, 0, 0, + 0, 0, 1094, 0, 3073, 0, 0, 0, 0, 1096, + 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, + 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 3527, 1057, 141, 1058, 1059, 0, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 3528, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, + 1078, 325, 326, 327, 328, 1079, 329, 330, 331, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, + 468, 803, 470, 471, 3529, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 1090, 0, 0, 0, 0, 0, 0, 1091, + 1092, 1093, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, + 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 1266, 0, 1062, 0, 0, 1267, 130, 131, 0, - 132, 133, 134, 1268, 136, 137, 138, 139, 1063, 1269, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 1270, 0, 1271, 164, 165, - 166, 167, 168, 1272, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 1273, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 1275, 0, 1276, 238, 239, - 1277, 1278, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 1279, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 1280, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 1281, 1282, 281, 1283, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 1284, - 291, 1285, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1286, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 1287, 1084, 325, 326, 327, 328, 1085, - 329, 330, 1288, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 1289, 348, 1290, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 1291, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 1292, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 1293, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 1294, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 1295, 448, 800, 0, - 0, 450, 451, 0, 452, 1296, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 1297, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 1299, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 3159, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 1264, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 1266, 0, 1062, 0, - 0, 1267, 130, 131, 0, 132, 133, 134, 1268, 136, - 137, 138, 139, 1063, 1269, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 1270, 0, 1271, 164, 165, 166, 167, 168, 1272, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 1273, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 1275, 0, 1276, 238, 239, 1277, 1278, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 1279, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 1280, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 1281, 1282, 281, 1283, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 1284, 291, 1285, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1286, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 1287, 1084, - 325, 326, 327, 328, 1085, 329, 330, 1288, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 1289, - 348, 1290, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 1291, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 1292, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 1293, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 1294, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 1295, 448, 800, 0, 0, 450, 451, 0, 452, - 1296, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 1297, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 1299, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 1717, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 175, 176, 177, 178, 0, 179, 180, 181, 3528, 183, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 1079, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 3529, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1732, 821, 1057, 1058, 1059, 1733, 1061, + 515, 516, 517, 518, 519, 520, 1090, 0, 0, 0, + 0, 0, 0, 1091, 1092, 1093, 0, 0, 0, 0, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 1734, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, + 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, + 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, 146, + 147, 148, 149, 1060, 790, 150, 151, 152, 153, 1061, + 1062, 156, 0, 157, 158, 159, 160, 791, 0, 792, + 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 1064, 191, 192, 1065, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 1068, 222, 223, 224, 225, 226, 227, 793, 1069, 229, + 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, + 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, + 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, + 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, + 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1077, 323, 1078, 325, + 326, 327, 328, 0, 329, 330, 331, 332, 1080, 795, + 334, 1081, 336, 337, 338, 0, 339, 340, 0, 0, + 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, + 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, + 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, + 454, 455, 456, 457, 458, 0, 459, 1086, 1087, 0, + 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 0, 0, 0, 0, 0, 0, 0, 1427, 1428, 0, + 0, 0, 0, 0, 1094, 0, 1095, 0, 0, 0, + 0, 1096, 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, + 1053, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, + 134, 135, 136, 137, 138, -2081, 1057, 141, 1058, 1059, + 0, 144, 145, 146, 147, 148, 149, 1060, 790, 150, + 151, 152, 153, 1061, 1062, 156, 0, 157, 158, 159, + 160, 791, 0, 792, 0, 1063, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 179, 180, 181, 3528, 183, 184, 185, + 186, 187, 188, 189, 1064, 191, 192, 1065, 194, 1066, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 1068, 222, 223, 224, 225, 226, + 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, + 234, 0, 235, 236, 0, 237, 238, 239, 240, -2081, + 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, -2081, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 268, 269, 270, 271, 272, 273, 274, 1073, 1074, + 0, 1075, 0, 278, 0, 0, 281, 282, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 290, 291, -2081, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 1076, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 1077, 323, 1078, 325, 326, 327, 328, 0, 329, 330, + 0, 332, 1080, 795, 334, 1081, 336, 337, 338, 0, + 339, 340, 0, 0, 1082, 342, 343, 0, 0, 344, + 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 403, 404, 405, 406, + 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, -2081, 431, 432, 1085, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, + 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, + 459, 1086, 1087, 0, 0, 462, 463, 801, 465, 802, + 1088, 467, 468, 803, 470, 471, 3529, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, -2081, 0, 0, 0, 0, 0, + 0, 1091, 1092, 1093, 0, 0, 0, 0, 1094, 0, + 1095, 0, 0, 0, 0, 1096, 1097, 1098, 1099, 117, + 1050, 820, 1051, 1052, 0, 1054, 1055, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 1057, 141, 1058, 1059, 0, 144, 145, 146, 147, 148, + 149, 1060, 790, 150, 151, 152, 153, 1061, 1062, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 1064, 191, + 192, 1065, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 1068, 222, + 223, 224, 225, 226, 227, 793, 1069, 229, 0, 230, + 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 1071, 1072, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 1077, 323, 1078, 325, 326, 327, + 328, 0, 329, 330, 331, 332, 1080, 795, 334, 1081, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 1083, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 2204, 2205, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 1086, 1087, 0, 0, 462, + 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 2206, 2207, 0, 0, 0, + 0, 0, 1094, 0, 1095, 0, 0, 0, 0, 1096, + 1097, 1098, 1099, 117, 1050, 820, 1051, 1052, 1053, 1054, + 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 1056, + 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, + 136, 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, + 145, 146, 147, 148, 149, 1060, 790, 150, 151, 152, + 153, 1061, 1062, 156, 0, 157, 158, 159, 160, 791, + 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 1064, 191, 192, 1065, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 1068, 222, 223, 224, 225, 226, 227, 793, + 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, + 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, + 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, + 269, 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, + 0, 278, 0, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 1076, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 1077, 323, + 1078, 325, 326, 327, 328, 0, 329, 330, 331, 332, + 1080, 795, 334, 1081, 336, 337, 338, 0, 339, 340, + 0, 0, 1082, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 403, 404, 405, 406, 1084, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 430, 431, 432, 1085, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 452, 453, 454, 455, 456, 457, 458, 0, 459, 1086, + 1087, 0, 0, 462, 463, 801, 465, 802, 1088, 467, + 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 0, 0, 0, 0, 0, 0, 0, 1427, + 1428, 0, 0, 0, 0, 0, 1094, 0, 1095, 0, + 0, 0, 0, 1096, 1097, 1098, 1099, 117, 1050, 820, + 1051, 1052, 0, 1054, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 1449, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, + 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, + 240, 241, 242, 0, 243, 3090, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 0, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, + 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, + 0, 0, 117, 1050, 820, 1051, 1052, 0, 1054, 1055, + 1094, 0, 2778, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 137, 138, 139, 1057, 141, 1058, 1059, 0, 144, 145, + 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, + 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, + 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 189, 1064, 191, 192, 1065, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, + 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, + 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, + 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, + 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, + 315, 316, 317, 318, 319, 320, 321, 1077, 323, 1078, + 325, 326, 327, 328, 0, 329, 330, 331, 332, 1080, + 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, + 428, 429, 0, 430, 431, 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, + 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, + 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 2096, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 520, 0, 0, 0, 0, 0, 0, 117, 1050, 820, + 1051, 1052, 0, 1054, 1055, 1094, 0, 2778, 0, 0, + 0, 0, 1096, 1097, 1098, 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 1057, 141, + 1058, 1059, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 1061, 1062, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 184, 185, 186, 187, 188, 189, 1064, 191, 192, 1065, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 1068, 222, 223, 224, + 225, 226, 227, 793, 1069, 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 240, 241, 242, 0, 243, 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, + 1073, 1074, 0, 1075, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 1077, 323, 1078, 325, 326, 327, 328, 0, + 329, 330, 331, 332, 1080, 795, 334, 1081, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, + 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, + 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 458, 0, 459, 1086, 1087, 0, 0, 462, 463, 801, + 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, + 481, 0, 482, 483, 484, 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 2695, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, + 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, + 0, 0, 117, 1050, 820, 1051, 1052, 1053, 1054, 1055, + 1094, 0, 1095, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 137, 138, 0, 1057, 141, 1058, 1059, 0, 144, 145, + 146, 147, 148, 149, 1060, 790, 150, 151, 152, 153, + 1061, 1062, 156, 0, 157, 158, 159, 160, 791, 0, + 792, 0, 1063, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 189, 1064, 191, 192, 1065, 194, 1066, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, + 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, + 212, 213, 0, 214, 0, 216, 0, 217, 218, 219, + 220, 1068, 222, 223, 224, 225, 226, 227, 793, 1069, + 229, 0, 230, 231, 1070, 233, 0, 234, 0, 235, + 236, 0, 237, 238, 239, 240, 0, 242, 0, 243, + 0, 1071, 1072, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 270, 271, 272, 273, 274, 1073, 1074, 0, 1075, 0, + 278, 0, 0, 281, 282, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 290, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, + 315, 316, 317, 318, 319, 320, 321, 1077, 323, 1078, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 1080, + 795, 334, 1081, 336, 337, 338, 0, 339, 340, 0, + 0, 1082, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 1083, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 403, 404, 405, 406, 1084, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, + 428, 429, 0, 0, 431, 432, 1085, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 2752, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, + 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, + 453, 454, 455, 456, 457, 458, 0, 459, 1086, 1087, + 0, 0, 462, 463, 801, 465, 802, 1088, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 487, 1089, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 2878, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 3096, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 3097, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 3098, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 3099, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 3100, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 3321, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1737, 1738, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 2238, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 520, 0, 0, 0, 0, 0, 0, 0, 1091, 1092, + 1093, 0, 973, 1356, 820, 1094, 0, 1095, 1054, 0, + 0, 0, 1096, 1097, 1098, 1099, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 126, 127, 128, 0, 0, 0, 565, 0, 0, 0, + 0, 570, 130, 131, 0, 132, 133, 134, 572, 136, + 137, 138, 573, 574, 575, 576, 577, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 581, 582, 156, 0, 157, 158, 159, 160, 584, 0, + 586, 0, 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 594, 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 220, 605, 222, 223, 224, 225, 226, 227, 606, 1357, + 229, 0, 230, 231, 609, 233, 0, 234, 0, 235, + 612, 0, 614, 238, 239, 615, 616, 242, 0, 243, + 0, 619, 620, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 622, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 625, 626, + 270, 271, 272, 273, 274, 627, 628, 0, 630, 0, + 278, 632, 633, 281, 634, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 637, 291, 638, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 2385, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, + 325, 326, 327, 644, 0, 329, 330, 646, 332, 0, + 648, 334, 649, 336, 337, 338, 0, 339, 340, 1358, + 0, 341, 342, 343, 0, 0, 344, 345, 655, 656, + 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, + 663, 664, 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 668, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, + 420, 0, 674, 421, 422, 423, 424, 425, 426, 675, + 428, 429, 0, 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 446, 680, 448, 681, 0, 0, 450, 451, 0, 452, + 685, 454, 455, 456, 457, 458, 0, 459, 687, 688, + 0, 0, 462, 463, 691, 465, 692, 1359, 467, 468, + 694, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 699, 700, 489, 0, 490, 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, + 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, + 520, 0, 0, 0, 0, 0, 0, 117, 1360, 1361, + 2386, 0, 0, 0, 1055, 2387, 0, 2388, 0, 0, + 0, 0, 0, 0, 0, 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, + 0, 0, 0, 1056, 0, 0, 129, 130, 131, 0, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 1060, + 790, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 793, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, + 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, + 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 300, 1076, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 0, + 329, 330, 331, 332, 0, 795, 334, 335, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 801, + 465, 802, 0, 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 2325, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, + 0, 0, 528, 0, 0, 0, 0, 0, 0, 0, + 1094, 0, 2122, 0, 0, 0, 0, 1096, 1097, 1098, + 1099, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 1008, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, + 212, 213, 0, 214, 215, 216, -540, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, -540, 230, 231, 232, 233, -540, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, -540, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, -540, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, -540, 339, 340, 0, + 0, 341, 342, 343, 0, -540, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, -540, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 2547, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 3157, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1170, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 973, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2476, 3273, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 3, 4, 0, 565, 0, 0, 0, 0, 570, + 130, 131, 0, 132, 133, 134, 572, 136, 137, 138, + 573, 574, 575, 576, 577, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 581, 582, + 156, 0, 157, 158, 159, 160, 584, 0, 586, 0, + 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 592, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, + 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 14, 15, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 605, + 222, 223, 224, 225, 226, 227, 606, 0, 229, 0, + 230, 231, 609, 233, 0, 234, 0, 235, 612, 23, + 614, 238, 239, 615, 616, 242, 0, 243, 0, 619, + 620, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 622, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 625, 626, 270, 271, + 272, 273, 274, 627, 628, 0, 630, 0, 278, 632, + 633, 281, 634, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 637, 291, 638, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, + 327, 644, 0, 329, 330, 646, 332, 0, 648, 334, + 649, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 655, 656, 348, 657, + 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 26, 27, 28, 0, 362, 363, 663, 664, + 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 668, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, + 674, 421, 422, 423, 424, 425, 426, 675, 428, 429, + 35, 677, 431, 432, 678, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, + 448, 681, 37, 0, 450, 451, 38, 452, 685, 454, + 455, 456, 457, 458, 0, 459, 687, 688, 0, 0, + 462, 463, 691, 465, 692, 0, 467, 468, 694, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 974, 700, 489, 0, 490, 702, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, + 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, + 713, 714, 715, 716, 717, 517, 518, 519, 520, 0, + 117, 45, 554, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 46, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, + 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 14, 15, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 793, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 236, 23, + 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 794, + 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, 0, 795, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, + 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, + 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 26, 27, 28, 0, 362, 363, 798, 365, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 403, 404, 405, 406, 407, 799, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 33, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 35, 430, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 800, 37, 0, 450, 451, 38, 452, 453, 454, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 40, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 804, 488, 489, 0, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 44, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 0, + 117, 45, 554, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 805, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, + 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, + 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 793, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, + 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 794, + 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, 0, 795, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, + 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, + 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 403, 404, 405, 406, 407, 799, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 804, 488, 489, 0, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 3097, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 3098, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 3099, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 3100, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 0, 0, 0, 0, 0, 805, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, + 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 790, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 791, 0, 792, 0, 163, + 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 793, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 236, 0, 237, + 238, 239, 240, 241, 242, 0, 243, 0, 244, 245, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 279, 280, + 281, 282, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, 0, 795, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 347, 348, 349, 797, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 798, 365, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 403, 404, 405, 406, 407, 799, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 430, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 800, 0, 0, 450, 451, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, + 463, 801, 465, 802, 0, 467, 468, 803, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 117, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, + 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 790, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 791, 0, 792, 0, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 793, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, + 239, 240, 241, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 279, 280, 281, + 282, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 290, 291, 292, 0, 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, + 0, 329, 330, 331, 332, 0, 795, 334, 335, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 347, 348, 349, 797, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 362, 363, 798, 365, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 800, + 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 801, 465, 802, 0, 467, 468, 803, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3359, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 3565, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 1069, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 3566, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 1072, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, + 14, 15, 202, 203, 204, 205, 0, 0, 206, 207, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 23, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 1085, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 26, + 27, 28, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 3567, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 33, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 35, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 37, + 0, 450, 451, 38, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 40, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 804, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, + 0, 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 1096, 0, 0, 0, - 0, 0, 0, 1097, 1098, 1099, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 515, 516, 517, 518, 519, 520, 528, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 46, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 893, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, + 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, + 0, 234, 0, 235, 0, 23, 0, 238, 239, 529, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 26, 27, + 28, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 33, 0, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, + 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 38, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 894, 461, 0, 0, 895, 463, 464, 465, + 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 40, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 804, 488, 489, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 44, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 528, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, + 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, + 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, + 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 0, 235, 0, 23, 0, 238, 239, 529, 0, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, + 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 26, 27, 28, + 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 33, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, + 451, 38, 452, 0, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 40, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 804, 488, 489, 0, 490, + 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 44, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 0, 528, 45, 554, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 46, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, + 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, + 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, + 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, + 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, + 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, + 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 993, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, + 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, + 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, + 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, + 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, + 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1481, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2230, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 3566, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 1085, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 3567, 473, 474, 0, 0, 475, 476, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1096, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 1059, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2476, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2612, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, + 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, + 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, + 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, + 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, + 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, + 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3268, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2085, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, + 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, + 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, + 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, + 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, + 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, + 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2190, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 1088, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, - 0, 0, 0, 1435, 1436, 0, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, -2102, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 3566, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, -2102, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, -2102, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 0, 0, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, -2102, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, -2102, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 3567, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, -2102, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 0, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 2224, 2225, 409, 410, 411, 412, 413, 414, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, - 0, 0, 0, 2226, 2227, 0, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 0, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 0, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 0, 1435, 1436, - 0, 0, 0, 0, 0, 1100, 0, 1101, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 0, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 515, 516, 517, 518, 519, 520, 0, 2946, 1356, 820, + 0, 0, 2060, 1054, 0, 0, 0, 0, 0, 2061, + 2062, 0, 3131, 2063, 2064, 2065, 118, 119, 120, 121, + 122, 123, 124, 125, 561, 126, 127, 128, 562, 563, + 564, 2947, 566, 567, 568, 569, 2948, 130, 131, 571, + 132, 133, 134, 2949, 136, 137, 138, 0, 1494, 2950, + 1496, 1497, 578, 144, 145, 146, 147, 148, 149, 579, + 580, 150, 151, 152, 153, 1498, 1499, 156, 583, 157, + 158, 159, 160, 0, 585, 2951, 587, 2952, 164, 165, + 166, 167, 168, 2953, 170, 171, 172, 590, 173, 174, + 175, 176, 177, 178, 591, 2954, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 1504, 191, 192, 1505, + 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, + 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, + 1067, 209, 210, 602, 211, 212, 213, 603, 214, 215, + 216, 604, 217, 218, 219, 220, 0, 222, 223, 224, + 225, 226, 227, 0, 607, 229, 608, 230, 231, 1506, + 233, 610, 234, 611, 235, 2955, 613, 2956, 238, 239, + 2957, 2958, 242, 617, 243, 618, 0, 0, 246, 247, + 621, 248, 249, 250, 251, 252, 253, 254, 2959, 256, + 257, 258, 259, 623, 260, 261, 262, 263, 264, 265, + 266, 624, 267, 2960, 0, 270, 271, 272, 273, 274, + 1512, 1513, 629, 1514, 631, 278, 2961, 2962, 281, 2963, + 283, 284, 285, 286, 287, 288, 635, 636, 289, 2964, + 291, 2965, 639, 293, 294, 295, 296, 297, 298, 299, + 300, 2966, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 1521, 2967, 1523, 325, 326, 327, 2968, 645, + 329, 330, 2969, 332, 647, 0, 334, 1525, 336, 337, + 338, 650, 339, 340, 651, 652, 2970, 342, 343, 653, + 654, 344, 345, 0, 2971, 348, 2972, 0, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 659, + 660, 661, 662, 362, 363, 0, 2973, 366, 367, 0, + 369, 370, 371, 666, 372, 373, 374, 375, 376, 377, + 667, 378, 379, 380, 381, 382, 1529, 384, 385, 386, + 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 670, 401, 402, 2974, 404, + 405, 406, 1531, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 673, 2975, 421, 422, + 423, 424, 425, 426, 2976, 428, 429, 676, 2977, 431, + 432, 1535, 434, 679, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 2978, 448, 0, 682, + 683, 450, 451, 684, 452, 2979, 454, 455, 456, 457, + 458, 686, 459, 1538, 1539, 689, 690, 462, 463, 0, + 465, 0, 693, 467, 468, 2980, 470, 471, 472, 473, + 474, 2981, 696, 475, 476, 477, 697, 478, 479, 480, + 481, 698, 482, 483, 484, 485, 486, 0, 1542, 489, + 701, 490, 2982, 492, 493, 494, 495, 496, 497, 498, + 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, + 505, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 517, 518, 519, 520, 0, 528, 0, 2066, + 2067, 2068, 2060, 2983, 2984, 2071, 2072, 2073, 2074, 2061, + 2062, 0, 0, 2063, 2064, 2065, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 3117, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, + 515, 516, 517, 518, 519, 520, 0, 0, 0, 2066, + 2067, 2068, 0, 2069, 2070, 2071, 2072, 2073, 2074, 1626, + 0, 0, 1627, 0, 0, 0, 1628, 1629, 1630, 1631, + 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1635, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1637, 1626, 0, + 0, 1627, 0, 0, 1638, 1628, 1629, 1630, 1631, 1632, + 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1635, 0, 0, 0, + 0, 1639, 0, 0, 0, 0, 1637, 1626, 0, 0, + 1627, 0, 0, 1638, 1628, 1629, 1630, 1631, 1632, 1633, + 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1635, 0, 0, 0, 0, + 1639, 0, 0, 0, 0, 1637, 0, 0, 0, 0, + 0, 0, 1638, 0, 0, 1626, 0, 0, 1627, 0, + 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1639, + 0, 0, 0, 1635, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1637, 1626, 0, 0, 1627, 1640, 0, + 1638, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, + 0, 0, 0, 0, 0, 1641, 0, 0, 0, 0, + 1642, 0, 1635, 0, 0, 0, 0, 1639, 0, 0, + 0, 0, 1637, 0, 0, 0, 0, 1640, 0, 1638, + 0, 0, 0, 1643, 1644, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1641, 0, 0, 0, 1645, 1642, + 0, 0, 0, 0, 0, 0, 1639, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1640, 0, 0, 0, + 0, 0, 1643, 1644, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1641, 0, 0, 1646, 1645, 1642, 1647, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1100, 0, 2800, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 0, 1060, 1061, + 0, 0, 0, 1648, 0, 0, 1649, 0, 0, 0, + 0, 1643, 1644, 0, 1640, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1646, 1645, 0, 1647, 0, + 0, 1641, 0, 0, 0, 0, 1642, 0, 0, 0, + 0, 0, 1648, 0, 0, 1649, 0, 0, 0, 0, + 0, 0, 0, 1640, 0, 0, 0, 0, 0, 1643, + 1644, 0, 0, 0, 1646, 0, 0, 1647, 0, 0, + 1641, 0, 0, 0, 1645, 1642, 0, 0, 0, 0, + 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, + 0, 0, 0, 0, 0, 1650, 0, 0, 0, 0, + 0, 0, 1646, 1645, 0, 1647, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1648, + 0, 0, 1649, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1650, 0, 0, 0, 0, 0, + 0, 1646, 0, 0, 1647, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1648, 0, + 0, 1649, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 0, 329, 330, 331, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1100, 0, 2800, 0, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 117, 1056, 821, - 1057, 1058, 0, 1060, 1061, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 1062, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 1063, 141, - 1064, 1065, 0, 144, 145, 146, 147, 148, 149, 1066, - 790, 150, 151, 152, 153, 1067, 1068, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 1070, 191, 192, 1071, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 1073, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 1074, 222, 223, 224, - 225, 226, 227, 793, 1075, 229, 0, 230, 231, 1076, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 1077, 1078, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 1079, 1080, 0, 1081, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 1082, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 1083, 323, 1084, 325, 326, 327, 328, 0, - 329, 330, 331, 332, 1086, 795, 334, 1087, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 1089, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, - 405, 406, 1090, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, - 432, 1091, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 1092, 1093, 0, 0, 462, 463, 801, - 465, 802, 1094, 467, 468, 803, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 1095, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1100, 0, 1101, 0, 0, 0, 0, 0, 1102, 1103, - 1104, 1105, 117, 1056, 821, 1057, 1058, 1059, 1060, 1061, + 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, + 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 0, + 2892, 1650, 0, 0, 0, 0, 0, 1626, 0, 0, + 1627, 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, + 1634, 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, + 1656, 1657, 1658, 1659, 1660, 1635, 0, 0, 0, 3123, + 1650, 0, 0, 0, 0, 1637, 0, 0, 0, 0, + 0, 0, 1638, 0, 0, 0, 0, 0, 0, 0, + 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, + 1657, 1658, 1659, 1660, 0, 0, 0, 0, 3130, 1639, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 1062, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 0, 1063, 141, 1064, 1065, 0, 144, 145, - 146, 147, 148, 149, 1066, 790, 150, 151, 152, 153, - 1067, 1068, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 1069, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1070, 191, 192, 1071, 194, 1072, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 0, 216, 0, 217, 218, 219, - 220, 1074, 222, 223, 224, 225, 226, 227, 793, 1075, - 229, 0, 230, 231, 1076, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 0, 242, 0, 243, - 0, 1077, 1078, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, - 270, 271, 272, 273, 274, 1079, 1080, 0, 1081, 0, - 278, 0, 0, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 1082, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1083, 323, 1084, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 1086, - 795, 334, 1087, 336, 337, 338, 0, 339, 340, 0, - 0, 1088, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1089, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 1090, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 1091, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 1092, 1093, - 0, 0, 462, 463, 801, 465, 802, 1094, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 1095, 489, 0, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 0, 1097, 1098, - 1099, 0, 974, 1364, 821, 1100, 0, 1101, 1060, 0, - 0, 0, 0, 1102, 1103, 1104, 1105, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 565, 0, 0, 0, - 0, 570, 130, 131, 0, 132, 133, 134, 572, 136, - 137, 138, 573, 574, 575, 576, 577, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 581, 582, 156, 0, 157, 158, 159, 160, 584, 0, - 586, 0, 588, 164, 165, 166, 167, 168, 589, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 594, 191, 192, 595, 194, 0, 195, 0, 196, + 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, + 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 1651, + 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, + 1659, 1660, 1635, 0, 0, 0, 3288, 0, 0, 0, + 0, 0, 1637, 1626, 0, 0, 1627, 0, 0, 1638, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 1651, 0, + 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 1635, 0, 0, 0, 3310, 1639, 0, 0, 0, + 0, 1637, 1626, 0, 0, 1627, 1640, 0, 1638, 1628, + 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, + 0, 0, 0, 1641, 0, 0, 0, 0, 1642, 0, + 1635, 0, 0, 0, 0, 1639, 0, 0, 0, 0, + 1637, 0, 0, 0, 0, 0, 0, 1638, 0, 0, + 0, 1643, 1644, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1645, 0, 0, 0, + 0, 0, 0, 0, 1639, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1626, + 0, 0, 1627, 1640, 0, 0, 1628, 1629, 1630, 1631, + 1632, 1633, 1634, 0, 1646, 0, 0, 1647, 0, 0, + 1641, 0, 0, 0, 0, 1642, 0, 1635, 0, 0, + 0, 1648, 0, 0, 1649, 0, 0, 1637, 0, 0, + 0, 0, 1640, 0, 1638, 0, 0, 0, 1643, 1644, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, + 0, 0, 0, 1645, 1642, 0, 0, 0, 0, 0, + 0, 1639, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1640, 0, 0, 0, 0, 0, 1643, 1644, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1641, 0, + 0, 1646, 1645, 1642, 1647, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1648, 0, + 0, 1649, 0, 0, 0, 0, 1643, 1644, 0, 0, + 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, + 1646, 1645, 0, 1647, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 0, 1640, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1646, + 0, 0, 1647, 0, 0, 1641, 0, 0, 0, 0, + 1642, 0, 0, 0, 0, 0, 1648, 0, 0, 1649, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1643, 1644, 0, 0, 0, 0, 0, + 1650, 0, 0, 0, 0, 0, 0, 0, 1645, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, + 1657, 1658, 1659, 1660, 0, 0, 0, 0, 3409, 1650, + 0, 0, 0, 0, 0, 0, 1646, 0, 0, 1647, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1379, 1380, 1648, 0, 0, 1649, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1626, 0, 1650, 1627, + 0, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1381, 1382, 1635, 0, 1383, 1384, 1651, 0, + 0, 1652, 1653, 1654, 1637, 1655, 1656, 1657, 1658, 1659, + 1660, 1638, 0, 0, 0, 3465, 0, 0, 0, 0, + 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 0, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1651, 1639, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, + 0, 1635, 0, 0, 3487, 1650, 0, 0, 0, 0, + 0, 1637, 0, 0, 0, 0, 0, 0, 1638, 0, + 0, 0, 1385, 1386, 0, 0, 1651, 0, 0, 1652, + 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, + 0, 1815, 0, 0, 0, 1639, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1640, 1387, 1388, 1389, 1390, + 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, 0, 0, + 0, 0, 1641, 0, 0, 0, 0, 1642, 0, 0, + 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, + 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 2846, 0, + 1643, 1644, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1640, 0, 0, 1645, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, + 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, + 1397, 1398, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1646, 0, 0, 1647, 1643, 1644, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1648, 0, 1645, 1649, 0, 0, 0, 0, 0, 0, + 0, 1399, 1400, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 1647, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1650, 0, 0, 0, 0, 1401, 1402, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1403, 1404, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2018, 0, 0, 0, 0, 0, 0, 0, 1650, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, + 1658, 1659, 1660, 0, 0, 3278, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 560, 0, 0, 1651, 0, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, + 0, 0, 3449, 118, 119, 120, 121, 122, 123, 124, + 125, 561, 126, 127, 128, 562, 563, 564, 565, 566, + 567, 568, 569, 570, 130, 131, 571, 132, 133, 134, + 572, 136, 137, 138, 573, 574, 575, 576, 577, 578, + 144, 145, 146, 147, 148, 149, 579, 580, 150, 151, + 152, 153, 581, 582, 156, 583, 157, 158, 159, 160, + 584, 585, 586, 587, 588, 164, 165, 166, 167, 168, + 589, 170, 171, 172, 590, 173, 174, 175, 176, 177, + 178, 591, 592, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 594, 191, 192, 595, 194, 596, 195, + 597, 196, 197, 198, 199, 200, 201, 598, 599, 202, + 203, 204, 205, 600, 601, 206, 207, 208, 209, 210, + 602, 211, 212, 213, 603, 214, 215, 216, 604, 217, + 218, 219, 220, 605, 222, 223, 224, 225, 226, 227, + 606, 607, 229, 608, 230, 231, 609, 233, 610, 234, + 611, 235, 612, 613, 614, 238, 239, 615, 616, 242, + 617, 243, 618, 619, 620, 246, 247, 621, 248, 249, + 250, 251, 252, 253, 254, 622, 256, 257, 258, 259, + 623, 260, 261, 262, 263, 264, 265, 266, 624, 267, + 625, 626, 270, 271, 272, 273, 274, 627, 628, 629, + 630, 631, 278, 632, 633, 281, 634, 283, 284, 285, + 286, 287, 288, 635, 636, 289, 637, 291, 638, 639, + 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, + 642, 643, 325, 326, 327, 644, 645, 329, 330, 646, + 332, 647, 648, 334, 649, 336, 337, 338, 650, 339, + 340, 651, 652, 341, 342, 343, 653, 654, 344, 345, + 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 659, 660, 661, 662, + 362, 363, 663, 664, 366, 367, 665, 369, 370, 371, + 666, 372, 373, 374, 375, 376, 377, 667, 378, 379, + 380, 381, 382, 668, 384, 385, 386, 387, 669, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 670, 401, 402, 671, 404, 405, 406, 672, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 673, 674, 421, 422, 423, 424, 425, + 426, 675, 428, 429, 676, 677, 431, 432, 678, 434, + 679, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 680, 448, 681, 682, 683, 450, 451, + 684, 452, 685, 454, 455, 456, 457, 458, 686, 459, + 687, 688, 689, 690, 462, 463, 691, 465, 692, 693, + 467, 468, 694, 470, 471, 472, 473, 474, 695, 696, + 475, 476, 477, 697, 478, 479, 480, 481, 698, 482, + 483, 484, 485, 486, 699, 700, 489, 701, 490, 702, + 492, 493, 494, 495, 496, 497, 498, 703, 704, 499, + 705, 706, 500, 501, 502, 503, 504, 505, 707, 708, + 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, + 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, + 0, 0, 2096, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 0, 2744, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 605, 222, 223, 224, 225, 226, 227, 606, 1365, - 229, 0, 230, 231, 609, 233, 0, 234, 0, 235, - 612, 0, 614, 238, 239, 615, 616, 242, 0, 243, - 0, 619, 620, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 622, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 625, 626, - 270, 271, 272, 273, 274, 627, 628, 0, 630, 0, - 278, 632, 633, 281, 634, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 637, 291, 638, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 2406, 302, 303, 304, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, - 325, 326, 327, 644, 0, 329, 330, 646, 332, 0, - 648, 334, 649, 336, 337, 338, 0, 339, 340, 1366, - 0, 341, 342, 343, 0, 0, 344, 345, 655, 656, - 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 663, 664, 366, 367, 665, 369, 370, 371, 0, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 668, 384, 385, 386, 387, 0, 388, 389, 390, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 671, 404, 405, 406, 672, 408, 409, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 674, 421, 422, 423, 424, 425, 426, 675, - 428, 429, 0, 677, 431, 432, 678, 434, 0, 435, + 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 680, 448, 681, 0, 0, 450, 451, 0, 452, - 685, 454, 455, 456, 457, 458, 0, 459, 687, 688, - 0, 0, 462, 463, 691, 465, 692, 1367, 467, 468, - 694, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 699, 700, 489, 0, 490, 702, 492, 493, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, - 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, - 520, 0, 0, 0, 0, 0, 0, 0, 1368, 1369, - 2407, 117, 0, 0, 0, 2408, 0, 2409, 1061, 0, - 0, 0, 0, 0, 0, 0, 1105, 0, 0, 0, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 973, 1356, 820, 0, 0, 0, 1054, 0, 0, + 2747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 1062, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 1066, 790, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 127, 128, 0, 0, 0, 565, 0, 0, 0, 0, + 570, 130, 131, 0, 132, 133, 134, 572, 136, 137, + 138, 573, 574, 575, 576, 577, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 581, + 582, 156, 0, 157, 158, 159, 160, 584, 0, 586, + 0, 588, 164, 165, 166, 167, 168, 589, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 594, 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 793, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1082, 302, 303, 304, 305, + 605, 222, 223, 224, 225, 226, 227, 606, 1357, 229, + 0, 230, 231, 609, 233, 0, 234, 0, 235, 612, + 0, 614, 238, 239, 615, 616, 242, 0, 243, 0, + 619, 620, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 622, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 625, 626, 270, + 271, 272, 273, 274, 627, 628, 0, 630, 0, 278, + 632, 633, 281, 634, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 637, 291, 638, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 640, 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, 0, 329, 330, 331, 332, 0, 795, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, + 326, 327, 644, 0, 329, 330, 646, 332, 0, 648, + 334, 649, 336, 337, 338, 0, 339, 340, 1358, 0, + 341, 342, 343, 0, 0, 344, 345, 655, 656, 348, + 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 663, + 664, 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 668, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 433, 434, 0, 435, 436, + 0, 674, 421, 422, 423, 424, 425, 426, 675, 428, + 429, 0, 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 801, 465, 802, 0, 467, 468, 803, + 680, 448, 681, 0, 0, 450, 451, 0, 452, 685, + 454, 455, 456, 457, 458, 0, 459, 687, 688, 0, + 0, 462, 463, 691, 465, 692, 1359, 467, 468, 694, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, + 486, 699, 700, 489, 0, 490, 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, + 712, 713, 714, 715, 716, 717, 517, 518, 519, 520, + 0, 0, 1626, 0, 0, 1627, 0, 1360, 1361, 1628, + 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 528, 1982, 0, 1100, 0, 2142, 1983, 1061, 0, - 0, 0, 1102, 1103, 1104, 1105, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 0, 0, 0, 0, 0, 528, 0, 0, 0, 0, + 1635, 0, 0, 0, 0, 2196, 0, 0, 0, 0, + 1637, 1626, 0, 0, 1627, 0, 0, 1638, 1628, 1629, + 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 1626, + 0, 0, 1627, 0, 0, 0, 1628, 1629, 0, 1635, + 1632, 1633, 1634, 0, 1639, 0, 0, 0, 0, 1637, + 1626, 0, 0, 1627, 0, 0, 1638, 1628, 1629, 1630, + 1631, 1632, 1633, 1634, 0, 0, 0, 1637, 0, 0, + 0, 0, 0, 0, 1638, 0, 0, 0, 1635, 0, + 0, 0, 0, 1639, 0, 0, 0, 0, 1637, 0, + 2197, 0, 0, 0, 0, 1638, 0, 1626, 0, 0, + 1627, 1639, 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, + 1634, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1639, 0, 0, 1635, 0, 0, 0, 1914, + 0, 0, 0, 0, 0, 1637, 0, 0, 0, 0, + 0, 1640, 1638, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1641, 0, + 0, 0, 0, 1642, 0, 0, 0, 0, 0, 1639, + 1950, 0, 0, 0, 0, 1951, 0, 0, 0, 0, + 1640, 0, 0, 0, 0, 0, 1643, 1644, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1641, 1640, 0, + 0, 1645, 1642, 0, 0, 0, 0, 0, 3555, 0, + 0, 0, 0, 0, 0, 1641, 0, 0, 0, 1640, + 1642, 0, 0, 0, 0, 1643, 1644, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1641, 0, 0, 1646, + 1645, 1642, 1647, 1643, 1644, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1648, 0, 1645, 1649, + 0, 0, 0, 0, 1643, 1644, 1640, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1646, 1645, + 0, 1647, 0, 1641, 0, 0, 0, 0, 1642, 0, + 0, 0, 0, 0, 0, 1648, 1646, 0, 1649, 1647, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1102, 1103, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 1010, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, + 0, 1643, 1644, 1648, 0, 0, 0, 1646, 0, 0, + 1647, 0, 0, 0, 0, 0, 1645, 0, 0, 0, + 0, 0, 0, 0, 1648, 0, 0, 1649, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1650, 0, + 0, 0, 0, 0, 1646, 0, 3556, 1647, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, + 0, 0, 1626, 0, 0, 1627, 0, 1650, 0, 1628, + 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1650, 0, 0, 0, 0, + 1635, 2200, 0, 0, 0, 0, 0, 0, 0, 0, + 1637, 0, 0, 0, 0, 0, 1650, 1638, 0, 0, + 0, 0, 0, 1379, 1380, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1639, 0, 1651, 0, 0, 1652, + 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, + 0, 0, 0, 1650, 1381, 1382, 0, 0, 1383, 1384, + 0, 1626, 0, 0, 1627, 0, 0, 0, 1628, 1629, + 0, 0, 1632, 1633, 1634, 1651, 0, 0, 1652, 1653, + 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 1635, + 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, 1637, + 1655, 1656, 1657, 1658, 1659, 1660, 1638, 0, 0, 0, + 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, 1654, + 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, 0, + 0, 1640, 0, 1639, 1385, 1386, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1626, 1641, 0, + 1627, 0, 0, 1642, 1628, 1629, 1630, 1631, 1632, 1633, + 1634, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, + 1657, 1658, 1659, 1660, 0, 1635, 1643, 1644, 0, 1956, + 0, 0, 0, 0, 0, 1637, 0, 0, 0, 0, + 0, 1645, 1638, 0, 0, 0, 0, 0, 1387, 1388, + 1389, 1390, 1391, 1392, 1393, 1394, 0, 0, 1395, 1396, + 0, 0, 0, 1626, 0, 0, 1627, 0, 0, 1639, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 1646, + 1640, 0, 1647, 0, 0, 0, 0, 0, 0, 0, + 0, 1635, 0, 0, 0, 0, 1648, 1641, 0, 1649, + 0, 1637, 1642, 0, 0, 0, 0, 0, 1638, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1921, 0, 0, 1643, 1644, 0, 0, 0, + 0, 0, 1397, 1398, 0, 1639, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1626, 0, 0, 1627, 0, 0, 0, 1628, + 1629, 1630, 1631, 1632, 1633, 1634, 1640, 0, 0, 0, + 0, 0, 0, 1399, 1400, 0, 0, 0, 1646, 0, + 1635, 1647, 0, 1641, 1963, 0, 0, 0, 1642, 0, + 1637, 0, 0, 0, 0, 1648, 0, 1638, 1650, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1643, 1644, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1639, 0, 1645, 1961, 0, 0, + 0, 0, 1640, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1641, + 0, 0, 0, 0, 1642, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1646, 0, 0, 1647, 0, 1401, + 1402, 0, 0, 0, 0, 0, 0, 1643, 1644, 0, + 0, 1648, 0, 0, 1649, 0, 0, 0, 0, 0, + 0, 0, 1645, 1403, 1404, 0, 0, 1650, 0, 0, + 0, 0, 0, 0, 0, 0, 1651, 0, 0, 1652, + 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, + 0, 1640, 0, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 1647, 0, 0, 0, 0, 1641, 0, + 0, 0, 0, 1642, 0, 0, 0, 1648, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1626, 0, 0, 1627, 0, 1643, 1644, 1628, 1629, + 1630, 1631, 1632, 1633, 1634, 0, 0, 0, 0, 0, + 0, 1645, 0, 1650, 0, 0, 0, 0, 0, 1635, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1637, + 0, 0, 0, 0, 0, 1651, 1638, 0, 1652, 1653, + 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 1626, 1646, + 0, 1627, 1647, 0, 0, 1628, 1629, 1630, 1631, 1632, + 1633, 1634, 0, 1639, 0, 0, 1648, 0, 0, 1649, + 0, 0, 0, 0, 0, 0, 1635, 0, 0, 1650, + 0, 0, 0, 0, 0, 0, 1637, 0, 0, 0, + 0, 0, 0, 1638, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, 1656, + 1657, 1658, 1659, 1660, 0, 1626, 0, 0, 1627, 0, + 0, 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, + 2089, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1640, 0, 0, 1635, 0, 0, 0, 2822, 1650, 0, + 0, 0, 0, 1637, 0, 0, 0, 1641, 0, 0, + 1638, 0, 1642, 0, 0, 0, 0, 1651, 0, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, + 0, 0, 0, 0, 0, 1643, 1644, 1639, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1640, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1641, 0, 0, 0, 0, 1642, + 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 0, + 0, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1646, 0, + 0, 1647, 1643, 1644, 0, 0, 0, 0, 0, 0, + 0, 0, 1635, 0, 0, 1648, 1651, 1645, 1649, 1652, + 1653, 1654, 1637, 1655, 1656, 1657, 1658, 1659, 1660, 1638, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1640, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1646, 1639, 0, 1647, 0, + 0, 1641, 0, 0, 0, 0, 1642, 0, 0, 0, + 0, 0, 1648, 0, 0, 1649, 0, 0, 0, 0, + 0, 0, 0, 0, 1626, 0, 0, 1627, 0, 1643, + 1644, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, + 0, 0, 0, 0, 1645, 0, 0, 0, 0, 0, + 0, 0, 1635, 0, 0, 0, 0, 1650, 0, 0, + 0, 0, 1637, 0, 0, 0, 0, 0, 0, 1638, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1646, 0, 0, 1647, 0, 0, 0, 0, + 0, 0, 0, 1640, 0, 0, 1639, 0, 0, 1648, + 0, 0, 1649, 0, 0, 0, 0, 0, 0, 0, + 1641, 0, 0, 1626, 1650, 1642, 1627, 0, 0, 0, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1643, 1644, + 0, 1635, 0, 0, 0, 0, 0, 2808, 0, 0, + 0, 1637, 0, 1645, 0, 0, 0, 0, 1638, 0, + 0, 0, 0, 0, 0, 1651, 0, 0, 1652, 1653, + 1654, 0, 1655, 1656, 1657, 1658, 1659, 1660, 0, 0, + 0, 0, 0, 0, 0, 1639, 0, 0, 0, 0, + 0, 1646, 0, 1640, 1647, 0, 0, 0, 0, 0, + 0, 1650, 0, 0, 0, 0, 0, 0, 1648, 0, + 1641, 1649, 0, 0, 0, 1642, 0, 0, 0, 0, + 0, 0, 1651, 0, 0, 1652, 1653, 1654, 0, 1655, + 1656, 1657, 1658, 1659, 1660, 0, 0, 0, 1825, 1644, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1645, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1640, 0, 0, 0, 0, 0, 0, 0, + 0, 1646, 0, 0, 1647, 0, 0, 0, 0, 1641, + 0, 0, 0, 0, 1642, 0, 0, 0, 1648, 1651, + 1650, 1649, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, + 1659, 1660, 0, 0, 0, 0, 0, 1643, 1644, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1645, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 1647, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1648, 0, 0, + 1649, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1650, 0, 0, 0, 0, 0, 0, 0, 1651, 0, + 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1650, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1651, 0, + 0, 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 1659, + 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 560, 0, 2112, 0, 0, 0, 1651, 0, 0, + 1652, 1653, 1654, 0, 1655, 1656, 1657, 1658, 2217, 1660, + 118, 119, 120, 121, 122, 123, 124, 125, 561, 126, + 127, 128, 562, 563, 564, 565, 566, 567, 568, 569, + 570, 130, 131, 571, 132, 133, 134, 572, 136, 137, + 138, 573, 574, 575, 576, 577, 578, 144, 145, 146, + 147, 148, 149, 579, 580, 150, 151, 152, 153, 581, + 582, 156, 583, 157, 158, 159, 160, 584, 585, 586, + 587, 588, 164, 165, 166, 167, 168, 589, 170, 171, + 172, 590, 173, 174, 175, 176, 177, 178, 591, 592, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 594, 191, 192, 595, 194, 596, 195, 597, 196, 197, + 198, 199, 200, 201, 598, 599, 202, 203, 204, 205, + 600, 601, 206, 207, 208, 209, 210, 602, 211, 212, + 213, 603, 214, 215, 216, 604, 217, 218, 219, 220, + 605, 222, 223, 224, 225, 226, 227, 606, 607, 229, + 608, 230, 231, 609, 233, 610, 234, 611, 235, 612, + 613, 614, 238, 239, 615, 616, 242, 617, 243, 618, + 619, 620, 246, 247, 621, 248, 249, 250, 251, 252, + 253, 254, 622, 256, 257, 258, 259, 623, 260, 261, + 262, 263, 264, 265, 266, 624, 267, 625, 626, 270, + 271, 272, 273, 274, 627, 628, 629, 630, 631, 278, + 632, 633, 281, 634, 283, 284, 285, 286, 287, 288, + 635, 636, 289, 637, 291, 638, 639, 293, 294, 295, + 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, + 326, 327, 644, 645, 329, 330, 646, 332, 647, 648, + 334, 649, 336, 337, 338, 650, 339, 340, 651, 652, + 341, 342, 343, 653, 654, 344, 345, 655, 656, 348, + 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 659, 660, 661, 662, 362, 363, 663, + 664, 366, 367, 665, 369, 370, 371, 666, 372, 373, + 374, 375, 376, 377, 667, 378, 379, 380, 381, 382, + 668, 384, 385, 386, 387, 669, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 670, + 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 673, 674, 421, 422, 423, 424, 425, 426, 675, 428, + 429, 676, 677, 431, 432, 678, 434, 679, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 680, 448, 681, 682, 683, 450, 451, 684, 452, 685, + 454, 455, 456, 457, 458, 686, 459, 687, 688, 689, + 690, 462, 463, 691, 465, 692, 693, 467, 468, 694, + 470, 471, 472, 473, 474, 695, 696, 475, 476, 477, + 697, 478, 479, 480, 481, 698, 482, 483, 484, 485, + 486, 699, 700, 489, 701, 490, 702, 492, 493, 494, + 495, 496, 497, 498, 703, 704, 499, 705, 706, 500, + 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, + 712, 713, 714, 715, 716, 717, 517, 518, 519, 520, + 560, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 561, 126, 127, + 128, 562, 563, 564, 565, 566, 567, 568, 569, 570, + 130, 131, 571, 132, 133, 134, 572, 136, 137, 138, + 573, 574, 575, 576, 577, 578, 144, 145, 146, 147, + 148, 149, 579, 580, 150, 151, 152, 153, 581, 582, + 156, 583, 157, 158, 159, 160, 584, 585, 586, 587, + 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, + 590, 173, 174, 175, 176, 177, 178, 591, 592, 180, + 181, 182, 183, 184, 185, 593, 187, 188, 189, 594, + 191, 192, 595, 194, 596, 195, 597, 196, 197, 198, + 199, 200, 201, 598, 599, 202, 203, 204, 205, 600, + 601, 206, 207, 208, 209, 210, 602, 211, 212, 213, + 603, 214, 215, 216, 604, 217, 218, 219, 220, 605, + 222, 223, 224, 225, 226, 227, 606, 607, 229, 608, + 230, 231, 609, 233, 610, 234, 611, 235, 612, 613, + 614, 238, 239, 615, 616, 242, 617, 243, 618, 619, + 620, 246, 247, 621, 248, 249, 250, 251, 252, 253, + 254, 622, 256, 257, 258, 259, 623, 260, 261, 262, + 263, 264, 265, 266, 624, 267, 625, 626, 270, 271, + 272, 273, 274, 627, 628, 629, 630, 631, 278, 632, + 633, 281, 634, 283, 284, 285, 286, 287, 288, 635, + 636, 289, 637, 291, 638, 639, 293, 294, 295, 296, + 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, + 327, 644, 645, 329, 330, 646, 332, 647, 648, 334, + 649, 336, 337, 338, 650, 339, 340, 651, 652, 341, + 342, 343, 653, 654, 344, 345, 655, 656, 348, 657, + 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 659, 660, 661, 662, 362, 363, 663, 664, + 366, 367, 665, 369, 370, 371, 666, 372, 373, 374, + 375, 376, 377, 667, 378, 379, 380, 381, 382, 668, + 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 670, 401, + 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 673, + 674, 421, 422, 423, 424, 425, 426, 675, 428, 429, + 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, + 448, 681, 682, 683, 450, 451, 684, 452, 685, 454, + 455, 456, 457, 458, 686, 459, 687, 688, 689, 690, + 462, 463, 691, 465, 692, 693, 467, 468, 694, 470, + 471, 472, 473, 474, 695, 696, 475, 476, 477, 697, + 478, 479, 480, 481, 698, 482, 483, 484, 485, 486, + 699, 700, 489, 701, 490, 702, 492, 493, 494, 495, + 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, + 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, + 713, 714, 715, 716, 717, 517, 518, 519, 520, 560, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 561, 126, 127, 128, + 562, 563, 564, 565, 566, 567, 568, 569, 570, 130, + 131, 571, 132, 133, 134, 572, 136, 137, 138, 573, + 574, 575, 576, 577, 578, 144, 145, 146, 147, 148, + 149, 579, 580, 150, 151, 152, 153, 581, 582, 156, + 583, 157, 158, 159, 160, 584, 585, 586, 587, 588, + 164, 165, 166, 167, 168, 589, 170, 171, 172, 590, + 173, 174, 175, 176, 177, 178, 591, 592, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 594, 191, + 192, 595, 194, 596, 195, 597, 196, 197, 198, 199, + 200, 201, 598, 599, 202, 203, 204, 205, 600, 601, + 206, 207, 208, 209, 210, 602, 211, 212, 213, 603, + 214, 215, 216, 604, 217, 218, 219, 220, 605, 222, + 223, 224, 225, 226, 227, 606, 607, 229, 608, 230, + 231, 609, 233, 610, 234, 611, 235, 612, 613, 614, + 238, 239, 615, 616, 242, 617, 243, 618, 619, 620, + 246, 247, 621, 248, 249, 250, 251, 252, 949, 254, + 622, 256, 257, 258, 259, 623, 260, 261, 262, 263, + 264, 265, 266, 624, 267, 625, 626, 270, 271, 272, + 273, 274, 627, 628, 629, 630, 631, 278, 632, 633, + 281, 634, 283, 284, 285, 286, 287, 288, 635, 636, + 289, 637, 291, 638, 639, 293, 294, 295, 296, 297, + 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 641, 642, 643, 325, 326, 327, + 644, 645, 329, 330, 646, 332, 647, 648, 334, 649, + 336, 337, 338, 650, 339, 340, 651, 652, 341, 342, + 343, 653, 654, 344, 345, 655, 656, 348, 657, 658, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 659, 660, 661, 662, 362, 363, 663, 664, 366, + 367, 665, 369, 370, 371, 666, 372, 373, 374, 375, + 376, 377, 667, 378, 379, 380, 381, 382, 668, 384, + 385, 386, 387, 669, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 670, 401, 402, + 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 673, 674, + 421, 422, 423, 424, 425, 426, 675, 428, 429, 676, + 677, 431, 432, 678, 434, 679, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 680, 448, + 681, 682, 683, 450, 451, 684, 452, 685, 454, 455, + 456, 457, 458, 686, 459, 687, 688, 689, 690, 462, + 463, 691, 465, 692, 693, 467, 468, 694, 470, 471, + 472, 473, 474, 695, 696, 475, 476, 477, 697, 478, + 479, 480, 481, 698, 482, 483, 484, 485, 486, 699, + 700, 489, 701, 490, 702, 492, 493, 494, 495, 496, + 497, 498, 703, 704, 499, 705, 706, 500, 501, 502, + 503, 504, 505, 707, 708, 709, 710, 711, 712, 713, + 714, 715, 716, 717, 517, 518, 519, 520, 560, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 561, 126, 127, 128, 562, + 563, 564, 565, 566, 567, 568, 569, 570, 130, 131, + 571, 132, 133, 134, 572, 136, 137, 138, 573, 574, + 575, 576, 577, 578, 144, 145, 146, 147, 148, 149, + 579, 580, 150, 151, 152, 153, 581, 582, 156, 583, + 157, 158, 159, 160, 584, 585, 586, 587, 588, 164, + 165, 166, 167, 168, 589, 170, 171, 172, 590, 173, + 174, 175, 176, 177, 178, 591, 592, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 594, 191, 192, + 595, 194, 596, 195, 597, 196, 197, 198, 199, 200, + 201, 598, 599, 202, 203, 204, 205, 600, 601, 206, + 207, 208, 209, 210, 602, 211, 212, 213, 603, 214, + 215, 216, 604, 217, 218, 219, 220, 605, 222, 223, + 224, 225, 226, 227, 606, 607, 229, 608, 230, 231, + 609, 233, 610, 234, 611, 235, 612, 613, 614, 238, + 239, 615, 616, 242, 617, 243, 618, 619, 620, 246, + 247, 621, 248, 249, 250, 251, 252, 253, 254, 622, + 256, 257, 258, 259, 623, 260, 261, 262, 263, 264, + 265, 266, 624, 267, 625, 626, 270, 271, 272, 273, + 274, 627, 628, 629, 630, 631, 278, 632, 633, 281, + 634, 283, 284, 285, 286, 287, 288, 635, 636, 289, + 637, 291, 638, 639, 293, 294, 295, 296, 297, 298, + 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 641, 642, 643, 325, 326, 327, 644, + 645, 329, 330, 646, 332, 647, 648, 334, 649, 336, + 337, 338, 650, 339, 340, 651, 652, 341, 342, 343, + 653, 654, 344, 345, 655, 656, 348, 657, 658, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 659, 660, 661, 662, 362, 363, 663, 664, 366, 367, + 665, 369, 370, 371, 666, 372, 373, 374, 375, 376, + 377, 667, 378, 379, 380, 381, 382, 668, 384, 385, + 386, 387, 669, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 670, 401, 402, 671, + 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 673, 674, 421, + 422, 423, 424, 425, 426, 675, 428, 429, 676, 677, + 431, 432, 678, 434, 679, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 680, 448, 681, + 682, 683, 450, 451, 684, 452, 685, 454, 455, 456, + 457, 458, 686, 459, 687, 688, 689, 690, 462, 463, + 691, 465, 692, 693, 467, 468, 694, 470, 471, 472, + 473, 474, 695, 696, 475, 476, 477, 697, 478, 479, + 480, 481, 698, 482, 483, 484, 485, 486, 699, 700, + 489, 701, 490, 702, 492, 493, 494, 495, 496, 497, + 498, 703, 704, 499, 705, 706, 500, 501, 502, 503, + 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, + 715, 716, 717, 517, 518, 519, 520, 560, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 2266, 123, 124, 125, 561, 126, 127, 128, 562, 563, + 564, 565, 566, 567, 568, 569, 570, 130, 131, 571, + 132, 133, 134, 572, 136, 137, 138, 573, 574, 575, + 576, 577, 578, 144, 145, 146, 147, 148, 149, 579, + 580, 150, 151, 152, 153, 581, 582, 156, 583, 157, + 158, 159, 160, 584, 585, 586, 587, 588, 164, 165, + 166, 167, 168, 589, 170, 171, 172, 590, 173, 174, + 175, 176, 177, 178, 591, 592, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 594, 191, 192, 595, + 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, + 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, + 208, 2267, 210, 602, 211, 212, 213, 603, 214, 215, + 216, 604, 217, 218, 219, 220, 605, 222, 223, 224, + 225, 226, 227, 606, 607, 229, 608, 230, 231, 609, + 233, 610, 234, 611, 235, 612, 613, 614, 238, 239, + 615, 616, 242, 617, 243, 618, 619, 620, 246, 247, + 621, 248, 249, 250, 251, 252, 253, 254, 622, 256, + 257, 258, 259, 623, 260, 261, 262, 263, 264, 265, + 266, 624, 267, 625, 626, 270, 271, 272, 273, 274, + 627, 628, 629, 630, 631, 278, 632, 633, 281, 634, + 283, 284, 285, 286, 287, 288, 635, 636, 289, 637, + 291, 638, 639, 293, 294, 295, 296, 297, 298, 299, + 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 641, 642, 643, 325, 326, 327, 644, 645, + 329, 330, 646, 332, 647, 648, 334, 649, 336, 337, + 338, 650, 339, 340, 651, 652, 341, 342, 343, 653, + 654, 344, 345, 655, 656, 348, 657, 658, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 659, + 660, 661, 662, 362, 363, 663, 664, 366, 367, 665, + 369, 370, 371, 666, 372, 373, 374, 375, 376, 377, + 667, 378, 379, 380, 381, 382, 668, 384, 385, 386, + 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 670, 401, 402, 671, 404, + 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 673, 674, 421, 422, + 423, 424, 425, 2268, 675, 428, 429, 676, 677, 431, + 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 680, 448, 681, 682, + 683, 450, 451, 684, 452, 685, 454, 455, 456, 457, + 458, 686, 459, 687, 688, 689, 690, 462, 463, 691, + 465, 692, 693, 467, 468, 694, 470, 471, 472, 473, + 474, 695, 696, 475, 476, 477, 697, 478, 479, 480, + 481, 698, 482, 483, 484, 485, 486, 699, 700, 489, + 701, 490, 702, 492, 493, 494, 495, 496, 497, 498, + 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, + 505, 707, 708, 709, 710, 711, 712, 713, 714, 715, + 716, 717, 517, 518, 519, 520, 973, 0, 820, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 565, 0, 0, 0, 0, 570, 130, 131, 0, 132, + 133, 134, 572, 136, 137, 138, 573, 574, 575, 576, + 577, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 581, 582, 156, 0, 157, 158, + 159, 160, 584, 0, 586, 0, 588, 164, 165, 166, + 167, 168, 589, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 592, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 594, 191, 192, 595, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 605, 222, 223, 224, 225, + 226, 227, 606, 1357, 229, 0, 230, 231, 609, 233, + 0, 234, 0, 235, 612, 0, 614, 238, 239, 615, + 616, 242, 0, 243, 0, 619, 620, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 622, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 625, 626, 270, 271, 272, 273, 274, 627, + 628, 0, 630, 0, 278, 632, 633, 281, 634, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 637, 291, + 638, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 641, 642, 643, 325, 326, 327, 644, 0, 329, + 330, 646, 332, 0, 648, 334, 649, 336, 337, 338, + 0, 339, 340, 1358, 0, 341, 342, 343, 0, 0, + 344, 345, 655, 656, 348, 657, 658, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 663, 664, 366, 367, 665, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 668, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 671, 404, 405, + 406, 672, 408, 409, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 674, 421, 422, 423, + 424, 425, 426, 675, 428, 429, 0, 677, 431, 432, + 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 680, 448, 681, 0, 0, + 450, 451, 0, 452, 685, 454, 455, 456, 457, 458, + 0, 459, 687, 688, 0, 0, 462, 463, 691, 465, + 692, 1359, 467, 468, 694, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 699, 700, 489, 0, + 490, 702, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, + 717, 517, 518, 519, 520, 973, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 3, 4, 0, 565, + 0, 0, 0, 0, 570, 130, 131, 0, 132, 133, + 134, 572, 136, 137, 138, 573, 574, 575, 576, 577, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 151, 152, 153, 581, 582, 156, 0, 157, 158, 159, + 160, 584, 0, 586, 0, 588, 164, 165, 166, 167, + 168, 589, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 592, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 594, 191, 192, 595, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, -540, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, -540, 230, 231, 232, 233, -540, - 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 605, 222, 223, 224, 225, 226, + 227, 606, 0, 229, 0, 230, 231, 609, 233, 0, + 234, 0, 235, 612, 0, 614, 238, 239, 615, 616, + 242, 0, 243, 0, 619, 620, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 622, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - -540, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - -540, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 267, 625, 626, 270, 271, 272, 273, 274, 627, 628, + 0, 630, 0, 278, 632, 633, 281, 634, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 637, 291, 638, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, -540, - 339, 340, 0, 0, 341, 342, 343, 0, -540, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, + 641, 642, 643, 325, 326, 327, 644, 0, 329, 330, + 646, 332, 0, 648, 334, 649, 336, 337, 338, 0, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 345, 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 0, 362, 363, 663, 664, 366, 367, 665, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 379, 380, 381, 382, 668, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 398, 399, 400, 0, 401, 402, 671, 404, 405, 406, + 672, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 674, 421, 422, 423, 424, + 425, 426, 675, 428, 429, 0, 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, -540, + 443, 444, 445, 446, 680, 448, 681, 0, 0, 450, + 451, 0, 452, 685, 454, 455, 456, 457, 458, 0, + 459, 687, 688, 0, 0, 462, 463, 691, 465, 692, + 0, 467, 468, 694, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, + 482, 483, 484, 485, 486, 699, 700, 489, 0, 490, + 702, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 707, + 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, + 517, 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1177, 0, 118, 119, 120, 121, 122, 123, 124, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, - 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, + 0, 0, 0, 129, 130, 131, 0, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, - 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, - 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, + 791, 0, 792, 0, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, + 793, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, - 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 290, 291, 292, 0, + 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, - 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, - 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, + 323, 324, 325, 326, 327, 328, 0, 329, 330, 331, + 332, 0, 795, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, + 346, 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, + 362, 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, + 399, 400, 0, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, + 426, 427, 428, 429, 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, - 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, - 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, + 444, 445, 446, 447, 448, 800, 0, 0, 450, 451, + 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 801, 465, 802, 0, + 467, 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 974, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2495, - 3307, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 3, 4, 0, 565, 0, 0, - 0, 0, 570, 130, 131, 0, 132, 133, 134, 572, - 136, 137, 138, 573, 574, 575, 576, 577, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 581, 582, 156, 0, 157, 158, 159, 160, 584, - 0, 586, 0, 588, 164, 165, 166, 167, 168, 589, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 592, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 594, 191, 192, 595, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 14, 15, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 605, 222, 223, 224, 225, 226, 227, 606, - 0, 229, 0, 230, 231, 609, 233, 0, 234, 0, - 235, 612, 23, 614, 238, 239, 615, 616, 242, 0, - 243, 0, 619, 620, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 622, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 625, - 626, 270, 271, 272, 273, 274, 627, 628, 0, 630, - 0, 278, 632, 633, 281, 634, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 637, 291, 638, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 641, 642, - 643, 325, 326, 327, 644, 0, 329, 330, 646, 332, - 0, 648, 334, 649, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 655, - 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 26, 27, 28, 0, 362, - 363, 663, 664, 366, 367, 665, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 668, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 671, 404, 405, 406, 672, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 33, 674, 421, 422, 423, 424, 425, 426, - 675, 428, 429, 35, 677, 431, 432, 678, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 680, 448, 681, 37, 0, 450, 451, 38, - 452, 685, 454, 455, 456, 457, 458, 0, 459, 687, - 688, 0, 0, 462, 463, 691, 465, 692, 0, 467, - 468, 694, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 40, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 975, 700, 489, 0, 490, 702, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 44, 500, 501, 502, 503, 504, 505, 707, 708, 709, - 710, 711, 712, 713, 714, 715, 716, 717, 517, 518, - 519, 520, 0, 117, 45, 554, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 790, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 14, 15, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 793, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 236, 23, 237, 238, 239, 240, 241, 242, 0, - 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 794, 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, - 0, 795, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 26, 27, 28, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 407, 799, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 33, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 35, 430, 431, 432, 433, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 37, 0, 450, 451, 38, - 452, 453, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 801, 465, 802, 0, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 40, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 804, 488, 489, 0, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 44, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 0, 117, 45, 554, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 805, 0, + 518, 519, 520, 117, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 790, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 791, - 0, 792, 0, 163, 164, 165, 166, 167, 168, 169, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 162, 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 793, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, @@ -7708,236 +9371,186 @@ static const yytype_int16 yytable[] = 260, 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 794, 0, 289, 290, 291, 292, 0, 293, + 287, 288, 0, 0, 289, 290, 291, 292, 0, 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, 0, 329, 330, 331, 332, - 0, 795, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, - 347, 348, 349, 797, 351, 352, 353, 354, 355, 356, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 798, 365, 366, 367, 368, 369, 370, 371, 0, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 403, 404, 405, 406, 407, 799, + 400, 0, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 800, 0, 0, 450, 451, 0, + 445, 446, 447, 448, 449, 0, 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 801, 465, 802, 0, 467, - 468, 803, 470, 471, 472, 473, 474, 0, 0, 475, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 804, 488, 489, 0, 490, 491, 492, + 484, 485, 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 117, 0, 554, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 805, 0, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 129, 130, 131, 0, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 790, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 791, 0, - 792, 0, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 1758, 157, 158, 159, 160, 161, 0, + 0, 1759, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 1760, 173, 174, 175, 176, 177, 178, 0, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 793, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 236, 0, 237, 238, 239, 240, 241, 242, 0, 243, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 1761, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 268, 269, + 252, 1762, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 290, 291, 292, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, 0, - 795, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 796, 341, 342, 343, 0, 0, 344, 345, 346, 347, - 348, 349, 797, 351, 352, 353, 354, 355, 356, 357, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 798, 365, 366, 367, 368, 369, 370, 371, 0, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 1763, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 403, 404, 405, 406, 407, 799, 409, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 430, 431, 432, 433, 434, 0, 435, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 800, 0, 0, 450, 451, 0, 452, - 453, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 801, 465, 802, 0, 467, 468, - 803, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 1764, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 491, 492, 493, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 117, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1018, 0, 0, + 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 129, 130, 131, 0, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 790, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 791, 0, 792, - 0, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 179, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 1758, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 1760, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 793, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 236, - 0, 237, 238, 239, 240, 241, 242, 0, 243, 0, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 1761, 235, 0, + 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 268, 269, 270, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 290, 291, 292, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 2351, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, 0, 795, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 347, 348, - 349, 797, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 798, - 365, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 1763, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 403, 404, 405, 406, 407, 799, 409, 410, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 430, 431, 432, 433, 434, 0, 435, 436, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 447, 448, 800, 0, 0, 450, 451, 0, 452, 453, + 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 801, 465, 802, 0, 467, 468, 803, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 1764, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 491, 492, 493, 494, + 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 46, 0, 0, 118, + 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 129, - 130, 131, 0, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 790, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 791, 0, 792, 0, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 179, 180, + 128, 3, 4, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, + 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, + 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 793, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 236, 0, - 237, 238, 239, 240, 241, 242, 0, 243, 0, 244, + 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 290, 291, 292, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, + 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 530, 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, 0, 329, 330, 331, 332, 0, 795, 334, + 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, + 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 347, 348, 349, - 797, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 798, 365, + 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 430, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 800, 0, 0, 450, 451, 0, 452, 453, 454, + 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, + 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 801, 465, 802, 0, 467, 468, 803, 470, + 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 491, 492, 493, 494, 495, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3396, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 14, 15, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 23, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 26, 27, 28, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 33, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 35, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 37, 0, 450, 451, 38, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 40, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 804, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 44, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 0, 528, - 45, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 894, 126, 127, 128, + 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 555, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, @@ -7951,7 +9564,7 @@ static const yytype_int16 yytable[] = 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 23, 0, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, @@ -7966,127 +9579,27 @@ static const yytype_int16 yytable[] = 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 26, 27, 28, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 556, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 33, 0, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 38, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 895, 461, 0, 0, 896, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 40, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 804, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 44, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 0, 528, - 45, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 23, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 26, 27, 28, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 33, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 38, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 40, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 804, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 44, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 0, 528, - 45, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 994, 0, 0, 118, 119, 120, + 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, @@ -8113,7 +9626,7 @@ static const yytype_int16 yytable[] = 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 337, 338, 0, 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, @@ -8136,7 +9649,7 @@ static const yytype_int16 yytable[] = 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1493, 0, 0, 118, 119, 120, 121, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, @@ -8153,7 +9666,7 @@ static const yytype_int16 yytable[] = 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, + 0, 248, 249, 250, 251, 252, 903, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, @@ -8163,7 +9676,7 @@ static const yytype_int16 yytable[] = 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, + 338, 0, 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, @@ -8186,8 +9699,8 @@ static const yytype_int16 yytable[] = 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2103, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 947, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, @@ -8236,7 +9749,7 @@ static const yytype_int16 yytable[] = 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2250, 0, 0, 118, 119, 120, 121, 122, 123, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, @@ -8249,7 +9762,7 @@ static const yytype_int16 yytable[] = 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 1177, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, @@ -8263,7 +9776,7 @@ static const yytype_int16 yytable[] = 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 339, 340, 0, 796, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, @@ -8284,9 +9797,9 @@ static const yytype_int16 yytable[] = 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2495, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 517, 518, 519, 520, 528, 1967, 0, 0, 0, 0, + 1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, @@ -8335,7 +9848,7 @@ static const yytype_int16 yytable[] = 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, @@ -8351,14 +9864,14 @@ static const yytype_int16 yytable[] = 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 1975, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 294, 1976, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, @@ -8375,17 +9888,17 @@ static const yytype_int16 yytable[] = 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 1977, + 452, 0, 454, 1978, 456, 1979, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 476, 1980, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2847, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, @@ -8434,8 +9947,8 @@ static const yytype_int16 yytable[] = 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3302, 0, 0, + 520, 528, 0, 820, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, @@ -8485,108 +9998,8 @@ static const yytype_int16 yytable[] = 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2210, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 0, - 2973, 1364, 821, 0, 0, 2078, 1060, 0, 0, 0, - 0, 0, 2079, 2080, 0, 3164, 2081, 2082, 2083, 118, - 119, 120, 121, 122, 123, 124, 125, 561, 126, 127, - 128, 562, 563, 564, 2974, 566, 567, 568, 569, 2975, - 130, 131, 571, 132, 133, 134, 2976, 136, 137, 138, - 0, 1506, 2977, 1508, 1509, 578, 144, 145, 146, 147, - 148, 149, 579, 580, 150, 151, 152, 153, 1510, 1511, - 156, 583, 157, 158, 159, 160, 0, 585, 2978, 587, - 2979, 164, 165, 166, 167, 168, 2980, 170, 171, 172, - 590, 173, 174, 175, 176, 177, 178, 591, 2981, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 1516, - 191, 192, 1517, 194, 596, 195, 597, 196, 197, 198, - 199, 200, 201, 598, 599, 202, 203, 204, 205, 600, - 601, 206, 207, 1073, 209, 210, 602, 211, 212, 213, - 603, 214, 215, 216, 604, 217, 218, 219, 220, 0, - 222, 223, 224, 225, 226, 227, 0, 607, 229, 608, - 230, 231, 1518, 233, 610, 234, 611, 235, 2982, 613, - 2983, 238, 239, 2984, 2985, 242, 617, 243, 618, 0, - 0, 246, 247, 621, 248, 249, 250, 251, 252, 253, - 254, 2986, 256, 257, 258, 259, 623, 260, 261, 262, - 263, 264, 265, 266, 624, 267, 2987, 0, 270, 271, - 272, 273, 274, 1524, 1525, 629, 1526, 631, 278, 2988, - 2989, 281, 2990, 283, 284, 285, 286, 287, 288, 635, - 636, 289, 2991, 291, 2992, 639, 293, 294, 295, 296, - 297, 298, 299, 300, 2993, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 1533, 2994, 1535, 325, 326, - 327, 2995, 645, 329, 330, 2996, 332, 647, 0, 334, - 1537, 336, 337, 338, 650, 339, 340, 651, 652, 2997, - 342, 343, 653, 654, 344, 345, 0, 2998, 348, 2999, - 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 659, 660, 661, 662, 362, 363, 0, 3000, - 366, 367, 0, 369, 370, 371, 666, 372, 373, 374, - 375, 376, 377, 667, 378, 379, 380, 381, 382, 1541, - 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 670, 401, - 402, 3001, 404, 405, 406, 1543, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 673, - 3002, 421, 422, 423, 424, 425, 426, 3003, 428, 429, - 676, 3004, 431, 432, 1547, 434, 679, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 3005, - 448, 0, 682, 683, 450, 451, 684, 452, 3006, 454, - 455, 456, 457, 458, 686, 459, 1550, 1551, 689, 690, - 462, 463, 0, 465, 0, 693, 467, 468, 3007, 470, - 471, 472, 473, 474, 3008, 696, 475, 476, 477, 697, - 478, 479, 480, 481, 698, 482, 483, 484, 485, 486, - 0, 1554, 489, 701, 490, 3009, 492, 493, 494, 495, - 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, - 502, 503, 504, 505, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 517, 518, 519, 520, 0, - 528, 0, 2084, 2085, 2086, 2078, 3010, 3011, 2089, 2090, - 2091, 2092, 2079, 2080, 0, 0, 2081, 2082, 2083, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, + 119, 120, 121, 122, 123, 124, 125, 826, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, @@ -8601,13 +10014,13 @@ static const yytype_int16 yytable[] = 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, + 0, 238, 239, 529, 0, 827, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 0, 289, 0, 291, 0, 0, 293, 294, 828, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, @@ -8622,238 +10035,175 @@ static const yytype_int16 yytable[] = 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 421, 422, 423, 424, 829, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 455, 456, 457, 458, 0, 459, 830, 461, 0, 0, + 831, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, + 487, 488, 832, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 0, - 0, 0, 2084, 2085, 2086, 0, 2087, 2088, 2089, 2090, - 2091, 2092, 1639, 0, 0, 1640, 0, 0, 0, 1641, - 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1648, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1650, 1639, 0, 0, 1640, 0, 0, 1651, 1641, 1642, - 1643, 1644, 1645, 1646, 1647, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1648, - 0, 0, 0, 0, 1652, 0, 0, 0, 0, 1650, - 1639, 0, 0, 1640, 0, 0, 1651, 1641, 1642, 1643, - 1644, 1645, 1646, 1647, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1648, 0, - 0, 0, 0, 1652, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 0, 1651, 0, 0, 1639, 0, - 0, 1640, 0, 0, 0, 1641, 1642, 1643, 1644, 1645, - 1646, 1647, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1652, 0, 0, 0, 1648, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1650, 1639, 0, 0, - 1640, 1653, 0, 1651, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 0, 0, 0, 0, 0, 0, 0, 1654, 0, - 0, 0, 0, 1655, 0, 1648, 0, 0, 0, 0, - 1652, 0, 0, 0, 0, 1650, 0, 0, 0, 0, - 1653, 0, 1651, 0, 0, 0, 1656, 1657, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1654, 0, 0, - 0, 1658, 1655, 0, 0, 0, 0, 0, 0, 1652, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1653, - 0, 0, 0, 0, 0, 1656, 1657, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1654, 0, 0, 1659, - 1658, 1655, 1660, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1661, 0, 0, 1662, - 0, 0, 0, 0, 1656, 1657, 0, 1653, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1659, 1658, - 0, 1660, 0, 0, 1654, 0, 0, 0, 0, 1655, - 0, 0, 0, 0, 0, 1661, 0, 0, 1662, 0, - 0, 0, 0, 0, 0, 0, 1653, 0, 0, 0, - 0, 0, 1656, 1657, 0, 0, 0, 1659, 0, 0, - 1660, 0, 0, 1654, 0, 0, 0, 1658, 1655, 0, - 0, 0, 0, 0, 1661, 0, 0, 1662, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1656, 1657, 0, 0, 0, 0, 0, 1663, 0, - 0, 0, 0, 0, 0, 1659, 1658, 0, 1660, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1661, 0, 0, 1662, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1663, 0, 0, - 0, 0, 0, 0, 1659, 0, 0, 1660, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1661, 0, 0, 1662, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1664, 0, 0, 1665, - 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, - 0, 0, 0, 2919, 1663, 0, 0, 0, 0, 0, - 1639, 0, 0, 1640, 0, 0, 0, 1641, 1642, 1643, - 1644, 1645, 1646, 1647, 0, 1664, 0, 0, 1665, 1666, - 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 1648, 0, - 0, 0, 3156, 1663, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 0, 1651, 0, 0, 0, 0, - 0, 0, 0, 0, 1664, 0, 0, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, 0, - 0, 3163, 1652, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1639, 0, 0, - 1640, 0, 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 0, 1664, 0, 0, 1665, 1666, 1667, 0, 1668, - 1669, 1670, 1671, 1672, 1673, 1648, 0, 0, 0, 3325, - 0, 0, 0, 0, 0, 1650, 1639, 0, 0, 1640, - 0, 0, 1651, 1641, 1642, 1643, 1644, 1645, 1646, 1647, - 0, 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, - 1670, 1671, 1672, 1673, 1648, 0, 0, 0, 3347, 1652, - 0, 0, 0, 0, 1650, 1639, 0, 0, 1640, 1653, - 0, 1651, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, - 0, 0, 0, 0, 0, 0, 1654, 0, 0, 0, - 0, 1655, 0, 1648, 0, 0, 0, 0, 1652, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 0, - 1651, 0, 0, 0, 1656, 1657, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1658, - 0, 0, 0, 0, 0, 0, 0, 1652, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1639, 0, 0, 1640, 1653, 0, 0, 1641, - 1642, 1643, 1644, 1645, 1646, 1647, 0, 1659, 0, 0, - 1660, 0, 0, 1654, 0, 0, 0, 0, 1655, 0, - 1648, 0, 0, 0, 1661, 0, 0, 1662, 0, 0, - 1650, 0, 0, 0, 0, 1653, 0, 1651, 0, 0, - 0, 1656, 1657, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1654, 0, 0, 0, 1658, 1655, 0, 0, - 0, 0, 0, 0, 1652, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1653, 0, 0, 0, 0, 0, - 1656, 1657, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1654, 0, 0, 1659, 1658, 1655, 1660, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1661, 0, 0, 1662, 0, 0, 0, 0, 1656, - 1657, 0, 0, 0, 0, 0, 1663, 0, 0, 0, - 0, 0, 0, 1659, 1658, 0, 1660, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1661, 0, 0, 1662, 0, 0, 0, 0, 0, 0, - 0, 1653, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1659, 0, 0, 1660, 0, 0, 1654, 0, - 0, 0, 0, 1655, 0, 0, 0, 0, 0, 1661, - 0, 0, 1662, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1656, 1657, 0, 0, - 0, 0, 0, 1663, 0, 0, 0, 0, 0, 0, - 0, 1658, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1664, 0, 0, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, 0, - 0, 3447, 1663, 0, 0, 0, 0, 0, 0, 1659, - 0, 0, 1660, 0, 0, 0, 0, 0, 0, 0, - 1639, 0, 0, 1640, 0, 0, 1661, 1641, 1642, 1662, - 0, 1645, 1646, 1647, 0, 0, 0, 0, 0, 1639, - 0, 1663, 1640, 0, 0, 0, 1641, 1642, 1643, 1644, - 1645, 1646, 1647, 0, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 0, 1651, 0, 1648, 0, 0, - 0, 1664, 0, 0, 1665, 1666, 1667, 1650, 1668, 1669, - 1670, 1671, 1672, 1673, 1651, 0, 0, 0, 3503, 0, - 0, 0, 1652, 0, 0, 0, 1639, 0, 0, 1640, - 0, 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, - 1664, 1652, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, - 1671, 1672, 1673, 0, 1648, 0, 0, 3525, 1663, 0, - 0, 0, 0, 0, 1650, 0, 0, 0, 0, 0, - 0, 1651, 0, 0, 0, 0, 0, 0, 0, 1664, - 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, - 1672, 1673, 0, 0, 1827, 0, 0, 0, 1652, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1653, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1654, 0, 1653, 0, - 0, 1655, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1654, 0, 0, 0, 0, - 1655, 0, 0, 0, -2102, -2102, 1664, 0, 0, 1665, - 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 1658, - 0, 2873, 0, 1656, 1657, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1653, 0, 0, 1658, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1654, 0, 0, 0, 0, 1655, 0, 0, - -2102, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1661, 0, 1659, 0, 0, 1660, - 1656, 1657, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1661, 0, 1658, 1662, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1659, 0, 0, 1660, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1661, 0, 0, 1662, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1663, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1664, 0, 0, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, 0, - 0, 0, 0, 1664, 0, 0, 1665, 1666, 1667, 0, - 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, 3315, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, - 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, - 1671, 1672, 1673, 0, 0, 3487, 118, 119, 120, 121, - 122, 123, 124, 125, 561, 126, 127, 128, 562, 563, - 564, 565, 566, 567, 568, 569, 570, 130, 131, 571, - 132, 133, 134, 572, 136, 137, 138, 573, 574, 575, - 576, 577, 578, 144, 145, 146, 147, 148, 149, 579, - 580, 150, 151, 152, 153, 581, 582, 156, 583, 157, - 158, 159, 160, 584, 585, 586, 587, 588, 164, 165, - 166, 167, 168, 589, 170, 171, 172, 590, 173, 174, - 175, 176, 177, 178, 591, 592, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 594, 191, 192, 595, - 194, 596, 195, 597, 196, 197, 198, 199, 200, 201, - 598, 599, 202, 203, 204, 205, 600, 601, 206, 207, - 208, 209, 210, 602, 211, 212, 213, 603, 214, 215, - 216, 604, 217, 218, 219, 220, 605, 222, 223, 224, - 225, 226, 227, 606, 607, 229, 608, 230, 231, 609, - 233, 610, 234, 611, 235, 612, 613, 614, 238, 239, - 615, 616, 242, 617, 243, 618, 619, 620, 246, 247, - 621, 248, 249, 250, 251, 252, 253, 254, 622, 256, - 257, 258, 259, 623, 260, 261, 262, 263, 264, 265, - 266, 624, 267, 625, 626, 270, 271, 272, 273, 274, - 627, 628, 629, 630, 631, 278, 632, 633, 281, 634, - 283, 284, 285, 286, 287, 288, 635, 636, 289, 637, - 291, 638, 639, 293, 294, 295, 296, 297, 298, 299, - 300, 640, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 641, 642, 643, 325, 326, 327, 644, 645, - 329, 330, 646, 332, 647, 648, 334, 649, 336, 337, - 338, 650, 339, 340, 651, 652, 341, 342, 343, 653, - 654, 344, 345, 655, 656, 348, 657, 658, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 659, - 660, 661, 662, 362, 363, 663, 664, 366, 367, 665, - 369, 370, 371, 666, 372, 373, 374, 375, 376, 377, - 667, 378, 379, 380, 381, 382, 668, 384, 385, 386, - 387, 669, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 670, 401, 402, 671, 404, - 405, 406, 672, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 673, 674, 421, 422, - 423, 424, 425, 426, 675, 428, 429, 676, 677, 431, - 432, 678, 434, 679, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 680, 448, 681, 682, - 683, 450, 451, 684, 452, 685, 454, 455, 456, 457, - 458, 686, 459, 687, 688, 689, 690, 462, 463, 691, - 465, 692, 693, 467, 468, 694, 470, 471, 472, 473, - 474, 695, 696, 475, 476, 477, 697, 478, 479, 480, - 481, 698, 482, 483, 484, 485, 486, 699, 700, 489, - 701, 490, 702, 492, 493, 494, 495, 496, 497, 498, - 703, 704, 499, 705, 706, 500, 501, 502, 503, 504, - 505, 707, 708, 709, 710, 711, 712, 713, 714, 715, - 716, 717, 517, 518, 519, 520, 528, 0, 0, 0, - 0, 0, 0, 0, 0, 2115, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, - 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, + 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, + 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, + 385, 865, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, + 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, + 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, + 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 898, 254, 0, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, + 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, + 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, + 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 901, 254, 0, 256, + 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, + 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, @@ -8865,7 +10215,7 @@ static const yytype_int16 yytable[] = 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, + 248, 249, 250, 251, 252, 905, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, @@ -8896,8 +10246,8 @@ static const yytype_int16 yytable[] = 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, - 0, 0, 0, 0, 2766, 0, 0, 0, 0, 0, + 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, @@ -8915,7 +10265,7 @@ static const yytype_int16 yytable[] = 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, + 249, 250, 251, 252, 935, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, @@ -8946,705 +10296,465 @@ static const yytype_int16 yytable[] = 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 974, 1364, 821, 0, 0, 0, - 1060, 0, 0, 2769, 0, 0, 0, 0, 0, 0, + 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 0, 126, 127, 128, 0, 0, 0, 565, 0, - 0, 0, 0, 570, 130, 131, 0, 132, 133, 134, - 572, 136, 137, 138, 573, 574, 575, 576, 577, 0, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 581, 582, 156, 0, 157, 158, 159, 160, - 584, 0, 586, 0, 588, 164, 165, 166, 167, 168, - 589, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 592, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 594, 191, 192, 595, 194, 0, 195, + 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, + 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, + 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 605, 222, 223, 224, 225, 226, 227, - 606, 1365, 229, 0, 230, 231, 609, 233, 0, 234, - 0, 235, 612, 0, 614, 238, 239, 615, 616, 242, - 0, 243, 0, 619, 620, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 622, 256, 257, 258, 259, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, + 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, + 250, 251, 252, 963, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 625, 626, 270, 271, 272, 273, 274, 627, 628, 0, - 630, 0, 278, 632, 633, 281, 634, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 637, 291, 638, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, + 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, + 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, - 642, 643, 325, 326, 327, 644, 0, 329, 330, 646, - 332, 0, 648, 334, 649, 336, 337, 338, 0, 339, - 340, 1366, 0, 341, 342, 343, 0, 0, 344, 345, - 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, + 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 663, 664, 366, 367, 665, 369, 370, 371, + 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 668, 384, 385, 386, 387, 0, 388, + 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 671, 404, 405, 406, 672, + 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 674, 421, 422, 423, 424, 425, - 426, 675, 428, 429, 0, 677, 431, 432, 678, 434, + 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 680, 448, 681, 0, 0, 450, 451, - 0, 452, 685, 454, 455, 456, 457, 458, 0, 459, - 687, 688, 0, 0, 462, 463, 691, 465, 692, 1367, - 467, 468, 694, 470, 471, 472, 473, 474, 0, 0, + 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, + 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, + 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 699, 700, 489, 0, 490, 702, + 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 707, 708, - 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, - 518, 519, 520, 0, 0, 1639, 0, 0, 1640, 0, - 1368, 1369, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1648, 0, 0, 0, 0, 2216, 0, - 0, 0, 0, 1650, 1639, 0, 0, 1640, 0, 0, - 1651, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1648, 0, 0, 0, 0, 1652, 0, 0, - 0, 0, 1650, 1639, 0, 0, 1640, 0, 0, 1651, - 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1648, 0, 0, 0, 0, 1652, 0, 0, 0, - 0, 1650, 0, 2217, 0, 0, 0, 0, 1651, 0, - 1639, 0, 0, 1640, 0, 0, 0, 1641, 1642, 1643, - 1644, 1645, 1646, 1647, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1652, 0, 0, 1648, 0, - 0, 0, 1929, 0, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 1653, 1651, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1654, 0, 0, 0, 0, 1655, 0, 0, 0, - 0, 0, 1652, 1965, 0, 0, 0, 0, 1966, 0, - 0, 0, 0, 1653, 0, 0, 0, 0, 0, 1656, - 1657, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1654, 0, 0, 0, 1658, 1655, 0, 0, 0, 0, - 0, 3593, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1653, 0, 0, 0, 0, 0, 1656, 1657, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1654, - 0, 0, 1659, 1658, 1655, 1660, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1661, - 0, 0, 1662, 0, 0, 0, 0, 1656, 1657, 1653, + 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, + 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, + 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1659, 1658, 0, 1660, 0, 1654, 0, 0, 0, - 0, 1655, 0, 0, 0, 0, 0, 0, 1661, 0, - 0, 1662, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1656, 1657, 0, 0, 0, 0, - 1659, 0, 0, 1660, 0, 0, 0, 0, 0, 1658, - 0, 0, 0, 0, 0, 0, 0, 1661, 0, 0, - 1662, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, + 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, + 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, + 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, + 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, + 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, + 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, + 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, + 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, + 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, + 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, + 251, 252, 966, 254, 0, 256, 257, 258, 259, 0, + 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, + 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, + 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, + 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, + 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, + 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, + 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, + 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, + 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, + 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, + 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, + 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, + 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, + 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, + 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, + 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, + 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, + 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, + 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, + 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, + 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1663, 0, 0, 0, 0, 0, 1659, 0, 3594, - 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1661, 0, 0, 1662, 0, 0, - 0, 0, 0, 0, 0, 1639, 0, 0, 1640, 0, - 1663, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1648, 2220, 0, 0, 0, 0, 0, - 0, 0, 0, 1650, 0, 0, 0, 0, 0, 1663, - 1651, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1652, 0, 1664, - 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, - 1672, 1673, 0, 0, 0, 0, 1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1664, 0, - 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1664, 0, 0, - 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, - 0, 0, 0, 0, 1653, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1639, 1654, 0, 1640, 0, 0, 1655, 1641, 1642, 1643, - 1644, 1645, 1646, 1647, 1664, 0, 0, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 1648, 1656, - 1657, 0, 1971, 0, 0, 0, 0, 0, 1650, 0, - 0, 0, 0, 0, 1658, 1651, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1639, 0, 0, 1640, - 0, 0, 1652, 1641, 1642, 1643, 1644, 1645, 1646, 1647, - 0, 0, 1659, 0, 0, 1660, 0, 0, 0, 0, - 0, 0, 0, 0, 1648, 0, 0, 0, 0, 1661, - 0, 0, 1662, 0, 1650, 0, 0, 0, 0, 0, - 0, 1651, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1936, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1652, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1639, 0, 0, 1640, 0, - 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1653, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1648, 0, 0, 1654, 1978, 0, 0, - 0, 1655, 0, 1650, 0, 0, 0, 0, 0, 0, - 1651, 1663, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1656, 1657, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1652, 0, 1658, - 1976, 0, 0, 0, 0, 1653, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1654, 0, 0, 0, 0, 1655, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1659, 0, 0, - 1660, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1656, 1657, 0, 0, 1661, 0, 0, 1662, 0, 0, - 0, 0, 0, 0, 0, 1658, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1664, - 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, - 1672, 1673, 0, 0, 1653, 0, 0, 0, 0, 0, - 0, 0, 0, 1659, 0, 0, 1660, 0, 0, 0, - 0, 1654, 0, 0, 0, 0, 1655, 0, 0, 0, - 1661, 0, 0, 1662, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1639, 0, 0, 1640, 0, 1656, - 1657, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 0, 0, - 0, 0, 0, 0, 1658, 0, 1663, 0, 0, 0, - 0, 0, 1648, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1650, 0, 0, 0, 0, 0, 0, 1651, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1639, 1659, 0, 1640, 1660, 0, 0, 1641, 1642, - 1643, 1644, 1645, 1646, 1647, 0, 1652, 0, 0, 1661, - 0, 0, 1662, 0, 0, 0, 0, 0, 0, 1648, - 0, 0, 1663, 0, 0, 0, 0, 0, 0, 1650, - 0, 0, 0, 0, 0, 0, 1651, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1652, 1664, 0, 0, 1665, 1666, 1667, - 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 1639, 0, - 0, 1640, 0, 0, 0, 1641, 1642, 1643, 1644, 1645, - 1646, 1647, 0, 2108, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1653, 0, 0, 1648, 0, 0, 0, - 2846, 1663, 0, 0, 0, 0, 1650, 0, 0, 0, - 1654, 0, 0, 1651, 0, 1655, 0, 0, 0, 0, - 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, - 1671, 1672, 1673, 0, 0, 0, 0, 0, 1656, 1657, - 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1653, 0, 0, 1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1654, 0, 0, - 0, 0, 1655, 0, 0, 0, 0, 1639, 0, 0, - 1640, 0, 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 1659, 0, 0, 1660, 1656, 1657, 0, 0, 0, - 0, 0, 0, 0, 0, 1648, 0, 0, 1661, 1664, - 1658, 1662, 1665, 1666, 1667, 1650, 1668, 1669, 1670, 1671, - 1672, 1673, 1651, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1653, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1659, 1652, - 0, 1660, 0, 0, 1654, 0, 0, 0, 0, 1655, - 0, 0, 0, 0, 0, 1661, 0, 0, 1662, 0, - 0, 0, 0, 0, 0, 0, 0, 1639, 0, 0, - 1640, 0, 1656, 1657, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 0, 0, 0, 0, 0, 0, 1658, 0, 0, - 0, 0, 0, 0, 0, 1648, 0, 0, 0, 0, - 1663, 0, 0, 0, 0, 1650, 0, 0, 0, 0, - 0, 0, 1651, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1659, 0, 0, 1660, 0, - 0, 0, 0, 0, 0, 0, 1653, 0, 0, 1652, - 0, 0, 1661, 0, 0, 1662, 0, 0, 0, 0, - 0, 0, 0, 1654, 0, 0, 1639, 1663, 1655, 1640, - 0, 0, 0, 1641, 1642, 1643, 1644, 1645, 1646, 1647, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1656, 1657, 0, 1648, 0, 0, 0, 0, 0, - 2830, 0, 0, 0, 1650, 0, 1658, 0, 0, 0, - 0, 1651, 0, 0, 0, 0, 0, 0, 1664, 0, - 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, 1671, 1672, - 1673, 0, 0, 0, 0, 0, 0, 0, 1652, 0, - 0, 0, 0, 0, 1659, 0, 1653, 1660, 0, 0, - 0, 0, 0, 0, 1663, 0, 0, 0, 0, 0, - 0, 1661, 0, 1654, 1662, 0, 0, 0, 1655, 0, - 0, 0, 0, 0, 0, 1664, 0, 0, 1665, 1666, - 1667, 0, 1668, 1669, 1670, 1671, 1672, 1673, 0, 0, - 0, 1840, 1657, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1658, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1653, 0, 0, 0, 0, - 0, 0, 0, 0, 1659, 0, 0, 1660, 0, 0, - 0, 0, 1654, 0, 0, 0, 0, 1655, 0, 0, - 0, 1661, 1664, 1663, 1662, 1665, 1666, 1667, 0, 1668, - 1669, 1670, 1671, 1672, 1673, 0, 0, 0, 0, 0, - 1656, 1657, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1658, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1659, 0, 0, 1660, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1661, 0, 0, 1662, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1663, 0, 0, 0, 0, 0, 0, - 0, 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, - 1670, 1671, 1672, 1673, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1663, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, - 1670, 1671, 1672, 1673, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 560, 0, 2132, 0, 0, 0, - 1664, 0, 0, 1665, 1666, 1667, 0, 1668, 1669, 1670, - 1671, 2237, 1673, 118, 119, 120, 121, 122, 123, 124, - 125, 561, 126, 127, 128, 562, 563, 564, 565, 566, - 567, 568, 569, 570, 130, 131, 571, 132, 133, 134, - 572, 136, 137, 138, 573, 574, 575, 576, 577, 578, - 144, 145, 146, 147, 148, 149, 579, 580, 150, 151, - 152, 153, 581, 582, 156, 583, 157, 158, 159, 160, - 584, 585, 586, 587, 588, 164, 165, 166, 167, 168, - 589, 170, 171, 172, 590, 173, 174, 175, 176, 177, - 178, 591, 592, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 594, 191, 192, 595, 194, 596, 195, - 597, 196, 197, 198, 199, 200, 201, 598, 599, 202, - 203, 204, 205, 600, 601, 206, 207, 208, 209, 210, - 602, 211, 212, 213, 603, 214, 215, 216, 604, 217, - 218, 219, 220, 605, 222, 223, 224, 225, 226, 227, - 606, 607, 229, 608, 230, 231, 609, 233, 610, 234, - 611, 235, 612, 613, 614, 238, 239, 615, 616, 242, - 617, 243, 618, 619, 620, 246, 247, 621, 248, 249, - 250, 251, 252, 253, 254, 622, 256, 257, 258, 259, - 623, 260, 261, 262, 263, 264, 265, 266, 624, 267, - 625, 626, 270, 271, 272, 273, 274, 627, 628, 629, - 630, 631, 278, 632, 633, 281, 634, 283, 284, 285, - 286, 287, 288, 635, 636, 289, 637, 291, 638, 639, - 293, 294, 295, 296, 297, 298, 299, 300, 640, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 641, - 642, 643, 325, 326, 327, 644, 645, 329, 330, 646, - 332, 647, 648, 334, 649, 336, 337, 338, 650, 339, - 340, 651, 652, 341, 342, 343, 653, 654, 344, 345, - 655, 656, 348, 657, 658, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 659, 660, 661, 662, - 362, 363, 663, 664, 366, 367, 665, 369, 370, 371, - 666, 372, 373, 374, 375, 376, 377, 667, 378, 379, - 380, 381, 382, 668, 384, 385, 386, 387, 669, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 670, 401, 402, 671, 404, 405, 406, 672, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 673, 674, 421, 422, 423, 424, 425, - 426, 675, 428, 429, 676, 677, 431, 432, 678, 434, - 679, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 680, 448, 681, 682, 683, 450, 451, - 684, 452, 685, 454, 455, 456, 457, 458, 686, 459, - 687, 688, 689, 690, 462, 463, 691, 465, 692, 693, - 467, 468, 694, 470, 471, 472, 473, 474, 695, 696, - 475, 476, 477, 697, 478, 479, 480, 481, 698, 482, - 483, 484, 485, 486, 699, 700, 489, 701, 490, 702, - 492, 493, 494, 495, 496, 497, 498, 703, 704, 499, - 705, 706, 500, 501, 502, 503, 504, 505, 707, 708, - 709, 710, 711, 712, 713, 714, 715, 716, 717, 517, - 518, 519, 520, 560, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 561, 126, 127, 128, 562, 563, 564, 565, 566, 567, - 568, 569, 570, 130, 131, 571, 132, 133, 134, 572, - 136, 137, 138, 573, 574, 575, 576, 577, 578, 144, - 145, 146, 147, 148, 149, 579, 580, 150, 151, 152, - 153, 581, 582, 156, 583, 157, 158, 159, 160, 584, - 585, 586, 587, 588, 164, 165, 166, 167, 168, 589, - 170, 171, 172, 590, 173, 174, 175, 176, 177, 178, - 591, 592, 180, 181, 182, 183, 184, 185, 593, 187, - 188, 189, 594, 191, 192, 595, 194, 596, 195, 597, - 196, 197, 198, 199, 200, 201, 598, 599, 202, 203, - 204, 205, 600, 601, 206, 207, 208, 209, 210, 602, - 211, 212, 213, 603, 214, 215, 216, 604, 217, 218, - 219, 220, 605, 222, 223, 224, 225, 226, 227, 606, - 607, 229, 608, 230, 231, 609, 233, 610, 234, 611, - 235, 612, 613, 614, 238, 239, 615, 616, 242, 617, - 243, 618, 619, 620, 246, 247, 621, 248, 249, 250, - 251, 252, 253, 254, 622, 256, 257, 258, 259, 623, - 260, 261, 262, 263, 264, 265, 266, 624, 267, 625, - 626, 270, 271, 272, 273, 274, 627, 628, 629, 630, - 631, 278, 632, 633, 281, 634, 283, 284, 285, 286, - 287, 288, 635, 636, 289, 637, 291, 638, 639, 293, - 294, 295, 296, 297, 298, 299, 300, 640, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 641, 642, - 643, 325, 326, 327, 644, 645, 329, 330, 646, 332, - 647, 648, 334, 649, 336, 337, 338, 650, 339, 340, - 651, 652, 341, 342, 343, 653, 654, 344, 345, 655, - 656, 348, 657, 658, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 659, 660, 661, 662, 362, - 363, 663, 664, 366, 367, 665, 369, 370, 371, 666, - 372, 373, 374, 375, 376, 377, 667, 378, 379, 380, - 381, 382, 668, 384, 385, 386, 387, 669, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 670, 401, 402, 671, 404, 405, 406, 672, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 673, 674, 421, 422, 423, 424, 425, 426, - 675, 428, 429, 676, 677, 431, 432, 678, 434, 679, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 680, 448, 681, 682, 683, 450, 451, 684, - 452, 685, 454, 455, 456, 457, 458, 686, 459, 687, - 688, 689, 690, 462, 463, 691, 465, 692, 693, 467, - 468, 694, 470, 471, 472, 473, 474, 695, 696, 475, - 476, 477, 697, 478, 479, 480, 481, 698, 482, 483, - 484, 485, 486, 699, 700, 489, 701, 490, 702, 492, - 493, 494, 495, 496, 497, 498, 703, 704, 499, 705, - 706, 500, 501, 502, 503, 504, 505, 707, 708, 709, - 710, 711, 712, 713, 714, 715, 716, 717, 517, 518, - 519, 520, 560, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 561, - 126, 127, 128, 562, 563, 564, 565, 566, 567, 568, - 569, 570, 130, 131, 571, 132, 133, 134, 572, 136, - 137, 138, 573, 574, 575, 576, 577, 578, 144, 145, - 146, 147, 148, 149, 579, 580, 150, 151, 152, 153, - 581, 582, 156, 583, 157, 158, 159, 160, 584, 585, - 586, 587, 588, 164, 165, 166, 167, 168, 589, 170, - 171, 172, 590, 173, 174, 175, 176, 177, 178, 591, - 592, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 594, 191, 192, 595, 194, 596, 195, 597, 196, - 197, 198, 199, 200, 201, 598, 599, 202, 203, 204, - 205, 600, 601, 206, 207, 208, 209, 210, 602, 211, - 212, 213, 603, 214, 215, 216, 604, 217, 218, 219, - 220, 605, 222, 223, 224, 225, 226, 227, 606, 607, - 229, 608, 230, 231, 609, 233, 610, 234, 611, 235, - 612, 613, 614, 238, 239, 615, 616, 242, 617, 243, - 618, 619, 620, 246, 247, 621, 248, 249, 250, 251, - 252, 950, 254, 622, 256, 257, 258, 259, 623, 260, - 261, 262, 263, 264, 265, 266, 624, 267, 625, 626, - 270, 271, 272, 273, 274, 627, 628, 629, 630, 631, - 278, 632, 633, 281, 634, 283, 284, 285, 286, 287, - 288, 635, 636, 289, 637, 291, 638, 639, 293, 294, - 295, 296, 297, 298, 299, 300, 640, 302, 303, 304, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, + 126, 127, 128, 0, 0, 0, 0, 0, 0, 1008, + 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, + 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, + 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, + 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, + 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, + 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, + 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, + 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, + 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, + 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, + 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, + 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, + 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, + 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, + 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, + 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, + 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 641, 642, 643, - 325, 326, 327, 644, 645, 329, 330, 646, 332, 647, - 648, 334, 649, 336, 337, 338, 650, 339, 340, 651, - 652, 341, 342, 343, 653, 654, 344, 345, 655, 656, - 348, 657, 658, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 659, 660, 661, 662, 362, 363, - 663, 664, 366, 367, 665, 369, 370, 371, 666, 372, - 373, 374, 375, 376, 377, 667, 378, 379, 380, 381, - 382, 668, 384, 385, 386, 387, 669, 388, 389, 390, + 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, + 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, + 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, + 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, + 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, + 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 670, 401, 402, 671, 404, 405, 406, 672, 408, 409, + 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 673, 674, 421, 422, 423, 424, 425, 426, 675, - 428, 429, 676, 677, 431, 432, 678, 434, 679, 435, + 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 680, 448, 681, 682, 683, 450, 451, 684, 452, - 685, 454, 455, 456, 457, 458, 686, 459, 687, 688, - 689, 690, 462, 463, 691, 465, 692, 693, 467, 468, - 694, 470, 471, 472, 473, 474, 695, 696, 475, 476, - 477, 697, 478, 479, 480, 481, 698, 482, 483, 484, - 485, 486, 699, 700, 489, 701, 490, 702, 492, 493, - 494, 495, 496, 497, 498, 703, 704, 499, 705, 706, - 500, 501, 502, 503, 504, 505, 707, 708, 709, 710, - 711, 712, 713, 714, 715, 716, 717, 517, 518, 519, - 520, 560, 0, 0, 0, 0, 0, 0, 0, 0, + 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, + 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, + 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, + 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, + 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, + 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, + 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 561, 126, - 127, 128, 562, 563, 564, 565, 566, 567, 568, 569, - 570, 130, 131, 571, 132, 133, 134, 572, 136, 137, - 138, 573, 574, 575, 576, 577, 578, 144, 145, 146, - 147, 148, 149, 579, 580, 150, 151, 152, 153, 581, - 582, 156, 583, 157, 158, 159, 160, 584, 585, 586, - 587, 588, 164, 165, 166, 167, 168, 589, 170, 171, - 172, 590, 173, 174, 175, 176, 177, 178, 591, 592, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 0, 0, 0, 1031, 0, + 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, + 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, + 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, + 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 594, 191, 192, 595, 194, 596, 195, 597, 196, 197, - 198, 199, 200, 201, 598, 599, 202, 203, 204, 205, - 600, 601, 206, 207, 208, 209, 210, 602, 211, 212, - 213, 603, 214, 215, 216, 604, 217, 218, 219, 220, - 605, 222, 223, 224, 225, 226, 227, 606, 607, 229, - 608, 230, 231, 609, 233, 610, 234, 611, 235, 612, - 613, 614, 238, 239, 615, 616, 242, 617, 243, 618, - 619, 620, 246, 247, 621, 248, 249, 250, 251, 252, - 253, 254, 622, 256, 257, 258, 259, 623, 260, 261, - 262, 263, 264, 265, 266, 624, 267, 625, 626, 270, - 271, 272, 273, 274, 627, 628, 629, 630, 631, 278, - 632, 633, 281, 634, 283, 284, 285, 286, 287, 288, - 635, 636, 289, 637, 291, 638, 639, 293, 294, 295, - 296, 297, 298, 299, 300, 640, 302, 303, 304, 305, + 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, + 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, + 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, + 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, + 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, + 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, + 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 641, 642, 643, 325, - 326, 327, 644, 645, 329, 330, 646, 332, 647, 648, - 334, 649, 336, 337, 338, 650, 339, 340, 651, 652, - 341, 342, 343, 653, 654, 344, 345, 655, 656, 348, - 657, 658, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 659, 660, 661, 662, 362, 363, 663, - 664, 366, 367, 665, 369, 370, 371, 666, 372, 373, - 374, 375, 376, 377, 667, 378, 379, 380, 381, 382, - 668, 384, 385, 386, 387, 669, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 670, - 401, 402, 671, 404, 405, 406, 672, 408, 409, 410, + 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, + 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, + 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, + 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 673, 674, 421, 422, 423, 424, 425, 426, 675, 428, - 429, 676, 677, 431, 432, 678, 434, 679, 435, 436, + 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 680, 448, 681, 682, 683, 450, 451, 684, 452, 685, - 454, 455, 456, 457, 458, 686, 459, 687, 688, 689, - 690, 462, 463, 691, 465, 692, 693, 467, 468, 694, - 470, 471, 472, 473, 474, 695, 696, 475, 476, 477, - 697, 478, 479, 480, 481, 698, 482, 483, 484, 485, - 486, 699, 700, 489, 701, 490, 702, 492, 493, 494, - 495, 496, 497, 498, 703, 704, 499, 705, 706, 500, - 501, 502, 503, 504, 505, 707, 708, 709, 710, 711, - 712, 713, 714, 715, 716, 717, 517, 518, 519, 520, - 560, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, + 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, + 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, + 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, + 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 2286, 123, 124, 125, 561, 126, 127, - 128, 562, 563, 564, 565, 566, 567, 568, 569, 570, - 130, 131, 571, 132, 133, 134, 572, 136, 137, 138, - 573, 574, 575, 576, 577, 578, 144, 145, 146, 147, - 148, 149, 579, 580, 150, 151, 152, 153, 581, 582, - 156, 583, 157, 158, 159, 160, 584, 585, 586, 587, - 588, 164, 165, 166, 167, 168, 589, 170, 171, 172, - 590, 173, 174, 175, 176, 177, 178, 591, 592, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 594, - 191, 192, 595, 194, 596, 195, 597, 196, 197, 198, - 199, 200, 201, 598, 599, 202, 203, 204, 205, 600, - 601, 206, 207, 208, 2287, 210, 602, 211, 212, 213, - 603, 214, 215, 216, 604, 217, 218, 219, 220, 605, - 222, 223, 224, 225, 226, 227, 606, 607, 229, 608, - 230, 231, 609, 233, 610, 234, 611, 235, 612, 613, - 614, 238, 239, 615, 616, 242, 617, 243, 618, 619, - 620, 246, 247, 621, 248, 249, 250, 251, 252, 253, - 254, 622, 256, 257, 258, 259, 623, 260, 261, 262, - 263, 264, 265, 266, 624, 267, 625, 626, 270, 271, - 272, 273, 274, 627, 628, 629, 630, 631, 278, 632, - 633, 281, 634, 283, 284, 285, 286, 287, 288, 635, - 636, 289, 637, 291, 638, 639, 293, 294, 295, 296, - 297, 298, 299, 300, 640, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 641, 642, 643, 325, 326, - 327, 644, 645, 329, 330, 646, 332, 647, 648, 334, - 649, 336, 337, 338, 650, 339, 340, 651, 652, 341, - 342, 343, 653, 654, 344, 345, 655, 656, 348, 657, - 658, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 659, 660, 661, 662, 362, 363, 663, 664, - 366, 367, 665, 369, 370, 371, 666, 372, 373, 374, - 375, 376, 377, 667, 378, 379, 380, 381, 382, 668, - 384, 385, 386, 387, 669, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 670, 401, - 402, 671, 404, 405, 406, 672, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 673, - 674, 421, 422, 423, 424, 425, 2288, 675, 428, 429, - 676, 677, 431, 432, 678, 434, 679, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 680, - 448, 681, 682, 683, 450, 451, 684, 452, 685, 454, - 455, 456, 457, 458, 686, 459, 687, 688, 689, 690, - 462, 463, 691, 465, 692, 693, 467, 468, 694, 470, - 471, 472, 473, 474, 695, 696, 475, 476, 477, 697, - 478, 479, 480, 481, 698, 482, 483, 484, 485, 486, - 699, 700, 489, 701, 490, 702, 492, 493, 494, 495, - 496, 497, 498, 703, 704, 499, 705, 706, 500, 501, - 502, 503, 504, 505, 707, 708, 709, 710, 711, 712, - 713, 714, 715, 716, 717, 517, 518, 519, 520, 974, - 0, 821, 0, 0, 0, 0, 0, 0, 0, 0, + 119, 120, 121, 122, 123, 124, 125, 826, 126, 127, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, + 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, + 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, + 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, + 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, + 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, + 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, + 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, + 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, + 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, + 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, + 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, + 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, + 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, + 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, + 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, + 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, + 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, + 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, + 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, + 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, + 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, + 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, + 455, 456, 457, 458, 0, 459, 830, 461, 0, 0, + 831, 463, 464, 465, 466, 0, 467, 468, 469, 470, + 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, + 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, + 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, + 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, + 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 565, 0, 0, 0, 0, 570, 130, - 131, 0, 132, 133, 134, 572, 136, 137, 138, 573, - 574, 575, 576, 577, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 581, 582, 156, - 0, 157, 158, 159, 160, 584, 0, 586, 0, 588, - 164, 165, 166, 167, 168, 589, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 592, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 594, 191, - 192, 595, 194, 0, 195, 0, 196, 197, 198, 199, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 605, 222, - 223, 224, 225, 226, 227, 606, 1365, 229, 0, 230, - 231, 609, 233, 0, 234, 0, 235, 612, 0, 614, - 238, 239, 615, 616, 242, 0, 243, 0, 619, 620, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 622, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 625, 626, 270, 271, 272, - 273, 274, 627, 628, 0, 630, 0, 278, 632, 633, - 281, 634, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 637, 291, 638, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 640, 302, 303, 304, 305, 306, 307, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, + 246, 247, 0, 248, 249, 250, 251, 252, 1318, 254, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 641, 642, 643, 325, 326, 327, - 644, 0, 329, 330, 646, 332, 0, 648, 334, 649, - 336, 337, 338, 0, 339, 340, 1366, 0, 341, 342, - 343, 0, 0, 344, 345, 655, 656, 348, 657, 658, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 663, 664, 366, - 367, 665, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 668, 384, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 671, 404, 405, 406, 672, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 674, - 421, 422, 423, 424, 425, 426, 675, 428, 429, 0, - 677, 431, 432, 678, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 680, 448, - 681, 0, 0, 450, 451, 0, 452, 685, 454, 455, - 456, 457, 458, 0, 459, 687, 688, 0, 0, 462, - 463, 691, 465, 692, 1367, 467, 468, 694, 470, 471, + 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 699, - 700, 489, 0, 490, 702, 492, 493, 494, 495, 496, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 707, 708, 709, 710, 711, 712, 713, - 714, 715, 716, 717, 517, 518, 519, 520, 974, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, + 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 3, - 4, 0, 565, 0, 0, 0, 0, 570, 130, 131, - 0, 132, 133, 134, 572, 136, 137, 138, 573, 574, - 575, 576, 577, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 581, 582, 156, 0, - 157, 158, 159, 160, 584, 0, 586, 0, 588, 164, - 165, 166, 167, 168, 589, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 592, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 594, 191, 192, - 595, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, + 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, + 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 605, 222, 223, - 224, 225, 226, 227, 606, 0, 229, 0, 230, 231, - 609, 233, 0, 234, 0, 235, 612, 0, 614, 238, - 239, 615, 616, 242, 0, 243, 0, 619, 620, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 622, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, + 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 1320, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 625, 626, 270, 271, 272, 273, - 274, 627, 628, 0, 630, 0, 278, 632, 633, 281, - 634, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 637, 291, 638, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 640, 302, 303, 304, 305, 306, 307, 308, + 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, + 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 641, 642, 643, 325, 326, 327, 644, - 0, 329, 330, 646, 332, 0, 648, 334, 649, 336, + 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, + 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 655, 656, 348, 657, 658, 351, + 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 663, 664, 366, 367, - 665, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 668, 384, 385, + 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 671, - 404, 405, 406, 672, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 674, 421, - 422, 423, 424, 425, 426, 675, 428, 429, 0, 677, - 431, 432, 678, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 680, 448, 681, - 0, 0, 450, 451, 0, 452, 685, 454, 455, 456, - 457, 458, 0, 459, 687, 688, 0, 0, 462, 463, - 691, 465, 692, 0, 467, 468, 694, 470, 471, 472, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, + 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 699, 700, - 489, 0, 490, 702, 492, 493, 494, 495, 496, 497, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 707, 708, 709, 710, 711, 712, 713, 714, - 715, 716, 717, 517, 518, 519, 520, 117, 0, 0, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 129, 130, 131, 0, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 790, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 791, 0, 792, 0, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 179, 180, 181, 182, 183, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 793, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 236, 0, 237, 238, 239, - 240, 241, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 1323, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 290, - 291, 292, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 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, 0, - 329, 330, 331, 332, 0, 795, 334, 335, 336, 337, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 347, 348, 349, 797, 351, 352, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 798, 365, 366, 367, 368, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 403, 404, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 430, 431, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 800, 0, - 0, 450, 451, 0, 452, 453, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 801, - 465, 802, 0, 467, 468, 803, 470, 471, 472, 473, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 117, 0, 0, 0, + 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 129, 130, 131, 0, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, - 159, 160, 161, 0, 162, 0, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 179, 180, 181, 182, 183, 184, + 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 236, 0, 237, 238, 239, 240, - 241, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, + 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, + 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 1325, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 0, 277, 0, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 290, 291, - 292, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, + 530, 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, 0, 329, - 330, 331, 332, 0, 333, 334, 335, 336, 337, 338, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, - 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 364, 365, 366, 367, 368, 369, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 403, 404, 405, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 430, 431, 432, + 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 449, 0, 0, - 450, 451, 0, 452, 453, 454, 455, 456, 457, 458, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, + 516, 517, 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 1770, 157, 158, 159, - 160, 161, 0, 0, 1771, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 1772, 173, 174, 175, 176, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, + 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, @@ -9652,9 +10762,9 @@ static const yytype_int16 yytable[] = 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 1773, 235, 0, 0, 0, 238, 239, 529, 0, + 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 1774, 254, 0, 256, 257, 258, + 249, 250, 251, 252, 2262, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, @@ -9668,7 +10778,7 @@ static const yytype_int16 yytable[] = 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, - 371, 1775, 372, 373, 374, 375, 376, 377, 0, 378, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, @@ -9680,35 +10790,283 @@ static const yytype_int16 yytable[] = 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, - 1776, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, + 517, 518, 519, 520, 1490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, + 125, 0, 126, 127, 128, 0, 0, 0, 1491, 0, + 0, -802, 0, 1492, 130, 131, 0, 132, 133, 134, + 1493, 136, 137, 138, 0, 1494, 1495, 1496, 1497, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 154, 155, 156, 1770, 157, 158, 159, 160, - 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, - 0, 170, 171, 172, 1772, 173, 174, 175, 176, 177, - 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, + 152, 153, 1498, 1499, 156, 0, 157, 158, 159, 160, + 0, 0, 1500, 0, 1501, 164, 165, 166, 167, 168, + 1502, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 1503, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 1504, 191, 192, 1505, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 203, 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 1773, 235, 0, 0, 0, 238, 239, 529, 0, 242, + 218, 219, 220, 0, 222, 223, 224, 225, 226, 227, + 0, 0, 229, 0, 230, 231, 1506, 233, 0, 234, + 0, 235, 1507, 0, 1508, 238, 239, -802, 1509, 242, + 0, 243, 0, 0, 0, 246, 247, 0, 248, 249, + 250, 251, 252, 253, 254, 1510, 256, 257, 258, 259, + 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, + 1511, 0, 270, 271, 272, 273, 274, 1512, 1513, 0, + 1514, 0, 278, 1515, 1516, 281, 1517, 283, 284, 285, + 286, 287, 288, 0, 0, 289, 1518, 291, 1519, 0, + 293, 294, 295, 296, 297, 298, 299, 300, 1520, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 1521, + 1522, 1523, 325, 326, 327, 0, 0, 329, 330, 1524, + 332, 0, 0, 334, 1525, 336, 337, 338, 0, 339, + 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, + 0, 1526, 348, 1527, 0, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, + 362, 363, 0, 1528, 366, 367, 0, 369, 370, 371, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 380, 381, 382, 1529, 384, 385, 386, 387, 0, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, + 399, 400, 0, 401, 402, 1530, 404, 405, 406, 1531, + 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 0, 1532, 421, 422, 423, 424, 425, + 426, 1533, 428, 429, 0, 1534, 431, 432, 1535, 434, + 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, 1536, 448, 0, 0, 0, 450, 451, + 0, 452, 1537, 454, 455, 456, 457, 458, 0, 459, + 1538, 1539, 0, 0, 462, 463, 0, 465, 0, 0, + 467, 468, 1540, 470, 471, 472, 473, 474, 1541, 0, + 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, + 483, 484, 485, 486, 0, 1542, 489, 0, 490, 1543, + 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, + 0, 0, 500, 501, 502, 503, 504, 505, 528, 0, + 554, 0, 0, 0, 0, 0, 0, 0, 0, 517, + 518, 519, 520, 0, 0, 0, 0, 118, 119, 120, + 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, + 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, + 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, + 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, + 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, + 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, + 247, 0, 248, 249, 250, 251, 252, 3024, 254, 0, + 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, + 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, + 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, + 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, + 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, + 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, + 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, + 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, + 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, + 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, + 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, + 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, + 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, + 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, + 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, + 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, + 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, + 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, + 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, + 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, + 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, + 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, + 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, + 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, + 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, + 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, + 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, + 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, + 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, + 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, + 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, + 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, + 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, + 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, + 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, + 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, + 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, + 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, + 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, + 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, + 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, + 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, + 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, + 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, + 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, + 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, + 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, + 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, + 0, 842, 0, 243, 0, 244, 245, 246, 247, 0, + 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, + 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, + 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, + 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, + 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, + 0, 0, 293, 294, 843, 296, 297, 298, 299, 300, + 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, + 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, + 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, + 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, + 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, + 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, + 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, + 406, 407, 408, 409, 410, 411, 844, 413, 414, 415, + 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, + 424, 845, 426, 427, 428, 429, 0, 0, 431, 432, + 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, + 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, + 0, 459, 846, 461, 0, 0, 462, 463, 464, 465, + 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, + 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, + 0, 482, 483, 484, 485, 486, 487, 488, 847, 0, + 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, + 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, + 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, + 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, + 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, + 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, + 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, + 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, + 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, + 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, + 249, 250, 251, 252, 959, 254, 0, 256, 257, 258, + 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, + 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, + 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, + 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, + 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, + 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, + 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, + 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, + 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, + 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, + 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, + 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, + 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, + 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, + 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, + 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, + 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, + 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, + 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, + 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, + 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, + 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, + 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, + 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 0, 291, 2372, 0, + 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, @@ -9718,27 +11076,27 @@ static const yytype_int16 yytable[] = 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, - 1775, 372, 373, 374, 375, 376, 377, 0, 378, 379, + 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 408, 409, 410, 411, 844, 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, - 467, 468, 469, 470, 471, 472, 473, 474, 0, 1776, + 846, 461, 0, 0, 462, 463, 464, 465, 466, 0, + 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, + 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 3, 4, 0, 0, 0, 0, + 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, @@ -9754,7 +11112,7 @@ static const yytype_int16 yytable[] = 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, + 251, 252, 1314, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, @@ -9785,9 +11143,9 @@ static const yytype_int16 yytable[] = 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, + 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 555, + 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, @@ -9804,7 +11162,7 @@ static const yytype_int16 yytable[] = 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 0, 256, 257, 258, 259, 0, 260, + 252, 1335, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, @@ -9817,7 +11175,7 @@ static const yytype_int16 yytable[] = 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 556, 370, 371, 0, 372, + 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, @@ -9835,10 +11193,10 @@ static const yytype_int16 yytable[] = 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, + 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 127, 128, 0, 0, 0, 0, 0, 0, 1686, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, @@ -9863,7 +11221,7 @@ static const yytype_int16 yytable[] = 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 796, + 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, @@ -9873,7 +11231,7 @@ static const yytype_int16 yytable[] = 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, + 0, 0, 421, 422, 423, 424, 425, 0, 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, @@ -9885,7 +11243,7 @@ static const yytype_int16 yytable[] = 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, + 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -9903,7 +11261,7 @@ static const yytype_int16 yytable[] = 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 904, + 245, 246, 247, 0, 248, 249, 250, 251, 252, 1872, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, @@ -9913,7 +11271,7 @@ static const yytype_int16 yytable[] = 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 796, 341, + 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, @@ -9935,9 +11293,9 @@ static const yytype_int16 yytable[] = 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 948, 126, 127, 128, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, @@ -9953,7 +11311,7 @@ static const yytype_int16 yytable[] = 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 246, 247, 0, 248, 249, 250, 251, 252, 2249, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, @@ -9985,7 +11343,7 @@ static const yytype_int16 yytable[] = 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, - 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, @@ -10000,10 +11358,10 @@ static const yytype_int16 yytable[] = 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 1184, 227, 228, 0, 229, 0, 230, 231, + 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, + 247, 0, 248, 249, 250, 251, 252, 2264, 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, @@ -10013,7 +11371,7 @@ static const yytype_int16 yytable[] = 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 796, 341, 342, 343, + 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, @@ -10034,4186 +11392,1333 @@ static const yytype_int16 yytable[] = 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, + 514, 515, 516, 517, 518, 519, 520, 1490, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, - 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, - 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 0, 1491, 0, 0, 0, 0, 1492, 130, 131, 0, + 132, 133, 134, 1493, 136, 137, 138, 0, 1494, 1495, + 1496, 1497, 0, 144, 145, 146, 147, 148, 149, 0, + 0, 150, 151, 152, 153, 1498, 1499, 156, 0, 157, + 158, 159, 160, 0, 0, 1500, 0, 1501, 164, 165, + 166, 167, 168, 1502, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 0, 1503, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 1504, 191, 192, 1505, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, - 529, 0, 1992, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 253, 254, 0, 256, + 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, + 216, 0, 217, 218, 219, 220, 0, 222, 223, 224, + 225, 226, 227, 0, 0, 229, 0, 230, 231, 1506, + 233, 0, 234, 0, 235, 1507, 0, 1508, 238, 239, + 0, 1509, 242, 0, 243, 0, 0, 0, 246, 247, + 0, 248, 249, 250, 251, 252, 253, 254, 1510, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, - 291, 0, 0, 293, 294, 1993, 296, 297, 298, 299, - 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, + 266, 0, 267, 1511, 0, 270, 271, 272, 273, 274, + 1512, 1513, 0, 1514, 0, 278, 1515, 1516, 281, 1517, + 283, 284, 285, 286, 287, 288, 0, 0, 289, 1518, + 291, 1519, 0, 293, 294, 295, 296, 297, 298, 299, + 300, 1520, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, - 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, + 320, 321, 1521, 1522, 1523, 325, 326, 327, 0, 0, + 329, 330, 1524, 332, 0, 0, 334, 1525, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, + 0, 344, 345, 0, 1526, 348, 1527, 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, + 0, 0, 0, 362, 363, 0, 1528, 366, 367, 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, + 0, 378, 379, 380, 381, 382, 1529, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, - 0, 450, 451, 1994, 452, 0, 454, 1995, 456, 1996, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, - 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 1997, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, + 396, 397, 398, 399, 400, 0, 401, 402, 1530, 404, + 405, 406, 1531, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 0, 1532, 421, 422, + 423, 424, 425, 426, 1533, 428, 429, 0, 1534, 431, + 432, 1535, 434, 0, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 1536, 448, 0, 0, + 0, 450, 451, 0, 452, 1537, 454, 455, 456, 457, + 458, 0, 459, 1538, 1539, 0, 0, 462, 463, 0, + 465, 0, 0, 467, 468, 1540, 470, 471, 472, 473, + 474, 1541, 0, 475, 476, 477, 0, 478, 479, 480, + 481, 0, 482, 483, 484, 485, 486, 0, 1542, 489, + 0, 490, 1543, 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 554, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, - 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, - 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, - 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, - 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, - 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, - 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, - 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, - 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, - 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, - 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, - 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, - 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, - 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, - 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 821, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 505, 1490, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 517, 518, 519, 520, 0, 0, 0, 0, + 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, + 127, 128, 0, 0, 0, 1491, 0, 0, 0, 0, + 1492, 130, 131, 0, 132, 133, 134, 1493, 136, 137, + 138, 0, 1494, 1495, 1496, 1497, 0, 144, 145, 146, + 147, 148, 149, 0, 0, 150, 151, 152, 153, 1498, + 1499, 156, 0, 157, 158, 159, 160, 0, 0, 1500, + 0, 1501, 164, 165, 166, 167, 168, 1502, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 0, 1503, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 1504, 191, 192, 1505, 194, 0, 195, 0, 196, 197, + 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, + 213, 0, 1848, 215, 216, 0, 217, 218, 219, 220, + 0, 222, 223, 224, 225, 226, 227, 0, 0, 229, + 0, 230, 231, 1506, 233, 0, 234, 0, 235, 1507, + 0, 1508, 238, 239, 0, 1509, 242, 0, 243, 0, + 0, 0, 246, 247, 0, 248, 249, 250, 251, 252, + 253, 254, 1510, 256, 257, 258, 259, 0, 260, 261, + 262, 263, 264, 265, 266, 0, 267, 1511, 0, 270, + 271, 272, 273, 274, 1512, 1513, 0, 1514, 0, 278, + 1515, 1516, 281, 1517, 283, 284, 285, 286, 287, 288, + 0, 0, 289, 1518, 291, 1519, 0, 293, 294, 295, + 296, 297, 298, 299, 300, 1520, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 1521, 1522, 1523, 325, + 326, 327, 0, 0, 329, 330, 1524, 332, 0, 0, + 334, 1525, 336, 337, 338, 0, 339, 340, 0, 0, + 341, 342, 343, 0, 0, 344, 345, 0, 1526, 348, + 1527, 0, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, 361, 0, 0, 0, 0, 362, 363, 0, + 1528, 366, 367, 0, 369, 370, 371, 0, 372, 373, + 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, + 1529, 384, 385, 386, 387, 0, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, + 401, 402, 1530, 404, 405, 406, 1531, 408, 409, 410, + 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, + 0, 1532, 421, 422, 423, 424, 425, 426, 1533, 428, + 429, 0, 1534, 431, 432, 1535, 434, 0, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + 1536, 448, 0, 0, 0, 450, 451, 0, 452, 1537, + 454, 455, 456, 457, 458, 0, 459, 1538, 1539, 0, + 0, 462, 463, 0, 465, 0, 0, 467, 468, 1540, + 470, 471, 472, 473, 474, 1541, 0, 475, 476, 477, + 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, + 486, 0, 1542, 489, 0, 490, 1543, 492, 493, 494, + 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, + 501, 502, 503, 504, 505, 3199, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 517, 518, 519, 520, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, + 124, 125, 0, 126, 127, 128, 0, 0, 0, 2947, + 0, 0, 0, 0, 2948, 130, 131, 0, 132, 133, + 134, 2949, 136, 137, 138, 0, 1494, 2950, 1496, 1497, 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, + 151, 152, 153, 1498, 1499, 156, 0, 157, 158, 159, + 160, 0, 0, 2951, 0, 2952, 164, 165, 166, 167, + 168, 2953, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 0, 2954, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 1504, 191, 192, 1505, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, + 202, 203, 204, 205, 0, 0, 206, 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, + 217, 218, 219, 220, 0, 222, 223, 224, 225, 226, + 227, 0, 0, 229, 0, 230, 231, 1506, 233, 0, + 234, 0, 235, 2955, 0, 2956, 238, 239, 2957, 2958, + 242, 0, 243, 0, 0, 0, 246, 247, 0, 248, + 249, 250, 251, 252, 253, 254, 2959, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, + 267, 2960, 0, 270, 271, 272, 273, 274, 1512, 1513, + 0, 1514, 0, 278, 2961, 2962, 281, 2963, 283, 284, + 285, 286, 287, 288, 0, 0, 289, 2964, 291, 2965, + 0, 293, 294, 295, 296, 297, 298, 299, 300, 3200, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, + 1521, 2967, 1523, 325, 326, 327, 0, 0, 329, 330, + 2969, 332, 0, 0, 334, 1525, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, + 345, 0, 2971, 348, 2972, 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, + 0, 362, 363, 0, 2973, 366, 367, 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, + 379, 380, 381, 382, 1529, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, + 398, 399, 400, 0, 401, 402, 2974, 404, 405, 406, + 0, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 0, 2975, 421, 422, 423, 424, + 425, 426, 0, 428, 429, 0, 2977, 431, 432, 1535, 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, + 443, 444, 445, 446, 3201, 448, 0, 0, 0, 450, + 451, 0, 452, 2979, 454, 455, 456, 457, 458, 0, + 459, 1538, 1539, 0, 0, 462, 463, 0, 465, 0, + 0, 467, 468, 2980, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, + 482, 483, 484, 485, 486, 0, 1542, 489, 0, 490, + 2982, 492, 493, 494, 495, 496, 497, 498, 0, 0, + 499, 0, 0, 500, 501, 502, 503, 504, 505, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 827, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, - 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, - 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, - 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, - 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, - 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 0, 235, 0, 0, 0, 238, 239, 529, 0, 828, - 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, - 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, - 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, - 293, 294, 829, 296, 297, 298, 299, 300, 530, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, - 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, - 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, - 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 0, 421, 422, 423, 424, 830, - 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, - 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, - 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 831, 461, 0, 0, 832, 463, 464, 465, 466, 0, - 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, - 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 488, 833, 0, 490, 0, - 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, + 517, 518, 519, 520, 0, 0, 0, 0, 118, 119, + 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, + 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, + 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, + 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, + 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, + 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, + 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, + 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, + 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, + 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, + 0, 247, 0, 248, 249, 250, 251, 252, 253, 254, + 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, + 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, + 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, + 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, + 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, + 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, + 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, + 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, + 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, + 351, 352, 353, 354, 355, 356, 0, 358, 359, 360, + 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, + 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, + 376, 377, 0, 378, 379, 380, 0, 382, 383, 384, + 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, + 0, 404, 405, 406, 407, 0, 409, 410, 411, 412, + 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, + 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, + 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, + 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, + 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, + 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, + 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, + 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, + 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 1785, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, - 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, - 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, - 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, - 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 383, 384, 385, 866, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, - 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 899, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 902, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 906, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 936, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, - 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, - 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, - 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, + 0, 0, 1491, 0, 0, 0, 0, 1492, 130, 131, + 0, 132, 133, 134, 1493, 136, 137, 138, 0, 1494, + 1495, 1496, 1497, 0, 144, 145, 146, 147, 148, 149, + 0, 0, 150, 151, 152, 153, 1498, 1499, 156, 0, + 157, 158, 159, 160, 0, 0, 1500, 0, 1501, 164, + 165, 166, 167, 168, 1502, 170, 171, 172, 0, 173, + 174, 175, 176, 177, 178, 0, 1503, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 1504, 191, 192, + 1505, 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 964, 254, 0, + 207, 1067, 209, 210, 0, 211, 212, 213, 0, 214, + 215, 216, 0, 217, 218, 219, 220, 0, 222, 223, + 224, 225, 226, 227, 0, 0, 229, 0, 230, 231, + 1506, 233, 0, 234, 0, 235, 1507, 0, 1508, 238, + 239, 0, 1509, 242, 0, 243, 0, 0, 0, 246, + 247, 0, 248, 249, 250, 251, 252, 253, 254, 1510, 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, - 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, + 265, 266, 0, 267, 1511, 0, 270, 271, 272, 273, + 274, 1512, 1513, 0, 1514, 0, 278, 1515, 1516, 281, + 1517, 283, 284, 285, 286, 287, 288, 0, 0, 289, + 1518, 291, 1519, 0, 293, 294, 295, 296, 297, 298, + 299, 300, 0, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, - 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, + 319, 320, 321, 1521, 1522, 1523, 325, 326, 327, 0, + 0, 329, 330, 1524, 332, 0, 0, 334, 1525, 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, + 0, 0, 344, 345, 0, 1526, 348, 1527, 0, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, + 0, 0, 0, 0, 362, 363, 0, 1528, 366, 367, + 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, + 377, 0, 378, 379, 380, 381, 382, 1529, 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 460, 461, 0, 0, 462, 463, - 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, + 395, 396, 397, 398, 399, 400, 0, 401, 402, 1530, + 404, 405, 406, 0, 408, 409, 410, 411, 412, 413, + 414, 415, 416, 417, 418, 419, 420, 0, 1532, 421, + 422, 423, 424, 425, 426, 0, 428, 429, 0, 1534, + 431, 432, 1535, 434, 0, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 0, 448, 0, + 0, 0, 450, 451, 0, 452, 1537, 454, 455, 456, + 457, 458, 0, 459, 1538, 1539, 0, 0, 462, 463, + 0, 465, 0, 0, 467, 468, 1540, 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 554, + 480, 481, 0, 482, 483, 484, 485, 486, 0, 1542, + 489, 0, 490, 1543, 492, 493, 494, 495, 496, 497, + 498, 0, 1, 499, 0, 0, 500, 501, 502, 503, + 504, 505, 2, 0, 3, 4, 0, 0, 0, 0, + 1, 0, 0, 517, 518, 519, 520, 0, 0, 0, + 2, 0, 6, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 8, 0, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, + 0, 0, 0, 8, 0, 0, 0, 0, 11, 0, + 751, 0, 0, 0, 10, 0, 0, 0, 0, 0, + 0, 13, 0, 0, 0, 0, 11, 0, 751, 0, + 0, 0, 0, 0, 0, 0, 14, 15, 0, 13, + 0, 0, 0, 0, 0, 0, 0, 752, 0, 0, + 0, 0, 0, 18, 14, 15, 0, 0, 0, 0, + 0, 19, 0, 0, 0, 752, 0, 0, 0, 0, + 0, 18, 0, 0, 0, 0, 0, 0, 22, 19, + 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, + 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, - 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, - 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, - 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 967, 254, 0, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, - 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, - 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, - 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, - 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, + 0, 0, 0, 0, -1445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 1010, 0, 0, 130, 131, 0, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, - 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, - 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, - 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, - 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, - 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 253, 254, 0, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, - 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, - 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, - 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, - 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, - 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, - 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, - 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, - 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, - 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, + 0, 0, -1445, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 1037, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 431, 432, 433, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 827, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, - 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, - 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, - 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, - 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, - 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, - 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 253, 254, 0, 256, 257, 258, 259, - 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, - 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, - 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, - 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, - 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, - 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, - 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 831, 461, 0, 0, 832, 463, 464, 465, 466, 0, - 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, - 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, - 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, - 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, - 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 1326, 254, 0, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, - 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, - 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, - 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 1328, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 554, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 1331, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 554, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 242, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 1333, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 295, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 460, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 489, 0, 490, 0, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 2282, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 1502, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 1503, 0, 0, -808, 0, 1504, 130, 131, - 0, 132, 133, 134, 1505, 136, 137, 138, 0, 1506, - 1507, 1508, 1509, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 1510, 1511, 156, 0, - 157, 158, 159, 160, 0, 0, 1512, 0, 1513, 164, - 165, 166, 167, 168, 1514, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 1515, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 1516, 191, 192, - 1517, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 1073, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 0, 222, 223, - 224, 225, 226, 227, 0, 0, 229, 0, 230, 231, - 1518, 233, 0, 234, 0, 235, 1519, 0, 1520, 238, - 239, -808, 1521, 242, 0, 243, 0, 0, 0, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 1522, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 1523, 0, 270, 271, 272, 273, - 274, 1524, 1525, 0, 1526, 0, 278, 1527, 1528, 281, - 1529, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 1530, 291, 1531, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 1532, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 1533, 1534, 1535, 325, 326, 327, 0, - 0, 329, 330, 1536, 332, 0, 0, 334, 1537, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 0, 1538, 348, 1539, 0, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 0, 1540, 366, 367, - 0, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 1541, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 1542, - 404, 405, 406, 1543, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 1544, 421, - 422, 423, 424, 425, 426, 1545, 428, 429, 0, 1546, - 431, 432, 1547, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 1548, 448, 0, - 0, 0, 450, 451, 0, 452, 1549, 454, 455, 456, - 457, 458, 0, 459, 1550, 1551, 0, 0, 462, 463, - 0, 465, 0, 0, 467, 468, 1552, 470, 471, 472, - 473, 474, 1553, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 0, 1554, - 489, 0, 490, 1555, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 528, 0, 554, 0, 0, 0, 0, 0, - 0, 0, 0, 517, 518, 519, 520, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 3051, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 528, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 130, 131, 0, 132, 133, 134, 0, 136, 137, - 138, 139, 140, 0, 142, 143, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 154, - 155, 156, 0, 157, 158, 159, 160, 161, 0, 0, - 0, 163, 164, 165, 166, 167, 168, 0, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 0, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 208, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 0, 229, - 0, 230, 231, 232, 233, 0, 234, 0, 235, 0, - 0, 0, 238, 239, 529, 0, 242, 0, 243, 0, - 244, 245, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 0, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 0, 269, 270, - 271, 272, 273, 274, 275, 276, 0, 277, 0, 278, - 0, 0, 281, 0, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 0, 291, 0, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 530, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 0, 324, 325, - 326, 327, 328, 0, 329, 330, 0, 332, 0, 333, - 334, 335, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 346, 0, 348, - 0, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 364, - 0, 366, 367, 368, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 383, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 0, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 0, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 431, 432, 433, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 531, 448, 449, 0, 0, 450, 451, 0, 452, 0, - 454, 455, 456, 457, 458, 0, 459, 460, 461, 0, - 0, 462, 463, 464, 465, 466, 0, 467, 468, 469, - 470, 471, 472, 473, 474, 0, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 487, 488, 489, 0, 490, 0, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, - 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, - 119, 120, 121, 122, 123, 124, 125, 0, 126, 127, - 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 130, 131, 0, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 0, 142, 143, 0, 144, 145, 146, 147, - 148, 149, 0, 0, 150, 151, 152, 153, 154, 155, - 156, 0, 157, 158, 159, 160, 161, 0, 0, 0, - 163, 164, 165, 166, 167, 168, 0, 170, 171, 172, - 0, 173, 174, 175, 176, 177, 178, 0, 0, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 0, 195, 0, 196, 197, 198, - 199, 200, 201, 0, 0, 202, 203, 204, 205, 0, - 0, 206, 207, 208, 209, 210, 0, 211, 212, 213, - 0, 214, 215, 216, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 0, 229, 0, - 230, 231, 232, 233, 0, 234, 0, 235, 0, 0, - 0, 238, 239, 529, 0, 843, 0, 243, 0, 244, - 245, 246, 247, 0, 248, 249, 250, 251, 252, 253, - 254, 0, 256, 257, 258, 259, 0, 260, 261, 262, - 263, 264, 265, 266, 0, 267, 0, 269, 270, 271, - 272, 273, 274, 275, 276, 0, 277, 0, 278, 0, - 0, 281, 0, 283, 284, 285, 286, 287, 288, 0, - 0, 289, 0, 291, 0, 0, 293, 294, 844, 296, - 297, 298, 299, 300, 530, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 0, 324, 325, 326, - 327, 328, 0, 329, 330, 0, 332, 0, 333, 334, - 335, 336, 337, 338, 0, 339, 340, 0, 0, 341, - 342, 343, 0, 0, 344, 345, 346, 0, 348, 0, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 0, 0, 0, 0, 362, 363, 364, 0, - 366, 367, 368, 369, 370, 371, 0, 372, 373, 374, - 375, 376, 377, 0, 378, 379, 380, 381, 382, 383, - 384, 385, 386, 387, 0, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 0, 401, - 402, 0, 404, 405, 406, 407, 408, 409, 410, 411, - 845, 413, 414, 415, 416, 417, 418, 419, 420, 0, - 0, 421, 422, 423, 424, 846, 426, 427, 428, 429, - 0, 0, 431, 432, 433, 434, 0, 435, 436, 437, - 438, 439, 440, 441, 442, 443, 444, 445, 446, 531, - 448, 449, 0, 0, 450, 451, 0, 452, 0, 454, - 455, 456, 457, 458, 0, 459, 847, 461, 0, 0, - 462, 463, 464, 465, 466, 0, 467, 468, 469, 470, - 471, 472, 473, 474, 0, 0, 475, 476, 477, 0, - 478, 479, 480, 481, 0, 482, 483, 484, 485, 486, - 487, 488, 848, 0, 490, 0, 492, 493, 494, 495, - 496, 497, 498, 0, 0, 499, 0, 0, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 528, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, - 131, 0, 132, 133, 134, 0, 136, 137, 138, 139, - 140, 0, 142, 143, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 154, 155, 156, - 0, 157, 158, 159, 160, 161, 0, 0, 0, 163, - 164, 165, 166, 167, 168, 0, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 0, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 208, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 0, 229, 0, 230, - 231, 232, 233, 0, 234, 0, 235, 0, 0, 0, - 238, 239, 529, 0, 242, 0, 243, 0, 244, 245, - 246, 247, 0, 248, 249, 250, 251, 252, 960, 254, - 0, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 0, 269, 270, 271, 272, - 273, 274, 275, 276, 0, 277, 0, 278, 0, 0, - 281, 0, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 0, 291, 0, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 530, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 0, 324, 325, 326, 327, - 328, 0, 329, 330, 0, 332, 0, 333, 334, 335, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 346, 0, 348, 0, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 364, 0, 366, - 367, 368, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 0, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 0, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 431, 432, 433, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 531, 448, - 449, 0, 0, 450, 451, 0, 452, 0, 454, 455, - 456, 457, 458, 0, 459, 460, 461, 0, 0, 462, - 463, 464, 465, 466, 0, 467, 468, 469, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 487, - 488, 489, 0, 490, 0, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, - 513, 514, 515, 516, 517, 518, 519, 520, 528, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 118, 119, 120, - 121, 122, 123, 124, 125, 0, 126, 127, 128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 130, 131, - 0, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 0, 142, 143, 0, 144, 145, 146, 147, 148, 149, - 0, 0, 150, 151, 152, 153, 154, 155, 156, 0, - 157, 158, 159, 160, 161, 0, 0, 0, 163, 164, - 165, 166, 167, 168, 0, 170, 171, 172, 0, 173, - 174, 175, 176, 177, 178, 0, 0, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 0, 195, 0, 196, 197, 198, 199, 200, - 201, 0, 0, 202, 203, 204, 205, 0, 0, 206, - 207, 208, 209, 210, 0, 211, 212, 213, 0, 214, - 215, 216, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 0, 229, 0, 230, 231, - 232, 233, 0, 234, 0, 235, 0, 0, 0, 238, - 239, 529, 0, 242, 0, 243, 0, 244, 245, 246, - 247, 0, 248, 249, 250, 251, 252, 253, 254, 0, - 256, 257, 258, 259, 0, 260, 261, 262, 263, 264, - 265, 266, 0, 267, 0, 269, 270, 271, 272, 273, - 274, 275, 276, 0, 277, 0, 278, 0, 0, 281, - 0, 283, 284, 285, 286, 287, 288, 0, 0, 289, - 0, 291, 0, 0, 293, 294, 295, 296, 297, 298, - 299, 300, 530, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 319, 320, 321, 322, 0, 324, 325, 326, 327, 328, - 0, 329, 330, 0, 332, 0, 333, 334, 335, 336, - 337, 338, 0, 339, 340, 0, 0, 341, 342, 343, - 0, 0, 344, 345, 346, 0, 348, 0, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, - 0, 0, 0, 0, 362, 363, 364, 0, 366, 367, - 368, 369, 370, 371, 0, 372, 373, 374, 375, 376, - 377, 0, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 0, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 0, 401, 402, 0, - 404, 405, 406, 407, 408, 409, 410, 411, 845, 413, - 414, 415, 416, 417, 418, 419, 420, 0, 0, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 431, 432, 433, 434, 0, 435, 436, 437, 438, 439, - 440, 441, 442, 443, 444, 445, 446, 531, 448, 449, - 0, 0, 450, 451, 0, 452, 0, 454, 455, 456, - 457, 458, 0, 459, 847, 461, 0, 0, 462, 463, - 464, 465, 466, 0, 467, 468, 469, 470, 471, 472, - 473, 474, 0, 0, 475, 476, 477, 0, 478, 479, - 480, 481, 0, 482, 483, 484, 485, 486, 487, 488, - 489, 0, 490, 0, 492, 493, 494, 495, 496, 497, - 498, 0, 0, 499, 0, 0, 500, 501, 502, 503, - 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, - 514, 515, 516, 517, 518, 519, 520, 528, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 118, 119, 120, 121, - 122, 123, 124, 125, 0, 126, 127, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 130, 131, 0, - 132, 133, 134, 0, 136, 137, 138, 139, 140, 0, - 142, 143, 0, 144, 145, 146, 147, 148, 149, 0, - 0, 150, 151, 152, 153, 154, 155, 156, 0, 157, - 158, 159, 160, 161, 0, 0, 0, 163, 164, 165, - 166, 167, 168, 0, 170, 171, 172, 0, 173, 174, - 175, 176, 177, 178, 0, 0, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 0, 195, 0, 196, 197, 198, 199, 200, 201, - 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, - 208, 209, 210, 0, 211, 212, 213, 0, 214, 215, - 216, 0, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 0, 229, 0, 230, 231, 232, - 233, 0, 234, 0, 235, 0, 0, 0, 238, 239, - 529, 0, 242, 0, 243, 0, 244, 245, 246, 247, - 0, 248, 249, 250, 251, 252, 1322, 254, 0, 256, - 257, 258, 259, 0, 260, 261, 262, 263, 264, 265, - 266, 0, 267, 0, 269, 270, 271, 272, 273, 274, - 275, 276, 0, 277, 0, 278, 0, 0, 281, 0, - 283, 284, 285, 286, 287, 288, 0, 0, 289, 0, - 291, 0, 0, 293, 294, 295, 296, 297, 298, 299, - 300, 530, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 0, 324, 325, 326, 327, 328, 0, - 329, 330, 0, 332, 0, 333, 334, 335, 336, 337, - 338, 0, 339, 340, 0, 0, 341, 342, 343, 0, - 0, 344, 345, 346, 0, 348, 0, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 0, - 0, 0, 0, 362, 363, 364, 0, 366, 367, 368, - 369, 370, 371, 0, 372, 373, 374, 375, 376, 377, - 0, 378, 379, 380, 381, 382, 383, 384, 385, 386, - 387, 0, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 0, 401, 402, 0, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 0, 0, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 0, 0, 431, - 432, 433, 434, 0, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 531, 448, 449, 0, - 0, 450, 451, 0, 452, 0, 454, 455, 456, 457, - 458, 0, 459, 460, 461, 0, 0, 462, 463, 464, - 465, 466, 0, 467, 468, 469, 470, 471, 472, 473, - 474, 0, 0, 475, 476, 477, 0, 478, 479, 480, - 481, 0, 482, 483, 484, 485, 486, 487, 488, 489, - 0, 490, 0, 492, 493, 494, 495, 496, 497, 498, - 0, 0, 499, 0, 0, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 528, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 118, 119, 120, 121, 122, - 123, 124, 125, 0, 126, 127, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 130, 131, 0, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 0, 142, - 143, 0, 144, 145, 146, 147, 148, 149, 0, 0, - 150, 151, 152, 153, 154, 155, 156, 0, 157, 158, - 159, 160, 161, 0, 0, 0, 163, 164, 165, 166, - 167, 168, 0, 170, 171, 172, 0, 173, 174, 175, - 176, 177, 178, 0, 0, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 0, 195, 0, 196, 197, 198, 199, 200, 201, 0, - 0, 202, 203, 204, 205, 0, 0, 206, 207, 208, - 209, 210, 0, 211, 212, 213, 0, 214, 215, 216, - 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 0, 229, 0, 230, 231, 232, 233, - 0, 234, 0, 235, 0, 0, 0, 238, 239, 529, - 0, 242, 0, 243, 0, 244, 245, 246, 247, 0, - 248, 249, 250, 251, 252, 1343, 254, 0, 256, 257, - 258, 259, 0, 260, 261, 262, 263, 264, 265, 266, - 0, 267, 0, 269, 270, 271, 272, 273, 274, 275, - 276, 0, 277, 0, 278, 0, 0, 281, 0, 283, - 284, 285, 286, 287, 288, 0, 0, 289, 0, 291, - 0, 0, 293, 294, 295, 296, 297, 298, 299, 300, - 530, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 0, 324, 325, 326, 327, 328, 0, 329, - 330, 0, 332, 0, 333, 334, 335, 336, 337, 338, - 0, 339, 340, 0, 0, 341, 342, 343, 0, 0, - 344, 345, 346, 0, 348, 0, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, 361, 0, 0, - 0, 0, 362, 363, 364, 0, 366, 367, 368, 369, - 370, 371, 0, 372, 373, 374, 375, 376, 377, 0, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, - 0, 388, 389, 390, 391, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 0, 401, 402, 0, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 0, 0, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 431, 432, - 433, 434, 0, 435, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 531, 448, 449, 0, 0, - 450, 451, 0, 452, 0, 454, 455, 456, 457, 458, - 0, 459, 460, 461, 0, 0, 462, 463, 464, 465, - 466, 0, 467, 468, 469, 470, 471, 472, 473, 474, - 0, 0, 475, 476, 477, 0, 478, 479, 480, 481, - 0, 482, 483, 484, 485, 486, 487, 488, 489, 0, - 490, 0, 492, 493, 494, 495, 496, 497, 498, 0, - 0, 499, 0, 0, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, - 516, 517, 518, 519, 520, 528, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 0, - 0, 0, 1698, 0, 0, 130, 131, 0, 132, 133, - 134, 0, 136, 137, 138, 139, 140, 0, 142, 143, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 154, 155, 156, 0, 157, 158, 159, - 160, 161, 0, 0, 0, 163, 164, 165, 166, 167, - 168, 0, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 0, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 208, 209, - 210, 0, 211, 212, 213, 0, 214, 215, 216, 0, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 0, 229, 0, 230, 231, 232, 233, 0, - 234, 0, 235, 0, 0, 0, 238, 239, 529, 0, - 242, 0, 243, 0, 244, 245, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 0, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 0, 269, 270, 271, 272, 273, 274, 275, 276, - 0, 277, 0, 278, 0, 0, 281, 0, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 0, 291, 0, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 530, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 0, 324, 325, 326, 327, 328, 0, 329, 330, - 0, 332, 0, 333, 334, 335, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 346, 0, 348, 0, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 364, 0, 366, 367, 368, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 0, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 0, 421, 422, 423, 424, - 425, 0, 427, 428, 429, 0, 0, 431, 432, 433, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 531, 448, 449, 0, 0, 450, - 451, 0, 452, 0, 454, 455, 456, 457, 458, 0, - 459, 460, 461, 0, 0, 462, 463, 464, 465, 466, - 0, 467, 468, 469, 470, 471, 472, 473, 474, 0, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 487, 488, 489, 0, 490, - 0, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 506, - 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, - 517, 518, 519, 520, 528, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 118, 119, 120, 121, 122, 123, 124, - 125, 0, 126, 127, 128, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 130, 131, 0, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 0, 142, 143, 0, - 144, 145, 146, 147, 148, 149, 0, 0, 150, 151, - 152, 153, 154, 155, 156, 0, 157, 158, 159, 160, - 161, 0, 0, 0, 163, 164, 165, 166, 167, 168, - 0, 170, 171, 172, 0, 173, 174, 175, 176, 177, - 178, 0, 0, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 0, 195, - 0, 196, 197, 198, 199, 200, 201, 0, 0, 202, - 203, 204, 205, 0, 0, 206, 207, 208, 209, 210, - 0, 211, 212, 213, 0, 214, 215, 216, 0, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 0, 229, 0, 230, 231, 232, 233, 0, 234, - 0, 235, 0, 0, 0, 238, 239, 529, 0, 242, - 0, 243, 0, 244, 245, 246, 247, 0, 248, 249, - 250, 251, 252, 1887, 254, 0, 256, 257, 258, 259, - 0, 260, 261, 262, 263, 264, 265, 266, 0, 267, - 0, 269, 270, 271, 272, 273, 274, 275, 276, 0, - 277, 0, 278, 0, 0, 281, 0, 283, 284, 285, - 286, 287, 288, 0, 0, 289, 0, 291, 0, 0, - 293, 294, 295, 296, 297, 298, 299, 300, 530, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, - 0, 324, 325, 326, 327, 328, 0, 329, 330, 0, - 332, 0, 333, 334, 335, 336, 337, 338, 0, 339, - 340, 0, 0, 341, 342, 343, 0, 0, 344, 345, - 346, 0, 348, 0, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, 361, 0, 0, 0, 0, - 362, 363, 364, 0, 366, 367, 368, 369, 370, 371, - 0, 372, 373, 374, 375, 376, 377, 0, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 0, 388, - 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, - 399, 400, 0, 401, 402, 0, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 0, 0, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 431, 432, 433, 434, - 0, 435, 436, 437, 438, 439, 440, 441, 442, 443, - 444, 445, 446, 531, 448, 449, 0, 0, 450, 451, - 0, 452, 0, 454, 455, 456, 457, 458, 0, 459, - 460, 461, 0, 0, 462, 463, 464, 465, 466, 0, - 467, 468, 469, 470, 471, 472, 473, 474, 0, 0, - 475, 476, 477, 0, 478, 479, 480, 481, 0, 482, - 483, 484, 485, 486, 487, 488, 489, 0, 490, 0, - 492, 493, 494, 495, 496, 497, 498, 0, 0, 499, - 0, 0, 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, - 518, 519, 520, 528, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, - 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, - 243, 0, 244, 245, 246, 247, 0, 248, 249, 250, - 251, 252, 2269, 254, 0, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, - 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, - 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 381, 382, 383, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 0, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, - 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 528, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 130, 131, 0, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 0, 142, 143, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 154, 155, 156, 0, 157, 158, 159, 160, 161, 0, - 0, 0, 163, 164, 165, 166, 167, 168, 0, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 0, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 208, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 0, - 229, 0, 230, 231, 232, 233, 0, 234, 0, 235, - 0, 0, 0, 238, 239, 529, 0, 242, 0, 243, - 0, 244, 245, 246, 247, 0, 248, 249, 250, 251, - 252, 2284, 254, 0, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 0, 269, - 270, 271, 272, 273, 274, 275, 276, 0, 277, 0, - 278, 0, 0, 281, 0, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 0, 291, 0, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 530, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 0, 324, - 325, 326, 327, 328, 0, 329, 330, 0, 332, 0, - 333, 334, 335, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 346, 0, - 348, 0, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 364, 0, 366, 367, 368, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 0, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 0, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 431, 432, 433, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 531, 448, 449, 0, 0, 450, 451, 0, 452, - 0, 454, 455, 456, 457, 458, 0, 459, 460, 461, - 0, 0, 462, 463, 464, 465, 466, 0, 467, 468, - 469, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 487, 488, 489, 0, 490, 0, 492, 493, - 494, 495, 496, 497, 498, 0, 0, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, - 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, - 520, 1502, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 118, 119, 120, 121, 122, 123, 124, 125, 0, 126, - 127, 128, 0, 0, 0, 1503, 0, 0, 0, 0, - 1504, 130, 131, 0, 132, 133, 134, 1505, 136, 137, - 138, 0, 1506, 1507, 1508, 1509, 0, 144, 145, 146, - 147, 148, 149, 0, 0, 150, 151, 152, 153, 1510, - 1511, 156, 0, 157, 158, 159, 160, 0, 0, 1512, - 0, 1513, 164, 165, 166, 167, 168, 1514, 170, 171, - 172, 0, 173, 174, 175, 176, 177, 178, 0, 1515, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 1516, 191, 192, 1517, 194, 0, 195, 0, 196, 197, - 198, 199, 200, 201, 0, 0, 202, 203, 204, 205, - 0, 0, 206, 207, 1073, 209, 210, 0, 211, 212, - 213, 0, 214, 215, 216, 0, 217, 218, 219, 220, - 0, 222, 223, 224, 225, 226, 227, 0, 0, 229, - 0, 230, 231, 1518, 233, 0, 234, 0, 235, 1519, - 0, 1520, 238, 239, 0, 1521, 242, 0, 243, 0, - 0, 0, 246, 247, 0, 248, 249, 250, 251, 252, - 253, 254, 1522, 256, 257, 258, 259, 0, 260, 261, - 262, 263, 264, 265, 266, 0, 267, 1523, 0, 270, - 271, 272, 273, 274, 1524, 1525, 0, 1526, 0, 278, - 1527, 1528, 281, 1529, 283, 284, 285, 286, 287, 288, - 0, 0, 289, 1530, 291, 1531, 0, 293, 294, 295, - 296, 297, 298, 299, 300, 1532, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 1533, 1534, 1535, 325, - 326, 327, 0, 0, 329, 330, 1536, 332, 0, 0, - 334, 1537, 336, 337, 338, 0, 339, 340, 0, 0, - 341, 342, 343, 0, 0, 344, 345, 0, 1538, 348, - 1539, 0, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 0, 0, 0, 0, 362, 363, 0, - 1540, 366, 367, 0, 369, 370, 371, 0, 372, 373, - 374, 375, 376, 377, 0, 378, 379, 380, 381, 382, - 1541, 384, 385, 386, 387, 0, 388, 389, 390, 391, - 392, 393, 394, 395, 396, 397, 398, 399, 400, 0, - 401, 402, 1542, 404, 405, 406, 1543, 408, 409, 410, - 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, - 0, 1544, 421, 422, 423, 424, 425, 426, 1545, 428, - 429, 0, 1546, 431, 432, 1547, 434, 0, 435, 436, - 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, - 1548, 448, 0, 0, 0, 450, 451, 0, 452, 1549, - 454, 455, 456, 457, 458, 0, 459, 1550, 1551, 0, - 0, 462, 463, 0, 465, 0, 0, 467, 468, 1552, - 470, 471, 472, 473, 474, 1553, 0, 475, 476, 477, - 0, 478, 479, 480, 481, 0, 482, 483, 484, 485, - 486, 0, 1554, 489, 0, 490, 1555, 492, 493, 494, - 495, 496, 497, 498, 0, 0, 499, 0, 0, 500, - 501, 502, 503, 504, 505, 1502, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 517, 518, 519, 520, - 0, 0, 0, 0, 118, 119, 120, 121, 122, 123, - 124, 125, 0, 126, 127, 128, 0, 0, 0, 1503, - 0, 0, 0, 0, 1504, 130, 131, 0, 132, 133, - 134, 1505, 136, 137, 138, 0, 1506, 1507, 1508, 1509, - 0, 144, 145, 146, 147, 148, 149, 0, 0, 150, - 151, 152, 153, 1510, 1511, 156, 0, 157, 158, 159, - 160, 0, 0, 1512, 0, 1513, 164, 165, 166, 167, - 168, 1514, 170, 171, 172, 0, 173, 174, 175, 176, - 177, 178, 0, 1515, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 1516, 191, 192, 1517, 194, 0, - 195, 0, 196, 197, 198, 199, 200, 201, 0, 0, - 202, 203, 204, 205, 0, 0, 206, 207, 1073, 209, - 210, 0, 211, 212, 213, 0, 1863, 215, 216, 0, - 217, 218, 219, 220, 0, 222, 223, 224, 225, 226, - 227, 0, 0, 229, 0, 230, 231, 1518, 233, 0, - 234, 0, 235, 1519, 0, 1520, 238, 239, 0, 1521, - 242, 0, 243, 0, 0, 0, 246, 247, 0, 248, - 249, 250, 251, 252, 253, 254, 1522, 256, 257, 258, - 259, 0, 260, 261, 262, 263, 264, 265, 266, 0, - 267, 1523, 0, 270, 271, 272, 273, 274, 1524, 1525, - 0, 1526, 0, 278, 1527, 1528, 281, 1529, 283, 284, - 285, 286, 287, 288, 0, 0, 289, 1530, 291, 1531, - 0, 293, 294, 295, 296, 297, 298, 299, 300, 1532, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 1533, 1534, 1535, 325, 326, 327, 0, 0, 329, 330, - 1536, 332, 0, 0, 334, 1537, 336, 337, 338, 0, - 339, 340, 0, 0, 341, 342, 343, 0, 0, 344, - 345, 0, 1538, 348, 1539, 0, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 0, 0, 0, - 0, 362, 363, 0, 1540, 366, 367, 0, 369, 370, - 371, 0, 372, 373, 374, 375, 376, 377, 0, 378, - 379, 380, 381, 382, 1541, 384, 385, 386, 387, 0, - 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 0, 401, 402, 1542, 404, 405, 406, - 1543, 408, 409, 410, 411, 412, 413, 414, 415, 416, - 417, 418, 419, 420, 0, 1544, 421, 422, 423, 424, - 425, 426, 1545, 428, 429, 0, 1546, 431, 432, 1547, - 434, 0, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 1548, 448, 0, 0, 0, 450, - 451, 0, 452, 1549, 454, 455, 456, 457, 458, 0, - 459, 1550, 1551, 0, 0, 462, 463, 0, 465, 0, - 0, 467, 468, 1552, 470, 471, 472, 473, 474, 1553, - 0, 475, 476, 477, 0, 478, 479, 480, 481, 0, - 482, 483, 484, 485, 486, 0, 1554, 489, 0, 490, - 1555, 492, 493, 494, 495, 496, 497, 498, 0, 0, - 499, 0, 0, 500, 501, 502, 503, 504, 505, 3233, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 517, 518, 519, 520, 0, 0, 0, 0, 118, 119, - 120, 121, 122, 123, 124, 125, 0, 126, 127, 128, - 0, 0, 0, 2974, 0, 0, 0, 0, 2975, 130, - 131, 0, 132, 133, 134, 2976, 136, 137, 138, 0, - 1506, 2977, 1508, 1509, 0, 144, 145, 146, 147, 148, - 149, 0, 0, 150, 151, 152, 153, 1510, 1511, 156, - 0, 157, 158, 159, 160, 0, 0, 2978, 0, 2979, - 164, 165, 166, 167, 168, 2980, 170, 171, 172, 0, - 173, 174, 175, 176, 177, 178, 0, 2981, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 1516, 191, - 192, 1517, 194, 0, 195, 0, 196, 197, 198, 199, - 200, 201, 0, 0, 202, 203, 204, 205, 0, 0, - 206, 207, 1073, 209, 210, 0, 211, 212, 213, 0, - 214, 215, 216, 0, 217, 218, 219, 220, 0, 222, - 223, 224, 225, 226, 227, 0, 0, 229, 0, 230, - 231, 1518, 233, 0, 234, 0, 235, 2982, 0, 2983, - 238, 239, 2984, 2985, 242, 0, 243, 0, 0, 0, - 246, 247, 0, 248, 249, 250, 251, 252, 253, 254, - 2986, 256, 257, 258, 259, 0, 260, 261, 262, 263, - 264, 265, 266, 0, 267, 2987, 0, 270, 271, 272, - 273, 274, 1524, 1525, 0, 1526, 0, 278, 2988, 2989, - 281, 2990, 283, 284, 285, 286, 287, 288, 0, 0, - 289, 2991, 291, 2992, 0, 293, 294, 295, 296, 297, - 298, 299, 300, 3234, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 1533, 2994, 1535, 325, 326, 327, - 0, 0, 329, 330, 2996, 332, 0, 0, 334, 1537, - 336, 337, 338, 0, 339, 340, 0, 0, 341, 342, - 343, 0, 0, 344, 345, 0, 2998, 348, 2999, 0, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - 361, 0, 0, 0, 0, 362, 363, 0, 3000, 366, - 367, 0, 369, 370, 371, 0, 372, 373, 374, 375, - 376, 377, 0, 378, 379, 380, 381, 382, 1541, 384, - 385, 386, 387, 0, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 0, 401, 402, - 3001, 404, 405, 406, 0, 408, 409, 410, 411, 412, - 413, 414, 415, 416, 417, 418, 419, 420, 0, 3002, - 421, 422, 423, 424, 425, 426, 0, 428, 429, 0, - 3004, 431, 432, 1547, 434, 0, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, 3235, 448, - 0, 0, 0, 450, 451, 0, 452, 3006, 454, 455, - 456, 457, 458, 0, 459, 1550, 1551, 0, 0, 462, - 463, 0, 465, 0, 0, 467, 468, 3007, 470, 471, - 472, 473, 474, 0, 0, 475, 476, 477, 0, 478, - 479, 480, 481, 0, 482, 483, 484, 485, 486, 0, - 1554, 489, 0, 490, 3009, 492, 493, 494, 495, 496, - 497, 498, 0, 0, 499, 0, 0, 500, 501, 502, - 503, 504, 505, 528, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 517, 518, 519, 520, 0, 0, - 0, 0, 118, 119, 120, 121, 122, 123, 124, 125, - 0, 126, 127, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 130, 131, 0, 132, 133, 134, 0, - 136, 137, 138, 139, 140, 0, 142, 143, 0, 144, - 145, 146, 147, 148, 149, 0, 0, 150, 151, 152, - 153, 154, 155, 156, 0, 157, 158, 159, 160, 161, - 0, 0, 0, 163, 164, 165, 166, 167, 168, 0, - 170, 171, 172, 0, 173, 174, 175, 176, 177, 178, - 0, 0, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 0, 195, 0, - 196, 197, 198, 199, 200, 201, 0, 0, 202, 203, - 204, 205, 0, 0, 206, 207, 208, 209, 210, 0, - 211, 212, 213, 0, 214, 215, 216, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 0, 229, 0, 230, 231, 232, 233, 0, 234, 0, - 235, 0, 0, 0, 238, 239, 529, 0, 242, 0, - 243, 0, 244, 245, 0, 247, 0, 248, 249, 250, - 251, 252, 253, 254, 0, 256, 257, 258, 259, 0, - 260, 261, 262, 263, 264, 265, 266, 0, 267, 0, - 269, 270, 271, 272, 273, 274, 275, 276, 0, 277, - 0, 278, 0, 0, 281, 0, 283, 284, 285, 286, - 287, 288, 0, 0, 289, 0, 291, 0, 0, 293, - 294, 295, 296, 297, 298, 299, 300, 530, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 0, - 324, 325, 326, 327, 328, 0, 329, 330, 0, 332, - 0, 333, 334, 335, 336, 337, 338, 0, 339, 340, - 0, 0, 341, 342, 343, 0, 0, 344, 345, 346, - 0, 348, 0, 350, 351, 352, 353, 354, 355, 356, - 0, 358, 359, 360, 361, 0, 0, 0, 0, 362, - 363, 364, 0, 366, 367, 368, 369, 370, 371, 0, - 372, 373, 374, 375, 376, 377, 0, 378, 379, 380, - 0, 382, 383, 384, 385, 386, 387, 0, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, - 400, 0, 401, 402, 0, 404, 405, 406, 407, 0, - 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, - 419, 420, 0, 0, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 0, 0, 431, 432, 433, 434, 0, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 531, 448, 449, 0, 0, 450, 451, 0, - 452, 0, 454, 455, 456, 457, 458, 0, 459, 460, - 461, 0, 0, 462, 463, 464, 465, 466, 0, 467, - 468, 469, 470, 471, 472, 473, 474, 0, 0, 475, - 476, 477, 0, 478, 479, 480, 481, 0, 482, 483, - 484, 485, 486, 487, 488, 489, 0, 490, 0, 492, - 493, 494, 495, 496, 497, 498, 0, 0, 499, 0, - 0, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 1797, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 118, 119, 120, 121, 122, 123, 124, 125, 0, - 126, 127, 128, 0, 0, 0, 1503, 0, 0, 0, - 0, 1504, 130, 131, 0, 132, 133, 134, 1505, 136, - 137, 138, 0, 1506, 1507, 1508, 1509, 0, 144, 145, - 146, 147, 148, 149, 0, 0, 150, 151, 152, 153, - 1510, 1511, 156, 0, 157, 158, 159, 160, 0, 0, - 1512, 0, 1513, 164, 165, 166, 167, 168, 1514, 170, - 171, 172, 0, 173, 174, 175, 176, 177, 178, 0, - 1515, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 1516, 191, 192, 1517, 194, 0, 195, 0, 196, - 197, 198, 199, 200, 201, 0, 0, 202, 203, 204, - 205, 0, 0, 206, 207, 1073, 209, 210, 0, 211, - 212, 213, 0, 214, 215, 216, 0, 217, 218, 219, - 220, 0, 222, 223, 224, 225, 226, 227, 0, 0, - 229, 0, 230, 231, 1518, 233, 0, 234, 0, 235, - 1519, 0, 1520, 238, 239, 0, 1521, 242, 0, 243, - 0, 0, 0, 246, 247, 0, 248, 249, 250, 251, - 252, 253, 254, 1522, 256, 257, 258, 259, 0, 260, - 261, 262, 263, 264, 265, 266, 0, 267, 1523, 0, - 270, 271, 272, 273, 274, 1524, 1525, 0, 1526, 0, - 278, 1527, 1528, 281, 1529, 283, 284, 285, 286, 287, - 288, 0, 0, 289, 1530, 291, 1531, 0, 293, 294, - 295, 296, 297, 298, 299, 300, 0, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 1533, 1534, 1535, - 325, 326, 327, 0, 0, 329, 330, 1536, 332, 0, - 0, 334, 1537, 336, 337, 338, 0, 339, 340, 0, - 0, 341, 342, 343, 0, 0, 344, 345, 0, 1538, - 348, 1539, 0, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, 361, 0, 0, 0, 0, 362, 363, - 0, 1540, 366, 367, 0, 369, 370, 371, 0, 372, - 373, 374, 375, 376, 377, 0, 378, 379, 380, 381, - 382, 1541, 384, 385, 386, 387, 0, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, - 0, 401, 402, 1542, 404, 405, 406, 0, 408, 409, - 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, - 420, 0, 1544, 421, 422, 423, 424, 425, 426, 0, - 428, 429, 0, 1546, 431, 432, 1547, 434, 0, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 0, 448, 0, 0, 0, 450, 451, 0, 452, - 1549, 454, 455, 456, 457, 458, 0, 459, 1550, 1551, - 0, 0, 462, 463, 0, 465, 0, 0, 467, 468, - 1552, 470, 471, 472, 473, 474, 0, 0, 475, 476, - 477, 0, 478, 479, 480, 481, 0, 482, 483, 484, - 485, 486, 0, 1554, 489, 0, 490, 1555, 492, 493, - 494, 495, 496, 497, 498, 0, 1, 499, 0, 0, - 500, 501, 502, 503, 504, 505, 2, 0, 3, 4, - 0, 0, 0, 0, 1, 0, 0, 517, 518, 519, - 520, 0, 0, 0, 2, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 0, 0, 0, 8, - 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, - 10, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 0, 11, 0, 751, 0, 0, 0, 10, 0, - 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 11, 0, 751, 0, 0, 0, 0, 0, 0, 0, - 14, 15, 0, 13, 0, 0, 0, 0, 0, 0, - 0, 752, 0, 0, 0, 0, 0, 18, 14, 15, - 0, 0, 0, 0, 0, 19, 0, 0, 0, 752, - 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, - 0, 0, 22, 19, 0, 0, 23, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 22, 0, 0, 0, 23, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -1468, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1468, 0, 0, 0, - 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, - 27, 28, 0, 0, 0, 0, 0, 29, 0, 0, - 30, 0, 0, 0, 0, 0, 0, 26, 27, 28, - 0, 0, 0, 0, 0, 29, 0, 0, 30, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 31, - 0, 0, 0, 0, 0, 0, 33, 0, 32, 0, - 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, - 0, 0, 0, 0, 33, 0, 0, 36, 0, 0, - 0, 34, 0, 0, 0, 35, 0, 0, 0, 37, - 0, 0, 0, 38, 0, 36, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, - 0, 38, 0, 39, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, - 0, 39, 42, 0, 0, 0, 0, 43, 0, 0, - 0, 0, 753, 0, 40, 0, 0, 0, 0, 0, - 42, 0, 0, 0, 44, 43, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 44, 0, 0, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 754, 0, 0, 0, 45, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 46 -}; - -static const yytype_int16 yycheck[] = -{ - 7, 521, 46, 0, 0, 0, 0, 0, 0, 16, - 0, 0, 841, 888, 0, 746, 23, 0, 73, 903, - 815, 1443, 930, 7, 914, 999, 38, 0, 1256, 1459, - 1242, 1045, 1230, 965, 20, 754, 935, 20, 1720, 23, - 16, 1217, 1244, 1683, 1093, 7, 1175, 2221, 20, 990, - 1495, 1828, 990, 1612, 1836, 1321, 865, 1655, 1574, 77, - 2280, 23, 990, 980, 37, 1298, 1600, 1222, 75, 76, - 2029, 969, 2368, 23, 1210, 990, 2211, 980, 0, 77, - 17, 1219, 0, 2717, 0, 2190, 0, 2192, 1636, 1637, - 0, 75, 76, 0, 0, 2680, 0, 1140, 1346, 111, - 0, 0, 1145, 45, 0, 2276, 903, 0, 905, 1247, - 907, 2715, 0, 75, 76, 2680, 0, 34, 1008, 2156, - 2740, 2210, 754, 753, 747, 75, 76, 1101, 101, 810, - 0, 2733, 0, 0, 2547, 816, 2348, 0, 0, 5, - 1687, 0, 0, 75, 76, 2634, 1853, 13, 14, 2638, - 1850, 0, 5, 2030, 9, 0, 1738, 5, 9, 0, - 1967, 4, 1740, 1067, 1068, 2847, 9, 10, 63, 0, - 5, 3062, 5, 55, 0, 5, 9, 778, 2356, 988, - 1084, 45, 63, 5, 2360, 2360, 2354, 5, 80, 74, - 5, 5, 26, 5, 9, 5, 991, 1849, 2369, 13, - 14, 139, 5, 5, 997, 5, 5, 5, 45, 5, - 5, 5, 5, 13, 14, 13, 14, 13, 14, 1655, - 173, 3, 4, 5, 122, 13, 14, 9, 13, 14, - 4, 107, 82, 23, 1151, 9, 119, 4, 82, 860, - 3048, 11, 9, 93, 883, 147, 16, 1046, 172, 93, - 122, 1265, 2423, 2424, 30, 2426, 883, 3065, 90, 100, - 1274, 980, 38, 11, 2003, 2004, 104, 1157, 16, 3238, - 191, 40, 63, 3, 100, 2014, 1184, 63, 124, 2018, - 122, 172, 288, 2902, 169, 75, 76, 807, 11, 2493, - 172, 1100, 15, 16, 172, 296, 3018, 129, 46, 1071, - 5, 107, 173, 137, 34, 35, 53, 2883, 290, 2885, - 291, 992, 245, 805, 1231, 1087, 218, 1234, 1235, 2596, - 117, 2598, 291, 1004, 184, 1995, 1996, 1997, 107, 1458, - 5, 132, 80, 296, 854, 117, 245, 193, 30, 193, - 3370, 213, 119, 181, 11, 181, 38, 1545, 15, 16, - 276, 106, 1151, 983, 64, 3, 40, 5, 368, 166, - 382, 313, 391, 3400, 74, 3167, 1495, 3169, 345, 40, - 2475, 213, 3433, 41, 1640, 162, 1205, 1206, 279, 46, - 13, 14, 2650, 30, 3476, 119, 164, 108, 83, 30, - 482, 38, 117, 457, 296, 122, 3328, 480, 3330, 30, - 1209, 11, 2179, 482, 3565, 409, 120, 384, 507, 148, - 137, 1204, 504, 80, 794, 1937, 82, 369, 3003, 518, - 359, 504, 120, 3057, 1332, 504, 518, 93, 1303, 2649, - 177, 1230, 812, 3463, 3068, 273, 3466, 219, 309, 518, - 373, 171, 419, 173, 329, 3606, 1968, 194, 2622, 290, - 389, 238, 199, 148, 518, 3059, 3264, 132, 126, 241, - 294, 200, 1361, 3524, 290, 360, 191, 273, 472, 3561, - 80, 192, 3404, 207, 275, 2646, 308, 2648, 3369, 360, - 340, 195, 273, 280, 285, 160, 2754, 3289, 3525, 518, - 237, 132, 176, 470, 272, 396, 251, 195, 2535, 355, - 522, 132, 1551, 280, 358, 176, 261, 431, 518, 369, - 2787, 1777, 518, 2948, 3236, 3091, 485, 324, 451, 507, - 361, 522, 1321, 357, 395, 359, 1018, 1023, 454, 3559, - 3499, 241, 520, 1029, 167, 361, 518, 518, 476, 273, - 431, 275, 451, 419, 2103, 447, 2328, 2329, 2330, 11, - 275, 2729, 416, 15, 16, 389, 454, 178, 2726, 522, - 1181, 513, 3181, 448, 2162, 518, 539, 1168, 1207, 360, - 2746, 2746, 13, 3464, 360, 280, 459, 2022, 19, 416, - 1207, 431, 454, 507, 46, 518, 593, 431, 1108, 30, - 428, 469, 424, 2764, 373, 1771, 520, 518, 389, 2803, - 275, 328, 1835, 44, 45, 280, 1510, 1511, 513, 518, - 285, 457, 454, 482, 1345, 520, 2575, 593, 80, 1350, - 241, 457, 2156, 399, 516, 1356, 2433, 522, 520, 290, - 3312, 1535, 467, 11, 1463, 504, 518, 15, 16, 480, - 1449, 522, 1435, 1436, 1363, 2227, 2194, 394, 1441, 1897, - 2228, 3253, 518, 3238, 480, 1484, 108, 3465, 509, 510, - 132, 527, 517, 1929, 2371, 518, 2366, 2214, 109, 1871, - 518, 1685, 521, 3238, 527, 1941, 521, 522, 519, 482, - 521, 524, 525, 518, 1912, 518, 2220, 518, 518, 482, - 521, 1595, 1596, 519, 516, 521, 518, 3186, 520, 2919, - 518, 504, 3191, 518, 518, 1971, 518, 399, 518, 2361, - 754, 504, 1978, 480, 2926, 518, 518, 164, 518, 518, - 518, 3134, 518, 518, 518, 518, 2162, 509, 510, 1352, - 518, 1363, 1362, 518, 3368, 509, 510, 504, 468, 1629, - 1630, 1631, 509, 510, 514, 1517, 1545, 754, 11, 3045, - 2489, 520, 399, 2019, 33, 457, 3376, 2023, 406, 407, - 3195, 805, 162, 438, 75, 1537, 514, 753, 1577, 1578, - 753, 266, 275, 3375, 449, 1456, 227, 280, 1587, 3214, - 59, 433, 754, 46, 231, 149, 2052, 794, 511, 512, - 513, 514, 1601, 1448, 2027, 1450, 1451, 132, 805, 1571, - 812, 997, 423, 345, 425, 812, 2476, 2477, 2478, 2479, - 794, 2900, 26, 285, 26, 2597, 518, 80, 32, 2778, - 32, 805, 273, 1632, 162, 160, 321, 108, 812, 167, - 451, 483, 794, 888, 841, 842, 339, 201, 238, 857, - 3474, 1640, 384, 805, 511, 512, 513, 514, 860, 250, - 812, 1980, 3426, 3427, 2953, 805, 3460, 513, 865, 857, - 82, 916, 2961, 162, 520, 1879, 878, 1578, 167, 2906, - 418, 93, 419, 805, 275, 3046, 1587, 419, 875, 875, - 875, 875, 875, 875, 1801, 875, 875, 287, 1681, 875, - 341, 863, 875, 2022, 1811, 2493, 519, 1814, 227, 522, - 238, 518, 875, 2862, 3478, 912, 913, 5, 456, 916, - 917, 517, 1796, 3517, 3499, 516, 26, 523, 2695, 520, - 2697, 1652, 32, 137, 866, 137, 843, 844, 470, 846, - 517, 848, 2180, 1726, 3499, 2812, 523, 4, 2815, 238, - 2817, 392, 9, 4, 273, 280, 0, 1990, 9, 287, - 285, 3585, 521, 875, 1829, 1830, 1831, 875, 1857, 875, - 522, 875, 969, 1895, 3260, 875, 468, 1899, 875, 875, - 1902, 875, 1769, 980, 1018, 875, 875, 3197, 1777, 875, - 987, 988, 875, 245, 13, 14, 993, 875, 287, 996, - 997, 875, 999, 1000, 1001, 1002, 1913, 983, 935, 1796, - 983, 2535, 275, 454, 794, 875, 1904, 875, 875, 1016, - 1913, 1018, 875, 875, 2562, 805, 875, 875, 4, 1816, - 1027, 214, 812, 9, 1821, 5, 203, 137, 126, 127, - 518, 516, 1016, 2455, 1018, 520, 516, 1044, 1045, 1046, - 520, 1028, 3177, 1027, 2474, 1032, 341, 509, 510, 511, - 512, 513, 514, 518, 1016, 519, 1018, 1101, 522, 1066, - 2196, 519, 2198, 392, 522, 1027, 1016, 245, 1018, 108, - 843, 844, 37, 846, 172, 848, 1807, 1027, 1085, 355, - 294, 1812, 294, 516, 1016, 518, 1018, 520, 2604, 1096, - 1097, 1098, 380, 1100, 1101, 1027, 1103, 2874, 1618, 71, - 72, 2334, 2304, 438, 203, 519, 516, 2373, 522, 380, - 520, 373, 74, 523, 449, 556, 132, 828, 829, 830, - 252, 2250, 833, 3343, 436, 454, 3085, 1103, 419, 1136, - 1929, 509, 510, 511, 512, 513, 514, 245, 423, 353, - 425, 353, 1941, 357, 160, 357, 2680, 1154, 1155, 1942, - 1943, 1944, 1945, 1946, 1947, 117, 470, 1950, 1951, 1952, - 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1976, 377, 1181, - 1188, 1189, 1971, 1191, 2312, 389, 423, 389, 425, 1978, - 167, 189, 190, 1190, 294, 380, 30, 1194, 1195, 451, - 1188, 1189, 518, 1191, 1913, 373, 373, 1204, 1205, 1206, - 178, 245, 1209, 245, 172, 2803, 519, 384, 173, 522, - 511, 519, 2186, 174, 522, 13, 14, 315, 316, 317, - 2019, 13, 14, 1230, 2023, 2380, 1016, 523, 1018, 1920, - 2029, 2386, 519, 1924, 1246, 522, 1927, 1027, 518, 1435, - 1436, 85, 419, 2509, 209, 1441, 460, 357, 460, 518, - 94, 259, 260, 2052, 518, 2064, 518, 3039, 1265, 275, - 225, 13, 14, 241, 280, 373, 26, 1274, 519, 285, - 235, 522, 32, 451, 118, 519, 13, 14, 522, 389, - 2839, 26, 13, 14, 382, 246, 26, 32, 516, 518, - 518, 1298, 32, 470, 518, 393, 519, 8, 519, 522, - 11, 522, 504, 519, 15, 16, 522, 748, 19, 20, - 21, 224, 519, 275, 1321, 522, 2191, 415, 280, 519, - 518, 419, 522, 25, 1320, 1320, 1320, 1320, 518, 373, - 1337, 373, 518, 2142, 259, 260, 2781, 501, 519, 1346, - 518, 522, 518, 451, 2137, 2138, 480, 191, 482, 59, - 460, 2283, 519, 2285, 452, 522, 1363, 3577, 26, 518, - 204, 1337, 2491, 518, 32, 463, 2495, 329, 13, 14, - 378, 379, 2906, 1380, 13, 14, 1362, 137, 1385, 1362, - 519, 147, 480, 522, 345, 347, 519, 290, 3562, 522, - 3564, 1363, 137, 13, 14, 373, 162, 137, 520, 364, - 519, 167, 519, 522, 1380, 522, 504, 451, 519, 451, - 518, 522, 519, 115, 2680, 522, 519, 501, 383, 522, - 518, 171, 438, 384, 3529, 866, 2255, 519, 1435, 1436, - 522, 3605, 519, 449, 1441, 522, 1443, 519, 518, 3544, - 522, 1448, 1449, 1450, 1451, 423, 519, 425, 522, 522, - 2662, 2359, 218, 378, 379, 519, 1463, 1464, 419, 1443, - 2253, 2663, 172, 13, 14, 1472, 2694, 1474, 519, 137, - 1477, 2647, 238, 451, 518, 1482, 518, 1484, 1485, 519, - 1487, 1443, 522, 423, 1491, 425, 448, 423, 1472, 425, - 1474, 2540, 2541, 1477, 3599, 457, 519, 2709, 1482, 3604, - 172, 1485, 519, 1487, 295, 522, 2661, 1491, 2663, 470, - 1472, 222, 1474, 519, 519, 1477, 522, 522, 13, 14, - 1482, 287, 1472, 1485, 1474, 1487, 59, 1477, 519, 1491, - 296, 522, 1482, 518, 294, 1485, 420, 1487, 1545, 37, - 1472, 1491, 1474, 501, 3321, 1477, 3323, 224, 519, 294, - 1482, 522, 152, 1485, 294, 1487, 2286, 353, 2288, 1491, - 519, 405, 519, 522, 408, 522, 519, 13, 14, 522, - 1577, 1578, 40, 2547, 2373, 152, 2517, 1574, 2516, 1586, - 1587, 292, 1574, 152, 1574, 1574, 152, 1594, 1574, 2517, - 2518, 1574, 152, 353, 1601, 419, 174, 357, 2646, 2408, - 2648, 1574, 2517, 2518, 2519, 315, 316, 317, 353, 13, - 14, 8, 357, 353, 11, 13, 14, 357, 15, 16, - 1627, 1628, 19, 20, 21, 1632, 294, 519, 1635, 389, - 1685, 13, 14, 1640, 1641, 1642, 1643, 1644, 1645, 1646, - 1647, 1648, 1649, 880, 389, 882, 1653, 1654, 1655, 389, - 518, 1658, 275, 1443, 40, 1662, 13, 14, 1665, 1666, - 1667, 1668, 1669, 1670, 1671, 1672, 1673, 470, 246, 1676, - 2401, 1655, 382, 1649, 89, 173, 1683, 152, 1685, 13, - 14, 447, 1472, 484, 1474, 353, 152, 1477, 520, 357, - 2409, 3331, 1482, 13, 14, 1485, 1703, 1487, 1046, 152, - 460, 1491, 147, 2969, 3238, 1723, 13, 14, 178, 419, - 2509, 209, 13, 14, 152, 460, 290, 162, 355, 1726, - 460, 389, 167, 2613, 431, 1723, 519, 225, 518, 1701, - 1737, 1738, 518, 1174, 13, 14, 518, 235, 13, 14, - 13, 14, 452, 518, 2920, 421, 1942, 1943, 1944, 1945, - 1946, 1947, 300, 463, 1950, 1951, 1952, 1953, 1954, 1955, - 1956, 1957, 1958, 1959, 225, 2967, 220, 345, 13, 14, - 1777, 241, 518, 218, 13, 14, 2575, 368, 369, 1786, - 518, 1788, 368, 369, 368, 369, 2579, 2580, 368, 369, - 263, 264, 460, 238, 505, 506, 507, 225, 509, 510, - 511, 512, 513, 514, 225, 3003, 384, 2636, 518, 297, - 1786, 1014, 1788, 378, 379, 3043, 1019, 1020, 1021, 462, - 463, 1828, 2721, 40, 40, 2757, 2701, 236, 1835, 2391, - 2392, 1838, 1839, 1036, 6, 2743, 518, 1040, 10, 3571, - 3572, 419, 287, 60, 314, 3527, 18, 3539, 3540, 3531, - 5, 296, 1154, 1155, 2262, 2263, 5, 518, 3280, 518, - 32, 2875, 3128, 325, 36, 518, 364, 518, 5, 5, - 518, 5, 1879, 5, 518, 481, 9, 518, 518, 302, - 522, 2680, 1230, 104, 522, 383, 519, 40, 220, 106, - 1897, 167, 470, 389, 287, 292, 167, 1904, 1905, 59, - 285, 236, 1875, 373, 3586, 518, 1913, 431, 518, 93, - 380, 522, 1353, 431, 1355, 59, 59, 431, 266, 431, - 108, 523, 1929, 222, 431, 431, 1933, 1934, 480, 1936, - 380, 100, 152, 275, 1941, 1942, 1943, 1944, 1945, 1946, - 1947, 2137, 2138, 1950, 1951, 1952, 1953, 1954, 1955, 1956, - 1957, 1958, 1959, 423, 275, 425, 199, 275, 1965, 1966, - 518, 40, 1969, 275, 1971, 3499, 275, 518, 82, 1976, - 152, 1978, 3238, 1321, 172, 520, 13, 519, 0, 2778, - 519, 451, 2775, 172, 519, 202, 522, 519, 519, 519, - 519, 518, 477, 2000, 108, 225, 519, 225, 2005, 282, - 2007, 282, 447, 518, 2011, 518, 522, 2800, 467, 520, - 518, 3433, 2019, 518, 518, 518, 2023, 26, 2025, 518, - 2027, 2005, 2029, 32, 39, 518, 520, 2011, 476, 9, - 429, 40, 11, 429, 251, 518, 355, 3249, 2970, 2971, - 517, 2958, 522, 2005, 261, 2052, 528, 523, 522, 2011, - 429, 60, 181, 3475, 3484, 2005, 273, 2064, 2065, 431, - 174, 2011, 280, 2862, 163, 172, 518, 522, 519, 457, - 218, 516, 266, 2005, 519, 520, 392, 2808, 100, 2011, - 522, 227, 291, 522, 313, 522, 788, 313, 305, 203, - 181, 518, 220, 519, 275, 2102, 227, 106, 2142, 2106, - 227, 296, 3524, 282, 2111, 2112, 282, 519, 505, 506, - 507, 334, 509, 510, 511, 512, 513, 514, 820, 470, - 288, 152, 3, 518, 518, 147, 3100, 518, 137, 152, - 2137, 2138, 246, 152, 152, 2142, 37, 3365, 152, 480, - 162, 42, 359, 845, 522, 167, 522, 40, 2941, 275, - 172, 2158, 290, 3, 2161, 2162, 2163, 997, 40, 181, - 290, 59, 172, 11, 186, 40, 167, 384, 181, 519, - 2969, 518, 2179, 2180, 519, 3304, 519, 167, 2162, 2186, - 519, 518, 2189, 3, 39, 518, 403, 3, 516, 516, - 431, 893, 517, 202, 431, 431, 218, 1545, 431, 2206, - 101, 353, 519, 501, 3003, 2189, 519, 522, 2939, 519, - 501, 40, 2219, 519, 528, 2005, 238, 520, 520, 519, - 148, 2011, 2206, 519, 519, 519, 519, 2189, 172, 2236, - 2237, 60, 501, 3499, 518, 431, 518, 155, 518, 2189, - 518, 518, 251, 250, 2206, 477, 2253, 40, 2255, 59, - 522, 507, 261, 503, 454, 291, 2206, 291, 522, 373, - 244, 2268, 59, 59, 273, 287, 266, 469, 290, 431, - 384, 275, 173, 178, 296, 152, 518, 106, 980, 2286, - 2287, 2288, 203, 152, 152, 294, 3085, 518, 990, 431, - 431, 3084, 1640, 40, 519, 355, 305, 519, 203, 518, - 3502, 288, 519, 480, 290, 419, 431, 3215, 209, 431, - 2286, 2287, 2288, 40, 336, 522, 152, 527, 2325, 280, - 2364, 172, 519, 59, 225, 518, 518, 2334, 442, 3128, - 186, 1772, 519, 519, 235, 167, 241, 80, 516, 361, - 143, 1782, 522, 1784, 353, 519, 1787, 176, 357, 519, - 359, 522, 1793, 519, 1795, 1195, 470, 2353, 2353, 2353, - 2353, 2368, 3081, 519, 1204, 199, 2373, 1808, 269, 519, - 172, 518, 1813, 202, 519, 384, 1817, 1818, 1819, 1820, - 389, 1822, 1823, 2579, 2580, 301, 2393, 361, 523, 290, - 295, 291, 2368, 2913, 403, 518, 181, 419, 522, 2189, - 519, 2408, 2409, 518, 152, 522, 519, 519, 1110, 314, - 2417, 176, 518, 442, 315, 519, 2206, 519, 1120, 519, - 518, 322, 251, 520, 518, 447, 519, 522, 518, 1777, - 40, 86, 261, 40, 40, 457, 457, 522, 172, 3238, - 1142, 2417, 518, 3333, 273, 519, 479, 519, 2455, 1151, - 199, 460, 519, 517, 517, 477, 522, 479, 480, 290, - 519, 519, 519, 364, 519, 463, 507, 59, 373, 519, - 519, 2455, 519, 3302, 519, 380, 305, 8, 480, 205, - 11, 3290, 383, 3292, 15, 16, 2493, 117, 19, 20, - 21, 40, 518, 2455, 516, 227, 192, 519, 520, 521, - 88, 280, 2509, 2547, 280, 431, 431, 3300, 520, 2521, - 3305, 519, 3307, 507, 520, 520, 3490, 520, 423, 2526, - 425, 520, 517, 520, 520, 2532, 2533, 3435, 520, 520, - 359, 520, 520, 40, 517, 2590, 275, 442, 520, 520, - 2547, 2585, 520, 448, 520, 520, 451, 520, 520, 520, - 3425, 452, 520, 520, 520, 384, 2563, 520, 520, 2566, - 3444, 2568, 520, 520, 520, 520, 520, 520, 2575, 2576, - 520, 519, 2579, 2580, 403, 107, 519, 2584, 2585, 2775, - 518, 1929, 518, 480, 2591, 290, 419, 518, 9, 3418, - 1046, 354, 2636, 1941, 518, 1435, 1436, 59, 518, 2606, - 522, 1441, 199, 336, 519, 522, 519, 2604, 517, 2616, - 522, 519, 2604, 192, 2604, 2604, 7, 8, 2604, 37, - 522, 2604, 13, 1971, 42, 462, 91, 519, 19, 2636, - 1978, 2604, 23, 347, 25, 518, 40, 2610, 29, 30, - 31, 152, 117, 34, 520, 519, 37, 38, 124, 152, - 41, 40, 519, 44, 45, 519, 172, 369, 369, 518, - 40, 518, 40, 457, 522, 2455, 518, 310, 199, 518, - 2677, 2019, 280, 2680, 2681, 2023, 2683, 1379, 249, 191, - 457, 2029, 442, 101, 75, 76, 178, 74, 2695, 293, - 2697, 222, 518, 74, 80, 74, 9, 172, 519, 80, - 3499, 2677, 519, 518, 2052, 2681, 371, 2683, 2752, 517, - 101, 203, 93, 519, 59, 507, 517, 108, 109, 110, - 111, 112, 93, 133, 2720, 2720, 2720, 2720, 273, 290, - 40, 518, 442, 293, 293, 518, 117, 519, 119, 519, - 462, 3472, 205, 2716, 519, 2941, 290, 290, 519, 241, - 389, 454, 122, 980, 368, 173, 2800, 25, 148, 36, - 2201, 292, 147, 181, 298, 368, 875, 2664, 2775, 1794, - 2281, 2778, 2745, 8, 1230, 3335, 11, 162, 3475, 3429, - 15, 16, 167, 2677, 19, 20, 21, 2614, 2795, 2796, - 3576, 209, 1904, 2800, 2963, 178, 2803, 2396, 852, 315, - 316, 317, 8, 295, 3450, 11, 3554, 225, 3208, 15, - 16, 3503, 3512, 19, 20, 21, 1217, 235, 3547, 3266, - 203, 2274, 2734, 2830, 2287, 3501, 207, 2656, 3510, 304, - 36, 2683, 2271, 218, 3498, 1345, 2391, 1318, 2392, 2352, - 315, 316, 317, 2850, 2417, 3081, 2711, 2253, 1174, 2856, - 2857, 269, 2896, 238, 2861, 2862, 1015, 1015, 241, 2866, - 2219, 40, 2869, 2870, 1762, 1321, 382, 2874, 2875, 1198, - 2474, 2878, 290, 1197, 3484, 2882, 2236, 3397, 1726, 3406, - 3294, 60, 2889, 1761, 23, 2206, 1726, 2017, 3084, 1200, - 2803, 3123, 2455, 1120, 275, 2454, 992, 315, 2882, 280, - 3229, 2501, 287, 419, 322, 2032, 2969, 382, 990, 990, - 990, 296, 295, 990, 1913, 990, 1913, 990, 1913, 990, - 2882, 990, 990, 3410, 1151, 3409, 2933, 106, 107, 2113, - 2533, 423, 2882, 425, 2941, 2162, 452, 2220, 117, 2159, - 2066, 2889, 2383, 2851, 419, 1464, 364, 463, 329, 2115, - 2882, 2559, 3395, 2960, 2604, 1841, 448, 1363, 893, 451, - 2025, 789, 2969, 2853, 199, 383, 347, 1701, 1254, 2615, - 1702, 2324, -1, -1, 505, 506, 507, 452, 509, 510, - 511, 512, 513, 514, -1, -1, -1, 222, 463, -1, - 373, 1693, -1, -1, -1, -1, 3003, 176, -1, -1, - -1, -1, 518, -1, 1231, 480, -1, 1234, 1235, -1, - -1, -1, -1, -1, -1, -1, 222, -1, -1, -1, - -1, -1, -1, 202, -1, 2373, -1, -1, -1, 504, - -1, -1, -1, -1, 452, -1, -1, -1, 3045, 457, - 423, -1, 425, 518, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3100, 292, -1, 442, - -1, -1, 447, 1765, 1766, 448, 3073, 448, 451, 3045, - -1, -1, 251, -1, 3081, -1, 457, 3084, 3085, -1, - -1, -1, 261, -1, -1, -1, 292, 3060, -1, 1545, - -1, -1, 2882, 3100, 273, -1, 275, -1, -1, -1, - -1, -1, 1942, 1943, 1944, 1945, 1946, 1947, -1, -1, - 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, - -1, 3128, 1824, -1, 172, -1, 305, 3134, -1, -1, - -1, 516, -1, -1, -1, 520, -1, -1, 1840, 1841, - -1, 1368, 1369, -1, 3151, 3152, -1, -1, 3155, 540, - 3157, -1, -1, -1, 545, -1, -1, 548, -1, -1, - -1, 2509, -1, -1, -1, 556, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3182, -1, -1, -1, -1, - 359, -1, -1, -1, 1640, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 8, -1, -1, 2639, 3206, - -1, 2642, 15, 16, -1, 384, 19, 20, 21, -1, - -1, 1913, -1, -1, -1, -1, -1, 1919, -1, -1, - -1, -1, -1, -1, 403, -1, 405, 2575, 2669, 408, - -1, 3238, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2684, 2685, 2686, 2687, 2688, 2689, 2690, - 2691, 2692, 2693, 3260, -1, -1, 126, 127, 37, -1, - -1, -1, 41, -1, -1, -1, -1, 315, 316, 317, - 505, 506, 507, 3280, 509, 510, 511, 512, 513, 514, - -1, -1, 3255, 3290, 3260, 3292, -1, 3294, -1, -1, - -1, 3298, -1, 3300, -1, 3302, 3280, 2137, 2138, 505, - 506, 507, 172, 509, 510, 511, 512, 513, 514, 3316, - -1, -1, -1, -1, 3321, -1, 3323, -1, 3280, -1, - -1, 1777, 101, -1, 3331, -1, -1, -1, -1, 108, - -1, 110, 2680, 112, 382, -1, -1, 3344, -1, 518, - -1, -1, 3349, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 746, 747, 748, -1, 3332, - -1, 3334, -1, -1, -1, 1592, -1, -1, 3344, -1, - -1, 419, -1, -1, -1, -1, -1, 1604, -1, 1606, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3396, - -1, -1, -1, 1046, -1, -1, -1, 788, 789, 3406, - -1, 3374, -1, 794, 452, 796, -1, 1634, -1, -1, - -1, 3418, -1, 2253, 805, 463, -1, 3390, 809, 810, - -1, 812, -1, -1, 815, 816, 3433, -1, -1, -1, - 2778, -1, 480, -1, -1, -1, -1, 828, 829, 830, - -1, -1, 833, -1, 3451, 315, 316, 317, 55, 3433, - 841, 842, 843, 844, -1, 846, 504, 848, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3475, 860, - 518, 3433, -1, 1929, -1, 866, -1, -1, -1, 292, - -1, -1, -1, 3490, -1, 1941, -1, 878, -1, -1, - 3280, 3475, 3499, -1, 3501, 102, -1, -1, -1, 2940, - -1, 892, 893, -1, -1, -1, -1, -1, -1, -1, - 1737, 1738, 382, 3475, 2862, 1971, 123, 3524, 151, -1, - -1, -1, 1978, 393, -1, 3501, -1, -1, -1, -1, - -1, 3538, 3539, 3540, 141, -1, 927, 928, 145, 172, - 3524, -1, -1, 3516, -1, 415, -1, -1, 939, 419, - -1, -1, 943, 944, 945, 946, -1, -1, 3565, -1, - -1, 168, 3524, 2019, 171, -1, -1, 2023, 959, 3542, - -1, -1, -1, 2029, 1801, -1, -1, 1230, -1, -1, - 187, -1, 452, -1, 1811, -1, -1, 1814, -1, -1, - -1, 2293, -1, 463, -1, -1, 2052, -1, 1046, 3606, - 991, 992, -1, 994, -1, -1, 997, 1046, -1, -1, - 480, -1, 1003, 1004, -1, -1, -1, -1, -1, 1010, - -1, 2969, -1, -1, -1, 1016, -1, 1018, -1, 0, - -1, -1, -1, -1, 504, -1, 1027, -1, -1, -1, - -1, -1, -1, 3433, 2346, -1, 1037, -1, 518, 20, - -1, -1, 23, -1, -1, 3003, -1, -1, -1, -1, - -1, -1, 2364, 1054, -1, 37, 37, -1, 1321, -1, - 42, -1, -1, 280, -1, 46, -1, -1, -1, -1, - -1, 288, 315, 316, 317, 3475, 1913, -1, -1, -1, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, 310, 75, 76, 77, 2409, -1, -1, - -1, -1, -1, -1, 1105, -1, -1, 2419, -1, 2421, - -1, -1, -1, 2425, -1, 2427, -1, -1, -1, 101, - 101, -1, 339, -1, 3524, -1, -1, 3085, -1, 2579, - 2580, -1, -1, -1, -1, -1, -1, -1, -1, 382, - -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, - -1, 540, 19, 20, 21, -1, 545, 1158, -1, 548, - -1, -1, -1, -1, -1, -1, 3217, -1, -1, -1, - 3128, -1, 1230, 1174, 1175, -1, 419, -1, -1, 46, - 1181, 1230, -1, -1, -1, -1, 53, -1, 3239, 3240, - -1, 173, -1, -1, -1, -1, -1, -1, -1, 2036, - -1, -1, -1, 1204, 1205, 1206, -1, -1, -1, 452, - -1, 0, 3263, 80, -1, 1216, 1217, -1, -1, -1, - 463, 37, -1, -1, -1, -1, 42, 209, 1229, -1, - -1, -1, -1, -1, -1, -1, -1, 480, -1, -1, - -1, -1, -1, 225, 1046, 1246, -1, -1, -1, 1250, - 26, -1, -1, 235, 1255, -1, 32, -1, -1, -1, - -1, 504, -1, 1321, 40, -1, -1, -1, -1, -1, - -1, -1, 1321, -1, -1, 518, -1, -1, -1, -1, - 3238, -1, 1545, -1, 60, 101, -1, 269, -1, -1, - -1, -1, -1, -1, -1, 151, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 2373, -1, -1, - 177, 100, -1, 1314, -1, 1316, 172, -1, -1, -1, - -1, -1, -1, -1, 1325, 2775, -1, 194, -1, -1, - 106, 8, 199, 315, 11, 1336, -1, -1, 15, 16, - 322, -1, -1, -1, 1345, -1, -1, -1, -1, 1350, - 2800, 1352, 1353, -1, 1355, 1356, 2193, 173, 147, -1, - -1, 137, -1, -1, -1, -1, -1, -1, 2680, 46, - 237, -1, -1, 162, -1, -1, 53, 1640, 167, -1, - -1, -1, 364, 172, -1, -1, -1, -1, -1, 2226, - 2227, -1, 181, 209, -1, -1, -1, 186, -1, 2711, - 2850, 383, -1, 80, -1, -1, -1, 796, -1, 225, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 235, - -1, -1, -1, -1, -1, 292, 202, -1, 1230, 218, - -1, -1, -1, -1, 1435, 1436, -1, -1, -1, -1, - 1441, -1, 1443, 2509, 3495, -1, -1, -1, -1, 238, - -1, -1, -1, 269, -1, 1456, -1, 1458, 1459, 315, - 316, 317, 1463, 1464, -1, 1466, -1, -1, 145, -1, - 452, 1472, -1, 1474, 290, 251, 1477, -1, -1, -1, - -1, 1482, -1, 1484, 1485, 261, 1487, 1545, -1, -1, - 1491, 2941, 1493, -1, 1495, -1, 1545, 273, 287, 315, - 177, 290, -1, 892, -1, -1, 322, 296, -1, 2575, - -1, -1, -1, -1, 1777, -1, -1, 194, 294, 1321, - -1, -1, 199, -1, -1, -1, 382, 394, -1, 305, - -1, -1, -1, -1, -1, -1, -1, -1, 927, -1, - -1, 3499, -1, -1, -1, -1, -1, 336, 364, -1, - -1, -1, -1, -1, 943, 944, 945, 946, 539, -1, - 237, -1, -1, 419, -1, -1, -1, 383, -1, -1, - -1, -1, 361, -1, 2886, -1, -1, 353, -1, -1, - -1, 357, 1640, 359, -1, -1, -1, 13, -1, -1, - -1, 1640, -1, 19, -1, -1, 452, 23, -1, 1600, - -1, -1, -1, -1, 30, 994, -1, 463, 384, -1, - -1, 1612, -1, 389, 2680, 292, -1, -1, 44, 45, - -1, -1, -1, -1, 480, -1, -1, 403, -1, -1, - 419, -1, -1, -1, 3084, 502, 452, -1, 505, 506, - 507, 457, 509, 510, 511, 512, 513, 514, 504, 75, - 76, 1652, -1, -1, 1655, -1, -1, -1, 447, -1, - -1, -1, 518, -1, -1, -1, 1929, -1, 457, -1, - -1, -1, -1, -1, -1, -1, 2513, 2514, 1941, -1, - -1, -1, 1683, 109, 460, -1, -1, -1, 477, -1, - 479, 480, -1, -1, -1, -1, -1, 1698, -1, 1700, - -1, 1702, -1, -1, -1, -1, -1, -1, 1971, -1, - -1, 1712, 2778, 1714, -1, 1978, -1, 394, -1, 1777, - -1, -1, -1, -1, -1, 1726, -1, 516, 1777, -1, - 519, 520, 521, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3054, 1545, -1, -1, -1, -1, 40, -1, - 1751, -1, 1753, -1, -1, -1, 2019, -1, -1, -1, - 2023, -1, -1, -1, 1765, 1766, 2029, -1, 60, 3081, - 1771, 1772, 753, 754, -1, -1, -1, -1, -1, -1, - -1, 1782, 1783, 1784, 1785, -1, 1787, -1, -1, 2052, - -1, -1, 1793, -1, 1795, -1, 2862, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1807, 1808, -1, -1, - -1, 1812, 1813, 794, 106, -1, 1817, 1818, 1819, 1820, - -1, 1822, 1823, -1, 805, 502, -1, 1216, -1, -1, - -1, 812, 509, 510, 511, 512, 513, 514, 1640, -1, - 1229, 1842, -1, 2680, -1, -1, -1, -1, -1, 1850, - 3300, 1852, 1853, 1854, 1855, 1856, 3168, -1, -1, -1, - -1, 1250, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1929, 1873, -1, -1, -1, 857, -1, -1, -1, - 1929, -1, -1, 1941, -1, -1, -1, -1, -1, -1, - -1, 1892, 1941, -1, 875, -1, -1, -1, -1, -1, - -1, -1, -1, 2969, -1, -1, -1, -1, -1, -1, - 202, -1, -1, 1971, -1, -1, -1, -1, -1, -1, - 1978, -1, 1971, -1, -1, -1, 3238, 1316, -1, 1978, - -1, -1, -1, -1, -1, -1, 1325, 3003, -1, -1, - -1, 1942, 1943, 1944, 1945, 1946, 1947, -1, -1, 1950, - 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 251, - -1, 2019, -1, -1, -1, 2023, -1, -1, -1, 261, - 2019, 2029, -1, -1, 2023, 1777, 2813, 98, -1, 1980, - 2029, 273, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1994, 2052, -1, -1, -1, -1, -1, - -1, -1, 983, 2052, 2005, 126, 127, -1, -1, -1, - 2011, -1, -1, 305, -1, -1, 2017, -1, -1, 3085, - -1, 2022, -1, -1, -1, -1, -1, -1, -1, -1, - 2031, 2032, -1, -1, -1, 1016, -1, 1018, -1, -1, - -1, -1, -1, -1, -1, -1, 1027, -1, -1, -1, - -1, 172, -1, 8, 3366, -1, 11, -1, -1, 172, - 15, 16, 3128, -1, -1, -1, -1, 359, -1, -1, - -1, 8, -1, -1, 11, -1, -1, 1466, 15, 16, - -1, 1062, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 46, 384, 1074, -1, -1, -1, -1, 53, -1, - -1, -1, 2103, -1, -1, -1, -1, 2108, -1, 46, - 2373, 403, 2113, -1, -1, -1, 53, -1, -1, -1, - 1101, 2958, -1, 0, -1, 80, 2963, 1929, -1, -1, - 556, -1, -1, -1, -1, -1, 2137, 2138, -1, 1941, - -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2156, -1, -1, -1, -1, - -1, 2162, -1, -1, -1, -1, -1, -1, -1, 1971, - -1, -1, 3238, 3010, 3011, -1, 1978, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3499, 2189, -1, - 145, 304, -1, -1, 315, 316, 317, -1, -1, -1, - 2201, -1, 315, 316, 317, 2206, -1, 1188, 1189, 2210, - 1191, -1, -1, -1, -1, -1, -1, 2019, -1, -1, - -1, 2023, 177, 100, -1, -1, -1, 2029, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - 177, -1, -1, -1, 199, -1, 2509, -1, -1, 2250, - 2052, -1, 2253, -1, 2255, 2256, -1, 194, -1, -1, - -1, 382, 199, -1, -1, -1, -1, -1, -1, 382, - 147, -1, 393, -1, -1, 2276, -1, -1, -1, -1, - -1, -1, 237, -1, -1, 162, -1, -1, -1, -1, - 167, -1, -1, -1, 415, 172, -1, -1, 419, -1, - 237, -1, -1, -1, 181, -1, 419, -1, -1, 186, - -1, 1700, 2575, 1702, -1, 2373, -1, -1, 439, -1, - -1, 747, 748, 1712, 2373, -1, -1, -1, -1, -1, - -1, 452, -1, -1, -1, -1, -1, 292, -1, 452, - -1, 218, 463, -1, -1, -1, -1, 2348, -1, -1, - 463, -1, -1, -1, 2355, 292, -1, -1, -1, 480, - -1, 238, 1751, -1, -1, 2366, -1, 480, 2369, 2370, - 2371, 2372, -1, -1, -1, -1, -1, -1, -1, 805, - -1, 1362, 2383, 504, 2385, -1, -1, 2388, 3225, 3226, - -1, 504, -1, -1, 2395, -1, -1, 518, -1, -1, - 2401, 3238, -1, -1, -1, 518, -1, -1, -1, -1, - 287, -1, -1, 290, -1, -1, -1, 2680, -1, 296, - -1, -1, 2423, 2424, -1, 2426, -1, -1, -1, -1, - -1, -1, -1, 3499, -1, -1, -1, -1, -1, 394, - 866, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2509, -1, -1, 2455, -1, -1, 394, -1, 336, - 2509, -1, -1, 1852, 1853, 1854, 1855, 1856, -1, -1, - -1, -1, 2473, -1, -1, -1, -1, -1, -1, -1, - 2481, 2482, 2483, -1, 361, -1, -1, -1, -1, -1, - 2491, 1472, 2493, 1474, 2495, -1, 1477, -1, -1, -1, - 2501, 1482, -1, -1, 1485, -1, 1487, -1, -1, -1, - 1491, -1, -1, -1, -1, 2778, 8, 2575, -1, 11, - 2521, -1, -1, 15, 16, -1, 2575, 19, 20, 21, - -1, -1, -1, -1, 2535, -1, -1, -1, -1, -1, - -1, -1, 419, -1, 36, 2546, -1, 502, -1, 2550, - -1, -1, -1, -1, 509, 510, 511, 512, 513, 514, - -1, -1, -1, -1, -1, 502, -1, -1, -1, -1, - 447, 2373, 509, 510, 511, 512, 513, 514, 2579, 2580, - 457, -1, -1, -1, 1010, -1, -1, -1, -1, -1, - 1016, -1, 1018, 1574, -1, -1, -1, -1, -1, 2862, - 477, 1027, 479, 480, -1, 1994, -1, 2608, -1, -1, - -1, 1037, -1, 2614, -1, -1, -1, -1, -1, -1, - -1, -1, 2680, -1, -1, -1, -1, -1, -1, 2630, - -1, 2680, -1, 2634, -1, 2636, -1, 2638, 2639, 516, - -1, 2642, 519, 520, 521, 2646, 2647, 2648, 8, 2650, - -1, 11, -1, -1, -1, 15, 16, -1, -1, 19, - 20, 21, 3499, -1, -1, -1, -1, -1, 2669, -1, - 2671, -1, -1, -1, 1655, -1, 36, -1, -1, 1105, - -1, -1, -1, 2684, 2685, 2686, 2687, 2688, 2689, 2690, - 2691, 2692, 2693, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2969, 2509, -1, -1, - -1, -1, -1, -1, 2715, -1, -1, -1, -1, -1, - 2778, 2722, -1, -1, -1, -1, -1, -1, -1, 2778, - 222, -1, -1, 2734, -1, -1, -1, -1, -1, -1, - 3003, -1, 1723, -1, -1, -1, -1, 8, 1174, 1175, - 11, -1, -1, 2754, 15, 16, -1, -1, 19, 20, - 21, -1, -1, 2764, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2575, 2775, 36, -1, -1, -1, -1, - 2781, -1, -1, -1, -1, -1, -1, 2788, 2789, 2790, - 2791, -1, -1, -1, -1, -1, -1, -1, -1, 2800, - 292, -1, 2803, -1, 2862, -1, 2807, 2808, -1, -1, - -1, -1, -1, 2862, -1, 2816, -1, -1, 8, -1, - -1, 11, 3085, -1, -1, 15, 16, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2839, -1, - -1, -1, -1, -1, -1, 2846, 2847, -1, -1, -1, - 2851, -1, -1, -1, -1, -1, 46, -1, -1, -1, - -1, -1, 222, 53, -1, 3128, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2680, 2880, - -1, 2882, 1863, -1, -1, -1, -1, -1, 2889, -1, - 80, -1, -1, -1, 1875, 2896, -1, -1, -1, 2900, - -1, -1, -1, -1, -1, 2906, -1, -1, -1, -1, - -1, 2969, -1, -1, -1, -1, -1, -1, -1, 2920, - 2969, -1, -1, -1, -1, 2926, 1352, 1353, -1, 1355, - -1, -1, 292, -1, -1, -1, -1, -1, 2939, 2940, - 2941, -1, -1, -1, -1, 3003, 2947, -1, -1, -1, - -1, -1, -1, -1, 3003, 145, -1, -1, -1, -1, - -1, 222, -1, 2964, -1, -1, 2355, -1, -1, -1, - -1, -1, -1, -1, -1, 3238, 2778, -1, -1, -1, - -1, 2370, 2371, 2372, -1, -1, -1, 177, -1, -1, - -1, -1, -1, -1, -1, -1, 2385, -1, -1, 2388, - -1, -1, -1, -1, 194, -1, 2395, -1, -1, 199, - -1, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, 2005, -1, -1, 3085, -1, -1, - 2011, 292, 1458, -1, -1, -1, 3085, -1, -1, -1, - -1, 3042, -1, -1, -1, 3046, 1472, 237, 1474, -1, - -1, 1477, -1, -1, -1, -1, 1482, -1, 3059, 1485, - 2862, 1487, -1, -1, -1, 1491, -1, 1493, -1, 1495, - 3128, -1, -1, -1, -1, -1, 3077, -1, -1, 3128, - -1, -1, -1, 3084, -1, -1, -1, -1, -1, -1, - -1, -1, 2481, 2482, 2483, -1, -1, -1, -1, -1, - -1, -1, 292, -1, -1, -1, -1, -1, -1, 3110, - -1, -1, -1, -1, -1, 3116, -1, -1, -1, -1, - -1, -1, 3123, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3140, - -1, -1, -1, -1, -1, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, - -1, 2142, -1, 3164, -1, -1, -1, 2969, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 3238, 2162, -1, -1, -1, 3186, 1612, -1, -1, 3238, - 3191, -1, -1, -1, -1, -1, -1, 2178, -1, -1, - -1, 3003, -1, -1, 394, -1, -1, -1, 2189, -1, - -1, 8, -1, -1, 11, -1, 3217, -1, 15, 16, - -1, -1, 19, 20, 21, 2206, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3499, -1, 3239, 3240, - -1, 2630, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, 3256, -1, 3258, -1, -1, - -1, -1, 3263, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3277, -1, -1, 3280, - -1, -1, -1, 3085, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3300, - -1, 3302, -1, 3304, 3305, -1, 3307, -1, -1, -1, - -1, 3312, 502, -1, -1, -1, -1, -1, -1, 509, - 510, 511, 512, 513, 514, -1, 3128, 1753, -1, -1, - 3331, -1, -1, 2722, 3335, -1, -1, -1, -1, -1, - 8, 3342, -1, 11, -1, -1, 1772, 15, 16, -1, - -1, -1, -1, -1, -1, -1, 1782, -1, 1784, -1, - -1, 1787, -1, -1, -1, -1, -1, 1793, -1, 1795, - -1, 3372, -1, -1, -1, -1, -1, -1, 46, -1, - -1, -1, 1808, 2364, -1, 53, -1, 1813, -1, -1, - -1, 1817, 1818, 1819, 1820, -1, 1822, 1823, -1, 2788, - 2789, 2790, 2791, -1, -1, -1, -1, -1, -1, 3410, - -1, -1, 80, -1, -1, -1, -1, 3418, -1, -1, - -1, -1, -1, -1, -1, 222, -1, -1, -1, -1, - -1, -1, 3433, -1, -1, -1, 3238, -1, -1, -1, - -1, 3499, -1, -1, 0, -1, -1, -1, -1, -1, - 3499, -1, -1, -1, -1, -1, -1, -1, -1, 3460, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, 3472, 3473, -1, 3475, 3476, 32, 145, 34, 35, - -1, -1, -1, 3484, -1, -1, 841, 842, -1, -1, - -1, 47, -1, -1, 3495, 292, 52, -1, -1, -1, - -1, -1, -1, -1, -1, 61, -1, -1, -1, 177, - -1, -1, -1, -1, -1, -1, 3517, -1, -1, 75, - -1, -1, -1, 3524, -1, -1, 194, -1, 84, -1, - 86, 199, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 98, -1, 100, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1980, 111, -1, 912, 2947, -1, - 3561, 916, 917, -1, -1, -1, 2547, -1, -1, 237, - 126, 127, 128, -1, -1, 3576, -1, -1, -1, 2005, - -1, 137, -1, -1, -1, 2011, -1, 143, -1, -1, - -1, 2017, -1, -1, -1, 151, 2022, 153, 154, -1, - -1, -1, -1, -1, 2585, -1, -1, -1, -1, -1, - -1, -1, 168, -1, 969, -1, 172, -1, -1, -1, - -1, -1, -1, 2604, 292, -1, -1, -1, -1, 2610, - -1, -1, 987, -1, -1, -1, -1, -1, 993, -1, - -1, 996, 198, -1, 999, 1000, 1001, 1002, -1, -1, - -1, -1, -1, -1, -1, 2636, -1, -1, 214, -1, - -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, - 16, -1, -1, 19, 20, 21, -1, 2103, -1, -1, - -1, -1, -1, -1, 240, -1, -1, 2113, -1, 1044, - 1045, -1, -1, -1, -1, -1, -1, 3499, -1, -1, - 46, -1, -1, -1, -1, -1, -1, 53, 505, 506, - 507, 1066, 509, 510, 511, 512, 513, 514, -1, -1, - 8, -1, -1, 11, -1, -1, 394, 15, 16, -1, - 1085, 19, 20, 21, 80, 2716, -1, -1, -1, -1, - -1, 1096, 1097, 1098, -1, 1100, 1101, -1, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 46, 315, - 316, 317, -1, 2189, 2745, 53, -1, 323, -1, -1, - 326, 2752, -1, -1, -1, 2201, -1, -1, -1, -1, - 2206, 1136, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 80, -1, -1, -1, -1, -1, -1, 1154, - 1155, 357, -1, -1, -1, -1, 3, -1, 5, -1, - 366, -1, -1, -1, -1, -1, -1, -1, -1, 2800, - -1, -1, -1, -1, 2250, -1, 382, -1, -1, -1, - 2256, 177, -1, 389, 502, 1190, -1, 393, -1, 1194, - 1195, 509, 510, 511, 512, 513, 514, 403, 194, -1, - 1205, 1206, -1, 199, -1, -1, -1, -1, -1, 415, - -1, -1, -1, 419, -1, -1, -1, 3256, -1, -1, - -1, 68, 69, -1, -1, -1, 222, 223, -1, -1, - -1, -1, -1, 439, -1, -1, -1, -1, 3277, 177, - -1, 237, -1, -1, -1, -1, 452, -1, -1, 455, - -1, 2882, 458, -1, -1, -1, 194, 463, -1, -1, - 1265, 199, 109, 110, -1, 2896, 113, 114, -1, 1274, - -1, -1, -1, -1, 480, -1, -1, -1, -1, 275, - -1, -1, 278, -1, 222, 223, -1, -1, -1, -1, - -1, -1, -1, 1298, -1, -1, 292, -1, 504, 237, - -1, -1, -1, 3342, -1, -1, -1, 2383, -1, -1, - -1, -1, 518, 8, -1, 521, 11, -1, -1, -1, - 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, - -1, -1, -1, 3372, -1, -1, -1, 275, -1, -1, - 278, 36, 189, 190, -1, -1, -1, -1, -1, -1, - -1, 46, -1, -1, 292, -1, -1, 295, 53, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1385, -1, -1, -1, -1, 80, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, - -1, -1, -1, -1, -1, -1, 253, 254, 255, 256, - 257, 258, 259, 260, -1, 2491, 263, 264, -1, 2495, - -1, -1, -1, -1, -1, 2501, -1, -1, -1, 3060, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1448, -1, 1450, 1451, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 394, -1, 1463, 1464, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3100, - 2546, -1, -1, -1, 2550, -1, -1, -1, -1, 1484, - -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, - 337, 338, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, -1, -1, 199, -1, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, -1, -1, -1, -1, -1, -1, 222, 223, -1, - -1, 378, 379, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 2634, -1, - -1, -1, 2638, 2639, 502, -1, 2642, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - 275, 1586, -1, 278, 8, -1, -1, 11, -1, 1594, - -1, 15, 16, 2669, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, 2684, 2685, - 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, -1, -1, - -1, -1, 46, 1628, 3255, -1, -1, 474, 475, 53, - 1635, -1, -1, -1, -1, -1, 1641, 1642, 1643, 1644, - 1645, 1646, 1647, 1648, -1, 3276, -1, -1, 1653, 1654, - -1, 498, 499, 1658, -1, -1, 80, 1662, -1, -1, - 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, -1, - -1, 1676, -1, -1, -1, -1, -1, -1, 1683, 8, - 1685, -1, 11, -1, -1, -1, 15, 16, 17, 18, - 19, 20, 21, -1, -1, -1, -1, -1, 1703, 394, - -1, 3332, -1, 3334, -1, 2781, -1, 36, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, - -1, 145, -1, -1, 53, -1, -1, -1, -1, -1, - -1, 2807, 1737, 1738, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3374, -1, -1, -1, -1, -1, -1, - -1, 80, -1, 177, 8, -1, -1, 11, -1, 3390, - -1, 15, 16, 2839, -1, 19, 20, 21, -1, -1, - 194, 2847, -1, -1, -1, 199, -1, -1, -1, -1, - -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 46, -1, -1, -1, -1, -1, -1, 53, - -1, -1, -1, -1, -1, -1, 2882, 502, -1, -1, - 505, 506, 507, 237, 509, 510, 511, 512, 513, 514, - -1, -1, -1, 1828, -1, -1, 80, -1, 523, -1, - 1835, -1, -1, 1838, 1839, -1, -1, -1, -1, 3, - -1, -1, -1, -1, 8, -1, -1, 11, 177, -1, - -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, 2940, 194, -1, -1, 292, -1, - 199, -1, 36, -1, 1879, -1, 40, -1, -1, -1, - -1, -1, 46, -1, -1, 3516, -1, -1, -1, 53, - -1, -1, -1, 222, 223, -1, -1, -1, -1, 1904, - 1905, -1, -1, -1, -1, -1, -1, -1, 237, -1, - -1, 3542, -1, -1, -1, -1, 80, -1, -1, -1, - -1, -1, -1, 177, -1, -1, -1, -1, 1933, 1934, - -1, 1936, 997, -1, -1, -1, -1, -1, -1, -1, - 194, -1, -1, -1, -1, 199, 275, -1, -1, 278, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1965, 1966, -1, 292, 1969, -1, 295, -1, 222, 223, - 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 2000, -1, -1, -1, -1, - -1, -1, 2007, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, - 2025, 275, 2027, -1, 278, -1, -1, -1, -1, -1, - 194, -1, -1, -1, -1, 199, -1, -1, 292, -1, - 3116, -1, -1, -1, -1, -1, -1, 3123, -1, -1, - -1, -1, -1, -1, -1, -1, 1121, -1, 222, 223, - 2065, -1, -1, -1, -1, 394, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, 502, -1, - -1, -1, -1, -1, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, 2102, -1, -1, - -1, 2106, -1, -1, -1, 1170, 2111, 2112, -1, -1, - 3186, 275, -1, -1, 278, 3191, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, - -1, 295, -1, -1, -1, -1, -1, -1, -1, 1204, - 394, 3217, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2158, -1, -1, 2161, -1, 2163, -1, - -1, -1, -1, 3239, 3240, -1, -1, -1, -1, -1, - -1, -1, -1, 502, 2179, -1, 505, 506, 507, -1, - 509, 510, 511, 512, 513, 514, -1, 3263, -1, -1, - -1, -1, -1, 522, 1259, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 2219, -1, 8, -1, -1, 11, - -1, -1, -1, 15, 16, -1, -1, -1, 3304, -1, - 394, 2236, 2237, -1, -1, -1, 3312, 1302, -1, -1, - -1, -1, -1, -1, 1309, -1, -1, -1, 502, -1, - 2255, 505, 506, 507, 46, 509, 510, 511, 512, 513, - 514, 53, -1, 2268, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, - -1, -1, -1, 36, 1359, -1, -1, 40, -1, -1, - -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, - 53, -1, -1, -1, -1, -1, -1, -1, 1383, -1, - 2325, -1, -1, -1, -1, -1, -1, -1, -1, 2334, - -1, -1, -1, -1, -1, -1, -1, 80, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, 145, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1431, -1, 1433, -1, - 1435, 1436, -1, 1438, -1, -1, 1441, -1, -1, 1444, - -1, -1, 1447, -1, -1, 177, -1, 1452, 2393, -1, - 1455, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, -1, 3495, - -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, 1498, 177, -1, -1, -1, -1, -1, - -1, -1, 36, -1, -1, 237, -1, -1, -1, -1, - -1, 194, 46, -1, -1, -1, 199, -1, -1, 53, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 222, - 223, -1, -1, -1, -1, -1, 80, -1, -1, -1, - -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, - 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1582, -1, -1, - -1, 2526, -1, -1, -1, -1, -1, 2532, 2533, -1, - -1, -1, 275, 1598, -1, 278, -1, -1, -1, -1, - -1, -1, 2547, 1608, 1609, 1610, -1, -1, -1, 292, - 1615, -1, 295, -1, 1619, -1, -1, -1, 2563, -1, - -1, 2566, -1, 2568, -1, -1, -1, -1, -1, -1, - -1, 2576, -1, -1, -1, -1, -1, -1, -1, 2584, - 2585, -1, -1, 177, -1, -1, 2591, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 194, 2606, 394, -1, -1, 199, -1, -1, -1, -1, - -1, 2616, -1, -1, -1, -1, -1, 1682, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, - -1, 2636, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, - -1, 394, -1, -1, -1, 1720, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1736, -1, -1, -1, -1, 1741, -1, -1, -1, - -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, - 2695, -1, 2697, 1758, -1, -1, -1, -1, 292, -1, - -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, - 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, - 512, 513, 514, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 502, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, -1, -1, 519, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2795, 2796, -1, -1, -1, -1, -1, -1, -1, -1, - 394, -1, -1, -1, 8, -1, -1, 11, -1, -1, - -1, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, -1, 2830, -1, -1, -1, -1, - -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 46, -1, -1, 2850, -1, -1, -1, 53, - -1, 2856, 2857, -1, -1, -1, 2861, -1, -1, -1, - -1, 2866, -1, -1, 2869, 2870, 1931, -1, -1, 2874, - 2875, -1, -1, 2878, 1939, 1940, 80, 1942, 1943, 1944, - 1945, 1946, 1947, -1, 2889, 1950, 1951, 1952, 1953, 1954, - 1955, 1956, 1957, 1958, 1959, 1960, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, 519, 68, 69, 2933, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, -1, -1, 11, 2960, -1, -1, 15, 16, - 17, 18, 19, 20, 21, -1, -1, 109, 110, -1, - -1, 113, 114, 177, -1, -1, -1, -1, -1, 36, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, - 194, -1, -1, -1, -1, 199, 53, -1, -1, -1, - -1, -1, -1, 2068, -1, -1, 2071, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, - -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 189, 190, -1, - -1, 2116, -1, -1, -1, 2120, -1, -1, -1, 2124, - 2125, 2126, 2127, 2128, 2129, 2130, 2131, -1, 3073, -1, - -1, 275, 2137, 2138, 278, 2140, 2141, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 292, 2154, - -1, 295, 2157, -1, -1, 3100, -1, -1, -1, -1, - 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, - -1, 253, 254, 255, 256, 257, 258, 259, 260, -1, - 177, 263, 264, -1, -1, -1, -1, -1, -1, 3134, - -1, -1, -1, -1, -1, 2200, -1, 194, -1, -1, - -1, -1, 199, -1, -1, -1, 3151, 3152, -1, -1, - 3155, -1, 3157, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 222, 223, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3182, -1, -1, - 237, -1, -1, -1, -1, -1, -1, -1, 2253, -1, - 394, -1, -1, -1, -1, 337, 338, -1, -1, -1, - -1, 3206, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 275, -1, - -1, 278, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 292, 378, 379, 295, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2326, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 2337, 2338, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3294, - -1, -1, -1, 3298, -1, -1, -1, 3302, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, 3316, -1, -1, -1, 519, 3321, -1, 3323, -1, - -1, -1, -1, -1, -1, -1, 3331, -1, -1, -1, - -1, -1, 474, 475, -1, -1, -1, 394, -1, 2404, - -1, -1, -1, -1, 3349, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 498, 499, -1, -1, - -1, -1, -1, -1, -1, 2430, 2431, 2432, -1, -1, - 2435, 2436, 2437, 2438, 2439, 2440, 518, -1, -1, 2444, - 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, -1, - -1, 3396, -1, 2458, 2459, 8, -1, -1, 11, -1, - -1, 3406, 15, 16, 17, 18, 19, 20, 21, -1, - -1, -1, -1, 3418, -1, -1, -1, -1, -1, 2484, - -1, -1, -1, 36, -1, 2490, -1, -1, -1, -1, - -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, - 53, -1, -1, -1, -1, 502, 3451, -1, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, - 2525, -1, 519, -1, -1, -1, -1, 80, -1, -1, - -1, -1, -1, 24, -1, -1, -1, 2542, -1, -1, - -1, -1, -1, 2548, -1, -1, -1, -1, -1, -1, - -1, 2556, 2557, -1, -1, -1, -1, -1, -1, 2564, - 2565, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 2578, 2579, 2580, 2581, -1, 2583, -1, - -1, -1, 2587, -1, -1, -1, -1, -1, -1, -1, - 81, -1, -1, 3538, 3539, 3540, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 97, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, - 3565, -1, 11, -1, 177, -1, 15, 16, 17, 18, - 19, 20, 21, -1, -1, -1, -1, -1, 2643, -1, - -1, 194, -1, -1, -1, -1, 199, 36, -1, -1, - -1, -1, -1, -1, -1, 146, -1, 46, -1, -1, - -1, 3606, -1, -1, 53, 156, -1, -1, -1, 222, - 223, -1, -1, -1, -1, -1, -1, -1, 169, -1, - -1, -1, -1, 174, 237, -1, -1, -1, -1, -1, - -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, - -1, 11, 203, -1, -1, 15, 16, 17, 18, 19, - 20, 21, 275, -1, -1, 278, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 36, -1, -1, 292, - -1, -1, 295, -1, -1, -1, 46, -1, 2753, -1, - -1, -1, -1, 53, -1, 246, -1, -1, -1, 250, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 2775, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 80, -1, -1, -1, -1, -1, 8, -1, 177, 11, - -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, - -1, -1, -1, -1, -1, 194, -1, -1, -1, -1, - 199, -1, -1, -1, 36, -1, -1, -1, -1, -1, - -1, -1, -1, 314, 46, -1, 2831, -1, 2833, 320, - -1, 53, -1, 222, 223, -1, -1, 2842, -1, -1, - -1, 394, -1, -1, 335, -1, -1, -1, 237, -1, - 2855, -1, -1, 2858, -1, 2860, -1, -1, 80, 2864, - -1, -1, 2867, 2868, -1, -1, 2871, 2872, -1, -1, - -1, -1, -1, -1, 2879, -1, -1, 177, -1, 370, - -1, -1, 373, 2888, -1, -1, 275, -1, -1, 278, - -1, -1, -1, 384, 194, -1, 387, -1, 2903, 199, - -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, - -1, -1, -1, -1, 405, -1, -1, -1, -1, -1, - -1, -1, 222, 223, -1, -1, -1, -1, 419, -1, - -1, -1, -1, -1, 425, 426, 2941, 237, -1, -1, - -1, -1, -1, -1, -1, 436, -1, -1, -1, 502, - -1, 442, 505, 506, 507, 177, 509, 510, 511, 512, - 513, 514, -1, -1, -1, -1, 519, -1, -1, -1, - -1, -1, 194, -1, -1, 275, -1, 199, 278, 470, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 68, 69, 292, -1, -1, 295, -1, -1, -1, -1, - 222, 223, -1, -1, -1, 394, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, - -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, - -1, 109, 110, -1, -1, 113, 114, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 275, -1, -1, 278, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 292, -1, -1, 295, -1, -1, -1, -1, 3083, 3084, - -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 394, -1, -1, 97, -1, -1, - -1, -1, -1, 3108, 3109, -1, -1, -1, -1, -1, - -1, 189, 190, 502, -1, -1, 505, 506, 507, -1, - 509, 510, 511, 512, 513, 514, -1, 3132, -1, -1, - 519, -1, -1, -1, -1, -1, 3141, -1, -1, -1, - 3145, 3146, 3147, -1, -1, 3150, 146, -1, 3153, 3154, - -1, -1, -1, -1, -1, -1, 156, 3162, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, - -1, -1, 394, -1, 174, 253, 254, 255, 256, 257, - 258, 259, 260, -1, -1, 263, 264, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 3203, -1, - -1, -1, 502, 203, 3209, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, -1, -1, 3222, -1, 519, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 246, -1, -1, -1, - 250, -1, -1, -1, -1, -1, -1, -1, -1, 337, - 338, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3282, -1, -1, - 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, -1, -1, -1, 519, -1, -1, - 378, 379, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3318, 3319, 3320, -1, -1, -1, -1, - 320, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3338, -1, 335, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 3350, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 370, -1, -1, 373, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 384, -1, -1, 387, -1, -1, - -1, -1, -1, -1, -1, -1, 474, 475, -1, -1, - -1, -1, -1, -1, -1, 405, 3411, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3421, -1, -1, 419, - 498, 499, -1, -1, -1, -1, 426, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 436, -1, -1, -1, - -1, 3446, 442, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3471, -1, -1, -1, - 470, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 3514, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 3568, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, 172, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, -1, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, 504, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, 519, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, 172, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, 382, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - -1, 417, 418, 419, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, 452, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, 480, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, 504, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, 172, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, 504, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, - -1, 37, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, 132, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, 519, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, -1, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, 172, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, 317, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, 415, -1, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, 504, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 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, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, 172, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, 233, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, 432, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, 37, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, 37, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, 519, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, -1, -1, -1, -1, 38, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, 399, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, 37, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, 519, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, 37, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, 172, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, 519, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, 419, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, 477, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 27, 28, 0, 0, + 0, 0, 0, 29, 0, 0, 30, 0, 0, 0, + 0, 0, 0, 26, 27, 28, 0, 0, 0, 0, + 0, 29, 0, 0, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, + 0, 0, 33, 0, 32, 0, 0, 0, 0, 34, + 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 36, 0, 0, 0, 34, 0, 0, + 0, 35, 0, 0, 0, 37, 0, 0, 0, 38, + 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 38, 0, 39, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 0, 0, 0, 0, 39, 42, 0, + 0, 0, 0, 43, 0, 0, 0, 0, 753, 0, + 40, 0, 0, 0, 0, 0, 42, 0, 0, 0, + 44, 43, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, + 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 46 +}; + +static const yytype_int16 yycheck[] = +{ + 7, 840, 0, 521, 0, 0, 746, 902, 887, 16, + 0, 0, 0, 814, 864, 46, 23, 998, 0, 0, + 38, 0, 0, 7, 73, 754, 913, 75, 76, 0, + 1237, 929, 1223, 1249, 964, 1235, 1435, 1708, 20, 23, + 77, 1039, 20, 934, 16, 77, 1168, 1210, 37, 1670, + 1087, 989, 20, 1588, 989, 7, 989, 2201, 989, 1642, + 1313, 1816, 1483, 2260, 1562, 1203, 1212, 979, 75, 76, + 1215, 23, 13, 2011, 1291, 2191, 968, 979, 19, 2347, + 1338, 17, 0, 23, 1623, 1624, 0, 45, 0, 30, + 0, 75, 76, 111, 1240, 0, 0, 0, 2718, 23, + 0, 0, 0, 44, 45, 2656, 1133, 2695, 2170, 0, + 2172, 1138, 101, 902, 1095, 904, 0, 906, 34, 2136, + 1007, 2190, 2711, 75, 76, 2256, 2693, 0, 0, 0, + 2656, 0, 0, 753, 0, 75, 76, 987, 0, 0, + 754, 810, 0, 2308, 2309, 2310, 815, 2012, 747, 2327, + 0, 75, 76, 2610, 2525, 1838, 0, 2614, 0, 1835, + 9, 1061, 1062, 9, 1726, 0, 0, 5, 109, 5, + 1728, 1674, 1952, 26, 80, 13, 14, 3035, 1078, 32, + 5, 5, 63, 1834, 5, 9, 5, 5, 9, 990, + 2339, 55, 5, 5, 13, 14, 5, 778, 5, 5, + 13, 14, 13, 14, 13, 14, 13, 14, 1642, 5, + 26, 5, 13, 14, 5, 5, 32, 2348, 2335, 5, + 5, 3021, 45, 5, 5, 172, 172, 5, 82, 2333, + 119, 74, 1144, 2339, 3, 45, 5, 122, 3038, 93, + 173, 11, 882, 11, 1094, 124, 16, 882, 16, 37, + 979, 139, 3, 4, 5, 107, 100, 859, 9, 2474, + 1258, 63, 4, 104, 1151, 30, 100, 9, 5, 1267, + 30, 2402, 2403, 38, 2405, 245, 46, 4, 38, 1177, + 1985, 1986, 9, 63, 137, 90, 172, 181, 11, 807, + 122, 1996, 15, 16, 11, 2000, 122, 30, 15, 16, + 2991, 288, 119, 82, 191, 38, 291, 172, 172, 5, + 80, 193, 1224, 11, 93, 1227, 1228, 15, 16, 3, + 296, 137, 991, 46, 129, 290, 169, 2856, 1450, 2858, + 313, 291, 63, 1065, 1003, 107, 2875, 3204, 856, 313, + 181, 276, 1533, 147, 1978, 1979, 1980, 147, 46, 1081, + 34, 35, 1202, 193, 382, 64, 368, 80, 162, 1198, + 1199, 1483, 982, 167, 117, 74, 117, 119, 315, 316, + 317, 2572, 40, 2574, 1627, 30, 3134, 117, 3136, 3395, + 164, 213, 80, 108, 40, 173, 245, 213, 30, 107, + 173, 120, 2626, 83, 2456, 369, 279, 41, 409, 296, + 13, 14, 11, 373, 2159, 120, 1017, 433, 2573, 1922, + 3363, 391, 1023, 418, 218, 11, 1295, 149, 218, 250, + 507, 209, 33, 3388, 3389, 2976, 1324, 482, 2625, 108, + 3230, 2926, 273, 520, 238, 382, 132, 225, 191, 2934, + 1953, 294, 3030, 85, 275, 122, 290, 235, 59, 504, + 46, 456, 94, 3041, 2598, 207, 290, 483, 148, 166, + 137, 472, 1353, 280, 160, 3032, 195, 192, 219, 201, + 3486, 80, 419, 355, 3332, 3440, 118, 132, 294, 360, + 195, 451, 126, 287, 80, 431, 329, 171, 272, 173, + 241, 2622, 296, 2624, 522, 132, 296, 3255, 2732, 2516, + 353, 273, 1539, 308, 357, 452, 518, 245, 176, 26, + 2921, 3202, 1765, 396, 373, 32, 463, 361, 358, 454, + 176, 273, 275, 275, 11, 485, 309, 361, 15, 16, + 513, 518, 241, 518, 3487, 3064, 389, 353, 518, 513, + 280, 357, 273, 280, 8, 431, 522, 11, 518, 191, + 539, 15, 16, 518, 167, 19, 20, 21, 360, 2142, + 1200, 507, 204, 457, 2765, 1200, 2781, 419, 3426, 454, + 459, 518, 1174, 389, 520, 2724, 364, 431, 457, 275, + 360, 1162, 1100, 2004, 280, 518, 593, 428, 476, 285, + 2707, 1441, 451, 416, 3461, 383, 1759, 1337, 1498, 1499, + 2704, 2136, 1342, 1820, 469, 448, 416, 460, 1348, 3148, + 516, 2742, 395, 2551, 520, 556, 1455, 324, 2724, 424, + 137, 593, 454, 1523, 1882, 522, 1355, 3427, 454, 360, + 3219, 518, 2412, 1472, 399, 2174, 480, 406, 407, 399, + 290, 522, 467, 447, 460, 2207, 480, 447, 285, 1856, + 2208, 328, 431, 3204, 518, 373, 132, 75, 389, 518, + 108, 1914, 148, 509, 510, 2200, 399, 2350, 517, 2345, + 482, 521, 522, 1926, 1672, 519, 518, 521, 3204, 521, + 518, 1897, 518, 1583, 1584, 519, 521, 521, 526, 2340, + 526, 2194, 504, 518, 518, 2892, 3153, 518, 516, 518, + 518, 3158, 520, 1956, 482, 518, 518, 518, 2142, 518, + 1963, 518, 518, 451, 200, 1565, 1566, 518, 227, 3339, + 522, 2899, 518, 754, 518, 1575, 504, 518, 518, 1616, + 1617, 1618, 518, 518, 1354, 3106, 518, 518, 480, 1589, + 518, 1355, 438, 3331, 514, 1344, 514, 754, 2001, 3338, + 3018, 3162, 2005, 449, 30, 227, 419, 805, 509, 510, + 3438, 162, 504, 405, 273, 2470, 408, 509, 510, 1619, + 3181, 753, 164, 1505, 805, 753, 162, 294, 3527, 1448, + 518, 2034, 509, 510, 468, 457, 754, 794, 511, 512, + 513, 514, 2009, 1525, 511, 512, 513, 514, 805, 275, + 457, 273, 26, 519, 2873, 245, 522, 748, 266, 285, + 794, 509, 510, 511, 512, 513, 514, 854, 2756, 3568, + 359, 805, 854, 2457, 2458, 2459, 2460, 1559, 292, 259, + 260, 518, 341, 840, 841, 1566, 353, 238, 887, 231, + 357, 859, 794, 1965, 1575, 3523, 518, 3012, 3436, 507, + 389, 480, 238, 805, 0, 3422, 132, 864, 178, 877, + 518, 518, 2879, 321, 468, 805, 1864, 521, 275, 82, + 794, 59, 389, 280, 106, 504, 874, 1789, 874, 874, + 93, 805, 2004, 392, 874, 874, 874, 1799, 3019, 1784, + 1802, 2474, 874, 874, 862, 874, 874, 2835, 522, 1639, + 482, 287, 2160, 874, 911, 912, 132, 865, 915, 916, + 3461, 1429, 3479, 137, 519, 174, 2671, 522, 2673, 184, + 392, 241, 504, 214, 865, 2790, 842, 843, 2793, 845, + 2795, 847, 339, 373, 160, 3461, 518, 245, 1817, 1818, + 1819, 5, 203, 460, 3333, 454, 1973, 275, 378, 379, + 1880, 1842, 82, 341, 1884, 53, 874, 1887, 3226, 3547, + 874, 968, 874, 2085, 874, 245, 1014, 3164, 1757, 874, + 874, 874, 979, 1021, 874, 874, 874, 518, 108, 986, + 987, 2516, 454, 874, 172, 992, 1898, 246, 995, 996, + 874, 998, 999, 1000, 1001, 1784, 1898, 1889, 934, 2538, + 982, 874, 874, 874, 982, 874, 874, 1014, 874, 245, + 82, 451, 874, 874, 1021, 1804, 874, 174, 74, 251, + 1809, 93, 509, 510, 511, 512, 513, 514, 3144, 261, + 1014, 1038, 1039, 1040, 518, 2434, 3425, 1021, 2176, 3428, + 2178, 505, 506, 507, 174, 509, 510, 511, 512, 513, + 514, 4, 517, 1060, 280, 1795, 9, 517, 1012, 285, + 1800, 117, 1014, 528, 1095, 373, 4, 37, 528, 1021, + 294, 9, 1079, 203, 1014, 340, 1030, 2284, 518, 177, + 1034, 1021, 2580, 1090, 1091, 1092, 345, 1094, 1095, 246, + 1014, 1098, 2847, 373, 2311, 519, 194, 1021, 522, 2352, + 513, 199, 482, 423, 369, 425, 108, 520, 2230, 3306, + 513, 1961, 373, 189, 190, 178, 246, 520, 13, 14, + 3058, 2656, 1129, 384, 504, 384, 1098, 315, 316, 317, + 355, 451, 3521, 357, 178, 359, 380, 373, 518, 237, + 1147, 1148, 26, 451, 1181, 1182, 2292, 1184, 32, 1181, + 1182, 519, 1184, 3291, 522, 3293, 1174, 1905, 419, 147, + 419, 1909, 4, 519, 1912, 389, 522, 9, 162, 1898, + 162, 451, 4, 167, 162, 167, 1183, 9, 241, 167, + 1187, 1188, 516, 259, 260, 2166, 520, 516, 345, 518, + 1197, 1198, 1199, 8, 382, 1202, 2046, 241, 2781, 380, + 15, 16, 203, 173, 19, 20, 21, 71, 72, 470, + 518, 470, 438, 516, 2359, 451, 1223, 520, 516, 275, + 2365, 1239, 520, 449, 280, 519, 1167, 384, 522, 3367, + 218, 419, 1440, 8, 1442, 1443, 11, 2490, 518, 209, + 15, 16, 519, 373, 238, 522, 238, 827, 828, 829, + 238, 1258, 832, 137, 384, 225, 252, 6, 345, 1022, + 1267, 10, 419, 1026, 452, 235, 480, 436, 482, 18, + 314, 46, 2122, 329, 26, 463, 842, 843, 53, 845, + 32, 847, 518, 32, 1291, 13, 14, 36, 25, 419, + 470, 347, 2171, 287, 419, 287, 394, 384, 519, 287, + 377, 522, 378, 379, 167, 80, 1313, 516, 296, 518, + 373, 520, 442, 470, 1312, 519, 1312, 1312, 522, 2266, + 519, 2268, 1329, 522, 1312, 519, 13, 14, 522, 373, + 518, 1338, 419, 2263, 519, 2265, 380, 522, 2759, 380, + 470, 26, 3539, 519, 2879, 518, 522, 32, 1355, 519, + 2472, 518, 522, 519, 2476, 519, 522, 1329, 522, 518, + 423, 519, 425, 519, 522, 1372, 522, 2622, 518, 2624, + 1377, 132, 1354, 423, 519, 425, 1354, 522, 115, 423, + 3524, 425, 3526, 470, 518, 137, 519, 1355, 451, 522, + 519, 518, 448, 522, 364, 519, 2235, 518, 522, 160, + 1372, 457, 177, 2656, 1345, 519, 1347, 451, 522, 423, + 294, 425, 1460, 383, 1462, 519, 172, 1465, 522, 194, + 1427, 1428, 1470, 3567, 199, 1473, 1433, 1475, 1435, 3491, + 518, 1479, 2639, 1440, 1441, 1442, 1443, 518, 2638, 519, + 2338, 423, 522, 425, 3506, 423, 511, 425, 1455, 1456, + 518, 1435, 137, 1460, 2670, 1462, 13, 14, 1465, 447, + 2623, 519, 237, 1470, 522, 1472, 1473, 519, 1475, 353, + 522, 519, 1479, 357, 522, 518, 1460, 292, 1462, 13, + 14, 1465, 40, 1435, 2521, 2522, 1470, 2687, 518, 1473, + 519, 1475, 2637, 522, 2639, 1479, 504, 519, 519, 3561, + 522, 522, 60, 519, 3566, 389, 522, 224, 1460, 519, + 1462, 1435, 522, 1465, 275, 13, 14, 292, 1470, 280, + 1460, 1473, 1462, 1475, 285, 1465, 1533, 1479, 516, 3284, + 1470, 3286, 520, 1473, 501, 1475, 1460, 2387, 1462, 1479, + 519, 1465, 294, 522, 2525, 520, 1470, 519, 106, 1473, + 522, 1475, 13, 14, 519, 1479, 345, 522, 1565, 1566, + 2498, 2499, 2500, 2498, 2499, 2498, 2497, 1574, 1575, 879, + 290, 881, 1562, 1562, 501, 1582, 460, 13, 14, 520, + 1562, 1562, 1589, 1562, 1562, 13, 14, 13, 14, 13, + 14, 1562, 13, 14, 171, 384, 13, 14, 522, 13, + 14, 353, 13, 14, 518, 357, 13, 14, 1615, 294, + 519, 26, 1619, 13, 14, 1622, 519, 32, 519, 394, + 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, + 419, 13, 14, 1640, 1641, 1642, 172, 389, 1645, 295, + 2380, 59, 1649, 518, 202, 1652, 1653, 1654, 1655, 1656, + 1657, 1658, 1659, 1660, 13, 14, 1663, 420, 1642, 2388, + 13, 14, 501, 1670, 1636, 1672, 13, 14, 979, 3204, + 13, 14, 357, 3294, 1711, 13, 14, 438, 224, 1711, + 152, 470, 13, 14, 1691, 13, 14, 353, 449, 2942, + 505, 506, 507, 251, 509, 510, 511, 512, 513, 514, + 368, 369, 2589, 261, 389, 368, 369, 1714, 460, 368, + 369, 368, 369, 263, 264, 273, 40, 8, 1725, 1726, + 11, 1689, 137, 152, 15, 16, 419, 502, 378, 379, + 2893, 462, 463, 2940, 509, 510, 511, 512, 513, 514, + 2370, 2371, 3501, 3502, 3533, 3534, 152, 305, 1147, 1148, + 2242, 2243, 519, 152, 152, 46, 518, 275, 1765, 40, + 470, 152, 53, 89, 152, 484, 520, 1774, 152, 1776, + 290, 152, 355, 2612, 518, 460, 431, 518, 518, 421, + 519, 220, 518, 225, 300, 2976, 518, 225, 225, 80, + 297, 518, 40, 236, 518, 5, 5, 518, 2677, 325, + 3016, 359, 1774, 1114, 1776, 2735, 518, 518, 2699, 1816, + 518, 5, 5, 1820, 518, 5, 1823, 1824, 3489, 1760, + 518, 5, 3493, 2721, 147, 302, 384, 9, 518, 1770, + 518, 1772, 481, 1144, 1775, 104, 178, 519, 522, 162, + 1781, 522, 1783, 40, 167, 403, 220, 3246, 3101, 389, + 2848, 167, 287, 167, 145, 1796, 5, 1864, 285, 59, + 1801, 203, 431, 236, 1805, 1806, 1807, 1808, 93, 1810, + 1811, 1860, 518, 518, 522, 1882, 431, 3548, 59, 294, + 59, 266, 1889, 1890, 431, 108, 177, 431, 528, 222, + 431, 1898, 431, 480, 380, 218, 152, 100, 275, 241, + 199, 518, 40, 194, 275, 275, 275, 1914, 199, 275, + 518, 1918, 1919, 1224, 1921, 238, 1227, 1228, 152, 1926, + 1927, 1928, 1929, 1930, 1931, 1932, 3461, 172, 1935, 1936, + 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 353, 1987, + 520, 996, 357, 1950, 1951, 1993, 237, 1954, 13, 1956, + 522, 3204, 8, 295, 1961, 11, 1963, 519, 519, 15, + 16, 519, 518, 151, 287, 172, 519, 519, 519, 477, + 519, 519, 225, 296, 389, 225, 1983, 126, 127, 282, + 1987, 282, 1989, 518, 172, 518, 1993, 467, 520, 117, + 46, 522, 520, 518, 2001, 518, 3395, 53, 2005, 518, + 2007, 292, 2009, 1987, 2011, 518, 518, 39, 518, 1993, + 476, 9, 11, 2943, 2944, 3215, 429, 429, 518, 2931, + 355, 517, 528, 172, 80, 522, 527, 2034, 522, 280, + 518, 373, 178, 429, 431, 1987, 181, 163, 3437, 2046, + 2047, 1993, 172, 522, 172, 460, 2786, 1987, 996, 1360, + 1361, 788, 519, 1993, 1040, 457, 218, 203, 522, 227, + 266, 291, 392, 1987, 313, 522, 313, 522, 181, 1993, + 220, 519, 518, 227, 275, 227, 296, 2084, 470, 334, + 2087, 423, 819, 425, 288, 2092, 2093, 3486, 518, 145, + 152, 2122, 3073, 3, 152, 241, 518, 152, 518, 152, + 442, 480, 152, 394, 40, 275, 448, 844, 3, 451, + 2117, 2118, 3328, 522, 522, 2122, 290, 290, 40, 59, + 172, 177, 11, 40, 447, 167, 519, 315, 316, 317, + 519, 2138, 519, 1188, 2141, 2142, 2143, 181, 194, 519, + 518, 167, 1197, 199, 3, 39, 518, 3, 3270, 295, + 518, 516, 2159, 2160, 516, 892, 431, 431, 2142, 2166, + 431, 431, 2169, 519, 519, 517, 315, 316, 317, 519, + 527, 522, 2912, 148, 520, 519, 304, 172, 519, 2186, + 501, 237, 501, 519, 501, 2169, 518, 315, 316, 317, + 519, 1040, 2199, 516, 382, 431, 519, 520, 155, 519, + 477, 519, 2186, 518, 250, 518, 518, 518, 3461, 2216, + 2217, 502, 40, 59, 522, 507, 1040, 2169, 509, 510, + 511, 512, 513, 514, 503, 291, 2233, 291, 2235, 2169, + 454, 419, 522, 382, 2186, 244, 292, 1223, 59, 59, + 2181, 2248, 979, 266, 393, 2169, 2186, 275, 469, 152, + 518, 431, 989, 203, 382, 152, 152, 3464, 282, 2266, + 2267, 2268, 2186, 282, 452, 431, 415, 431, 74, 1580, + 419, 431, 431, 519, 80, 463, 518, 423, 518, 425, + 40, 1592, 355, 1594, 3182, 522, 519, 93, 288, 290, + 40, 419, 480, 480, 2266, 2267, 2268, 152, 2305, 526, + 280, 519, 448, 452, 2311, 451, 172, 518, 59, 186, + 1621, 117, 2343, 119, 463, 167, 504, 519, 80, 518, + 1144, 519, 172, 519, 452, 3054, 143, 1313, 519, 199, + 518, 480, 518, 516, 2332, 463, 2332, 2332, 394, 528, + 2347, 519, 519, 518, 2332, 2352, 522, 519, 519, 301, + 361, 518, 480, 522, 519, 504, 291, 181, 519, 152, + 176, 442, 519, 518, 522, 2372, 519, 1104, 519, 518, + 40, 519, 1427, 1428, 1223, 2347, 504, 1114, 1433, 520, + 2387, 2388, 518, 518, 86, 519, 518, 40, 40, 2396, + 518, 522, 172, 522, 457, 518, 479, 519, 1135, 1223, + 519, 207, 199, 519, 522, 517, 3256, 1144, 3258, 3296, + 40, 517, 519, 507, 1725, 1726, 519, 519, 519, 290, + 463, 2362, 59, 519, 2396, 117, 519, 2434, 519, 3268, + 60, 519, 480, 205, 40, 227, 518, 88, 192, 280, + 280, 520, 520, 520, 520, 520, 502, 431, 520, 520, + 2434, 520, 520, 509, 510, 511, 512, 513, 514, 520, + 520, 520, 431, 520, 1313, 40, 520, 2474, 517, 275, + 3271, 3452, 3273, 520, 280, 520, 106, 517, 1789, 1427, + 1428, 520, 2434, 2490, 2502, 1433, 520, 520, 1799, 1313, + 520, 1802, 275, 520, 2525, 520, 107, 507, 520, 3397, + 2507, 480, 520, 520, 520, 520, 2513, 2514, 3387, 290, + 2434, 3406, 520, 520, 520, 520, 519, 2566, 2525, 419, + 9, 354, 519, 329, 336, 519, 518, 518, 518, 518, + 2561, 518, 2539, 59, 522, 2542, 522, 2544, 519, 199, + 517, 347, 3381, 519, 2551, 2552, 176, 1533, 2555, 2556, + 192, 522, 91, 2560, 2561, 8, 462, 519, 11, 347, + 2567, 178, 15, 16, 518, 40, 19, 20, 21, 152, + 124, 520, 202, 519, 152, 2582, 40, 519, 369, 369, + 40, 2612, 519, 36, 518, 2592, 203, 1898, 7, 8, + 2580, 2580, 518, 40, 13, 522, 457, 2586, 2580, 2580, + 19, 2580, 2580, 518, 23, 2612, 25, 310, 280, 2580, + 29, 30, 31, 518, 249, 34, 442, 191, 37, 38, + 457, 251, 41, 74, 241, 44, 45, 518, 293, 74, + 80, 261, 9, 151, 1371, 519, 519, 518, 371, 519, + 133, 1627, 448, 273, 517, 517, 2653, 59, 273, 2656, + 2657, 457, 2659, 93, 172, 442, 75, 76, 507, 1714, + 40, 290, 293, 462, 2671, 518, 2673, 293, 519, 205, + 518, 290, 519, 389, 2615, 305, 519, 2618, 295, 122, + 290, 2653, 101, 519, 1533, 2657, 454, 2659, 368, 108, + 109, 110, 111, 112, 3434, 25, 148, 314, 36, 2730, + 2698, 368, 2698, 2698, 2645, 2694, 298, 2018, 2640, 1533, + 2698, 874, 1782, 2261, 2653, 3298, 2590, 3437, 3391, 2660, + 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 359, + 3538, 2936, 2375, 3412, 2723, 1889, 851, 3516, 3175, 3465, + 3474, 3509, 1210, 3232, 2254, 2267, 2753, 2778, 2712, 2756, + 3463, 3472, 2632, 2251, 384, 3460, 373, 2659, 1337, 2371, + 2370, 2331, 2396, 380, 3054, 1310, 2773, 2774, 2689, 222, + 2233, 2778, 1167, 403, 2781, 1013, 2199, 1750, 1627, 1765, + 1190, 1013, 2455, 3446, 2216, 1714, 1191, 3369, 3260, 1749, + 1193, 23, 2186, 1999, 3096, 2781, 991, 315, 316, 317, + 2433, 2808, 2434, 1627, 2482, 3196, 423, 2855, 425, 805, + 3373, 794, 2014, 1898, 1898, 1898, 2823, 3372, 1040, 2094, + 2514, 2200, 2829, 2830, 2142, 442, 2048, 2834, 2835, 1456, + 2824, 448, 2839, 989, 451, 2842, 2843, 2139, 2869, 292, + 2847, 2848, 3360, 2862, 2851, 989, 989, 989, 2855, 989, + 989, 2096, 989, 2535, 2580, 2862, 989, 3358, 789, 2007, + 1826, 892, 2173, 172, 382, 989, 1355, 1689, 2304, 2591, + 1690, 2855, 1927, 1928, 1929, 1930, 1931, 1932, 101, -1, + 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, + -1, -1, -1, 1247, -1, 2206, 2207, -1, -1, 2906, + -1, 419, -1, 2855, -1, -1, -1, 2914, -1, -1, + -1, -1, -1, -1, -1, 2855, 1765, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 2933, -1, 1914, -1, + -1, 2855, -1, -1, 452, 2942, -1, -1, -1, -1, + 1926, 1765, -1, 1680, -1, 463, -1, 40, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 126, + 127, 41, 480, -1, -1, -1, -1, 60, -1, 2976, + 1956, -1, 2913, -1, -1, -1, -1, 1963, -1, 1927, + 1928, 1929, 1930, 1931, 1932, -1, 504, 1935, 1936, 1937, + 1938, 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, -1, + 518, 1223, -1, 0, -1, 172, 315, 316, 317, -1, + -1, 3018, -1, 106, 107, 2001, 1753, 1754, -1, 2005, + -1, -1, -1, 20, 117, 2011, 23, -1, 108, -1, + 110, -1, 112, -1, -1, -1, 37, -1, -1, 3046, + 37, 42, 3073, -1, 3033, -1, 3018, 3054, 2034, 46, + 3057, 3058, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, 2117, 2118, -1, 1914, 3073, -1, -1, -1, + -1, -1, -1, 382, -1, 1812, -1, 1926, 75, 76, + 77, -1, -1, 176, -1, -1, -1, -1, 1825, 1826, + 1914, 1313, -1, -1, 3101, -1, -1, -1, -1, 3106, + 101, -1, 1926, -1, 101, -1, -1, 1956, -1, 202, + 419, 3118, 3119, -1, 1963, 3122, -1, 3124, -1, -1, + -1, 540, -1, -1, -1, -1, 545, -1, -1, 548, + -1, -1, 1956, -1, -1, -1, -1, 556, -1, 1963, + -1, -1, 3149, 452, -1, -1, -1, -1, 315, 316, + 317, -1, 2001, -1, 463, -1, 2005, -1, 251, -1, + -1, 1898, 2011, -1, -1, -1, 3173, 1904, 261, 2117, + 2118, 480, 173, -1, -1, -1, -1, 2001, 2233, -1, + 273, 2005, 275, 2494, 2495, 2034, -1, 2011, -1, -1, + -1, -1, -1, -1, -1, 504, -1, 3204, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 209, 518, + 2034, -1, 305, -1, -1, 382, -1, -1, -1, 3226, + -1, -1, -1, -1, 225, -1, 393, -1, -1, -1, + -1, 0, 3221, -1, 235, -1, -1, -1, -1, 3246, + -1, -1, -1, 3184, -1, -1, -1, -1, 415, 3256, + -1, 3258, 419, 3260, 3226, -1, -1, 3264, -1, 3266, + -1, 3268, 3246, -1, 3205, 3206, 359, -1, 269, -1, + -1, -1, 3279, -1, -1, -1, -1, 3284, 37, 3286, + -1, -1, -1, 42, -1, 452, -1, 3294, 3229, 290, + -1, 384, -1, -1, 3246, -1, 463, -1, -1, -1, + 3307, -1, -1, -1, -1, 3312, 3295, -1, 3297, -1, + 403, 1533, 405, 480, 315, 408, -1, -1, -1, -1, + -1, 322, 3246, -1, -1, -1, -1, 746, 747, 748, + -1, 100, -1, -1, -1, 3307, -1, 504, -1, -1, + -1, -1, 101, -1, -1, 2656, -1, -1, 3337, -1, + -1, 518, 3359, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3369, 364, 3353, -1, 2352, -1, -1, 788, + 789, -1, -1, -1, 3381, 794, -1, 796, 147, -1, + -1, -1, 383, -1, -1, -1, 805, -1, 3395, -1, + 809, 810, -1, 162, -1, 814, 815, -1, 167, -1, + -1, -1, -1, 172, -1, 1627, 3413, -1, 827, 828, + 829, 3395, 181, 832, 173, -1, -1, 186, -1, -1, + -1, -1, -1, 842, 843, 518, 845, -1, 847, -1, + 3437, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 859, -1, -1, 3395, -1, 3452, 865, -1, -1, 218, + 209, 452, -1, 3437, 3461, -1, 3463, -1, 877, -1, + 540, -1, -1, -1, -1, 545, 225, -1, 548, 238, + -1, 3395, 891, 892, -1, -1, 235, -1, -1, 3486, + 2791, -1, -1, -1, -1, 3437, -1, -1, -1, 3478, + -1, 3463, -1, 3500, 3501, 3502, -1, -1, -1, -1, + 2555, 2556, 3486, 2352, 2490, -1, -1, 926, 927, 40, + 269, -1, -1, 3437, -1, 3504, 3457, -1, 287, 938, + 3527, 290, -1, 942, 943, 944, 945, 296, 2352, 60, + -1, -1, -1, -1, 3486, -1, 2273, -1, 13, 958, + -1, -1, 539, 1765, 19, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 30, 315, -1, -1, -1, + -1, 3568, 3486, 322, -1, 2551, -1, 336, -1, 44, + 45, 990, 991, -1, 993, 106, -1, 996, -1, -1, + -1, -1, -1, 1002, 1003, -1, -1, -1, 2325, 1008, + -1, -1, 361, -1, -1, 1014, -1, -1, -1, -1, + -1, -1, 1021, -1, -1, 364, 2343, 2555, 2556, -1, + -1, -1, 1031, -1, -1, -1, -1, -1, -1, -1, + 2931, -1, -1, -1, 383, 2936, -1, -1, -1, 1048, + -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, + -1, 2490, -1, -1, -1, -1, -1, -1, -1, -1, + 419, 2388, -1, 55, -1, -1, -1, -1, -1, -1, + -1, 2398, -1, 2400, -1, -1, 2490, 2404, -1, 2406, + 2656, 202, 2983, 2984, -1, -1, -1, -1, 447, -1, + 1099, -1, -1, -1, -1, -1, -1, -1, 457, -1, + -1, 172, 1914, 452, -1, -1, -1, -1, 2753, -1, + 102, -1, 2551, -1, 1926, -1, -1, -1, 477, -1, + 479, 480, -1, -1, -1, -1, 796, -1, -1, -1, + 251, 123, -1, 2778, -1, -1, -1, 2551, -1, -1, + 261, 1150, -1, 1152, 1956, -1, -1, -1, -1, 141, + -1, 1963, 273, 145, -1, -1, -1, 516, 1167, 1168, + 519, 520, 521, -1, -1, 1174, 753, 754, -1, -1, + -1, -1, -1, -1, -1, -1, 168, -1, 2823, 171, + 2756, -1, -1, -1, 305, -1, -1, -1, 1197, 2001, + -1, -1, -1, 2005, -1, 187, -1, -1, -1, 2011, + 1209, 1210, -1, -1, -1, -1, -1, 794, -1, -1, + -1, -1, -1, 1222, -1, 2753, -1, 2656, 805, -1, + -1, 891, 2034, -1, 1040, -1, -1, 0, -1, -1, + 1239, -1, -1, 304, 1243, -1, -1, -1, 359, 1248, + 1040, -1, 2656, -1, 315, 316, 317, -1, -1, -1, + -1, -1, -1, 24, -1, -1, 926, -1, -1, 2835, + -1, -1, -1, 384, -1, -1, -1, 854, -1, 2914, + -1, -1, 942, 943, 944, 945, -1, 8, -1, -1, + 11, -1, 403, -1, 15, 16, -1, 874, 280, -1, + -1, 3192, 3193, -1, -1, -1, 288, 1306, -1, 1308, + -1, -1, -1, 3204, -1, -1, -1, -1, 1317, -1, + 81, 382, -1, -1, -1, 46, -1, 2756, 310, 1328, + -1, -1, 53, 993, -1, -1, 97, 100, 1337, 2656, + -1, -1, -1, 1342, -1, 1344, 1345, -1, 1347, 1348, + -1, -1, 2756, -1, -1, -1, -1, 339, 419, 80, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + -1, -1, 2689, 15, 16, -1, 2942, 19, 20, 21, + -1, -1, -1, -1, 147, 146, 2914, -1, -1, -1, + -1, 452, -1, -1, -1, 156, -1, -1, -1, 162, + -1, -1, 463, -1, 167, 982, 2835, -1, 169, 172, + 2976, -1, -1, 174, -1, -1, -1, 1223, 181, 480, + -1, -1, 3057, 186, 145, -1, -1, -1, 1427, 1428, + -1, 2835, -1, 1223, 1433, -1, 1435, 1014, -1, -1, + -1, -1, 203, 504, 1021, -1, -1, -1, -1, 1448, + -1, 1450, 1451, -1, -1, 218, 177, 518, -1, 1458, + -1, 1460, -1, 1462, -1, -1, 1465, -1, -1, -1, + -1, 1470, -1, 194, 1473, 238, 1475, -1, 199, 1056, + 1479, -1, 1481, -1, 1483, 246, -1, -1, -1, 250, + -1, 1068, 3058, -1, -1, -1, -1, -1, -1, -1, + -1, 556, -1, -1, -1, -1, -1, 1313, -1, -1, + -1, -1, -1, 2942, -1, -1, 237, -1, 1095, -1, + -1, -1, -1, 1313, 287, -1, -1, 290, -1, 3057, + -1, -1, -1, 296, -1, 3101, -1, -1, 2942, -1, + -1, -1, 2859, -1, -1, -1, -1, 2976, -1, 1209, + 2352, -1, -1, 314, -1, -1, -1, 199, -1, 320, + -1, -1, 1222, -1, -1, -1, -1, -1, -1, -1, + 3461, 292, 2976, 336, 335, -1, -1, -1, -1, -1, + 222, -1, -1, 1243, -1, -1, -1, -1, -1, 1588, + -1, -1, -1, -1, -1, -1, -1, -1, 361, -1, + -1, 1600, -1, -1, 1181, 1182, -1, 1184, -1, 370, + -1, 1040, 373, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 384, -1, -1, 387, -1, -1, 3058, + -1, 3266, -1, -1, -1, -1, -1, -1, 3204, -1, + 1639, -1, -1, 1642, 405, -1, -1, -1, 1308, -1, + 292, -1, -1, -1, 3058, -1, 419, 1317, 419, -1, + -1, -1, -1, -1, 425, 426, -1, -1, -1, -1, + -1, -1, 3101, 394, -1, 436, -1, -1, -1, -1, + -1, 442, -1, -1, 447, -1, -1, 1686, 2490, 1688, + -1, 1690, 747, 748, 457, -1, -1, 3101, -1, -1, + -1, 1700, -1, 1702, -1, -1, -1, -1, -1, 470, + 3027, -1, -1, -1, 477, 1714, 479, 480, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1533, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3054, -1, -1, + 1739, -1, 1741, 1533, -1, -1, -1, -1, -1, 2551, + -1, -1, -1, 516, 1753, 1754, 519, 520, 521, -1, + 1759, 1760, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1770, 1771, 1772, 1773, 3204, 1775, 1354, -1, -1, + -1, 502, 1781, -1, 1783, -1, -1, -1, 509, 510, + 511, 512, 513, 514, 1223, -1, 1795, 1796, 1458, -1, + 3204, 1800, 1801, -1, -1, -1, 1805, 1806, 1807, 1808, + 865, 1810, 1811, -1, -1, -1, -1, -1, 3135, -1, + -1, 1627, -1, -1, -1, -1, -1, -1, 1827, -1, + -1, -1, -1, -1, -1, -1, 1835, 1627, 1837, 1838, + 1839, 1840, 1841, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2656, -1, -1, -1, -1, 1858, + -1, -1, -1, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, -1, -1, -1, -1, -1, 1877, -1, + -1, -1, -1, 1460, 1313, 1462, -1, 3204, 1465, -1, + -1, -1, -1, 1470, -1, 3461, 1473, -1, 1475, -1, + -1, -1, 1479, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1927, 1928, + 1929, 1930, 1931, 1932, -1, -1, 1935, 1936, 1937, 1938, + 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, -1, -1, + -1, -1, -1, 1008, 2756, -1, -1, -1, -1, 1765, + -1, -1, -1, -1, -1, -1, 1965, -1, -1, -1, + -1, -1, -1, -1, -1, 1765, 1031, -1, 1977, -1, + -1, -1, -1, -1, -1, 1562, -1, -1, 1987, -1, + -1, -1, -1, -1, 1993, -1, -1, -1, -1, -1, + 1999, -1, -1, -1, -1, 2004, -1, -1, -1, -1, + -1, -1, 3329, 100, 2013, 2014, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1688, -1, + 1690, -1, 3461, 2835, -1, -1, -1, -1, 8, -1, + 1700, 11, -1, -1, 1099, 15, 16, 17, 18, 19, + 20, 21, -1, -1, -1, -1, -1, 3461, -1, -1, + 147, -1, -1, -1, -1, 1642, 36, -1, -1, -1, + -1, -1, -1, -1, -1, 162, 46, -1, -1, 1739, + 167, -1, -1, 53, -1, 172, 2085, -1, -1, -1, + 2089, -1, -1, -1, 181, 2094, -1, -1, -1, 186, + -1, -1, -1, -1, 1533, -1, -1, -1, 1914, -1, + 80, -1, 1167, 1168, -1, -1, -1, -1, 2117, 2118, + 1926, -1, -1, -1, 1914, -1, -1, -1, -1, -1, + -1, 218, -1, -1, 1711, -1, 1926, 2136, 8, -1, + 2942, 11, -1, 2142, 3461, 15, 16, -1, -1, -1, + 1956, 238, 8, -1, -1, 11, -1, 1963, -1, 15, + 16, -1, -1, 19, 20, 21, 1956, -1, -1, -1, + 2169, -1, -1, 1963, 2976, -1, 46, 1837, 1838, 1839, + 1840, 1841, 2181, 53, -1, -1, -1, 2186, -1, -1, + -1, 2190, -1, -1, -1, 2001, -1, -1, 1627, 2005, + 287, -1, -1, 290, -1, 2011, -1, 177, -1, 296, + 80, 2001, -1, -1, -1, 2005, -1, -1, -1, -1, + -1, 2011, -1, -1, 194, -1, -1, -1, 2034, 199, + -1, 2230, -1, -1, 2233, -1, -1, 2236, -1, -1, + -1, -1, -1, -1, 2034, -1, -1, -1, -1, 336, + -1, -1, 222, 223, -1, -1, 3058, 2256, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, + -1, 1848, -1, -1, 361, 145, -1, -1, -1, -1, + -1, -1, -1, 1860, -1, -1, -1, -1, -1, 1344, + 1345, -1, 1347, -1, -1, -1, -1, -1, -1, 3101, + -1, -1, -1, -1, -1, 275, -1, 177, 278, -1, + -1, -1, -1, -1, -1, -1, -1, 1977, -1, -1, + -1, -1, 292, -1, 194, 295, -1, -1, 2327, 199, + -1, -1, 419, -1, -1, 2334, 1765, -1, -1, -1, + -1, -1, -1, 199, -1, -1, 2345, -1, -1, 2348, + 2349, 2350, 2351, -1, -1, -1, -1, -1, -1, -1, + 447, -1, -1, 2362, -1, 2364, 222, 237, 2367, -1, + 457, -1, -1, -1, -1, 2374, -1, -1, -1, -1, + -1, 2380, -1, -1, -1, -1, -1, -1, -1, -1, + 477, -1, 479, 480, -1, 1450, -1, -1, -1, -1, + -1, -1, 3204, 2402, 2403, -1, 2405, -1, -1, -1, + 1987, -1, -1, -1, -1, -1, 1993, -1, -1, -1, + -1, -1, 292, -1, 394, -1, 1481, -1, 1483, 516, + -1, -1, 519, 520, 521, 2434, 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, + -1, -1, -1, -1, -1, 2454, -1, -1, -1, -1, + -1, -1, -1, 2462, 2463, 2464, -1, -1, -1, -1, + -1, -1, -1, 2472, -1, 2474, -1, 2476, -1, -1, + -1, -1, -1, 2482, -1, 1914, -1, -1, 8, -1, + -1, 11, -1, -1, -1, 15, 16, 1926, -1, 19, + 20, 21, -1, 2502, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 36, 2516, -1, -1, + -1, -1, -1, -1, 394, -1, -1, 1956, -1, -1, + -1, -1, 502, -1, 1963, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, 2122, 2352, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 2555, 2556, 528, -1, + -1, -1, 2352, -1, -1, 2142, -1, -1, -1, -1, + -1, -1, 2001, -1, -1, -1, 2005, -1, -1, -1, + -1, 2158, 2011, -1, -1, 2584, -1, -1, -1, -1, + -1, 2590, 2169, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2034, -1, 2606, -1, 2186, + -1, 2610, -1, -1, -1, 2614, 2615, -1, -1, 2618, + -1, -1, -1, 2622, 2623, 2624, -1, 2626, -1, -1, + -1, -1, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, 512, 513, 514, -1, 2645, -1, 2647, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, 3461, + -1, 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, + 2669, -1, -1, -1, 2334, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2490, -1, 1741, -1, -1, 2349, + 2350, 2351, -1, -1, 2693, -1, -1, -1, -1, -1, + 2490, 2700, 222, -1, 2364, 1760, -1, 2367, -1, -1, + -1, -1, -1, 2712, 2374, 1770, -1, 1772, -1, -1, + 1775, -1, -1, -1, -1, -1, 1781, -1, 1783, -1, + -1, -1, -1, 2732, -1, -1, -1, -1, -1, -1, + -1, 1796, -1, 2742, -1, 2551, 1801, -1, -1, -1, + 1805, 1806, 1807, 1808, 2753, 1810, 1811, -1, -1, -1, + 2759, 2551, -1, -1, -1, -1, 2343, 2766, 2767, 2768, + 2769, -1, 292, -1, -1, -1, -1, -1, -1, 2778, + -1, -1, 2781, -1, -1, -1, 2785, 2786, -1, -1, + -1, -1, -1, -1, -1, 2794, -1, -1, -1, -1, + -1, -1, 2462, 2463, 2464, -1, -1, -1, 98, 996, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 2822, -1, 2824, -1, 8, -1, -1, + 11, -1, -1, -1, 15, 16, 126, 127, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2656, -1, 46, -1, 2853, -1, 2855, -1, -1, 53, + -1, -1, 37, -1, -1, 46, 2656, 42, -1, -1, + 2869, -1, 53, -1, 2873, -1, -1, -1, -1, -1, + 2879, -1, 172, -1, 8, -1, 80, 11, -1, -1, + -1, 15, 16, -1, 2893, -1, -1, -1, -1, 80, + 2899, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1965, -1, -1, 2912, 2913, 2914, -1, -1, -1, -1, + -1, 2920, 46, 2352, -1, -1, 101, -1, -1, 53, + -1, -1, -1, -1, -1, -1, -1, -1, 2937, -1, + -1, -1, -1, -1, 1999, -1, 2606, -1, 2525, 2004, + 2756, 145, -1, -1, -1, -1, 80, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 2756, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, 177, 2561, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, 177, 36, 173, -1, + 194, -1, -1, 2580, -1, 199, 181, 46, -1, 2586, + 1197, -1, -1, 194, 53, -1, 3015, -1, 199, -1, + 3019, 145, -1, -1, -1, 315, 316, 317, -1, 2835, + 2085, -1, -1, 3032, 209, 2612, -1, -1, -1, 2094, + 2700, 80, -1, 237, -1, 2835, -1, -1, -1, -1, + 225, 3050, -1, 177, -1, -1, 237, -1, 3057, -1, + 235, 2490, -1, -1, -1, -1, -1, -1, -1, -1, + 194, -1, -1, -1, 8, 199, -1, 11, -1, -1, + -1, 15, 16, -1, 3083, 19, 20, 21, -1, -1, + 3089, -1, 382, -1, 269, -1, -1, 3096, 292, -1, + -1, -1, 36, 393, -1, -1, 2766, 2767, 2768, 2769, + -1, 292, -1, 237, -1, 290, -1, 2694, -1, -1, + -1, -1, 2551, -1, -1, 415, 2181, -1, -1, 419, + -1, -1, 3131, -1, -1, -1, 2942, -1, 177, -1, + 315, -1, -1, -1, -1, -1, 2723, 322, -1, 439, + -1, -1, 2942, 2730, 3153, 194, -1, -1, -1, 3158, + 199, -1, 452, -1, -1, -1, -1, -1, 292, -1, + 2976, -1, -1, 463, -1, 2230, -1, -1, -1, -1, + -1, 2236, -1, 222, 223, 3184, 2976, -1, -1, 364, + 480, -1, -1, -1, -1, -1, -1, -1, 237, -1, + 394, 2778, -1, -1, -1, -1, 3205, 3206, 383, -1, + 840, 841, -1, 394, 504, -1, -1, -1, -1, -1, + -1, -1, -1, 3222, -1, 3224, -1, 2656, 518, -1, + 3229, -1, -1, -1, -1, -1, 275, -1, -1, 278, + 1427, 1428, -1, -1, 3243, -1, 1433, 3246, -1, -1, + -1, -1, 3058, 292, -1, -1, 295, -1, -1, -1, + 2920, -1, -1, -1, -1, -1, -1, 3266, 3058, -1, + 394, 3270, 3271, -1, 3273, -1, -1, 452, 2855, -1, + -1, 911, 457, -1, -1, 915, 916, -1, 222, -1, + -1, -1, 2869, -1, -1, 3101, -1, -1, -1, 3298, + -1, -1, -1, -1, -1, -1, 3305, 2362, 502, -1, + -1, 3101, -1, -1, -1, 509, 510, 511, 512, 513, + 514, 502, -1, -1, 505, 506, 507, 2756, 509, 510, + 511, 512, 513, 514, 8, -1, 3335, 11, 968, -1, + -1, 15, 16, -1, -1, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, 394, 986, -1, 292, -1, + -1, -1, 992, -1, -1, 995, -1, -1, 998, 999, + 1000, 1001, -1, -1, 3373, -1, -1, -1, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, -1, 3395, -1, 3204, -1, + -1, -1, -1, -1, -1, -1, 2835, -1, 1038, 1039, + -1, -1, -1, -1, 3204, -1, -1, 2472, -1, -1, + -1, 2476, -1, 3422, -1, -1, -1, 2482, -1, -1, + 1060, -1, -1, -1, -1, 3434, 3435, -1, 3437, 3438, + -1, -1, -1, -1, -1, -1, -1, 3446, -1, 1079, + -1, -1, -1, -1, -1, -1, 3033, -1, 3457, -1, + 1090, 1091, 1092, 502, 1094, 1095, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, -1, -1, -1, -1, + 3479, 1668, -1, 522, -1, -1, -1, 3486, -1, -1, + -1, -1, -1, -1, -1, -1, 3073, -1, -1, 1129, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, - -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, + -1, -1, -1, 2942, -1, -1, -1, 1147, 1148, -1, + -1, -1, -1, -1, 3523, -1, -1, 1714, -1, -1, + -1, -1, -1, -1, -1, -1, 26, -1, -1, 3538, + -1, -1, 32, -1, -1, -1, -1, 2976, 222, -1, + 40, -1, -1, 1183, -1, 2610, -1, 1187, 1188, 2614, + 2615, -1, 3222, 2618, -1, -1, -1, -1, 1198, 1199, + 60, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, 8, -1, 3243, 11, -1, -1, -1, 15, 16, + 2645, -1, 19, 20, 21, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2660, 2661, 2662, 2663, 2664, + 2665, 2666, 2667, 2668, 2669, -1, 106, -1, 292, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1258, 3058, + -1, -1, -1, -1, -1, -1, -1, 1267, -1, -1, + -1, -1, -1, -1, 3221, 3305, -1, 137, -1, -1, + -1, -1, -1, -1, -1, 3461, -1, -1, -1, -1, + -1, 1291, -1, -1, -1, 3242, -1, -1, -1, -1, + -1, 3461, 3101, -1, -1, 3335, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2759, -1, -1, -1, -1, -1, + -1, -1, 202, -1, -1, -1, -1, -1, 3295, -1, + 3297, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2785, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1927, 1928, 1929, 1930, 1931, 1932, -1, 1377, 1935, 1936, + 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, -1, -1, + 3337, 251, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 261, -1, -1, 8, 3204, 3353, 11, -1, -1, + -1, 15, 16, 273, -1, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, 222, -1, -1, -1, -1, + -1, -1, 36, -1, 294, -1, -1, -1, -1, -1, + 1440, -1, 1442, 1443, -1, 305, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1455, 1456, -1, -1, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, 1472, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 2913, -1, + -1, -1, -1, 353, -1, 292, -1, 357, -1, 359, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 384, -1, -1, -1, -1, 389, + -1, 3478, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 403, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3504, -1, -1, + 2117, 2118, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, 1574, 11, -1, -1, -1, 15, + 16, -1, 1582, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 460, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, -1, 53, 222, -1, + -1, -1, 1622, -1, -1, -1, -1, -1, 1628, 1629, + 1630, 1631, 1632, 1633, 1634, 1635, -1, -1, -1, -1, + 1640, 1641, -1, -1, 80, 1645, 0, -1, -1, 1649, + -1, -1, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, + 1660, -1, 3461, 1663, 3089, -1, -1, -1, 22, -1, + 1670, 3096, 1672, -1, -1, -1, 2233, -1, 32, -1, + 34, 35, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 1691, -1, 47, -1, -1, -1, -1, 52, -1, + -1, -1, -1, -1, -1, -1, -1, 61, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, + -1, 75, -1, -1, -1, 1725, 1726, -1, 3153, -1, + 84, -1, 86, 3158, -1, -1, -1, -1, -1, -1, + -1, 177, -1, -1, 98, -1, 100, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 111, 194, 3184, + -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, + -1, -1, 126, 127, 128, -1, -1, -1, -1, -1, + 3205, 3206, -1, 137, -1, -1, 222, 223, -1, 143, + -1, -1, -1, -1, -1, -1, -1, 151, -1, 153, + 154, 237, -1, -1, 3229, -1, -1, 996, -1, -1, + -1, -1, -1, -1, 168, -1, 1816, -1, 172, -1, + 1820, -1, 3, 1823, 1824, -1, -1, 8, -1, -1, + 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, + 21, -1, 278, -1, 198, 3270, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 36, 292, -1, -1, 40, + 214, -1, -1, -1, 1864, 46, -1, -1, -1, -1, + -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 240, -1, -1, 1889, + 1890, -1, -1, -1, -1, -1, -1, -1, -1, 80, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, -1, -1, -1, 1918, 1919, + -1, 1921, -1, -1, -1, -1, 1115, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1950, 1951, -1, -1, 1954, -1, -1, -1, 394, -1, + -1, 315, 316, 317, -1, -1, -1, -1, -1, 323, + -1, -1, 326, -1, 1163, -1, -1, -1, -1, -1, + -1, -1, -1, 1983, -1, -1, -1, -1, -1, 1989, + -1, -1, -1, -1, -1, -1, 177, -1, 2555, 2556, + 37, -1, -1, 357, -1, 42, -1, 2007, 1197, 2009, + -1, -1, 366, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 382, -1, + -1, -1, 3457, -1, -1, 389, -1, -1, -1, 393, + -1, 222, 223, -1, -1, -1, -1, 2047, -1, 403, + -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, + -1, 415, -1, 1252, 101, 419, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, -1, -1, -1, 2084, 439, -1, 2087, -1, -1, + -1, -1, 2092, 2093, 275, -1, -1, 278, 452, -1, + -1, 455, -1, -1, 458, 1294, -1, -1, -1, 463, + -1, 292, 1301, -1, 295, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 480, -1, -1, -1, + -1, 26, -1, -1, -1, -1, 173, 32, 2138, -1, + -1, 2141, -1, 2143, -1, 40, -1, -1, -1, -1, + 504, -1, -1, -1, -1, -1, -1, -1, -1, 2159, + -1, -1, 1351, -1, 518, 60, -1, 521, -1, -1, + -1, -1, 209, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1375, -1, 225, -1, + -1, -1, -1, -1, -1, -1, 2753, -1, 235, 2199, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 106, -1, 394, -1, -1, 2216, 2217, -1, -1, + -1, 2778, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 269, -1, 1423, 2235, 1425, -1, 1427, 1428, + -1, 1430, 137, -1, 1433, -1, -1, 1436, 2248, -1, + 1439, -1, -1, 290, -1, 1444, -1, -1, 1447, -1, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 17, 18, 19, 20, 21, 315, -1, + -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, + -1, -1, 36, -1, -1, -1, 40, 1486, -1, -1, + -1, -1, 46, -1, -1, 2305, -1, 202, -1, 53, + -1, 2311, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 502, -1, -1, 505, 506, 507, 364, 509, 510, + 511, 512, 513, 514, -1, -1, 80, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 383, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 251, 2914, -1, -1, + -1, -1, -1, -1, -1, -1, 261, -1, -1, -1, + -1, -1, 2372, -1, -1, -1, -1, -1, 273, -1, + -1, 1570, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, 1586, -1, 294, + 15, 16, 17, 18, 19, 20, 21, 1596, 1597, 1598, + 305, -1, -1, -1, 1603, 452, -1, -1, 1607, -1, + 457, 36, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 46, -1, 177, -1, -1, -1, -1, 53, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 194, -1, -1, -1, -1, 199, -1, -1, 353, -1, + -1, -1, 357, -1, 359, 80, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, + 1669, -1, -1, -1, -1, -1, -1, -1, -1, 384, + -1, -1, -1, 237, 389, -1, -1, -1, -1, -1, + 3057, -1, -1, -1, -1, -1, -1, 2507, 403, -1, + -1, -1, -1, 2513, 2514, -1, -1, -1, -1, 1708, + -1, -1, -1, -1, -1, 2525, -1, -1, -1, -1, + -1, 275, -1, -1, 278, 1724, -1, -1, -1, 2539, + 1729, -1, 2542, -1, 2544, -1, -1, -1, 292, -1, + -1, 295, 2552, -1, -1, -1, -1, 1746, -1, -1, + 2560, 2561, 177, -1, -1, 460, -1, 2567, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, 2582, -1, 199, -1, -1, -1, -1, -1, + 8, -1, 2592, 11, -1, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, 222, 223, -1, + -1, -1, 2612, -1, -1, -1, -1, -1, 36, -1, + -1, -1, 237, -1, -1, -1, -1, -1, 46, -1, + -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, + 8, -1, -1, 11, -1, -1, -1, 15, 16, -1, + 394, 19, 20, 21, -1, -1, -1, -1, -1, -1, + 275, -1, 80, 278, -1, -1, -1, -1, 36, -1, + -1, 2671, -1, 2673, -1, -1, -1, 292, 46, -1, + 295, -1, -1, -1, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3266, + -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1916, -1, -1, + -1, -1, -1, -1, -1, 1924, 1925, -1, 1927, 1928, + 1929, 1930, 1931, 1932, -1, -1, 1935, 1936, 1937, 1938, + 1939, 1940, 1941, 1942, 1943, 1944, 1945, -1, 502, 177, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, 2773, 2774, 519, 194, -1, -1, 394, + -1, 199, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 222, 223, -1, -1, 2808, 177, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, + -1, -1, -1, 2823, -1, -1, 194, -1, -1, 2829, + 2830, 199, -1, -1, 2834, -1, -1, -1, -1, 2839, + -1, -1, 2842, 2843, -1, -1, -1, 2847, 2848, -1, + -1, 2851, -1, -1, 222, 223, -1, 275, -1, -1, + 278, 2050, 2862, -1, 2053, -1, -1, -1, -1, 237, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, -1, -1, -1, 519, -1, 2906, 275, -1, -1, + 278, 2100, -1, -1, -1, 2104, 2105, 2106, 2107, 2108, + 2109, 2110, 2111, -1, 292, -1, -1, 295, 2117, 2118, + -1, 2120, 2121, 2933, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2134, -1, -1, 2137, -1, + -1, -1, -1, -1, -1, -1, 2145, 2146, 2147, 2148, + 2149, 2150, 2151, 2152, 2153, 2154, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, + -1, 2180, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 46, -1, -1, 394, -1, -1, -1, + 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2233, -1, 3046, -1, -1, -1, + -1, -1, 24, -1, -1, -1, -1, 80, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3073, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + -1, 519, -1, -1, -1, -1, 3106, -1, -1, 81, + -1, -1, -1, -1, -1, -1, -1, 2306, 3118, 3119, + -1, -1, 3122, -1, 3124, 97, -1, 2316, 2317, -1, + -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, 3149, + -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 194, -1, 3173, 146, -1, 199, -1, -1, -1, + -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 2383, -1, -1, 169, -1, 222, + 223, -1, 174, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, + 2409, 2410, 2411, -1, -1, 2414, 2415, 2416, 2417, 2418, + 2419, 203, -1, -1, 2423, 2424, 2425, 2426, 2427, 2428, + 2429, 2430, 2431, 2432, -1, -1, -1, -1, 2437, 2438, + -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, + 3260, -1, -1, -1, 3264, -1, -1, -1, 3268, 292, + -1, -1, 295, -1, 246, -1, 2465, -1, 250, 3279, + -1, -1, 2471, -1, 3284, -1, 3286, -1, -1, -1, + 8, -1, -1, 11, 3294, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, + -1, -1, 3312, -1, -1, -1, -1, 2506, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, + -1, -1, -1, -1, 2523, 53, -1, 2526, -1, -1, + -1, -1, -1, 2532, 2533, -1, -1, -1, 320, -1, + -1, 2540, 2541, -1, -1, -1, -1, -1, -1, 3359, + -1, -1, 80, 335, -1, 2554, 2555, 2556, 2557, 3369, + 2559, 394, -1, -1, 2563, -1, -1, -1, -1, -1, + 8, 3381, -1, 11, -1, -1, -1, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, -1, 370, -1, + -1, 373, -1, -1, -1, -1, -1, -1, 36, -1, + -1, -1, 384, 3413, -1, 387, -1, -1, 46, -1, + -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, + 2619, -1, -1, 405, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 419, -1, -1, + -1, -1, 80, -1, 426, -1, -1, -1, -1, 177, + -1, -1, -1, -1, 436, -1, -1, -1, -1, -1, + 442, -1, -1, -1, -1, -1, 194, -1, -1, 502, + -1, 199, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, -1, -1, -1, -1, 519, -1, 470, -1, + 3500, 3501, 3502, -1, 222, 223, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, -1, -1, 237, + 15, 16, 17, 18, 19, 20, 21, 3527, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 36, 2731, -1, -1, -1, -1, -1, -1, 177, + -1, 46, -1, -1, -1, -1, -1, 275, 53, -1, + 278, -1, -1, -1, 2753, -1, 194, 3, 3568, 5, + -1, 199, -1, -1, 292, -1, -1, 295, -1, -1, + -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, + -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2809, -1, 2811, -1, -1, -1, -1, -1, -1, 2818, + -1, -1, 68, 69, -1, -1, -1, -1, -1, 2828, + -1, -1, 2831, -1, 2833, -1, -1, 275, 2837, -1, + 278, 2840, 2841, -1, -1, 2844, 2845, -1, -1, -1, + -1, -1, -1, 2852, 292, -1, -1, 295, -1, -1, + -1, -1, 2861, 109, 110, -1, 394, 113, 114, -1, + -1, -1, 177, -1, -1, -1, -1, 2876, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2914, -1, 222, 223, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + -1, -1, 237, 15, 16, 17, 18, 19, 20, 21, + -1, -1, -1, 189, 190, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 36, -1, 394, -1, -1, -1, + -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, + 275, 53, -1, 278, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, 292, -1, -1, + 295, 519, -1, -1, -1, -1, -1, -1, 80, -1, + -1, -1, -1, -1, -1, -1, -1, 253, 254, 255, + 256, 257, 258, 259, 260, -1, -1, 263, 264, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3056, 3057, -1, + -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + -1, 519, 3081, 3082, -1, -1, -1, -1, -1, 394, + -1, 337, 338, -1, -1, 177, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3105, -1, -1, -1, + 3109, -1, 194, 3112, 3113, 3114, -1, 199, 3117, -1, + -1, 3120, 3121, -1, -1, -1, -1, -1, -1, -1, + 3129, -1, 378, 379, -1, -1, -1, -1, -1, -1, + 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3170, -1, -1, -1, -1, -1, 3176, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3189, -1, -1, 275, -1, -1, 278, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + 292, -1, -1, 295, 519, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 474, 475, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3248, + -1, -1, 498, 499, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3281, 3282, 3283, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3301, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 394, -1, 3313, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3374, -1, -1, -1, -1, + -1, -1, -1, -1, 3383, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3408, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, -1, 3433, -1, -1, 519, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3476, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 3530, 75, 76, 77, 78, 79, -1, 81, -1, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, + 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, + -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, + -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, + -1, -1, -1, -1, -1, -1, 509, 510, 511, -1, + -1, -1, -1, 516, -1, 518, -1, -1, -1, -1, + 523, 524, 525, 526, -1, 528, 3, 4, 5, 6, + 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, + -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, + 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, + 237, -1, 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, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, + 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, + 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, -1, -1, -1, -1, + -1, -1, 509, 510, 511, -1, -1, -1, -1, 516, + -1, 518, -1, -1, -1, -1, 523, 524, 525, 526, + -1, 528, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, @@ -14225,12 +12730,12 @@ static const yytype_int16 yycheck[] = 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, + 171, 172, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, @@ -14244,32 +12749,292 @@ static const yytype_int16 yycheck[] = 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 311, 312, 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, + 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + 411, 412, 413, 414, 415, -1, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 471, 472, 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, + 501, 502, -1, 504, -1, -1, -1, -1, 509, 510, + 511, -1, -1, -1, -1, 516, -1, 518, 519, -1, + -1, -1, 523, 524, 525, 526, 3, 4, 5, 6, + 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, -1, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, 171, 172, 173, 174, 175, 176, + 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, -1, -1, 234, 235, 236, + 237, -1, 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, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, -1, 319, 320, 321, 322, 323, 324, 325, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, -1, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, + -1, -1, 449, 450, 451, 452, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, + 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, -1, 504, -1, -1, + -1, -1, 509, 510, 511, -1, -1, -1, -1, 516, + -1, 518, -1, -1, -1, -1, 523, 524, 525, 526, + 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, + 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, + -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, + -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, -1, -1, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, + -1, 504, -1, -1, -1, -1, 509, 510, 511, -1, + -1, -1, -1, 516, -1, 518, -1, -1, -1, -1, + 523, 524, 525, 526, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, -1, -1, -1, 37, -1, + 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, 132, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, + 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, + 509, 510, 511, -1, -1, -1, -1, 516, -1, 518, + 519, -1, -1, -1, 523, 524, 525, 526, 3, 4, + 5, 6, 7, -1, 9, 10, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, + -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, 171, 172, 173, 174, + 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, + 235, 236, 237, -1, 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, + -1, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, -1, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, -1, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, -1, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, 452, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, + 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, + 475, -1, -1, 478, -1, 480, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, -1, -1, 504, + -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, + 10, 516, -1, 518, -1, -1, -1, -1, 523, 524, + 525, 526, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, + -1, -1, 42, 43, 44, -1, 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, -1, 75, 76, 77, 78, 79, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, 172, 173, 174, 175, 176, 177, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, 233, 234, 235, 236, 237, -1, 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, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, + -1, 37, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, @@ -14303,7 +13068,7 @@ static const yytype_int16 yycheck[] = 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, @@ -14312,68 +13077,225 @@ static const yytype_int16 yycheck[] = 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, 37, -1, 39, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, + -1, -1, -1, -1, 516, -1, 518, 519, -1, -1, + -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, + 38, 39, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, + -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, + 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, 37, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, 519, -1, -1, -1, 523, + 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, + 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, 37, -1, 39, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, @@ -14382,7 +13304,7 @@ static const yytype_int16 yycheck[] = 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, @@ -14397,7 +13319,7 @@ static const yytype_int16 yycheck[] = 236, 237, -1, 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, -1, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, @@ -14420,63 +13342,220 @@ static const yytype_int16 yycheck[] = -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, -1, 509, 510, -1, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, + 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, + -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, -1, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, + -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, + -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, 172, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, + -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, + 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, 519, -1, -1, -1, 523, + 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, + 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, + 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, @@ -14487,7 +13566,7 @@ static const yytype_int16 yycheck[] = 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, @@ -14502,112 +13581,7 @@ static const yytype_int16 yycheck[] = 236, 237, -1, 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, -1, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, - 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, - 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, -1, 509, 510, -1, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, -1, 509, 510, - -1, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, 181, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 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, -1, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, @@ -14628,65 +13602,222 @@ static const yytype_int16 yycheck[] = 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + -1, 477, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, -1, 9, 10, + 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, + -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 516, -1, 518, -1, -1, - -1, -1, -1, 524, 525, 526, 527, 3, 4, 5, - 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, + -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, + -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, + -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, + 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, + 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, + 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, + 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, @@ -14697,7 +13828,7 @@ static const yytype_int16 yycheck[] = 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, @@ -14712,7 +13843,7 @@ static const yytype_int16 yycheck[] = 236, 237, -1, 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, -1, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, @@ -14735,330 +13866,184 @@ static const yytype_int16 yycheck[] = -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 516, -1, 518, -1, -1, -1, -1, -1, 524, 525, - 526, 527, 3, 4, 5, 6, 7, 8, 9, 10, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, -1, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, -1, -1, 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, -1, 276, 277, -1, 279, 280, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, -1, 509, 510, - 511, -1, 3, 4, 5, 516, -1, 518, 9, -1, - -1, -1, -1, 524, 525, 526, 527, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, - -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, -1, -1, -1, -1, -1, -1, -1, 509, 510, - 511, 3, -1, -1, -1, 516, -1, 518, 10, -1, - -1, -1, -1, -1, -1, -1, 527, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, + -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, -1, 516, -1, 518, 9, 10, -1, - -1, -1, 524, 525, 526, 527, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, - 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, - -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, - -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 239, 240, 241, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 270, 271, - 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 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, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, - -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 524, 525, 22, 23, 24, 25, 26, 27, + 502, -1, -1, -1, -1, -1, -1, 509, 510, 511, + -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, + -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, - 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, - -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, + -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, - 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, 147, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, -1, 161, 162, 163, 164, 165, 166, 167, - 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, -1, 221, -1, -1, 224, -1, 226, 227, - 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, - -1, 279, -1, 281, 282, 283, 284, 285, 286, 287, - 288, 289, -1, -1, 292, 293, 294, -1, 296, 297, - 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, + 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, + 278, 279, 280, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - -1, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 519, -1, 22, 23, 24, 25, 26, 27, 28, - 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, - -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, - 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, - 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, - 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, - -1, 90, 91, 92, -1, 94, 95, 96, 97, 98, - 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, - -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, - 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, - -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, - -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, - -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, - 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, - -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, - -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, - 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, - 229, 230, 231, -1, -1, 234, -1, 236, -1, -1, - 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, - -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, - 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, - 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, - 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, - 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, - -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, - 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, - 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, - 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, - -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, - -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, - 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, - 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, - 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, - 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, - -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, - 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, - 519, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, 34, 35, -1, 37, -1, -1, + 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, + -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, + 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 502, -1, + -1, -1, -1, -1, -1, 509, 510, 511, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, + 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, + 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 110, 111, 112, 113, 114, 115, 116, 117, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, 172, 173, 174, 175, 176, 177, 178, -1, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, @@ -15068,86 +14053,248 @@ static const yytype_int16 yycheck[] = 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, -1, 276, 277, 278, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, -1, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 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, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, -1, 417, 418, 419, - 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, 452, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, -1, 3, 504, 5, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, - -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, -1, 66, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, 171, 172, 173, 174, 175, 176, 177, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, -1, 319, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, 382, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 397, 398, -1, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, 415, -1, 417, 418, 419, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, 452, 453, 454, 455, 456, -1, 458, 459, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, -1, 3, 504, 5, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, + 500, 501, 502, -1, -1, -1, -1, -1, -1, 509, + 510, 511, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, + 6, 7, 8, 9, 10, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, -1, -1, -1, + -1, -1, -1, 509, 510, 511, -1, -1, -1, -1, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 3, 4, 5, 6, 7, 8, 9, 10, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + -1, -1, -1, -1, -1, -1, -1, 509, 510, -1, + -1, -1, -1, -1, 516, -1, 518, -1, -1, -1, + -1, 523, 524, 525, 526, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + -1, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, -1, -1, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, + -1, 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, -1, 276, 277, + -1, 279, 280, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 502, -1, -1, -1, -1, -1, + -1, 509, 510, 511, -1, -1, -1, -1, 516, -1, + 518, -1, -1, -1, -1, 523, 524, 525, 526, 3, + 4, 5, 6, 7, -1, 9, 10, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, -1, -1, + -1, -1, -1, -1, -1, 509, 510, -1, -1, -1, + -1, -1, 516, -1, 518, -1, -1, -1, -1, 523, + 524, 525, 526, 3, 4, 5, 6, 7, 8, 9, + 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, - 60, 61, 62, 63, 64, -1, 66, 67, 68, 69, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, @@ -15157,20 +14304,20 @@ static const yytype_int16 yycheck[] = 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, -1, 234, 235, 236, 237, -1, 239, + -1, 221, -1, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, + 280, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, @@ -15184,20 +14331,225 @@ static const yytype_int16 yycheck[] = 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 430, -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, + 500, 501, -1, -1, -1, -1, -1, -1, -1, 509, + 510, -1, -1, -1, -1, -1, 516, -1, 518, -1, + -1, -1, -1, 523, 524, 525, 526, 3, 4, 5, + 6, 7, -1, 9, 10, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + 176, 177, 178, -1, 180, 181, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, -1, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, + -1, -1, 3, 4, 5, 6, 7, -1, 9, 10, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, + -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, 280, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, -1, -1, -1, -1, -1, -1, 3, 4, 5, + 6, 7, -1, 9, 10, 516, -1, 518, -1, -1, + -1, -1, 523, 524, 525, 526, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, -1, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, + -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, 39, -1, + -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, + 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, -1, 146, -1, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + 171, -1, 173, 174, 175, 176, -1, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, -1, -1, 224, 225, 226, 227, 228, 229, 230, + 231, -1, -1, 234, 235, 236, -1, -1, 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, -1, 276, 277, -1, 279, 280, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, + 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, -1, -1, -1, -1, -1, -1, -1, 509, 510, + 511, -1, 3, 4, 5, 516, -1, 518, 9, -1, + -1, -1, 523, 524, 525, 526, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, + 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, 66, 67, 68, 69, 70, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, @@ -15206,7 +14558,7 @@ static const yytype_int16 yycheck[] = 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, @@ -15219,8 +14571,8 @@ static const yytype_int16 yycheck[] = 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, -1, 276, 277, 278, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - 291, 292, 293, 294, -1, -1, 297, 298, 299, 300, + 281, 282, 283, 284, 285, 286, -1, 288, 289, 290, + -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, @@ -15229,70 +14581,271 @@ static const yytype_int16 yycheck[] = 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + -1, -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, + 501, -1, -1, -1, -1, -1, -1, 3, 509, 510, + 511, -1, -1, -1, 10, 516, -1, 518, -1, -1, + -1, -1, -1, -1, -1, 526, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, 39, -1, -1, 42, 43, 44, -1, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, -1, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, -1, + 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, -1, -1, -1, -1, + -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, + 516, -1, 518, -1, -1, -1, -1, 523, 524, 525, + 526, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, 40, + -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, + 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, + 161, 162, 163, 164, 165, 166, 167, 168, -1, 170, + -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, + 211, 212, 213, 214, 215, 216, 217, 218, 219, -1, + 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, + 231, -1, -1, 234, -1, 236, -1, 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, -1, 270, + 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, + 281, 282, 283, 284, 285, 286, 287, 288, 289, -1, + -1, 292, 293, 294, -1, 296, 297, 298, 299, -1, + 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, 447, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 519, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, - 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, 66, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, - -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, - -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - -1, -1, 234, 235, 236, 237, -1, 239, 240, 241, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 276, 277, 278, 279, -1, 281, + 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 518, 519, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, 34, 35, -1, 37, -1, -1, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, + 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 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, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, -1, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, + 3, 504, 5, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 518, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, + 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, 66, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, 81, -1, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, 171, 172, + 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, + 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, -1, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, + -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, 415, -1, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, 452, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, 480, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, + 3, 504, 5, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, @@ -15313,13 +14866,13 @@ static const yytype_int16 yycheck[] = 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, -1, + 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, @@ -15344,253 +14897,103 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, 172, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, 415, -1, 417, 418, 419, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, 452, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, 480, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, -1, 3, - 504, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 518, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, 172, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, 419, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, 452, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, 480, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, -1, 3, - 504, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 518, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, 172, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, 317, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, 382, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, 419, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, 452, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, 480, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, -1, 3, - 504, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 518, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, + -1, -1, -1, -1, -1, -1, -1, -1, 42, 43, + 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, 66, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, + 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, + 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 239, 240, 241, 242, 243, + 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, + 234, 235, 236, 237, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, + 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, + 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, + 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, + 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, - 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, - -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, - -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, - 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, -1, -1, -1, -1, -1, 42, 43, 44, + -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, 66, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, - 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, + 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, + 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, - -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, - -1, 236, -1, -1, 239, 240, 241, 242, 243, 244, + 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, + 235, 236, 237, -1, 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, -1, 270, 271, 272, 273, 274, - -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, + -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, + -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, + 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, + 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, + -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, + 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, + 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, @@ -15603,11 +15006,11 @@ static const yytype_int16 yycheck[] = 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 126, 127, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, + 166, -1, 168, -1, 170, -1, 172, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, @@ -15621,29 +15024,29 @@ static const yytype_int16 yycheck[] = 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, + 376, 377, 378, 379, 380, 381, 382, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, 393, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, + 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, + -1, 417, 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 446, -1, -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + -1, -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, + 496, 497, 498, 499, 500, 501, 3, -1, 504, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, @@ -15657,7 +15060,7 @@ static const yytype_int16 yycheck[] = 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, + -1, 168, -1, 170, -1, 172, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, @@ -15671,26 +15074,26 @@ static const yytype_int16 yycheck[] = 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, - -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 377, 378, 379, 380, 381, 382, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, + 417, 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + -1, 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, + 497, 498, 499, 500, 501, 3, -1, 504, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, @@ -15707,6 +15110,56 @@ static const yytype_int16 yycheck[] = 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, -1, 172, -1, 174, 175, 176, -1, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, + 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, + -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, + -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, 452, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, 480, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, -1, 3, 504, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 518, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, + 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, + 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, @@ -15875,173 +15328,73 @@ static const yytype_int16 yycheck[] = 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, - 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, - -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, - -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, - 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, - -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, - 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, - 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, - -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, - -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, - -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, - 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, - 3, 4, 5, -1, -1, 8, 9, -1, -1, -1, - -1, -1, 15, 16, -1, 518, 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, - -1, 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, -1, 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, -1, - 153, 154, 155, 156, 157, 158, -1, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, -1, - -1, 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, -1, 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, -1, 282, - 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, - 293, 294, 295, 296, 297, 298, -1, 300, 301, 302, - -1, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, 317, 318, 319, 320, -1, 322, - 323, 324, -1, 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, -1, 415, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, - 433, 434, -1, 436, -1, 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, - -1, 464, 465, 466, 467, 468, 469, 470, 471, 472, - 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, - 483, 484, 485, 486, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 498, 499, 500, 501, -1, - 3, -1, 505, 506, 507, 8, 509, 510, 511, 512, - 513, 514, 15, 16, -1, -1, 19, 20, 21, 22, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 518, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, @@ -16089,202 +15442,189 @@ static const yytype_int16 yycheck[] = 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, -1, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, 8, -1, -1, 11, -1, -1, -1, 15, - 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 46, 8, -1, -1, 11, -1, -1, 53, 15, 16, - 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, - -1, -1, -1, -1, 80, -1, -1, -1, -1, 46, - 8, -1, -1, 11, -1, -1, 53, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, - -1, -1, -1, 80, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, 53, -1, -1, 8, -1, - -1, 11, -1, -1, -1, 15, 16, 17, 18, 19, - 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 80, -1, -1, -1, 36, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 46, 8, -1, -1, - 11, 177, -1, 53, 15, 16, 17, 18, 19, 20, - 21, -1, -1, -1, -1, -1, -1, -1, 194, -1, - -1, -1, -1, 199, -1, 36, -1, -1, -1, -1, - 80, -1, -1, -1, -1, 46, -1, -1, -1, -1, - 177, -1, 53, -1, -1, -1, 222, 223, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 194, -1, -1, - -1, 237, 199, -1, -1, -1, -1, -1, -1, 80, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 177, - -1, -1, -1, -1, -1, 222, 223, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 194, -1, -1, 275, - 237, 199, 278, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 292, -1, -1, 295, - -1, -1, -1, -1, 222, 223, -1, 177, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 275, 237, - -1, 278, -1, -1, 194, -1, -1, -1, -1, 199, - -1, -1, -1, -1, -1, 292, -1, -1, 295, -1, - -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, - -1, -1, 222, 223, -1, -1, -1, 275, -1, -1, - 278, -1, -1, 194, -1, -1, -1, 237, 199, -1, - -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 222, 223, -1, -1, -1, -1, -1, 394, -1, - -1, -1, -1, -1, -1, 275, 237, -1, 278, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 394, -1, -1, - -1, -1, -1, -1, 275, -1, -1, 278, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, - -1, -1, -1, 519, 394, -1, -1, -1, -1, -1, - 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, - 18, 19, 20, 21, -1, 502, -1, -1, 505, 506, - 507, -1, 509, 510, 511, 512, 513, 514, 36, -1, - -1, -1, 519, 394, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, 519, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, - 21, -1, 502, -1, -1, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, 36, -1, -1, -1, 519, - -1, -1, -1, -1, -1, 46, 8, -1, -1, 11, - -1, -1, 53, 15, 16, 17, 18, 19, 20, 21, - -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, 36, -1, -1, -1, 519, 80, - -1, -1, -1, -1, 46, 8, -1, -1, 11, 177, - -1, 53, 15, 16, 17, 18, 19, 20, 21, -1, - -1, -1, -1, -1, -1, -1, 194, -1, -1, -1, - -1, 199, -1, 36, -1, -1, -1, -1, 80, -1, - -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, - 53, -1, -1, -1, 222, 223, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, - -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, 177, -1, -1, 15, - 16, 17, 18, 19, 20, 21, -1, 275, -1, -1, - 278, -1, -1, 194, -1, -1, -1, -1, 199, -1, - 36, -1, -1, -1, 292, -1, -1, 295, -1, -1, - 46, -1, -1, -1, -1, 177, -1, 53, -1, -1, - -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 194, -1, -1, -1, 237, 199, -1, -1, - -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, - 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 194, -1, -1, 275, 237, 199, 278, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 292, -1, -1, 295, -1, -1, -1, -1, 222, - 223, -1, -1, -1, -1, -1, 394, -1, -1, -1, - -1, -1, -1, 275, 237, -1, 278, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, - -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 275, -1, -1, 278, -1, -1, 194, -1, - -1, -1, -1, 199, -1, -1, -1, -1, -1, 292, - -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 222, 223, -1, -1, - -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, - -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, 519, 394, -1, -1, -1, -1, -1, -1, 275, - -1, -1, 278, -1, -1, -1, -1, -1, -1, -1, - 8, -1, -1, 11, -1, -1, 292, 15, 16, 295, - -1, 19, 20, 21, -1, -1, -1, -1, -1, 8, - -1, 394, 11, -1, -1, -1, 15, 16, 17, 18, - 19, 20, 21, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, 53, -1, 36, -1, -1, - -1, 502, -1, -1, 505, 506, 507, 46, 509, 510, - 511, 512, 513, 514, 53, -1, -1, -1, 519, -1, - -1, -1, 80, -1, -1, -1, 8, -1, -1, 11, - -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, - 502, 80, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, 36, -1, -1, 519, 394, -1, - -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, - -1, 53, -1, -1, -1, -1, -1, -1, -1, 502, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, 517, -1, -1, -1, 80, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 177, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 194, -1, 177, -1, - -1, 199, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 194, -1, -1, -1, -1, - 199, -1, -1, -1, 222, 223, 502, -1, -1, 505, - 506, 507, -1, 509, 510, 511, 512, 513, 514, 237, - -1, 517, -1, 222, 223, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 177, -1, -1, 237, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, - 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 292, -1, 275, -1, -1, 278, - 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 292, -1, 237, 295, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 275, -1, -1, 278, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, - -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, - 509, 510, 511, 512, 513, 514, -1, -1, 517, -1, + 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 518, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, + 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, + 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, + 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, + 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, + 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, + 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 518, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, + -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, + -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, + 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, + 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, + -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, + -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, + -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, + 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, + 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, + 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, + 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, - 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, -1, 517, 22, 23, 24, 25, + -1, -1, -1, 518, -1, -1, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, + 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, + 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, + 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, + 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, + 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, + 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, -1, 3, 4, 5, + -1, -1, 8, 9, -1, -1, -1, -1, -1, 15, + 16, -1, 518, 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, + 46, 47, 48, 49, 50, 51, 52, -1, 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, + 76, 77, 78, -1, 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, + 146, 147, 148, 149, 150, 151, -1, 153, 154, 155, + 156, 157, 158, -1, 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, + 176, 177, 178, 179, 180, 181, -1, -1, 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, + 206, 207, 208, 209, -1, 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, + 276, 277, 278, 279, 280, -1, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 296, 297, 298, -1, 300, 301, 302, -1, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 316, 317, 318, 319, 320, -1, 322, 323, 324, -1, 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, @@ -16293,507 +15633,620 @@ static const yytype_int16 yycheck[] = 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, + 406, 407, 408, 409, 410, 411, 412, 413, -1, 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, + 426, 427, 428, 429, 430, 431, 432, 433, 434, -1, + 436, -1, 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, + 456, 457, 458, 459, 460, 461, 462, -1, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, + 486, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 498, 499, 500, 501, -1, 3, -1, 505, + 506, 507, 8, 509, 510, 511, 512, 513, 514, 15, + 16, -1, -1, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, + 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, + 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, + 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, + 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, + 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, + 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, - -1, -1, -1, -1, -1, 511, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, - 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, - 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, - 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, - 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, - 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, - 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, - -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, - 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, - -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, - -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, - -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, - 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, - 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, - -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, - 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, - 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, - -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, - 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, - -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, - 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, - -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, - 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, - 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, - -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, - 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, - 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, - 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, - 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, - -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, - -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, - -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, - 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, - -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, - 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, - -1, -1, -1, -1, 511, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, - 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, - -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, - 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, - 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, - 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, - 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, - 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, - 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, - 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, - 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, - 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, - -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, - -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, - 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, - 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, - 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, - 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, - -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, - 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, - 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, - 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, 4, 5, -1, -1, -1, - 9, -1, -1, 511, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, - -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, - 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, - 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, - 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, - 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, - -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, - 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, - -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 496, 497, 498, 499, 500, 501, -1, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, 8, + -1, -1, 11, -1, -1, -1, 15, 16, 17, 18, + 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 46, 8, -1, + -1, 11, -1, -1, 53, 15, 16, 17, 18, 19, + 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, + -1, 80, -1, -1, -1, -1, 46, 8, -1, -1, + 11, -1, -1, 53, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, + 80, -1, -1, -1, -1, 46, -1, -1, -1, -1, + -1, -1, 53, -1, -1, 8, -1, -1, 11, -1, + -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 46, 8, -1, -1, 11, 177, -1, + 53, 15, 16, 17, 18, 19, 20, 21, -1, -1, + -1, -1, -1, -1, -1, 194, -1, -1, -1, -1, + 199, -1, 36, -1, -1, -1, -1, 80, -1, -1, + -1, -1, 46, -1, -1, -1, -1, 177, -1, 53, + -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 194, -1, -1, -1, 237, 199, + -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, + -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 194, -1, -1, 275, 237, 199, 278, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, + -1, 222, 223, -1, 177, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 275, 237, -1, 278, -1, + -1, 194, -1, -1, -1, -1, 199, -1, -1, -1, + -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, + -1, -1, -1, 177, -1, -1, -1, -1, -1, 222, + 223, -1, -1, -1, 275, -1, -1, 278, -1, -1, + 194, -1, -1, -1, 237, 199, -1, -1, -1, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, + -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, + -1, -1, 275, 237, -1, 278, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 292, + -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, + -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, -1, -1, -1, -1, + 519, 394, -1, -1, -1, -1, -1, 8, -1, -1, + 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, + 21, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, 36, -1, -1, -1, 519, + 394, -1, -1, -1, -1, 46, -1, -1, -1, -1, + -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, 519, 80, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 17, 18, 19, 20, 21, -1, 502, + -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, 36, -1, -1, -1, 519, -1, -1, -1, + -1, -1, 46, 8, -1, -1, 11, -1, -1, 53, + 15, 16, 17, 18, 19, 20, 21, -1, 502, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, 36, -1, -1, -1, 519, 80, -1, -1, -1, + -1, 46, 8, -1, -1, 11, 177, -1, 53, 15, + 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, 194, -1, -1, -1, -1, 199, -1, + 36, -1, -1, -1, -1, 80, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, + -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, + -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, -1, 11, 177, -1, -1, 15, 16, 17, 18, + 19, 20, 21, -1, 275, -1, -1, 278, -1, -1, + 194, -1, -1, -1, -1, 199, -1, 36, -1, -1, + -1, 292, -1, -1, 295, -1, -1, 46, -1, -1, + -1, -1, 177, -1, 53, -1, -1, -1, 222, 223, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, 237, 199, -1, -1, -1, -1, -1, + -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 177, -1, -1, -1, -1, -1, 222, 223, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, 275, 237, 199, 278, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, + -1, 295, -1, -1, -1, -1, 222, 223, -1, -1, + -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, + 275, 237, -1, 278, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, + 295, -1, -1, -1, -1, -1, -1, -1, 177, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 275, + -1, -1, 278, -1, -1, 194, -1, -1, -1, -1, + 199, -1, -1, -1, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, + 394, -1, -1, -1, -1, -1, -1, -1, 237, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, -1, -1, -1, 519, 394, + -1, -1, -1, -1, -1, -1, 275, -1, -1, 278, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 68, 69, 292, -1, -1, 295, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8, -1, 394, 11, + -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 109, 110, 36, -1, 113, 114, 502, -1, + -1, 505, 506, 507, 46, 509, 510, 511, 512, 513, + 514, 53, -1, -1, -1, 519, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, -1, -1, -1, + 15, 16, 17, 18, 19, 20, 21, 502, 80, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, 36, -1, -1, 519, 394, -1, -1, -1, -1, + -1, 46, -1, -1, -1, -1, -1, -1, 53, -1, + -1, -1, 189, 190, -1, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, 517, -1, -1, -1, 80, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 177, 253, 254, 255, 256, + 257, 258, 259, 260, -1, -1, 263, 264, -1, -1, + -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, + -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, + 509, 510, 511, 512, 513, 514, -1, -1, 517, -1, + 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 177, -1, -1, 237, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, + 337, 338, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 275, -1, -1, 278, 222, 223, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 292, -1, 237, 295, -1, -1, -1, -1, -1, -1, + -1, 378, 379, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, + 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 394, -1, -1, -1, -1, 474, 475, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 498, 499, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 518, -1, -1, -1, -1, -1, -1, -1, 394, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, + 512, 513, 514, -1, -1, 517, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, -1, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, -1, 517, 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, -1, 163, 164, 165, 166, -1, 168, - -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, - -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, + 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, - -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, - 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, 276, 277, 278, - 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, - 289, 290, -1, 292, 293, 294, -1, -1, 297, 298, + 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, -1, -1, -1, -1, + 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 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, -1, 362, 363, 364, 365, 366, 367, 368, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, - 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, - -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, - 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, - -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, - 429, 430, -1, -1, 433, 434, 435, 436, 437, 438, - 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, - 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, - 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, - -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, + 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, -1, -1, 8, -1, -1, 11, -1, - 509, 510, 15, 16, 17, 18, 19, 20, 21, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 36, -1, -1, -1, -1, 41, -1, - -1, -1, -1, 46, 8, -1, -1, 11, -1, -1, - 53, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 36, -1, -1, -1, -1, 80, -1, -1, - -1, -1, 46, 8, -1, -1, 11, -1, -1, 53, - 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 36, -1, -1, -1, -1, 80, -1, -1, -1, - -1, 46, -1, 126, -1, -1, -1, -1, 53, -1, - 8, -1, -1, 11, -1, -1, -1, 15, 16, 17, - 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 80, -1, -1, 36, -1, - -1, -1, 40, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, 177, 53, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 194, -1, -1, -1, -1, 199, -1, -1, -1, - -1, -1, 80, 167, -1, -1, -1, -1, 172, -1, - -1, -1, -1, 177, -1, -1, -1, -1, -1, 222, - 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 194, -1, -1, -1, 237, 199, -1, -1, -1, -1, - -1, 166, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 177, -1, -1, -1, -1, -1, 222, 223, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, - -1, -1, 275, 237, 199, 278, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 292, - -1, -1, 295, -1, -1, -1, -1, 222, 223, 177, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 275, 237, -1, 278, -1, 194, -1, -1, -1, - -1, 199, -1, -1, -1, -1, -1, -1, 292, -1, - -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, - 275, -1, -1, 278, -1, -1, -1, -1, -1, 237, - -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, - 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, + -1, -1, 511, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, + 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, + 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, + -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, + -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, + -1, 511, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, + 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, + 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, + 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, + -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, + 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, + 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, + 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, + 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, + -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, + 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, + 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, + 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, + 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, + 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, + 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, + 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, + -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, + 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, + 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, + 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, + 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, + -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, + 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, + 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, + 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, + -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, + -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, + 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, + 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, + 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, + 501, 3, 4, 5, -1, -1, -1, 9, -1, -1, + 511, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, 37, -1, -1, -1, -1, + 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, 81, + -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, + -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + -1, -1, 234, 235, 236, 237, -1, 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, -1, 276, 277, 278, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, 290, -1, + 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, + 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, 438, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + -1, -1, 8, -1, -1, 11, -1, 509, 510, 15, + 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 394, -1, -1, -1, -1, -1, 275, -1, 324, - 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, - -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, - 394, -1, 15, 16, 17, 18, 19, 20, 21, -1, + 36, -1, -1, -1, -1, 41, -1, -1, -1, -1, + 46, 8, -1, -1, 11, -1, -1, 53, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, -1, 8, + -1, -1, 11, -1, -1, -1, 15, 16, -1, 36, + 19, 20, 21, -1, 80, -1, -1, -1, -1, 46, + 8, -1, -1, 11, -1, -1, 53, 15, 16, 17, + 18, 19, 20, 21, -1, -1, -1, 46, -1, -1, + -1, -1, -1, -1, 53, -1, -1, -1, 36, -1, + -1, -1, -1, 80, -1, -1, -1, -1, 46, -1, + 126, -1, -1, -1, -1, 53, -1, 8, -1, -1, + 11, 80, -1, -1, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 80, -1, -1, 36, -1, -1, -1, 40, + -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, + -1, 177, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, + -1, -1, -1, 199, -1, -1, -1, -1, -1, 80, + 167, -1, -1, -1, -1, 172, -1, -1, -1, -1, + 177, -1, -1, -1, -1, -1, 222, 223, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 194, 177, -1, + -1, 237, 199, -1, -1, -1, -1, -1, 166, -1, + -1, -1, -1, -1, -1, 194, -1, -1, -1, 177, + 199, -1, -1, -1, -1, 222, 223, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 194, -1, -1, 275, + 237, 199, 278, 222, 223, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 292, -1, 237, 295, + -1, -1, -1, -1, 222, 223, 177, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 275, 237, + -1, 278, -1, 194, -1, -1, -1, -1, 199, -1, + -1, -1, -1, -1, -1, 292, 275, -1, 295, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 36, 457, -1, -1, -1, -1, -1, - -1, -1, -1, 46, -1, -1, -1, -1, -1, 394, - 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 222, 223, 292, -1, -1, -1, 275, -1, -1, + 278, -1, -1, -1, -1, -1, 237, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 80, -1, 502, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, -1, -1, 394, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, + -1, -1, -1, -1, 275, -1, 324, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, -1, 394, -1, 15, + 16, 17, 18, 19, 20, 21, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, + 36, 457, -1, -1, -1, -1, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, 394, 53, -1, -1, + -1, -1, -1, 68, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 502, -1, -1, - 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, - -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 80, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, -1, -1, 394, 109, 110, -1, -1, 113, 114, + -1, 8, -1, -1, 11, -1, -1, -1, 15, 16, + -1, -1, 19, 20, 21, 502, -1, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, -1, 36, + -1, -1, -1, 502, -1, -1, 505, 506, 507, 46, + 509, 510, 511, 512, 513, 514, 53, -1, -1, -1, + -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, + -1, 509, 510, 511, 512, 513, 514, -1, -1, -1, + -1, 177, -1, 80, 189, 190, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8, 194, -1, + 11, -1, -1, 199, 15, 16, 17, 18, 19, 20, + 21, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, 36, 222, 223, -1, 40, + -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, + -1, 237, 53, -1, -1, -1, -1, -1, 253, 254, + 255, 256, 257, 258, 259, 260, -1, -1, 263, 264, + -1, -1, -1, 8, -1, -1, 11, -1, -1, 80, + 15, 16, 17, 18, 19, 20, 21, -1, -1, 275, + 177, -1, 278, -1, -1, -1, -1, -1, -1, -1, + -1, 36, -1, -1, -1, -1, 292, 194, -1, 295, + -1, 46, 199, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 8, 194, -1, 11, -1, -1, 199, 15, 16, 17, - 18, 19, 20, 21, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, 36, 222, - 223, -1, 40, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, 237, 53, -1, -1, -1, -1, + -1, -1, 318, -1, -1, 222, 223, -1, -1, -1, + -1, -1, 337, 338, -1, 80, -1, -1, -1, -1, + 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, -1, -1, -1, 15, + 16, 17, 18, 19, 20, 21, 177, -1, -1, -1, + -1, -1, -1, 378, 379, -1, -1, -1, 275, -1, + 36, 278, -1, 194, 40, -1, -1, -1, 199, -1, + 46, -1, -1, -1, -1, 292, -1, 53, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - -1, -1, 80, 15, 16, 17, 18, 19, 20, 21, - -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, - -1, -1, -1, -1, 36, -1, -1, -1, -1, 292, - -1, -1, 295, -1, 46, -1, -1, -1, -1, -1, - -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 318, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, + -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 80, -1, 237, 172, -1, -1, + -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, + -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 275, -1, -1, 278, -1, 474, + 475, -1, -1, -1, -1, -1, -1, 222, 223, -1, + -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, + -1, -1, 237, 498, 499, -1, -1, 394, -1, -1, + -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, + 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, + -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, + 275, -1, -1, 278, -1, -1, -1, -1, 194, -1, + -1, -1, -1, 199, -1, -1, -1, 292, -1, -1, + 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, -1, 222, 223, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, + -1, 237, -1, 394, -1, -1, -1, -1, -1, 36, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, + -1, -1, -1, -1, -1, 502, 53, -1, 505, 506, + 507, -1, 509, 510, 511, 512, 513, 514, 8, 275, + -1, 11, 278, -1, -1, 15, 16, 17, 18, 19, + 20, 21, -1, 80, -1, -1, 292, -1, -1, 295, + -1, -1, -1, -1, -1, -1, 36, -1, -1, 394, + -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, + -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, - -1, -1, 15, 16, 17, 18, 19, 20, 21, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 36, -1, -1, 194, 40, -1, -1, - -1, 199, -1, 46, -1, -1, -1, -1, -1, -1, - 53, 394, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 80, -1, 237, - 172, -1, -1, -1, -1, 177, -1, -1, -1, -1, + 80, 502, -1, -1, 505, 506, 507, -1, 509, 510, + 511, 512, 513, 514, -1, 8, -1, -1, 11, -1, + -1, -1, 15, 16, 17, 18, 19, 20, 21, -1, + 167, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 177, -1, -1, 36, -1, -1, -1, 40, 394, -1, + -1, -1, -1, 46, -1, -1, -1, 194, -1, -1, + 53, -1, 199, -1, -1, -1, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, + -1, -1, -1, -1, -1, 222, 223, 80, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, + 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 194, -1, -1, -1, -1, 199, + -1, -1, -1, -1, 8, -1, -1, 11, -1, -1, + -1, 15, 16, 17, 18, 19, 20, 21, 275, -1, + -1, 278, 222, 223, -1, -1, -1, -1, -1, -1, + -1, -1, 36, -1, -1, 292, 502, 237, 295, 505, + 506, 507, 46, 509, 510, 511, 512, 513, 514, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 275, -1, -1, - 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 222, 223, -1, -1, 292, -1, -1, 295, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 502, - -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, - 513, 514, -1, -1, 177, -1, -1, -1, -1, -1, - -1, -1, -1, 275, -1, -1, 278, -1, -1, -1, + -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 275, 80, -1, 278, -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, -1, - 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, + -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, -1, 222, 223, 15, 16, 17, 18, 19, 20, 21, -1, -1, - -1, -1, -1, -1, 237, -1, 394, -1, -1, -1, - -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 237, -1, -1, -1, -1, -1, + -1, -1, 36, -1, -1, -1, -1, 394, -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, 275, -1, 11, 278, -1, -1, 15, 16, - 17, 18, 19, 20, 21, -1, 80, -1, -1, 292, - -1, -1, 295, -1, -1, -1, -1, -1, -1, 36, - -1, -1, 394, -1, -1, -1, -1, -1, -1, 46, - -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 80, 502, -1, -1, 505, 506, 507, - -1, 509, 510, 511, 512, 513, 514, -1, 8, -1, - -1, 11, -1, -1, -1, 15, 16, 17, 18, 19, - 20, 21, -1, 167, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 177, -1, -1, 36, -1, -1, -1, - 40, 394, -1, -1, -1, -1, 46, -1, -1, -1, - 194, -1, -1, 53, -1, 199, -1, -1, -1, -1, - 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, -1, -1, -1, -1, -1, 222, 223, - 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 177, -1, -1, 237, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 194, -1, -1, - -1, -1, 199, -1, -1, -1, -1, 8, -1, -1, - 11, -1, -1, -1, 15, 16, 17, 18, 19, 20, - 21, 275, -1, -1, 278, 222, 223, -1, -1, -1, - -1, -1, -1, -1, -1, 36, -1, -1, 292, 502, - 237, 295, 505, 506, 507, 46, 509, 510, 511, 512, - 513, 514, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 275, 80, - -1, 278, -1, -1, 194, -1, -1, -1, -1, 199, - -1, -1, -1, -1, -1, 292, -1, -1, 295, -1, - -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, - 11, -1, 222, 223, 15, 16, 17, 18, 19, 20, - 21, -1, -1, -1, -1, -1, -1, 237, -1, -1, - -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, - 394, -1, -1, -1, -1, 46, -1, -1, -1, -1, - -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 275, -1, -1, 278, -1, - -1, -1, -1, -1, -1, -1, 177, -1, -1, 80, - -1, -1, 292, -1, -1, 295, -1, -1, -1, -1, - -1, -1, -1, 194, -1, -1, 8, 394, 199, 11, - -1, -1, -1, 15, 16, 17, 18, 19, 20, 21, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 222, 223, -1, 36, -1, -1, -1, -1, -1, - 427, -1, -1, -1, 46, -1, 237, -1, -1, -1, - -1, 53, -1, -1, -1, -1, -1, -1, 502, -1, - -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, - 514, -1, -1, -1, -1, -1, -1, -1, 80, -1, - -1, -1, -1, -1, 275, -1, 177, 278, -1, -1, - -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, - -1, 292, -1, 194, 295, -1, -1, -1, 199, -1, + -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, + -1, -1, -1, 177, -1, -1, 80, -1, -1, 292, + -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, + 194, -1, -1, 8, 394, 199, 11, -1, -1, -1, + 15, 16, 17, 18, 19, 20, 21, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 222, 223, + -1, 36, -1, -1, -1, -1, -1, 427, -1, -1, + -1, 46, -1, 237, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, -1, -1, - -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 177, -1, -1, -1, -1, - -1, -1, -1, -1, 275, -1, -1, 278, -1, -1, - -1, -1, 194, -1, -1, -1, -1, 199, -1, -1, - -1, 292, 502, 394, 295, 505, 506, 507, -1, 509, - 510, 511, 512, 513, 514, -1, -1, -1, -1, -1, - 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, + -1, 275, -1, 177, 278, -1, -1, -1, -1, -1, + -1, 394, -1, -1, -1, -1, -1, -1, 292, -1, + 194, 295, -1, -1, -1, 199, -1, -1, -1, -1, + -1, -1, 502, -1, -1, 505, 506, 507, -1, 509, + 510, 511, 512, 513, 514, -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 292, -1, -1, 295, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, - -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, + -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, + -1, 275, -1, -1, 278, -1, -1, -1, -1, 194, + -1, -1, -1, -1, 199, -1, -1, -1, 292, 502, + 394, 295, 505, 506, 507, -1, 509, 510, 511, 512, + 513, 514, -1, -1, -1, -1, -1, 222, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 237, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 275, -1, -1, 278, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 292, -1, -1, + 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 394, -1, -1, -1, -1, -1, -1, -1, 502, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 502, -1, -1, 505, 506, 507, -1, 509, 510, - 511, 512, 513, 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, + -1, 505, 506, 507, -1, 509, 510, 511, 512, 513, + 514, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3, -1, 5, -1, -1, -1, - 502, -1, -1, 505, 506, 507, -1, 509, 510, 511, - 512, 513, 514, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3, -1, 5, -1, -1, -1, 502, -1, -1, + 505, 506, 507, -1, 509, 510, 511, 512, 513, 514, 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, @@ -16892,160 +16345,160 @@ static const yytype_int16 yycheck[] = 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, 3, - -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, 37, -1, -1, -1, -1, 42, 43, - 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, 81, -1, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + 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, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, - 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, - 234, 235, 236, 237, -1, 239, 240, 241, 242, 243, + 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, -1, 276, 277, 278, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, 290, -1, 292, 293, - 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, + 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, -1, -1, -1, -1, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + 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, -1, 383, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 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, -1, -1, 417, 418, -1, 420, 421, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 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, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, 34, - 35, -1, 37, -1, -1, -1, -1, 42, 43, 44, - -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, 79, -1, 81, -1, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, + 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, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, - 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, - 235, 236, 237, -1, 239, 240, 241, 242, 243, 244, + 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, - -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, + 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, - -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, + 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, -1, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 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, - -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, - 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, - 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, + 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, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, - 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, - -1, -1, -1, -1, -1, -1, 42, 43, 44, -1, + 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, -1, 59, 60, 61, 62, 63, 64, -1, - 66, 67, 68, 69, 70, 71, 72, 73, -1, 75, - 76, 77, 78, 79, -1, 81, -1, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, - 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 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, -1, 118, -1, 120, 121, 122, 123, 124, 125, - -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, - 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, - 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, - 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, - 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, - -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, - 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, - 236, 237, -1, 239, 240, 241, 242, 243, 244, 245, + 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, -1, - 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, - -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, - -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, - 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, - -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, - 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 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, -1, -1, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, - 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, - 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, - 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, - 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, - 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, - -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, - -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 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, 3, -1, -1, -1, + 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, -1, -1, 42, 43, 44, -1, 46, + 37, -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, @@ -17057,7 +16510,7 @@ static const yytype_int16 yycheck[] = -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, + 157, 158, 159, 160, 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, @@ -17070,7 +16523,7 @@ static const yytype_int16 yycheck[] = 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, - -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + -1, 288, 289, 290, -1, 292, 293, 294, -1, -1, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, 322, 323, 324, 325, 326, @@ -17079,13 +16532,13 @@ static const yytype_int16 yycheck[] = -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, - 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, - 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, + 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, @@ -17094,170 +16547,170 @@ static const yytype_int16 yycheck[] = 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, - 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, - 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, + 28, 29, -1, 31, 32, 33, 34, 35, -1, 37, + -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, -1, -1, 82, 83, 84, 85, 86, 87, - 88, -1, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, 81, -1, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, - 168, 169, 170, -1, -1, -1, 174, 175, 176, -1, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, - 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, + 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, - 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, - -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, - 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, + 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, - -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 268, 269, 270, 271, 272, 273, 274, -1, 276, 277, + 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, - 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, + 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, - -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, - 328, 329, 330, 331, 332, 333, 334, 335, -1, 337, + -1, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, - 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, + 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, + 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, - 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, + 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, - 448, 449, 450, 451, -1, 453, 454, 455, 456, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, - -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, - -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, - 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, - -1, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, + -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, 66, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + 79, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, - 169, 170, -1, -1, -1, 174, 175, 176, -1, 178, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, - 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, - -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, - 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, - 229, 230, 231, -1, -1, 234, -1, 236, 237, -1, + 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, - -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, + 269, 270, 271, 272, 273, 274, -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, - 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, + 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, - 319, 320, 321, -1, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, - 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, - -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, - 439, 440, 441, 442, 443, 444, 445, 446, -1, 448, + 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, - 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, + 459, 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, + 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, 34, 35, -1, -1, -1, -1, - -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, - 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, + -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, + -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, + -1, 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, + -1, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, - 230, 231, -1, -1, 234, -1, 236, -1, -1, 239, + -1, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, -1, -1, 234, 235, 236, 237, -1, 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, -1, - 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, -1, 276, 277, 278, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 320, 321, 322, 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 360, -1, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 390, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 460, 461, 462, 463, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, + -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, + 71, 72, 73, 74, 75, 76, 77, 78, 79, -1, + -1, 82, 83, 84, 85, 86, 87, 88, -1, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, + 161, -1, 163, 164, 165, 166, -1, 168, 169, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, @@ -17273,7 +16726,7 @@ static const yytype_int16 yycheck[] = -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, + 321, -1, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, @@ -17285,45 +16738,45 @@ static const yytype_int16 yycheck[] = 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, + 441, 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, + 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + 72, 73, 74, 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 92, 93, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + -1, 163, 164, 165, 166, -1, 168, 169, 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 239, 240, 241, + -1, -1, 234, -1, 236, 237, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, 291, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + -1, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, @@ -17335,7 +16788,7 @@ static const yytype_int16 yycheck[] = 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + 442, 443, 444, 445, 446, -1, 448, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, @@ -17344,7 +16797,7 @@ static const yytype_int16 yycheck[] = 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, @@ -17369,7 +16822,7 @@ static const yytype_int16 yycheck[] = 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, 291, 292, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, @@ -17519,7 +16972,7 @@ static const yytype_int16 yycheck[] = 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, - 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + 286, -1, 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, @@ -17532,7 +16985,7 @@ static const yytype_int16 yycheck[] = 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, - -1, 417, 418, 419, 420, -1, 422, 423, 424, 425, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, @@ -17543,7 +16996,7 @@ static const yytype_int16 yycheck[] = 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, - 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, @@ -17619,7 +17072,7 @@ static const yytype_int16 yycheck[] = 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, - 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 288, 289, -1, 291, 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, @@ -17640,10 +17093,10 @@ static const yytype_int16 yycheck[] = -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 498, 499, 500, 501, 3, 4, -1, -1, -1, -1, + 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, @@ -17731,7 +17184,7 @@ static const yytype_int16 yycheck[] = 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 410, 411, 412, 413, 414, -1, -1, 417, 418, 419, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, @@ -17840,9 +17293,9 @@ static const yytype_int16 yycheck[] = 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, + 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, @@ -18039,11 +17492,11 @@ static const yytype_int16 yycheck[] = -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, + 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, - -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, + -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, @@ -18089,11 +17542,11 @@ static const yytype_int16 yycheck[] = 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, - 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, + 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, + -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, @@ -18139,10 +17592,10 @@ static const yytype_int16 yycheck[] = -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, + 498, 499, 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, + 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, @@ -18201,296 +17654,48 @@ static const yytype_int16 yycheck[] = 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, - 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, - 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, - 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, - 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, 5, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, - 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, 79, -1, - -1, -1, 83, 84, 85, 86, 87, 88, -1, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, -1, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - -1, -1, -1, 174, 175, 176, -1, 178, -1, 180, - -1, 182, 183, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, -1, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, -1, 210, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, -1, -1, 224, -1, 226, 227, 228, 229, 230, - 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, - 271, 272, 273, 274, -1, 276, 277, -1, 279, -1, - 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, 299, -1, - 301, -1, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - 321, -1, 323, 324, 325, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, -1, 384, 385, 386, 387, 388, 389, 390, - 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, - -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, 435, 436, 437, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, 463, 464, 465, -1, 467, -1, 469, 470, - 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 3, -1, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, - 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, - 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, - 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, - -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, - 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, - 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, - -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, - 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, - -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, - -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, - 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, - 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, - 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, - 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, - -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, - -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, - 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, - 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, - 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, - -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, - -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, - 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, - 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, - 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, - -1, -1, 384, 385, 386, 387, 388, 389, 390, 391, - 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, - 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, - 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, - -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, - 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, - -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, - 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, - 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, - 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 3, -1, 5, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, - 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, - 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, - 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, - 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, - -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, - 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, - -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, - -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, - 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, - -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, - 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, - 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, - 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, - 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, - -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, - -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, - 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, - 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, - 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, - 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, - 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, - 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, - -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, - -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, - 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, - 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, - 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, - 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, - 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, - 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, - 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, - 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, - 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, - -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, - 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, - 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, - 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, - 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, - 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, - 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, - 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, - 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, - 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, - 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, - 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, - 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, - 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, - -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, - 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, - 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, - 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, - 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, - 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, - 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, + 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, + 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, + 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, + 180, -1, 182, 183, 184, 185, -1, 187, 188, 189, + 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, + 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, + 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, + -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, + 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, + 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, + -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, + -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, + -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, -1, -1, -1, -1, 319, + 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, + 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, + 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, + 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, + 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, + 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, + 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, + 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, + 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, + -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, + 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, - 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, - -1, -1, 37, -1, -1, 40, -1, 42, 43, 44, - -1, 46, 47, 48, 49, 50, 51, 52, -1, 54, - 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, - -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, - 75, 76, 77, 78, -1, -1, 81, -1, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, - 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, - 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, - 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, - 145, 146, -1, 148, 149, 150, 151, -1, 153, 154, - 155, 156, 157, 158, -1, -1, 161, -1, 163, 164, - 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, - 175, 176, 177, 178, -1, 180, -1, -1, -1, 184, - 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, - 205, 206, -1, 208, 209, -1, 211, 212, 213, 214, - 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, - 235, 236, 237, -1, 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, -1, - -1, 276, 277, 278, 279, -1, -1, 282, 283, 284, - 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, - -1, -1, 297, 298, -1, 300, 301, 302, -1, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - -1, -1, -1, -1, 319, 320, -1, 322, 323, 324, - -1, 326, 327, 328, -1, 330, 331, 332, 333, 334, - 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, -1, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, -1, 394, - 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, -1, - -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, - 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, - -1, 436, -1, -1, 439, 440, 441, 442, 443, 444, - 445, 446, 447, -1, 449, 450, 451, -1, 453, 454, - 455, 456, -1, 458, 459, 460, 461, 462, -1, 464, - 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, - 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, - 485, 486, 3, -1, 5, -1, -1, -1, -1, -1, - -1, -1, -1, 498, 499, 500, 501, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, + 31, 32, 33, -1, -1, -1, -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, @@ -18540,7 +17745,7 @@ static const yytype_int16 yycheck[] = 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, - 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, + 32, 33, -1, -1, -1, -1, -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, @@ -18589,7 +17794,7 @@ static const yytype_int16 yycheck[] = 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, - 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, @@ -18637,7 +17842,7 @@ static const yytype_int16 yycheck[] = 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, @@ -18687,8 +17892,256 @@ static const yytype_int16 yycheck[] = 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, + -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, + -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, + 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, + 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, + -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, + -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, + -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, + 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, + 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, + 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, + 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 3, -1, 5, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, + 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, 79, -1, -1, -1, 83, 84, 85, + 86, 87, 88, -1, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, -1, -1, -1, 174, 175, + 176, -1, 178, -1, 180, -1, 182, 183, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, -1, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, -1, 210, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, -1, -1, 224, -1, + 226, 227, 228, 229, 230, 231, -1, -1, 234, -1, + 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, + 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, 299, -1, 301, -1, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, 321, -1, 323, 324, 325, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, -1, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, -1, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, + -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, 435, + 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, + 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, 463, 464, 465, + -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 3, -1, 5, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, + 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, + 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, + 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, + 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, + 77, 78, 79, -1, -1, -1, 83, 84, 85, 86, + 87, 88, -1, 90, 91, 92, -1, 94, 95, 96, + 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, + -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, + 137, 138, -1, 140, 141, 142, -1, 144, 145, 146, + -1, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, -1, 161, -1, 163, 164, 165, 166, + -1, 168, -1, 170, -1, -1, -1, 174, 175, 176, + -1, 178, -1, 180, -1, 182, 183, 184, 185, -1, + 187, 188, 189, 190, 191, 192, 193, -1, 195, 196, + 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, + -1, 208, -1, 210, 211, 212, 213, 214, 215, 216, + 217, -1, 219, -1, 221, -1, -1, 224, -1, 226, + 227, 228, 229, 230, 231, -1, -1, 234, -1, 236, + -1, -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, + 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, + -1, 288, 289, -1, -1, 292, 293, 294, -1, -1, + 297, 298, 299, -1, 301, -1, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, -1, -1, + -1, -1, 319, 320, 321, -1, 323, 324, 325, 326, + 327, 328, -1, 330, 331, 332, 333, 334, 335, -1, + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, + -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, -1, 362, 363, -1, 365, 366, + 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, + 387, 388, 389, 390, 391, 392, -1, -1, 395, 396, + 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, + 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, + -1, 428, 429, 430, -1, -1, 433, 434, 435, 436, + 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, + -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, + -1, 458, 459, 460, 461, 462, 463, 464, 465, -1, + 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, + -1, 478, -1, -1, 481, 482, 483, 484, 485, 486, + 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 3, -1, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, + 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, + 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, + -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, + 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, + 78, 79, -1, -1, -1, 83, 84, 85, 86, 87, + 88, -1, 90, 91, 92, -1, 94, 95, 96, 97, + 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, + 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, + 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, + 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, -1, 161, -1, 163, 164, 165, 166, -1, + 168, -1, 170, -1, -1, -1, 174, 175, 176, -1, + 178, -1, 180, -1, 182, 183, 184, 185, -1, 187, + 188, 189, 190, 191, 192, 193, -1, 195, 196, 197, + 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, + 208, -1, 210, 211, 212, 213, 214, 215, 216, 217, + -1, 219, -1, 221, -1, -1, 224, -1, 226, 227, + 228, 229, 230, 231, -1, -1, 234, -1, 236, -1, + -1, 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, -1, 270, 271, 272, 273, 274, -1, 276, 277, + -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, + 288, 289, -1, -1, 292, 293, 294, -1, -1, 297, + 298, 299, -1, 301, -1, 303, 304, 305, 306, 307, + 308, 309, 310, 311, 312, 313, 314, -1, -1, -1, + -1, 319, 320, 321, -1, 323, 324, 325, 326, 327, + 328, -1, 330, 331, 332, 333, 334, 335, -1, 337, + 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, + 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, + 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, + 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, + 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, + 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, + 428, 429, 430, -1, -1, 433, 434, 435, 436, 437, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, + -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, + 458, 459, 460, 461, 462, 463, 464, 465, -1, 467, + -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, + 478, -1, -1, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, + -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, + 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, + -1, 40, -1, 42, 43, 44, -1, 46, 47, 48, + 49, 50, 51, 52, -1, 54, 55, 56, 57, -1, + 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, + 69, 70, 71, 72, 73, -1, 75, 76, 77, 78, + -1, -1, 81, -1, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, -1, 94, 95, 96, 97, 98, + 99, -1, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, + -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, + 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, + -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, + 149, 150, 151, -1, 153, 154, 155, 156, 157, 158, + -1, -1, 161, -1, 163, 164, 165, 166, -1, 168, + -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, + -1, 180, -1, -1, -1, 184, 185, -1, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + -1, 200, 201, 202, 203, 204, 205, 206, -1, 208, + 209, -1, 211, 212, 213, 214, 215, 216, 217, -1, + 219, -1, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, -1, -1, 234, 235, 236, 237, -1, + 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, -1, -1, 276, 277, 278, + 279, -1, -1, 282, 283, 284, 285, 286, -1, 288, + 289, -1, -1, 292, 293, 294, -1, -1, 297, 298, + -1, 300, 301, 302, -1, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, -1, -1, -1, -1, + 319, 320, -1, 322, 323, 324, -1, 326, 327, 328, + -1, 330, 331, 332, 333, 334, 335, -1, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, + 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, + 359, 360, -1, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, + 379, 380, 381, -1, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, -1, 394, 395, 396, 397, 398, + -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 411, 412, 413, -1, -1, -1, 417, 418, + -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, + 429, 430, -1, -1, 433, 434, -1, 436, -1, -1, + 439, 440, 441, 442, 443, 444, 445, 446, 447, -1, + 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, + 459, 460, 461, 462, -1, 464, 465, -1, 467, 468, + 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, + -1, -1, 481, 482, 483, 484, 485, 486, 3, -1, + 5, -1, -1, -1, -1, -1, -1, -1, -1, 498, + 499, 500, 501, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, @@ -18840,7 +18293,7 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, -1, - -1, -1, 40, -1, -1, 43, 44, -1, 46, 47, + -1, -1, -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, 76, 77, @@ -18875,7 +18328,7 @@ static const yytype_int16 yycheck[] = 358, 359, 360, -1, 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, 385, 386, 387, - 388, -1, 390, 391, 392, -1, -1, 395, 396, 397, + 388, 389, 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, @@ -19039,6 +18492,254 @@ static const yytype_int16 yycheck[] = 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, + 32, 33, -1, -1, -1, -1, -1, -1, 40, -1, + -1, 43, 44, -1, 46, 47, 48, -1, 50, 51, + 52, 53, 54, -1, 56, 57, -1, 59, 60, 61, + 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, + 72, 73, -1, 75, 76, 77, 78, 79, -1, -1, + -1, 83, 84, 85, 86, 87, 88, -1, 90, 91, + 92, -1, 94, 95, 96, 97, 98, 99, -1, -1, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, + 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, + -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, + 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, -1, 161, + -1, 163, 164, 165, 166, -1, 168, -1, 170, -1, + -1, -1, 174, 175, 176, -1, 178, -1, 180, -1, + 182, 183, 184, 185, -1, 187, 188, 189, 190, 191, + 192, 193, -1, 195, 196, 197, 198, -1, 200, 201, + 202, 203, 204, 205, 206, -1, 208, -1, 210, 211, + 212, 213, 214, 215, 216, 217, -1, 219, -1, 221, + -1, -1, 224, -1, 226, 227, 228, 229, 230, 231, + -1, -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, + 272, 273, 274, -1, 276, 277, -1, 279, -1, 281, + 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, + 292, 293, 294, -1, -1, 297, 298, 299, -1, 301, + -1, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 312, 313, 314, -1, -1, -1, -1, 319, 320, 321, + -1, 323, 324, 325, 326, 327, 328, -1, 330, 331, + 332, 333, 334, 335, -1, 337, 338, 339, 340, 341, + 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, + 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, + 362, 363, -1, 365, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + -1, -1, 384, 385, 386, 387, 388, -1, 390, 391, + 392, -1, -1, 395, 396, 397, 398, -1, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, 414, -1, -1, 417, 418, -1, 420, -1, + 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, + -1, 433, 434, 435, 436, 437, -1, 439, 440, 441, + 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, + -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, + 462, 463, 464, 465, -1, 467, -1, 469, 470, 471, + 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, + 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 43, 44, -1, 46, 47, 48, -1, 50, 51, 52, + 53, 54, -1, 56, 57, -1, 59, 60, 61, 62, + 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, + 73, -1, 75, 76, 77, 78, 79, -1, -1, -1, + 83, 84, 85, 86, 87, 88, -1, 90, 91, 92, + -1, 94, 95, 96, 97, 98, 99, -1, -1, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, + 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, + -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, + -1, 144, 145, 146, -1, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, -1, 161, -1, + 163, 164, 165, 166, -1, 168, -1, 170, -1, -1, + -1, 174, 175, 176, -1, 178, -1, 180, -1, 182, + 183, 184, 185, -1, 187, 188, 189, 190, 191, 192, + 193, -1, 195, 196, 197, 198, -1, 200, 201, 202, + 203, 204, 205, 206, -1, 208, -1, 210, 211, 212, + 213, 214, 215, 216, 217, -1, 219, -1, 221, -1, + -1, 224, -1, 226, 227, 228, 229, 230, 231, -1, + -1, 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, + 273, 274, -1, 276, 277, -1, 279, -1, 281, 282, + 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, + 293, 294, -1, -1, 297, 298, 299, -1, 301, -1, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, -1, -1, -1, -1, 319, 320, 321, -1, + 323, 324, 325, 326, 327, 328, -1, 330, 331, 332, + 333, 334, 335, -1, 337, 338, 339, 340, 341, 342, + 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, + 363, -1, 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, + -1, 384, 385, 386, 387, 388, 389, 390, 391, 392, + -1, -1, 395, 396, 397, 398, -1, 400, 401, 402, + 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, + 413, 414, -1, -1, 417, 418, -1, 420, -1, 422, + 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, + 433, 434, 435, 436, 437, -1, 439, 440, 441, 442, + 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, + 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, + 463, 464, 465, -1, 467, -1, 469, 470, 471, 472, + 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 495, 496, 497, 498, 499, 500, 501, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, + 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, + 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, + -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, + 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, + 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, + 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, + 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, + 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, + -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, + 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, + 234, -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, + 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, + 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, + 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, + -1, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, + 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, + 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, + 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, + 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 43, 44, + -1, 46, 47, 48, -1, 50, 51, 52, 53, 54, + -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, 79, -1, -1, -1, 83, 84, + 85, 86, 87, 88, -1, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, -1, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, -1, -1, -1, 174, + 175, 176, -1, 178, -1, 180, -1, 182, 183, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, -1, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, -1, 210, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, -1, -1, 224, + -1, 226, 227, 228, 229, 230, 231, -1, -1, 234, + -1, 236, -1, -1, 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, -1, 270, 271, 272, 273, 274, + -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 297, 298, 299, -1, 301, -1, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + -1, -1, -1, -1, 319, 320, 321, -1, 323, 324, + 325, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 362, 363, -1, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, -1, -1, 384, + 385, 386, 387, 388, 389, 390, 391, 392, -1, -1, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, 463, 464, + 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, + 475, -1, -1, 478, -1, -1, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 22, 23, 24, 25, + 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, + -1, 37, -1, -1, -1, -1, 42, 43, 44, -1, + 46, 47, 48, 49, 50, 51, 52, -1, 54, 55, + 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, + -1, 67, 68, 69, 70, 71, 72, 73, -1, 75, + 76, 77, 78, -1, -1, 81, -1, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, -1, 94, 95, + 96, 97, 98, 99, -1, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, + -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, + 136, 137, 138, -1, 140, 141, 142, -1, 144, 145, + 146, -1, 148, 149, 150, 151, -1, 153, 154, 155, + 156, 157, 158, -1, -1, 161, -1, 163, 164, 165, + 166, -1, 168, -1, 170, 171, -1, 173, 174, 175, + -1, 177, 178, -1, 180, -1, -1, -1, 184, 185, + -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, + 206, -1, 208, 209, -1, 211, 212, 213, 214, 215, + 216, 217, -1, 219, -1, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, -1, -1, 234, 235, + 236, 237, -1, 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, -1, -1, + 276, 277, 278, 279, -1, -1, 282, 283, 284, 285, + 286, -1, 288, 289, -1, -1, 292, 293, 294, -1, + -1, 297, 298, -1, 300, 301, 302, -1, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, -1, + -1, -1, -1, 319, 320, -1, 322, 323, 324, -1, + 326, 327, 328, -1, 330, 331, 332, 333, 334, 335, + -1, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, + 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, + 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, + 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, + 386, 387, 388, 389, 390, 391, 392, -1, 394, 395, + 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, + 406, 407, 408, 409, 410, 411, 412, 413, -1, -1, + -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, + 426, -1, 428, 429, 430, -1, -1, 433, 434, -1, + 436, -1, -1, 439, 440, 441, 442, 443, 444, 445, + 446, 447, -1, 449, 450, 451, -1, 453, 454, 455, + 456, -1, 458, 459, 460, 461, 462, -1, 464, 465, + -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, + -1, -1, 478, -1, -1, 481, 482, 483, 484, 485, + 486, 3, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 498, 499, 500, 501, -1, -1, -1, -1, + 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, 61, @@ -19101,7 +18802,7 @@ static const yytype_int16 yycheck[] = 138, -1, 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, 151, -1, 153, 154, 155, 156, 157, 158, -1, -1, 161, -1, 163, 164, 165, 166, -1, - 168, -1, 170, 171, -1, 173, 174, 175, -1, 177, + 168, -1, 170, 171, -1, 173, 174, 175, 176, 177, 178, -1, 180, -1, -1, -1, 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, 205, 206, -1, @@ -19121,14 +18822,14 @@ static const yytype_int16 yycheck[] = 338, 339, 340, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + -1, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, 384, 385, 386, 387, - 388, 389, 390, 391, 392, -1, 394, 395, 396, 397, + 388, 389, -1, 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, -1, -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, -1, 436, -1, - -1, 439, 440, 441, 442, 443, 444, 445, 446, 447, + -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, 461, 462, -1, 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, 475, -1, -1, @@ -19136,201 +18837,152 @@ static const yytype_int16 yycheck[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 498, 499, 500, 501, -1, -1, -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, 31, 32, 33, - -1, -1, -1, 37, -1, -1, -1, -1, 42, 43, - 44, -1, 46, 47, 48, 49, 50, 51, 52, -1, - 54, 55, 56, 57, -1, 59, 60, 61, 62, 63, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + 44, -1, 46, 47, 48, -1, 50, 51, 52, 53, + 54, -1, 56, 57, -1, 59, 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, 71, 72, 73, - -1, 75, 76, 77, 78, -1, -1, 81, -1, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, -1, - 94, 95, 96, 97, 98, 99, -1, 101, 102, 103, + -1, 75, 76, 77, 78, 79, -1, -1, -1, 83, + 84, 85, 86, 87, 88, -1, 90, 91, 92, -1, + 94, 95, 96, 97, 98, 99, -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, 141, 142, -1, - 144, 145, 146, -1, 148, 149, 150, 151, -1, 153, - 154, 155, 156, 157, 158, -1, -1, 161, -1, 163, - 164, 165, 166, -1, 168, -1, 170, 171, -1, 173, - 174, 175, 176, 177, 178, -1, 180, -1, -1, -1, - 184, 185, -1, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, -1, 200, 201, 202, 203, - 204, 205, 206, -1, 208, 209, -1, 211, 212, 213, - 214, 215, 216, 217, -1, 219, -1, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, -1, -1, - 234, 235, 236, 237, -1, 239, 240, 241, 242, 243, + 144, 145, 146, -1, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159, -1, 161, -1, 163, + 164, 165, 166, -1, 168, -1, 170, -1, -1, -1, + 174, 175, 176, -1, 178, -1, 180, -1, 182, 183, + -1, 185, -1, 187, 188, 189, 190, 191, 192, 193, + -1, 195, 196, 197, 198, -1, 200, 201, 202, 203, + 204, 205, 206, -1, 208, -1, 210, 211, 212, 213, + 214, 215, 216, 217, -1, 219, -1, 221, -1, -1, + 224, -1, 226, 227, 228, 229, 230, 231, -1, -1, + 234, -1, 236, -1, -1, 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, - -1, -1, 276, 277, 278, 279, -1, -1, 282, 283, + 264, 265, 266, 267, 268, -1, 270, 271, 272, 273, + 274, -1, 276, 277, -1, 279, -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, -1, -1, 292, 293, - 294, -1, -1, 297, 298, -1, 300, 301, 302, -1, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, -1, -1, -1, -1, 319, 320, -1, 322, 323, - 324, -1, 326, 327, 328, -1, 330, 331, 332, 333, - 334, 335, -1, 337, 338, 339, 340, 341, 342, 343, + 294, -1, -1, 297, 298, 299, -1, 301, -1, 303, + 304, 305, 306, 307, 308, 309, -1, 311, 312, 313, + 314, -1, -1, -1, -1, 319, 320, 321, -1, 323, + 324, 325, 326, 327, 328, -1, 330, 331, 332, 333, + 334, 335, -1, 337, 338, 339, -1, 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, -1, 362, 363, - 364, 365, 366, 367, -1, 369, 370, 371, 372, 373, - 374, 375, 376, 377, 378, 379, 380, 381, -1, 383, - 384, 385, 386, 387, 388, 389, -1, 391, 392, -1, - 394, 395, 396, 397, 398, -1, 400, 401, 402, 403, + -1, 365, 366, 367, 368, -1, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 381, -1, -1, + 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + -1, 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, - -1, -1, -1, 417, 418, -1, 420, 421, 422, 423, + 414, -1, -1, 417, 418, -1, 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, 430, -1, -1, 433, - 434, -1, 436, -1, -1, 439, 440, 441, 442, 443, + 434, 435, 436, 437, -1, 439, 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, 451, -1, 453, - 454, 455, 456, -1, 458, 459, 460, 461, 462, -1, - 464, 465, -1, 467, 468, 469, 470, 471, 472, 473, + 454, 455, 456, -1, 458, 459, 460, 461, 462, 463, + 464, 465, -1, 467, -1, 469, 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, -1, 481, 482, 483, - 484, 485, 486, 3, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 498, 499, 500, 501, -1, -1, - -1, -1, 22, 23, 24, 25, 26, 27, 28, 29, - -1, 31, 32, 33, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, 44, -1, 46, 47, 48, -1, - 50, 51, 52, 53, 54, -1, 56, 57, -1, 59, - 60, 61, 62, 63, 64, -1, -1, 67, 68, 69, - 70, 71, 72, 73, -1, 75, 76, 77, 78, 79, - -1, -1, -1, 83, 84, 85, 86, 87, 88, -1, - 90, 91, 92, -1, 94, 95, 96, 97, 98, 99, - -1, -1, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, -1, 118, -1, - 120, 121, 122, 123, 124, 125, -1, -1, 128, 129, - 130, 131, -1, -1, 134, 135, 136, 137, 138, -1, - 140, 141, 142, -1, 144, 145, 146, -1, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - -1, 161, -1, 163, 164, 165, 166, -1, 168, -1, - 170, -1, -1, -1, 174, 175, 176, -1, 178, -1, - 180, -1, 182, 183, -1, 185, -1, 187, 188, 189, - 190, 191, 192, 193, -1, 195, 196, 197, 198, -1, - 200, 201, 202, 203, 204, 205, 206, -1, 208, -1, - 210, 211, 212, 213, 214, 215, 216, 217, -1, 219, - -1, 221, -1, -1, 224, -1, 226, 227, 228, 229, - 230, 231, -1, -1, 234, -1, 236, -1, -1, 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, -1, - 270, 271, 272, 273, 274, -1, 276, 277, -1, 279, - -1, 281, 282, 283, 284, 285, 286, -1, 288, 289, - -1, -1, 292, 293, 294, -1, -1, 297, 298, 299, - -1, 301, -1, 303, 304, 305, 306, 307, 308, 309, - -1, 311, 312, 313, 314, -1, -1, -1, -1, 319, - 320, 321, -1, 323, 324, 325, 326, 327, 328, -1, - 330, 331, 332, 333, 334, 335, -1, 337, 338, 339, - -1, 341, 342, 343, 344, 345, 346, -1, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, -1, 362, 363, -1, 365, 366, 367, 368, -1, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, -1, -1, 384, 385, 386, 387, 388, 389, - 390, 391, 392, -1, -1, 395, 396, 397, 398, -1, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, - 410, 411, 412, 413, 414, -1, -1, 417, 418, -1, - 420, -1, 422, 423, 424, 425, 426, -1, 428, 429, - 430, -1, -1, 433, 434, 435, 436, 437, -1, 439, - 440, 441, 442, 443, 444, 445, 446, -1, -1, 449, - 450, 451, -1, 453, 454, 455, 456, -1, 458, 459, - 460, 461, 462, 463, 464, 465, -1, 467, -1, 469, - 470, 471, 472, 473, 474, 475, -1, -1, 478, -1, - -1, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, 23, 24, 25, 26, 27, 28, 29, -1, - 31, 32, 33, -1, -1, -1, 37, -1, -1, -1, - -1, 42, 43, 44, -1, 46, 47, 48, 49, 50, - 51, 52, -1, 54, 55, 56, 57, -1, 59, 60, - 61, 62, 63, 64, -1, -1, 67, 68, 69, 70, - 71, 72, 73, -1, 75, 76, 77, 78, -1, -1, - 81, -1, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, -1, 94, 95, 96, 97, 98, 99, -1, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, -1, 118, -1, 120, - 121, 122, 123, 124, 125, -1, -1, 128, 129, 130, - 131, -1, -1, 134, 135, 136, 137, 138, -1, 140, - 141, 142, -1, 144, 145, 146, -1, 148, 149, 150, - 151, -1, 153, 154, 155, 156, 157, 158, -1, -1, - 161, -1, 163, 164, 165, 166, -1, 168, -1, 170, - 171, -1, 173, 174, 175, -1, 177, 178, -1, 180, - -1, -1, -1, 184, 185, -1, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, -1, 200, - 201, 202, 203, 204, 205, 206, -1, 208, 209, -1, - 211, 212, 213, 214, 215, 216, 217, -1, 219, -1, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, -1, -1, 234, 235, 236, 237, -1, 239, 240, - 241, 242, 243, 244, 245, 246, -1, 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, -1, -1, 276, 277, 278, 279, -1, - -1, 282, 283, 284, 285, 286, -1, 288, 289, -1, - -1, 292, 293, 294, -1, -1, 297, 298, -1, 300, - 301, 302, -1, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, -1, -1, -1, -1, 319, 320, - -1, 322, 323, 324, -1, 326, 327, 328, -1, 330, - 331, 332, 333, 334, 335, -1, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 346, -1, 348, 349, 350, - 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, - -1, 362, 363, 364, 365, 366, 367, -1, 369, 370, - 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, - 381, -1, 383, 384, 385, 386, 387, 388, 389, -1, - 391, 392, -1, 394, 395, 396, 397, 398, -1, 400, - 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, - 411, -1, 413, -1, -1, -1, 417, 418, -1, 420, - 421, 422, 423, 424, 425, 426, -1, 428, 429, 430, - -1, -1, 433, 434, -1, 436, -1, -1, 439, 440, - 441, 442, 443, 444, 445, 446, -1, -1, 449, 450, - 451, -1, 453, 454, 455, 456, -1, 458, 459, 460, - 461, 462, -1, 464, 465, -1, 467, 468, 469, 470, - 471, 472, 473, 474, 475, -1, 22, 478, -1, -1, - 481, 482, 483, 484, 485, 486, 32, -1, 34, 35, - -1, -1, -1, -1, 22, -1, -1, 498, 499, 500, - 501, -1, -1, -1, 32, -1, 52, -1, -1, -1, - -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, - -1, -1, -1, -1, 52, -1, -1, -1, -1, 75, - -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, - 86, -1, -1, -1, -1, -1, -1, 75, -1, -1, - -1, -1, 98, -1, 100, -1, -1, -1, 86, -1, - -1, -1, -1, -1, -1, 111, -1, -1, -1, -1, - 98, -1, 100, -1, -1, -1, -1, -1, -1, -1, - 126, 127, -1, 111, -1, -1, -1, -1, -1, -1, - -1, 137, -1, -1, -1, -1, -1, 143, 126, 127, - -1, -1, -1, -1, -1, 151, -1, -1, -1, 137, - -1, -1, -1, -1, -1, 143, -1, -1, -1, -1, - -1, -1, 168, 151, -1, -1, 172, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 168, -1, -1, -1, 172, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 214, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 214, -1, -1, -1, - -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, + 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 22, 23, 24, + 25, 26, 27, 28, 29, -1, 31, 32, 33, -1, + -1, -1, 37, -1, -1, -1, -1, 42, 43, 44, + -1, 46, 47, 48, 49, 50, 51, 52, -1, 54, + 55, 56, 57, -1, 59, 60, 61, 62, 63, 64, + -1, -1, 67, 68, 69, 70, 71, 72, 73, -1, + 75, 76, 77, 78, -1, -1, 81, -1, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, -1, 94, + 95, 96, 97, 98, 99, -1, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, -1, 118, -1, 120, 121, 122, 123, 124, + 125, -1, -1, 128, 129, 130, 131, -1, -1, 134, + 135, 136, 137, 138, -1, 140, 141, 142, -1, 144, + 145, 146, -1, 148, 149, 150, 151, -1, 153, 154, + 155, 156, 157, 158, -1, -1, 161, -1, 163, 164, + 165, 166, -1, 168, -1, 170, 171, -1, 173, 174, + 175, -1, 177, 178, -1, 180, -1, -1, -1, 184, + 185, -1, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, -1, 200, 201, 202, 203, 204, + 205, 206, -1, 208, 209, -1, 211, 212, 213, 214, + 215, 216, 217, -1, 219, -1, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, -1, -1, 234, + 235, 236, 237, -1, 239, 240, 241, 242, 243, 244, + 245, 246, -1, 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, -1, + -1, 276, 277, 278, 279, -1, -1, 282, 283, 284, + 285, 286, -1, 288, 289, -1, -1, 292, 293, 294, + -1, -1, 297, 298, -1, 300, 301, 302, -1, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + -1, -1, -1, -1, 319, 320, -1, 322, 323, 324, + -1, 326, 327, 328, -1, 330, 331, 332, 333, 334, + 335, -1, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, -1, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, -1, 362, 363, 364, + 365, 366, 367, -1, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, -1, 383, 384, + 385, 386, 387, 388, 389, -1, 391, 392, -1, 394, + 395, 396, 397, 398, -1, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, -1, 413, -1, + -1, -1, 417, 418, -1, 420, 421, 422, 423, 424, + 425, 426, -1, 428, 429, 430, -1, -1, 433, 434, + -1, 436, -1, -1, 439, 440, 441, 442, 443, 444, + 445, 446, -1, -1, 449, 450, 451, -1, 453, 454, + 455, 456, -1, 458, 459, 460, 461, 462, -1, 464, + 465, -1, 467, 468, 469, 470, 471, 472, 473, 474, + 475, -1, 22, 478, -1, -1, 481, 482, 483, 484, + 485, 486, 32, -1, 34, 35, -1, -1, -1, -1, + 22, -1, -1, 498, 499, 500, 501, -1, -1, -1, + 32, -1, 52, -1, -1, -1, -1, -1, -1, -1, + -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, + 52, -1, -1, -1, -1, 75, -1, -1, -1, 61, + -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, + -1, -1, -1, 75, -1, -1, -1, -1, 98, -1, + 100, -1, -1, -1, 86, -1, -1, -1, -1, -1, + -1, 111, -1, -1, -1, -1, 98, -1, 100, -1, + -1, -1, -1, -1, -1, -1, 126, 127, -1, 111, + -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, + -1, -1, -1, 143, 126, 127, -1, -1, -1, -1, + -1, 151, -1, -1, -1, 137, -1, -1, -1, -1, + -1, 143, -1, -1, -1, -1, -1, -1, 168, 151, + -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, + 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 214, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 214, -1, -1, -1, -1, -1, -1, -1, + 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 315, - 316, 317, -1, -1, -1, -1, -1, 323, -1, -1, - 326, -1, -1, -1, -1, -1, -1, 315, 316, 317, - -1, -1, -1, -1, -1, 323, -1, -1, 326, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 357, -1, -1, -1, -1, -1, -1, -1, -1, - 366, -1, -1, -1, -1, -1, -1, -1, -1, 357, - -1, -1, -1, -1, -1, -1, 382, -1, 366, -1, - -1, -1, -1, 389, -1, -1, -1, 393, -1, -1, - -1, -1, -1, -1, 382, -1, -1, 403, -1, -1, - -1, 389, -1, -1, -1, 393, -1, -1, -1, 415, - -1, -1, -1, 419, -1, 403, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 415, -1, -1, - -1, 419, -1, 439, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 452, -1, -1, -1, - -1, 439, 458, -1, -1, -1, -1, 463, -1, -1, - -1, -1, 468, -1, 452, -1, -1, -1, -1, -1, - 458, -1, -1, -1, 480, 463, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 480, -1, -1, -1, -1, -1, 504, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 518, -1, -1, -1, 504, -1, -1, -1, + -1, -1, -1, -1, -1, 315, 316, 317, -1, -1, + -1, -1, -1, 323, -1, -1, 326, -1, -1, -1, + -1, -1, -1, 315, 316, 317, -1, -1, -1, -1, + -1, 323, -1, -1, 326, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 357, -1, -1, + -1, -1, -1, -1, -1, -1, 366, -1, -1, -1, + -1, -1, -1, -1, -1, 357, -1, -1, -1, -1, + -1, -1, 382, -1, 366, -1, -1, -1, -1, 389, + -1, -1, -1, 393, -1, -1, -1, -1, -1, -1, + 382, -1, -1, 403, -1, -1, -1, 389, -1, -1, + -1, 393, -1, -1, -1, 415, -1, -1, -1, 419, + -1, 403, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 415, -1, -1, -1, 419, -1, 439, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 518 + -1, -1, 452, -1, -1, -1, -1, 439, 458, -1, + -1, -1, -1, 463, -1, -1, -1, -1, 468, -1, + 452, -1, -1, -1, -1, -1, 458, -1, -1, -1, + 480, 463, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 480, -1, + -1, -1, -1, -1, 504, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 518, -1, + -1, -1, 504, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 518 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -19344,11 +18996,11 @@ static const yytype_uint16 yystos[] = 452, 455, 458, 463, 480, 504, 518, 530, 531, 532, 533, 544, 553, 555, 560, 576, 579, 580, 582, 586, 587, 591, 598, 600, 603, 604, 652, 658, 667, 668, - 686, 687, 688, 689, 691, 693, 694, 698, 752, 753, - 935, 938, 941, 948, 949, 951, 954, 955, 956, 963, - 967, 973, 974, 977, 982, 986, 987, 988, 991, 994, - 995, 996, 999, 1000, 1002, 433, 483, 601, 203, 373, - 384, 419, 470, 108, 192, 989, 601, 3, 22, 23, + 686, 687, 688, 689, 691, 693, 694, 698, 751, 752, + 925, 928, 931, 938, 939, 941, 944, 945, 946, 953, + 957, 963, 964, 967, 972, 976, 977, 978, 981, 984, + 985, 986, 990, 991, 993, 433, 483, 601, 203, 373, + 384, 419, 470, 108, 192, 979, 601, 3, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63, 64, @@ -19389,10 +19041,10 @@ static const yytype_uint16 yystos[] = 467, 468, 469, 470, 471, 472, 473, 474, 475, 478, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 546, 834, 924, 928, 1005, 1006, 1007, 3, 176, - 247, 412, 546, 950, 1005, 290, 601, 55, 172, 518, + 501, 546, 831, 914, 918, 996, 997, 998, 3, 176, + 247, 412, 546, 940, 996, 290, 601, 55, 172, 518, 681, 178, 241, 295, 314, 373, 423, 425, 442, 448, - 451, 584, 650, 947, 5, 30, 326, 546, 547, 923, + 451, 584, 650, 937, 5, 30, 326, 546, 547, 913, 3, 30, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 49, 53, 54, 55, 56, 57, 58, 65, 66, 71, 72, 74, 79, 80, 81, 82, 83, 89, @@ -19408,297 +19060,293 @@ static const yytype_uint16 yystos[] = 412, 414, 415, 416, 419, 421, 427, 429, 430, 431, 432, 435, 437, 438, 441, 447, 448, 452, 457, 463, 464, 466, 468, 476, 477, 479, 480, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 552, 1005, - 1009, 1011, 24, 81, 97, 146, 156, 169, 174, 203, + 490, 491, 492, 493, 494, 495, 496, 497, 552, 996, + 1000, 1002, 24, 81, 97, 146, 156, 169, 174, 203, 246, 250, 320, 335, 370, 373, 384, 387, 405, 419, 425, 426, 436, 442, 470, 584, 653, 654, 657, 601, - 923, 100, 137, 468, 518, 533, 544, 553, 555, 576, + 913, 100, 137, 468, 518, 533, 544, 553, 555, 576, 579, 580, 586, 587, 591, 600, 604, 652, 658, 667, - 668, 686, 935, 938, 941, 948, 949, 959, 963, 967, - 973, 977, 982, 991, 994, 999, 1000, 1002, 108, 75, + 668, 686, 925, 928, 931, 938, 939, 949, 953, 957, + 963, 967, 972, 981, 984, 990, 991, 993, 108, 75, 66, 79, 81, 159, 232, 281, 291, 303, 321, 369, 414, 435, 437, 441, 463, 518, 545, 546, 547, 687, - 753, 755, 757, 758, 768, 775, 776, 834, 836, 837, - 108, 5, 546, 548, 975, 546, 923, 30, 178, 241, - 388, 429, 433, 465, 546, 992, 993, 998, 601, 30, - 132, 707, 708, 178, 241, 373, 388, 429, 465, 968, - 969, 998, 601, 545, 546, 547, 686, 698, 775, 419, - 704, 545, 173, 518, 979, 518, 345, 699, 700, 923, - 699, 687, 688, 994, 0, 521, 122, 213, 454, 147, - 218, 296, 447, 710, 711, 758, 758, 687, 689, 691, - 522, 468, 957, 214, 30, 429, 433, 545, 686, 192, - 545, 923, 192, 545, 192, 775, 192, 545, 275, 548, - 341, 602, 516, 520, 549, 550, 518, 82, 108, 174, - 203, 246, 373, 384, 419, 442, 470, 953, 108, 686, - 545, 423, 425, 423, 425, 355, 192, 545, 545, 380, - 174, 246, 345, 384, 419, 470, 665, 203, 30, 923, - 192, 552, 252, 436, 107, 419, 419, 470, 377, 380, - 192, 546, 655, 930, 192, 920, 923, 192, 923, 518, - 590, 295, 425, 959, 3, 463, 960, 962, 963, 965, - 966, 1005, 1009, 957, 546, 548, 950, 518, 518, 167, - 518, 687, 776, 518, 518, 545, 518, 518, 172, 518, - 518, 518, 518, 687, 753, 758, 768, 511, 549, 523, - 40, 546, 769, 770, 769, 382, 522, 690, 518, 687, - 775, 776, 37, 42, 101, 173, 209, 225, 235, 269, - 315, 322, 364, 383, 452, 772, 770, 40, 546, 769, - 771, 504, 780, 548, 507, 518, 518, 936, 993, 993, - 993, 501, 224, 993, 520, 290, 4, 6, 7, 8, - 9, 10, 39, 54, 56, 57, 65, 71, 72, 83, - 112, 115, 117, 136, 152, 160, 165, 182, 183, 216, - 217, 219, 247, 268, 270, 275, 280, 283, 292, 342, - 368, 397, 429, 430, 438, 464, 502, 509, 510, 511, - 516, 518, 524, 525, 526, 527, 546, 548, 687, 742, - 792, 795, 798, 799, 800, 802, 803, 804, 805, 807, - 808, 824, 826, 827, 828, 829, 830, 831, 832, 833, - 834, 835, 837, 839, 854, 855, 866, 888, 895, 903, - 904, 905, 924, 925, 926, 902, 904, 968, 968, 548, - 968, 501, 968, 172, 431, 507, 602, 549, 775, 983, - 3, 171, 173, 468, 963, 978, 980, 171, 981, 546, - 824, 872, 873, 699, 522, 518, 932, 519, 519, 519, - 532, 172, 295, 563, 157, 983, 30, 132, 705, 705, - 59, 705, 162, 167, 238, 287, 716, 718, 719, 745, - 747, 748, 749, 181, 290, 457, 290, 710, 711, 518, - 545, 975, 420, 997, 501, 224, 152, 26, 32, 137, - 294, 353, 357, 389, 460, 538, 541, 542, 353, 152, - 40, 60, 106, 202, 251, 261, 273, 305, 353, 359, - 384, 389, 403, 541, 592, 595, 152, 353, 389, 541, - 152, 353, 389, 541, 152, 40, 990, 291, 485, 824, - 896, 551, 552, 550, 3, 30, 37, 42, 49, 55, - 81, 83, 89, 101, 132, 171, 173, 176, 177, 194, - 209, 222, 223, 225, 235, 237, 247, 269, 278, 300, - 302, 322, 364, 383, 394, 412, 421, 441, 466, 468, - 519, 711, 824, 875, 876, 927, 933, 1005, 1010, 824, - 419, 545, 546, 519, 518, 639, 373, 584, 650, 275, - 939, 40, 192, 546, 583, 470, 192, 545, 192, 545, - 1004, 192, 545, 192, 545, 89, 944, 152, 484, 90, - 129, 308, 424, 192, 546, 152, 520, 931, 63, 360, - 522, 656, 152, 522, 656, 152, 290, 588, 589, 824, - 933, 355, 519, 522, 4, 160, 290, 438, 509, 510, - 548, 594, 597, 926, 958, 960, 961, 964, 959, 431, - 518, 676, 680, 824, 873, 518, 3, 68, 69, 109, - 110, 113, 114, 189, 190, 253, 254, 255, 256, 257, - 258, 259, 260, 263, 264, 337, 338, 378, 379, 474, - 475, 498, 499, 548, 810, 811, 812, 813, 814, 815, - 816, 817, 818, 819, 820, 821, 822, 878, 879, 770, - 771, 824, 545, 824, 880, 509, 510, 546, 825, 826, - 855, 866, 882, 518, 824, 872, 883, 824, 58, 172, - 233, 432, 824, 873, 886, 824, 519, 547, 518, 421, - 725, 726, 726, 707, 708, 758, 220, 702, 768, 726, - 726, 726, 225, 37, 225, 383, 772, 225, 300, 773, - 758, 773, 225, 772, 518, 225, 773, 225, 148, 200, - 760, 225, 726, 518, 547, 518, 726, 297, 824, 970, - 972, 875, 3, 37, 42, 49, 54, 55, 56, 57, - 71, 72, 81, 83, 89, 101, 112, 115, 165, 171, - 173, 177, 194, 209, 216, 217, 219, 222, 223, 225, - 235, 237, 247, 268, 269, 270, 278, 283, 300, 302, - 322, 342, 364, 368, 383, 390, 394, 397, 412, 421, - 429, 430, 441, 447, 464, 468, 786, 788, 789, 791, - 793, 795, 797, 799, 800, 801, 803, 804, 807, 808, - 877, 929, 1005, 1008, 40, 236, 546, 518, 516, 687, - 467, 806, 824, 892, 806, 806, 518, 518, 794, 794, - 325, 687, 518, 796, 527, 71, 72, 806, 824, 794, - 518, 518, 482, 504, 518, 809, 518, 809, 824, 824, - 824, 83, 148, 906, 910, 824, 873, 874, 687, 824, - 872, 552, 9, 547, 856, 857, 858, 520, 523, 549, - 897, 549, 518, 548, 518, 518, 548, 926, 3, 8, - 11, 15, 16, 17, 18, 19, 20, 21, 36, 40, - 46, 53, 80, 177, 194, 199, 222, 223, 237, 275, - 278, 292, 295, 394, 502, 505, 506, 507, 509, 510, - 511, 512, 513, 514, 864, 865, 866, 868, 900, 481, - 840, 302, 824, 522, 702, 518, 548, 702, 3, 117, - 241, 548, 594, 808, 971, 104, 972, 972, 40, 546, - 519, 522, 957, 522, 519, 700, 920, 921, 40, 983, - 193, 355, 220, 639, 389, 689, 689, 30, 712, 713, - 824, 59, 689, 706, 164, 272, 733, 227, 273, 341, - 392, 454, 4, 9, 30, 728, 824, 509, 510, 729, - 730, 824, 826, 745, 746, 719, 718, 716, 717, 167, - 748, 285, 750, 59, 695, 696, 697, 761, 825, 904, - 904, 716, 745, 873, 932, 172, 469, 976, 236, 545, - 74, 82, 93, 169, 192, 329, 448, 546, 621, 631, - 646, 82, 93, 554, 93, 554, 518, 431, 518, 619, - 245, 451, 619, 93, 522, 431, 545, 3, 791, 594, - 59, 596, 594, 594, 106, 251, 261, 59, 431, 480, - 504, 593, 266, 373, 593, 595, 775, 93, 431, 554, - 373, 545, 431, 373, 989, 546, 676, 517, 523, 875, - 875, 876, 193, 358, 709, 522, 710, 711, 13, 14, - 222, 222, 431, 431, 546, 638, 643, 480, 679, 545, - 380, 345, 384, 419, 470, 665, 152, 100, 580, 604, - 940, 941, 1000, 144, 788, 275, 199, 585, 545, 275, - 581, 592, 275, 518, 639, 40, 275, 639, 275, 518, - 659, 660, 661, 662, 663, 664, 666, 192, 546, 633, - 945, 552, 152, 172, 599, 655, 551, 520, 930, 920, - 923, 923, 930, 519, 522, 13, 959, 965, 4, 926, - 4, 926, 548, 552, 678, 685, 55, 102, 123, 141, - 145, 168, 171, 187, 280, 288, 310, 339, 682, 40, - 519, 824, 519, 172, 522, 519, 318, 881, 519, 825, - 825, 11, 15, 16, 19, 20, 21, 199, 222, 292, - 505, 506, 507, 509, 510, 511, 512, 513, 514, 866, - 825, 519, 777, 778, 836, 167, 172, 884, 885, 522, - 519, 40, 886, 873, 886, 886, 172, 519, 40, 769, - 518, 921, 4, 9, 546, 720, 721, 723, 724, 829, - 904, 902, 178, 241, 419, 423, 425, 451, 545, 703, - 477, 781, 519, 758, 758, 225, 758, 290, 457, 774, - 758, 225, 904, 758, 758, 282, 282, 518, 758, 547, - 782, 783, 518, 547, 782, 522, 519, 522, 520, 518, - 791, 518, 518, 520, 39, 790, 518, 810, 811, 812, - 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, - 823, 519, 522, 794, 555, 560, 667, 668, 686, 937, - 982, 994, 873, 874, 518, 476, 889, 890, 824, 874, - 926, 824, 859, 860, 861, 862, 806, 806, 8, 15, - 16, 19, 20, 21, 505, 506, 507, 509, 510, 511, - 512, 513, 514, 546, 864, 869, 519, 873, 429, 429, - 926, 926, 518, 518, 547, 907, 355, 914, 167, 517, - 519, 522, 523, 522, 528, 511, 824, 550, 873, 926, - 824, 823, 823, 788, 824, 824, 824, 824, 824, 824, - 824, 824, 5, 552, 934, 429, 45, 416, 901, 930, - 824, 824, 518, 687, 830, 887, 895, 132, 160, 275, - 280, 285, 438, 449, 824, 280, 518, 824, 431, 53, - 177, 194, 199, 237, 394, 824, 824, 824, 824, 824, - 824, 824, 824, 824, 824, 30, 38, 399, 863, 516, - 520, 899, 181, 163, 841, 368, 518, 855, 905, 172, - 754, 875, 754, 518, 548, 546, 545, 978, 545, 986, - 824, 522, 519, 250, 275, 701, 457, 985, 545, 557, + 752, 754, 756, 766, 773, 774, 831, 833, 834, 108, + 5, 546, 548, 965, 546, 913, 30, 178, 241, 388, + 429, 433, 465, 546, 982, 983, 988, 601, 30, 132, + 707, 708, 178, 241, 373, 388, 429, 465, 958, 959, + 988, 601, 546, 686, 698, 989, 546, 773, 419, 704, + 545, 173, 518, 969, 518, 345, 699, 700, 913, 699, + 687, 688, 984, 0, 521, 122, 213, 454, 147, 218, + 296, 447, 710, 711, 756, 756, 687, 689, 691, 522, + 468, 947, 214, 30, 429, 433, 686, 989, 192, 545, + 913, 192, 545, 192, 773, 192, 545, 275, 548, 341, + 602, 516, 520, 549, 550, 518, 82, 108, 174, 203, + 246, 373, 384, 419, 442, 470, 943, 108, 686, 545, + 423, 425, 423, 425, 355, 192, 545, 545, 380, 174, + 246, 345, 384, 419, 470, 665, 203, 30, 913, 192, + 552, 252, 436, 107, 419, 419, 470, 377, 380, 192, + 546, 655, 920, 192, 910, 913, 192, 913, 518, 590, + 295, 425, 949, 3, 463, 950, 952, 953, 955, 956, + 996, 1000, 947, 546, 548, 940, 518, 518, 167, 518, + 687, 774, 518, 518, 545, 518, 518, 172, 518, 518, + 518, 518, 687, 752, 756, 766, 511, 549, 40, 546, + 767, 768, 767, 382, 522, 690, 37, 42, 101, 173, + 209, 225, 235, 269, 315, 322, 364, 383, 452, 770, + 768, 40, 546, 767, 769, 504, 778, 548, 507, 518, + 518, 926, 983, 983, 983, 501, 224, 983, 520, 290, + 4, 6, 7, 8, 9, 10, 39, 54, 56, 57, + 65, 71, 72, 83, 112, 115, 117, 136, 152, 160, + 165, 182, 183, 216, 217, 219, 247, 268, 270, 275, + 280, 283, 292, 342, 368, 397, 429, 430, 438, 464, + 502, 509, 510, 511, 516, 518, 523, 524, 525, 526, + 546, 548, 687, 741, 790, 793, 796, 797, 798, 800, + 801, 802, 803, 805, 806, 822, 824, 825, 826, 827, + 828, 829, 830, 831, 832, 834, 836, 851, 852, 863, + 885, 892, 900, 901, 902, 914, 915, 916, 899, 901, + 958, 958, 548, 958, 501, 958, 172, 431, 507, 602, + 520, 549, 773, 973, 3, 171, 173, 468, 953, 968, + 970, 171, 971, 822, 869, 870, 699, 522, 518, 922, + 519, 519, 519, 532, 172, 295, 563, 157, 973, 30, + 132, 705, 705, 59, 705, 162, 167, 238, 287, 716, + 718, 719, 744, 746, 747, 748, 181, 290, 457, 290, + 710, 711, 518, 545, 965, 420, 987, 501, 224, 152, + 26, 32, 137, 294, 353, 357, 389, 460, 538, 541, + 542, 353, 152, 40, 60, 106, 202, 251, 261, 273, + 305, 353, 359, 384, 389, 403, 541, 592, 595, 152, + 353, 389, 541, 152, 353, 389, 541, 152, 40, 980, + 291, 485, 822, 893, 551, 552, 550, 3, 30, 37, + 42, 49, 55, 81, 83, 89, 101, 132, 171, 173, + 176, 177, 194, 209, 222, 223, 225, 235, 237, 247, + 269, 278, 300, 302, 322, 364, 383, 394, 412, 421, + 441, 466, 468, 519, 822, 872, 873, 917, 923, 996, + 1001, 822, 419, 545, 546, 519, 518, 639, 373, 584, + 650, 275, 929, 40, 192, 546, 583, 470, 192, 545, + 192, 545, 995, 192, 545, 192, 545, 89, 934, 152, + 484, 90, 129, 308, 424, 192, 546, 152, 520, 921, + 63, 360, 522, 656, 152, 522, 656, 152, 290, 588, + 589, 822, 923, 355, 519, 522, 4, 160, 290, 438, + 509, 510, 548, 594, 597, 916, 948, 950, 951, 954, + 949, 431, 518, 676, 680, 822, 870, 518, 3, 68, + 69, 109, 110, 113, 114, 189, 190, 253, 254, 255, + 256, 257, 258, 259, 260, 263, 264, 337, 338, 378, + 379, 474, 475, 498, 499, 548, 808, 809, 810, 811, + 812, 813, 814, 815, 816, 817, 818, 819, 820, 875, + 876, 768, 769, 822, 545, 822, 877, 509, 510, 546, + 823, 824, 852, 863, 879, 518, 822, 869, 880, 822, + 58, 172, 233, 432, 822, 870, 883, 822, 519, 547, + 518, 421, 724, 725, 725, 707, 708, 756, 220, 702, + 225, 37, 225, 383, 770, 225, 300, 771, 756, 771, + 225, 770, 518, 225, 771, 225, 148, 200, 758, 225, + 725, 518, 547, 518, 725, 297, 822, 960, 962, 872, + 3, 37, 42, 49, 54, 55, 56, 57, 71, 72, + 81, 83, 89, 101, 112, 115, 165, 171, 173, 177, + 194, 209, 216, 217, 219, 222, 223, 225, 235, 237, + 247, 268, 269, 270, 278, 283, 300, 302, 322, 342, + 364, 368, 383, 390, 394, 397, 412, 421, 429, 430, + 441, 447, 464, 468, 784, 786, 787, 789, 791, 793, + 795, 797, 798, 799, 801, 802, 805, 806, 874, 919, + 996, 999, 40, 236, 546, 518, 516, 687, 467, 804, + 822, 889, 804, 804, 518, 518, 792, 792, 325, 687, + 518, 794, 526, 71, 72, 804, 822, 792, 518, 518, + 482, 504, 518, 807, 518, 807, 822, 822, 822, 83, + 148, 903, 904, 822, 870, 871, 687, 822, 869, 9, + 552, 547, 853, 854, 855, 520, 549, 894, 549, 518, + 548, 518, 518, 548, 916, 3, 8, 11, 15, 16, + 17, 18, 19, 20, 21, 36, 40, 46, 53, 80, + 177, 194, 199, 222, 223, 237, 275, 278, 292, 295, + 394, 502, 505, 506, 507, 509, 510, 511, 512, 513, + 514, 861, 862, 863, 865, 897, 481, 837, 302, 822, + 522, 702, 518, 548, 702, 3, 117, 241, 548, 594, + 806, 961, 104, 962, 962, 546, 40, 546, 519, 522, + 947, 522, 519, 700, 910, 911, 40, 973, 193, 355, + 220, 639, 389, 689, 689, 30, 712, 713, 822, 59, + 689, 706, 164, 272, 732, 227, 273, 341, 392, 454, + 4, 9, 30, 727, 822, 509, 510, 728, 729, 822, + 824, 744, 745, 719, 718, 716, 717, 167, 747, 285, + 749, 59, 695, 696, 697, 759, 823, 901, 901, 716, + 744, 870, 922, 172, 469, 966, 236, 545, 74, 82, + 93, 169, 192, 329, 448, 546, 621, 631, 646, 82, + 93, 554, 93, 554, 518, 431, 518, 619, 245, 451, + 619, 93, 522, 431, 545, 3, 789, 594, 59, 596, + 594, 594, 106, 251, 261, 59, 431, 480, 504, 593, + 266, 373, 593, 595, 773, 93, 431, 554, 373, 545, + 431, 373, 979, 546, 676, 517, 528, 872, 872, 873, + 522, 710, 711, 13, 14, 222, 222, 431, 431, 546, + 638, 643, 480, 679, 545, 380, 345, 384, 419, 470, + 665, 152, 100, 580, 604, 930, 931, 991, 144, 786, + 275, 199, 585, 545, 275, 581, 592, 275, 518, 639, + 40, 275, 639, 275, 518, 659, 660, 661, 662, 663, + 664, 666, 192, 546, 633, 935, 552, 152, 172, 599, + 655, 551, 520, 920, 910, 913, 913, 920, 519, 522, + 13, 949, 955, 4, 916, 4, 916, 548, 552, 678, + 685, 55, 102, 123, 141, 145, 168, 171, 187, 280, + 288, 310, 339, 682, 40, 519, 822, 519, 172, 522, + 519, 318, 878, 519, 823, 823, 11, 15, 16, 19, + 20, 21, 199, 222, 292, 505, 506, 507, 509, 510, + 511, 512, 513, 514, 863, 823, 519, 775, 776, 833, + 167, 172, 881, 882, 522, 519, 40, 883, 870, 883, + 883, 172, 519, 40, 767, 518, 911, 4, 9, 546, + 720, 722, 723, 901, 899, 178, 241, 419, 423, 425, + 451, 545, 703, 477, 779, 756, 756, 225, 756, 290, + 457, 772, 756, 225, 901, 756, 756, 282, 282, 518, + 756, 547, 780, 781, 518, 547, 780, 522, 519, 522, + 520, 518, 789, 518, 518, 520, 39, 788, 518, 808, + 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, + 819, 820, 821, 519, 522, 792, 555, 560, 667, 668, + 686, 927, 972, 984, 870, 871, 518, 476, 886, 887, + 822, 871, 916, 822, 856, 857, 858, 859, 804, 804, + 8, 15, 16, 19, 20, 21, 505, 506, 507, 509, + 510, 511, 512, 513, 514, 546, 861, 866, 519, 870, + 429, 429, 916, 916, 518, 518, 546, 355, 908, 167, + 517, 519, 522, 528, 522, 527, 511, 550, 870, 916, + 822, 821, 821, 786, 822, 822, 822, 822, 822, 822, + 822, 822, 5, 552, 924, 429, 45, 416, 898, 920, + 822, 822, 518, 687, 827, 884, 892, 132, 160, 275, + 280, 285, 438, 449, 822, 280, 518, 822, 431, 53, + 177, 194, 199, 237, 394, 822, 822, 822, 822, 822, + 822, 822, 822, 822, 822, 30, 38, 399, 860, 516, + 520, 896, 181, 163, 838, 368, 518, 852, 902, 172, + 753, 872, 753, 518, 548, 546, 545, 968, 545, 976, + 822, 522, 519, 250, 275, 701, 457, 975, 545, 557, 518, 546, 562, 572, 573, 575, 41, 126, 714, 522, - 457, 714, 266, 689, 368, 369, 509, 510, 730, 732, - 826, 392, 227, 291, 313, 313, 522, 513, 4, 731, - 926, 731, 368, 369, 732, 545, 919, 279, 396, 751, - 518, 921, 922, 522, 181, 457, 199, 181, 220, 746, + 457, 714, 266, 689, 368, 369, 509, 510, 729, 731, + 824, 392, 227, 291, 313, 313, 522, 513, 4, 730, + 916, 730, 368, 369, 731, 545, 909, 279, 396, 750, + 518, 911, 912, 522, 181, 457, 199, 181, 220, 745, 717, 519, 546, 548, 546, 548, 353, 541, 518, 192, - 631, 923, 227, 275, 227, 457, 518, 624, 787, 788, - 923, 546, 192, 923, 192, 546, 26, 137, 389, 537, - 540, 552, 615, 629, 923, 552, 623, 642, 923, 538, - 923, 353, 389, 541, 592, 594, 930, 923, 594, 930, - 923, 594, 353, 389, 541, 923, 923, 923, 923, 353, - 389, 541, 923, 923, 548, 510, 824, 896, 710, 710, - 710, 282, 282, 519, 466, 876, 709, 824, 824, 280, - 548, 952, 280, 952, 546, 334, 675, 519, 522, 288, - 172, 431, 670, 939, 583, 470, 545, 545, 1004, 545, - 545, 545, 295, 650, 518, 687, 152, 3, 518, 518, - 152, 152, 237, 546, 621, 631, 634, 637, 647, 649, - 480, 482, 626, 151, 686, 152, 480, 946, 152, 519, - 875, 522, 522, 40, 275, 290, 546, 3, 656, 551, - 656, 290, 656, 588, 824, 676, 247, 511, 516, 518, - 594, 677, 831, 832, 833, 964, 519, 522, 40, 674, - 548, 674, 275, 280, 339, 674, 59, 674, 788, 519, - 824, 824, 824, 884, 788, 825, 825, 825, 825, 825, - 825, 132, 275, 285, 825, 825, 825, 825, 825, 825, - 825, 825, 825, 825, 519, 522, 40, 779, 824, 824, - 885, 884, 788, 519, 519, 519, 873, 788, 921, 519, - 313, 369, 513, 518, 518, 702, 423, 425, 423, 425, - 545, 704, 704, 704, 824, 181, 734, 774, 774, 758, - 824, 518, 758, 167, 774, 518, 547, 765, 774, 788, - 519, 522, 782, 519, 970, 3, 877, 39, 790, 546, - 785, 785, 3, 516, 516, 926, 431, 431, 431, 431, - 788, 454, 519, 517, 873, 824, 139, 890, 891, 519, - 519, 519, 523, 522, 528, 520, 519, 519, 501, 501, - 519, 519, 824, 907, 908, 909, 520, 518, 824, 911, - 353, 918, 546, 838, 893, 894, 824, 824, 856, 910, - 519, 519, 519, 501, 825, 825, 145, 873, 172, 132, - 160, 280, 285, 438, 449, 518, 145, 869, 824, 416, - 901, 824, 887, 824, 431, 518, 687, 824, 896, 551, - 518, 518, 155, 842, 755, 756, 781, 710, 781, 926, - 823, 932, 932, 250, 518, 756, 477, 984, 40, 59, - 558, 568, 575, 897, 522, 754, 507, 503, 715, 713, - 292, 864, 867, 715, 4, 926, 732, 291, 454, 729, - 522, 244, 921, 695, 59, 904, 518, 547, 59, 266, - 976, 976, 431, 824, 275, 646, 518, 152, 518, 624, - 203, 643, 644, 605, 40, 176, 614, 640, 605, 26, - 137, 357, 359, 389, 534, 535, 536, 542, 543, 152, - 656, 152, 656, 615, 629, 615, 519, 522, 548, 608, - 507, 520, 519, 522, 431, 373, 93, 431, 554, 373, - 431, 431, 431, 373, 990, 523, 517, 523, 709, 709, - 709, 876, 519, 518, 669, 3, 406, 407, 548, 684, - 638, 675, 585, 545, 581, 518, 40, 639, 662, 664, - 939, 355, 419, 548, 577, 578, 583, 685, 643, 545, - 545, 1004, 545, 519, 522, 288, 619, 288, 290, 618, - 923, 480, 1003, 545, 619, 40, 545, 519, 660, 666, - 663, 666, 419, 824, 152, 545, 599, 930, 672, 683, - 964, 678, 548, 548, 280, 643, 511, 643, 548, 511, - 643, 548, 519, 519, 885, 172, 132, 285, 518, 780, - 777, 518, 519, 519, 519, 546, 721, 781, 704, 704, - 704, 704, 545, 545, 545, 59, 186, 743, 774, 921, - 518, 762, 763, 764, 827, 830, 921, 167, 80, 784, - 783, 519, 519, 516, 788, 519, 522, 519, 926, 517, - 926, 519, 811, 813, 814, 815, 814, 815, 815, 519, - 427, 824, 143, 824, 859, 869, 809, 809, 519, 522, - 519, 547, 824, 911, 912, 913, 40, 518, 907, 915, - 199, 522, 519, 914, 823, 824, 36, 36, 824, 519, - 824, 172, 518, 877, 824, 519, 145, 825, 825, 145, - 145, 824, 824, 517, 523, 518, 898, 711, 477, 824, - 301, 846, 522, 734, 709, 734, 519, 937, 824, 361, - 566, 546, 266, 321, 117, 304, 518, 556, 686, 519, - 522, 562, 984, 824, 164, 231, 518, 715, 291, 545, - 519, 922, 181, 687, 688, 904, 922, 923, 923, 519, - 152, 644, 631, 644, 605, 633, 522, 519, 119, 207, - 273, 275, 630, 518, 33, 59, 651, 640, 74, 80, - 93, 117, 119, 207, 275, 280, 329, 347, 448, 457, - 610, 611, 625, 176, 117, 191, 275, 619, 593, 107, - 117, 176, 275, 405, 408, 595, 619, 389, 536, 442, - 923, 546, 540, 3, 37, 42, 49, 55, 81, 83, - 89, 101, 171, 173, 176, 177, 194, 209, 222, 223, - 225, 235, 237, 247, 269, 274, 278, 292, 300, 302, - 322, 364, 383, 390, 394, 412, 421, 441, 447, 468, - 509, 510, 548, 594, 606, 645, 788, 867, 927, 1005, - 1011, 552, 642, 923, 923, 923, 923, 923, 923, 923, - 923, 923, 923, 676, 896, 896, 519, 519, 519, 710, - 107, 373, 520, 593, 684, 518, 518, 637, 686, 946, - 650, 192, 545, 519, 522, 585, 519, 519, 581, 518, - 40, 628, 626, 634, 86, 590, 107, 273, 639, 686, - 662, 664, 40, 40, 687, 688, 633, 457, 943, 656, - 519, 522, 643, 825, 172, 518, 877, 782, 519, 522, - 519, 734, 545, 545, 545, 545, 30, 103, 182, 367, - 518, 735, 736, 737, 738, 739, 740, 741, 824, 824, - 479, 843, 519, 826, 870, 871, 199, 181, 759, 763, - 519, 765, 766, 767, 930, 790, 926, 790, 546, 790, - 517, 517, 824, 907, 522, 519, 546, 915, 916, 917, - 40, 824, 826, 894, 918, 824, 824, 824, 877, 519, - 824, 36, 36, 824, 824, 145, 519, 510, 896, 519, - 875, 519, 824, 519, 518, 546, 847, 743, 519, 743, - 548, 519, 903, 463, 418, 456, 567, 546, 561, 571, - 290, 564, 507, 575, 566, 869, 59, 519, 519, 462, - 463, 692, 605, 631, 519, 519, 480, 636, 120, 195, - 205, 119, 459, 824, 117, 40, 518, 930, 923, 825, - 120, 195, 119, 280, 227, 545, 636, 88, 651, 192, - 280, 594, 824, 651, 280, 509, 510, 597, 546, 787, - 788, 656, 656, 3, 247, 412, 927, 931, 507, 431, - 431, 517, 517, 709, 519, 519, 546, 676, 457, 671, - 673, 685, 643, 519, 1003, 40, 419, 275, 518, 548, - 518, 946, 637, 151, 686, 149, 201, 618, 122, 137, - 328, 1003, 107, 946, 480, 1001, 419, 290, 546, 942, - 518, 683, 825, 877, 519, 519, 9, 354, 727, 743, - 518, 391, 518, 519, 522, 546, 844, 845, 336, 744, - 522, 519, 518, 547, 59, 519, 199, 519, 766, 517, - 788, 911, 522, 519, 546, 517, 192, 519, 824, 824, - 824, 523, 517, 523, 519, 519, 546, 848, 843, 548, - 843, 522, 462, 897, 519, 522, 91, 566, 824, 519, - 922, 922, 347, 636, 518, 627, 605, 519, 191, 518, - 824, 275, 611, 636, 639, 923, 40, 152, 784, 931, - 513, 606, 923, 923, 519, 593, 124, 519, 519, 626, - 686, 545, 152, 685, 40, 519, 923, 1003, 30, 85, - 94, 118, 191, 204, 405, 408, 622, 622, 369, 369, - 40, 64, 74, 241, 687, 545, 518, 546, 565, 574, - 836, 519, 519, 518, 843, 873, 518, 873, 737, 40, - 522, 824, 457, 722, 826, 904, 921, 770, 518, 770, - 915, 824, 896, 896, 310, 849, 744, 744, 686, 304, - 686, 561, 290, 518, 559, 545, 605, 552, 632, 635, - 409, 472, 612, 613, 518, 607, 824, 519, 249, 648, - 191, 457, 539, 513, 442, 676, 548, 946, 618, 1001, - 518, 545, 519, 686, 626, 590, 686, 74, 293, 74, - 943, 824, 80, 569, 519, 522, 569, 9, 744, 519, - 736, 519, 847, 845, 371, 519, 904, 517, 517, 517, - 59, 710, 722, 722, 567, 93, 574, 133, 639, 507, - 519, 522, 592, 519, 273, 620, 173, 309, 395, 290, - 616, 617, 641, 607, 824, 442, 40, 518, 1001, 618, - 1003, 1001, 293, 293, 518, 519, 930, 570, 930, 946, - 565, 570, 519, 722, 519, 724, 519, 872, 184, 340, - 369, 850, 462, 923, 519, 276, 454, 648, 606, 635, - 519, 613, 205, 122, 454, 290, 641, 290, 616, 686, - 574, 569, 714, 781, 714, 53, 104, 444, 824, 851, - 852, 851, 851, 519, 686, 781, 389, 617, 63, 273, - 360, 389, 609, 609, 1001, 519, 570, 715, 715, 852, - 368, 166, 324, 166, 324, 148, 853, 853, 853, 573, - 605, 25, 117, 280, 946, 714, 36, 104, 181, 273, - 428, 781, 781, 715, 852, 368, 298 + 631, 913, 227, 275, 227, 457, 518, 624, 785, 786, + 913, 546, 192, 913, 192, 546, 26, 137, 389, 537, + 540, 552, 615, 629, 913, 552, 623, 642, 913, 538, + 913, 353, 389, 541, 592, 594, 920, 913, 594, 920, + 913, 594, 353, 389, 541, 913, 913, 913, 913, 353, + 389, 541, 913, 913, 548, 510, 822, 893, 710, 710, + 710, 466, 873, 193, 358, 709, 822, 822, 280, 548, + 942, 280, 942, 546, 334, 675, 519, 522, 288, 172, + 431, 670, 929, 583, 470, 545, 545, 995, 545, 545, + 545, 295, 650, 518, 687, 152, 3, 518, 518, 152, + 152, 237, 546, 621, 631, 634, 637, 647, 649, 480, + 482, 626, 151, 686, 152, 480, 936, 152, 519, 872, + 522, 522, 40, 275, 290, 546, 3, 656, 551, 656, + 290, 656, 588, 822, 676, 247, 511, 516, 518, 594, + 677, 828, 829, 830, 954, 519, 522, 40, 674, 548, + 674, 275, 280, 339, 674, 59, 674, 786, 519, 822, + 822, 822, 881, 786, 823, 823, 823, 823, 823, 823, + 132, 275, 285, 823, 823, 823, 823, 823, 823, 823, + 823, 823, 823, 519, 522, 40, 777, 822, 822, 882, + 881, 786, 519, 519, 519, 870, 786, 911, 519, 313, + 513, 313, 369, 513, 518, 518, 702, 423, 425, 423, + 425, 545, 704, 704, 704, 822, 181, 733, 772, 772, + 756, 822, 518, 756, 167, 772, 518, 547, 763, 772, + 786, 519, 522, 780, 519, 960, 3, 874, 39, 788, + 546, 783, 783, 3, 516, 516, 916, 431, 431, 431, + 431, 786, 454, 519, 517, 870, 822, 139, 887, 888, + 519, 519, 519, 528, 522, 527, 520, 519, 519, 501, + 501, 519, 519, 822, 911, 518, 822, 905, 546, 835, + 890, 891, 822, 822, 853, 904, 519, 519, 519, 501, + 823, 823, 145, 870, 172, 132, 160, 280, 285, 438, + 449, 518, 145, 866, 822, 416, 898, 822, 884, 822, + 431, 518, 687, 822, 893, 551, 518, 518, 155, 839, + 754, 755, 779, 710, 779, 916, 821, 922, 922, 250, + 518, 755, 477, 974, 40, 59, 558, 568, 575, 894, + 522, 753, 507, 503, 715, 713, 292, 861, 864, 715, + 4, 916, 731, 291, 454, 728, 522, 244, 911, 695, + 59, 901, 518, 547, 59, 266, 966, 966, 431, 822, + 275, 646, 518, 152, 518, 624, 203, 643, 644, 605, + 40, 176, 614, 640, 605, 26, 137, 357, 359, 389, + 534, 535, 536, 542, 543, 152, 656, 152, 656, 615, + 629, 615, 519, 522, 548, 608, 507, 520, 519, 522, + 431, 373, 93, 431, 554, 373, 431, 431, 431, 373, + 980, 528, 517, 528, 709, 709, 709, 873, 282, 282, + 519, 518, 669, 3, 406, 407, 548, 684, 638, 675, + 585, 545, 581, 518, 40, 639, 662, 664, 929, 355, + 419, 548, 577, 578, 583, 685, 643, 545, 545, 995, + 545, 519, 522, 288, 619, 288, 290, 618, 913, 480, + 994, 545, 619, 40, 545, 519, 660, 666, 663, 666, + 419, 822, 152, 545, 599, 920, 672, 683, 954, 678, + 548, 548, 280, 643, 511, 643, 548, 511, 643, 548, + 519, 519, 882, 172, 132, 285, 518, 778, 775, 518, + 519, 519, 519, 546, 720, 779, 704, 704, 704, 704, + 545, 545, 545, 59, 186, 742, 772, 911, 518, 760, + 761, 762, 825, 827, 911, 167, 80, 782, 781, 519, + 519, 516, 786, 519, 522, 519, 916, 517, 916, 519, + 809, 811, 812, 813, 812, 813, 813, 519, 427, 822, + 143, 822, 856, 866, 807, 807, 519, 519, 822, 905, + 906, 907, 40, 199, 522, 519, 908, 821, 822, 36, + 36, 822, 519, 822, 172, 518, 874, 822, 519, 145, + 823, 823, 145, 145, 822, 822, 517, 528, 518, 895, + 711, 477, 822, 301, 843, 522, 733, 709, 733, 519, + 927, 822, 361, 566, 546, 266, 321, 117, 304, 518, + 556, 686, 519, 522, 562, 974, 822, 164, 231, 518, + 715, 291, 545, 519, 912, 181, 687, 688, 901, 912, + 913, 913, 519, 152, 644, 631, 644, 605, 633, 522, + 519, 119, 207, 273, 275, 630, 518, 33, 59, 651, + 640, 74, 80, 93, 117, 119, 207, 275, 280, 329, + 347, 448, 457, 610, 611, 625, 176, 117, 191, 275, + 619, 593, 107, 117, 176, 275, 405, 408, 595, 619, + 389, 536, 442, 913, 546, 540, 3, 37, 42, 49, + 55, 81, 83, 89, 101, 171, 173, 176, 177, 194, + 209, 222, 223, 225, 235, 237, 247, 269, 274, 278, + 292, 300, 302, 322, 364, 383, 390, 394, 412, 421, + 441, 447, 468, 509, 510, 548, 594, 606, 645, 786, + 864, 917, 996, 1002, 552, 642, 913, 913, 913, 913, + 913, 913, 913, 913, 913, 913, 676, 893, 893, 519, + 519, 519, 710, 107, 373, 520, 593, 684, 518, 518, + 637, 686, 936, 650, 192, 545, 519, 522, 585, 519, + 519, 581, 518, 40, 628, 626, 634, 86, 590, 107, + 273, 639, 686, 662, 664, 40, 40, 687, 688, 633, + 457, 933, 656, 519, 522, 643, 823, 172, 518, 874, + 780, 519, 522, 519, 733, 545, 545, 545, 545, 30, + 103, 182, 367, 518, 734, 735, 736, 737, 738, 739, + 740, 822, 822, 479, 840, 519, 824, 867, 868, 199, + 181, 757, 761, 519, 763, 764, 765, 920, 788, 916, + 788, 546, 788, 517, 517, 822, 522, 519, 546, 822, + 824, 891, 822, 822, 822, 874, 519, 822, 36, 36, + 822, 822, 145, 519, 510, 893, 519, 872, 519, 822, + 519, 518, 546, 844, 742, 519, 742, 548, 519, 900, + 463, 418, 456, 567, 546, 561, 571, 290, 564, 507, + 575, 566, 866, 59, 519, 519, 462, 463, 692, 605, + 631, 519, 519, 480, 636, 120, 195, 205, 119, 459, + 822, 117, 40, 518, 920, 913, 823, 120, 195, 119, + 280, 227, 545, 636, 88, 651, 192, 280, 594, 822, + 651, 280, 509, 510, 597, 546, 786, 656, 656, 3, + 247, 412, 917, 921, 507, 431, 431, 517, 517, 709, + 519, 519, 546, 676, 457, 671, 673, 685, 643, 519, + 994, 40, 419, 275, 518, 548, 518, 936, 637, 151, + 686, 149, 201, 618, 122, 137, 328, 994, 107, 936, + 480, 992, 419, 290, 546, 932, 518, 683, 823, 874, + 519, 519, 9, 354, 726, 742, 518, 391, 518, 519, + 522, 546, 841, 842, 336, 743, 522, 519, 518, 547, + 59, 519, 199, 519, 764, 517, 786, 905, 517, 192, + 519, 822, 822, 822, 528, 517, 528, 519, 519, 546, + 845, 840, 548, 840, 522, 462, 894, 519, 522, 91, + 566, 822, 519, 912, 912, 347, 636, 518, 627, 605, + 519, 191, 518, 822, 275, 611, 636, 639, 913, 40, + 152, 782, 921, 513, 606, 913, 913, 519, 593, 124, + 519, 519, 626, 686, 545, 152, 685, 40, 519, 913, + 994, 30, 85, 94, 118, 191, 204, 405, 408, 622, + 622, 369, 369, 40, 64, 74, 241, 687, 545, 518, + 546, 565, 574, 833, 519, 519, 518, 840, 870, 518, + 870, 736, 40, 522, 822, 457, 721, 824, 901, 911, + 768, 518, 768, 822, 893, 893, 310, 846, 743, 743, + 686, 304, 686, 561, 290, 518, 559, 545, 605, 552, + 632, 635, 409, 472, 612, 613, 518, 607, 822, 519, + 249, 648, 191, 457, 539, 513, 442, 676, 548, 936, + 618, 992, 518, 545, 519, 686, 626, 590, 686, 74, + 293, 74, 933, 822, 80, 569, 519, 522, 569, 9, + 743, 519, 735, 519, 844, 842, 371, 519, 901, 517, + 517, 517, 59, 710, 721, 721, 567, 93, 574, 133, + 639, 507, 519, 522, 592, 519, 273, 620, 173, 309, + 395, 290, 616, 617, 641, 607, 822, 442, 40, 518, + 992, 618, 994, 992, 293, 293, 518, 519, 920, 570, + 920, 936, 565, 570, 519, 721, 519, 723, 519, 869, + 184, 340, 369, 847, 462, 913, 519, 276, 454, 648, + 606, 635, 519, 613, 205, 122, 454, 290, 641, 290, + 616, 686, 574, 569, 714, 779, 714, 53, 104, 444, + 822, 848, 849, 848, 848, 519, 686, 779, 389, 617, + 63, 273, 360, 389, 609, 609, 992, 519, 570, 715, + 715, 849, 368, 166, 324, 166, 324, 148, 850, 850, + 850, 573, 605, 25, 117, 280, 936, 714, 36, 104, + 181, 273, 428, 779, 779, 715, 849, 368, 298 }; #define yyerrok (yyerrstatus = 0) @@ -20541,14 +20189,14 @@ YYLTYPE yylloc; switch (yyn) { case 2: -#line 510 "third_party/libpg_query/grammar/grammar.y" +#line 509 "third_party/libpg_query/grammar/grammar.y" { pg_yyget_extra(yyscanner)->parsetree = (yyvsp[(1) - (1)].list); ;} break; case 3: -#line 526 "third_party/libpg_query/grammar/grammar.y" +#line 525 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (3)].list) != NIL) { @@ -20563,7 +20211,7 @@ YYLTYPE yylloc; break; case 4: -#line 538 "third_party/libpg_query/grammar/grammar.y" +#line 537 "third_party/libpg_query/grammar/grammar.y" { if ((yyvsp[(1) - (1)].node) != NULL) (yyval.list) = list_make1(makeRawStmt((yyvsp[(1) - (1)].node), 0)); @@ -20573,7 +20221,7 @@ YYLTYPE yylloc; break; case 46: -#line 588 "third_party/libpg_query/grammar/grammar.y" +#line 587 "third_party/libpg_query/grammar/grammar.y" { (yyval.node) = NULL; ;} break; @@ -25169,357 +24817,357 @@ YYLTYPE yylloc; break; case 634: -#line 689 "third_party/libpg_query/grammar/statements/select.y" +#line 692 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); - ;} + (yyval.node) = makeSampleSize(makeFloat((yyvsp[(1) - (2)].str)), true); + ;} break; case 635: -#line 693 "third_party/libpg_query/grammar/statements/select.y" +#line 696 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), true); + ;} + break; + + case 636: +#line 700 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); - ;} + (yyval.node) = makeSampleSize(makeFloat((yyvsp[(1) - (2)].str)), true); + ;} break; case 637: #line 704 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); + (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), true); ;} break; case 638: #line 708 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), true); + (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (1)].ival)), false); ;} break; case 639: #line 712 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeSampleSize((yyvsp[(1) - (1)].node), false); + (yyval.node) = makeSampleSize(makeInteger((yyvsp[(1) - (2)].ival)), false); ;} break; case 640: -#line 716 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.node) = makeSampleSize((yyvsp[(1) - (2)].node), false); - ;} - break; - - case 641: -#line 723 "third_party/libpg_query/grammar/statements/select.y" +#line 719 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (3)].node); ;} break; - case 642: -#line 727 "third_party/libpg_query/grammar/statements/select.y" + case 641: +#line 723 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 643: -#line 734 "third_party/libpg_query/grammar/statements/select.y" + case 642: +#line 730 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 644: -#line 735 "third_party/libpg_query/grammar/statements/select.y" + case 643: +#line 731 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = NULL; ;} break; - case 645: -#line 740 "third_party/libpg_query/grammar/statements/select.y" + case 644: +#line 736 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (5)].ival); (yyval.node) = makeSampleOptions((yyvsp[(3) - (5)].node), (yyvsp[(1) - (5)].str), &seed, (yylsp[(1) - (5)])); ;} break; - case 646: -#line 745 "third_party/libpg_query/grammar/statements/select.y" + case 645: +#line 741 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleOptions((yyvsp[(1) - (1)].node), NULL, NULL, (yylsp[(1) - (1)])); ;} break; - case 647: -#line 749 "third_party/libpg_query/grammar/statements/select.y" + case 646: +#line 745 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeSampleOptions((yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].str), NULL, (yylsp[(1) - (4)])); ;} break; - case 648: -#line 753 "third_party/libpg_query/grammar/statements/select.y" + case 647: +#line 749 "third_party/libpg_query/grammar/statements/select.y" { int seed = (yyvsp[(5) - (6)].ival); (yyval.node) = makeSampleOptions((yyvsp[(1) - (6)].node), (yyvsp[(3) - (6)].str), &seed, (yylsp[(1) - (6)])); ;} break; - case 649: -#line 761 "third_party/libpg_query/grammar/statements/select.y" + case 648: +#line 757 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 650: -#line 767 "third_party/libpg_query/grammar/statements/select.y" + case 649: +#line 763 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 651: -#line 768 "third_party/libpg_query/grammar/statements/select.y" + case 650: +#line 764 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 652: -#line 773 "third_party/libpg_query/grammar/statements/select.y" + case 651: +#line 769 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = (yyvsp[(3) - (4)].ival); ;} break; - case 653: -#line 774 "third_party/libpg_query/grammar/statements/select.y" + case 652: +#line 770 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = -1; ;} break; - case 654: -#line 778 "third_party/libpg_query/grammar/statements/select.y" + case 653: +#line 774 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 655: -#line 780 "third_party/libpg_query/grammar/statements/select.y" + case 654: +#line 776 "third_party/libpg_query/grammar/statements/select.y" { /* LIMIT ALL is represented as a NULL constant */ (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 656: -#line 785 "third_party/libpg_query/grammar/statements/select.y" + case 655: +#line 781 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeLimitPercent((yyvsp[(1) - (2)].node)); ;} break; + case 656: +#line 783 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeLimitPercent(makeFloatConst((yyvsp[(1) - (2)].str),(yylsp[(1) - (2)]))); ;} + break; + case 657: -#line 787 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeLimitPercent(makeFloatConst((yyvsp[(1) - (2)].str),(yylsp[(1) - (2)]))); ;} +#line 785 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeLimitPercent(makeIntConst((yyvsp[(1) - (2)].ival),(yylsp[(1) - (2)]))); ;} break; case 658: #line 789 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeLimitPercent(makeIntConst((yyvsp[(1) - (2)].ival),(yylsp[(1) - (2)]))); ;} + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 659: -#line 793 "third_party/libpg_query/grammar/statements/select.y" +#line 809 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 660: -#line 813 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} +#line 811 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 661: -#line 815 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} +#line 813 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; case 662: #line 817 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} + { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival),(yylsp[(1) - (1)])); ;} break; case 663: -#line 821 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival),(yylsp[(1) - (1)])); ;} +#line 818 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str),(yylsp[(1) - (1)])); ;} break; case 664: #line 822 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str),(yylsp[(1) - (1)])); ;} + { (yyval.ival) = 0; ;} break; case 665: -#line 826 "third_party/libpg_query/grammar/statements/select.y" +#line 823 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 666: -#line 827 "third_party/libpg_query/grammar/statements/select.y" +#line 826 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 667: -#line 830 "third_party/libpg_query/grammar/statements/select.y" +#line 827 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; case 668: -#line 831 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.ival) = 0; ;} - break; - - case 669: -#line 856 "third_party/libpg_query/grammar/statements/select.y" +#line 852 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 670: -#line 858 "third_party/libpg_query/grammar/statements/select.y" + case 669: +#line 854 "third_party/libpg_query/grammar/statements/select.y" { PGNode *node = (PGNode *) makeGroupingSet(GROUPING_SET_ALL, NIL, (yylsp[(3) - (3)])); (yyval.list) = list_make1(node); ;} break; + case 670: +#line 858 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = NIL; ;} + break; + case 671: #line 862 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} + { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; case 672: -#line 866 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} +#line 863 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = lappend((yyvsp[(1) - (3)].list),(yyvsp[(3) - (3)].node)); ;} break; case 673: #line 867 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (3)].list),(yyvsp[(3) - (3)].node)); ;} + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 674: -#line 871 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} +#line 868 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; case 675: #line 872 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (2)].list); ;} + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 676: -#line 876 "third_party/libpg_query/grammar/statements/select.y" +#line 873 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 677: -#line 877 "third_party/libpg_query/grammar/statements/select.y" +#line 874 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 678: -#line 878 "third_party/libpg_query/grammar/statements/select.y" +#line 875 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 679: -#line 879 "third_party/libpg_query/grammar/statements/select.y" +#line 876 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; case 680: -#line 880 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(1) - (1)].node); ;} - break; - - case 681: -#line 885 "third_party/libpg_query/grammar/statements/select.y" +#line 881 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_EMPTY, NIL, (yylsp[(1) - (2)])); ;} break; - case 682: -#line 898 "third_party/libpg_query/grammar/statements/select.y" + case 681: +#line 894 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_ROLLUP, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 683: -#line 905 "third_party/libpg_query/grammar/statements/select.y" + case 682: +#line 901 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_CUBE, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 684: -#line 912 "third_party/libpg_query/grammar/statements/select.y" + case 683: +#line 908 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeGroupingSet(GROUPING_SET_SETS, (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; + case 684: +#line 914 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = NULL; ;} + break; + case 685: -#line 918 "third_party/libpg_query/grammar/statements/select.y" +#line 915 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; case 686: #line 919 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} + { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 687: -#line 923 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(2) - (2)].node); ;} +#line 920 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = NULL; ;} break; case 688: #line 924 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} + { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; case 689: -#line 928 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = (yyvsp[(2) - (2)].node); ;} +#line 925 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = NULL; ;} break; case 690: #line 929 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.node) = NULL; ;} + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 691: -#line 933 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} +#line 930 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = NIL; ;} break; case 692: #line 934 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} + { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; case 693: -#line 938 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} +#line 935 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = NIL; ;} break; case 694: #line 939 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NIL; ;} - break; - - case 695: -#line 943 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 696: -#line 944 "third_party/libpg_query/grammar/statements/select.y" + case 695: +#line 940 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 697: -#line 949 "third_party/libpg_query/grammar/statements/select.y" + case 696: +#line 945 "third_party/libpg_query/grammar/statements/select.y" { PGLockingClause *n = makeNode(PGLockingClause); n->lockedRels = (yyvsp[(2) - (3)].list); @@ -25529,53 +25177,53 @@ YYLTYPE yylloc; ;} break; - case 698: -#line 959 "third_party/libpg_query/grammar/statements/select.y" + case 697: +#line 955 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = LCS_FORUPDATE; ;} break; - case 699: -#line 960 "third_party/libpg_query/grammar/statements/select.y" + case 698: +#line 956 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORNOKEYUPDATE; ;} break; - case 700: -#line 961 "third_party/libpg_query/grammar/statements/select.y" + case 699: +#line 957 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORSHARE; ;} break; - case 701: -#line 962 "third_party/libpg_query/grammar/statements/select.y" + case 700: +#line 958 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockstrength) = PG_LCS_FORKEYSHARE; ;} break; - case 702: -#line 966 "third_party/libpg_query/grammar/statements/select.y" + case 701: +#line 962 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 703: -#line 967 "third_party/libpg_query/grammar/statements/select.y" + case 702: +#line 963 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 704: -#line 972 "third_party/libpg_query/grammar/statements/select.y" + case 703: +#line 968 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = LockWaitError; ;} break; - case 705: -#line 973 "third_party/libpg_query/grammar/statements/select.y" + case 704: +#line 969 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitSkip; ;} break; - case 706: -#line 974 "third_party/libpg_query/grammar/statements/select.y" + case 705: +#line 970 "third_party/libpg_query/grammar/statements/select.y" { (yyval.lockwaitpolicy) = PGLockWaitBlock; ;} break; - case 707: -#line 984 "third_party/libpg_query/grammar/statements/select.y" + case 706: +#line 980 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = makeNode(PGSelectStmt); n->valuesLists = list_make1((yyvsp[(3) - (4)].list)); @@ -25583,8 +25231,8 @@ YYLTYPE yylloc; ;} break; - case 708: -#line 990 "third_party/libpg_query/grammar/statements/select.y" + case 707: +#line 986 "third_party/libpg_query/grammar/statements/select.y" { PGSelectStmt *n = (PGSelectStmt *) (yyvsp[(1) - (5)].node); n->valuesLists = lappend(n->valuesLists, (yyvsp[(4) - (5)].list)); @@ -25592,56 +25240,48 @@ YYLTYPE yylloc; ;} break; - case 709: -#line 998 "third_party/libpg_query/grammar/statements/select.y" + case 708: +#line 994 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 710: -#line 999 "third_party/libpg_query/grammar/statements/select.y" + case 709: +#line 995 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (2)].node); ;} break; - case 711: -#line 1012 "third_party/libpg_query/grammar/statements/select.y" + case 710: +#line 1008 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 712: -#line 1013 "third_party/libpg_query/grammar/statements/select.y" + case 711: +#line 1009 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 713: -#line 1017 "third_party/libpg_query/grammar/statements/select.y" + case 712: +#line 1013 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 714: -#line 1018 "third_party/libpg_query/grammar/statements/select.y" + case 713: +#line 1014 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 715: -#line 1022 "third_party/libpg_query/grammar/statements/select.y" + case 714: +#line 1018 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 716: -#line 1023 "third_party/libpg_query/grammar/statements/select.y" + case 715: +#line 1019 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 717: -#line 1028 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.alias) = makeNode(PGAlias); - (yyval.alias)->aliasname = (yyvsp[(1) - (2)].str); - ;} - break; - - case 718: -#line 1039 "third_party/libpg_query/grammar/statements/select.y" + case 716: +#line 1026 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(1) - (3)].range)->alias = (yyvsp[(2) - (3)].alias); (yyvsp[(1) - (3)].range)->sample = (yyvsp[(3) - (3)].node); @@ -25649,17 +25289,8 @@ YYLTYPE yylloc; ;} break; - case 719: -#line 1045 "third_party/libpg_query/grammar/statements/select.y" - { - (yyvsp[(2) - (3)].range)->alias = (yyvsp[(1) - (3)].alias); - (yyvsp[(2) - (3)].range)->sample = (yyvsp[(3) - (3)].node); - (yyval.node) = (PGNode *) (yyvsp[(2) - (3)].range); - ;} - break; - - case 720: -#line 1051 "third_party/libpg_query/grammar/statements/select.y" + case 717: +#line 1032 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(1) - (3)].node); n->alias = (PGAlias*) linitial((yyvsp[(2) - (3)].list)); @@ -25669,30 +25300,20 @@ YYLTYPE yylloc; ;} break; - case 721: -#line 1059 "third_party/libpg_query/grammar/statements/select.y" + case 718: +#line 1040 "third_party/libpg_query/grammar/statements/select.y" { - PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); - n->alias = (yyvsp[(1) - (3)].alias); - n->sample = (yyvsp[(3) - (3)].node); - (yyval.node) = (PGNode *) n; - ;} - break; - - case 722: -#line 1067 "third_party/libpg_query/grammar/statements/select.y" - { - PGRangeSubselect *n = makeNode(PGRangeSubselect); - n->lateral = false; - n->subquery = (yyvsp[(1) - (3)].node); - n->alias = (yyvsp[(2) - (3)].alias); - n->sample = (yyvsp[(3) - (3)].node); - (yyval.node) = (PGNode *) n; - ;} + PGRangeSubselect *n = makeNode(PGRangeSubselect); + n->lateral = false; + n->subquery = (yyvsp[(1) - (3)].node); + n->alias = (yyvsp[(2) - (3)].alias); + n->sample = (yyvsp[(3) - (3)].node); + (yyval.node) = (PGNode *) n; + ;} break; - case 723: -#line 1077 "third_party/libpg_query/grammar/statements/select.y" + case 719: +#line 1049 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = (PGRangeFunction *) (yyvsp[(2) - (3)].node); n->lateral = true; @@ -25702,8 +25323,8 @@ YYLTYPE yylloc; ;} break; - case 724: -#line 1085 "third_party/libpg_query/grammar/statements/select.y" + case 720: +#line 1057 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); n->lateral = false; @@ -25714,20 +25335,8 @@ YYLTYPE yylloc; ;} break; - case 725: -#line 1094 "third_party/libpg_query/grammar/statements/select.y" - { - PGRangeSubselect *n = makeNode(PGRangeSubselect); - n->lateral = false; - n->subquery = (yyvsp[(2) - (3)].node); - n->alias = (yyvsp[(1) - (3)].alias); - n->sample = (yyvsp[(3) - (3)].node); - (yyval.node) = (PGNode *) n; - ;} - break; - - case 726: -#line 1103 "third_party/libpg_query/grammar/statements/select.y" + case 721: +#line 1066 "third_party/libpg_query/grammar/statements/select.y" { PGRangeSubselect *n = makeNode(PGRangeSubselect); n->lateral = true; @@ -25738,31 +25347,23 @@ YYLTYPE yylloc; ;} break; - case 727: -#line 1112 "third_party/libpg_query/grammar/statements/select.y" + case 722: +#line 1075 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].jexpr); ;} break; - case 728: -#line 1116 "third_party/libpg_query/grammar/statements/select.y" + case 723: +#line 1079 "third_party/libpg_query/grammar/statements/select.y" { (yyvsp[(2) - (4)].jexpr)->alias = (yyvsp[(4) - (4)].alias); (yyval.node) = (PGNode *) (yyvsp[(2) - (4)].jexpr); ;} break; - case 729: -#line 1121 "third_party/libpg_query/grammar/statements/select.y" - { - (yyvsp[(3) - (4)].jexpr)->alias = (yyvsp[(1) - (4)].alias); - (yyval.node) = (PGNode *) (yyvsp[(3) - (4)].jexpr); - ;} - break; - - case 730: -#line 1126 "third_party/libpg_query/grammar/statements/select.y" + case 724: +#line 1084 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); n->source = (yyvsp[(1) - (9)].node); @@ -25775,8 +25376,8 @@ YYLTYPE yylloc; ;} break; - case 731: -#line 1137 "third_party/libpg_query/grammar/statements/select.y" + case 725: +#line 1095 "third_party/libpg_query/grammar/statements/select.y" { PGPivotExpr *n = makeNode(PGPivotExpr); n->source = (yyvsp[(1) - (9)].node); @@ -25789,33 +25390,33 @@ YYLTYPE yylloc; ;} break; - case 732: -#line 1150 "third_party/libpg_query/grammar/statements/select.y" + case 726: +#line 1108 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 733: -#line 1151 "third_party/libpg_query/grammar/statements/select.y" + case 727: +#line 1109 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 734: -#line 1154 "third_party/libpg_query/grammar/statements/select.y" + case 728: +#line 1112 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 735: -#line 1155 "third_party/libpg_query/grammar/statements/select.y" + case 729: +#line 1113 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 736: -#line 1156 "third_party/libpg_query/grammar/statements/select.y" + case 730: +#line 1114 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 737: -#line 1160 "third_party/libpg_query/grammar/statements/select.y" + case 731: +#line 1118 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = list_make1((yyvsp[(1) - (5)].node)); @@ -25824,8 +25425,8 @@ YYLTYPE yylloc; ;} break; - case 738: -#line 1168 "third_party/libpg_query/grammar/statements/select.y" + case 732: +#line 1126 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = list_make1((yyvsp[(1) - (3)].node)); @@ -25834,23 +25435,23 @@ YYLTYPE yylloc; ;} break; - case 739: -#line 1177 "third_party/libpg_query/grammar/statements/select.y" + case 733: +#line 1135 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 740: -#line 1178 "third_party/libpg_query/grammar/statements/select.y" + case 734: +#line 1136 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 741: -#line 1179 "third_party/libpg_query/grammar/statements/select.y" + case 735: +#line 1137 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 742: -#line 1183 "third_party/libpg_query/grammar/statements/select.y" + case 736: +#line 1141 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = (yyvsp[(1) - (5)].list); @@ -25859,8 +25460,8 @@ YYLTYPE yylloc; ;} break; - case 743: -#line 1191 "third_party/libpg_query/grammar/statements/select.y" + case 737: +#line 1149 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->pivot_columns = (yyvsp[(1) - (3)].list); @@ -25869,32 +25470,32 @@ YYLTYPE yylloc; ;} break; - case 744: -#line 1200 "third_party/libpg_query/grammar/statements/select.y" + case 738: +#line 1158 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 745: -#line 1204 "third_party/libpg_query/grammar/statements/select.y" + case 739: +#line 1162 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 746: -#line 1210 "third_party/libpg_query/grammar/statements/select.y" + case 740: +#line 1168 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 747: -#line 1211 "third_party/libpg_query/grammar/statements/select.y" + case 741: +#line 1169 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 748: -#line 1216 "third_party/libpg_query/grammar/statements/select.y" + case 742: +#line 1174 "third_party/libpg_query/grammar/statements/select.y" { PGPivot *n = makeNode(PGPivot); n->unpivot_columns = (yyvsp[(1) - (5)].list); @@ -25903,29 +25504,29 @@ YYLTYPE yylloc; ;} break; - case 749: -#line 1225 "third_party/libpg_query/grammar/statements/select.y" + case 743: +#line 1183 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 750: -#line 1229 "third_party/libpg_query/grammar/statements/select.y" + case 744: +#line 1187 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 751: -#line 1254 "third_party/libpg_query/grammar/statements/select.y" + case 745: +#line 1212 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jexpr) = (yyvsp[(2) - (3)].jexpr); ;} break; - case 752: -#line 1258 "third_party/libpg_query/grammar/statements/select.y" + case 746: +#line 1216 "third_party/libpg_query/grammar/statements/select.y" { /* CROSS JOIN is same as unqualified inner join */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25940,8 +25541,8 @@ YYLTYPE yylloc; ;} break; - case 753: -#line 1271 "third_party/libpg_query/grammar/statements/select.y" + case 747: +#line 1229 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(2) - (5)].jtype); @@ -25957,8 +25558,8 @@ YYLTYPE yylloc; ;} break; - case 754: -#line 1285 "third_party/libpg_query/grammar/statements/select.y" + case 748: +#line 1243 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -25975,8 +25576,8 @@ YYLTYPE yylloc; ;} break; - case 755: -#line 1300 "third_party/libpg_query/grammar/statements/select.y" + case 749: +#line 1258 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(3) - (5)].jtype); @@ -25990,8 +25591,8 @@ YYLTYPE yylloc; ;} break; - case 756: -#line 1312 "third_party/libpg_query/grammar/statements/select.y" + case 750: +#line 1270 "third_party/libpg_query/grammar/statements/select.y" { /* letting join_type reduce to empty doesn't work */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -26006,8 +25607,8 @@ YYLTYPE yylloc; ;} break; - case 757: -#line 1325 "third_party/libpg_query/grammar/statements/select.y" + case 751: +#line 1283 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = (yyvsp[(3) - (6)].jtype); @@ -26023,8 +25624,8 @@ YYLTYPE yylloc; ;} break; - case 758: -#line 1339 "third_party/libpg_query/grammar/statements/select.y" + case 752: +#line 1297 "third_party/libpg_query/grammar/statements/select.y" { PGJoinExpr *n = makeNode(PGJoinExpr); n->jointype = PG_JOIN_INNER; @@ -26040,8 +25641,8 @@ YYLTYPE yylloc; ;} break; - case 759: -#line 1353 "third_party/libpg_query/grammar/statements/select.y" + case 753: +#line 1311 "third_party/libpg_query/grammar/statements/select.y" { /* POSITIONAL JOIN is a coordinated scan */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -26056,8 +25657,8 @@ YYLTYPE yylloc; ;} break; - case 760: -#line 1366 "third_party/libpg_query/grammar/statements/select.y" + case 754: +#line 1324 "third_party/libpg_query/grammar/statements/select.y" { /* ANTI JOIN is a filter */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -26074,8 +25675,8 @@ YYLTYPE yylloc; ;} break; - case 761: -#line 1381 "third_party/libpg_query/grammar/statements/select.y" + case 755: +#line 1339 "third_party/libpg_query/grammar/statements/select.y" { /* SEMI JOIN is also a filter */ PGJoinExpr *n = makeNode(PGJoinExpr); @@ -26093,8 +25694,8 @@ YYLTYPE yylloc; ;} break; - case 762: -#line 1400 "third_party/libpg_query/grammar/statements/select.y" + case 756: +#line 1358 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(2) - (5)].str); @@ -26102,16 +25703,16 @@ YYLTYPE yylloc; ;} break; - case 763: -#line 1406 "third_party/libpg_query/grammar/statements/select.y" + case 757: +#line 1364 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(2) - (2)].str); ;} break; - case 764: -#line 1411 "third_party/libpg_query/grammar/statements/select.y" + case 758: +#line 1369 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(1) - (4)].str); @@ -26119,40 +25720,40 @@ YYLTYPE yylloc; ;} break; - case 765: -#line 1417 "third_party/libpg_query/grammar/statements/select.y" + case 759: +#line 1375 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = makeNode(PGAlias); (yyval.alias)->aliasname = (yyvsp[(1) - (1)].str); ;} break; - case 766: -#line 1423 "third_party/libpg_query/grammar/statements/select.y" + case 760: +#line 1381 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = (yyvsp[(1) - (1)].alias); ;} break; - case 767: -#line 1424 "third_party/libpg_query/grammar/statements/select.y" + case 761: +#line 1382 "third_party/libpg_query/grammar/statements/select.y" { (yyval.alias) = NULL; ;} break; - case 768: -#line 1433 "third_party/libpg_query/grammar/statements/select.y" + case 762: +#line 1391 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (1)].alias), NIL); ;} break; - case 769: -#line 1437 "third_party/libpg_query/grammar/statements/select.y" + case 763: +#line 1395 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, (yyvsp[(3) - (4)].list)); ;} break; - case 770: -#line 1441 "third_party/libpg_query/grammar/statements/select.y" + case 764: +#line 1399 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); a->aliasname = (yyvsp[(2) - (5)].str); @@ -26160,8 +25761,8 @@ YYLTYPE yylloc; ;} break; - case 771: -#line 1447 "third_party/libpg_query/grammar/statements/select.y" + case 765: +#line 1405 "third_party/libpg_query/grammar/statements/select.y" { PGAlias *a = makeNode(PGAlias); a->aliasname = (yyvsp[(1) - (4)].str); @@ -26169,65 +25770,65 @@ YYLTYPE yylloc; ;} break; - case 772: -#line 1453 "third_party/libpg_query/grammar/statements/select.y" + case 766: +#line 1411 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(NULL, NIL); ;} break; - case 773: -#line 1458 "third_party/libpg_query/grammar/statements/select.y" + case 767: +#line 1416 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_FULL; ;} break; - case 774: -#line 1459 "third_party/libpg_query/grammar/statements/select.y" + case 768: +#line 1417 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_LEFT; ;} break; - case 775: -#line 1460 "third_party/libpg_query/grammar/statements/select.y" + case 769: +#line 1418 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_RIGHT; ;} break; - case 776: -#line 1461 "third_party/libpg_query/grammar/statements/select.y" + case 770: +#line 1419 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_SEMI; ;} break; - case 777: -#line 1462 "third_party/libpg_query/grammar/statements/select.y" + case 771: +#line 1420 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_ANTI; ;} break; - case 778: -#line 1463 "third_party/libpg_query/grammar/statements/select.y" + case 772: +#line 1421 "third_party/libpg_query/grammar/statements/select.y" { (yyval.jtype) = PG_JOIN_INNER; ;} break; - case 779: -#line 1467 "third_party/libpg_query/grammar/statements/select.y" + case 773: +#line 1425 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 780: -#line 1468 "third_party/libpg_query/grammar/statements/select.y" + case 774: +#line 1426 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 781: -#line 1480 "third_party/libpg_query/grammar/statements/select.y" + case 775: +#line 1438 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) (yyvsp[(3) - (4)].list); ;} break; - case 782: -#line 1481 "third_party/libpg_query/grammar/statements/select.y" + case 776: +#line 1439 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 783: -#line 1487 "third_party/libpg_query/grammar/statements/select.y" + case 777: +#line 1445 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, implicitly */ (yyval.range) = (yyvsp[(1) - (1)].range); @@ -26236,8 +25837,8 @@ YYLTYPE yylloc; ;} break; - case 784: -#line 1494 "third_party/libpg_query/grammar/statements/select.y" + case 778: +#line 1452 "third_party/libpg_query/grammar/statements/select.y" { /* inheritance query, explicitly */ (yyval.range) = (yyvsp[(1) - (2)].range); @@ -26246,8 +25847,8 @@ YYLTYPE yylloc; ;} break; - case 785: -#line 1501 "third_party/libpg_query/grammar/statements/select.y" + case 779: +#line 1459 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance */ (yyval.range) = (yyvsp[(2) - (2)].range); @@ -26256,8 +25857,8 @@ YYLTYPE yylloc; ;} break; - case 786: -#line 1508 "third_party/libpg_query/grammar/statements/select.y" + case 780: +#line 1466 "third_party/libpg_query/grammar/statements/select.y" { /* no inheritance, SQL99-style syntax */ (yyval.range) = (yyvsp[(3) - (4)].range); @@ -26266,8 +25867,8 @@ YYLTYPE yylloc; ;} break; - case 787: -#line 1540 "third_party/libpg_query/grammar/statements/select.y" + case 781: +#line 1498 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); n->lateral = false; @@ -26280,8 +25881,8 @@ YYLTYPE yylloc; ;} break; - case 788: -#line 1551 "third_party/libpg_query/grammar/statements/select.y" + case 782: +#line 1509 "third_party/libpg_query/grammar/statements/select.y" { PGRangeFunction *n = makeNode(PGRangeFunction); n->lateral = false; @@ -26294,67 +25895,67 @@ YYLTYPE yylloc; ;} break; - case 789: -#line 1564 "third_party/libpg_query/grammar/statements/select.y" + case 783: +#line 1522 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].list)); ;} break; - case 790: -#line 1568 "third_party/libpg_query/grammar/statements/select.y" + case 784: +#line 1526 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 791: -#line 1569 "third_party/libpg_query/grammar/statements/select.y" + case 785: +#line 1527 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 792: -#line 1572 "third_party/libpg_query/grammar/statements/select.y" + case 786: +#line 1530 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 793: -#line 1573 "third_party/libpg_query/grammar/statements/select.y" + case 787: +#line 1531 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 794: -#line 1576 "third_party/libpg_query/grammar/statements/select.y" + case 788: +#line 1534 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 795: -#line 1577 "third_party/libpg_query/grammar/statements/select.y" + case 789: +#line 1535 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 796: -#line 1582 "third_party/libpg_query/grammar/statements/select.y" + case 790: +#line 1540 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 797: -#line 1583 "third_party/libpg_query/grammar/statements/select.y" + case 791: +#line 1541 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 798: -#line 1589 "third_party/libpg_query/grammar/statements/select.y" + case 792: +#line 1547 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 799: -#line 1593 "third_party/libpg_query/grammar/statements/select.y" + case 793: +#line 1551 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 800: -#line 1599 "third_party/libpg_query/grammar/statements/select.y" + case 794: +#line 1557 "third_party/libpg_query/grammar/statements/select.y" { PGColumnDef *n = makeNode(PGColumnDef); n->colname = (yyvsp[(1) - (3)].str); @@ -26374,8 +25975,8 @@ YYLTYPE yylloc; ;} break; - case 801: -#line 1620 "third_party/libpg_query/grammar/statements/select.y" + case 795: +#line 1578 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); n->arg = NULL; @@ -26385,45 +25986,45 @@ YYLTYPE yylloc; ;} break; - case 802: -#line 1627 "third_party/libpg_query/grammar/statements/select.y" + case 796: +#line 1585 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 803: -#line 1641 "third_party/libpg_query/grammar/statements/select.y" + case 797: +#line 1598 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(list_make2(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].typnam))); ;} break; - case 804: -#line 1644 "third_party/libpg_query/grammar/statements/select.y" + case 798: +#line 1601 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), list_make2(makeString((yyvsp[(3) - (4)].str)), (yyvsp[(4) - (4)].typnam))); ;} break; - case 807: -#line 1651 "third_party/libpg_query/grammar/statements/select.y" + case 801: +#line 1608 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 808: -#line 1652 "third_party/libpg_query/grammar/statements/select.y" + case 802: +#line 1609 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = NULL; ;} break; - case 809: -#line 1655 "third_party/libpg_query/grammar/statements/select.y" + case 803: +#line 1612 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(2) - (2)].list); ;} break; - case 810: -#line 1660 "third_party/libpg_query/grammar/statements/select.y" + case 804: +#line 1617 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = (yyvsp[(3) - (3)].list); @@ -26431,16 +26032,16 @@ YYLTYPE yylloc; ;} break; - case 811: -#line 1667 "third_party/libpg_query/grammar/statements/select.y" + case 805: +#line 1624 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (5)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(4) - (5)].ival))); ;} break; - case 812: -#line 1672 "third_party/libpg_query/grammar/statements/select.y" + case 806: +#line 1629 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (6)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger((yyvsp[(5) - (6)].ival))); @@ -26448,16 +26049,16 @@ YYLTYPE yylloc; ;} break; - case 813: -#line 1678 "third_party/libpg_query/grammar/statements/select.y" + case 807: +#line 1635 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); ;} break; - case 814: -#line 1683 "third_party/libpg_query/grammar/statements/select.y" + case 808: +#line 1640 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (3)].typnam); (yyval.typnam)->arrayBounds = list_make1(makeInteger(-1)); @@ -26465,15 +26066,15 @@ YYLTYPE yylloc; ;} break; - case 815: -#line 1689 "third_party/libpg_query/grammar/statements/select.y" + case 809: +#line 1646 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeNameFromNameList((yyvsp[(1) - (1)].list)); ;} break; - case 816: -#line 1693 "third_party/libpg_query/grammar/statements/select.y" + case 810: +#line 1650 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("struct"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26482,8 +26083,8 @@ YYLTYPE yylloc; ;} break; - case 817: -#line 1700 "third_party/libpg_query/grammar/statements/select.y" + case 811: +#line 1657 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("map"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26492,8 +26093,8 @@ YYLTYPE yylloc; ;} break; - case 818: -#line 1707 "third_party/libpg_query/grammar/statements/select.y" + case 812: +#line 1664 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("union"); (yyval.typnam)->arrayBounds = (yyvsp[(5) - (5)].list); @@ -26502,66 +26103,66 @@ YYLTYPE yylloc; ;} break; - case 819: -#line 1716 "third_party/libpg_query/grammar/statements/select.y" + case 813: +#line 1673 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(makeString((yyvsp[(1) - (3)].str)), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 820: -#line 1717 "third_party/libpg_query/grammar/statements/select.y" + case 814: +#line 1674 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 821: -#line 1722 "third_party/libpg_query/grammar/statements/select.y" + case 815: +#line 1679 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeInteger(-1)); ;} break; - case 822: -#line 1724 "third_party/libpg_query/grammar/statements/select.y" + case 816: +#line 1681 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (4)].list), makeInteger((yyvsp[(3) - (4)].ival))); ;} break; - case 823: -#line 1726 "third_party/libpg_query/grammar/statements/select.y" + case 817: +#line 1683 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 824: -#line 1730 "third_party/libpg_query/grammar/statements/select.y" + case 818: +#line 1687 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 825: -#line 1731 "third_party/libpg_query/grammar/statements/select.y" + case 819: +#line 1688 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 826: -#line 1732 "third_party/libpg_query/grammar/statements/select.y" + case 820: +#line 1689 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 827: -#line 1733 "third_party/libpg_query/grammar/statements/select.y" + case 821: +#line 1690 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 828: -#line 1734 "third_party/libpg_query/grammar/statements/select.y" + case 822: +#line 1691 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 829: -#line 1736 "third_party/libpg_query/grammar/statements/select.y" + case 823: +#line 1693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (2)].typnam); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); ;} break; - case 830: -#line 1741 "third_party/libpg_query/grammar/statements/select.y" + case 824: +#line 1698 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (4)].typnam); (yyval.typnam)->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), @@ -26569,28 +26170,28 @@ YYLTYPE yylloc; ;} break; - case 831: -#line 1760 "third_party/libpg_query/grammar/statements/select.y" + case 825: +#line 1717 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 832: -#line 1761 "third_party/libpg_query/grammar/statements/select.y" + case 826: +#line 1718 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 833: -#line 1762 "third_party/libpg_query/grammar/statements/select.y" + case 827: +#line 1719 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 834: -#line 1763 "third_party/libpg_query/grammar/statements/select.y" + case 828: +#line 1720 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 835: -#line 1775 "third_party/libpg_query/grammar/statements/select.y" + case 829: +#line 1732 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = makeTypeName((yyvsp[(1) - (2)].str)); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26598,74 +26199,74 @@ YYLTYPE yylloc; ;} break; - case 836: -#line 1788 "third_party/libpg_query/grammar/statements/select.y" + case 830: +#line 1745 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 837: -#line 1789 "third_party/libpg_query/grammar/statements/select.y" + case 831: +#line 1746 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 838: -#line 1796 "third_party/libpg_query/grammar/statements/select.y" + case 832: +#line 1753 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 839: -#line 1801 "third_party/libpg_query/grammar/statements/select.y" + case 833: +#line 1758 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 840: -#line 1806 "third_party/libpg_query/grammar/statements/select.y" + case 834: +#line 1763 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int2"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 841: -#line 1811 "third_party/libpg_query/grammar/statements/select.y" + case 835: +#line 1768 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("int8"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 842: -#line 1816 "third_party/libpg_query/grammar/statements/select.y" + case 836: +#line 1773 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 843: -#line 1821 "third_party/libpg_query/grammar/statements/select.y" + case 837: +#line 1778 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(2) - (2)].typnam); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 844: -#line 1826 "third_party/libpg_query/grammar/statements/select.y" + case 838: +#line 1783 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float8"); (yyval.typnam)->location = (yylsp[(1) - (2)]); ;} break; - case 845: -#line 1831 "third_party/libpg_query/grammar/statements/select.y" + case 839: +#line 1788 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26673,8 +26274,8 @@ YYLTYPE yylloc; ;} break; - case 846: -#line 1837 "third_party/libpg_query/grammar/statements/select.y" + case 840: +#line 1794 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26682,8 +26283,8 @@ YYLTYPE yylloc; ;} break; - case 847: -#line 1843 "third_party/libpg_query/grammar/statements/select.y" + case 841: +#line 1800 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("numeric"); (yyval.typnam)->typmods = (yyvsp[(2) - (2)].list); @@ -26691,16 +26292,16 @@ YYLTYPE yylloc; ;} break; - case 848: -#line 1849 "third_party/libpg_query/grammar/statements/select.y" + case 842: +#line 1806 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("bool"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 849: -#line 1856 "third_party/libpg_query/grammar/statements/select.y" + case 843: +#line 1813 "third_party/libpg_query/grammar/statements/select.y" { /* * Check FLOAT() precision limits assuming IEEE floating @@ -26723,44 +26324,44 @@ YYLTYPE yylloc; ;} break; - case 850: -#line 1877 "third_party/libpg_query/grammar/statements/select.y" + case 844: +#line 1834 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("float4"); ;} break; - case 851: -#line 1887 "third_party/libpg_query/grammar/statements/select.y" + case 845: +#line 1844 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 852: -#line 1891 "third_party/libpg_query/grammar/statements/select.y" + case 846: +#line 1848 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 853: -#line 1899 "third_party/libpg_query/grammar/statements/select.y" + case 847: +#line 1856 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 854: -#line 1903 "third_party/libpg_query/grammar/statements/select.y" + case 848: +#line 1860 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); (yyval.typnam)->typmods = NIL; ;} break; - case 855: -#line 1911 "third_party/libpg_query/grammar/statements/select.y" + case 849: +#line 1868 "third_party/libpg_query/grammar/statements/select.y" { const char *typname; @@ -26771,8 +26372,8 @@ YYLTYPE yylloc; ;} break; - case 856: -#line 1923 "third_party/libpg_query/grammar/statements/select.y" + case 850: +#line 1880 "third_party/libpg_query/grammar/statements/select.y" { /* bit defaults to bit(1), varbit to no limit */ if ((yyvsp[(2) - (2)].boolean)) @@ -26788,29 +26389,29 @@ YYLTYPE yylloc; ;} break; - case 857: -#line 1944 "third_party/libpg_query/grammar/statements/select.y" + case 851: +#line 1901 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 858: -#line 1948 "third_party/libpg_query/grammar/statements/select.y" + case 852: +#line 1905 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 859: -#line 1954 "third_party/libpg_query/grammar/statements/select.y" + case 853: +#line 1911 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = (yyvsp[(1) - (1)].typnam); ;} break; - case 860: -#line 1958 "third_party/libpg_query/grammar/statements/select.y" + case 854: +#line 1915 "third_party/libpg_query/grammar/statements/select.y" { /* Length was not specified so allow to be unrestricted. * This handles problems with fixed-length (bpchar) strings @@ -26823,8 +26424,8 @@ YYLTYPE yylloc; ;} break; - case 861: -#line 1971 "third_party/libpg_query/grammar/statements/select.y" + case 855: +#line 1928 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (4)].conststr)); (yyval.typnam)->typmods = list_make1(makeIntConst((yyvsp[(3) - (4)].ival), (yylsp[(3) - (4)]))); @@ -26832,8 +26433,8 @@ YYLTYPE yylloc; ;} break; - case 862: -#line 1979 "third_party/libpg_query/grammar/statements/select.y" + case 856: +#line 1936 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName((yyvsp[(1) - (1)].conststr)); /* char defaults to char(1), varchar to no limit */ @@ -26843,48 +26444,48 @@ YYLTYPE yylloc; ;} break; - case 863: -#line 1989 "third_party/libpg_query/grammar/statements/select.y" + case 857: +#line 1946 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 864: -#line 1991 "third_party/libpg_query/grammar/statements/select.y" + case 858: +#line 1948 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 865: -#line 1993 "third_party/libpg_query/grammar/statements/select.y" + case 859: +#line 1950 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "varchar"; ;} break; - case 866: -#line 1995 "third_party/libpg_query/grammar/statements/select.y" + case 860: +#line 1952 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 867: -#line 1997 "third_party/libpg_query/grammar/statements/select.y" + case 861: +#line 1954 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(3) - (3)].boolean) ? "varchar": "bpchar"; ;} break; - case 868: -#line 1999 "third_party/libpg_query/grammar/statements/select.y" + case 862: +#line 1956 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = (yyvsp[(2) - (2)].boolean) ? "varchar": "bpchar"; ;} break; - case 869: -#line 2003 "third_party/libpg_query/grammar/statements/select.y" + case 863: +#line 1960 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 870: -#line 2004 "third_party/libpg_query/grammar/statements/select.y" + case 864: +#line 1961 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 871: -#line 2012 "third_party/libpg_query/grammar/statements/select.y" + case 865: +#line 1969 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -26895,8 +26496,8 @@ YYLTYPE yylloc; ;} break; - case 872: -#line 2021 "third_party/libpg_query/grammar/statements/select.y" + case 866: +#line 1978 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timestamptz"); @@ -26906,8 +26507,8 @@ YYLTYPE yylloc; ;} break; - case 873: -#line 2029 "third_party/libpg_query/grammar/statements/select.y" + case 867: +#line 1986 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(5) - (5)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -26918,8 +26519,8 @@ YYLTYPE yylloc; ;} break; - case 874: -#line 2038 "third_party/libpg_query/grammar/statements/select.y" + case 868: +#line 1995 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].boolean)) (yyval.typnam) = SystemTypeName("timetz"); @@ -26929,112 +26530,112 @@ YYLTYPE yylloc; ;} break; - case 875: -#line 2049 "third_party/libpg_query/grammar/statements/select.y" + case 869: +#line 2006 "third_party/libpg_query/grammar/statements/select.y" { (yyval.typnam) = SystemTypeName("interval"); (yyval.typnam)->location = (yylsp[(1) - (1)]); ;} break; - case 876: -#line 2056 "third_party/libpg_query/grammar/statements/select.y" + case 870: +#line 2013 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 877: -#line 2057 "third_party/libpg_query/grammar/statements/select.y" + case 871: +#line 2014 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 878: -#line 2058 "third_party/libpg_query/grammar/statements/select.y" + case 872: +#line 2015 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 905: -#line 2102 "third_party/libpg_query/grammar/statements/select.y" + case 899: +#line 2059 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR), (yylsp[(1) - (1)]))); ;} break; - case 906: -#line 2104 "third_party/libpg_query/grammar/statements/select.y" + case 900: +#line 2061 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MONTH), (yylsp[(1) - (1)]))); ;} break; - case 907: -#line 2106 "third_party/libpg_query/grammar/statements/select.y" + case 901: +#line 2063 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY), (yylsp[(1) - (1)]))); ;} break; - case 908: -#line 2108 "third_party/libpg_query/grammar/statements/select.y" + case 902: +#line 2065 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR), (yylsp[(1) - (1)]))); ;} break; - case 909: -#line 2110 "third_party/libpg_query/grammar/statements/select.y" + case 903: +#line 2067 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), (yylsp[(1) - (1)]))); ;} break; - case 910: -#line 2112 "third_party/libpg_query/grammar/statements/select.y" + case 904: +#line 2069 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(SECOND), (yylsp[(1) - (1)]))); ;} break; - case 911: -#line 2114 "third_party/libpg_query/grammar/statements/select.y" + case 905: +#line 2071 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLISECOND), (yylsp[(1) - (1)]))); ;} break; - case 912: -#line 2116 "third_party/libpg_query/grammar/statements/select.y" + case 906: +#line 2073 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MICROSECOND), (yylsp[(1) - (1)]))); ;} break; - case 913: -#line 2118 "third_party/libpg_query/grammar/statements/select.y" + case 907: +#line 2075 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(WEEK), (yylsp[(1) - (1)]))); ;} break; - case 914: -#line 2120 "third_party/libpg_query/grammar/statements/select.y" + case 908: +#line 2077 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(QUARTER), (yylsp[(1) - (1)]))); ;} break; - case 915: -#line 2122 "third_party/libpg_query/grammar/statements/select.y" + case 909: +#line 2079 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DECADE), (yylsp[(1) - (1)]))); ;} break; - case 916: -#line 2124 "third_party/libpg_query/grammar/statements/select.y" + case 910: +#line 2081 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(CENTURY), (yylsp[(1) - (1)]))); ;} break; - case 917: -#line 2126 "third_party/libpg_query/grammar/statements/select.y" + case 911: +#line 2083 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MILLENNIUM), (yylsp[(1) - (1)]))); ;} break; - case 918: -#line 2128 "third_party/libpg_query/grammar/statements/select.y" + case 912: +#line 2085 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH), (yylsp[(1) - (3)]))); ;} break; - case 919: -#line 2133 "third_party/libpg_query/grammar/statements/select.y" + case 913: +#line 2090 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR), (yylsp[(1) - (3)]))); ;} break; - case 920: -#line 2138 "third_party/libpg_query/grammar/statements/select.y" + case 914: +#line 2095 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -27042,8 +26643,8 @@ YYLTYPE yylloc; ;} break; - case 921: -#line 2144 "third_party/libpg_query/grammar/statements/select.y" + case 915: +#line 2101 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | @@ -27052,16 +26653,16 @@ YYLTYPE yylloc; ;} break; - case 922: -#line 2151 "third_party/libpg_query/grammar/statements/select.y" + case 916: +#line 2108 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE), (yylsp[(1) - (3)]))); ;} break; - case 923: -#line 2156 "third_party/libpg_query/grammar/statements/select.y" + case 917: +#line 2113 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | @@ -27069,31 +26670,31 @@ YYLTYPE yylloc; ;} break; - case 924: -#line 2162 "third_party/libpg_query/grammar/statements/select.y" + case 918: +#line 2119 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeIntConst(INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND), (yylsp[(1) - (3)]))); ;} break; - case 925: -#line 2167 "third_party/libpg_query/grammar/statements/select.y" + case 919: +#line 2124 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 926: -#line 2198 "third_party/libpg_query/grammar/statements/select.y" + case 920: +#line 2155 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 927: -#line 2201 "third_party/libpg_query/grammar/statements/select.y" + case 921: +#line 2158 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), 0, (yylsp[(2) - (3)])); ;} break; - case 928: -#line 2203 "third_party/libpg_query/grammar/statements/select.y" + case 922: +#line 2160 "third_party/libpg_query/grammar/statements/select.y" { PGCollateClause *n = makeNode(PGCollateClause); n->arg = (yyvsp[(1) - (3)].node); @@ -27103,8 +26704,8 @@ YYLTYPE yylloc; ;} break; - case 929: -#line 2211 "third_party/libpg_query/grammar/statements/select.y" + case 923: +#line 2168 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("timezone"), list_make2((yyvsp[(5) - (5)].node), (yyvsp[(1) - (5)].node)), @@ -27112,139 +26713,139 @@ YYLTYPE yylloc; ;} break; - case 930: -#line 2226 "third_party/libpg_query/grammar/statements/select.y" + case 924: +#line 2183 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 931: -#line 2228 "third_party/libpg_query/grammar/statements/select.y" + case 925: +#line 2185 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 932: -#line 2230 "third_party/libpg_query/grammar/statements/select.y" + case 926: +#line 2187 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 933: -#line 2232 "third_party/libpg_query/grammar/statements/select.y" + case 927: +#line 2189 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 934: -#line 2234 "third_party/libpg_query/grammar/statements/select.y" + case 928: +#line 2191 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 935: -#line 2236 "third_party/libpg_query/grammar/statements/select.y" + case 929: +#line 2193 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 936: -#line 2238 "third_party/libpg_query/grammar/statements/select.y" + case 930: +#line 2195 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "//", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 937: -#line 2240 "third_party/libpg_query/grammar/statements/select.y" + case 931: +#line 2197 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 938: -#line 2242 "third_party/libpg_query/grammar/statements/select.y" + case 932: +#line 2199 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 939: -#line 2244 "third_party/libpg_query/grammar/statements/select.y" + case 933: +#line 2201 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "**", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 940: -#line 2246 "third_party/libpg_query/grammar/statements/select.y" + case 934: +#line 2203 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 941: -#line 2248 "third_party/libpg_query/grammar/statements/select.y" + case 935: +#line 2205 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 942: -#line 2250 "third_party/libpg_query/grammar/statements/select.y" + case 936: +#line 2207 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 943: -#line 2252 "third_party/libpg_query/grammar/statements/select.y" + case 937: +#line 2209 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 944: -#line 2254 "third_party/libpg_query/grammar/statements/select.y" + case 938: +#line 2211 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 945: -#line 2256 "third_party/libpg_query/grammar/statements/select.y" + case 939: +#line 2213 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 946: -#line 2259 "third_party/libpg_query/grammar/statements/select.y" + case 940: +#line 2216 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 947: -#line 2261 "third_party/libpg_query/grammar/statements/select.y" + case 941: +#line 2218 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 948: -#line 2263 "third_party/libpg_query/grammar/statements/select.y" + case 942: +#line 2220 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (2)].list), (yyvsp[(1) - (2)].node), NULL, (yylsp[(2) - (2)])); ;} break; - case 949: -#line 2266 "third_party/libpg_query/grammar/statements/select.y" + case 943: +#line 2223 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeAndExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 950: -#line 2268 "third_party/libpg_query/grammar/statements/select.y" + case 944: +#line 2225 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeOrExpr((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 951: -#line 2270 "third_party/libpg_query/grammar/statements/select.y" + case 945: +#line 2227 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 952: -#line 2272 "third_party/libpg_query/grammar/statements/select.y" + case 946: +#line 2229 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNotExpr((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 953: -#line 2274 "third_party/libpg_query/grammar/statements/select.y" + case 947: +#line 2231 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_GLOB, "~~~", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 954: -#line 2279 "third_party/libpg_query/grammar/statements/select.y" + case 948: +#line 2236 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_LIKE, "~~", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 955: -#line 2284 "third_party/libpg_query/grammar/statements/select.y" + case 949: +#line 2241 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("like_escape"), list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -27253,16 +26854,16 @@ YYLTYPE yylloc; ;} break; - case 956: -#line 2291 "third_party/libpg_query/grammar/statements/select.y" + case 950: +#line 2248 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_LIKE, "!~~", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); ;} break; - case 957: -#line 2296 "third_party/libpg_query/grammar/statements/select.y" + case 951: +#line 2253 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("not_like_escape"), list_make3((yyvsp[(1) - (6)].node), (yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -27271,16 +26872,16 @@ YYLTYPE yylloc; ;} break; - case 958: -#line 2303 "third_party/libpg_query/grammar/statements/select.y" + case 952: +#line 2260 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_ILIKE, "~~*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 959: -#line 2308 "third_party/libpg_query/grammar/statements/select.y" + case 953: +#line 2265 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("ilike_escape"), list_make3((yyvsp[(1) - (5)].node), (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)), @@ -27289,16 +26890,16 @@ YYLTYPE yylloc; ;} break; - case 960: -#line 2315 "third_party/libpg_query/grammar/statements/select.y" + case 954: +#line 2272 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_ILIKE, "!~~*", (yyvsp[(1) - (4)].node), (yyvsp[(4) - (4)].node), (yylsp[(2) - (4)])); ;} break; - case 961: -#line 2320 "third_party/libpg_query/grammar/statements/select.y" + case 955: +#line 2277 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("not_ilike_escape"), list_make3((yyvsp[(1) - (6)].node), (yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -27307,8 +26908,8 @@ YYLTYPE yylloc; ;} break; - case 962: -#line 2328 "third_party/libpg_query/grammar/statements/select.y" + case 956: +#line 2285 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (4)].node), makeNullAConst(-1)), @@ -27318,8 +26919,8 @@ YYLTYPE yylloc; ;} break; - case 963: -#line 2336 "third_party/libpg_query/grammar/statements/select.y" + case 957: +#line 2293 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(4) - (6)].node), (yyvsp[(6) - (6)].node)), @@ -27329,8 +26930,8 @@ YYLTYPE yylloc; ;} break; - case 964: -#line 2344 "third_party/libpg_query/grammar/statements/select.y" + case 958: +#line 2301 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (5)].node), makeNullAConst(-1)), @@ -27340,8 +26941,8 @@ YYLTYPE yylloc; ;} break; - case 965: -#line 2352 "third_party/libpg_query/grammar/statements/select.y" + case 959: +#line 2309 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("similar_escape"), list_make2((yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)), @@ -27351,8 +26952,8 @@ YYLTYPE yylloc; ;} break; - case 966: -#line 2370 "third_party/libpg_query/grammar/statements/select.y" + case 960: +#line 2327 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27362,8 +26963,8 @@ YYLTYPE yylloc; ;} break; - case 967: -#line 2378 "third_party/libpg_query/grammar/statements/select.y" + case 961: +#line 2335 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -27373,8 +26974,8 @@ YYLTYPE yylloc; ;} break; - case 968: -#line 2386 "third_party/libpg_query/grammar/statements/select.y" + case 962: +#line 2343 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27384,8 +26985,8 @@ YYLTYPE yylloc; ;} break; - case 969: -#line 2394 "third_party/libpg_query/grammar/statements/select.y" + case 963: +#line 2351 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27395,8 +26996,8 @@ YYLTYPE yylloc; ;} break; - case 970: -#line 2402 "third_party/libpg_query/grammar/statements/select.y" + case 964: +#line 2359 "third_party/libpg_query/grammar/statements/select.y" { PGNullTest *n = makeNode(PGNullTest); n->arg = (PGExpr *) (yyvsp[(1) - (2)].node); @@ -27406,8 +27007,8 @@ YYLTYPE yylloc; ;} break; - case 971: -#line 2410 "third_party/libpg_query/grammar/statements/select.y" + case 965: +#line 2367 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *n = makeNode(PGLambdaFunction); n->lhs = (yyvsp[(1) - (3)].node); @@ -27417,15 +27018,15 @@ YYLTYPE yylloc; ;} break; - case 972: -#line 2418 "third_party/libpg_query/grammar/statements/select.y" + case 966: +#line 2375 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "->>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 973: -#line 2422 "third_party/libpg_query/grammar/statements/select.y" + case 967: +#line 2379 "third_party/libpg_query/grammar/statements/select.y" { if (list_length((yyvsp[(1) - (3)].list)) != 2) ereport(ERROR, @@ -27443,8 +27044,8 @@ YYLTYPE yylloc; ;} break; - case 974: -#line 2438 "third_party/libpg_query/grammar/statements/select.y" + case 968: +#line 2395 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27454,8 +27055,8 @@ YYLTYPE yylloc; ;} break; - case 975: -#line 2446 "third_party/libpg_query/grammar/statements/select.y" + case 969: +#line 2403 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27465,8 +27066,8 @@ YYLTYPE yylloc; ;} break; - case 976: -#line 2454 "third_party/libpg_query/grammar/statements/select.y" + case 970: +#line 2411 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27476,8 +27077,8 @@ YYLTYPE yylloc; ;} break; - case 977: -#line 2462 "third_party/libpg_query/grammar/statements/select.y" + case 971: +#line 2419 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27487,8 +27088,8 @@ YYLTYPE yylloc; ;} break; - case 978: -#line 2470 "third_party/libpg_query/grammar/statements/select.y" + case 972: +#line 2427 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (3)].node); @@ -27498,8 +27099,8 @@ YYLTYPE yylloc; ;} break; - case 979: -#line 2478 "third_party/libpg_query/grammar/statements/select.y" + case 973: +#line 2435 "third_party/libpg_query/grammar/statements/select.y" { PGBooleanTest *b = makeNode(PGBooleanTest); b->arg = (PGExpr *) (yyvsp[(1) - (4)].node); @@ -27509,36 +27110,36 @@ YYLTYPE yylloc; ;} break; - case 980: -#line 2486 "third_party/libpg_query/grammar/statements/select.y" + case 974: +#line 2443 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; - case 981: -#line 2490 "third_party/libpg_query/grammar/statements/select.y" + case 975: +#line 2447 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; - case 982: -#line 2494 "third_party/libpg_query/grammar/statements/select.y" + case 976: +#line 2451 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "=", (yyvsp[(1) - (6)].node), (PGNode *) (yyvsp[(5) - (6)].list), (yylsp[(2) - (6)])); ;} break; - case 983: -#line 2498 "third_party/libpg_query/grammar/statements/select.y" + case 977: +#line 2455 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "<>", (yyvsp[(1) - (7)].node), (PGNode *) (yyvsp[(6) - (7)].list), (yylsp[(2) - (7)])); ;} break; - case 984: -#line 2502 "third_party/libpg_query/grammar/statements/select.y" + case 978: +#line 2459 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN, "BETWEEN", @@ -27548,8 +27149,8 @@ YYLTYPE yylloc; ;} break; - case 985: -#line 2510 "third_party/libpg_query/grammar/statements/select.y" + case 979: +#line 2467 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN, "NOT BETWEEN", @@ -27559,8 +27160,8 @@ YYLTYPE yylloc; ;} break; - case 986: -#line 2518 "third_party/libpg_query/grammar/statements/select.y" + case 980: +#line 2475 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_BETWEEN_SYM, "BETWEEN SYMMETRIC", @@ -27570,8 +27171,8 @@ YYLTYPE yylloc; ;} break; - case 987: -#line 2526 "third_party/libpg_query/grammar/statements/select.y" + case 981: +#line 2483 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_BETWEEN_SYM, "NOT BETWEEN SYMMETRIC", @@ -27581,8 +27182,8 @@ YYLTYPE yylloc; ;} break; - case 988: -#line 2534 "third_party/libpg_query/grammar/statements/select.y" + case 982: +#line 2491 "third_party/libpg_query/grammar/statements/select.y" { /* in_expr returns a PGSubLink or a list of a_exprs */ if (IsA((yyvsp[(3) - (3)].node), PGSubLink)) @@ -27604,8 +27205,8 @@ YYLTYPE yylloc; ;} break; - case 989: -#line 2554 "third_party/libpg_query/grammar/statements/select.y" + case 983: +#line 2511 "third_party/libpg_query/grammar/statements/select.y" { /* in_expr returns a PGSubLink or a list of a_exprs */ if (IsA((yyvsp[(4) - (4)].node), PGSubLink)) @@ -27629,8 +27230,8 @@ YYLTYPE yylloc; ;} break; - case 990: -#line 2576 "third_party/libpg_query/grammar/statements/select.y" + case 984: +#line 2533 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = (yyvsp[(3) - (4)].subquerytype); @@ -27643,8 +27244,8 @@ YYLTYPE yylloc; ;} break; - case 991: -#line 2587 "third_party/libpg_query/grammar/statements/select.y" + case 985: +#line 2544 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(3) - (6)].subquerytype) == PG_ANY_SUBLINK) (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP_ANY, (yyvsp[(2) - (6)].list), (yyvsp[(1) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(2) - (6)])); @@ -27653,8 +27254,8 @@ YYLTYPE yylloc; ;} break; - case 992: -#line 2594 "third_party/libpg_query/grammar/statements/select.y" + case 986: +#line 2551 "third_party/libpg_query/grammar/statements/select.y" { /* * The SQL spec only allows DEFAULT in "contextually typed @@ -27670,8 +27271,8 @@ YYLTYPE yylloc; ;} break; - case 993: -#line 2608 "third_party/libpg_query/grammar/statements/select.y" + case 987: +#line 2565 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(4) - (5)].node); @@ -27682,8 +27283,8 @@ YYLTYPE yylloc; ;} break; - case 994: -#line 2617 "third_party/libpg_query/grammar/statements/select.y" + case 988: +#line 2574 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); star->expr = (yyvsp[(3) - (4)].node); @@ -27693,166 +27294,164 @@ YYLTYPE yylloc; ;} break; - case 995: -#line 2625 "third_party/libpg_query/grammar/statements/select.y" + case 989: +#line 2582 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); - star->except_list = (yyvsp[(2) - (4)].list); - star->replace_list = (yyvsp[(3) - (4)].list); - star->rename_list = (yyvsp[(4) - (4)].list); - star->location = (yylsp[(1) - (4)]); + star->except_list = (yyvsp[(2) - (3)].list); + star->replace_list = (yyvsp[(3) - (3)].list); + star->location = (yylsp[(1) - (3)]); (yyval.node) = (PGNode *) star; ;} break; - case 996: -#line 2634 "third_party/libpg_query/grammar/statements/select.y" + case 990: +#line 2590 "third_party/libpg_query/grammar/statements/select.y" { PGAStar *star = makeNode(PGAStar); - star->relation = (yyvsp[(1) - (6)].str); - star->except_list = (yyvsp[(4) - (6)].list); - star->replace_list = (yyvsp[(5) - (6)].list); - star->rename_list = (yyvsp[(6) - (6)].list); - star->location = (yylsp[(1) - (6)]); + star->relation = (yyvsp[(1) - (5)].str); + star->except_list = (yyvsp[(4) - (5)].list); + star->replace_list = (yyvsp[(5) - (5)].list); + star->location = (yylsp[(1) - (5)]); (yyval.node) = (PGNode *) star; ;} break; - case 997: -#line 2655 "third_party/libpg_query/grammar/statements/select.y" + case 991: +#line 2610 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 998: -#line 2657 "third_party/libpg_query/grammar/statements/select.y" + case 992: +#line 2612 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].typnam), 0, (yylsp[(2) - (3)])); ;} break; - case 999: -#line 2659 "third_party/libpg_query/grammar/statements/select.y" + case 993: +#line 2614 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1000: -#line 2661 "third_party/libpg_query/grammar/statements/select.y" + case 994: +#line 2616 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = doNegate((yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1001: -#line 2663 "third_party/libpg_query/grammar/statements/select.y" + case 995: +#line 2618 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "+", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1002: -#line 2665 "third_party/libpg_query/grammar/statements/select.y" + case 996: +#line 2620 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "-", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1003: -#line 2667 "third_party/libpg_query/grammar/statements/select.y" + case 997: +#line 2622 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "*", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1004: -#line 2669 "third_party/libpg_query/grammar/statements/select.y" + case 998: +#line 2624 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "/", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1005: -#line 2671 "third_party/libpg_query/grammar/statements/select.y" + case 999: +#line 2626 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "//", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1006: -#line 2673 "third_party/libpg_query/grammar/statements/select.y" + case 1000: +#line 2628 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "%", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1007: -#line 2675 "third_party/libpg_query/grammar/statements/select.y" + case 1001: +#line 2630 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "^", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1008: -#line 2677 "third_party/libpg_query/grammar/statements/select.y" + case 1002: +#line 2632 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "**", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1009: -#line 2679 "third_party/libpg_query/grammar/statements/select.y" + case 1003: +#line 2634 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1010: -#line 2681 "third_party/libpg_query/grammar/statements/select.y" + case 1004: +#line 2636 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1011: -#line 2683 "third_party/libpg_query/grammar/statements/select.y" + case 1005: +#line 2638 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1012: -#line 2685 "third_party/libpg_query/grammar/statements/select.y" + case 1006: +#line 2640 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1013: -#line 2687 "third_party/libpg_query/grammar/statements/select.y" + case 1007: +#line 2642 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, ">=", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1014: -#line 2689 "third_party/libpg_query/grammar/statements/select.y" + case 1008: +#line 2644 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OP, "<>", (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1015: -#line 2691 "third_party/libpg_query/grammar/statements/select.y" + case 1009: +#line 2646 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (3)].list), (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yylsp[(2) - (3)])); ;} break; - case 1016: -#line 2693 "third_party/libpg_query/grammar/statements/select.y" + case 1010: +#line 2648 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(1) - (2)].list), NULL, (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1017: -#line 2695 "third_party/libpg_query/grammar/statements/select.y" + case 1011: +#line 2650 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeAExpr(PG_AEXPR_OP, (yyvsp[(2) - (2)].list), (yyvsp[(1) - (2)].node), NULL, (yylsp[(2) - (2)])); ;} break; - case 1018: -#line 2697 "third_party/libpg_query/grammar/statements/select.y" + case 1012: +#line 2652 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_DISTINCT, "=", (yyvsp[(1) - (5)].node), (yyvsp[(5) - (5)].node), (yylsp[(2) - (5)])); ;} break; - case 1019: -#line 2701 "third_party/libpg_query/grammar/statements/select.y" + case 1013: +#line 2656 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NOT_DISTINCT, "=", (yyvsp[(1) - (6)].node), (yyvsp[(6) - (6)].node), (yylsp[(2) - (6)])); ;} break; - case 1020: -#line 2705 "third_party/libpg_query/grammar/statements/select.y" + case 1014: +#line 2660 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "=", (yyvsp[(1) - (6)].node), (PGNode *) (yyvsp[(5) - (6)].list), (yylsp[(2) - (6)])); ;} break; - case 1021: -#line 2709 "third_party/libpg_query/grammar/statements/select.y" + case 1015: +#line 2664 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_OF, "<>", (yyvsp[(1) - (7)].node), (PGNode *) (yyvsp[(6) - (7)].list), (yylsp[(2) - (7)])); ;} break; - case 1023: -#line 2724 "third_party/libpg_query/grammar/statements/select.y" + case 1017: +#line 2679 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -27866,18 +27465,18 @@ YYLTYPE yylloc; ;} break; - case 1024: -#line 2737 "third_party/libpg_query/grammar/statements/select.y" + case 1018: +#line 2692 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1025: -#line 2738 "third_party/libpg_query/grammar/statements/select.y" + case 1019: +#line 2693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1026: -#line 2740 "third_party/libpg_query/grammar/statements/select.y" + case 1020: +#line 2695 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXPR_SUBLINK; @@ -27890,8 +27489,8 @@ YYLTYPE yylloc; ;} break; - case 1027: -#line 2751 "third_party/libpg_query/grammar/statements/select.y" + case 1021: +#line 2706 "third_party/libpg_query/grammar/statements/select.y" { /* * Because the select_with_parens nonterminal is designed @@ -27917,8 +27516,8 @@ YYLTYPE yylloc; ;} break; - case 1028: -#line 2775 "third_party/libpg_query/grammar/statements/select.y" + case 1022: +#line 2730 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_EXISTS_SUBLINK; @@ -27931,8 +27530,8 @@ YYLTYPE yylloc; ;} break; - case 1029: -#line 2786 "third_party/libpg_query/grammar/statements/select.y" + case 1023: +#line 2741 "third_party/libpg_query/grammar/statements/select.y" { PGGroupingFunc *g = makeNode(PGGroupingFunc); g->args = (yyvsp[(3) - (4)].list); @@ -27941,37 +27540,37 @@ YYLTYPE yylloc; ;} break; - case 1030: -#line 2796 "third_party/libpg_query/grammar/statements/select.y" + case 1024: +#line 2751 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (3)].node); ;} break; - case 1031: -#line 2800 "third_party/libpg_query/grammar/statements/select.y" + case 1025: +#line 2755 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1032: -#line 2803 "third_party/libpg_query/grammar/statements/select.y" + case 1026: +#line 2758 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("row"), (yyvsp[(1) - (1)].list), (yylsp[(1) - (1)])); (yyval.node) = (PGNode *) n; ;} break; - case 1033: -#line 2811 "third_party/libpg_query/grammar/statements/select.y" + case 1027: +#line 2766 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeParamRef(0, (yylsp[(1) - (1)])); ;} break; - case 1034: -#line 2815 "third_party/libpg_query/grammar/statements/select.y" + case 1028: +#line 2770 "third_party/libpg_query/grammar/statements/select.y" { PGParamRef *p = makeNode(PGParamRef); p->number = (yyvsp[(1) - (1)].ival); @@ -27980,15 +27579,48 @@ YYLTYPE yylloc; ;} break; - case 1035: -#line 2822 "third_party/libpg_query/grammar/statements/select.y" + case 1029: +#line 2777 "third_party/libpg_query/grammar/statements/select.y" { - (yyval.node) = makeNamedParamRef((yyvsp[(2) - (2)].str), (yylsp[(1) - (2)])); + (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1043: -#line 2836 "third_party/libpg_query/grammar/statements/select.y" + case 1030: +#line 2781 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + ;} + break; + + case 1031: +#line 2785 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + ;} + break; + + case 1032: +#line 2789 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); ;} + break; + + case 1033: +#line 2790 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + ;} + break; + + case 1034: +#line 2793 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + ;} + break; + + case 1035: +#line 2797 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subLinkType = PG_ARRAY_SUBLINK; @@ -28001,8 +27633,8 @@ YYLTYPE yylloc; ;} break; - case 1044: -#line 2846 "third_party/libpg_query/grammar/statements/select.y" + case 1036: +#line 2807 "third_party/libpg_query/grammar/statements/select.y" { PGList *func_name = list_make1(makeString("construct_array")); PGFuncCall *n = makeFuncCall(func_name, (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); @@ -28010,8 +27642,8 @@ YYLTYPE yylloc; ;} break; - case 1045: -#line 2852 "third_party/libpg_query/grammar/statements/select.y" + case 1037: +#line 2813 "third_party/libpg_query/grammar/statements/select.y" { PGPositionalReference *n = makeNode(PGPositionalReference); n->position = (yyvsp[(2) - (2)].ival); @@ -28020,24 +27652,31 @@ YYLTYPE yylloc; ;} break; - case 1046: -#line 2860 "third_party/libpg_query/grammar/statements/select.y" + case 1038: +#line 2820 "third_party/libpg_query/grammar/statements/select.y" + { + (yyval.node) = makeNamedParamRef((yyvsp[(2) - (2)].str), (yylsp[(1) - (2)])); + ;} + break; + + case 1039: +#line 2825 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("list_value"), (yyvsp[(2) - (3)].list), (yylsp[(2) - (3)])); (yyval.node) = (PGNode *) n; ;} break; - case 1047: -#line 2867 "third_party/libpg_query/grammar/statements/select.y" + case 1040: +#line 2832 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *f = makeFuncCall(SystemFuncName("struct_pack"), (yyvsp[(2) - (3)].list), (yylsp[(2) - (3)])); (yyval.node) = (PGNode *) f; ;} break; - case 1048: -#line 2874 "third_party/libpg_query/grammar/statements/select.y" + case 1041: +#line 2839 "third_party/libpg_query/grammar/statements/select.y" { PGList *key_list = NULL; PGList *value_list = NULL; @@ -28056,25 +27695,15 @@ YYLTYPE yylloc; ;} break; - case 1049: -#line 2894 "third_party/libpg_query/grammar/statements/select.y" + case 1042: +#line 2859 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall((yyvsp[(1) - (3)].list), NIL, (yylsp[(1) - (3)])); ;} break; - case 1050: -#line 2898 "third_party/libpg_query/grammar/statements/select.y" - { - PGFuncCall *n = makeFuncCall((yyvsp[(1) - (5)].list), NIL, (yylsp[(1) - (5)])); - n->agg_order = (yyvsp[(3) - (5)].list); - n->agg_ignore_nulls = (yyvsp[(4) - (5)].ignorenulls); - (yyval.node) = (PGNode *)n; - ;} - break; - - case 1051: -#line 2905 "third_party/libpg_query/grammar/statements/select.y" + case 1043: +#line 2863 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (6)].list), (yyvsp[(3) - (6)].list), (yylsp[(1) - (6)])); n->agg_order = (yyvsp[(4) - (6)].list); @@ -28083,8 +27712,8 @@ YYLTYPE yylloc; ;} break; - case 1052: -#line 2912 "third_party/libpg_query/grammar/statements/select.y" + case 1044: +#line 2870 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), list_make1((yyvsp[(4) - (7)].node)), (yylsp[(1) - (7)])); n->func_variadic = true; @@ -28094,8 +27723,8 @@ YYLTYPE yylloc; ;} break; - case 1053: -#line 2920 "third_party/libpg_query/grammar/statements/select.y" + case 1045: +#line 2878 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (9)].list), lappend((yyvsp[(3) - (9)].list), (yyvsp[(6) - (9)].node)), (yylsp[(1) - (9)])); n->func_variadic = true; @@ -28105,8 +27734,8 @@ YYLTYPE yylloc; ;} break; - case 1054: -#line 2928 "third_party/libpg_query/grammar/statements/select.y" + case 1046: +#line 2886 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), (yyvsp[(4) - (7)].list), (yylsp[(1) - (7)])); n->agg_order = (yyvsp[(5) - (7)].list); @@ -28119,8 +27748,8 @@ YYLTYPE yylloc; ;} break; - case 1055: -#line 2939 "third_party/libpg_query/grammar/statements/select.y" + case 1047: +#line 2897 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall((yyvsp[(1) - (7)].list), (yyvsp[(4) - (7)].list), (yylsp[(1) - (7)])); n->agg_order = (yyvsp[(5) - (7)].list); @@ -28130,8 +27759,8 @@ YYLTYPE yylloc; ;} break; - case 1056: -#line 2959 "third_party/libpg_query/grammar/statements/select.y" + case 1048: +#line 2917 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = (PGFuncCall *) (yyvsp[(1) - (5)].node); /* @@ -28169,23 +27798,23 @@ YYLTYPE yylloc; ;} break; - case 1057: -#line 2995 "third_party/libpg_query/grammar/statements/select.y" + case 1049: +#line 2953 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1058: -#line 3005 "third_party/libpg_query/grammar/statements/select.y" + case 1050: +#line 2963 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1059: -#line 3006 "third_party/libpg_query/grammar/statements/select.y" + case 1051: +#line 2964 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1060: -#line 3014 "third_party/libpg_query/grammar/statements/select.y" + case 1052: +#line 2972 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("pg_collation_for"), list_make1((yyvsp[(4) - (5)].node)), @@ -28193,25 +27822,25 @@ YYLTYPE yylloc; ;} break; - case 1061: -#line 3020 "third_party/libpg_query/grammar/statements/select.y" + case 1053: +#line 2978 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].typnam), 0, (yylsp[(1) - (6)])); ;} break; - case 1062: -#line 3022 "third_party/libpg_query/grammar/statements/select.y" + case 1054: +#line 2980 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeTypeCast((yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].typnam), 1, (yylsp[(1) - (6)])); ;} break; - case 1063: -#line 3024 "third_party/libpg_query/grammar/statements/select.y" + case 1055: +#line 2982 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("date_part"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1064: -#line 3028 "third_party/libpg_query/grammar/statements/select.y" + case 1056: +#line 2986 "third_party/libpg_query/grammar/statements/select.y" { /* overlay(A PLACING B FROM C FOR D) is converted to * overlay(A, B, C, D) @@ -28222,16 +27851,16 @@ YYLTYPE yylloc; ;} break; - case 1065: -#line 3037 "third_party/libpg_query/grammar/statements/select.y" + case 1057: +#line 2995 "third_party/libpg_query/grammar/statements/select.y" { /* position(A in B) is converted to position_inverse(A, B) */ (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("__internal_position_operator"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1066: -#line 3042 "third_party/libpg_query/grammar/statements/select.y" + case 1058: +#line 3000 "third_party/libpg_query/grammar/statements/select.y" { /* substring(A from B for C) is converted to * substring(A, B, C) - thomas 2000-11-28 @@ -28240,8 +27869,8 @@ YYLTYPE yylloc; ;} break; - case 1067: -#line 3049 "third_party/libpg_query/grammar/statements/select.y" + case 1059: +#line 3007 "third_party/libpg_query/grammar/statements/select.y" { /* TREAT(expr AS target) converts expr of a particular type to target, * which is defined to be a subtype of the original expression. @@ -28258,8 +27887,8 @@ YYLTYPE yylloc; ;} break; - case 1068: -#line 3064 "third_party/libpg_query/grammar/statements/select.y" + case 1060: +#line 3022 "third_party/libpg_query/grammar/statements/select.y" { /* various trim expressions are defined in SQL * - thomas 1997-07-19 @@ -28268,36 +27897,36 @@ YYLTYPE yylloc; ;} break; - case 1069: -#line 3071 "third_party/libpg_query/grammar/statements/select.y" + case 1061: +#line 3029 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("ltrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1070: -#line 3075 "third_party/libpg_query/grammar/statements/select.y" + case 1062: +#line 3033 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("rtrim"), (yyvsp[(4) - (5)].list), (yylsp[(1) - (5)])); ;} break; - case 1071: -#line 3079 "third_party/libpg_query/grammar/statements/select.y" + case 1063: +#line 3037 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeFuncCall(SystemFuncName("trim"), (yyvsp[(3) - (4)].list), (yylsp[(1) - (4)])); ;} break; - case 1072: -#line 3083 "third_party/libpg_query/grammar/statements/select.y" + case 1064: +#line 3041 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *) makeSimpleAExpr(PG_AEXPR_NULLIF, "=", (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node), (yylsp[(1) - (6)])); ;} break; - case 1073: -#line 3087 "third_party/libpg_query/grammar/statements/select.y" + case 1065: +#line 3045 "third_party/libpg_query/grammar/statements/select.y" { PGCoalesceExpr *c = makeNode(PGCoalesceExpr); c->args = (yyvsp[(3) - (4)].list); @@ -28306,16 +27935,16 @@ YYLTYPE yylloc; ;} break; - case 1074: -#line 3097 "third_party/libpg_query/grammar/statements/select.y" + case 1066: +#line 3055 "third_party/libpg_query/grammar/statements/select.y" { PGFuncCall *n = makeFuncCall(SystemFuncName("row"), (yyvsp[(1) - (1)].list), (yylsp[(1) - (1)])); (yyval.node) = (PGNode *) n; ;} break; - case 1075: -#line 3105 "third_party/libpg_query/grammar/statements/select.y" + case 1067: +#line 3063 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (7)].node); @@ -28326,8 +27955,8 @@ YYLTYPE yylloc; ;} break; - case 1076: -#line 3114 "third_party/libpg_query/grammar/statements/select.y" + case 1068: +#line 3072 "third_party/libpg_query/grammar/statements/select.y" { PGLambdaFunction *lambda = makeNode(PGLambdaFunction); lambda->lhs = (yyvsp[(4) - (9)].node); @@ -28344,63 +27973,63 @@ YYLTYPE yylloc; ;} break; - case 1077: -#line 3135 "third_party/libpg_query/grammar/statements/select.y" + case 1069: +#line 3093 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(4) - (5)].list); ;} break; - case 1078: -#line 3136 "third_party/libpg_query/grammar/statements/select.y" + case 1070: +#line 3094 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1079: -#line 3140 "third_party/libpg_query/grammar/statements/select.y" + case 1071: +#line 3098 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(4) - (5)].node); ;} break; - case 1080: -#line 3141 "third_party/libpg_query/grammar/statements/select.y" + case 1072: +#line 3099 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(3) - (4)].node); ;} break; - case 1081: -#line 3142 "third_party/libpg_query/grammar/statements/select.y" + case 1073: +#line 3100 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1082: -#line 3146 "third_party/libpg_query/grammar/statements/select.y" + case 1074: +#line 3104 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = true; ;} break; - case 1083: -#line 3147 "third_party/libpg_query/grammar/statements/select.y" + case 1075: +#line 3105 "third_party/libpg_query/grammar/statements/select.y" { (yyval.boolean) = false; ;} break; - case 1084: -#line 3154 "third_party/libpg_query/grammar/statements/select.y" + case 1076: +#line 3112 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1085: -#line 3155 "third_party/libpg_query/grammar/statements/select.y" + case 1077: +#line 3113 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1086: -#line 3159 "third_party/libpg_query/grammar/statements/select.y" + case 1078: +#line 3117 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].windef)); ;} break; - case 1087: -#line 3161 "third_party/libpg_query/grammar/statements/select.y" + case 1079: +#line 3119 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].windef)); ;} break; - case 1088: -#line 3166 "third_party/libpg_query/grammar/statements/select.y" + case 1080: +#line 3124 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(3) - (3)].windef); n->name = (yyvsp[(1) - (3)].str); @@ -28408,13 +28037,13 @@ YYLTYPE yylloc; ;} break; - case 1089: -#line 3174 "third_party/libpg_query/grammar/statements/select.y" + case 1081: +#line 3132 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = (yyvsp[(2) - (2)].windef); ;} break; - case 1090: -#line 3176 "third_party/libpg_query/grammar/statements/select.y" + case 1082: +#line 3134 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = (yyvsp[(2) - (2)].str); @@ -28429,13 +28058,13 @@ YYLTYPE yylloc; ;} break; - case 1091: -#line 3189 "third_party/libpg_query/grammar/statements/select.y" + case 1083: +#line 3147 "third_party/libpg_query/grammar/statements/select.y" { (yyval.windef) = NULL; ;} break; - case 1092: -#line 3194 "third_party/libpg_query/grammar/statements/select.y" + case 1084: +#line 3152 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); n->name = NULL; @@ -28451,28 +28080,28 @@ YYLTYPE yylloc; ;} break; - case 1093: -#line 3219 "third_party/libpg_query/grammar/statements/select.y" + case 1085: +#line 3177 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1094: -#line 3220 "third_party/libpg_query/grammar/statements/select.y" + case 1086: +#line 3178 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = NULL; ;} break; - case 1095: -#line 3223 "third_party/libpg_query/grammar/statements/select.y" + case 1087: +#line 3181 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (3)].list); ;} break; - case 1096: -#line 3224 "third_party/libpg_query/grammar/statements/select.y" + case 1088: +#line 3182 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1097: -#line 3233 "third_party/libpg_query/grammar/statements/select.y" + case 1089: +#line 3191 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28482,8 +28111,8 @@ YYLTYPE yylloc; ;} break; - case 1098: -#line 3241 "third_party/libpg_query/grammar/statements/select.y" + case 1090: +#line 3199 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28493,8 +28122,8 @@ YYLTYPE yylloc; ;} break; - case 1099: -#line 3249 "third_party/libpg_query/grammar/statements/select.y" + case 1091: +#line 3207 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(2) - (3)].windef); @@ -28504,8 +28133,8 @@ YYLTYPE yylloc; ;} break; - case 1100: -#line 3257 "third_party/libpg_query/grammar/statements/select.y" + case 1092: +#line 3215 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28516,8 +28145,8 @@ YYLTYPE yylloc; ;} break; - case 1101: -#line 3268 "third_party/libpg_query/grammar/statements/select.y" + case 1093: +#line 3226 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = (yyvsp[(1) - (1)].windef); @@ -28537,8 +28166,8 @@ YYLTYPE yylloc; ;} break; - case 1102: -#line 3286 "third_party/libpg_query/grammar/statements/select.y" + case 1094: +#line 3244 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n1 = (yyvsp[(2) - (4)].windef); PGWindowDef *n2 = (yyvsp[(4) - (4)].windef); @@ -28578,8 +28207,8 @@ YYLTYPE yylloc; ;} break; - case 1103: -#line 3332 "third_party/libpg_query/grammar/statements/select.y" + case 1095: +#line 3290 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28590,8 +28219,8 @@ YYLTYPE yylloc; ;} break; - case 1104: -#line 3341 "third_party/libpg_query/grammar/statements/select.y" + case 1096: +#line 3299 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28602,8 +28231,8 @@ YYLTYPE yylloc; ;} break; - case 1105: -#line 3350 "third_party/libpg_query/grammar/statements/select.y" + case 1097: +#line 3308 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28614,8 +28243,8 @@ YYLTYPE yylloc; ;} break; - case 1106: -#line 3359 "third_party/libpg_query/grammar/statements/select.y" + case 1098: +#line 3317 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28626,8 +28255,8 @@ YYLTYPE yylloc; ;} break; - case 1107: -#line 3368 "third_party/libpg_query/grammar/statements/select.y" + case 1099: +#line 3326 "third_party/libpg_query/grammar/statements/select.y" { PGWindowDef *n = makeNode(PGWindowDef); @@ -28638,53 +28267,53 @@ YYLTYPE yylloc; ;} break; - case 1108: -#line 3379 "third_party/libpg_query/grammar/statements/select.y" + case 1100: +#line 3337 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_CURRENT_ROW; ;} break; - case 1109: -#line 3380 "third_party/libpg_query/grammar/statements/select.y" + case 1101: +#line 3338 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_GROUP; ;} break; - case 1110: -#line 3381 "third_party/libpg_query/grammar/statements/select.y" + case 1102: +#line 3339 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = FRAMEOPTION_EXCLUDE_TIES; ;} break; - case 1111: -#line 3382 "third_party/libpg_query/grammar/statements/select.y" + case 1103: +#line 3340 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1112: -#line 3383 "third_party/libpg_query/grammar/statements/select.y" + case 1104: +#line 3341 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = 0; ;} break; - case 1113: -#line 3397 "third_party/libpg_query/grammar/statements/select.y" + case 1105: +#line 3355 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1114: -#line 3398 "third_party/libpg_query/grammar/statements/select.y" + case 1106: +#line 3356 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1115: -#line 3401 "third_party/libpg_query/grammar/statements/select.y" + case 1107: +#line 3359 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list);;} break; - case 1116: -#line 3402 "third_party/libpg_query/grammar/statements/select.y" + case 1108: +#line 3360 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(2) - (5)].list), (yyvsp[(4) - (5)].node)); ;} break; - case 1117: -#line 3406 "third_party/libpg_query/grammar/statements/select.y" + case 1109: +#line 3364 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -28695,321 +28324,321 @@ YYLTYPE yylloc; ;} break; - case 1118: -#line 3416 "third_party/libpg_query/grammar/statements/select.y" + case 1110: +#line 3374 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1119: -#line 3417 "third_party/libpg_query/grammar/statements/select.y" + case 1111: +#line 3375 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1120: -#line 3421 "third_party/libpg_query/grammar/statements/select.y" + case 1112: +#line 3379 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1121: -#line 3422 "third_party/libpg_query/grammar/statements/select.y" + case 1113: +#line 3380 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1122: -#line 3427 "third_party/libpg_query/grammar/statements/select.y" + case 1114: +#line 3385 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1123: -#line 3433 "third_party/libpg_query/grammar/statements/select.y" + case 1115: +#line 3391 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1124: -#line 3434 "third_party/libpg_query/grammar/statements/select.y" + case 1116: +#line 3392 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1125: -#line 3439 "third_party/libpg_query/grammar/statements/select.y" + case 1117: +#line 3397 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1126: -#line 3440 "third_party/libpg_query/grammar/statements/select.y" + case 1118: +#line 3398 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1127: -#line 3445 "third_party/libpg_query/grammar/statements/select.y" + case 1119: +#line 3403 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1128: -#line 3446 "third_party/libpg_query/grammar/statements/select.y" + case 1120: +#line 3404 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1129: -#line 3449 "third_party/libpg_query/grammar/statements/select.y" + case 1121: +#line 3407 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1130: -#line 3450 "third_party/libpg_query/grammar/statements/select.y" + case 1122: +#line 3408 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ANY_SUBLINK; ;} break; - case 1131: -#line 3451 "third_party/libpg_query/grammar/statements/select.y" + case 1123: +#line 3409 "third_party/libpg_query/grammar/statements/select.y" { (yyval.subquerytype) = PG_ALL_SUBLINK; ;} break; - case 1132: -#line 3454 "third_party/libpg_query/grammar/statements/select.y" + case 1124: +#line 3412 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1133: -#line 3455 "third_party/libpg_query/grammar/statements/select.y" + case 1125: +#line 3413 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) (yyvsp[(1) - (1)].conststr); ;} break; - case 1134: -#line 3458 "third_party/libpg_query/grammar/statements/select.y" + case 1126: +#line 3416 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "+"; ;} break; - case 1135: -#line 3459 "third_party/libpg_query/grammar/statements/select.y" + case 1127: +#line 3417 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "-"; ;} break; - case 1136: -#line 3460 "third_party/libpg_query/grammar/statements/select.y" + case 1128: +#line 3418 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "*"; ;} break; - case 1137: -#line 3461 "third_party/libpg_query/grammar/statements/select.y" + case 1129: +#line 3419 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "/"; ;} break; - case 1138: -#line 3462 "third_party/libpg_query/grammar/statements/select.y" + case 1130: +#line 3420 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "//"; ;} break; - case 1139: -#line 3463 "third_party/libpg_query/grammar/statements/select.y" + case 1131: +#line 3421 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "%"; ;} break; - case 1140: -#line 3464 "third_party/libpg_query/grammar/statements/select.y" + case 1132: +#line 3422 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "^"; ;} break; - case 1141: -#line 3465 "third_party/libpg_query/grammar/statements/select.y" + case 1133: +#line 3423 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "**"; ;} break; - case 1142: -#line 3466 "third_party/libpg_query/grammar/statements/select.y" + case 1134: +#line 3424 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<"; ;} break; - case 1143: -#line 3467 "third_party/libpg_query/grammar/statements/select.y" + case 1135: +#line 3425 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">"; ;} break; - case 1144: -#line 3468 "third_party/libpg_query/grammar/statements/select.y" + case 1136: +#line 3426 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "="; ;} break; - case 1145: -#line 3469 "third_party/libpg_query/grammar/statements/select.y" + case 1137: +#line 3427 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<="; ;} break; - case 1146: -#line 3470 "third_party/libpg_query/grammar/statements/select.y" + case 1138: +#line 3428 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = ">="; ;} break; - case 1147: -#line 3471 "third_party/libpg_query/grammar/statements/select.y" + case 1139: +#line 3429 "third_party/libpg_query/grammar/statements/select.y" { (yyval.conststr) = "<>"; ;} break; - case 1148: -#line 3475 "third_party/libpg_query/grammar/statements/select.y" + case 1140: +#line 3433 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1149: -#line 3477 "third_party/libpg_query/grammar/statements/select.y" + case 1141: +#line 3435 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1150: -#line 3482 "third_party/libpg_query/grammar/statements/select.y" + case 1142: +#line 3440 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1151: -#line 3484 "third_party/libpg_query/grammar/statements/select.y" + case 1143: +#line 3442 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1152: -#line 3489 "third_party/libpg_query/grammar/statements/select.y" + case 1144: +#line 3447 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1153: -#line 3491 "third_party/libpg_query/grammar/statements/select.y" + case 1145: +#line 3449 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1154: -#line 3493 "third_party/libpg_query/grammar/statements/select.y" + case 1146: +#line 3451 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~")); ;} break; - case 1155: -#line 3495 "third_party/libpg_query/grammar/statements/select.y" + case 1147: +#line 3453 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~")); ;} break; - case 1156: -#line 3497 "third_party/libpg_query/grammar/statements/select.y" + case 1148: +#line 3455 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~~")); ;} break; - case 1157: -#line 3499 "third_party/libpg_query/grammar/statements/select.y" + case 1149: +#line 3457 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~~")); ;} break; - case 1158: -#line 3501 "third_party/libpg_query/grammar/statements/select.y" + case 1150: +#line 3459 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("~~*")); ;} break; - case 1159: -#line 3503 "third_party/libpg_query/grammar/statements/select.y" + case 1151: +#line 3461 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString("!~~*")); ;} break; - case 1160: -#line 3517 "third_party/libpg_query/grammar/statements/select.y" + case 1152: +#line 3475 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1161: -#line 3519 "third_party/libpg_query/grammar/statements/select.y" + case 1153: +#line 3477 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (3)].str)), (yyvsp[(3) - (3)].list)); ;} break; - case 1162: -#line 3524 "third_party/libpg_query/grammar/statements/select.y" + case 1154: +#line 3482 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1163: -#line 3528 "third_party/libpg_query/grammar/statements/select.y" + case 1155: +#line 3486 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1164: -#line 3535 "third_party/libpg_query/grammar/statements/select.y" + case 1156: +#line 3493 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1165: -#line 3540 "third_party/libpg_query/grammar/statements/select.y" + case 1157: +#line 3498 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1166: -#line 3546 "third_party/libpg_query/grammar/statements/select.y" + case 1158: +#line 3504 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1167: -#line 3550 "third_party/libpg_query/grammar/statements/select.y" + case 1159: +#line 3508 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1168: -#line 3557 "third_party/libpg_query/grammar/statements/select.y" + case 1160: +#line 3515 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1169: -#line 3562 "third_party/libpg_query/grammar/statements/select.y" + case 1161: +#line 3520 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1170: -#line 3569 "third_party/libpg_query/grammar/statements/select.y" + case 1162: +#line 3527 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1171: -#line 3573 "third_party/libpg_query/grammar/statements/select.y" + case 1163: +#line 3531 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1172: -#line 3582 "third_party/libpg_query/grammar/statements/select.y" + case 1164: +#line 3540 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1173: -#line 3586 "third_party/libpg_query/grammar/statements/select.y" + case 1165: +#line 3544 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1174: -#line 3592 "third_party/libpg_query/grammar/statements/select.y" + case 1166: +#line 3550 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1175: -#line 3596 "third_party/libpg_query/grammar/statements/select.y" + case 1167: +#line 3554 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -29020,8 +28649,8 @@ YYLTYPE yylloc; ;} break; - case 1176: -#line 3605 "third_party/libpg_query/grammar/statements/select.y" + case 1168: +#line 3563 "third_party/libpg_query/grammar/statements/select.y" { PGNamedArgExpr *na = makeNode(PGNamedArgExpr); na->name = (yyvsp[(1) - (3)].str); @@ -29032,156 +28661,156 @@ YYLTYPE yylloc; ;} break; - case 1177: -#line 3615 "third_party/libpg_query/grammar/statements/select.y" + case 1169: +#line 3573 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].typnam)); ;} break; - case 1178: -#line 3616 "third_party/libpg_query/grammar/statements/select.y" + case 1170: +#line 3574 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].typnam)); ;} break; - case 1179: -#line 3621 "third_party/libpg_query/grammar/statements/select.y" + case 1171: +#line 3579 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2(makeStringConst((yyvsp[(1) - (3)].str), (yylsp[(1) - (3)])), (yyvsp[(3) - (3)].node)); ;} break; - case 1180: -#line 3624 "third_party/libpg_query/grammar/statements/select.y" + case 1172: +#line 3582 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1181: -#line 3631 "third_party/libpg_query/grammar/statements/select.y" + case 1173: +#line 3589 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1182: -#line 3632 "third_party/libpg_query/grammar/statements/select.y" + case 1174: +#line 3590 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "year"; ;} break; - case 1183: -#line 3633 "third_party/libpg_query/grammar/statements/select.y" + case 1175: +#line 3591 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "month"; ;} break; - case 1184: -#line 3634 "third_party/libpg_query/grammar/statements/select.y" + case 1176: +#line 3592 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "day"; ;} break; - case 1185: -#line 3635 "third_party/libpg_query/grammar/statements/select.y" + case 1177: +#line 3593 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "hour"; ;} break; - case 1186: -#line 3636 "third_party/libpg_query/grammar/statements/select.y" + case 1178: +#line 3594 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "minute"; ;} break; - case 1187: -#line 3637 "third_party/libpg_query/grammar/statements/select.y" + case 1179: +#line 3595 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "second"; ;} break; - case 1188: -#line 3638 "third_party/libpg_query/grammar/statements/select.y" + case 1180: +#line 3596 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millisecond"; ;} break; - case 1189: -#line 3639 "third_party/libpg_query/grammar/statements/select.y" + case 1181: +#line 3597 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "microsecond"; ;} break; - case 1190: -#line 3640 "third_party/libpg_query/grammar/statements/select.y" + case 1182: +#line 3598 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "week"; ;} break; - case 1191: -#line 3641 "third_party/libpg_query/grammar/statements/select.y" + case 1183: +#line 3599 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "quarter"; ;} break; - case 1192: -#line 3642 "third_party/libpg_query/grammar/statements/select.y" + case 1184: +#line 3600 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "decade"; ;} break; - case 1193: -#line 3643 "third_party/libpg_query/grammar/statements/select.y" + case 1185: +#line 3601 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "century"; ;} break; - case 1194: -#line 3644 "third_party/libpg_query/grammar/statements/select.y" + case 1186: +#line 3602 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (char*) "millennium"; ;} break; - case 1195: -#line 3645 "third_party/libpg_query/grammar/statements/select.y" + case 1187: +#line 3603 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1196: -#line 3656 "third_party/libpg_query/grammar/statements/select.y" + case 1188: +#line 3614 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make4((yyvsp[(1) - (4)].node), (yyvsp[(2) - (4)].node), (yyvsp[(3) - (4)].node), (yyvsp[(4) - (4)].node)); ;} break; - case 1197: -#line 3660 "third_party/libpg_query/grammar/statements/select.y" + case 1189: +#line 3618 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1198: -#line 3667 "third_party/libpg_query/grammar/statements/select.y" + case 1190: +#line 3625 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1199: -#line 3673 "third_party/libpg_query/grammar/statements/select.y" + case 1191: +#line 3631 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1200: -#line 3674 "third_party/libpg_query/grammar/statements/select.y" + case 1192: +#line 3632 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1201: -#line 3691 "third_party/libpg_query/grammar/statements/select.y" + case 1193: +#line 3649 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; - case 1202: -#line 3695 "third_party/libpg_query/grammar/statements/select.y" + case 1194: +#line 3653 "third_party/libpg_query/grammar/statements/select.y" { /* not legal per SQL99, but might as well allow it */ (yyval.list) = list_make3((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].node)); ;} break; - case 1203: -#line 3700 "third_party/libpg_query/grammar/statements/select.y" + case 1195: +#line 3658 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ;} break; - case 1204: -#line 3704 "third_party/libpg_query/grammar/statements/select.y" + case 1196: +#line 3662 "third_party/libpg_query/grammar/statements/select.y" { /* * Since there are no cases where this syntax allows @@ -29198,45 +28827,45 @@ YYLTYPE yylloc; ;} break; - case 1205: -#line 3719 "third_party/libpg_query/grammar/statements/select.y" + case 1197: +#line 3677 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1206: -#line 3723 "third_party/libpg_query/grammar/statements/select.y" + case 1198: +#line 3681 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1207: -#line 3727 "third_party/libpg_query/grammar/statements/select.y" + case 1199: +#line 3685 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1208: -#line 3730 "third_party/libpg_query/grammar/statements/select.y" + case 1200: +#line 3688 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1209: -#line 3733 "third_party/libpg_query/grammar/statements/select.y" + case 1201: +#line 3691 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(3) - (3)].list), (yyvsp[(1) - (3)].node)); ;} break; - case 1210: -#line 3734 "third_party/libpg_query/grammar/statements/select.y" + case 1202: +#line 3692 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1211: -#line 3735 "third_party/libpg_query/grammar/statements/select.y" + case 1203: +#line 3693 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1212: -#line 3739 "third_party/libpg_query/grammar/statements/select.y" + case 1204: +#line 3697 "third_party/libpg_query/grammar/statements/select.y" { PGSubLink *n = makeNode(PGSubLink); n->subselect = (yyvsp[(1) - (1)].node); @@ -29245,18 +28874,18 @@ YYLTYPE yylloc; ;} break; - case 1213: -#line 3745 "third_party/libpg_query/grammar/statements/select.y" + case 1205: +#line 3703 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(2) - (3)].list); ;} break; - case 1215: -#line 3747 "third_party/libpg_query/grammar/statements/select.y" + case 1207: +#line 3705 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (PGNode *)(yyvsp[(1) - (1)].node); ;} break; - case 1216: -#line 3758 "third_party/libpg_query/grammar/statements/select.y" + case 1208: +#line 3716 "third_party/libpg_query/grammar/statements/select.y" { PGCaseExpr *c = makeNode(PGCaseExpr); c->casetype = InvalidOid; /* not analyzed yet */ @@ -29268,18 +28897,18 @@ YYLTYPE yylloc; ;} break; - case 1217: -#line 3771 "third_party/libpg_query/grammar/statements/select.y" + case 1209: +#line 3729 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1218: -#line 3772 "third_party/libpg_query/grammar/statements/select.y" + case 1210: +#line 3730 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1219: -#line 3777 "third_party/libpg_query/grammar/statements/select.y" + case 1211: +#line 3735 "third_party/libpg_query/grammar/statements/select.y" { PGCaseWhen *w = makeNode(PGCaseWhen); w->expr = (PGExpr *) (yyvsp[(2) - (4)].node); @@ -29289,59 +28918,59 @@ YYLTYPE yylloc; ;} break; - case 1220: -#line 3787 "third_party/libpg_query/grammar/statements/select.y" + case 1212: +#line 3745 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1221: -#line 3788 "third_party/libpg_query/grammar/statements/select.y" + case 1213: +#line 3746 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1222: -#line 3791 "third_party/libpg_query/grammar/statements/select.y" + case 1214: +#line 3749 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1223: -#line 3792 "third_party/libpg_query/grammar/statements/select.y" + case 1215: +#line 3750 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1224: -#line 3796 "third_party/libpg_query/grammar/statements/select.y" + case 1216: +#line 3754 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1225: -#line 3797 "third_party/libpg_query/grammar/statements/select.y" + case 1217: +#line 3755 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1226: -#line 3801 "third_party/libpg_query/grammar/statements/select.y" + case 1218: +#line 3759 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1227: -#line 3807 "third_party/libpg_query/grammar/statements/select.y" + case 1219: +#line 3765 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (1)].str), NIL, (yylsp[(1) - (1)]), yyscanner); ;} break; - case 1228: -#line 3811 "third_party/libpg_query/grammar/statements/select.y" + case 1220: +#line 3769 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeColumnRef((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].list), (yylsp[(1) - (2)]), yyscanner); ;} break; - case 1229: -#line 3818 "third_party/libpg_query/grammar/statements/select.y" + case 1221: +#line 3776 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -29351,8 +28980,8 @@ YYLTYPE yylloc; ;} break; - case 1230: -#line 3826 "third_party/libpg_query/grammar/statements/select.y" + case 1222: +#line 3784 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29362,8 +28991,8 @@ YYLTYPE yylloc; ;} break; - case 1231: -#line 3833 "third_party/libpg_query/grammar/statements/select.y" + case 1223: +#line 3791 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29374,8 +29003,8 @@ YYLTYPE yylloc; ;} break; - case 1232: -#line 3841 "third_party/libpg_query/grammar/statements/select.y" + case 1224: +#line 3799 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29385,43 +29014,43 @@ YYLTYPE yylloc; ;} break; - case 1233: -#line 3851 "third_party/libpg_query/grammar/statements/select.y" + case 1225: +#line 3809 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1234: -#line 3852 "third_party/libpg_query/grammar/statements/select.y" + case 1226: +#line 3810 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = NULL; ;} break; - case 1235: -#line 3857 "third_party/libpg_query/grammar/statements/select.y" + case 1227: +#line 3815 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1236: -#line 3858 "third_party/libpg_query/grammar/statements/select.y" + case 1228: +#line 3816 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1237: -#line 3862 "third_party/libpg_query/grammar/statements/select.y" + case 1229: +#line 3820 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1238: -#line 3863 "third_party/libpg_query/grammar/statements/select.y" + case 1230: +#line 3821 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(NULL); ;} break; - case 1239: -#line 3864 "third_party/libpg_query/grammar/statements/select.y" + case 1231: +#line 3822 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1240: -#line 3869 "third_party/libpg_query/grammar/statements/select.y" + case 1232: +#line 3827 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(3) - (3)].list)) { PGFuncCall *n = makeFuncCall(list_make1(makeString((yyvsp[(2) - (3)].str))), (yyvsp[(3) - (3)].list)->head->data.ptr_value ? (yyvsp[(3) - (3)].list) : NULL, (yylsp[(2) - (3)])); @@ -29432,8 +29061,8 @@ YYLTYPE yylloc; ;} break; - case 1241: -#line 3878 "third_party/libpg_query/grammar/statements/select.y" + case 1233: +#line 3836 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = false; @@ -29443,8 +29072,8 @@ YYLTYPE yylloc; ;} break; - case 1242: -#line 3886 "third_party/libpg_query/grammar/statements/select.y" + case 1234: +#line 3844 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29454,8 +29083,8 @@ YYLTYPE yylloc; ;} break; - case 1243: -#line 3893 "third_party/libpg_query/grammar/statements/select.y" + case 1235: +#line 3851 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29466,8 +29095,8 @@ YYLTYPE yylloc; ;} break; - case 1244: -#line 3902 "third_party/libpg_query/grammar/statements/select.y" + case 1236: +#line 3860 "third_party/libpg_query/grammar/statements/select.y" { PGAIndices *ai = makeNode(PGAIndices); ai->is_slice = true; @@ -29477,48 +29106,48 @@ YYLTYPE yylloc; ;} break; - case 1245: -#line 3917 "third_party/libpg_query/grammar/statements/select.y" + case 1237: +#line 3875 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1246: -#line 3918 "third_party/libpg_query/grammar/statements/select.y" + case 1238: +#line 3876 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); ;} break; - case 1249: -#line 3934 "third_party/libpg_query/grammar/statements/select.y" + case 1241: +#line 3892 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1250: -#line 3935 "third_party/libpg_query/grammar/statements/select.y" + case 1242: +#line 3893 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1251: -#line 3939 "third_party/libpg_query/grammar/statements/select.y" + case 1243: +#line 3897 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].target)); ;} break; - case 1252: -#line 3940 "third_party/libpg_query/grammar/statements/select.y" + case 1244: +#line 3898 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].target)); ;} break; - case 1253: -#line 3944 "third_party/libpg_query/grammar/statements/select.y" + case 1245: +#line 3902 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1254: -#line 3945 "third_party/libpg_query/grammar/statements/select.y" + case 1246: +#line 3903 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1255: -#line 3949 "third_party/libpg_query/grammar/statements/select.y" + case 1247: +#line 3907 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(3) - (3)].str); @@ -29528,8 +29157,8 @@ YYLTYPE yylloc; ;} break; - case 1256: -#line 3965 "third_party/libpg_query/grammar/statements/select.y" + case 1248: +#line 3923 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = (yyvsp[(2) - (2)].str); @@ -29539,8 +29168,8 @@ YYLTYPE yylloc; ;} break; - case 1257: -#line 3973 "third_party/libpg_query/grammar/statements/select.y" + case 1249: +#line 3931 "third_party/libpg_query/grammar/statements/select.y" { (yyval.target) = makeNode(PGResTarget); (yyval.target)->name = NULL; @@ -29550,225 +29179,140 @@ YYLTYPE yylloc; ;} break; - case 1258: -#line 3981 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.target) = makeNode(PGResTarget); - (yyval.target)->name = (yyvsp[(1) - (3)].str); - (yyval.target)->indirection = NIL; - (yyval.target)->val = (PGNode *)(yyvsp[(3) - (3)].node); - (yyval.target)->location = (yylsp[(1) - (3)]); - ;} - break; - - case 1259: -#line 3990 "third_party/libpg_query/grammar/statements/select.y" + case 1250: +#line 3940 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1260: -#line 3991 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} - break; - - case 1261: -#line 3996 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.list) = list_make1((yyvsp[(1) - (1)].str)); - ;} - break; - - case 1262: -#line 4000 "third_party/libpg_query/grammar/statements/select.y" - { - (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); - ;} - break; - - case 1263: -#line 4006 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} - break; - - case 1264: -#line 4008 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} - break; - - case 1265: -#line 4012 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} - break; - - case 1266: -#line 4013 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (2)].list); ;} + case 1251: +#line 3941 "third_party/libpg_query/grammar/statements/select.y" + { (yyval.list) = list_make1(makeString((yyvsp[(2) - (2)].str))); ;} break; - case 1267: -#line 4017 "third_party/libpg_query/grammar/statements/select.y" + case 1252: +#line 3944 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1268: -#line 4018 "third_party/libpg_query/grammar/statements/select.y" + case 1253: +#line 3945 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1269: -#line 4021 "third_party/libpg_query/grammar/statements/select.y" + case 1254: +#line 3948 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make2((yyvsp[(1) - (3)].node), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1270: -#line 4025 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} - break; - - case 1271: -#line 4026 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} - break; - - case 1272: -#line 4030 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (1)].list); ;} - break; - - case 1273: -#line 4031 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(1) - (2)].list); ;} - break; - - case 1274: -#line 4034 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = (yyvsp[(3) - (4)].list); ;} - break; - - case 1275: -#line 4035 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} - break; - - case 1276: -#line 4036 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = NULL; ;} - break; - - case 1277: -#line 4039 "third_party/libpg_query/grammar/statements/select.y" - { (yyval.list) = list_make2((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].str)); ;} - break; - - case 1278: -#line 4043 "third_party/libpg_query/grammar/statements/select.y" + case 1255: +#line 3952 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].list)); ;} break; - case 1279: -#line 4044 "third_party/libpg_query/grammar/statements/select.y" + case 1256: +#line 3953 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); ;} break; - case 1280: -#line 4048 "third_party/libpg_query/grammar/statements/select.y" + case 1257: +#line 3957 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1281: -#line 4049 "third_party/libpg_query/grammar/statements/select.y" + case 1258: +#line 3958 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1282: -#line 4051 "third_party/libpg_query/grammar/statements/select.y" + case 1259: +#line 3961 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(3) - (4)].list); ;} break; - case 1283: -#line 4052 "third_party/libpg_query/grammar/statements/select.y" + case 1260: +#line 3962 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(2) - (2)].list)); ;} break; - case 1284: -#line 4053 "third_party/libpg_query/grammar/statements/select.y" + case 1261: +#line 3963 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NULL; ;} break; - case 1285: -#line 4063 "third_party/libpg_query/grammar/statements/select.y" + case 1262: +#line 3973 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].range)); ;} break; - case 1286: -#line 4064 "third_party/libpg_query/grammar/statements/select.y" + case 1263: +#line 3974 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].range)); ;} break; - case 1287: -#line 4069 "third_party/libpg_query/grammar/statements/select.y" + case 1264: +#line 3979 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1288: -#line 4071 "third_party/libpg_query/grammar/statements/select.y" + case 1265: +#line 3981 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1289: -#line 4076 "third_party/libpg_query/grammar/statements/select.y" + case 1266: +#line 3986 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1290: -#line 4077 "third_party/libpg_query/grammar/statements/select.y" + case 1267: +#line 3987 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (2)].list); ;} break; - case 1291: -#line 4081 "third_party/libpg_query/grammar/statements/select.y" + case 1268: +#line 3991 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(1) - (1)].list); ;} break; - case 1292: -#line 4082 "third_party/libpg_query/grammar/statements/select.y" + case 1269: +#line 3992 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1293: -#line 4085 "third_party/libpg_query/grammar/statements/select.y" + case 1270: +#line 3995 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1294: -#line 4097 "third_party/libpg_query/grammar/statements/select.y" + case 1271: +#line 4007 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1295: -#line 4100 "third_party/libpg_query/grammar/statements/select.y" + case 1272: +#line 4010 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = check_func_name(lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)), yyscanner); ;} break; - case 1296: -#line 4111 "third_party/libpg_query/grammar/statements/select.y" + case 1273: +#line 4021 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntConst((yyvsp[(1) - (1)].ival), (yylsp[(1) - (1)])); ;} break; - case 1297: -#line 4115 "third_party/libpg_query/grammar/statements/select.y" + case 1274: +#line 4025 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeFloatConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1298: -#line 4119 "third_party/libpg_query/grammar/statements/select.y" + case 1275: +#line 4029 "third_party/libpg_query/grammar/statements/select.y" { if ((yyvsp[(2) - (2)].list)) { @@ -29782,15 +29326,15 @@ YYLTYPE yylloc; ;} break; - case 1299: -#line 4131 "third_party/libpg_query/grammar/statements/select.y" + case 1276: +#line 4041 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBitStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1300: -#line 4135 "third_party/libpg_query/grammar/statements/select.y" + case 1277: +#line 4045 "third_party/libpg_query/grammar/statements/select.y" { /* This is a bit constant per SQL99: * Without Feature F511, "BIT data type", @@ -29801,8 +29345,8 @@ YYLTYPE yylloc; ;} break; - case 1301: -#line 4144 "third_party/libpg_query/grammar/statements/select.y" + case 1278: +#line 4054 "third_party/libpg_query/grammar/statements/select.y" { /* generic type 'literal' syntax */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (2)].list)); @@ -29811,8 +29355,8 @@ YYLTYPE yylloc; ;} break; - case 1302: -#line 4151 "third_party/libpg_query/grammar/statements/select.y" + case 1279: +#line 4061 "third_party/libpg_query/grammar/statements/select.y" { /* generic syntax with a type modifier */ PGTypeName *t = makeTypeNameFromNameList((yyvsp[(1) - (7)].list)); @@ -29852,146 +29396,146 @@ YYLTYPE yylloc; ;} break; - case 1303: -#line 4189 "third_party/libpg_query/grammar/statements/select.y" + case 1280: +#line 4099 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeStringConstCast((yyvsp[(2) - (2)].str), (yylsp[(2) - (2)]), (yyvsp[(1) - (2)].typnam)); ;} break; - case 1304: -#line 4193 "third_party/libpg_query/grammar/statements/select.y" + case 1281: +#line 4103 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(3) - (5)].node), (yylsp[(3) - (5)]), (yyvsp[(5) - (5)].list)); ;} break; - case 1305: -#line 4197 "third_party/libpg_query/grammar/statements/select.y" + case 1282: +#line 4107 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].ival), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1306: -#line 4201 "third_party/libpg_query/grammar/statements/select.y" + case 1283: +#line 4111 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeIntervalNode((yyvsp[(2) - (3)].str), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].list)); ;} break; - case 1307: -#line 4205 "third_party/libpg_query/grammar/statements/select.y" + case 1284: +#line 4115 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(true, (yylsp[(1) - (1)])); ;} break; - case 1308: -#line 4209 "third_party/libpg_query/grammar/statements/select.y" + case 1285: +#line 4119 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeBoolAConst(false, (yylsp[(1) - (1)])); ;} break; - case 1309: -#line 4213 "third_party/libpg_query/grammar/statements/select.y" + case 1286: +#line 4123 "third_party/libpg_query/grammar/statements/select.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1310: -#line 4218 "third_party/libpg_query/grammar/statements/select.y" + case 1287: +#line 4128 "third_party/libpg_query/grammar/statements/select.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1311: -#line 4235 "third_party/libpg_query/grammar/statements/select.y" + case 1288: +#line 4145 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1312: -#line 4236 "third_party/libpg_query/grammar/statements/select.y" + case 1289: +#line 4146 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1313: -#line 4237 "third_party/libpg_query/grammar/statements/select.y" + case 1290: +#line 4147 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1314: -#line 4240 "third_party/libpg_query/grammar/statements/select.y" + case 1291: +#line 4150 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1315: -#line 4241 "third_party/libpg_query/grammar/statements/select.y" + case 1292: +#line 4151 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1316: -#line 4242 "third_party/libpg_query/grammar/statements/select.y" + case 1293: +#line 4152 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1317: -#line 4245 "third_party/libpg_query/grammar/statements/select.y" + case 1294: +#line 4155 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1318: -#line 4246 "third_party/libpg_query/grammar/statements/select.y" + case 1295: +#line 4156 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1319: -#line 4247 "third_party/libpg_query/grammar/statements/select.y" + case 1296: +#line 4157 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1320: -#line 4250 "third_party/libpg_query/grammar/statements/select.y" + case 1297: +#line 4160 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(1) - (1)].str))); ;} break; - case 1321: -#line 4251 "third_party/libpg_query/grammar/statements/select.y" + case 1298: +#line 4161 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lcons(makeString((yyvsp[(1) - (2)].str)), (yyvsp[(2) - (2)].list)); ;} break; - case 1322: -#line 4255 "third_party/libpg_query/grammar/statements/select.y" + case 1299: +#line 4165 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = list_make1(makeString((yyvsp[(2) - (2)].str))); ;} break; - case 1323: -#line 4257 "third_party/libpg_query/grammar/statements/select.y" + case 1300: +#line 4167 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), makeString((yyvsp[(3) - (3)].str))); ;} break; - case 1324: -#line 4261 "third_party/libpg_query/grammar/statements/select.y" + case 1301: +#line 4171 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1325: -#line 4262 "third_party/libpg_query/grammar/statements/select.y" + case 1302: +#line 4172 "third_party/libpg_query/grammar/statements/select.y" { (yyval.list) = NIL; ;} break; - case 1327: -#line 4269 "third_party/libpg_query/grammar/statements/select.y" + case 1304: +#line 4179 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1328: -#line 4270 "third_party/libpg_query/grammar/statements/select.y" + case 1305: +#line 4180 "third_party/libpg_query/grammar/statements/select.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1329: + case 1306: #line 8 "third_party/libpg_query/grammar/statements/prepare.y" { PGPrepareStmt *n = makeNode(PGPrepareStmt); @@ -30002,17 +29546,17 @@ YYLTYPE yylloc; ;} break; - case 1330: + case 1307: #line 18 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = (yyvsp[(2) - (3)].list); ;} break; - case 1331: + case 1308: #line 19 "third_party/libpg_query/grammar/statements/prepare.y" { (yyval.list) = NIL; ;} break; - case 1338: + case 1315: #line 8 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -30034,7 +29578,7 @@ YYLTYPE yylloc; ;} break; - case 1339: + case 1316: #line 27 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -30061,7 +29605,7 @@ YYLTYPE yylloc; ;} break; - case 1340: + case 1317: #line 51 "third_party/libpg_query/grammar/statements/create_schema.y" { PGCreateSchemaStmt *n = makeNode(PGCreateSchemaStmt); @@ -30083,7 +29627,7 @@ YYLTYPE yylloc; ;} break; - case 1341: + case 1318: #line 74 "third_party/libpg_query/grammar/statements/create_schema.y" { if ((yyloc) < 0) /* see comments for YYLLOC_DEFAULT */ @@ -30092,12 +29636,12 @@ YYLTYPE yylloc; ;} break; - case 1342: + case 1319: #line 80 "third_party/libpg_query/grammar/statements/create_schema.y" { (yyval.list) = NIL; ;} break; - case 1347: + case 1324: #line 11 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -30123,7 +29667,7 @@ YYLTYPE yylloc; ;} break; - case 1348: + case 1325: #line 36 "third_party/libpg_query/grammar/statements/index.y" { PGIndexStmt *n = makeNode(PGIndexStmt); @@ -30149,62 +29693,62 @@ YYLTYPE yylloc; ;} break; - case 1349: + case 1326: #line 62 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1350: + case 1327: #line 66 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1351: + case 1328: #line 67 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (char*) DEFAULT_INDEX_TYPE; ;} break; - case 1352: + case 1329: #line 72 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1353: + case 1330: #line 73 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1354: + case 1331: #line 78 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1355: + case 1332: #line 79 "third_party/libpg_query/grammar/statements/index.y" { (yyval.str) = NULL; ;} break; - case 1356: + case 1333: #line 83 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1357: + case 1334: #line 84 "third_party/libpg_query/grammar/statements/index.y" { (yyval.list) = NIL; ;} break; - case 1358: + case 1335: #line 89 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = true; ;} break; - case 1359: + case 1336: #line 90 "third_party/libpg_query/grammar/statements/index.y" { (yyval.boolean) = false; ;} break; - case 1360: + case 1337: #line 8 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30216,7 +29760,7 @@ YYLTYPE yylloc; ;} break; - case 1361: + case 1338: #line 17 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30228,7 +29772,7 @@ YYLTYPE yylloc; ;} break; - case 1362: + case 1339: #line 26 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30240,7 +29784,7 @@ YYLTYPE yylloc; ;} break; - case 1363: + case 1340: #line 35 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30252,7 +29796,7 @@ YYLTYPE yylloc; ;} break; - case 1364: + case 1341: #line 44 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30264,7 +29808,7 @@ YYLTYPE yylloc; ;} break; - case 1365: + case 1342: #line 53 "third_party/libpg_query/grammar/statements/alter_schema.y" { PGAlterObjectSchemaStmt *n = makeNode(PGAlterObjectSchemaStmt); @@ -30276,7 +29820,7 @@ YYLTYPE yylloc; ;} break; - case 1366: + case 1343: #line 6 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -30286,7 +29830,7 @@ YYLTYPE yylloc; ;} break; - case 1367: + case 1344: #line 13 "third_party/libpg_query/grammar/statements/checkpoint.y" { PGCheckPointStmt *n = makeNode(PGCheckPointStmt); @@ -30296,17 +29840,17 @@ YYLTYPE yylloc; ;} break; - case 1368: + case 1345: #line 22 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1369: + case 1346: #line 23 "third_party/libpg_query/grammar/statements/checkpoint.y" { (yyval.str) = NULL; ;} break; - case 1370: + case 1347: #line 8 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -30317,7 +29861,7 @@ YYLTYPE yylloc; ;} break; - case 1371: + case 1348: #line 16 "third_party/libpg_query/grammar/statements/comment_on.y" { PGCommentOnStmt *n = makeNode(PGCommentOnStmt); @@ -30328,67 +29872,67 @@ YYLTYPE yylloc; ;} break; - case 1372: + case 1349: #line 26 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1373: + case 1350: #line 27 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.node) = makeNullAConst((yylsp[(1) - (1)])); ;} break; - case 1374: + case 1351: #line 30 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE; ;} break; - case 1375: + case 1352: #line 31 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SEQUENCE; ;} break; - case 1376: + case 1353: #line 32 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1377: + case 1354: #line 33 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_FUNCTION; ;} break; - case 1378: + case 1355: #line 34 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TABLE_MACRO; ;} break; - case 1379: + case 1356: #line 35 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_VIEW; ;} break; - case 1380: + case 1357: #line 36 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_DATABASE; ;} break; - case 1381: + case 1358: #line 37 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_INDEX; ;} break; - case 1382: + case 1359: #line 38 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_SCHEMA; ;} break; - case 1383: + case 1360: #line 39 "third_party/libpg_query/grammar/statements/comment_on.y" { (yyval.objtype) = PG_OBJECT_TYPE; ;} break; - case 1384: + case 1361: #line 8 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -30402,7 +29946,7 @@ YYLTYPE yylloc; ;} break; - case 1385: + case 1362: #line 20 "third_party/libpg_query/grammar/statements/export.y" { PGExportStmt *n = makeNode(PGExportStmt); @@ -30416,7 +29960,7 @@ YYLTYPE yylloc; ;} break; - case 1386: + case 1363: #line 34 "third_party/libpg_query/grammar/statements/export.y" { PGImportStmt *n = makeNode(PGImportStmt); @@ -30425,7 +29969,7 @@ YYLTYPE yylloc; ;} break; - case 1387: + case 1364: #line 10 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30435,7 +29979,7 @@ YYLTYPE yylloc; ;} break; - case 1388: + case 1365: #line 17 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30448,7 +29992,7 @@ YYLTYPE yylloc; ;} break; - case 1389: + case 1366: #line 27 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30458,7 +30002,7 @@ YYLTYPE yylloc; ;} break; - case 1390: + case 1367: #line 34 "third_party/libpg_query/grammar/statements/explain.y" { PGExplainStmt *n = makeNode(PGExplainStmt); @@ -30468,118 +30012,118 @@ YYLTYPE yylloc; ;} break; - case 1391: + case 1368: #line 44 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = true; ;} break; - case 1392: + case 1369: #line 45 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.boolean) = false; ;} break; - case 1393: + case 1370: #line 50 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) makeString((yyvsp[(1) - (1)].str)); ;} break; - case 1394: + case 1371: #line 51 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = (PGNode *) (yyvsp[(1) - (1)].value); ;} break; - case 1395: + case 1372: #line 52 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.node) = NULL; ;} break; - case 1427: + case 1404: #line 91 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1428: + case 1405: #line 92 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1429: + case 1406: #line 93 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = pstrdup((yyvsp[(1) - (1)].keyword)); ;} break; - case 1430: + case 1407: #line 98 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1431: + case 1408: #line 99 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1432: + case 1409: #line 105 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].defelt)); ;} break; - case 1433: + case 1410: #line 109 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].defelt)); ;} break; - case 1434: + case 1411: #line 116 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1435: + case 1412: #line 117 "third_party/libpg_query/grammar/statements/explain.y" {;} break; - case 1436: + case 1413: #line 122 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "true"; ;} break; - case 1437: + case 1414: #line 123 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "false"; ;} break; - case 1438: + case 1415: #line 124 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "on"; ;} break; - case 1439: + case 1416: #line 130 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1440: + case 1417: #line 136 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.defelt) = makeDefElem((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].node), (yylsp[(1) - (2)])); ;} break; - case 1441: + case 1418: #line 143 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1442: + case 1419: #line 144 "third_party/libpg_query/grammar/statements/explain.y" { (yyval.str) = (char*) "analyze"; ;} break; - case 1443: + case 1420: #line 11 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(2) - (2)].vsetstmt); @@ -30588,7 +30132,7 @@ YYLTYPE yylloc; ;} break; - case 1444: + case 1421: #line 17 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30597,7 +30141,7 @@ YYLTYPE yylloc; ;} break; - case 1445: + case 1422: #line 23 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30606,7 +30150,7 @@ YYLTYPE yylloc; ;} break; - case 1446: + case 1423: #line 29 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30615,7 +30159,7 @@ YYLTYPE yylloc; ;} break; - case 1447: + case 1424: #line 35 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = (yyvsp[(3) - (3)].vsetstmt); @@ -30624,12 +30168,12 @@ YYLTYPE yylloc; ;} break; - case 1448: + case 1425: #line 44 "third_party/libpg_query/grammar/statements/variable_set.y" {(yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt);;} break; - case 1449: + case 1426: #line 46 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30639,7 +30183,7 @@ YYLTYPE yylloc; ;} break; - case 1450: + case 1427: #line 54 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30653,7 +30197,7 @@ YYLTYPE yylloc; ;} break; - case 1451: + case 1428: #line 65 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30664,7 +30208,7 @@ YYLTYPE yylloc; ;} break; - case 1452: + case 1429: #line 77 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30675,7 +30219,7 @@ YYLTYPE yylloc; ;} break; - case 1453: + case 1430: #line 85 "third_party/libpg_query/grammar/statements/variable_set.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -30686,26 +30230,26 @@ YYLTYPE yylloc; ;} break; - case 1454: + case 1431: #line 96 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = (yyvsp[(1) - (1)].node); ;} break; - case 1455: + case 1432: #line 102 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1456: + case 1433: #line 106 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeStringConst((yyvsp[(1) - (1)].str), (yylsp[(1) - (1)])); ;} break; - case 1457: + case 1434: #line 110 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (3)].typnam); @@ -30723,7 +30267,7 @@ YYLTYPE yylloc; ;} break; - case 1458: + case 1435: #line 125 "third_party/libpg_query/grammar/statements/variable_set.y" { PGTypeName *t = (yyvsp[(1) - (5)].typnam); @@ -30733,32 +30277,32 @@ YYLTYPE yylloc; ;} break; - case 1459: + case 1436: #line 131 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = makeAConst((yyvsp[(1) - (1)].value), (yylsp[(1) - (1)])); ;} break; - case 1460: + case 1437: #line 132 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1461: + case 1438: #line 133 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.node) = NULL; ;} break; - case 1462: + case 1439: #line 137 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = list_make1((yyvsp[(1) - (1)].node)); ;} break; - case 1463: + case 1440: #line 138 "third_party/libpg_query/grammar/statements/variable_set.y" { (yyval.list) = lappend((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); ;} break; - case 1464: + case 1441: #line 8 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30771,7 +30315,7 @@ YYLTYPE yylloc; ;} break; - case 1465: + case 1442: #line 17 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30784,7 +30328,7 @@ YYLTYPE yylloc; ;} break; - case 1466: + case 1443: #line 26 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30797,7 +30341,7 @@ YYLTYPE yylloc; ;} break; - case 1467: + case 1444: #line 35 "third_party/libpg_query/grammar/statements/load.y" { PGLoadStmt *n = makeNode(PGLoadStmt); @@ -30810,42 +30354,42 @@ YYLTYPE yylloc; ;} break; - case 1468: + case 1445: #line 46 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_INSTALL; ;} break; - case 1469: + case 1446: #line 47 "third_party/libpg_query/grammar/statements/load.y" { (yyval.loadinstalltype) = PG_LOAD_TYPE_FORCE_INSTALL; ;} break; - case 1470: + case 1447: #line 49 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1471: + case 1448: #line 50 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1472: + case 1449: #line 53 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = NULL; ;} break; - case 1473: + case 1450: #line 54 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1474: + case 1451: #line 55 "third_party/libpg_query/grammar/statements/load.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1475: + case 1452: #line 9 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30862,7 +30406,7 @@ YYLTYPE yylloc; ;} break; - case 1476: + case 1453: #line 23 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30879,7 +30423,7 @@ YYLTYPE yylloc; ;} break; - case 1477: + case 1454: #line 37 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = (PGVacuumStmt *) (yyvsp[(5) - (5)].node); @@ -30894,7 +30438,7 @@ YYLTYPE yylloc; ;} break; - case 1478: + case 1455: #line 49 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30905,7 +30449,7 @@ YYLTYPE yylloc; ;} break; - case 1479: + case 1456: #line 57 "third_party/libpg_query/grammar/statements/vacuum.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -30918,27 +30462,27 @@ YYLTYPE yylloc; ;} break; - case 1480: + case 1457: #line 70 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_ANALYZE; ;} break; - case 1481: + case 1458: #line 71 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_VERBOSE; ;} break; - case 1482: + case 1459: #line 72 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FREEZE; ;} break; - case 1483: + case 1460: #line 73 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = PG_VACOPT_FULL; ;} break; - case 1484: + case 1461: #line 75 "third_party/libpg_query/grammar/statements/vacuum.y" { if (strcmp((yyvsp[(1) - (1)].str), "disable_page_skipping") == 0) @@ -30951,37 +30495,37 @@ YYLTYPE yylloc; ;} break; - case 1485: + case 1462: #line 87 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1486: + case 1463: #line 88 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1487: + case 1464: #line 93 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (1)].ival); ;} break; - case 1488: + case 1465: #line 94 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.ival) = (yyvsp[(1) - (3)].ival) | (yyvsp[(3) - (3)].ival); ;} break; - case 1489: + case 1466: #line 98 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = true; ;} break; - case 1490: + case 1467: #line 99 "third_party/libpg_query/grammar/statements/vacuum.y" { (yyval.boolean) = false; ;} break; - case 1491: + case 1468: #line 9 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -30994,7 +30538,7 @@ YYLTYPE yylloc; ;} break; - case 1492: + case 1469: #line 19 "third_party/libpg_query/grammar/statements/delete.y" { PGDeleteStmt *n = makeNode(PGDeleteStmt); @@ -31007,14 +30551,14 @@ YYLTYPE yylloc; ;} break; - case 1493: + case 1470: #line 32 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.range) = (yyvsp[(1) - (1)].range); ;} break; - case 1494: + case 1471: #line 36 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -31024,7 +30568,7 @@ YYLTYPE yylloc; ;} break; - case 1495: + case 1472: #line 43 "third_party/libpg_query/grammar/statements/delete.y" { PGAlias *alias = makeNode(PGAlias); @@ -31034,27 +30578,27 @@ YYLTYPE yylloc; ;} break; - case 1496: + case 1473: #line 53 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; - case 1497: + case 1474: #line 54 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.node) = NULL; ;} break; - case 1498: + case 1475: #line 60 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = (yyvsp[(2) - (2)].list); ;} break; - case 1499: + case 1476: #line 61 "third_party/libpg_query/grammar/statements/delete.y" { (yyval.list) = NIL; ;} break; - case 1500: + case 1477: #line 10 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -31067,7 +30611,7 @@ YYLTYPE yylloc; ;} break; - case 1501: + case 1478: #line 20 "third_party/libpg_query/grammar/statements/analyze.y" { PGVacuumStmt *n = makeNode(PGVacuumStmt); @@ -31080,7 +30624,7 @@ YYLTYPE yylloc; ;} break; - case 1502: + case 1479: #line 8 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -31092,7 +30636,7 @@ YYLTYPE yylloc; ;} break; - case 1503: + case 1480: #line 17 "third_party/libpg_query/grammar/statements/attach.y" { PGAttachStmt *n = makeNode(PGAttachStmt); @@ -31104,7 +30648,7 @@ YYLTYPE yylloc; ;} break; - case 1504: + case 1481: #line 29 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -31114,7 +30658,7 @@ YYLTYPE yylloc; ;} break; - case 1505: + case 1482: #line 36 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -31124,7 +30668,7 @@ YYLTYPE yylloc; ;} break; - case 1506: + case 1483: #line 43 "third_party/libpg_query/grammar/statements/attach.y" { PGDetachStmt *n = makeNode(PGDetachStmt); @@ -31134,27 +30678,27 @@ YYLTYPE yylloc; ;} break; - case 1507: + case 1484: #line 51 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1508: + case 1485: #line 52 "third_party/libpg_query/grammar/statements/attach.y" {;} break; - case 1509: + case 1486: #line 56 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = (yyvsp[(2) - (2)].str); ;} break; - case 1510: + case 1487: #line 57 "third_party/libpg_query/grammar/statements/attach.y" { (yyval.str) = NULL; ;} break; - case 1511: + case 1488: #line 3 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(2) - (2)].vsetstmt)->scope = VAR_SET_SCOPE_DEFAULT; @@ -31162,7 +30706,7 @@ YYLTYPE yylloc; ;} break; - case 1512: + case 1489: #line 8 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_LOCAL; @@ -31170,7 +30714,7 @@ YYLTYPE yylloc; ;} break; - case 1513: + case 1490: #line 13 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_SESSION; @@ -31178,7 +30722,7 @@ YYLTYPE yylloc; ;} break; - case 1514: + case 1491: #line 18 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_GLOBAL; @@ -31186,7 +30730,7 @@ YYLTYPE yylloc; ;} break; - case 1515: + case 1492: #line 23 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyvsp[(3) - (3)].vsetstmt)->scope = VAR_SET_SCOPE_VARIABLE; @@ -31194,7 +30738,7 @@ YYLTYPE yylloc; ;} break; - case 1516: + case 1493: #line 32 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31204,7 +30748,7 @@ YYLTYPE yylloc; ;} break; - case 1517: + case 1494: #line 39 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31213,12 +30757,12 @@ YYLTYPE yylloc; ;} break; - case 1518: + case 1495: #line 48 "third_party/libpg_query/grammar/statements/variable_reset.y" { (yyval.vsetstmt) = (yyvsp[(1) - (1)].vsetstmt); ;} break; - case 1519: + case 1496: #line 50 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31228,7 +30772,7 @@ YYLTYPE yylloc; ;} break; - case 1520: + case 1497: #line 57 "third_party/libpg_query/grammar/statements/variable_reset.y" { PGVariableSetStmt *n = makeNode(PGVariableSetStmt); @@ -31238,7 +30782,7 @@ YYLTYPE yylloc; ;} break; - case 1521: + case 1498: #line 3 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -31249,7 +30793,7 @@ YYLTYPE yylloc; ;} break; - case 1522: + case 1499: #line 10 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowSelectStmt *n = makeNode(PGVariableShowSelectStmt); @@ -31260,77 +30804,87 @@ YYLTYPE yylloc; ;} break; - case 1523: + case 1500: #line 18 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->relation = (yyvsp[(2) - (2)].range); + n->name = (yyvsp[(2) - (2)].str); n->is_summary = 1; (yyval.node) = (PGNode *) n; ;} break; - case 1524: + case 1501: #line 25 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->relation = (yyvsp[(2) - (2)].range); + n->name = (yyvsp[(2) - (2)].str); n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1525: + case 1502: #line 32 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->set = (char*) "timezone"; + n->name = (char*) "timezone"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1526: + case 1503: #line 39 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->set = (char*) "transaction_isolation"; + n->name = (char*) "transaction_isolation"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1527: + case 1504: #line 46 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->set = (char*) "__show_tables_expanded"; + n->name = (char*) "__show_tables_expanded"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1528: + case 1505: #line 53 "third_party/libpg_query/grammar/statements/variable_show.y" { PGVariableShowStmt *n = makeNode(PGVariableShowStmt); - n->set = (char*) "__show_tables_expanded"; + n->name = (char*) "__show_tables_expanded"; n->is_summary = 0; (yyval.node) = (PGNode *) n; ;} break; - case 1535: + case 1512: #line 67 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 1536: + case 1513: #line 69 "third_party/libpg_query/grammar/statements/variable_show.y" { (yyval.str) = psprintf("%s.%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;} break; - case 1537: + case 1514: +#line 72 "third_party/libpg_query/grammar/statements/variable_show.y" + { (yyval.str) = psprintf("\"%s\"", (yyvsp[(1) - (1)].str)); ;} + break; + + case 1515: +#line 74 "third_party/libpg_query/grammar/statements/variable_show.y" + { (yyval.str) = psprintf("%s.\"%s\"", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ;} + break; + + case 1516: #line 7 "third_party/libpg_query/grammar/statements/call.y" { PGCallStmt *n = makeNode(PGCallStmt); @@ -31339,7 +30893,7 @@ YYLTYPE yylloc; ;} break; - case 1538: + case 1517: #line 10 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -31354,7 +30908,7 @@ YYLTYPE yylloc; ;} break; - case 1539: + case 1518: #line 23 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -31369,7 +30923,7 @@ YYLTYPE yylloc; ;} break; - case 1540: + case 1519: #line 36 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -31384,7 +30938,7 @@ YYLTYPE yylloc; ;} break; - case 1541: + case 1520: #line 49 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -31404,7 +30958,7 @@ YYLTYPE yylloc; ;} break; - case 1542: + case 1521: #line 67 "third_party/libpg_query/grammar/statements/view.y" { PGViewStmt *n = makeNode(PGViewStmt); @@ -31424,27 +30978,27 @@ YYLTYPE yylloc; ;} break; - case 1543: + case 1522: #line 87 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1544: + case 1523: #line 88 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = CASCADED_CHECK_OPTION; ;} break; - case 1545: + case 1524: #line 89 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_LOCAL_CHECK_OPTION; ;} break; - case 1546: + case 1525: #line 90 "third_party/libpg_query/grammar/statements/view.y" { (yyval.viewcheckoption) = PG_NO_CHECK_OPTION; ;} break; - case 1547: + case 1526: #line 12 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31460,7 +31014,7 @@ YYLTYPE yylloc; ;} break; - case 1548: + case 1527: #line 25 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31476,7 +31030,7 @@ YYLTYPE yylloc; ;} break; - case 1549: + case 1528: #line 38 "third_party/libpg_query/grammar/statements/create_as.y" { PGCreateTableAsStmt *ctas = makeNode(PGCreateTableAsStmt); @@ -31492,22 +31046,22 @@ YYLTYPE yylloc; ;} break; - case 1550: + case 1529: #line 54 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1551: + case 1530: #line 55 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = false; ;} break; - case 1552: + case 1531: #line 56 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.boolean) = true; ;} break; - case 1553: + case 1532: #line 62 "third_party/libpg_query/grammar/statements/create_as.y" { (yyval.into) = makeNode(PGIntoClause); @@ -31522,7 +31076,7 @@ YYLTYPE yylloc; /* Line 1267 of yacc.c. */ -#line 31526 "third_party/libpg_query/grammar/grammar_out.cpp" +#line 31080 "third_party/libpg_query/grammar/grammar_out.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -31905,10 +31459,10 @@ makeIntervalNode(PGNode *arg, int location, PGList *typmods) { } static PGNode * -makeSampleSize(PGNode *sample_size, bool is_percentage) { +makeSampleSize(PGValue *sample_size, bool is_percentage) { PGSampleSize *n = makeNode(PGSampleSize); - n->sample_size = sample_size; + n->sample_size = *sample_size; n->is_percentage = is_percentage; return (PGNode *)n; diff --git a/src/duckdb/third_party/parquet/parquet_constants.cpp b/src/duckdb/third_party/parquet/parquet_constants.cpp new file mode 100644 index 000000000..de4420ba0 --- /dev/null +++ b/src/duckdb/third_party/parquet/parquet_constants.cpp @@ -0,0 +1,17 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#include "parquet_constants.h" + +namespace duckdb_parquet { namespace format { + +const parquetConstants g_parquet_constants; + +parquetConstants::parquetConstants() { +} + +}} // namespace + diff --git a/src/duckdb/third_party/parquet/parquet_constants.h b/src/duckdb/third_party/parquet/parquet_constants.h new file mode 100644 index 000000000..468309ce8 --- /dev/null +++ b/src/duckdb/third_party/parquet/parquet_constants.h @@ -0,0 +1,24 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +#ifndef parquet_CONSTANTS_H +#define parquet_CONSTANTS_H + +#include "parquet_types.h" + +namespace duckdb_parquet { namespace format { + +class parquetConstants { + public: + parquetConstants(); + +}; + +extern const parquetConstants g_parquet_constants; + +}} // namespace + +#endif diff --git a/src/duckdb/third_party/parquet/parquet_types.cpp b/src/duckdb/third_party/parquet/parquet_types.cpp index cd989782f..746965f83 100644 --- a/src/duckdb/third_party/parquet/parquet_types.cpp +++ b/src/duckdb/third_party/parquet/parquet_types.cpp @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.21.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -9,812 +9,244 @@ #include #include -#include - -namespace duckdb_parquet { - -int _kTypeValues[] = { - Type::BOOLEAN, - Type::INT32, - Type::INT64, - Type::INT96, - Type::FLOAT, - Type::DOUBLE, - Type::BYTE_ARRAY, - Type::FIXED_LEN_BYTE_ARRAY -}; -const char* _kTypeNames[] = { - "BOOLEAN", - "INT32", - "INT64", - "INT96", - "FLOAT", - "DOUBLE", - "BYTE_ARRAY", - "FIXED_LEN_BYTE_ARRAY" -}; -const std::map _Type_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(8, _kTypeValues, _kTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const Type::type& val) { - std::map::const_iterator it = _Type_VALUES_TO_NAMES.find(val); - if (it != _Type_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const Type::type& val) { - std::map::const_iterator it = _Type_VALUES_TO_NAMES.find(val); - if (it != _Type_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kConvertedTypeValues[] = { - /** - * a BYTE_ARRAY actually contains UTF8 encoded chars - */ - ConvertedType::UTF8, - /** - * a map is converted as an optional field containing a repeated key/value pair - */ - ConvertedType::MAP, - /** - * a key/value pair is converted into a group of two fields - */ - ConvertedType::MAP_KEY_VALUE, - /** - * a list is converted into an optional field containing a repeated field for its - * values - */ - ConvertedType::LIST, - /** - * an enum is converted into a BYTE_ARRAY field - */ - ConvertedType::ENUM, - /** - * A decimal value. - * - * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive - * types. The underlying byte array stores the unscaled value encoded as two's - * complement using big-endian byte order (the most significant byte is the - * zeroth element). The value of the decimal is the value * 10^{-scale}. - * - * This must be accompanied by a (maximum) precision and a scale in the - * SchemaElement. The precision specifies the number of digits in the decimal - * and the scale stores the location of the decimal point. For example 1.23 - * would have precision 3 (3 total digits) and scale 2 (the decimal point is - * 2 digits over). - */ - ConvertedType::DECIMAL, - /** - * A Date - * - * Stored as days since Unix epoch, encoded as the INT32 physical type. - * - */ - ConvertedType::DATE, - /** - * A time - * - * The total number of milliseconds since midnight. The value is stored - * as an INT32 physical type. - */ - ConvertedType::TIME_MILLIS, - /** - * A time. - * - * The total number of microseconds since midnight. The value is stored as - * an INT64 physical type. - */ - ConvertedType::TIME_MICROS, - /** - * A date/time combination - * - * Date and time recorded as milliseconds since the Unix epoch. Recorded as - * a physical type of INT64. - */ - ConvertedType::TIMESTAMP_MILLIS, - /** - * A date/time combination - * - * Date and time recorded as microseconds since the Unix epoch. The value is - * stored as an INT64 physical type. - */ - ConvertedType::TIMESTAMP_MICROS, - /** - * An unsigned integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ - ConvertedType::UINT_8, - ConvertedType::UINT_16, - ConvertedType::UINT_32, - ConvertedType::UINT_64, - /** - * A signed integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ - ConvertedType::INT_8, - ConvertedType::INT_16, - ConvertedType::INT_32, - ConvertedType::INT_64, - /** - * An embedded JSON document - * - * A JSON document embedded within a single UTF8 column. - */ - ConvertedType::JSON, - /** - * An embedded BSON document - * - * A BSON document embedded within a single BYTE_ARRAY column. - */ - ConvertedType::BSON, - /** - * An interval of time - * - * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 - * This data is composed of three separate little endian unsigned - * integers. Each stores a component of a duration of time. The first - * integer identifies the number of months associated with the duration, - * the second identifies the number of days associated with the duration - * and the third identifies the number of milliseconds associated with - * the provided duration. This duration of time is independent of any - * particular timezone or date. - */ - ConvertedType::INTERVAL -}; -const char* _kConvertedTypeNames[] = { - /** - * a BYTE_ARRAY actually contains UTF8 encoded chars - */ - "UTF8", - /** - * a map is converted as an optional field containing a repeated key/value pair - */ - "MAP", - /** - * a key/value pair is converted into a group of two fields - */ - "MAP_KEY_VALUE", - /** - * a list is converted into an optional field containing a repeated field for its - * values - */ - "LIST", - /** - * an enum is converted into a BYTE_ARRAY field - */ - "ENUM", - /** - * A decimal value. - * - * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive - * types. The underlying byte array stores the unscaled value encoded as two's - * complement using big-endian byte order (the most significant byte is the - * zeroth element). The value of the decimal is the value * 10^{-scale}. - * - * This must be accompanied by a (maximum) precision and a scale in the - * SchemaElement. The precision specifies the number of digits in the decimal - * and the scale stores the location of the decimal point. For example 1.23 - * would have precision 3 (3 total digits) and scale 2 (the decimal point is - * 2 digits over). - */ - "DECIMAL", - /** - * A Date - * - * Stored as days since Unix epoch, encoded as the INT32 physical type. - * - */ - "DATE", - /** - * A time - * - * The total number of milliseconds since midnight. The value is stored - * as an INT32 physical type. - */ - "TIME_MILLIS", - /** - * A time. - * - * The total number of microseconds since midnight. The value is stored as - * an INT64 physical type. - */ - "TIME_MICROS", - /** - * A date/time combination - * - * Date and time recorded as milliseconds since the Unix epoch. Recorded as - * a physical type of INT64. - */ - "TIMESTAMP_MILLIS", - /** - * A date/time combination - * - * Date and time recorded as microseconds since the Unix epoch. The value is - * stored as an INT64 physical type. - */ - "TIMESTAMP_MICROS", - /** - * An unsigned integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ - "UINT_8", - "UINT_16", - "UINT_32", - "UINT_64", - /** - * A signed integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ - "INT_8", - "INT_16", - "INT_32", - "INT_64", - /** - * An embedded JSON document - * - * A JSON document embedded within a single UTF8 column. - */ - "JSON", - /** - * An embedded BSON document - * - * A BSON document embedded within a single BYTE_ARRAY column. - */ - "BSON", - /** - * An interval of time - * - * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 - * This data is composed of three separate little endian unsigned - * integers. Each stores a component of a duration of time. The first - * integer identifies the number of months associated with the duration, - * the second identifies the number of days associated with the duration - * and the third identifies the number of milliseconds associated with - * the provided duration. This duration of time is independent of any - * particular timezone or date. - */ - "INTERVAL" -}; -const std::map _ConvertedType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(22, _kConvertedTypeValues, _kConvertedTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val) { - std::map::const_iterator it = _ConvertedType_VALUES_TO_NAMES.find(val); - if (it != _ConvertedType_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const ConvertedType::type& val) { - std::map::const_iterator it = _ConvertedType_VALUES_TO_NAMES.find(val); - if (it != _ConvertedType_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kFieldRepetitionTypeValues[] = { - /** - * This field is required (can not be null) and each row has exactly 1 value. - */ - FieldRepetitionType::REQUIRED, - /** - * The field is optional (can be null) and each row has 0 or 1 values. - */ - FieldRepetitionType::OPTIONAL, - /** - * The field is repeated and can contain 0 or more values - */ - FieldRepetitionType::REPEATED -}; -const char* _kFieldRepetitionTypeNames[] = { - /** - * This field is required (can not be null) and each row has exactly 1 value. - */ - "REQUIRED", - /** - * The field is optional (can be null) and each row has 0 or 1 values. - */ - "OPTIONAL", - /** - * The field is repeated and can contain 0 or more values - */ - "REPEATED" -}; -const std::map _FieldRepetitionType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(3, _kFieldRepetitionTypeValues, _kFieldRepetitionTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const FieldRepetitionType::type& val) { - std::map::const_iterator it = _FieldRepetitionType_VALUES_TO_NAMES.find(val); - if (it != _FieldRepetitionType_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const FieldRepetitionType::type& val) { - std::map::const_iterator it = _FieldRepetitionType_VALUES_TO_NAMES.find(val); - if (it != _FieldRepetitionType_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kEncodingValues[] = { - /** - * Default encoding. - * BOOLEAN - 1 bit per value. 0 is false; 1 is true. - * INT32 - 4 bytes per value. Stored as little-endian. - * INT64 - 8 bytes per value. Stored as little-endian. - * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. - * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. - * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. - * FIXED_LEN_BYTE_ARRAY - Just the bytes. - */ - Encoding::PLAIN, - /** - * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the - * plain type. - * in a data page use RLE_DICTIONARY instead. - * in a Dictionary page use PLAIN instead - */ - Encoding::PLAIN_DICTIONARY, - /** - * Group packed run length encoding. Usable for definition/repetition levels - * encoding and Booleans (on one bit: 0 is false; 1 is true.) - */ - Encoding::RLE, - /** - * Bit packed encoding. This can only be used if the data has a known max - * width. Usable for definition/repetition levels encoding. - */ - Encoding::BIT_PACKED, - /** - * Delta encoding for integers. This can be used for int columns and works best - * on sorted data - */ - Encoding::DELTA_BINARY_PACKED, - /** - * Encoding for byte arrays to separate the length values and the data. The lengths - * are encoded using DELTA_BINARY_PACKED - */ - Encoding::DELTA_LENGTH_BYTE_ARRAY, - /** - * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. - * Suffixes are stored as delta length byte arrays. - */ - Encoding::DELTA_BYTE_ARRAY, - /** - * Dictionary encoding: the ids are encoded using the RLE encoding - */ - Encoding::RLE_DICTIONARY, - /** - * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). - * K byte-streams are created where K is the size in bytes of the data type. - * The individual bytes of a value are scattered to the corresponding stream and - * the streams are concatenated. - * This itself does not reduce the size of the data but can lead to better compression - * afterwards. - * - * Added in 2.8 for FLOAT and DOUBLE. - * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. - */ - Encoding::BYTE_STREAM_SPLIT -}; -const char* _kEncodingNames[] = { - /** - * Default encoding. - * BOOLEAN - 1 bit per value. 0 is false; 1 is true. - * INT32 - 4 bytes per value. Stored as little-endian. - * INT64 - 8 bytes per value. Stored as little-endian. - * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. - * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. - * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. - * FIXED_LEN_BYTE_ARRAY - Just the bytes. - */ - "PLAIN", - /** - * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the - * plain type. - * in a data page use RLE_DICTIONARY instead. - * in a Dictionary page use PLAIN instead - */ - "PLAIN_DICTIONARY", - /** - * Group packed run length encoding. Usable for definition/repetition levels - * encoding and Booleans (on one bit: 0 is false; 1 is true.) - */ - "RLE", - /** - * Bit packed encoding. This can only be used if the data has a known max - * width. Usable for definition/repetition levels encoding. - */ - "BIT_PACKED", - /** - * Delta encoding for integers. This can be used for int columns and works best - * on sorted data - */ - "DELTA_BINARY_PACKED", - /** - * Encoding for byte arrays to separate the length values and the data. The lengths - * are encoded using DELTA_BINARY_PACKED - */ - "DELTA_LENGTH_BYTE_ARRAY", - /** - * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. - * Suffixes are stored as delta length byte arrays. - */ - "DELTA_BYTE_ARRAY", - /** - * Dictionary encoding: the ids are encoded using the RLE encoding - */ - "RLE_DICTIONARY", - /** - * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). - * K byte-streams are created where K is the size in bytes of the data type. - * The individual bytes of a value are scattered to the corresponding stream and - * the streams are concatenated. - * This itself does not reduce the size of the data but can lead to better compression - * afterwards. - * - * Added in 2.8 for FLOAT and DOUBLE. - * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. - */ - "BYTE_STREAM_SPLIT" -}; -const std::map _Encoding_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(9, _kEncodingValues, _kEncodingNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const Encoding::type& val) { - std::map::const_iterator it = _Encoding_VALUES_TO_NAMES.find(val); - if (it != _Encoding_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const Encoding::type& val) { - std::map::const_iterator it = _Encoding_VALUES_TO_NAMES.find(val); - if (it != _Encoding_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kCompressionCodecValues[] = { - CompressionCodec::UNCOMPRESSED, - CompressionCodec::SNAPPY, - CompressionCodec::GZIP, - CompressionCodec::LZO, - CompressionCodec::BROTLI, - CompressionCodec::LZ4, - CompressionCodec::ZSTD, - CompressionCodec::LZ4_RAW -}; -const char* _kCompressionCodecNames[] = { - "UNCOMPRESSED", - "SNAPPY", - "GZIP", - "LZO", - "BROTLI", - "LZ4", - "ZSTD", - "LZ4_RAW" -}; -const std::map _CompressionCodec_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(8, _kCompressionCodecValues, _kCompressionCodecNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val) { - std::map::const_iterator it = _CompressionCodec_VALUES_TO_NAMES.find(val); - if (it != _CompressionCodec_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const CompressionCodec::type& val) { - std::map::const_iterator it = _CompressionCodec_VALUES_TO_NAMES.find(val); - if (it != _CompressionCodec_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kPageTypeValues[] = { - PageType::DATA_PAGE, - PageType::INDEX_PAGE, - PageType::DICTIONARY_PAGE, - PageType::DATA_PAGE_V2 -}; -const char* _kPageTypeNames[] = { - "DATA_PAGE", - "INDEX_PAGE", - "DICTIONARY_PAGE", - "DATA_PAGE_V2" -}; -const std::map _PageType_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(4, _kPageTypeValues, _kPageTypeNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const PageType::type& val) { - std::map::const_iterator it = _PageType_VALUES_TO_NAMES.find(val); - if (it != _PageType_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const PageType::type& val) { - std::map::const_iterator it = _PageType_VALUES_TO_NAMES.find(val); - if (it != _PageType_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - -int _kBoundaryOrderValues[] = { - BoundaryOrder::UNORDERED, - BoundaryOrder::ASCENDING, - BoundaryOrder::DESCENDING -}; -const char* _kBoundaryOrderNames[] = { - "UNORDERED", - "ASCENDING", - "DESCENDING" -}; -const std::map _BoundaryOrder_VALUES_TO_NAMES(::apache::thrift::TEnumIterator(3, _kBoundaryOrderValues, _kBoundaryOrderNames), ::apache::thrift::TEnumIterator(-1, nullptr, nullptr)); - -std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val) { - std::map::const_iterator it = _BoundaryOrder_VALUES_TO_NAMES.find(val); - if (it != _BoundaryOrder_VALUES_TO_NAMES.end()) { - out << it->second; - } else { - out << static_cast(val); - } - return out; -} - -std::string to_string(const BoundaryOrder::type& val) { - std::map::const_iterator it = _BoundaryOrder_VALUES_TO_NAMES.find(val); - if (it != _BoundaryOrder_VALUES_TO_NAMES.end()) { - return std::string(it->second); - } else { - return std::to_string(static_cast(val)); - } -} - - -SizeStatistics::~SizeStatistics() noexcept { -} - -SizeStatistics::SizeStatistics() noexcept - : unencoded_byte_array_data_bytes(0) { -} - -void SizeStatistics::__set_unencoded_byte_array_data_bytes(const int64_t val) { - this->unencoded_byte_array_data_bytes = val; -__isset.unencoded_byte_array_data_bytes = true; -} - -void SizeStatistics::__set_repetition_level_histogram(const duckdb::vector & val) { - this->repetition_level_histogram = val; -__isset.repetition_level_histogram = true; -} - -void SizeStatistics::__set_definition_level_histogram(const duckdb::vector & val) { - this->definition_level_histogram = val; -__isset.definition_level_histogram = true; -} -std::ostream& operator<<(std::ostream& out, const SizeStatistics& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t SizeStatistics::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - switch (fid) - { - case 1: - if (ftype == ::apache::thrift::protocol::T_I64) { - xfer += iprot->readI64(this->unencoded_byte_array_data_bytes); - this->__isset.unencoded_byte_array_data_bytes = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 2: - if (ftype == ::apache::thrift::protocol::T_LIST) { - { - this->repetition_level_histogram.clear(); - uint32_t _size0; - ::apache::thrift::protocol::TType _etype3; - xfer += iprot->readListBegin(_etype3, _size0); - this->repetition_level_histogram.resize(_size0); - uint32_t _i4; - for (_i4 = 0; _i4 < _size0; ++_i4) - { - xfer += iprot->readI64(this->repetition_level_histogram[_i4]); - } - xfer += iprot->readListEnd(); - } - this->__isset.repetition_level_histogram = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 3: - if (ftype == ::apache::thrift::protocol::T_LIST) { - { - this->definition_level_histogram.clear(); - uint32_t _size5; - ::apache::thrift::protocol::TType _etype8; - xfer += iprot->readListBegin(_etype8, _size5); - this->definition_level_histogram.resize(_size5); - uint32_t _i9; - for (_i9 = 0; _i9 < _size5; ++_i9) - { - xfer += iprot->readI64(this->definition_level_histogram[_i9]); - } - xfer += iprot->readListEnd(); - } - this->__isset.definition_level_histogram = true; - } else { - xfer += iprot->skip(ftype); - } - break; - default: - xfer += iprot->skip(ftype); - break; - } - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t SizeStatistics::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("SizeStatistics"); - - if (this->__isset.unencoded_byte_array_data_bytes) { - xfer += oprot->writeFieldBegin("unencoded_byte_array_data_bytes", ::apache::thrift::protocol::T_I64, 1); - xfer += oprot->writeI64(this->unencoded_byte_array_data_bytes); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.repetition_level_histogram) { - xfer += oprot->writeFieldBegin("repetition_level_histogram", ::apache::thrift::protocol::T_LIST, 2); - { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->repetition_level_histogram.size())); - duckdb::vector ::const_iterator _iter10; - for (_iter10 = this->repetition_level_histogram.begin(); _iter10 != this->repetition_level_histogram.end(); ++_iter10) - { - xfer += oprot->writeI64((*_iter10)); - } - xfer += oprot->writeListEnd(); - } - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.definition_level_histogram) { - xfer += oprot->writeFieldBegin("definition_level_histogram", ::apache::thrift::protocol::T_LIST, 3); - { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->definition_level_histogram.size())); - duckdb::vector ::const_iterator _iter11; - for (_iter11 = this->definition_level_histogram.begin(); _iter11 != this->definition_level_histogram.end(); ++_iter11) - { - xfer += oprot->writeI64((*_iter11)); - } - xfer += oprot->writeListEnd(); - } - xfer += oprot->writeFieldEnd(); - } - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(SizeStatistics &a, SizeStatistics &b) { - using ::std::swap; - swap(a.unencoded_byte_array_data_bytes, b.unencoded_byte_array_data_bytes); - swap(a.repetition_level_histogram, b.repetition_level_histogram); - swap(a.definition_level_histogram, b.definition_level_histogram); - swap(a.__isset, b.__isset); -} - -SizeStatistics::SizeStatistics(const SizeStatistics& other12) { - unencoded_byte_array_data_bytes = other12.unencoded_byte_array_data_bytes; - repetition_level_histogram = other12.repetition_level_histogram; - definition_level_histogram = other12.definition_level_histogram; - __isset = other12.__isset; -} -SizeStatistics& SizeStatistics::operator=(const SizeStatistics& other13) { - unencoded_byte_array_data_bytes = other13.unencoded_byte_array_data_bytes; - repetition_level_histogram = other13.repetition_level_histogram; - definition_level_histogram = other13.definition_level_histogram; - __isset = other13.__isset; - return *this; -} -void SizeStatistics::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "SizeStatistics("; - out << "unencoded_byte_array_data_bytes="; (__isset.unencoded_byte_array_data_bytes ? (out << to_string(unencoded_byte_array_data_bytes)) : (out << "")); - out << ", " << "repetition_level_histogram="; (__isset.repetition_level_histogram ? (out << to_string(repetition_level_histogram)) : (out << "")); - out << ", " << "definition_level_histogram="; (__isset.definition_level_histogram ? (out << to_string(definition_level_histogram)) : (out << "")); - out << ")"; -} - - -Statistics::~Statistics() noexcept { +#include "thrift/TToString.h" + +namespace duckdb_parquet { namespace format { + +std::ostream &operator<<(std::ostream &out, const Type::type &val) { + switch (val) { + case Type::BOOLEAN: + out << "BOOLEAN"; + return out; + case Type::INT32: + out << "INT32"; + return out; + case Type::INT64: + out << "INT64"; + return out; + case Type::INT96: + out << "INT96"; + return out; + case Type::FLOAT: + out << "FLOAT"; + return out; + case Type::DOUBLE: + out << "DOUBLE"; + return out; + case Type::BYTE_ARRAY: + out << "BYTE_ARRAY"; + return out; + case Type::FIXED_LEN_BYTE_ARRAY: + out << "FIXED_LEN_BYTE_ARRAY"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const ConvertedType::type &val) { + switch (val) { + case ConvertedType::UTF8: + out << "UTF8"; + return out; + case ConvertedType::MAP: + out << "MAP"; + return out; + case ConvertedType::MAP_KEY_VALUE: + out << "MAP_KEY_VALUE"; + return out; + case ConvertedType::LIST: + out << "LIST"; + return out; + case ConvertedType::ENUM: + out << "ENUM"; + return out; + case ConvertedType::DECIMAL: + out << "DECIMAL"; + return out; + case ConvertedType::DATE: + out << "DATE"; + return out; + case ConvertedType::TIME_MILLIS: + out << "TIME_MILLIS"; + return out; + case ConvertedType::TIME_MICROS: + out << "TIME_MICROS"; + return out; + case ConvertedType::TIMESTAMP_MILLIS: + out << "TIMESTAMP_MILLIS"; + return out; + case ConvertedType::TIMESTAMP_MICROS: + out << "TIMESTAMP_MICROS"; + return out; + case ConvertedType::UINT_8: + out << "UINT_8"; + return out; + case ConvertedType::UINT_16: + out << "UINT_16"; + return out; + case ConvertedType::UINT_32: + out << "UINT_32"; + return out; + case ConvertedType::UINT_64: + out << "UINT_64"; + return out; + case ConvertedType::INT_8: + out << "INT_8"; + return out; + case ConvertedType::INT_16: + out << "INT_16"; + return out; + case ConvertedType::INT_32: + out << "INT_32"; + return out; + case ConvertedType::INT_64: + out << "INT_64"; + return out; + case ConvertedType::JSON: + out << "JSON"; + return out; + case ConvertedType::BSON: + out << "BSON"; + return out; + case ConvertedType::INTERVAL: + out << "INTERVAL"; + return out; + case ConvertedType::NULL_TYPE: + out << "NULL"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const FieldRepetitionType::type &val) { + switch (val) { + case FieldRepetitionType::REQUIRED: + out << "REQUIRED"; + return out; + case FieldRepetitionType::OPTIONAL: + out << "OPTIONAL"; + return out; + case FieldRepetitionType::REPEATED: + out << "REPEATED"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const Encoding::type &val) { + switch (val) { + case Encoding::PLAIN: + out << "PLAIN"; + return out; + case Encoding::PLAIN_DICTIONARY: + out << "PLAIN_DICTIONARY"; + return out; + case Encoding::RLE: + out << "RLE"; + return out; + case Encoding::BIT_PACKED: + out << "BIT_PACKED"; + return out; + case Encoding::DELTA_BINARY_PACKED: + out << "DELTA_BINARY_PACKED"; + return out; + case Encoding::DELTA_LENGTH_BYTE_ARRAY: + out << "DELTA_LENGTH_BYTE_ARRAY"; + return out; + case Encoding::DELTA_BYTE_ARRAY: + out << "DELTA_BYTE_ARRAY"; + return out; + case Encoding::RLE_DICTIONARY: + out << "RLE_DICTIONARY"; + return out; + case Encoding::BYTE_STREAM_SPLIT: + out << "BYTE_STREAM_SPLIT"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const CompressionCodec::type &val) { + switch (val) { + case CompressionCodec::UNCOMPRESSED: + out << "UNCOMPRESSED"; + return out; + case CompressionCodec::SNAPPY: + out << "SNAPPY"; + return out; + case CompressionCodec::GZIP: + out << "GZIP"; + return out; + case CompressionCodec::LZO: + out << "LZO"; + return out; + case CompressionCodec::BROTLI: + out << "BROTLI"; + return out; + case CompressionCodec::LZ4: + out << "LZ4"; + return out; + case CompressionCodec::ZSTD: + out << "ZSTD"; + return out; + case CompressionCodec::LZ4_RAW: + out << "LZ4_RAW"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const PageType::type &val) { + switch (val) { + case PageType::DATA_PAGE: + out << "DATA_PAGE"; + return out; + case PageType::INDEX_PAGE: + out << "INDEX_PAGE"; + return out; + case PageType::DICTIONARY_PAGE: + out << "DICTIONARY_PAGE"; + return out; + case PageType::DATA_PAGE_V2: + out << "DATA_PAGE_V2"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + +std::ostream &operator<<(std::ostream &out, const BoundaryOrder::type &val) { + switch (val) { + case BoundaryOrder::UNORDERED: + out << "UNORDERED"; + return out; + case BoundaryOrder::ASCENDING: + out << "ASCENDING"; + return out; + case BoundaryOrder::DESCENDING: + out << "DESCENDING"; + return out; + // no default for compiler error on missing enum + } + out << static_cast(val); + return out; +} + + +Statistics::~Statistics() throw() { } -Statistics::Statistics() noexcept - : max(), - min(), - null_count(0), - distinct_count(0), - max_value(), - min_value(), - is_max_value_exact(0), - is_min_value_exact(0) { -} void Statistics::__set_max(const std::string& val) { this->max = val; @@ -845,16 +277,6 @@ void Statistics::__set_min_value(const std::string& val) { this->min_value = val; __isset.min_value = true; } - -void Statistics::__set_is_max_value_exact(const bool val) { - this->is_max_value_exact = val; -__isset.is_max_value_exact = true; -} - -void Statistics::__set_is_min_value_exact(const bool val) { - this->is_min_value_exact = val; -__isset.is_min_value_exact = true; -} std::ostream& operator<<(std::ostream& out, const Statistics& obj) { obj.printTo(out); @@ -862,29 +284,29 @@ std::ostream& operator<<(std::ostream& out, const Statistics& obj) } -uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t Statistics::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->max); this->__isset.max = true; } else { @@ -892,7 +314,7 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->min); this->__isset.min = true; } else { @@ -900,7 +322,7 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->null_count); this->__isset.null_count = true; } else { @@ -908,7 +330,7 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->distinct_count); this->__isset.distinct_count = true; } else { @@ -916,7 +338,7 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->max_value); this->__isset.max_value = true; } else { @@ -924,29 +346,13 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->min_value); this->__isset.min_value = true; } else { xfer += iprot->skip(ftype); } break; - case 7: - if (ftype == ::apache::thrift::protocol::T_BOOL) { - xfer += iprot->readBool(this->is_max_value_exact); - this->__isset.is_max_value_exact = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 8: - if (ftype == ::apache::thrift::protocol::T_BOOL) { - xfer += iprot->readBool(this->is_min_value_exact); - this->__isset.is_min_value_exact = true; - } else { - xfer += iprot->skip(ftype); - } - break; default: xfer += iprot->skip(ftype); break; @@ -959,51 +365,41 @@ uint32_t Statistics::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t Statistics::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t Statistics::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("Statistics"); if (this->__isset.max) { - xfer += oprot->writeFieldBegin("max", ::apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("max", ::duckdb_apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->max); xfer += oprot->writeFieldEnd(); } if (this->__isset.min) { - xfer += oprot->writeFieldBegin("min", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("min", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->min); xfer += oprot->writeFieldEnd(); } if (this->__isset.null_count) { - xfer += oprot->writeFieldBegin("null_count", ::apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("null_count", ::duckdb_apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->null_count); xfer += oprot->writeFieldEnd(); } if (this->__isset.distinct_count) { - xfer += oprot->writeFieldBegin("distinct_count", ::apache::thrift::protocol::T_I64, 4); + xfer += oprot->writeFieldBegin("distinct_count", ::duckdb_apache::thrift::protocol::T_I64, 4); xfer += oprot->writeI64(this->distinct_count); xfer += oprot->writeFieldEnd(); } if (this->__isset.max_value) { - xfer += oprot->writeFieldBegin("max_value", ::apache::thrift::protocol::T_STRING, 5); + xfer += oprot->writeFieldBegin("max_value", ::duckdb_apache::thrift::protocol::T_STRING, 5); xfer += oprot->writeBinary(this->max_value); xfer += oprot->writeFieldEnd(); } if (this->__isset.min_value) { - xfer += oprot->writeFieldBegin("min_value", ::apache::thrift::protocol::T_STRING, 6); + xfer += oprot->writeFieldBegin("min_value", ::duckdb_apache::thrift::protocol::T_STRING, 6); xfer += oprot->writeBinary(this->min_value); xfer += oprot->writeFieldEnd(); } - if (this->__isset.is_max_value_exact) { - xfer += oprot->writeFieldBegin("is_max_value_exact", ::apache::thrift::protocol::T_BOOL, 7); - xfer += oprot->writeBool(this->is_max_value_exact); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.is_min_value_exact) { - xfer += oprot->writeFieldBegin("is_min_value_exact", ::apache::thrift::protocol::T_BOOL, 8); - xfer += oprot->writeBool(this->is_min_value_exact); - xfer += oprot->writeFieldEnd(); - } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -1017,36 +413,30 @@ void swap(Statistics &a, Statistics &b) { swap(a.distinct_count, b.distinct_count); swap(a.max_value, b.max_value); swap(a.min_value, b.min_value); - swap(a.is_max_value_exact, b.is_max_value_exact); - swap(a.is_min_value_exact, b.is_min_value_exact); swap(a.__isset, b.__isset); } -Statistics::Statistics(const Statistics& other14) { - max = other14.max; - min = other14.min; - null_count = other14.null_count; - distinct_count = other14.distinct_count; - max_value = other14.max_value; - min_value = other14.min_value; - is_max_value_exact = other14.is_max_value_exact; - is_min_value_exact = other14.is_min_value_exact; - __isset = other14.__isset; -} -Statistics& Statistics::operator=(const Statistics& other15) { - max = other15.max; - min = other15.min; - null_count = other15.null_count; - distinct_count = other15.distinct_count; - max_value = other15.max_value; - min_value = other15.min_value; - is_max_value_exact = other15.is_max_value_exact; - is_min_value_exact = other15.is_min_value_exact; - __isset = other15.__isset; +Statistics::Statistics(const Statistics& other0) { + max = other0.max; + min = other0.min; + null_count = other0.null_count; + distinct_count = other0.distinct_count; + max_value = other0.max_value; + min_value = other0.min_value; + __isset = other0.__isset; +} +Statistics& Statistics::operator=(const Statistics& other1) { + max = other1.max; + min = other1.min; + null_count = other1.null_count; + distinct_count = other1.distinct_count; + max_value = other1.max_value; + min_value = other1.min_value; + __isset = other1.__isset; return *this; } void Statistics::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "Statistics("; out << "max="; (__isset.max ? (out << to_string(max)) : (out << "")); out << ", " << "min="; (__isset.min ? (out << to_string(min)) : (out << "")); @@ -1054,17 +444,13 @@ void Statistics::printTo(std::ostream& out) const { out << ", " << "distinct_count="; (__isset.distinct_count ? (out << to_string(distinct_count)) : (out << "")); out << ", " << "max_value="; (__isset.max_value ? (out << to_string(max_value)) : (out << "")); out << ", " << "min_value="; (__isset.min_value ? (out << to_string(min_value)) : (out << "")); - out << ", " << "is_max_value_exact="; (__isset.is_max_value_exact ? (out << to_string(is_max_value_exact)) : (out << "")); - out << ", " << "is_min_value_exact="; (__isset.is_min_value_exact ? (out << to_string(is_min_value_exact)) : (out << "")); out << ")"; } -StringType::~StringType() noexcept { +StringType::~StringType() throw() { } -StringType::StringType() noexcept { -} std::ostream& operator<<(std::ostream& out, const StringType& obj) { obj.printTo(out); @@ -1072,23 +458,23 @@ std::ostream& operator<<(std::ostream& out, const StringType& obj) } -uint32_t StringType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t StringType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1100,9 +486,9 @@ uint32_t StringType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t StringType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t StringType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("StringType"); xfer += oprot->writeFieldStop(); @@ -1116,25 +502,23 @@ void swap(StringType &a, StringType &b) { (void) b; } -StringType::StringType(const StringType& other16) noexcept { - (void) other16; +StringType::StringType(const StringType& other2) { + (void) other2; } -StringType& StringType::operator=(const StringType& other17) noexcept { - (void) other17; +StringType& StringType::operator=(const StringType& other3) { + (void) other3; return *this; } void StringType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "StringType("; out << ")"; } -UUIDType::~UUIDType() noexcept { +UUIDType::~UUIDType() throw() { } -UUIDType::UUIDType() noexcept { -} std::ostream& operator<<(std::ostream& out, const UUIDType& obj) { obj.printTo(out); @@ -1142,23 +526,23 @@ std::ostream& operator<<(std::ostream& out, const UUIDType& obj) } -uint32_t UUIDType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t UUIDType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1170,9 +554,9 @@ uint32_t UUIDType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t UUIDType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t UUIDType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("UUIDType"); xfer += oprot->writeFieldStop(); @@ -1186,25 +570,23 @@ void swap(UUIDType &a, UUIDType &b) { (void) b; } -UUIDType::UUIDType(const UUIDType& other18) noexcept { - (void) other18; +UUIDType::UUIDType(const UUIDType& other4) { + (void) other4; } -UUIDType& UUIDType::operator=(const UUIDType& other19) noexcept { - (void) other19; +UUIDType& UUIDType::operator=(const UUIDType& other5) { + (void) other5; return *this; } void UUIDType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "UUIDType("; out << ")"; } -MapType::~MapType() noexcept { +MapType::~MapType() throw() { } -MapType::MapType() noexcept { -} std::ostream& operator<<(std::ostream& out, const MapType& obj) { obj.printTo(out); @@ -1212,23 +594,23 @@ std::ostream& operator<<(std::ostream& out, const MapType& obj) } -uint32_t MapType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t MapType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1240,9 +622,9 @@ uint32_t MapType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t MapType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MapType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MapType"); xfer += oprot->writeFieldStop(); @@ -1256,25 +638,23 @@ void swap(MapType &a, MapType &b) { (void) b; } -MapType::MapType(const MapType& other20) noexcept { - (void) other20; +MapType::MapType(const MapType& other6) { + (void) other6; } -MapType& MapType::operator=(const MapType& other21) noexcept { - (void) other21; +MapType& MapType::operator=(const MapType& other7) { + (void) other7; return *this; } void MapType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "MapType("; out << ")"; } -ListType::~ListType() noexcept { +ListType::~ListType() throw() { } -ListType::ListType() noexcept { -} std::ostream& operator<<(std::ostream& out, const ListType& obj) { obj.printTo(out); @@ -1282,23 +662,23 @@ std::ostream& operator<<(std::ostream& out, const ListType& obj) } -uint32_t ListType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ListType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1310,9 +690,9 @@ uint32_t ListType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ListType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ListType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ListType"); xfer += oprot->writeFieldStop(); @@ -1326,25 +706,23 @@ void swap(ListType &a, ListType &b) { (void) b; } -ListType::ListType(const ListType& other22) noexcept { - (void) other22; +ListType::ListType(const ListType& other8) { + (void) other8; } -ListType& ListType::operator=(const ListType& other23) noexcept { - (void) other23; +ListType& ListType::operator=(const ListType& other9) { + (void) other9; return *this; } void ListType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ListType("; out << ")"; } -EnumType::~EnumType() noexcept { +EnumType::~EnumType() throw() { } -EnumType::EnumType() noexcept { -} std::ostream& operator<<(std::ostream& out, const EnumType& obj) { obj.printTo(out); @@ -1352,23 +730,23 @@ std::ostream& operator<<(std::ostream& out, const EnumType& obj) } -uint32_t EnumType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t EnumType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1380,9 +758,9 @@ uint32_t EnumType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t EnumType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EnumType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EnumType"); xfer += oprot->writeFieldStop(); @@ -1396,25 +774,23 @@ void swap(EnumType &a, EnumType &b) { (void) b; } -EnumType::EnumType(const EnumType& other24) noexcept { - (void) other24; +EnumType::EnumType(const EnumType& other10) { + (void) other10; } -EnumType& EnumType::operator=(const EnumType& other25) noexcept { - (void) other25; +EnumType& EnumType::operator=(const EnumType& other11) { + (void) other11; return *this; } void EnumType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "EnumType("; out << ")"; } -DateType::~DateType() noexcept { +DateType::~DateType() throw() { } -DateType::DateType() noexcept { -} std::ostream& operator<<(std::ostream& out, const DateType& obj) { obj.printTo(out); @@ -1422,23 +798,23 @@ std::ostream& operator<<(std::ostream& out, const DateType& obj) } -uint32_t DateType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t DateType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1450,9 +826,9 @@ uint32_t DateType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t DateType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DateType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DateType"); xfer += oprot->writeFieldStop(); @@ -1466,95 +842,23 @@ void swap(DateType &a, DateType &b) { (void) b; } -DateType::DateType(const DateType& other26) noexcept { - (void) other26; +DateType::DateType(const DateType& other12) { + (void) other12; } -DateType& DateType::operator=(const DateType& other27) noexcept { - (void) other27; +DateType& DateType::operator=(const DateType& other13) { + (void) other13; return *this; } void DateType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "DateType("; out << ")"; } -Float16Type::~Float16Type() noexcept { -} - -Float16Type::Float16Type() noexcept { -} -std::ostream& operator<<(std::ostream& out, const Float16Type& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t Float16Type::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - xfer += iprot->skip(ftype); - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t Float16Type::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("Float16Type"); - - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(Float16Type &a, Float16Type &b) { - using ::std::swap; - (void) a; - (void) b; -} - -Float16Type::Float16Type(const Float16Type& other28) noexcept { - (void) other28; -} -Float16Type& Float16Type::operator=(const Float16Type& other29) noexcept { - (void) other29; - return *this; -} -void Float16Type::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "Float16Type("; - out << ")"; -} - - -NullType::~NullType() noexcept { +NullType::~NullType() throw() { } -NullType::NullType() noexcept { -} std::ostream& operator<<(std::ostream& out, const NullType& obj) { obj.printTo(out); @@ -1562,23 +866,23 @@ std::ostream& operator<<(std::ostream& out, const NullType& obj) } -uint32_t NullType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t NullType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1590,9 +894,9 @@ uint32_t NullType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t NullType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t NullType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("NullType"); xfer += oprot->writeFieldStop(); @@ -1606,27 +910,23 @@ void swap(NullType &a, NullType &b) { (void) b; } -NullType::NullType(const NullType& other30) noexcept { - (void) other30; +NullType::NullType(const NullType& other14) { + (void) other14; } -NullType& NullType::operator=(const NullType& other31) noexcept { - (void) other31; +NullType& NullType::operator=(const NullType& other15) { + (void) other15; return *this; } void NullType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "NullType("; out << ")"; } -DecimalType::~DecimalType() noexcept { +DecimalType::~DecimalType() throw() { } -DecimalType::DecimalType() noexcept - : scale(0), - precision(0) { -} void DecimalType::__set_scale(const int32_t val) { this->scale = val; @@ -1642,17 +942,17 @@ std::ostream& operator<<(std::ostream& out, const DecimalType& obj) } -uint32_t DecimalType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t DecimalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_scale = false; bool isset_precision = false; @@ -1660,13 +960,13 @@ uint32_t DecimalType::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->scale); isset_scale = true; } else { @@ -1674,7 +974,7 @@ uint32_t DecimalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->precision); isset_precision = true; } else { @@ -1697,16 +997,16 @@ uint32_t DecimalType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t DecimalType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DecimalType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DecimalType"); - xfer += oprot->writeFieldBegin("scale", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("scale", ::duckdb_apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->scale); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("precision", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("precision", ::duckdb_apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->precision); xfer += oprot->writeFieldEnd(); @@ -1721,17 +1021,17 @@ void swap(DecimalType &a, DecimalType &b) { swap(a.precision, b.precision); } -DecimalType::DecimalType(const DecimalType& other32) noexcept { - scale = other32.scale; - precision = other32.precision; +DecimalType::DecimalType(const DecimalType& other16) { + scale = other16.scale; + precision = other16.precision; } -DecimalType& DecimalType::operator=(const DecimalType& other33) noexcept { - scale = other33.scale; - precision = other33.precision; +DecimalType& DecimalType::operator=(const DecimalType& other17) { + scale = other17.scale; + precision = other17.precision; return *this; } void DecimalType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "DecimalType("; out << "scale=" << to_string(scale); out << ", " << "precision=" << to_string(precision); @@ -1739,11 +1039,9 @@ void DecimalType::printTo(std::ostream& out) const { } -MilliSeconds::~MilliSeconds() noexcept { +MilliSeconds::~MilliSeconds() throw() { } -MilliSeconds::MilliSeconds() noexcept { -} std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj) { obj.printTo(out); @@ -1751,23 +1049,23 @@ std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj) } -uint32_t MilliSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t MilliSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1779,9 +1077,9 @@ uint32_t MilliSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t MilliSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MilliSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MilliSeconds"); xfer += oprot->writeFieldStop(); @@ -1795,25 +1093,23 @@ void swap(MilliSeconds &a, MilliSeconds &b) { (void) b; } -MilliSeconds::MilliSeconds(const MilliSeconds& other34) noexcept { - (void) other34; +MilliSeconds::MilliSeconds(const MilliSeconds& other18) { + (void) other18; } -MilliSeconds& MilliSeconds::operator=(const MilliSeconds& other35) noexcept { - (void) other35; +MilliSeconds& MilliSeconds::operator=(const MilliSeconds& other19) { + (void) other19; return *this; } void MilliSeconds::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "MilliSeconds("; out << ")"; } -MicroSeconds::~MicroSeconds() noexcept { +MicroSeconds::~MicroSeconds() throw() { } -MicroSeconds::MicroSeconds() noexcept { -} std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj) { obj.printTo(out); @@ -1821,23 +1117,23 @@ std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj) } -uint32_t MicroSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t MicroSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1849,9 +1145,9 @@ uint32_t MicroSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t MicroSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t MicroSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("MicroSeconds"); xfer += oprot->writeFieldStop(); @@ -1865,25 +1161,23 @@ void swap(MicroSeconds &a, MicroSeconds &b) { (void) b; } -MicroSeconds::MicroSeconds(const MicroSeconds& other36) noexcept { - (void) other36; +MicroSeconds::MicroSeconds(const MicroSeconds& other20) { + (void) other20; } -MicroSeconds& MicroSeconds::operator=(const MicroSeconds& other37) noexcept { - (void) other37; +MicroSeconds& MicroSeconds::operator=(const MicroSeconds& other21) { + (void) other21; return *this; } void MicroSeconds::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "MicroSeconds("; out << ")"; } -NanoSeconds::~NanoSeconds() noexcept { +NanoSeconds::~NanoSeconds() throw() { } -NanoSeconds::NanoSeconds() noexcept { -} std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj) { obj.printTo(out); @@ -1891,23 +1185,23 @@ std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj) } -uint32_t NanoSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t NanoSeconds::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -1919,9 +1213,9 @@ uint32_t NanoSeconds::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t NanoSeconds::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t NanoSeconds::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("NanoSeconds"); xfer += oprot->writeFieldStop(); @@ -1935,25 +1229,23 @@ void swap(NanoSeconds &a, NanoSeconds &b) { (void) b; } -NanoSeconds::NanoSeconds(const NanoSeconds& other38) noexcept { - (void) other38; +NanoSeconds::NanoSeconds(const NanoSeconds& other22) { + (void) other22; } -NanoSeconds& NanoSeconds::operator=(const NanoSeconds& other39) noexcept { - (void) other39; +NanoSeconds& NanoSeconds::operator=(const NanoSeconds& other23) { + (void) other23; return *this; } void NanoSeconds::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "NanoSeconds("; out << ")"; } -TimeUnit::~TimeUnit() noexcept { +TimeUnit::~TimeUnit() throw() { } -TimeUnit::TimeUnit() noexcept { -} void TimeUnit::__set_MILLIS(const MilliSeconds& val) { this->MILLIS = val; @@ -1976,29 +1268,29 @@ std::ostream& operator<<(std::ostream& out, const TimeUnit& obj) } -uint32_t TimeUnit::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimeUnit::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->MILLIS.read(iprot); this->__isset.MILLIS = true; } else { @@ -2006,7 +1298,7 @@ uint32_t TimeUnit::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->MICROS.read(iprot); this->__isset.MICROS = true; } else { @@ -2014,7 +1306,7 @@ uint32_t TimeUnit::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->NANOS.read(iprot); this->__isset.NANOS = true; } else { @@ -2033,23 +1325,23 @@ uint32_t TimeUnit::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TimeUnit::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimeUnit::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimeUnit"); if (this->__isset.MILLIS) { - xfer += oprot->writeFieldBegin("MILLIS", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("MILLIS", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->MILLIS.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.MICROS) { - xfer += oprot->writeFieldBegin("MICROS", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("MICROS", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->MICROS.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.NANOS) { - xfer += oprot->writeFieldBegin("NANOS", ::apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("NANOS", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); xfer += this->NANOS.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -2066,21 +1358,21 @@ void swap(TimeUnit &a, TimeUnit &b) { swap(a.__isset, b.__isset); } -TimeUnit::TimeUnit(const TimeUnit& other40) noexcept { - MILLIS = other40.MILLIS; - MICROS = other40.MICROS; - NANOS = other40.NANOS; - __isset = other40.__isset; +TimeUnit::TimeUnit(const TimeUnit& other24) { + MILLIS = other24.MILLIS; + MICROS = other24.MICROS; + NANOS = other24.NANOS; + __isset = other24.__isset; } -TimeUnit& TimeUnit::operator=(const TimeUnit& other41) noexcept { - MILLIS = other41.MILLIS; - MICROS = other41.MICROS; - NANOS = other41.NANOS; - __isset = other41.__isset; +TimeUnit& TimeUnit::operator=(const TimeUnit& other25) { + MILLIS = other25.MILLIS; + MICROS = other25.MICROS; + NANOS = other25.NANOS; + __isset = other25.__isset; return *this; } void TimeUnit::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "TimeUnit("; out << "MILLIS="; (__isset.MILLIS ? (out << to_string(MILLIS)) : (out << "")); out << ", " << "MICROS="; (__isset.MICROS ? (out << to_string(MICROS)) : (out << "")); @@ -2089,12 +1381,9 @@ void TimeUnit::printTo(std::ostream& out) const { } -TimestampType::~TimestampType() noexcept { +TimestampType::~TimestampType() throw() { } -TimestampType::TimestampType() noexcept - : isAdjustedToUTC(0) { -} void TimestampType::__set_isAdjustedToUTC(const bool val) { this->isAdjustedToUTC = val; @@ -2110,17 +1399,17 @@ std::ostream& operator<<(std::ostream& out, const TimestampType& obj) } -uint32_t TimestampType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimestampType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_isAdjustedToUTC = false; bool isset_unit = false; @@ -2128,13 +1417,13 @@ uint32_t TimestampType::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isAdjustedToUTC); isset_isAdjustedToUTC = true; } else { @@ -2142,7 +1431,7 @@ uint32_t TimestampType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->unit.read(iprot); isset_unit = true; } else { @@ -2165,16 +1454,16 @@ uint32_t TimestampType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TimestampType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimestampType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimestampType"); - xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::apache::thrift::protocol::T_BOOL, 1); + xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::duckdb_apache::thrift::protocol::T_BOOL, 1); xfer += oprot->writeBool(this->isAdjustedToUTC); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("unit", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("unit", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->unit.write(oprot); xfer += oprot->writeFieldEnd(); @@ -2189,17 +1478,17 @@ void swap(TimestampType &a, TimestampType &b) { swap(a.unit, b.unit); } -TimestampType::TimestampType(const TimestampType& other42) noexcept { - isAdjustedToUTC = other42.isAdjustedToUTC; - unit = other42.unit; +TimestampType::TimestampType(const TimestampType& other26) { + isAdjustedToUTC = other26.isAdjustedToUTC; + unit = other26.unit; } -TimestampType& TimestampType::operator=(const TimestampType& other43) noexcept { - isAdjustedToUTC = other43.isAdjustedToUTC; - unit = other43.unit; +TimestampType& TimestampType::operator=(const TimestampType& other27) { + isAdjustedToUTC = other27.isAdjustedToUTC; + unit = other27.unit; return *this; } void TimestampType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "TimestampType("; out << "isAdjustedToUTC=" << to_string(isAdjustedToUTC); out << ", " << "unit=" << to_string(unit); @@ -2207,12 +1496,9 @@ void TimestampType::printTo(std::ostream& out) const { } -TimeType::~TimeType() noexcept { +TimeType::~TimeType() throw() { } -TimeType::TimeType() noexcept - : isAdjustedToUTC(0) { -} void TimeType::__set_isAdjustedToUTC(const bool val) { this->isAdjustedToUTC = val; @@ -2228,17 +1514,17 @@ std::ostream& operator<<(std::ostream& out, const TimeType& obj) } -uint32_t TimeType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t TimeType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_isAdjustedToUTC = false; bool isset_unit = false; @@ -2246,13 +1532,13 @@ uint32_t TimeType::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isAdjustedToUTC); isset_isAdjustedToUTC = true; } else { @@ -2260,7 +1546,7 @@ uint32_t TimeType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->unit.read(iprot); isset_unit = true; } else { @@ -2283,16 +1569,16 @@ uint32_t TimeType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TimeType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TimeType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TimeType"); - xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::apache::thrift::protocol::T_BOOL, 1); + xfer += oprot->writeFieldBegin("isAdjustedToUTC", ::duckdb_apache::thrift::protocol::T_BOOL, 1); xfer += oprot->writeBool(this->isAdjustedToUTC); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("unit", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("unit", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->unit.write(oprot); xfer += oprot->writeFieldEnd(); @@ -2307,17 +1593,17 @@ void swap(TimeType &a, TimeType &b) { swap(a.unit, b.unit); } -TimeType::TimeType(const TimeType& other44) noexcept { - isAdjustedToUTC = other44.isAdjustedToUTC; - unit = other44.unit; +TimeType::TimeType(const TimeType& other28) { + isAdjustedToUTC = other28.isAdjustedToUTC; + unit = other28.unit; } -TimeType& TimeType::operator=(const TimeType& other45) noexcept { - isAdjustedToUTC = other45.isAdjustedToUTC; - unit = other45.unit; +TimeType& TimeType::operator=(const TimeType& other29) { + isAdjustedToUTC = other29.isAdjustedToUTC; + unit = other29.unit; return *this; } void TimeType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "TimeType("; out << "isAdjustedToUTC=" << to_string(isAdjustedToUTC); out << ", " << "unit=" << to_string(unit); @@ -2325,13 +1611,9 @@ void TimeType::printTo(std::ostream& out) const { } -IntType::~IntType() noexcept { +IntType::~IntType() throw() { } -IntType::IntType() noexcept - : bitWidth(0), - isSigned(0) { -} void IntType::__set_bitWidth(const int8_t val) { this->bitWidth = val; @@ -2347,17 +1629,17 @@ std::ostream& operator<<(std::ostream& out, const IntType& obj) } -uint32_t IntType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t IntType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_bitWidth = false; bool isset_isSigned = false; @@ -2365,13 +1647,13 @@ uint32_t IntType::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_BYTE) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BYTE) { xfer += iprot->readByte(this->bitWidth); isset_bitWidth = true; } else { @@ -2379,7 +1661,7 @@ uint32_t IntType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->isSigned); isset_isSigned = true; } else { @@ -2402,16 +1684,16 @@ uint32_t IntType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t IntType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t IntType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("IntType"); - xfer += oprot->writeFieldBegin("bitWidth", ::apache::thrift::protocol::T_BYTE, 1); + xfer += oprot->writeFieldBegin("bitWidth", ::duckdb_apache::thrift::protocol::T_BYTE, 1); xfer += oprot->writeByte(this->bitWidth); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("isSigned", ::apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeFieldBegin("isSigned", ::duckdb_apache::thrift::protocol::T_BOOL, 2); xfer += oprot->writeBool(this->isSigned); xfer += oprot->writeFieldEnd(); @@ -2426,17 +1708,17 @@ void swap(IntType &a, IntType &b) { swap(a.isSigned, b.isSigned); } -IntType::IntType(const IntType& other46) noexcept { - bitWidth = other46.bitWidth; - isSigned = other46.isSigned; +IntType::IntType(const IntType& other30) { + bitWidth = other30.bitWidth; + isSigned = other30.isSigned; } -IntType& IntType::operator=(const IntType& other47) noexcept { - bitWidth = other47.bitWidth; - isSigned = other47.isSigned; +IntType& IntType::operator=(const IntType& other31) { + bitWidth = other31.bitWidth; + isSigned = other31.isSigned; return *this; } void IntType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "IntType("; out << "bitWidth=" << to_string(bitWidth); out << ", " << "isSigned=" << to_string(isSigned); @@ -2444,11 +1726,9 @@ void IntType::printTo(std::ostream& out) const { } -JsonType::~JsonType() noexcept { +JsonType::~JsonType() throw() { } -JsonType::JsonType() noexcept { -} std::ostream& operator<<(std::ostream& out, const JsonType& obj) { obj.printTo(out); @@ -2456,23 +1736,23 @@ std::ostream& operator<<(std::ostream& out, const JsonType& obj) } -uint32_t JsonType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t JsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -2484,9 +1764,9 @@ uint32_t JsonType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t JsonType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t JsonType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("JsonType"); xfer += oprot->writeFieldStop(); @@ -2500,25 +1780,23 @@ void swap(JsonType &a, JsonType &b) { (void) b; } -JsonType::JsonType(const JsonType& other48) noexcept { - (void) other48; +JsonType::JsonType(const JsonType& other32) { + (void) other32; } -JsonType& JsonType::operator=(const JsonType& other49) noexcept { - (void) other49; +JsonType& JsonType::operator=(const JsonType& other33) { + (void) other33; return *this; } void JsonType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "JsonType("; out << ")"; } -BsonType::~BsonType() noexcept { +BsonType::~BsonType() throw() { } -BsonType::BsonType() noexcept { -} std::ostream& operator<<(std::ostream& out, const BsonType& obj) { obj.printTo(out); @@ -2526,23 +1804,23 @@ std::ostream& operator<<(std::ostream& out, const BsonType& obj) } -uint32_t BsonType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t BsonType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -2554,9 +1832,9 @@ uint32_t BsonType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t BsonType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t BsonType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("BsonType"); xfer += oprot->writeFieldStop(); @@ -2570,25 +1848,23 @@ void swap(BsonType &a, BsonType &b) { (void) b; } -BsonType::BsonType(const BsonType& other50) noexcept { - (void) other50; +BsonType::BsonType(const BsonType& other34) { + (void) other34; } -BsonType& BsonType::operator=(const BsonType& other51) noexcept { - (void) other51; +BsonType& BsonType::operator=(const BsonType& other35) { + (void) other35; return *this; } void BsonType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "BsonType("; out << ")"; } -LogicalType::~LogicalType() noexcept { +LogicalType::~LogicalType() throw() { } -LogicalType::LogicalType() noexcept { -} void LogicalType::__set_STRING(const StringType& val) { this->STRING = val; @@ -2654,11 +1930,6 @@ void LogicalType::__set_UUID(const UUIDType& val) { this->UUID = val; __isset.UUID = true; } - -void LogicalType::__set_FLOAT16(const Float16Type& val) { - this->FLOAT16 = val; -__isset.FLOAT16 = true; -} std::ostream& operator<<(std::ostream& out, const LogicalType& obj) { obj.printTo(out); @@ -2666,29 +1937,29 @@ std::ostream& operator<<(std::ostream& out, const LogicalType& obj) } -uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t LogicalType::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->STRING.read(iprot); this->__isset.STRING = true; } else { @@ -2696,7 +1967,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->MAP.read(iprot); this->__isset.MAP = true; } else { @@ -2704,7 +1975,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->LIST.read(iprot); this->__isset.LIST = true; } else { @@ -2712,7 +1983,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->ENUM.read(iprot); this->__isset.ENUM = true; } else { @@ -2720,7 +1991,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->DECIMAL.read(iprot); this->__isset.DECIMAL = true; } else { @@ -2728,7 +1999,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->DATE.read(iprot); this->__isset.DATE = true; } else { @@ -2736,7 +2007,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->TIME.read(iprot); this->__isset.TIME = true; } else { @@ -2744,7 +2015,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->TIMESTAMP.read(iprot); this->__isset.TIMESTAMP = true; } else { @@ -2752,7 +2023,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 10: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->INTEGER.read(iprot); this->__isset.INTEGER = true; } else { @@ -2760,7 +2031,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 11: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->UNKNOWN.read(iprot); this->__isset.UNKNOWN = true; } else { @@ -2768,7 +2039,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 12: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->JSON.read(iprot); this->__isset.JSON = true; } else { @@ -2776,7 +2047,7 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 13: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->BSON.read(iprot); this->__isset.BSON = true; } else { @@ -2784,21 +2055,13 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 14: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->UUID.read(iprot); this->__isset.UUID = true; } else { xfer += iprot->skip(ftype); } break; - case 15: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->FLOAT16.read(iprot); - this->__isset.FLOAT16 = true; - } else { - xfer += iprot->skip(ftype); - } - break; default: xfer += iprot->skip(ftype); break; @@ -2811,81 +2074,76 @@ uint32_t LogicalType::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t LogicalType::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t LogicalType::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("LogicalType"); if (this->__isset.STRING) { - xfer += oprot->writeFieldBegin("STRING", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("STRING", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->STRING.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.MAP) { - xfer += oprot->writeFieldBegin("MAP", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("MAP", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->MAP.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.LIST) { - xfer += oprot->writeFieldBegin("LIST", ::apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("LIST", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); xfer += this->LIST.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.ENUM) { - xfer += oprot->writeFieldBegin("ENUM", ::apache::thrift::protocol::T_STRUCT, 4); + xfer += oprot->writeFieldBegin("ENUM", ::duckdb_apache::thrift::protocol::T_STRUCT, 4); xfer += this->ENUM.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.DECIMAL) { - xfer += oprot->writeFieldBegin("DECIMAL", ::apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("DECIMAL", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); xfer += this->DECIMAL.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.DATE) { - xfer += oprot->writeFieldBegin("DATE", ::apache::thrift::protocol::T_STRUCT, 6); + xfer += oprot->writeFieldBegin("DATE", ::duckdb_apache::thrift::protocol::T_STRUCT, 6); xfer += this->DATE.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.TIME) { - xfer += oprot->writeFieldBegin("TIME", ::apache::thrift::protocol::T_STRUCT, 7); + xfer += oprot->writeFieldBegin("TIME", ::duckdb_apache::thrift::protocol::T_STRUCT, 7); xfer += this->TIME.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.TIMESTAMP) { - xfer += oprot->writeFieldBegin("TIMESTAMP", ::apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("TIMESTAMP", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); xfer += this->TIMESTAMP.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.INTEGER) { - xfer += oprot->writeFieldBegin("INTEGER", ::apache::thrift::protocol::T_STRUCT, 10); + xfer += oprot->writeFieldBegin("INTEGER", ::duckdb_apache::thrift::protocol::T_STRUCT, 10); xfer += this->INTEGER.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.UNKNOWN) { - xfer += oprot->writeFieldBegin("UNKNOWN", ::apache::thrift::protocol::T_STRUCT, 11); + xfer += oprot->writeFieldBegin("UNKNOWN", ::duckdb_apache::thrift::protocol::T_STRUCT, 11); xfer += this->UNKNOWN.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.JSON) { - xfer += oprot->writeFieldBegin("JSON", ::apache::thrift::protocol::T_STRUCT, 12); + xfer += oprot->writeFieldBegin("JSON", ::duckdb_apache::thrift::protocol::T_STRUCT, 12); xfer += this->JSON.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.BSON) { - xfer += oprot->writeFieldBegin("BSON", ::apache::thrift::protocol::T_STRUCT, 13); + xfer += oprot->writeFieldBegin("BSON", ::duckdb_apache::thrift::protocol::T_STRUCT, 13); xfer += this->BSON.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.UUID) { - xfer += oprot->writeFieldBegin("UUID", ::apache::thrift::protocol::T_STRUCT, 14); + xfer += oprot->writeFieldBegin("UUID", ::duckdb_apache::thrift::protocol::T_STRUCT, 14); xfer += this->UUID.write(oprot); xfer += oprot->writeFieldEnd(); } - if (this->__isset.FLOAT16) { - xfer += oprot->writeFieldBegin("FLOAT16", ::apache::thrift::protocol::T_STRUCT, 15); - xfer += this->FLOAT16.write(oprot); - xfer += oprot->writeFieldEnd(); - } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -2906,47 +2164,44 @@ void swap(LogicalType &a, LogicalType &b) { swap(a.JSON, b.JSON); swap(a.BSON, b.BSON); swap(a.UUID, b.UUID); - swap(a.FLOAT16, b.FLOAT16); swap(a.__isset, b.__isset); } -LogicalType::LogicalType(const LogicalType& other52) noexcept { - STRING = other52.STRING; - MAP = other52.MAP; - LIST = other52.LIST; - ENUM = other52.ENUM; - DECIMAL = other52.DECIMAL; - DATE = other52.DATE; - TIME = other52.TIME; - TIMESTAMP = other52.TIMESTAMP; - INTEGER = other52.INTEGER; - UNKNOWN = other52.UNKNOWN; - JSON = other52.JSON; - BSON = other52.BSON; - UUID = other52.UUID; - FLOAT16 = other52.FLOAT16; - __isset = other52.__isset; -} -LogicalType& LogicalType::operator=(const LogicalType& other53) noexcept { - STRING = other53.STRING; - MAP = other53.MAP; - LIST = other53.LIST; - ENUM = other53.ENUM; - DECIMAL = other53.DECIMAL; - DATE = other53.DATE; - TIME = other53.TIME; - TIMESTAMP = other53.TIMESTAMP; - INTEGER = other53.INTEGER; - UNKNOWN = other53.UNKNOWN; - JSON = other53.JSON; - BSON = other53.BSON; - UUID = other53.UUID; - FLOAT16 = other53.FLOAT16; - __isset = other53.__isset; +LogicalType::LogicalType(const LogicalType& other36) { + STRING = other36.STRING; + MAP = other36.MAP; + LIST = other36.LIST; + ENUM = other36.ENUM; + DECIMAL = other36.DECIMAL; + DATE = other36.DATE; + TIME = other36.TIME; + TIMESTAMP = other36.TIMESTAMP; + INTEGER = other36.INTEGER; + UNKNOWN = other36.UNKNOWN; + JSON = other36.JSON; + BSON = other36.BSON; + UUID = other36.UUID; + __isset = other36.__isset; +} +LogicalType& LogicalType::operator=(const LogicalType& other37) { + STRING = other37.STRING; + MAP = other37.MAP; + LIST = other37.LIST; + ENUM = other37.ENUM; + DECIMAL = other37.DECIMAL; + DATE = other37.DATE; + TIME = other37.TIME; + TIMESTAMP = other37.TIMESTAMP; + INTEGER = other37.INTEGER; + UNKNOWN = other37.UNKNOWN; + JSON = other37.JSON; + BSON = other37.BSON; + UUID = other37.UUID; + __isset = other37.__isset; return *this; } void LogicalType::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "LogicalType("; out << "STRING="; (__isset.STRING ? (out << to_string(STRING)) : (out << "")); out << ", " << "MAP="; (__isset.MAP ? (out << to_string(MAP)) : (out << "")); @@ -2961,25 +2216,13 @@ void LogicalType::printTo(std::ostream& out) const { out << ", " << "JSON="; (__isset.JSON ? (out << to_string(JSON)) : (out << "")); out << ", " << "BSON="; (__isset.BSON ? (out << to_string(BSON)) : (out << "")); out << ", " << "UUID="; (__isset.UUID ? (out << to_string(UUID)) : (out << "")); - out << ", " << "FLOAT16="; (__isset.FLOAT16 ? (out << to_string(FLOAT16)) : (out << "")); out << ")"; } -SchemaElement::~SchemaElement() noexcept { +SchemaElement::~SchemaElement() throw() { } -SchemaElement::SchemaElement() noexcept - : type(static_cast(0)), - type_length(0), - repetition_type(static_cast(0)), - name(), - num_children(0), - converted_type(static_cast(0)), - scale(0), - precision(0), - field_id(0) { -} void SchemaElement::__set_type(const Type::type val) { this->type = val; @@ -3036,40 +2279,40 @@ std::ostream& operator<<(std::ostream& out, const SchemaElement& obj) } -uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t SchemaElement::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_name = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast54; - xfer += iprot->readI32(ecast54); - this->type = static_cast(ecast54); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast38; + xfer += iprot->readI32(ecast38); + this->type = (Type::type)ecast38; this->__isset.type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->type_length); this->__isset.type_length = true; } else { @@ -3077,17 +2320,17 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast55; - xfer += iprot->readI32(ecast55); - this->repetition_type = static_cast(ecast55); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast39; + xfer += iprot->readI32(ecast39); + this->repetition_type = (FieldRepetitionType::type)ecast39; this->__isset.repetition_type = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->name); isset_name = true; } else { @@ -3095,7 +2338,7 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_children); this->__isset.num_children = true; } else { @@ -3103,17 +2346,17 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast56; - xfer += iprot->readI32(ecast56); - this->converted_type = static_cast(ecast56); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast40; + xfer += iprot->readI32(ecast40); + this->converted_type = (ConvertedType::type)ecast40; this->__isset.converted_type = true; } else { xfer += iprot->skip(ftype); } break; case 7: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->scale); this->__isset.scale = true; } else { @@ -3121,7 +2364,7 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->precision); this->__isset.precision = true; } else { @@ -3129,7 +2372,7 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 9: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->field_id); this->__isset.field_id = true; } else { @@ -3137,7 +2380,7 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 10: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->logicalType.read(iprot); this->__isset.logicalType = true; } else { @@ -3158,57 +2401,57 @@ uint32_t SchemaElement::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t SchemaElement::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t SchemaElement::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("SchemaElement"); if (this->__isset.type) { - xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(static_cast(this->type)); + xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->type); xfer += oprot->writeFieldEnd(); } if (this->__isset.type_length) { - xfer += oprot->writeFieldBegin("type_length", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("type_length", ::duckdb_apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->type_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.repetition_type) { - xfer += oprot->writeFieldBegin("repetition_type", ::apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32(static_cast(this->repetition_type)); + xfer += oprot->writeFieldBegin("repetition_type", ::duckdb_apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32((int32_t)this->repetition_type); xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("name", ::apache::thrift::protocol::T_STRING, 4); + xfer += oprot->writeFieldBegin("name", ::duckdb_apache::thrift::protocol::T_STRING, 4); xfer += oprot->writeString(this->name); xfer += oprot->writeFieldEnd(); if (this->__isset.num_children) { - xfer += oprot->writeFieldBegin("num_children", ::apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeFieldBegin("num_children", ::duckdb_apache::thrift::protocol::T_I32, 5); xfer += oprot->writeI32(this->num_children); xfer += oprot->writeFieldEnd(); } if (this->__isset.converted_type) { - xfer += oprot->writeFieldBegin("converted_type", ::apache::thrift::protocol::T_I32, 6); - xfer += oprot->writeI32(static_cast(this->converted_type)); + xfer += oprot->writeFieldBegin("converted_type", ::duckdb_apache::thrift::protocol::T_I32, 6); + xfer += oprot->writeI32((int32_t)this->converted_type); xfer += oprot->writeFieldEnd(); } if (this->__isset.scale) { - xfer += oprot->writeFieldBegin("scale", ::apache::thrift::protocol::T_I32, 7); + xfer += oprot->writeFieldBegin("scale", ::duckdb_apache::thrift::protocol::T_I32, 7); xfer += oprot->writeI32(this->scale); xfer += oprot->writeFieldEnd(); } if (this->__isset.precision) { - xfer += oprot->writeFieldBegin("precision", ::apache::thrift::protocol::T_I32, 8); + xfer += oprot->writeFieldBegin("precision", ::duckdb_apache::thrift::protocol::T_I32, 8); xfer += oprot->writeI32(this->precision); xfer += oprot->writeFieldEnd(); } if (this->__isset.field_id) { - xfer += oprot->writeFieldBegin("field_id", ::apache::thrift::protocol::T_I32, 9); + xfer += oprot->writeFieldBegin("field_id", ::duckdb_apache::thrift::protocol::T_I32, 9); xfer += oprot->writeI32(this->field_id); xfer += oprot->writeFieldEnd(); } if (this->__isset.logicalType) { - xfer += oprot->writeFieldBegin("logicalType", ::apache::thrift::protocol::T_STRUCT, 10); + xfer += oprot->writeFieldBegin("logicalType", ::duckdb_apache::thrift::protocol::T_STRUCT, 10); xfer += this->logicalType.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -3232,35 +2475,35 @@ void swap(SchemaElement &a, SchemaElement &b) { swap(a.__isset, b.__isset); } -SchemaElement::SchemaElement(const SchemaElement& other57) { - type = other57.type; - type_length = other57.type_length; - repetition_type = other57.repetition_type; - name = other57.name; - num_children = other57.num_children; - converted_type = other57.converted_type; - scale = other57.scale; - precision = other57.precision; - field_id = other57.field_id; - logicalType = other57.logicalType; - __isset = other57.__isset; +SchemaElement::SchemaElement(const SchemaElement& other41) { + type = other41.type; + type_length = other41.type_length; + repetition_type = other41.repetition_type; + name = other41.name; + num_children = other41.num_children; + converted_type = other41.converted_type; + scale = other41.scale; + precision = other41.precision; + field_id = other41.field_id; + logicalType = other41.logicalType; + __isset = other41.__isset; } -SchemaElement& SchemaElement::operator=(const SchemaElement& other58) { - type = other58.type; - type_length = other58.type_length; - repetition_type = other58.repetition_type; - name = other58.name; - num_children = other58.num_children; - converted_type = other58.converted_type; - scale = other58.scale; - precision = other58.precision; - field_id = other58.field_id; - logicalType = other58.logicalType; - __isset = other58.__isset; +SchemaElement& SchemaElement::operator=(const SchemaElement& other42) { + type = other42.type; + type_length = other42.type_length; + repetition_type = other42.repetition_type; + name = other42.name; + num_children = other42.num_children; + converted_type = other42.converted_type; + scale = other42.scale; + precision = other42.precision; + field_id = other42.field_id; + logicalType = other42.logicalType; + __isset = other42.__isset; return *this; } void SchemaElement::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "SchemaElement("; out << "type="; (__isset.type ? (out << to_string(type)) : (out << "")); out << ", " << "type_length="; (__isset.type_length ? (out << to_string(type_length)) : (out << "")); @@ -3276,15 +2519,9 @@ void SchemaElement::printTo(std::ostream& out) const { } -DataPageHeader::~DataPageHeader() noexcept { +DataPageHeader::~DataPageHeader() throw() { } -DataPageHeader::DataPageHeader() noexcept - : num_values(0), - encoding(static_cast(0)), - definition_level_encoding(static_cast(0)), - repetition_level_encoding(static_cast(0)) { -} void DataPageHeader::__set_num_values(const int32_t val) { this->num_values = val; @@ -3313,17 +2550,17 @@ std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj) } -uint32_t DataPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t DataPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_num_values = false; bool isset_encoding = false; @@ -3333,13 +2570,13 @@ uint32_t DataPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_values); isset_num_values = true; } else { @@ -3347,37 +2584,37 @@ uint32_t DataPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast59; - xfer += iprot->readI32(ecast59); - this->encoding = static_cast(ecast59); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast43; + xfer += iprot->readI32(ecast43); + this->encoding = (Encoding::type)ecast43; isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast60; - xfer += iprot->readI32(ecast60); - this->definition_level_encoding = static_cast(ecast60); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast44; + xfer += iprot->readI32(ecast44); + this->definition_level_encoding = (Encoding::type)ecast44; isset_definition_level_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast61; - xfer += iprot->readI32(ecast61); - this->repetition_level_encoding = static_cast(ecast61); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast45; + xfer += iprot->readI32(ecast45); + this->repetition_level_encoding = (Encoding::type)ecast45; isset_repetition_level_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->statistics.read(iprot); this->__isset.statistics = true; } else { @@ -3404,29 +2641,29 @@ uint32_t DataPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t DataPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DataPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DataPageHeader"); - xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32(static_cast(this->encoding)); + xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((int32_t)this->encoding); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("definition_level_encoding", ::apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32(static_cast(this->definition_level_encoding)); + xfer += oprot->writeFieldBegin("definition_level_encoding", ::duckdb_apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32((int32_t)this->definition_level_encoding); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("repetition_level_encoding", ::apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32(static_cast(this->repetition_level_encoding)); + xfer += oprot->writeFieldBegin("repetition_level_encoding", ::duckdb_apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32((int32_t)this->repetition_level_encoding); xfer += oprot->writeFieldEnd(); if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); xfer += this->statistics.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -3445,25 +2682,25 @@ void swap(DataPageHeader &a, DataPageHeader &b) { swap(a.__isset, b.__isset); } -DataPageHeader::DataPageHeader(const DataPageHeader& other62) { - num_values = other62.num_values; - encoding = other62.encoding; - definition_level_encoding = other62.definition_level_encoding; - repetition_level_encoding = other62.repetition_level_encoding; - statistics = other62.statistics; - __isset = other62.__isset; -} -DataPageHeader& DataPageHeader::operator=(const DataPageHeader& other63) { - num_values = other63.num_values; - encoding = other63.encoding; - definition_level_encoding = other63.definition_level_encoding; - repetition_level_encoding = other63.repetition_level_encoding; - statistics = other63.statistics; - __isset = other63.__isset; +DataPageHeader::DataPageHeader(const DataPageHeader& other46) { + num_values = other46.num_values; + encoding = other46.encoding; + definition_level_encoding = other46.definition_level_encoding; + repetition_level_encoding = other46.repetition_level_encoding; + statistics = other46.statistics; + __isset = other46.__isset; +} +DataPageHeader& DataPageHeader::operator=(const DataPageHeader& other47) { + num_values = other47.num_values; + encoding = other47.encoding; + definition_level_encoding = other47.definition_level_encoding; + repetition_level_encoding = other47.repetition_level_encoding; + statistics = other47.statistics; + __isset = other47.__isset; return *this; } void DataPageHeader::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "DataPageHeader("; out << "num_values=" << to_string(num_values); out << ", " << "encoding=" << to_string(encoding); @@ -3474,11 +2711,9 @@ void DataPageHeader::printTo(std::ostream& out) const { } -IndexPageHeader::~IndexPageHeader() noexcept { +IndexPageHeader::~IndexPageHeader() throw() { } -IndexPageHeader::IndexPageHeader() noexcept { -} std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj) { obj.printTo(out); @@ -3486,23 +2721,23 @@ std::ostream& operator<<(std::ostream& out, const IndexPageHeader& obj) } -uint32_t IndexPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t IndexPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -3514,9 +2749,9 @@ uint32_t IndexPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t IndexPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t IndexPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("IndexPageHeader"); xfer += oprot->writeFieldStop(); @@ -3530,28 +2765,23 @@ void swap(IndexPageHeader &a, IndexPageHeader &b) { (void) b; } -IndexPageHeader::IndexPageHeader(const IndexPageHeader& other64) noexcept { - (void) other64; +IndexPageHeader::IndexPageHeader(const IndexPageHeader& other48) { + (void) other48; } -IndexPageHeader& IndexPageHeader::operator=(const IndexPageHeader& other65) noexcept { - (void) other65; +IndexPageHeader& IndexPageHeader::operator=(const IndexPageHeader& other49) { + (void) other49; return *this; } void IndexPageHeader::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "IndexPageHeader("; out << ")"; } -DictionaryPageHeader::~DictionaryPageHeader() noexcept { +DictionaryPageHeader::~DictionaryPageHeader() throw() { } -DictionaryPageHeader::DictionaryPageHeader() noexcept - : num_values(0), - encoding(static_cast(0)), - is_sorted(0) { -} void DictionaryPageHeader::__set_num_values(const int32_t val) { this->num_values = val; @@ -3572,17 +2802,17 @@ std::ostream& operator<<(std::ostream& out, const DictionaryPageHeader& obj) } -uint32_t DictionaryPageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t DictionaryPageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_num_values = false; bool isset_encoding = false; @@ -3590,13 +2820,13 @@ uint32_t DictionaryPageHeader::read(::apache::thrift::protocol::TProtocol* iprot while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->num_values); isset_num_values = true; } else { @@ -3604,17 +2834,17 @@ uint32_t DictionaryPageHeader::read(::apache::thrift::protocol::TProtocol* iprot } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast66; - xfer += iprot->readI32(ecast66); - this->encoding = static_cast(ecast66); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast50; + xfer += iprot->readI32(ecast50); + this->encoding = (Encoding::type)ecast50; isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->is_sorted); this->__isset.is_sorted = true; } else { @@ -3637,21 +2867,21 @@ uint32_t DictionaryPageHeader::read(::apache::thrift::protocol::TProtocol* iprot return xfer; } -uint32_t DictionaryPageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DictionaryPageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("DictionaryPageHeader"); - xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32(static_cast(this->encoding)); + xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((int32_t)this->encoding); xfer += oprot->writeFieldEnd(); if (this->__isset.is_sorted) { - xfer += oprot->writeFieldBegin("is_sorted", ::apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("is_sorted", ::duckdb_apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->is_sorted); xfer += oprot->writeFieldEnd(); } @@ -3668,874 +2898,162 @@ void swap(DictionaryPageHeader &a, DictionaryPageHeader &b) { swap(a.__isset, b.__isset); } -DictionaryPageHeader::DictionaryPageHeader(const DictionaryPageHeader& other67) noexcept { - num_values = other67.num_values; - encoding = other67.encoding; - is_sorted = other67.is_sorted; - __isset = other67.__isset; +DictionaryPageHeader::DictionaryPageHeader(const DictionaryPageHeader& other51) { + num_values = other51.num_values; + encoding = other51.encoding; + is_sorted = other51.is_sorted; + __isset = other51.__isset; } -DictionaryPageHeader& DictionaryPageHeader::operator=(const DictionaryPageHeader& other68) noexcept { - num_values = other68.num_values; - encoding = other68.encoding; - is_sorted = other68.is_sorted; - __isset = other68.__isset; +DictionaryPageHeader& DictionaryPageHeader::operator=(const DictionaryPageHeader& other52) { + num_values = other52.num_values; + encoding = other52.encoding; + is_sorted = other52.is_sorted; + __isset = other52.__isset; return *this; } void DictionaryPageHeader::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "DictionaryPageHeader("; out << "num_values=" << to_string(num_values); - out << ", " << "encoding=" << to_string(encoding); - out << ", " << "is_sorted="; (__isset.is_sorted ? (out << to_string(is_sorted)) : (out << "")); - out << ")"; -} - - -DataPageHeaderV2::~DataPageHeaderV2() noexcept { -} - -DataPageHeaderV2::DataPageHeaderV2() noexcept - : num_values(0), - num_nulls(0), - num_rows(0), - encoding(static_cast(0)), - definition_levels_byte_length(0), - repetition_levels_byte_length(0), - is_compressed(true) { -} - -void DataPageHeaderV2::__set_num_values(const int32_t val) { - this->num_values = val; -} - -void DataPageHeaderV2::__set_num_nulls(const int32_t val) { - this->num_nulls = val; -} - -void DataPageHeaderV2::__set_num_rows(const int32_t val) { - this->num_rows = val; -} - -void DataPageHeaderV2::__set_encoding(const Encoding::type val) { - this->encoding = val; -} - -void DataPageHeaderV2::__set_definition_levels_byte_length(const int32_t val) { - this->definition_levels_byte_length = val; -} - -void DataPageHeaderV2::__set_repetition_levels_byte_length(const int32_t val) { - this->repetition_levels_byte_length = val; -} - -void DataPageHeaderV2::__set_is_compressed(const bool val) { - this->is_compressed = val; -__isset.is_compressed = true; -} - -void DataPageHeaderV2::__set_statistics(const Statistics& val) { - this->statistics = val; -__isset.statistics = true; -} -std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t DataPageHeaderV2::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - bool isset_num_values = false; - bool isset_num_nulls = false; - bool isset_num_rows = false; - bool isset_encoding = false; - bool isset_definition_levels_byte_length = false; - bool isset_repetition_levels_byte_length = false; - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - switch (fid) - { - case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_values); - isset_num_values = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_nulls); - isset_num_nulls = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 3: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->num_rows); - isset_num_rows = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 4: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast69; - xfer += iprot->readI32(ecast69); - this->encoding = static_cast(ecast69); - isset_encoding = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 5: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->definition_levels_byte_length); - isset_definition_levels_byte_length = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 6: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->repetition_levels_byte_length); - isset_repetition_levels_byte_length = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 7: - if (ftype == ::apache::thrift::protocol::T_BOOL) { - xfer += iprot->readBool(this->is_compressed); - this->__isset.is_compressed = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 8: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->statistics.read(iprot); - this->__isset.statistics = true; - } else { - xfer += iprot->skip(ftype); - } - break; - default: - xfer += iprot->skip(ftype); - break; - } - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - if (!isset_num_values) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_num_nulls) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_num_rows) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_encoding) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_definition_levels_byte_length) - throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_repetition_levels_byte_length) - throw TProtocolException(TProtocolException::INVALID_DATA); - return xfer; -} - -uint32_t DataPageHeaderV2::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("DataPageHeaderV2"); - - xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(this->num_values); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("num_nulls", ::apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32(this->num_nulls); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I32, 3); - xfer += oprot->writeI32(this->num_rows); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32(static_cast(this->encoding)); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("definition_levels_byte_length", ::apache::thrift::protocol::T_I32, 5); - xfer += oprot->writeI32(this->definition_levels_byte_length); - xfer += oprot->writeFieldEnd(); - - xfer += oprot->writeFieldBegin("repetition_levels_byte_length", ::apache::thrift::protocol::T_I32, 6); - xfer += oprot->writeI32(this->repetition_levels_byte_length); - xfer += oprot->writeFieldEnd(); - - if (this->__isset.is_compressed) { - xfer += oprot->writeFieldBegin("is_compressed", ::apache::thrift::protocol::T_BOOL, 7); - xfer += oprot->writeBool(this->is_compressed); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 8); - xfer += this->statistics.write(oprot); - xfer += oprot->writeFieldEnd(); - } - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b) { - using ::std::swap; - swap(a.num_values, b.num_values); - swap(a.num_nulls, b.num_nulls); - swap(a.num_rows, b.num_rows); - swap(a.encoding, b.encoding); - swap(a.definition_levels_byte_length, b.definition_levels_byte_length); - swap(a.repetition_levels_byte_length, b.repetition_levels_byte_length); - swap(a.is_compressed, b.is_compressed); - swap(a.statistics, b.statistics); - swap(a.__isset, b.__isset); -} - -DataPageHeaderV2::DataPageHeaderV2(const DataPageHeaderV2& other70) { - num_values = other70.num_values; - num_nulls = other70.num_nulls; - num_rows = other70.num_rows; - encoding = other70.encoding; - definition_levels_byte_length = other70.definition_levels_byte_length; - repetition_levels_byte_length = other70.repetition_levels_byte_length; - is_compressed = other70.is_compressed; - statistics = other70.statistics; - __isset = other70.__isset; -} -DataPageHeaderV2& DataPageHeaderV2::operator=(const DataPageHeaderV2& other71) { - num_values = other71.num_values; - num_nulls = other71.num_nulls; - num_rows = other71.num_rows; - encoding = other71.encoding; - definition_levels_byte_length = other71.definition_levels_byte_length; - repetition_levels_byte_length = other71.repetition_levels_byte_length; - is_compressed = other71.is_compressed; - statistics = other71.statistics; - __isset = other71.__isset; - return *this; -} -void DataPageHeaderV2::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "DataPageHeaderV2("; - out << "num_values=" << to_string(num_values); - out << ", " << "num_nulls=" << to_string(num_nulls); - out << ", " << "num_rows=" << to_string(num_rows); - out << ", " << "encoding=" << to_string(encoding); - out << ", " << "definition_levels_byte_length=" << to_string(definition_levels_byte_length); - out << ", " << "repetition_levels_byte_length=" << to_string(repetition_levels_byte_length); - out << ", " << "is_compressed="; (__isset.is_compressed ? (out << to_string(is_compressed)) : (out << "")); - out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); - out << ")"; -} - - -SplitBlockAlgorithm::~SplitBlockAlgorithm() noexcept { -} - -SplitBlockAlgorithm::SplitBlockAlgorithm() noexcept { -} -std::ostream& operator<<(std::ostream& out, const SplitBlockAlgorithm& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t SplitBlockAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - xfer += iprot->skip(ftype); - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t SplitBlockAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("SplitBlockAlgorithm"); - - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(SplitBlockAlgorithm &a, SplitBlockAlgorithm &b) { - using ::std::swap; - (void) a; - (void) b; -} - -SplitBlockAlgorithm::SplitBlockAlgorithm(const SplitBlockAlgorithm& other72) noexcept { - (void) other72; -} -SplitBlockAlgorithm& SplitBlockAlgorithm::operator=(const SplitBlockAlgorithm& other73) noexcept { - (void) other73; - return *this; -} -void SplitBlockAlgorithm::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "SplitBlockAlgorithm("; - out << ")"; -} - - -BloomFilterAlgorithm::~BloomFilterAlgorithm() noexcept { -} - -BloomFilterAlgorithm::BloomFilterAlgorithm() noexcept { -} - -void BloomFilterAlgorithm::__set_BLOCK(const SplitBlockAlgorithm& val) { - this->BLOCK = val; -__isset.BLOCK = true; -} -std::ostream& operator<<(std::ostream& out, const BloomFilterAlgorithm& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t BloomFilterAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - switch (fid) - { - case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->BLOCK.read(iprot); - this->__isset.BLOCK = true; - } else { - xfer += iprot->skip(ftype); - } - break; - default: - xfer += iprot->skip(ftype); - break; - } - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t BloomFilterAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("BloomFilterAlgorithm"); - - if (this->__isset.BLOCK) { - xfer += oprot->writeFieldBegin("BLOCK", ::apache::thrift::protocol::T_STRUCT, 1); - xfer += this->BLOCK.write(oprot); - xfer += oprot->writeFieldEnd(); - } - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(BloomFilterAlgorithm &a, BloomFilterAlgorithm &b) { - using ::std::swap; - swap(a.BLOCK, b.BLOCK); - swap(a.__isset, b.__isset); -} - -BloomFilterAlgorithm::BloomFilterAlgorithm(const BloomFilterAlgorithm& other74) noexcept { - BLOCK = other74.BLOCK; - __isset = other74.__isset; -} -BloomFilterAlgorithm& BloomFilterAlgorithm::operator=(const BloomFilterAlgorithm& other75) noexcept { - BLOCK = other75.BLOCK; - __isset = other75.__isset; - return *this; -} -void BloomFilterAlgorithm::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "BloomFilterAlgorithm("; - out << "BLOCK="; (__isset.BLOCK ? (out << to_string(BLOCK)) : (out << "")); - out << ")"; -} - - -XxHash::~XxHash() noexcept { -} - -XxHash::XxHash() noexcept { -} -std::ostream& operator<<(std::ostream& out, const XxHash& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t XxHash::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - xfer += iprot->skip(ftype); - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t XxHash::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("XxHash"); - - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(XxHash &a, XxHash &b) { - using ::std::swap; - (void) a; - (void) b; -} - -XxHash::XxHash(const XxHash& other76) noexcept { - (void) other76; -} -XxHash& XxHash::operator=(const XxHash& other77) noexcept { - (void) other77; - return *this; -} -void XxHash::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "XxHash("; - out << ")"; -} - - -BloomFilterHash::~BloomFilterHash() noexcept { -} - -BloomFilterHash::BloomFilterHash() noexcept { -} - -void BloomFilterHash::__set_XXHASH(const XxHash& val) { - this->XXHASH = val; -__isset.XXHASH = true; -} -std::ostream& operator<<(std::ostream& out, const BloomFilterHash& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t BloomFilterHash::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - switch (fid) - { - case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->XXHASH.read(iprot); - this->__isset.XXHASH = true; - } else { - xfer += iprot->skip(ftype); - } - break; - default: - xfer += iprot->skip(ftype); - break; - } - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t BloomFilterHash::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("BloomFilterHash"); - - if (this->__isset.XXHASH) { - xfer += oprot->writeFieldBegin("XXHASH", ::apache::thrift::protocol::T_STRUCT, 1); - xfer += this->XXHASH.write(oprot); - xfer += oprot->writeFieldEnd(); - } - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(BloomFilterHash &a, BloomFilterHash &b) { - using ::std::swap; - swap(a.XXHASH, b.XXHASH); - swap(a.__isset, b.__isset); -} - -BloomFilterHash::BloomFilterHash(const BloomFilterHash& other78) noexcept { - XXHASH = other78.XXHASH; - __isset = other78.__isset; -} -BloomFilterHash& BloomFilterHash::operator=(const BloomFilterHash& other79) noexcept { - XXHASH = other79.XXHASH; - __isset = other79.__isset; - return *this; -} -void BloomFilterHash::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "BloomFilterHash("; - out << "XXHASH="; (__isset.XXHASH ? (out << to_string(XXHASH)) : (out << "")); - out << ")"; -} - - -Uncompressed::~Uncompressed() noexcept { -} - -Uncompressed::Uncompressed() noexcept { -} -std::ostream& operator<<(std::ostream& out, const Uncompressed& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t Uncompressed::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - xfer += iprot->skip(ftype); - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t Uncompressed::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("Uncompressed"); - - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; -} - -void swap(Uncompressed &a, Uncompressed &b) { - using ::std::swap; - (void) a; - (void) b; -} - -Uncompressed::Uncompressed(const Uncompressed& other80) noexcept { - (void) other80; -} -Uncompressed& Uncompressed::operator=(const Uncompressed& other81) noexcept { - (void) other81; - return *this; -} -void Uncompressed::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "Uncompressed("; - out << ")"; -} - - -BloomFilterCompression::~BloomFilterCompression() noexcept { -} - -BloomFilterCompression::BloomFilterCompression() noexcept { -} - -void BloomFilterCompression::__set_UNCOMPRESSED(const Uncompressed& val) { - this->UNCOMPRESSED = val; -__isset.UNCOMPRESSED = true; -} -std::ostream& operator<<(std::ostream& out, const BloomFilterCompression& obj) -{ - obj.printTo(out); - return out; -} - - -uint32_t BloomFilterCompression::read(::apache::thrift::protocol::TProtocol* iprot) { - - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); - uint32_t xfer = 0; - std::string fname; - ::apache::thrift::protocol::TType ftype; - int16_t fid; - - xfer += iprot->readStructBegin(fname); - - using ::apache::thrift::protocol::TProtocolException; - - - while (true) - { - xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { - break; - } - switch (fid) - { - case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->UNCOMPRESSED.read(iprot); - this->__isset.UNCOMPRESSED = true; - } else { - xfer += iprot->skip(ftype); - } - break; - default: - xfer += iprot->skip(ftype); - break; - } - xfer += iprot->readFieldEnd(); - } - - xfer += iprot->readStructEnd(); - - return xfer; -} - -uint32_t BloomFilterCompression::write(::apache::thrift::protocol::TProtocol* oprot) const { - uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("BloomFilterCompression"); - - if (this->__isset.UNCOMPRESSED) { - xfer += oprot->writeFieldBegin("UNCOMPRESSED", ::apache::thrift::protocol::T_STRUCT, 1); - xfer += this->UNCOMPRESSED.write(oprot); - xfer += oprot->writeFieldEnd(); - } - xfer += oprot->writeFieldStop(); - xfer += oprot->writeStructEnd(); - return xfer; + out << ", " << "encoding=" << to_string(encoding); + out << ", " << "is_sorted="; (__isset.is_sorted ? (out << to_string(is_sorted)) : (out << "")); + out << ")"; } -void swap(BloomFilterCompression &a, BloomFilterCompression &b) { - using ::std::swap; - swap(a.UNCOMPRESSED, b.UNCOMPRESSED); - swap(a.__isset, b.__isset); -} -BloomFilterCompression::BloomFilterCompression(const BloomFilterCompression& other82) noexcept { - UNCOMPRESSED = other82.UNCOMPRESSED; - __isset = other82.__isset; -} -BloomFilterCompression& BloomFilterCompression::operator=(const BloomFilterCompression& other83) noexcept { - UNCOMPRESSED = other83.UNCOMPRESSED; - __isset = other83.__isset; - return *this; +DataPageHeaderV2::~DataPageHeaderV2() throw() { } -void BloomFilterCompression::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "BloomFilterCompression("; - out << "UNCOMPRESSED="; (__isset.UNCOMPRESSED ? (out << to_string(UNCOMPRESSED)) : (out << "")); - out << ")"; + + +void DataPageHeaderV2::__set_num_values(const int32_t val) { + this->num_values = val; } +void DataPageHeaderV2::__set_num_nulls(const int32_t val) { + this->num_nulls = val; +} -BloomFilterHeader::~BloomFilterHeader() noexcept { +void DataPageHeaderV2::__set_num_rows(const int32_t val) { + this->num_rows = val; } -BloomFilterHeader::BloomFilterHeader() noexcept - : numBytes(0) { +void DataPageHeaderV2::__set_encoding(const Encoding::type val) { + this->encoding = val; } -void BloomFilterHeader::__set_numBytes(const int32_t val) { - this->numBytes = val; +void DataPageHeaderV2::__set_definition_levels_byte_length(const int32_t val) { + this->definition_levels_byte_length = val; } -void BloomFilterHeader::__set_algorithm(const BloomFilterAlgorithm& val) { - this->algorithm = val; +void DataPageHeaderV2::__set_repetition_levels_byte_length(const int32_t val) { + this->repetition_levels_byte_length = val; } -void BloomFilterHeader::__set_hash(const BloomFilterHash& val) { - this->hash = val; +void DataPageHeaderV2::__set_is_compressed(const bool val) { + this->is_compressed = val; +__isset.is_compressed = true; } -void BloomFilterHeader::__set_compression(const BloomFilterCompression& val) { - this->compression = val; +void DataPageHeaderV2::__set_statistics(const Statistics& val) { + this->statistics = val; +__isset.statistics = true; } -std::ostream& operator<<(std::ostream& out, const BloomFilterHeader& obj) +std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj) { obj.printTo(out); return out; } -uint32_t BloomFilterHeader::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t DataPageHeaderV2::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; - bool isset_numBytes = false; - bool isset_algorithm = false; - bool isset_hash = false; - bool isset_compression = false; + bool isset_num_values = false; + bool isset_num_nulls = false; + bool isset_num_rows = false; + bool isset_encoding = false; + bool isset_definition_levels_byte_length = false; + bool isset_repetition_levels_byte_length = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->numBytes); - isset_numBytes = true; + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_values); + isset_num_values = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->algorithm.read(iprot); - isset_algorithm = true; + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_nulls); + isset_num_nulls = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->hash.read(iprot); - isset_hash = true; + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->num_rows); + isset_num_rows = true; } else { xfer += iprot->skip(ftype); } break; case 4: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->compression.read(iprot); - isset_compression = true; + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast53; + xfer += iprot->readI32(ecast53); + this->encoding = (Encoding::type)ecast53; + isset_encoding = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 5: + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->definition_levels_byte_length); + isset_definition_levels_byte_length = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 6: + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + xfer += iprot->readI32(this->repetition_levels_byte_length); + isset_repetition_levels_byte_length = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 7: + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { + xfer += iprot->readBool(this->is_compressed); + this->__isset.is_compressed = true; + } else { + xfer += iprot->skip(ftype); + } + break; + case 8: + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { + xfer += this->statistics.read(iprot); + this->__isset.statistics = true; } else { xfer += iprot->skip(ftype); } @@ -4549,84 +3067,119 @@ uint32_t BloomFilterHeader::read(::apache::thrift::protocol::TProtocol* iprot) { xfer += iprot->readStructEnd(); - if (!isset_numBytes) + if (!isset_num_values) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_num_nulls) + throw TProtocolException(TProtocolException::INVALID_DATA); + if (!isset_num_rows) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_algorithm) + if (!isset_encoding) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_hash) + if (!isset_definition_levels_byte_length) throw TProtocolException(TProtocolException::INVALID_DATA); - if (!isset_compression) + if (!isset_repetition_levels_byte_length) throw TProtocolException(TProtocolException::INVALID_DATA); return xfer; } -uint32_t BloomFilterHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t DataPageHeaderV2::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); - xfer += oprot->writeStructBegin("BloomFilterHeader"); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + xfer += oprot->writeStructBegin("DataPageHeaderV2"); + + xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32(this->num_values); + xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("numBytes", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(this->numBytes); + xfer += oprot->writeFieldBegin("num_nulls", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32(this->num_nulls); + xfer += oprot->writeFieldEnd(); + + xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeI32(this->num_rows); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("algorithm", ::apache::thrift::protocol::T_STRUCT, 2); - xfer += this->algorithm.write(oprot); + xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32((int32_t)this->encoding); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("hash", ::apache::thrift::protocol::T_STRUCT, 3); - xfer += this->hash.write(oprot); + xfer += oprot->writeFieldBegin("definition_levels_byte_length", ::duckdb_apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeI32(this->definition_levels_byte_length); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("compression", ::apache::thrift::protocol::T_STRUCT, 4); - xfer += this->compression.write(oprot); + xfer += oprot->writeFieldBegin("repetition_levels_byte_length", ::duckdb_apache::thrift::protocol::T_I32, 6); + xfer += oprot->writeI32(this->repetition_levels_byte_length); xfer += oprot->writeFieldEnd(); + if (this->__isset.is_compressed) { + xfer += oprot->writeFieldBegin("is_compressed", ::duckdb_apache::thrift::protocol::T_BOOL, 7); + xfer += oprot->writeBool(this->is_compressed); + xfer += oprot->writeFieldEnd(); + } + if (this->__isset.statistics) { + xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); + xfer += this->statistics.write(oprot); + xfer += oprot->writeFieldEnd(); + } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; } -void swap(BloomFilterHeader &a, BloomFilterHeader &b) { +void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b) { using ::std::swap; - swap(a.numBytes, b.numBytes); - swap(a.algorithm, b.algorithm); - swap(a.hash, b.hash); - swap(a.compression, b.compression); -} - -BloomFilterHeader::BloomFilterHeader(const BloomFilterHeader& other84) noexcept { - numBytes = other84.numBytes; - algorithm = other84.algorithm; - hash = other84.hash; - compression = other84.compression; -} -BloomFilterHeader& BloomFilterHeader::operator=(const BloomFilterHeader& other85) noexcept { - numBytes = other85.numBytes; - algorithm = other85.algorithm; - hash = other85.hash; - compression = other85.compression; + swap(a.num_values, b.num_values); + swap(a.num_nulls, b.num_nulls); + swap(a.num_rows, b.num_rows); + swap(a.encoding, b.encoding); + swap(a.definition_levels_byte_length, b.definition_levels_byte_length); + swap(a.repetition_levels_byte_length, b.repetition_levels_byte_length); + swap(a.is_compressed, b.is_compressed); + swap(a.statistics, b.statistics); + swap(a.__isset, b.__isset); +} + +DataPageHeaderV2::DataPageHeaderV2(const DataPageHeaderV2& other54) { + num_values = other54.num_values; + num_nulls = other54.num_nulls; + num_rows = other54.num_rows; + encoding = other54.encoding; + definition_levels_byte_length = other54.definition_levels_byte_length; + repetition_levels_byte_length = other54.repetition_levels_byte_length; + is_compressed = other54.is_compressed; + statistics = other54.statistics; + __isset = other54.__isset; +} +DataPageHeaderV2& DataPageHeaderV2::operator=(const DataPageHeaderV2& other55) { + num_values = other55.num_values; + num_nulls = other55.num_nulls; + num_rows = other55.num_rows; + encoding = other55.encoding; + definition_levels_byte_length = other55.definition_levels_byte_length; + repetition_levels_byte_length = other55.repetition_levels_byte_length; + is_compressed = other55.is_compressed; + statistics = other55.statistics; + __isset = other55.__isset; return *this; } -void BloomFilterHeader::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; - out << "BloomFilterHeader("; - out << "numBytes=" << to_string(numBytes); - out << ", " << "algorithm=" << to_string(algorithm); - out << ", " << "hash=" << to_string(hash); - out << ", " << "compression=" << to_string(compression); +void DataPageHeaderV2::printTo(std::ostream& out) const { + using ::duckdb_apache::thrift::to_string; + out << "DataPageHeaderV2("; + out << "num_values=" << to_string(num_values); + out << ", " << "num_nulls=" << to_string(num_nulls); + out << ", " << "num_rows=" << to_string(num_rows); + out << ", " << "encoding=" << to_string(encoding); + out << ", " << "definition_levels_byte_length=" << to_string(definition_levels_byte_length); + out << ", " << "repetition_levels_byte_length=" << to_string(repetition_levels_byte_length); + out << ", " << "is_compressed="; (__isset.is_compressed ? (out << to_string(is_compressed)) : (out << "")); + out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); out << ")"; } -PageHeader::~PageHeader() noexcept { +PageHeader::~PageHeader() throw() { } -PageHeader::PageHeader() noexcept - : type(static_cast(0)), - uncompressed_page_size(0), - compressed_page_size(0), - crc(0) { -} void PageHeader::__set_type(const PageType::type val) { this->type = val; @@ -4671,17 +3224,17 @@ std::ostream& operator<<(std::ostream& out, const PageHeader& obj) } -uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageHeader::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_type = false; bool isset_uncompressed_page_size = false; @@ -4690,23 +3243,23 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast86; - xfer += iprot->readI32(ecast86); - this->type = static_cast(ecast86); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast56; + xfer += iprot->readI32(ecast56); + this->type = (PageType::type)ecast56; isset_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->uncompressed_page_size); isset_uncompressed_page_size = true; } else { @@ -4714,7 +3267,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->compressed_page_size); isset_compressed_page_size = true; } else { @@ -4722,7 +3275,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->crc); this->__isset.crc = true; } else { @@ -4730,7 +3283,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->data_page_header.read(iprot); this->__isset.data_page_header = true; } else { @@ -4738,7 +3291,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->index_page_header.read(iprot); this->__isset.index_page_header = true; } else { @@ -4746,7 +3299,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->dictionary_page_header.read(iprot); this->__isset.dictionary_page_header = true; } else { @@ -4754,7 +3307,7 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->data_page_header_v2.read(iprot); this->__isset.data_page_header_v2 = true; } else { @@ -4779,45 +3332,45 @@ uint32_t PageHeader::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t PageHeader::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageHeader::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageHeader"); - xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(static_cast(this->type)); + xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->type); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("uncompressed_page_size", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("uncompressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->uncompressed_page_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("compressed_page_size", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeFieldBegin("compressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 3); xfer += oprot->writeI32(this->compressed_page_size); xfer += oprot->writeFieldEnd(); if (this->__isset.crc) { - xfer += oprot->writeFieldBegin("crc", ::apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeFieldBegin("crc", ::duckdb_apache::thrift::protocol::T_I32, 4); xfer += oprot->writeI32(this->crc); xfer += oprot->writeFieldEnd(); } if (this->__isset.data_page_header) { - xfer += oprot->writeFieldBegin("data_page_header", ::apache::thrift::protocol::T_STRUCT, 5); + xfer += oprot->writeFieldBegin("data_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 5); xfer += this->data_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.index_page_header) { - xfer += oprot->writeFieldBegin("index_page_header", ::apache::thrift::protocol::T_STRUCT, 6); + xfer += oprot->writeFieldBegin("index_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 6); xfer += this->index_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.dictionary_page_header) { - xfer += oprot->writeFieldBegin("dictionary_page_header", ::apache::thrift::protocol::T_STRUCT, 7); + xfer += oprot->writeFieldBegin("dictionary_page_header", ::duckdb_apache::thrift::protocol::T_STRUCT, 7); xfer += this->dictionary_page_header.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.data_page_header_v2) { - xfer += oprot->writeFieldBegin("data_page_header_v2", ::apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("data_page_header_v2", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); xfer += this->data_page_header_v2.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -4839,31 +3392,31 @@ void swap(PageHeader &a, PageHeader &b) { swap(a.__isset, b.__isset); } -PageHeader::PageHeader(const PageHeader& other87) { - type = other87.type; - uncompressed_page_size = other87.uncompressed_page_size; - compressed_page_size = other87.compressed_page_size; - crc = other87.crc; - data_page_header = other87.data_page_header; - index_page_header = other87.index_page_header; - dictionary_page_header = other87.dictionary_page_header; - data_page_header_v2 = other87.data_page_header_v2; - __isset = other87.__isset; -} -PageHeader& PageHeader::operator=(const PageHeader& other88) { - type = other88.type; - uncompressed_page_size = other88.uncompressed_page_size; - compressed_page_size = other88.compressed_page_size; - crc = other88.crc; - data_page_header = other88.data_page_header; - index_page_header = other88.index_page_header; - dictionary_page_header = other88.dictionary_page_header; - data_page_header_v2 = other88.data_page_header_v2; - __isset = other88.__isset; +PageHeader::PageHeader(const PageHeader& other57) { + type = other57.type; + uncompressed_page_size = other57.uncompressed_page_size; + compressed_page_size = other57.compressed_page_size; + crc = other57.crc; + data_page_header = other57.data_page_header; + index_page_header = other57.index_page_header; + dictionary_page_header = other57.dictionary_page_header; + data_page_header_v2 = other57.data_page_header_v2; + __isset = other57.__isset; +} +PageHeader& PageHeader::operator=(const PageHeader& other58) { + type = other58.type; + uncompressed_page_size = other58.uncompressed_page_size; + compressed_page_size = other58.compressed_page_size; + crc = other58.crc; + data_page_header = other58.data_page_header; + index_page_header = other58.index_page_header; + dictionary_page_header = other58.dictionary_page_header; + data_page_header_v2 = other58.data_page_header_v2; + __isset = other58.__isset; return *this; } void PageHeader::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "PageHeader("; out << "type=" << to_string(type); out << ", " << "uncompressed_page_size=" << to_string(uncompressed_page_size); @@ -4877,13 +3430,9 @@ void PageHeader::printTo(std::ostream& out) const { } -KeyValue::~KeyValue() noexcept { +KeyValue::~KeyValue() throw() { } -KeyValue::KeyValue() noexcept - : key(), - value() { -} void KeyValue::__set_key(const std::string& val) { this->key = val; @@ -4900,30 +3449,30 @@ std::ostream& operator<<(std::ostream& out, const KeyValue& obj) } -uint32_t KeyValue::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t KeyValue::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_key = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->key); isset_key = true; } else { @@ -4931,7 +3480,7 @@ uint32_t KeyValue::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->value); this->__isset.value = true; } else { @@ -4952,17 +3501,17 @@ uint32_t KeyValue::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t KeyValue::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t KeyValue::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("KeyValue"); - xfer += oprot->writeFieldBegin("key", ::apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("key", ::duckdb_apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeString(this->key); xfer += oprot->writeFieldEnd(); if (this->__isset.value) { - xfer += oprot->writeFieldBegin("value", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("value", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeString(this->value); xfer += oprot->writeFieldEnd(); } @@ -4978,19 +3527,19 @@ void swap(KeyValue &a, KeyValue &b) { swap(a.__isset, b.__isset); } -KeyValue::KeyValue(const KeyValue& other89) { - key = other89.key; - value = other89.value; - __isset = other89.__isset; +KeyValue::KeyValue(const KeyValue& other59) { + key = other59.key; + value = other59.value; + __isset = other59.__isset; } -KeyValue& KeyValue::operator=(const KeyValue& other90) { - key = other90.key; - value = other90.value; - __isset = other90.__isset; +KeyValue& KeyValue::operator=(const KeyValue& other60) { + key = other60.key; + value = other60.value; + __isset = other60.__isset; return *this; } void KeyValue::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "KeyValue("; out << "key=" << to_string(key); out << ", " << "value="; (__isset.value ? (out << to_string(value)) : (out << "")); @@ -4998,14 +3547,9 @@ void KeyValue::printTo(std::ostream& out) const { } -SortingColumn::~SortingColumn() noexcept { +SortingColumn::~SortingColumn() throw() { } -SortingColumn::SortingColumn() noexcept - : column_idx(0), - descending(0), - nulls_first(0) { -} void SortingColumn::__set_column_idx(const int32_t val) { this->column_idx = val; @@ -5025,17 +3569,17 @@ std::ostream& operator<<(std::ostream& out, const SortingColumn& obj) } -uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t SortingColumn::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_column_idx = false; bool isset_descending = false; @@ -5044,13 +3588,13 @@ uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->column_idx); isset_column_idx = true; } else { @@ -5058,7 +3602,7 @@ uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->descending); isset_descending = true; } else { @@ -5066,7 +3610,7 @@ uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->nulls_first); isset_nulls_first = true; } else { @@ -5091,20 +3635,20 @@ uint32_t SortingColumn::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t SortingColumn::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t SortingColumn::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("SortingColumn"); - xfer += oprot->writeFieldBegin("column_idx", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("column_idx", ::duckdb_apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->column_idx); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("descending", ::apache::thrift::protocol::T_BOOL, 2); + xfer += oprot->writeFieldBegin("descending", ::duckdb_apache::thrift::protocol::T_BOOL, 2); xfer += oprot->writeBool(this->descending); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("nulls_first", ::apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("nulls_first", ::duckdb_apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->nulls_first); xfer += oprot->writeFieldEnd(); @@ -5120,19 +3664,19 @@ void swap(SortingColumn &a, SortingColumn &b) { swap(a.nulls_first, b.nulls_first); } -SortingColumn::SortingColumn(const SortingColumn& other91) noexcept { - column_idx = other91.column_idx; - descending = other91.descending; - nulls_first = other91.nulls_first; +SortingColumn::SortingColumn(const SortingColumn& other61) { + column_idx = other61.column_idx; + descending = other61.descending; + nulls_first = other61.nulls_first; } -SortingColumn& SortingColumn::operator=(const SortingColumn& other92) noexcept { - column_idx = other92.column_idx; - descending = other92.descending; - nulls_first = other92.nulls_first; +SortingColumn& SortingColumn::operator=(const SortingColumn& other62) { + column_idx = other62.column_idx; + descending = other62.descending; + nulls_first = other62.nulls_first; return *this; } void SortingColumn::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "SortingColumn("; out << "column_idx=" << to_string(column_idx); out << ", " << "descending=" << to_string(descending); @@ -5141,14 +3685,9 @@ void SortingColumn::printTo(std::ostream& out) const { } -PageEncodingStats::~PageEncodingStats() noexcept { +PageEncodingStats::~PageEncodingStats() throw() { } -PageEncodingStats::PageEncodingStats() noexcept - : page_type(static_cast(0)), - encoding(static_cast(0)), - count(0) { -} void PageEncodingStats::__set_page_type(const PageType::type val) { this->page_type = val; @@ -5168,17 +3707,17 @@ std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj) } -uint32_t PageEncodingStats::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageEncodingStats::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_page_type = false; bool isset_encoding = false; @@ -5187,33 +3726,33 @@ uint32_t PageEncodingStats::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast93; - xfer += iprot->readI32(ecast93); - this->page_type = static_cast(ecast93); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast63; + xfer += iprot->readI32(ecast63); + this->page_type = (PageType::type)ecast63; isset_page_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast94; - xfer += iprot->readI32(ecast94); - this->encoding = static_cast(ecast94); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast64; + xfer += iprot->readI32(ecast64); + this->encoding = (Encoding::type)ecast64; isset_encoding = true; } else { xfer += iprot->skip(ftype); } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->count); isset_count = true; } else { @@ -5238,20 +3777,20 @@ uint32_t PageEncodingStats::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t PageEncodingStats::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageEncodingStats::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageEncodingStats"); - xfer += oprot->writeFieldBegin("page_type", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(static_cast(this->page_type)); + xfer += oprot->writeFieldBegin("page_type", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->page_type); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encoding", ::apache::thrift::protocol::T_I32, 2); - xfer += oprot->writeI32(static_cast(this->encoding)); + xfer += oprot->writeFieldBegin("encoding", ::duckdb_apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeI32((int32_t)this->encoding); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("count", ::apache::thrift::protocol::T_I32, 3); + xfer += oprot->writeFieldBegin("count", ::duckdb_apache::thrift::protocol::T_I32, 3); xfer += oprot->writeI32(this->count); xfer += oprot->writeFieldEnd(); @@ -5267,19 +3806,19 @@ void swap(PageEncodingStats &a, PageEncodingStats &b) { swap(a.count, b.count); } -PageEncodingStats::PageEncodingStats(const PageEncodingStats& other95) noexcept { - page_type = other95.page_type; - encoding = other95.encoding; - count = other95.count; +PageEncodingStats::PageEncodingStats(const PageEncodingStats& other65) { + page_type = other65.page_type; + encoding = other65.encoding; + count = other65.count; } -PageEncodingStats& PageEncodingStats::operator=(const PageEncodingStats& other96) noexcept { - page_type = other96.page_type; - encoding = other96.encoding; - count = other96.count; +PageEncodingStats& PageEncodingStats::operator=(const PageEncodingStats& other66) { + page_type = other66.page_type; + encoding = other66.encoding; + count = other66.count; return *this; } void PageEncodingStats::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "PageEncodingStats("; out << "page_type=" << to_string(page_type); out << ", " << "encoding=" << to_string(encoding); @@ -5288,21 +3827,9 @@ void PageEncodingStats::printTo(std::ostream& out) const { } -ColumnMetaData::~ColumnMetaData() noexcept { +ColumnMetaData::~ColumnMetaData() throw() { } -ColumnMetaData::ColumnMetaData() noexcept - : type(static_cast(0)), - codec(static_cast(0)), - num_values(0), - total_uncompressed_size(0), - total_compressed_size(0), - data_page_offset(0), - index_page_offset(0), - dictionary_page_offset(0), - bloom_filter_offset(0), - bloom_filter_length(0) { -} void ColumnMetaData::__set_type(const Type::type val) { this->type = val; @@ -5360,21 +3887,6 @@ void ColumnMetaData::__set_encoding_stats(const duckdb::vectorencoding_stats = val; __isset.encoding_stats = true; } - -void ColumnMetaData::__set_bloom_filter_offset(const int64_t val) { - this->bloom_filter_offset = val; -__isset.bloom_filter_offset = true; -} - -void ColumnMetaData::__set_bloom_filter_length(const int32_t val) { - this->bloom_filter_length = val; -__isset.bloom_filter_length = true; -} - -void ColumnMetaData::__set_size_statistics(const SizeStatistics& val) { - this->size_statistics = val; -__isset.size_statistics = true; -} std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj) { obj.printTo(out); @@ -5382,17 +3894,17 @@ std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj) } -uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_type = false; bool isset_encodings = false; @@ -5406,35 +3918,35 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast97; - xfer += iprot->readI32(ecast97); - this->type = static_cast(ecast97); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast67; + xfer += iprot->readI32(ecast67); + this->type = (Type::type)ecast67; isset_type = true; } else { xfer += iprot->skip(ftype); } break; case 2: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->encodings.clear(); - uint32_t _size98; - ::apache::thrift::protocol::TType _etype101; - xfer += iprot->readListBegin(_etype101, _size98); - this->encodings.resize(_size98); - uint32_t _i102; - for (_i102 = 0; _i102 < _size98; ++_i102) + uint32_t _size68; + ::duckdb_apache::thrift::protocol::TType _etype71; + xfer += iprot->readListBegin(_etype71, _size68); + this->encodings.resize(_size68); + uint32_t _i72; + for (_i72 = 0; _i72 < _size68; ++_i72) { - int32_t ecast103; - xfer += iprot->readI32(ecast103); - this->encodings[_i102] = static_cast(ecast103); + int32_t ecast73; + xfer += iprot->readI32(ecast73); + this->encodings[_i72] = (Encoding::type)ecast73; } xfer += iprot->readListEnd(); } @@ -5444,17 +3956,17 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->path_in_schema.clear(); - uint32_t _size104; - ::apache::thrift::protocol::TType _etype107; - xfer += iprot->readListBegin(_etype107, _size104); - this->path_in_schema.resize(_size104); - uint32_t _i108; - for (_i108 = 0; _i108 < _size104; ++_i108) + uint32_t _size74; + ::duckdb_apache::thrift::protocol::TType _etype77; + xfer += iprot->readListBegin(_etype77, _size74); + this->path_in_schema.resize(_size74); + uint32_t _i78; + for (_i78 = 0; _i78 < _size74; ++_i78) { - xfer += iprot->readString(this->path_in_schema[_i108]); + xfer += iprot->readString(this->path_in_schema[_i78]); } xfer += iprot->readListEnd(); } @@ -5464,17 +3976,17 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast109; - xfer += iprot->readI32(ecast109); - this->codec = static_cast(ecast109); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast79; + xfer += iprot->readI32(ecast79); + this->codec = (CompressionCodec::type)ecast79; isset_codec = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_values); isset_num_values = true; } else { @@ -5482,7 +3994,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_uncompressed_size); isset_total_uncompressed_size = true; } else { @@ -5490,7 +4002,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_compressed_size); isset_total_compressed_size = true; } else { @@ -5498,17 +4010,17 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->key_value_metadata.clear(); - uint32_t _size110; - ::apache::thrift::protocol::TType _etype113; - xfer += iprot->readListBegin(_etype113, _size110); - this->key_value_metadata.resize(_size110); - uint32_t _i114; - for (_i114 = 0; _i114 < _size110; ++_i114) + uint32_t _size80; + ::duckdb_apache::thrift::protocol::TType _etype83; + xfer += iprot->readListBegin(_etype83, _size80); + this->key_value_metadata.resize(_size80); + uint32_t _i84; + for (_i84 = 0; _i84 < _size80; ++_i84) { - xfer += this->key_value_metadata[_i114].read(iprot); + xfer += this->key_value_metadata[_i84].read(iprot); } xfer += iprot->readListEnd(); } @@ -5518,7 +4030,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 9: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->data_page_offset); isset_data_page_offset = true; } else { @@ -5526,7 +4038,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 10: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->index_page_offset); this->__isset.index_page_offset = true; } else { @@ -5534,7 +4046,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 11: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->dictionary_page_offset); this->__isset.dictionary_page_offset = true; } else { @@ -5542,7 +4054,7 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 12: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->statistics.read(iprot); this->__isset.statistics = true; } else { @@ -5550,17 +4062,17 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 13: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->encoding_stats.clear(); - uint32_t _size115; - ::apache::thrift::protocol::TType _etype118; - xfer += iprot->readListBegin(_etype118, _size115); - this->encoding_stats.resize(_size115); - uint32_t _i119; - for (_i119 = 0; _i119 < _size115; ++_i119) + uint32_t _size85; + ::duckdb_apache::thrift::protocol::TType _etype88; + xfer += iprot->readListBegin(_etype88, _size85); + this->encoding_stats.resize(_size85); + uint32_t _i89; + for (_i89 = 0; _i89 < _size85; ++_i89) { - xfer += this->encoding_stats[_i119].read(iprot); + xfer += this->encoding_stats[_i89].read(iprot); } xfer += iprot->readListEnd(); } @@ -5569,30 +4081,6 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { xfer += iprot->skip(ftype); } break; - case 14: - if (ftype == ::apache::thrift::protocol::T_I64) { - xfer += iprot->readI64(this->bloom_filter_offset); - this->__isset.bloom_filter_offset = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 15: - if (ftype == ::apache::thrift::protocol::T_I32) { - xfer += iprot->readI32(this->bloom_filter_length); - this->__isset.bloom_filter_length = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 16: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { - xfer += this->size_statistics.read(iprot); - this->__isset.size_statistics = true; - } else { - xfer += iprot->skip(ftype); - } - break; default: xfer += iprot->skip(ftype); break; @@ -5621,115 +4109,100 @@ uint32_t ColumnMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ColumnMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnMetaData"); - xfer += oprot->writeFieldBegin("type", ::apache::thrift::protocol::T_I32, 1); - xfer += oprot->writeI32(static_cast(this->type)); + xfer += oprot->writeFieldBegin("type", ::duckdb_apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeI32((int32_t)this->type); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("encodings", ::apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("encodings", ::duckdb_apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I32, static_cast(this->encodings.size())); - duckdb::vector ::const_iterator _iter120; - for (_iter120 = this->encodings.begin(); _iter120 != this->encodings.end(); ++_iter120) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_I32, static_cast(this->encodings.size())); + duckdb::vector ::const_iterator _iter90; + for (_iter90 = this->encodings.begin(); _iter90 != this->encodings.end(); ++_iter90) { - xfer += oprot->writeI32(static_cast((*_iter120))); + xfer += oprot->writeI32((int32_t)(*_iter90)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("path_in_schema", ::apache::thrift::protocol::T_LIST, 3); + xfer += oprot->writeFieldBegin("path_in_schema", ::duckdb_apache::thrift::protocol::T_LIST, 3); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); - duckdb::vector ::const_iterator _iter121; - for (_iter121 = this->path_in_schema.begin(); _iter121 != this->path_in_schema.end(); ++_iter121) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); + duckdb::vector ::const_iterator _iter91; + for (_iter91 = this->path_in_schema.begin(); _iter91 != this->path_in_schema.end(); ++_iter91) { - xfer += oprot->writeString((*_iter121)); + xfer += oprot->writeString((*_iter91)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("codec", ::apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32(static_cast(this->codec)); + xfer += oprot->writeFieldBegin("codec", ::duckdb_apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32((int32_t)this->codec); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_values", ::apache::thrift::protocol::T_I64, 5); + xfer += oprot->writeFieldBegin("num_values", ::duckdb_apache::thrift::protocol::T_I64, 5); xfer += oprot->writeI64(this->num_values); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_uncompressed_size", ::apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("total_uncompressed_size", ::duckdb_apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->total_uncompressed_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_compressed_size", ::apache::thrift::protocol::T_I64, 7); + xfer += oprot->writeFieldBegin("total_compressed_size", ::duckdb_apache::thrift::protocol::T_I64, 7); xfer += oprot->writeI64(this->total_compressed_size); xfer += oprot->writeFieldEnd(); if (this->__isset.key_value_metadata) { - xfer += oprot->writeFieldBegin("key_value_metadata", ::apache::thrift::protocol::T_LIST, 8); + xfer += oprot->writeFieldBegin("key_value_metadata", ::duckdb_apache::thrift::protocol::T_LIST, 8); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); - duckdb::vector ::const_iterator _iter122; - for (_iter122 = this->key_value_metadata.begin(); _iter122 != this->key_value_metadata.end(); ++_iter122) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); + duckdb::vector ::const_iterator _iter92; + for (_iter92 = this->key_value_metadata.begin(); _iter92 != this->key_value_metadata.end(); ++_iter92) { - xfer += (*_iter122).write(oprot); + xfer += (*_iter92).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("data_page_offset", ::apache::thrift::protocol::T_I64, 9); + xfer += oprot->writeFieldBegin("data_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 9); xfer += oprot->writeI64(this->data_page_offset); xfer += oprot->writeFieldEnd(); if (this->__isset.index_page_offset) { - xfer += oprot->writeFieldBegin("index_page_offset", ::apache::thrift::protocol::T_I64, 10); + xfer += oprot->writeFieldBegin("index_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 10); xfer += oprot->writeI64(this->index_page_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.dictionary_page_offset) { - xfer += oprot->writeFieldBegin("dictionary_page_offset", ::apache::thrift::protocol::T_I64, 11); + xfer += oprot->writeFieldBegin("dictionary_page_offset", ::duckdb_apache::thrift::protocol::T_I64, 11); xfer += oprot->writeI64(this->dictionary_page_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.statistics) { - xfer += oprot->writeFieldBegin("statistics", ::apache::thrift::protocol::T_STRUCT, 12); + xfer += oprot->writeFieldBegin("statistics", ::duckdb_apache::thrift::protocol::T_STRUCT, 12); xfer += this->statistics.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.encoding_stats) { - xfer += oprot->writeFieldBegin("encoding_stats", ::apache::thrift::protocol::T_LIST, 13); + xfer += oprot->writeFieldBegin("encoding_stats", ::duckdb_apache::thrift::protocol::T_LIST, 13); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->encoding_stats.size())); - duckdb::vector ::const_iterator _iter123; - for (_iter123 = this->encoding_stats.begin(); _iter123 != this->encoding_stats.end(); ++_iter123) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->encoding_stats.size())); + duckdb::vector ::const_iterator _iter93; + for (_iter93 = this->encoding_stats.begin(); _iter93 != this->encoding_stats.end(); ++_iter93) { - xfer += (*_iter123).write(oprot); + xfer += (*_iter93).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } - if (this->__isset.bloom_filter_offset) { - xfer += oprot->writeFieldBegin("bloom_filter_offset", ::apache::thrift::protocol::T_I64, 14); - xfer += oprot->writeI64(this->bloom_filter_offset); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.bloom_filter_length) { - xfer += oprot->writeFieldBegin("bloom_filter_length", ::apache::thrift::protocol::T_I32, 15); - xfer += oprot->writeI32(this->bloom_filter_length); - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.size_statistics) { - xfer += oprot->writeFieldBegin("size_statistics", ::apache::thrift::protocol::T_STRUCT, 16); - xfer += this->size_statistics.write(oprot); - xfer += oprot->writeFieldEnd(); - } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -5750,53 +4223,44 @@ void swap(ColumnMetaData &a, ColumnMetaData &b) { swap(a.dictionary_page_offset, b.dictionary_page_offset); swap(a.statistics, b.statistics); swap(a.encoding_stats, b.encoding_stats); - swap(a.bloom_filter_offset, b.bloom_filter_offset); - swap(a.bloom_filter_length, b.bloom_filter_length); - swap(a.size_statistics, b.size_statistics); swap(a.__isset, b.__isset); } -ColumnMetaData::ColumnMetaData(const ColumnMetaData& other124) { - type = other124.type; - encodings = other124.encodings; - path_in_schema = other124.path_in_schema; - codec = other124.codec; - num_values = other124.num_values; - total_uncompressed_size = other124.total_uncompressed_size; - total_compressed_size = other124.total_compressed_size; - key_value_metadata = other124.key_value_metadata; - data_page_offset = other124.data_page_offset; - index_page_offset = other124.index_page_offset; - dictionary_page_offset = other124.dictionary_page_offset; - statistics = other124.statistics; - encoding_stats = other124.encoding_stats; - bloom_filter_offset = other124.bloom_filter_offset; - bloom_filter_length = other124.bloom_filter_length; - size_statistics = other124.size_statistics; - __isset = other124.__isset; -} -ColumnMetaData& ColumnMetaData::operator=(const ColumnMetaData& other125) { - type = other125.type; - encodings = other125.encodings; - path_in_schema = other125.path_in_schema; - codec = other125.codec; - num_values = other125.num_values; - total_uncompressed_size = other125.total_uncompressed_size; - total_compressed_size = other125.total_compressed_size; - key_value_metadata = other125.key_value_metadata; - data_page_offset = other125.data_page_offset; - index_page_offset = other125.index_page_offset; - dictionary_page_offset = other125.dictionary_page_offset; - statistics = other125.statistics; - encoding_stats = other125.encoding_stats; - bloom_filter_offset = other125.bloom_filter_offset; - bloom_filter_length = other125.bloom_filter_length; - size_statistics = other125.size_statistics; - __isset = other125.__isset; +ColumnMetaData::ColumnMetaData(const ColumnMetaData& other94) { + type = other94.type; + encodings = other94.encodings; + path_in_schema = other94.path_in_schema; + codec = other94.codec; + num_values = other94.num_values; + total_uncompressed_size = other94.total_uncompressed_size; + total_compressed_size = other94.total_compressed_size; + key_value_metadata = other94.key_value_metadata; + data_page_offset = other94.data_page_offset; + index_page_offset = other94.index_page_offset; + dictionary_page_offset = other94.dictionary_page_offset; + statistics = other94.statistics; + encoding_stats = other94.encoding_stats; + __isset = other94.__isset; +} +ColumnMetaData& ColumnMetaData::operator=(const ColumnMetaData& other95) { + type = other95.type; + encodings = other95.encodings; + path_in_schema = other95.path_in_schema; + codec = other95.codec; + num_values = other95.num_values; + total_uncompressed_size = other95.total_uncompressed_size; + total_compressed_size = other95.total_compressed_size; + key_value_metadata = other95.key_value_metadata; + data_page_offset = other95.data_page_offset; + index_page_offset = other95.index_page_offset; + dictionary_page_offset = other95.dictionary_page_offset; + statistics = other95.statistics; + encoding_stats = other95.encoding_stats; + __isset = other95.__isset; return *this; } void ColumnMetaData::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ColumnMetaData("; out << "type=" << to_string(type); out << ", " << "encodings=" << to_string(encodings); @@ -5811,18 +4275,13 @@ void ColumnMetaData::printTo(std::ostream& out) const { out << ", " << "dictionary_page_offset="; (__isset.dictionary_page_offset ? (out << to_string(dictionary_page_offset)) : (out << "")); out << ", " << "statistics="; (__isset.statistics ? (out << to_string(statistics)) : (out << "")); out << ", " << "encoding_stats="; (__isset.encoding_stats ? (out << to_string(encoding_stats)) : (out << "")); - out << ", " << "bloom_filter_offset="; (__isset.bloom_filter_offset ? (out << to_string(bloom_filter_offset)) : (out << "")); - out << ", " << "bloom_filter_length="; (__isset.bloom_filter_length ? (out << to_string(bloom_filter_length)) : (out << "")); - out << ", " << "size_statistics="; (__isset.size_statistics ? (out << to_string(size_statistics)) : (out << "")); out << ")"; } -EncryptionWithFooterKey::~EncryptionWithFooterKey() noexcept { +EncryptionWithFooterKey::~EncryptionWithFooterKey() throw() { } -EncryptionWithFooterKey::EncryptionWithFooterKey() noexcept { -} std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj) { obj.printTo(out); @@ -5830,23 +4289,23 @@ std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj) } -uint32_t EncryptionWithFooterKey::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionWithFooterKey::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -5858,9 +4317,9 @@ uint32_t EncryptionWithFooterKey::read(::apache::thrift::protocol::TProtocol* ip return xfer; } -uint32_t EncryptionWithFooterKey::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionWithFooterKey::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionWithFooterKey"); xfer += oprot->writeFieldStop(); @@ -5874,26 +4333,23 @@ void swap(EncryptionWithFooterKey &a, EncryptionWithFooterKey &b) { (void) b; } -EncryptionWithFooterKey::EncryptionWithFooterKey(const EncryptionWithFooterKey& other126) noexcept { - (void) other126; +EncryptionWithFooterKey::EncryptionWithFooterKey(const EncryptionWithFooterKey& other96) { + (void) other96; } -EncryptionWithFooterKey& EncryptionWithFooterKey::operator=(const EncryptionWithFooterKey& other127) noexcept { - (void) other127; +EncryptionWithFooterKey& EncryptionWithFooterKey::operator=(const EncryptionWithFooterKey& other97) { + (void) other97; return *this; } void EncryptionWithFooterKey::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "EncryptionWithFooterKey("; out << ")"; } -EncryptionWithColumnKey::~EncryptionWithColumnKey() noexcept { +EncryptionWithColumnKey::~EncryptionWithColumnKey() throw() { } -EncryptionWithColumnKey::EncryptionWithColumnKey() noexcept - : key_metadata() { -} void EncryptionWithColumnKey::__set_path_in_schema(const duckdb::vector & val) { this->path_in_schema = val; @@ -5910,40 +4366,40 @@ std::ostream& operator<<(std::ostream& out, const EncryptionWithColumnKey& obj) } -uint32_t EncryptionWithColumnKey::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionWithColumnKey::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_path_in_schema = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->path_in_schema.clear(); - uint32_t _size128; - ::apache::thrift::protocol::TType _etype131; - xfer += iprot->readListBegin(_etype131, _size128); - this->path_in_schema.resize(_size128); - uint32_t _i132; - for (_i132 = 0; _i132 < _size128; ++_i132) + uint32_t _size98; + ::duckdb_apache::thrift::protocol::TType _etype101; + xfer += iprot->readListBegin(_etype101, _size98); + this->path_in_schema.resize(_size98); + uint32_t _i102; + for (_i102 = 0; _i102 < _size98; ++_i102) { - xfer += iprot->readString(this->path_in_schema[_i132]); + xfer += iprot->readString(this->path_in_schema[_i102]); } xfer += iprot->readListEnd(); } @@ -5953,7 +4409,7 @@ uint32_t EncryptionWithColumnKey::read(::apache::thrift::protocol::TProtocol* ip } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->key_metadata); this->__isset.key_metadata = true; } else { @@ -5974,25 +4430,25 @@ uint32_t EncryptionWithColumnKey::read(::apache::thrift::protocol::TProtocol* ip return xfer; } -uint32_t EncryptionWithColumnKey::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionWithColumnKey::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionWithColumnKey"); - xfer += oprot->writeFieldBegin("path_in_schema", ::apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("path_in_schema", ::duckdb_apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); - duckdb::vector ::const_iterator _iter133; - for (_iter133 = this->path_in_schema.begin(); _iter133 != this->path_in_schema.end(); ++_iter133) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->path_in_schema.size())); + duckdb::vector ::const_iterator _iter103; + for (_iter103 = this->path_in_schema.begin(); _iter103 != this->path_in_schema.end(); ++_iter103) { - xfer += oprot->writeString((*_iter133)); + xfer += oprot->writeString((*_iter103)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); if (this->__isset.key_metadata) { - xfer += oprot->writeFieldBegin("key_metadata", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->key_metadata); xfer += oprot->writeFieldEnd(); } @@ -6008,19 +4464,19 @@ void swap(EncryptionWithColumnKey &a, EncryptionWithColumnKey &b) { swap(a.__isset, b.__isset); } -EncryptionWithColumnKey::EncryptionWithColumnKey(const EncryptionWithColumnKey& other134) { - path_in_schema = other134.path_in_schema; - key_metadata = other134.key_metadata; - __isset = other134.__isset; +EncryptionWithColumnKey::EncryptionWithColumnKey(const EncryptionWithColumnKey& other104) { + path_in_schema = other104.path_in_schema; + key_metadata = other104.key_metadata; + __isset = other104.__isset; } -EncryptionWithColumnKey& EncryptionWithColumnKey::operator=(const EncryptionWithColumnKey& other135) { - path_in_schema = other135.path_in_schema; - key_metadata = other135.key_metadata; - __isset = other135.__isset; +EncryptionWithColumnKey& EncryptionWithColumnKey::operator=(const EncryptionWithColumnKey& other105) { + path_in_schema = other105.path_in_schema; + key_metadata = other105.key_metadata; + __isset = other105.__isset; return *this; } void EncryptionWithColumnKey::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "EncryptionWithColumnKey("; out << "path_in_schema=" << to_string(path_in_schema); out << ", " << "key_metadata="; (__isset.key_metadata ? (out << to_string(key_metadata)) : (out << "")); @@ -6028,11 +4484,9 @@ void EncryptionWithColumnKey::printTo(std::ostream& out) const { } -ColumnCryptoMetaData::~ColumnCryptoMetaData() noexcept { +ColumnCryptoMetaData::~ColumnCryptoMetaData() throw() { } -ColumnCryptoMetaData::ColumnCryptoMetaData() noexcept { -} void ColumnCryptoMetaData::__set_ENCRYPTION_WITH_FOOTER_KEY(const EncryptionWithFooterKey& val) { this->ENCRYPTION_WITH_FOOTER_KEY = val; @@ -6050,29 +4504,29 @@ std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj) } -uint32_t ColumnCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->ENCRYPTION_WITH_FOOTER_KEY.read(iprot); this->__isset.ENCRYPTION_WITH_FOOTER_KEY = true; } else { @@ -6080,7 +4534,7 @@ uint32_t ColumnCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->ENCRYPTION_WITH_COLUMN_KEY.read(iprot); this->__isset.ENCRYPTION_WITH_COLUMN_KEY = true; } else { @@ -6099,18 +4553,18 @@ uint32_t ColumnCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot return xfer; } -uint32_t ColumnCryptoMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnCryptoMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnCryptoMetaData"); if (this->__isset.ENCRYPTION_WITH_FOOTER_KEY) { - xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_FOOTER_KEY", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_FOOTER_KEY", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->ENCRYPTION_WITH_FOOTER_KEY.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.ENCRYPTION_WITH_COLUMN_KEY) { - xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_COLUMN_KEY", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("ENCRYPTION_WITH_COLUMN_KEY", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->ENCRYPTION_WITH_COLUMN_KEY.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -6126,19 +4580,19 @@ void swap(ColumnCryptoMetaData &a, ColumnCryptoMetaData &b) { swap(a.__isset, b.__isset); } -ColumnCryptoMetaData::ColumnCryptoMetaData(const ColumnCryptoMetaData& other136) { - ENCRYPTION_WITH_FOOTER_KEY = other136.ENCRYPTION_WITH_FOOTER_KEY; - ENCRYPTION_WITH_COLUMN_KEY = other136.ENCRYPTION_WITH_COLUMN_KEY; - __isset = other136.__isset; +ColumnCryptoMetaData::ColumnCryptoMetaData(const ColumnCryptoMetaData& other106) { + ENCRYPTION_WITH_FOOTER_KEY = other106.ENCRYPTION_WITH_FOOTER_KEY; + ENCRYPTION_WITH_COLUMN_KEY = other106.ENCRYPTION_WITH_COLUMN_KEY; + __isset = other106.__isset; } -ColumnCryptoMetaData& ColumnCryptoMetaData::operator=(const ColumnCryptoMetaData& other137) { - ENCRYPTION_WITH_FOOTER_KEY = other137.ENCRYPTION_WITH_FOOTER_KEY; - ENCRYPTION_WITH_COLUMN_KEY = other137.ENCRYPTION_WITH_COLUMN_KEY; - __isset = other137.__isset; +ColumnCryptoMetaData& ColumnCryptoMetaData::operator=(const ColumnCryptoMetaData& other107) { + ENCRYPTION_WITH_FOOTER_KEY = other107.ENCRYPTION_WITH_FOOTER_KEY; + ENCRYPTION_WITH_COLUMN_KEY = other107.ENCRYPTION_WITH_COLUMN_KEY; + __isset = other107.__isset; return *this; } void ColumnCryptoMetaData::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ColumnCryptoMetaData("; out << "ENCRYPTION_WITH_FOOTER_KEY="; (__isset.ENCRYPTION_WITH_FOOTER_KEY ? (out << to_string(ENCRYPTION_WITH_FOOTER_KEY)) : (out << "")); out << ", " << "ENCRYPTION_WITH_COLUMN_KEY="; (__isset.ENCRYPTION_WITH_COLUMN_KEY ? (out << to_string(ENCRYPTION_WITH_COLUMN_KEY)) : (out << "")); @@ -6146,18 +4600,9 @@ void ColumnCryptoMetaData::printTo(std::ostream& out) const { } -ColumnChunk::~ColumnChunk() noexcept { +ColumnChunk::~ColumnChunk() throw() { } -ColumnChunk::ColumnChunk() noexcept - : file_path(), - file_offset(0LL), - offset_index_offset(0), - offset_index_length(0), - column_index_offset(0), - column_index_length(0), - encrypted_column_metadata() { -} void ColumnChunk::__set_file_path(const std::string& val) { this->file_path = val; @@ -6209,30 +4654,30 @@ std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj) } -uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnChunk::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_file_offset = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->file_path); this->__isset.file_path = true; } else { @@ -6240,7 +4685,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->file_offset); isset_file_offset = true; } else { @@ -6248,7 +4693,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->meta_data.read(iprot); this->__isset.meta_data = true; } else { @@ -6256,7 +4701,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->offset_index_offset); this->__isset.offset_index_offset = true; } else { @@ -6264,7 +4709,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->offset_index_length); this->__isset.offset_index_length = true; } else { @@ -6272,7 +4717,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->column_index_offset); this->__isset.column_index_offset = true; } else { @@ -6280,7 +4725,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->column_index_length); this->__isset.column_index_length = true; } else { @@ -6288,7 +4733,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->crypto_metadata.read(iprot); this->__isset.crypto_metadata = true; } else { @@ -6296,7 +4741,7 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 9: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->encrypted_column_metadata); this->__isset.encrypted_column_metadata = true; } else { @@ -6317,52 +4762,52 @@ uint32_t ColumnChunk::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ColumnChunk::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnChunk::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnChunk"); if (this->__isset.file_path) { - xfer += oprot->writeFieldBegin("file_path", ::apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("file_path", ::duckdb_apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeString(this->file_path); xfer += oprot->writeFieldEnd(); } - xfer += oprot->writeFieldBegin("file_offset", ::apache::thrift::protocol::T_I64, 2); + xfer += oprot->writeFieldBegin("file_offset", ::duckdb_apache::thrift::protocol::T_I64, 2); xfer += oprot->writeI64(this->file_offset); xfer += oprot->writeFieldEnd(); if (this->__isset.meta_data) { - xfer += oprot->writeFieldBegin("meta_data", ::apache::thrift::protocol::T_STRUCT, 3); + xfer += oprot->writeFieldBegin("meta_data", ::duckdb_apache::thrift::protocol::T_STRUCT, 3); xfer += this->meta_data.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.offset_index_offset) { - xfer += oprot->writeFieldBegin("offset_index_offset", ::apache::thrift::protocol::T_I64, 4); + xfer += oprot->writeFieldBegin("offset_index_offset", ::duckdb_apache::thrift::protocol::T_I64, 4); xfer += oprot->writeI64(this->offset_index_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.offset_index_length) { - xfer += oprot->writeFieldBegin("offset_index_length", ::apache::thrift::protocol::T_I32, 5); + xfer += oprot->writeFieldBegin("offset_index_length", ::duckdb_apache::thrift::protocol::T_I32, 5); xfer += oprot->writeI32(this->offset_index_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_index_offset) { - xfer += oprot->writeFieldBegin("column_index_offset", ::apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("column_index_offset", ::duckdb_apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->column_index_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_index_length) { - xfer += oprot->writeFieldBegin("column_index_length", ::apache::thrift::protocol::T_I32, 7); + xfer += oprot->writeFieldBegin("column_index_length", ::duckdb_apache::thrift::protocol::T_I32, 7); xfer += oprot->writeI32(this->column_index_length); xfer += oprot->writeFieldEnd(); } if (this->__isset.crypto_metadata) { - xfer += oprot->writeFieldBegin("crypto_metadata", ::apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("crypto_metadata", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); xfer += this->crypto_metadata.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.encrypted_column_metadata) { - xfer += oprot->writeFieldBegin("encrypted_column_metadata", ::apache::thrift::protocol::T_STRING, 9); + xfer += oprot->writeFieldBegin("encrypted_column_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 9); xfer += oprot->writeBinary(this->encrypted_column_metadata); xfer += oprot->writeFieldEnd(); } @@ -6385,33 +4830,33 @@ void swap(ColumnChunk &a, ColumnChunk &b) { swap(a.__isset, b.__isset); } -ColumnChunk::ColumnChunk(const ColumnChunk& other138) { - file_path = other138.file_path; - file_offset = other138.file_offset; - meta_data = other138.meta_data; - offset_index_offset = other138.offset_index_offset; - offset_index_length = other138.offset_index_length; - column_index_offset = other138.column_index_offset; - column_index_length = other138.column_index_length; - crypto_metadata = other138.crypto_metadata; - encrypted_column_metadata = other138.encrypted_column_metadata; - __isset = other138.__isset; -} -ColumnChunk& ColumnChunk::operator=(const ColumnChunk& other139) { - file_path = other139.file_path; - file_offset = other139.file_offset; - meta_data = other139.meta_data; - offset_index_offset = other139.offset_index_offset; - offset_index_length = other139.offset_index_length; - column_index_offset = other139.column_index_offset; - column_index_length = other139.column_index_length; - crypto_metadata = other139.crypto_metadata; - encrypted_column_metadata = other139.encrypted_column_metadata; - __isset = other139.__isset; +ColumnChunk::ColumnChunk(const ColumnChunk& other108) { + file_path = other108.file_path; + file_offset = other108.file_offset; + meta_data = other108.meta_data; + offset_index_offset = other108.offset_index_offset; + offset_index_length = other108.offset_index_length; + column_index_offset = other108.column_index_offset; + column_index_length = other108.column_index_length; + crypto_metadata = other108.crypto_metadata; + encrypted_column_metadata = other108.encrypted_column_metadata; + __isset = other108.__isset; +} +ColumnChunk& ColumnChunk::operator=(const ColumnChunk& other109) { + file_path = other109.file_path; + file_offset = other109.file_offset; + meta_data = other109.meta_data; + offset_index_offset = other109.offset_index_offset; + offset_index_length = other109.offset_index_length; + column_index_offset = other109.column_index_offset; + column_index_length = other109.column_index_length; + crypto_metadata = other109.crypto_metadata; + encrypted_column_metadata = other109.encrypted_column_metadata; + __isset = other109.__isset; return *this; } void ColumnChunk::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ColumnChunk("; out << "file_path="; (__isset.file_path ? (out << to_string(file_path)) : (out << "")); out << ", " << "file_offset=" << to_string(file_offset); @@ -6426,16 +4871,9 @@ void ColumnChunk::printTo(std::ostream& out) const { } -RowGroup::~RowGroup() noexcept { +RowGroup::~RowGroup() throw() { } -RowGroup::RowGroup() noexcept - : total_byte_size(0), - num_rows(0), - file_offset(0), - total_compressed_size(0), - ordinal(0) { -} void RowGroup::__set_columns(const duckdb::vector & val) { this->columns = val; @@ -6475,17 +4913,17 @@ std::ostream& operator<<(std::ostream& out, const RowGroup& obj) } -uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t RowGroup::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_columns = false; bool isset_total_byte_size = false; @@ -6494,23 +4932,23 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->columns.clear(); - uint32_t _size140; - ::apache::thrift::protocol::TType _etype143; - xfer += iprot->readListBegin(_etype143, _size140); - this->columns.resize(_size140); - uint32_t _i144; - for (_i144 = 0; _i144 < _size140; ++_i144) + uint32_t _size110; + ::duckdb_apache::thrift::protocol::TType _etype113; + xfer += iprot->readListBegin(_etype113, _size110); + this->columns.resize(_size110); + uint32_t _i114; + for (_i114 = 0; _i114 < _size110; ++_i114) { - xfer += this->columns[_i144].read(iprot); + xfer += this->columns[_i114].read(iprot); } xfer += iprot->readListEnd(); } @@ -6520,7 +4958,7 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_byte_size); isset_total_byte_size = true; } else { @@ -6528,7 +4966,7 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_rows); isset_num_rows = true; } else { @@ -6536,17 +4974,17 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->sorting_columns.clear(); - uint32_t _size145; - ::apache::thrift::protocol::TType _etype148; - xfer += iprot->readListBegin(_etype148, _size145); - this->sorting_columns.resize(_size145); - uint32_t _i149; - for (_i149 = 0; _i149 < _size145; ++_i149) + uint32_t _size115; + ::duckdb_apache::thrift::protocol::TType _etype118; + xfer += iprot->readListBegin(_etype118, _size115); + this->sorting_columns.resize(_size115); + uint32_t _i119; + for (_i119 = 0; _i119 < _size115; ++_i119) { - xfer += this->sorting_columns[_i149].read(iprot); + xfer += this->sorting_columns[_i119].read(iprot); } xfer += iprot->readListEnd(); } @@ -6556,7 +4994,7 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->file_offset); this->__isset.file_offset = true; } else { @@ -6564,7 +5002,7 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->total_compressed_size); this->__isset.total_compressed_size = true; } else { @@ -6572,7 +5010,7 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_I16) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I16) { xfer += iprot->readI16(this->ordinal); this->__isset.ordinal = true; } else { @@ -6597,56 +5035,56 @@ uint32_t RowGroup::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t RowGroup::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t RowGroup::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("RowGroup"); - xfer += oprot->writeFieldBegin("columns", ::apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("columns", ::duckdb_apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->columns.size())); - duckdb::vector ::const_iterator _iter150; - for (_iter150 = this->columns.begin(); _iter150 != this->columns.end(); ++_iter150) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->columns.size())); + duckdb::vector ::const_iterator _iter120; + for (_iter120 = this->columns.begin(); _iter120 != this->columns.end(); ++_iter120) { - xfer += (*_iter150).write(oprot); + xfer += (*_iter120).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("total_byte_size", ::apache::thrift::protocol::T_I64, 2); + xfer += oprot->writeFieldBegin("total_byte_size", ::duckdb_apache::thrift::protocol::T_I64, 2); xfer += oprot->writeI64(this->total_byte_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->num_rows); xfer += oprot->writeFieldEnd(); if (this->__isset.sorting_columns) { - xfer += oprot->writeFieldBegin("sorting_columns", ::apache::thrift::protocol::T_LIST, 4); + xfer += oprot->writeFieldBegin("sorting_columns", ::duckdb_apache::thrift::protocol::T_LIST, 4); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->sorting_columns.size())); - duckdb::vector ::const_iterator _iter151; - for (_iter151 = this->sorting_columns.begin(); _iter151 != this->sorting_columns.end(); ++_iter151) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->sorting_columns.size())); + duckdb::vector ::const_iterator _iter121; + for (_iter121 = this->sorting_columns.begin(); _iter121 != this->sorting_columns.end(); ++_iter121) { - xfer += (*_iter151).write(oprot); + xfer += (*_iter121).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.file_offset) { - xfer += oprot->writeFieldBegin("file_offset", ::apache::thrift::protocol::T_I64, 5); + xfer += oprot->writeFieldBegin("file_offset", ::duckdb_apache::thrift::protocol::T_I64, 5); xfer += oprot->writeI64(this->file_offset); xfer += oprot->writeFieldEnd(); } if (this->__isset.total_compressed_size) { - xfer += oprot->writeFieldBegin("total_compressed_size", ::apache::thrift::protocol::T_I64, 6); + xfer += oprot->writeFieldBegin("total_compressed_size", ::duckdb_apache::thrift::protocol::T_I64, 6); xfer += oprot->writeI64(this->total_compressed_size); xfer += oprot->writeFieldEnd(); } if (this->__isset.ordinal) { - xfer += oprot->writeFieldBegin("ordinal", ::apache::thrift::protocol::T_I16, 7); + xfer += oprot->writeFieldBegin("ordinal", ::duckdb_apache::thrift::protocol::T_I16, 7); xfer += oprot->writeI16(this->ordinal); xfer += oprot->writeFieldEnd(); } @@ -6667,29 +5105,29 @@ void swap(RowGroup &a, RowGroup &b) { swap(a.__isset, b.__isset); } -RowGroup::RowGroup(const RowGroup& other152) { - columns = other152.columns; - total_byte_size = other152.total_byte_size; - num_rows = other152.num_rows; - sorting_columns = other152.sorting_columns; - file_offset = other152.file_offset; - total_compressed_size = other152.total_compressed_size; - ordinal = other152.ordinal; - __isset = other152.__isset; -} -RowGroup& RowGroup::operator=(const RowGroup& other153) { - columns = other153.columns; - total_byte_size = other153.total_byte_size; - num_rows = other153.num_rows; - sorting_columns = other153.sorting_columns; - file_offset = other153.file_offset; - total_compressed_size = other153.total_compressed_size; - ordinal = other153.ordinal; - __isset = other153.__isset; +RowGroup::RowGroup(const RowGroup& other122) { + columns = other122.columns; + total_byte_size = other122.total_byte_size; + num_rows = other122.num_rows; + sorting_columns = other122.sorting_columns; + file_offset = other122.file_offset; + total_compressed_size = other122.total_compressed_size; + ordinal = other122.ordinal; + __isset = other122.__isset; +} +RowGroup& RowGroup::operator=(const RowGroup& other123) { + columns = other123.columns; + total_byte_size = other123.total_byte_size; + num_rows = other123.num_rows; + sorting_columns = other123.sorting_columns; + file_offset = other123.file_offset; + total_compressed_size = other123.total_compressed_size; + ordinal = other123.ordinal; + __isset = other123.__isset; return *this; } void RowGroup::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "RowGroup("; out << "columns=" << to_string(columns); out << ", " << "total_byte_size=" << to_string(total_byte_size); @@ -6702,11 +5140,9 @@ void RowGroup::printTo(std::ostream& out) const { } -TypeDefinedOrder::~TypeDefinedOrder() noexcept { +TypeDefinedOrder::~TypeDefinedOrder() throw() { } -TypeDefinedOrder::TypeDefinedOrder() noexcept { -} std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj) { obj.printTo(out); @@ -6714,23 +5150,23 @@ std::ostream& operator<<(std::ostream& out, const TypeDefinedOrder& obj) } -uint32_t TypeDefinedOrder::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t TypeDefinedOrder::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } xfer += iprot->skip(ftype); @@ -6742,9 +5178,9 @@ uint32_t TypeDefinedOrder::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t TypeDefinedOrder::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t TypeDefinedOrder::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("TypeDefinedOrder"); xfer += oprot->writeFieldStop(); @@ -6758,25 +5194,23 @@ void swap(TypeDefinedOrder &a, TypeDefinedOrder &b) { (void) b; } -TypeDefinedOrder::TypeDefinedOrder(const TypeDefinedOrder& other154) noexcept { - (void) other154; +TypeDefinedOrder::TypeDefinedOrder(const TypeDefinedOrder& other124) { + (void) other124; } -TypeDefinedOrder& TypeDefinedOrder::operator=(const TypeDefinedOrder& other155) noexcept { - (void) other155; +TypeDefinedOrder& TypeDefinedOrder::operator=(const TypeDefinedOrder& other125) { + (void) other125; return *this; } void TypeDefinedOrder::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "TypeDefinedOrder("; out << ")"; } -ColumnOrder::~ColumnOrder() noexcept { +ColumnOrder::~ColumnOrder() throw() { } -ColumnOrder::ColumnOrder() noexcept { -} void ColumnOrder::__set_TYPE_ORDER(const TypeDefinedOrder& val) { this->TYPE_ORDER = val; @@ -6789,29 +5223,29 @@ std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj) } -uint32_t ColumnOrder::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnOrder::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->TYPE_ORDER.read(iprot); this->__isset.TYPE_ORDER = true; } else { @@ -6830,13 +5264,13 @@ uint32_t ColumnOrder::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ColumnOrder::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnOrder::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnOrder"); if (this->__isset.TYPE_ORDER) { - xfer += oprot->writeFieldBegin("TYPE_ORDER", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("TYPE_ORDER", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->TYPE_ORDER.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -6851,31 +5285,26 @@ void swap(ColumnOrder &a, ColumnOrder &b) { swap(a.__isset, b.__isset); } -ColumnOrder::ColumnOrder(const ColumnOrder& other156) noexcept { - TYPE_ORDER = other156.TYPE_ORDER; - __isset = other156.__isset; +ColumnOrder::ColumnOrder(const ColumnOrder& other126) { + TYPE_ORDER = other126.TYPE_ORDER; + __isset = other126.__isset; } -ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other157) noexcept { - TYPE_ORDER = other157.TYPE_ORDER; - __isset = other157.__isset; +ColumnOrder& ColumnOrder::operator=(const ColumnOrder& other127) { + TYPE_ORDER = other127.TYPE_ORDER; + __isset = other127.__isset; return *this; } void ColumnOrder::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ColumnOrder("; out << "TYPE_ORDER="; (__isset.TYPE_ORDER ? (out << to_string(TYPE_ORDER)) : (out << "")); out << ")"; } -PageLocation::~PageLocation() noexcept { +PageLocation::~PageLocation() throw() { } -PageLocation::PageLocation() noexcept - : offset(0), - compressed_page_size(0), - first_row_index(0) { -} void PageLocation::__set_offset(const int64_t val) { this->offset = val; @@ -6895,17 +5324,17 @@ std::ostream& operator<<(std::ostream& out, const PageLocation& obj) } -uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t PageLocation::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_offset = false; bool isset_compressed_page_size = false; @@ -6914,13 +5343,13 @@ uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->offset); isset_offset = true; } else { @@ -6928,7 +5357,7 @@ uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->compressed_page_size); isset_compressed_page_size = true; } else { @@ -6936,7 +5365,7 @@ uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->first_row_index); isset_first_row_index = true; } else { @@ -6961,20 +5390,20 @@ uint32_t PageLocation::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t PageLocation::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t PageLocation::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("PageLocation"); - xfer += oprot->writeFieldBegin("offset", ::apache::thrift::protocol::T_I64, 1); + xfer += oprot->writeFieldBegin("offset", ::duckdb_apache::thrift::protocol::T_I64, 1); xfer += oprot->writeI64(this->offset); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("compressed_page_size", ::apache::thrift::protocol::T_I32, 2); + xfer += oprot->writeFieldBegin("compressed_page_size", ::duckdb_apache::thrift::protocol::T_I32, 2); xfer += oprot->writeI32(this->compressed_page_size); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("first_row_index", ::apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("first_row_index", ::duckdb_apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->first_row_index); xfer += oprot->writeFieldEnd(); @@ -6990,19 +5419,19 @@ void swap(PageLocation &a, PageLocation &b) { swap(a.first_row_index, b.first_row_index); } -PageLocation::PageLocation(const PageLocation& other158) noexcept { - offset = other158.offset; - compressed_page_size = other158.compressed_page_size; - first_row_index = other158.first_row_index; +PageLocation::PageLocation(const PageLocation& other128) { + offset = other128.offset; + compressed_page_size = other128.compressed_page_size; + first_row_index = other128.first_row_index; } -PageLocation& PageLocation::operator=(const PageLocation& other159) noexcept { - offset = other159.offset; - compressed_page_size = other159.compressed_page_size; - first_row_index = other159.first_row_index; +PageLocation& PageLocation::operator=(const PageLocation& other129) { + offset = other129.offset; + compressed_page_size = other129.compressed_page_size; + first_row_index = other129.first_row_index; return *this; } void PageLocation::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "PageLocation("; out << "offset=" << to_string(offset); out << ", " << "compressed_page_size=" << to_string(compressed_page_size); @@ -7011,20 +5440,13 @@ void PageLocation::printTo(std::ostream& out) const { } -OffsetIndex::~OffsetIndex() noexcept { +OffsetIndex::~OffsetIndex() throw() { } -OffsetIndex::OffsetIndex() noexcept { -} void OffsetIndex::__set_page_locations(const duckdb::vector & val) { this->page_locations = val; } - -void OffsetIndex::__set_unencoded_byte_array_data_bytes(const duckdb::vector & val) { - this->unencoded_byte_array_data_bytes = val; -__isset.unencoded_byte_array_data_bytes = true; -} std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj) { obj.printTo(out); @@ -7032,40 +5454,40 @@ std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj) } -uint32_t OffsetIndex::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t OffsetIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_page_locations = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->page_locations.clear(); - uint32_t _size160; - ::apache::thrift::protocol::TType _etype163; - xfer += iprot->readListBegin(_etype163, _size160); - this->page_locations.resize(_size160); - uint32_t _i164; - for (_i164 = 0; _i164 < _size160; ++_i164) + uint32_t _size130; + ::duckdb_apache::thrift::protocol::TType _etype133; + xfer += iprot->readListBegin(_etype133, _size130); + this->page_locations.resize(_size130); + uint32_t _i134; + for (_i134 = 0; _i134 < _size130; ++_i134) { - xfer += this->page_locations[_i164].read(iprot); + xfer += this->page_locations[_i134].read(iprot); } xfer += iprot->readListEnd(); } @@ -7074,26 +5496,6 @@ uint32_t OffsetIndex::read(::apache::thrift::protocol::TProtocol* iprot) { xfer += iprot->skip(ftype); } break; - case 2: - if (ftype == ::apache::thrift::protocol::T_LIST) { - { - this->unencoded_byte_array_data_bytes.clear(); - uint32_t _size165; - ::apache::thrift::protocol::TType _etype168; - xfer += iprot->readListBegin(_etype168, _size165); - this->unencoded_byte_array_data_bytes.resize(_size165); - uint32_t _i169; - for (_i169 = 0; _i169 < _size165; ++_i169) - { - xfer += iprot->readI64(this->unencoded_byte_array_data_bytes[_i169]); - } - xfer += iprot->readListEnd(); - } - this->__isset.unencoded_byte_array_data_bytes = true; - } else { - xfer += iprot->skip(ftype); - } - break; default: xfer += iprot->skip(ftype); break; @@ -7108,36 +5510,23 @@ uint32_t OffsetIndex::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t OffsetIndex::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t OffsetIndex::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("OffsetIndex"); - xfer += oprot->writeFieldBegin("page_locations", ::apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("page_locations", ::duckdb_apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->page_locations.size())); - duckdb::vector ::const_iterator _iter170; - for (_iter170 = this->page_locations.begin(); _iter170 != this->page_locations.end(); ++_iter170) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->page_locations.size())); + duckdb::vector ::const_iterator _iter135; + for (_iter135 = this->page_locations.begin(); _iter135 != this->page_locations.end(); ++_iter135) { - xfer += (*_iter170).write(oprot); + xfer += (*_iter135).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - if (this->__isset.unencoded_byte_array_data_bytes) { - xfer += oprot->writeFieldBegin("unencoded_byte_array_data_bytes", ::apache::thrift::protocol::T_LIST, 2); - { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->unencoded_byte_array_data_bytes.size())); - duckdb::vector ::const_iterator _iter171; - for (_iter171 = this->unencoded_byte_array_data_bytes.begin(); _iter171 != this->unencoded_byte_array_data_bytes.end(); ++_iter171) - { - xfer += oprot->writeI64((*_iter171)); - } - xfer += oprot->writeListEnd(); - } - xfer += oprot->writeFieldEnd(); - } xfer += oprot->writeFieldStop(); xfer += oprot->writeStructEnd(); return xfer; @@ -7146,36 +5535,26 @@ uint32_t OffsetIndex::write(::apache::thrift::protocol::TProtocol* oprot) const void swap(OffsetIndex &a, OffsetIndex &b) { using ::std::swap; swap(a.page_locations, b.page_locations); - swap(a.unencoded_byte_array_data_bytes, b.unencoded_byte_array_data_bytes); - swap(a.__isset, b.__isset); } -OffsetIndex::OffsetIndex(const OffsetIndex& other172) { - page_locations = other172.page_locations; - unencoded_byte_array_data_bytes = other172.unencoded_byte_array_data_bytes; - __isset = other172.__isset; +OffsetIndex::OffsetIndex(const OffsetIndex& other136) { + page_locations = other136.page_locations; } -OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other173) { - page_locations = other173.page_locations; - unencoded_byte_array_data_bytes = other173.unencoded_byte_array_data_bytes; - __isset = other173.__isset; +OffsetIndex& OffsetIndex::operator=(const OffsetIndex& other137) { + page_locations = other137.page_locations; return *this; } void OffsetIndex::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "OffsetIndex("; out << "page_locations=" << to_string(page_locations); - out << ", " << "unencoded_byte_array_data_bytes="; (__isset.unencoded_byte_array_data_bytes ? (out << to_string(unencoded_byte_array_data_bytes)) : (out << "")); out << ")"; } -ColumnIndex::~ColumnIndex() noexcept { +ColumnIndex::~ColumnIndex() throw() { } -ColumnIndex::ColumnIndex() noexcept - : boundary_order(static_cast(0)) { -} void ColumnIndex::__set_null_pages(const duckdb::vector & val) { this->null_pages = val; @@ -7197,16 +5576,6 @@ void ColumnIndex::__set_null_counts(const duckdb::vector & val) { this->null_counts = val; __isset.null_counts = true; } - -void ColumnIndex::__set_repetition_level_histograms(const duckdb::vector & val) { - this->repetition_level_histograms = val; -__isset.repetition_level_histograms = true; -} - -void ColumnIndex::__set_definition_level_histograms(const duckdb::vector & val) { - this->definition_level_histograms = val; -__isset.definition_level_histograms = true; -} std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj) { obj.printTo(out); @@ -7214,17 +5583,17 @@ std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj) } -uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t ColumnIndex::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_null_pages = false; bool isset_min_values = false; @@ -7234,23 +5603,23 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->null_pages.clear(); - uint32_t _size174; - ::apache::thrift::protocol::TType _etype177; - xfer += iprot->readListBegin(_etype177, _size174); - this->null_pages.resize(_size174); - uint32_t _i178; - for (_i178 = 0; _i178 < _size174; ++_i178) + uint32_t _size138; + ::duckdb_apache::thrift::protocol::TType _etype141; + xfer += iprot->readListBegin(_etype141, _size138); + this->null_pages.resize(_size138); + uint32_t _i142; + for (_i142 = 0; _i142 < _size138; ++_i142) { - xfer += iprot->readBool(this->null_pages[_i178]); + xfer += iprot->readBool(this->null_pages[_i142]); } xfer += iprot->readListEnd(); } @@ -7260,17 +5629,17 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->min_values.clear(); - uint32_t _size179; - ::apache::thrift::protocol::TType _etype182; - xfer += iprot->readListBegin(_etype182, _size179); - this->min_values.resize(_size179); - uint32_t _i183; - for (_i183 = 0; _i183 < _size179; ++_i183) + uint32_t _size143; + ::duckdb_apache::thrift::protocol::TType _etype146; + xfer += iprot->readListBegin(_etype146, _size143); + this->min_values.resize(_size143); + uint32_t _i147; + for (_i147 = 0; _i147 < _size143; ++_i147) { - xfer += iprot->readBinary(this->min_values[_i183]); + xfer += iprot->readBinary(this->min_values[_i147]); } xfer += iprot->readListEnd(); } @@ -7280,17 +5649,17 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->max_values.clear(); - uint32_t _size184; - ::apache::thrift::protocol::TType _etype187; - xfer += iprot->readListBegin(_etype187, _size184); - this->max_values.resize(_size184); - uint32_t _i188; - for (_i188 = 0; _i188 < _size184; ++_i188) + uint32_t _size148; + ::duckdb_apache::thrift::protocol::TType _etype151; + xfer += iprot->readListBegin(_etype151, _size148); + this->max_values.resize(_size148); + uint32_t _i152; + for (_i152 = 0; _i152 < _size148; ++_i152) { - xfer += iprot->readBinary(this->max_values[_i188]); + xfer += iprot->readBinary(this->max_values[_i152]); } xfer += iprot->readListEnd(); } @@ -7300,27 +5669,27 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_I32) { - int32_t ecast189; - xfer += iprot->readI32(ecast189); - this->boundary_order = static_cast(ecast189); + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { + int32_t ecast153; + xfer += iprot->readI32(ecast153); + this->boundary_order = (BoundaryOrder::type)ecast153; isset_boundary_order = true; } else { xfer += iprot->skip(ftype); } break; case 5: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->null_counts.clear(); - uint32_t _size190; - ::apache::thrift::protocol::TType _etype193; - xfer += iprot->readListBegin(_etype193, _size190); - this->null_counts.resize(_size190); - uint32_t _i194; - for (_i194 = 0; _i194 < _size190; ++_i194) + uint32_t _size154; + ::duckdb_apache::thrift::protocol::TType _etype157; + xfer += iprot->readListBegin(_etype157, _size154); + this->null_counts.resize(_size154); + uint32_t _i158; + for (_i158 = 0; _i158 < _size154; ++_i158) { - xfer += iprot->readI64(this->null_counts[_i194]); + xfer += iprot->readI64(this->null_counts[_i158]); } xfer += iprot->readListEnd(); } @@ -7329,46 +5698,6 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { xfer += iprot->skip(ftype); } break; - case 6: - if (ftype == ::apache::thrift::protocol::T_LIST) { - { - this->repetition_level_histograms.clear(); - uint32_t _size195; - ::apache::thrift::protocol::TType _etype198; - xfer += iprot->readListBegin(_etype198, _size195); - this->repetition_level_histograms.resize(_size195); - uint32_t _i199; - for (_i199 = 0; _i199 < _size195; ++_i199) - { - xfer += iprot->readI64(this->repetition_level_histograms[_i199]); - } - xfer += iprot->readListEnd(); - } - this->__isset.repetition_level_histograms = true; - } else { - xfer += iprot->skip(ftype); - } - break; - case 7: - if (ftype == ::apache::thrift::protocol::T_LIST) { - { - this->definition_level_histograms.clear(); - uint32_t _size200; - ::apache::thrift::protocol::TType _etype203; - xfer += iprot->readListBegin(_etype203, _size200); - this->definition_level_histograms.resize(_size200); - uint32_t _i204; - for (_i204 = 0; _i204 < _size200; ++_i204) - { - xfer += iprot->readI64(this->definition_level_histograms[_i204]); - } - xfer += iprot->readListEnd(); - } - this->__isset.definition_level_histograms = true; - } else { - xfer += iprot->skip(ftype); - } - break; default: xfer += iprot->skip(ftype); break; @@ -7389,85 +5718,59 @@ uint32_t ColumnIndex::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t ColumnIndex::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t ColumnIndex::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("ColumnIndex"); - xfer += oprot->writeFieldBegin("null_pages", ::apache::thrift::protocol::T_LIST, 1); + xfer += oprot->writeFieldBegin("null_pages", ::duckdb_apache::thrift::protocol::T_LIST, 1); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_BOOL, static_cast(this->null_pages.size())); - duckdb::vector ::const_iterator _iter205; - for (_iter205 = this->null_pages.begin(); _iter205 != this->null_pages.end(); ++_iter205) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_BOOL, static_cast(this->null_pages.size())); + duckdb::vector ::const_iterator _iter159; + for (_iter159 = this->null_pages.begin(); _iter159 != this->null_pages.end(); ++_iter159) { - xfer += oprot->writeBool((*_iter205)); + xfer += oprot->writeBool((*_iter159)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("min_values", ::apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("min_values", ::duckdb_apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->min_values.size())); - duckdb::vector ::const_iterator _iter206; - for (_iter206 = this->min_values.begin(); _iter206 != this->min_values.end(); ++_iter206) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->min_values.size())); + duckdb::vector ::const_iterator _iter160; + for (_iter160 = this->min_values.begin(); _iter160 != this->min_values.end(); ++_iter160) { - xfer += oprot->writeBinary((*_iter206)); + xfer += oprot->writeBinary((*_iter160)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("max_values", ::apache::thrift::protocol::T_LIST, 3); + xfer += oprot->writeFieldBegin("max_values", ::duckdb_apache::thrift::protocol::T_LIST, 3); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRING, static_cast(this->max_values.size())); - duckdb::vector ::const_iterator _iter207; - for (_iter207 = this->max_values.begin(); _iter207 != this->max_values.end(); ++_iter207) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRING, static_cast(this->max_values.size())); + duckdb::vector ::const_iterator _iter161; + for (_iter161 = this->max_values.begin(); _iter161 != this->max_values.end(); ++_iter161) { - xfer += oprot->writeBinary((*_iter207)); + xfer += oprot->writeBinary((*_iter161)); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("boundary_order", ::apache::thrift::protocol::T_I32, 4); - xfer += oprot->writeI32(static_cast(this->boundary_order)); + xfer += oprot->writeFieldBegin("boundary_order", ::duckdb_apache::thrift::protocol::T_I32, 4); + xfer += oprot->writeI32((int32_t)this->boundary_order); xfer += oprot->writeFieldEnd(); if (this->__isset.null_counts) { - xfer += oprot->writeFieldBegin("null_counts", ::apache::thrift::protocol::T_LIST, 5); - { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->null_counts.size())); - duckdb::vector ::const_iterator _iter208; - for (_iter208 = this->null_counts.begin(); _iter208 != this->null_counts.end(); ++_iter208) - { - xfer += oprot->writeI64((*_iter208)); - } - xfer += oprot->writeListEnd(); - } - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.repetition_level_histograms) { - xfer += oprot->writeFieldBegin("repetition_level_histograms", ::apache::thrift::protocol::T_LIST, 6); - { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->repetition_level_histograms.size())); - duckdb::vector ::const_iterator _iter209; - for (_iter209 = this->repetition_level_histograms.begin(); _iter209 != this->repetition_level_histograms.end(); ++_iter209) - { - xfer += oprot->writeI64((*_iter209)); - } - xfer += oprot->writeListEnd(); - } - xfer += oprot->writeFieldEnd(); - } - if (this->__isset.definition_level_histograms) { - xfer += oprot->writeFieldBegin("definition_level_histograms", ::apache::thrift::protocol::T_LIST, 7); + xfer += oprot->writeFieldBegin("null_counts", ::duckdb_apache::thrift::protocol::T_LIST, 5); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_I64, static_cast(this->definition_level_histograms.size())); - duckdb::vector ::const_iterator _iter210; - for (_iter210 = this->definition_level_histograms.begin(); _iter210 != this->definition_level_histograms.end(); ++_iter210) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_I64, static_cast(this->null_counts.size())); + duckdb::vector ::const_iterator _iter162; + for (_iter162 = this->null_counts.begin(); _iter162 != this->null_counts.end(); ++_iter162) { - xfer += oprot->writeI64((*_iter210)); + xfer += oprot->writeI64((*_iter162)); } xfer += oprot->writeListEnd(); } @@ -7485,54 +5788,41 @@ void swap(ColumnIndex &a, ColumnIndex &b) { swap(a.max_values, b.max_values); swap(a.boundary_order, b.boundary_order); swap(a.null_counts, b.null_counts); - swap(a.repetition_level_histograms, b.repetition_level_histograms); - swap(a.definition_level_histograms, b.definition_level_histograms); swap(a.__isset, b.__isset); } -ColumnIndex::ColumnIndex(const ColumnIndex& other211) { - null_pages = other211.null_pages; - min_values = other211.min_values; - max_values = other211.max_values; - boundary_order = other211.boundary_order; - null_counts = other211.null_counts; - repetition_level_histograms = other211.repetition_level_histograms; - definition_level_histograms = other211.definition_level_histograms; - __isset = other211.__isset; -} -ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other212) { - null_pages = other212.null_pages; - min_values = other212.min_values; - max_values = other212.max_values; - boundary_order = other212.boundary_order; - null_counts = other212.null_counts; - repetition_level_histograms = other212.repetition_level_histograms; - definition_level_histograms = other212.definition_level_histograms; - __isset = other212.__isset; +ColumnIndex::ColumnIndex(const ColumnIndex& other163) { + null_pages = other163.null_pages; + min_values = other163.min_values; + max_values = other163.max_values; + boundary_order = other163.boundary_order; + null_counts = other163.null_counts; + __isset = other163.__isset; +} +ColumnIndex& ColumnIndex::operator=(const ColumnIndex& other164) { + null_pages = other164.null_pages; + min_values = other164.min_values; + max_values = other164.max_values; + boundary_order = other164.boundary_order; + null_counts = other164.null_counts; + __isset = other164.__isset; return *this; } void ColumnIndex::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "ColumnIndex("; out << "null_pages=" << to_string(null_pages); out << ", " << "min_values=" << to_string(min_values); out << ", " << "max_values=" << to_string(max_values); out << ", " << "boundary_order=" << to_string(boundary_order); out << ", " << "null_counts="; (__isset.null_counts ? (out << to_string(null_counts)) : (out << "")); - out << ", " << "repetition_level_histograms="; (__isset.repetition_level_histograms ? (out << to_string(repetition_level_histograms)) : (out << "")); - out << ", " << "definition_level_histograms="; (__isset.definition_level_histograms ? (out << to_string(definition_level_histograms)) : (out << "")); out << ")"; } -AesGcmV1::~AesGcmV1() noexcept { +AesGcmV1::~AesGcmV1() throw() { } -AesGcmV1::AesGcmV1() noexcept - : aad_prefix(), - aad_file_unique(), - supply_aad_prefix(0) { -} void AesGcmV1::__set_aad_prefix(const std::string& val) { this->aad_prefix = val; @@ -7555,29 +5845,29 @@ std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj) } -uint32_t AesGcmV1::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t AesGcmV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_prefix); this->__isset.aad_prefix = true; } else { @@ -7585,7 +5875,7 @@ uint32_t AesGcmV1::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_file_unique); this->__isset.aad_file_unique = true; } else { @@ -7593,7 +5883,7 @@ uint32_t AesGcmV1::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->supply_aad_prefix); this->__isset.supply_aad_prefix = true; } else { @@ -7612,23 +5902,23 @@ uint32_t AesGcmV1::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t AesGcmV1::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t AesGcmV1::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("AesGcmV1"); if (this->__isset.aad_prefix) { - xfer += oprot->writeFieldBegin("aad_prefix", ::apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("aad_prefix", ::duckdb_apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->aad_prefix); xfer += oprot->writeFieldEnd(); } if (this->__isset.aad_file_unique) { - xfer += oprot->writeFieldBegin("aad_file_unique", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("aad_file_unique", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->aad_file_unique); xfer += oprot->writeFieldEnd(); } if (this->__isset.supply_aad_prefix) { - xfer += oprot->writeFieldBegin("supply_aad_prefix", ::apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("supply_aad_prefix", ::duckdb_apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->supply_aad_prefix); xfer += oprot->writeFieldEnd(); } @@ -7645,21 +5935,21 @@ void swap(AesGcmV1 &a, AesGcmV1 &b) { swap(a.__isset, b.__isset); } -AesGcmV1::AesGcmV1(const AesGcmV1& other213) { - aad_prefix = other213.aad_prefix; - aad_file_unique = other213.aad_file_unique; - supply_aad_prefix = other213.supply_aad_prefix; - __isset = other213.__isset; +AesGcmV1::AesGcmV1(const AesGcmV1& other165) { + aad_prefix = other165.aad_prefix; + aad_file_unique = other165.aad_file_unique; + supply_aad_prefix = other165.supply_aad_prefix; + __isset = other165.__isset; } -AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other214) { - aad_prefix = other214.aad_prefix; - aad_file_unique = other214.aad_file_unique; - supply_aad_prefix = other214.supply_aad_prefix; - __isset = other214.__isset; +AesGcmV1& AesGcmV1::operator=(const AesGcmV1& other166) { + aad_prefix = other166.aad_prefix; + aad_file_unique = other166.aad_file_unique; + supply_aad_prefix = other166.supply_aad_prefix; + __isset = other166.__isset; return *this; } void AesGcmV1::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "AesGcmV1("; out << "aad_prefix="; (__isset.aad_prefix ? (out << to_string(aad_prefix)) : (out << "")); out << ", " << "aad_file_unique="; (__isset.aad_file_unique ? (out << to_string(aad_file_unique)) : (out << "")); @@ -7668,14 +5958,9 @@ void AesGcmV1::printTo(std::ostream& out) const { } -AesGcmCtrV1::~AesGcmCtrV1() noexcept { +AesGcmCtrV1::~AesGcmCtrV1() throw() { } -AesGcmCtrV1::AesGcmCtrV1() noexcept - : aad_prefix(), - aad_file_unique(), - supply_aad_prefix(0) { -} void AesGcmCtrV1::__set_aad_prefix(const std::string& val) { this->aad_prefix = val; @@ -7698,29 +5983,29 @@ std::ostream& operator<<(std::ostream& out, const AesGcmCtrV1& obj) } -uint32_t AesGcmCtrV1::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t AesGcmCtrV1::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_prefix); this->__isset.aad_prefix = true; } else { @@ -7728,7 +6013,7 @@ uint32_t AesGcmCtrV1::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->aad_file_unique); this->__isset.aad_file_unique = true; } else { @@ -7736,7 +6021,7 @@ uint32_t AesGcmCtrV1::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_BOOL) { + if (ftype == ::duckdb_apache::thrift::protocol::T_BOOL) { xfer += iprot->readBool(this->supply_aad_prefix); this->__isset.supply_aad_prefix = true; } else { @@ -7755,23 +6040,23 @@ uint32_t AesGcmCtrV1::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t AesGcmCtrV1::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t AesGcmCtrV1::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("AesGcmCtrV1"); if (this->__isset.aad_prefix) { - xfer += oprot->writeFieldBegin("aad_prefix", ::apache::thrift::protocol::T_STRING, 1); + xfer += oprot->writeFieldBegin("aad_prefix", ::duckdb_apache::thrift::protocol::T_STRING, 1); xfer += oprot->writeBinary(this->aad_prefix); xfer += oprot->writeFieldEnd(); } if (this->__isset.aad_file_unique) { - xfer += oprot->writeFieldBegin("aad_file_unique", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("aad_file_unique", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->aad_file_unique); xfer += oprot->writeFieldEnd(); } if (this->__isset.supply_aad_prefix) { - xfer += oprot->writeFieldBegin("supply_aad_prefix", ::apache::thrift::protocol::T_BOOL, 3); + xfer += oprot->writeFieldBegin("supply_aad_prefix", ::duckdb_apache::thrift::protocol::T_BOOL, 3); xfer += oprot->writeBool(this->supply_aad_prefix); xfer += oprot->writeFieldEnd(); } @@ -7788,21 +6073,21 @@ void swap(AesGcmCtrV1 &a, AesGcmCtrV1 &b) { swap(a.__isset, b.__isset); } -AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other215) { - aad_prefix = other215.aad_prefix; - aad_file_unique = other215.aad_file_unique; - supply_aad_prefix = other215.supply_aad_prefix; - __isset = other215.__isset; +AesGcmCtrV1::AesGcmCtrV1(const AesGcmCtrV1& other167) { + aad_prefix = other167.aad_prefix; + aad_file_unique = other167.aad_file_unique; + supply_aad_prefix = other167.supply_aad_prefix; + __isset = other167.__isset; } -AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other216) { - aad_prefix = other216.aad_prefix; - aad_file_unique = other216.aad_file_unique; - supply_aad_prefix = other216.supply_aad_prefix; - __isset = other216.__isset; +AesGcmCtrV1& AesGcmCtrV1::operator=(const AesGcmCtrV1& other168) { + aad_prefix = other168.aad_prefix; + aad_file_unique = other168.aad_file_unique; + supply_aad_prefix = other168.supply_aad_prefix; + __isset = other168.__isset; return *this; } void AesGcmCtrV1::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "AesGcmCtrV1("; out << "aad_prefix="; (__isset.aad_prefix ? (out << to_string(aad_prefix)) : (out << "")); out << ", " << "aad_file_unique="; (__isset.aad_file_unique ? (out << to_string(aad_file_unique)) : (out << "")); @@ -7811,11 +6096,9 @@ void AesGcmCtrV1::printTo(std::ostream& out) const { } -EncryptionAlgorithm::~EncryptionAlgorithm() noexcept { +EncryptionAlgorithm::~EncryptionAlgorithm() throw() { } -EncryptionAlgorithm::EncryptionAlgorithm() noexcept { -} void EncryptionAlgorithm::__set_AES_GCM_V1(const AesGcmV1& val) { this->AES_GCM_V1 = val; @@ -7833,29 +6116,29 @@ std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj) } -uint32_t EncryptionAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t EncryptionAlgorithm::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->AES_GCM_V1.read(iprot); this->__isset.AES_GCM_V1 = true; } else { @@ -7863,7 +6146,7 @@ uint32_t EncryptionAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->AES_GCM_CTR_V1.read(iprot); this->__isset.AES_GCM_CTR_V1 = true; } else { @@ -7882,18 +6165,18 @@ uint32_t EncryptionAlgorithm::read(::apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t EncryptionAlgorithm::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t EncryptionAlgorithm::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("EncryptionAlgorithm"); if (this->__isset.AES_GCM_V1) { - xfer += oprot->writeFieldBegin("AES_GCM_V1", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("AES_GCM_V1", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->AES_GCM_V1.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.AES_GCM_CTR_V1) { - xfer += oprot->writeFieldBegin("AES_GCM_CTR_V1", ::apache::thrift::protocol::T_STRUCT, 2); + xfer += oprot->writeFieldBegin("AES_GCM_CTR_V1", ::duckdb_apache::thrift::protocol::T_STRUCT, 2); xfer += this->AES_GCM_CTR_V1.write(oprot); xfer += oprot->writeFieldEnd(); } @@ -7909,19 +6192,19 @@ void swap(EncryptionAlgorithm &a, EncryptionAlgorithm &b) { swap(a.__isset, b.__isset); } -EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other217) { - AES_GCM_V1 = other217.AES_GCM_V1; - AES_GCM_CTR_V1 = other217.AES_GCM_CTR_V1; - __isset = other217.__isset; +EncryptionAlgorithm::EncryptionAlgorithm(const EncryptionAlgorithm& other169) { + AES_GCM_V1 = other169.AES_GCM_V1; + AES_GCM_CTR_V1 = other169.AES_GCM_CTR_V1; + __isset = other169.__isset; } -EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm& other218) { - AES_GCM_V1 = other218.AES_GCM_V1; - AES_GCM_CTR_V1 = other218.AES_GCM_CTR_V1; - __isset = other218.__isset; +EncryptionAlgorithm& EncryptionAlgorithm::operator=(const EncryptionAlgorithm& other170) { + AES_GCM_V1 = other170.AES_GCM_V1; + AES_GCM_CTR_V1 = other170.AES_GCM_CTR_V1; + __isset = other170.__isset; return *this; } void EncryptionAlgorithm::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "EncryptionAlgorithm("; out << "AES_GCM_V1="; (__isset.AES_GCM_V1 ? (out << to_string(AES_GCM_V1)) : (out << "")); out << ", " << "AES_GCM_CTR_V1="; (__isset.AES_GCM_CTR_V1 ? (out << to_string(AES_GCM_CTR_V1)) : (out << "")); @@ -7929,15 +6212,9 @@ void EncryptionAlgorithm::printTo(std::ostream& out) const { } -FileMetaData::~FileMetaData() noexcept { +FileMetaData::~FileMetaData() throw() { } -FileMetaData::FileMetaData() noexcept - : version(0), - num_rows(0), - created_by(), - footer_signing_key_metadata() { -} void FileMetaData::__set_version(const int32_t val) { this->version = val; @@ -7986,17 +6263,17 @@ std::ostream& operator<<(std::ostream& out, const FileMetaData& obj) } -uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t FileMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_version = false; bool isset_schema = false; @@ -8006,13 +6283,13 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_I32) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I32) { xfer += iprot->readI32(this->version); isset_version = true; } else { @@ -8020,17 +6297,17 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 2: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->schema.clear(); - uint32_t _size219; - ::apache::thrift::protocol::TType _etype222; - xfer += iprot->readListBegin(_etype222, _size219); - this->schema.resize(_size219); - uint32_t _i223; - for (_i223 = 0; _i223 < _size219; ++_i223) + uint32_t _size171; + ::duckdb_apache::thrift::protocol::TType _etype174; + xfer += iprot->readListBegin(_etype174, _size171); + this->schema.resize(_size171); + uint32_t _i175; + for (_i175 = 0; _i175 < _size171; ++_i175) { - xfer += this->schema[_i223].read(iprot); + xfer += this->schema[_i175].read(iprot); } xfer += iprot->readListEnd(); } @@ -8040,7 +6317,7 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 3: - if (ftype == ::apache::thrift::protocol::T_I64) { + if (ftype == ::duckdb_apache::thrift::protocol::T_I64) { xfer += iprot->readI64(this->num_rows); isset_num_rows = true; } else { @@ -8048,17 +6325,17 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 4: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->row_groups.clear(); - uint32_t _size224; - ::apache::thrift::protocol::TType _etype227; - xfer += iprot->readListBegin(_etype227, _size224); - this->row_groups.resize(_size224); - uint32_t _i228; - for (_i228 = 0; _i228 < _size224; ++_i228) + uint32_t _size176; + ::duckdb_apache::thrift::protocol::TType _etype179; + xfer += iprot->readListBegin(_etype179, _size176); + this->row_groups.resize(_size176); + uint32_t _i180; + for (_i180 = 0; _i180 < _size176; ++_i180) { - xfer += this->row_groups[_i228].read(iprot); + xfer += this->row_groups[_i180].read(iprot); } xfer += iprot->readListEnd(); } @@ -8068,17 +6345,17 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 5: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->key_value_metadata.clear(); - uint32_t _size229; - ::apache::thrift::protocol::TType _etype232; - xfer += iprot->readListBegin(_etype232, _size229); - this->key_value_metadata.resize(_size229); - uint32_t _i233; - for (_i233 = 0; _i233 < _size229; ++_i233) + uint32_t _size181; + ::duckdb_apache::thrift::protocol::TType _etype184; + xfer += iprot->readListBegin(_etype184, _size181); + this->key_value_metadata.resize(_size181); + uint32_t _i185; + for (_i185 = 0; _i185 < _size181; ++_i185) { - xfer += this->key_value_metadata[_i233].read(iprot); + xfer += this->key_value_metadata[_i185].read(iprot); } xfer += iprot->readListEnd(); } @@ -8088,7 +6365,7 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 6: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readString(this->created_by); this->__isset.created_by = true; } else { @@ -8096,17 +6373,17 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 7: - if (ftype == ::apache::thrift::protocol::T_LIST) { + if (ftype == ::duckdb_apache::thrift::protocol::T_LIST) { { this->column_orders.clear(); - uint32_t _size234; - ::apache::thrift::protocol::TType _etype237; - xfer += iprot->readListBegin(_etype237, _size234); - this->column_orders.resize(_size234); - uint32_t _i238; - for (_i238 = 0; _i238 < _size234; ++_i238) + uint32_t _size186; + ::duckdb_apache::thrift::protocol::TType _etype189; + xfer += iprot->readListBegin(_etype189, _size186); + this->column_orders.resize(_size186); + uint32_t _i190; + for (_i190 = 0; _i190 < _size186; ++_i190) { - xfer += this->column_orders[_i238].read(iprot); + xfer += this->column_orders[_i190].read(iprot); } xfer += iprot->readListEnd(); } @@ -8116,7 +6393,7 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 8: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->encryption_algorithm.read(iprot); this->__isset.encryption_algorithm = true; } else { @@ -8124,7 +6401,7 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { } break; case 9: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->footer_signing_key_metadata); this->__isset.footer_signing_key_metadata = true; } else { @@ -8151,81 +6428,81 @@ uint32_t FileMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { return xfer; } -uint32_t FileMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t FileMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("FileMetaData"); - xfer += oprot->writeFieldBegin("version", ::apache::thrift::protocol::T_I32, 1); + xfer += oprot->writeFieldBegin("version", ::duckdb_apache::thrift::protocol::T_I32, 1); xfer += oprot->writeI32(this->version); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("schema", ::apache::thrift::protocol::T_LIST, 2); + xfer += oprot->writeFieldBegin("schema", ::duckdb_apache::thrift::protocol::T_LIST, 2); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->schema.size())); - duckdb::vector ::const_iterator _iter239; - for (_iter239 = this->schema.begin(); _iter239 != this->schema.end(); ++_iter239) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->schema.size())); + duckdb::vector ::const_iterator _iter191; + for (_iter191 = this->schema.begin(); _iter191 != this->schema.end(); ++_iter191) { - xfer += (*_iter239).write(oprot); + xfer += (*_iter191).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("num_rows", ::apache::thrift::protocol::T_I64, 3); + xfer += oprot->writeFieldBegin("num_rows", ::duckdb_apache::thrift::protocol::T_I64, 3); xfer += oprot->writeI64(this->num_rows); xfer += oprot->writeFieldEnd(); - xfer += oprot->writeFieldBegin("row_groups", ::apache::thrift::protocol::T_LIST, 4); + xfer += oprot->writeFieldBegin("row_groups", ::duckdb_apache::thrift::protocol::T_LIST, 4); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->row_groups.size())); - duckdb::vector ::const_iterator _iter240; - for (_iter240 = this->row_groups.begin(); _iter240 != this->row_groups.end(); ++_iter240) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->row_groups.size())); + duckdb::vector ::const_iterator _iter192; + for (_iter192 = this->row_groups.begin(); _iter192 != this->row_groups.end(); ++_iter192) { - xfer += (*_iter240).write(oprot); + xfer += (*_iter192).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); if (this->__isset.key_value_metadata) { - xfer += oprot->writeFieldBegin("key_value_metadata", ::apache::thrift::protocol::T_LIST, 5); + xfer += oprot->writeFieldBegin("key_value_metadata", ::duckdb_apache::thrift::protocol::T_LIST, 5); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); - duckdb::vector ::const_iterator _iter241; - for (_iter241 = this->key_value_metadata.begin(); _iter241 != this->key_value_metadata.end(); ++_iter241) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->key_value_metadata.size())); + duckdb::vector ::const_iterator _iter193; + for (_iter193 = this->key_value_metadata.begin(); _iter193 != this->key_value_metadata.end(); ++_iter193) { - xfer += (*_iter241).write(oprot); + xfer += (*_iter193).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.created_by) { - xfer += oprot->writeFieldBegin("created_by", ::apache::thrift::protocol::T_STRING, 6); + xfer += oprot->writeFieldBegin("created_by", ::duckdb_apache::thrift::protocol::T_STRING, 6); xfer += oprot->writeString(this->created_by); xfer += oprot->writeFieldEnd(); } if (this->__isset.column_orders) { - xfer += oprot->writeFieldBegin("column_orders", ::apache::thrift::protocol::T_LIST, 7); + xfer += oprot->writeFieldBegin("column_orders", ::duckdb_apache::thrift::protocol::T_LIST, 7); { - xfer += oprot->writeListBegin(::apache::thrift::protocol::T_STRUCT, static_cast(this->column_orders.size())); - duckdb::vector ::const_iterator _iter242; - for (_iter242 = this->column_orders.begin(); _iter242 != this->column_orders.end(); ++_iter242) + xfer += oprot->writeListBegin(::duckdb_apache::thrift::protocol::T_STRUCT, static_cast(this->column_orders.size())); + duckdb::vector ::const_iterator _iter194; + for (_iter194 = this->column_orders.begin(); _iter194 != this->column_orders.end(); ++_iter194) { - xfer += (*_iter242).write(oprot); + xfer += (*_iter194).write(oprot); } xfer += oprot->writeListEnd(); } xfer += oprot->writeFieldEnd(); } if (this->__isset.encryption_algorithm) { - xfer += oprot->writeFieldBegin("encryption_algorithm", ::apache::thrift::protocol::T_STRUCT, 8); + xfer += oprot->writeFieldBegin("encryption_algorithm", ::duckdb_apache::thrift::protocol::T_STRUCT, 8); xfer += this->encryption_algorithm.write(oprot); xfer += oprot->writeFieldEnd(); } if (this->__isset.footer_signing_key_metadata) { - xfer += oprot->writeFieldBegin("footer_signing_key_metadata", ::apache::thrift::protocol::T_STRING, 9); + xfer += oprot->writeFieldBegin("footer_signing_key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 9); xfer += oprot->writeBinary(this->footer_signing_key_metadata); xfer += oprot->writeFieldEnd(); } @@ -8248,33 +6525,34 @@ void swap(FileMetaData &a, FileMetaData &b) { swap(a.__isset, b.__isset); } -FileMetaData::FileMetaData(const FileMetaData& other243) { - version = other243.version; - schema = other243.schema; - num_rows = other243.num_rows; - row_groups = other243.row_groups; - key_value_metadata = other243.key_value_metadata; - created_by = other243.created_by; - column_orders = other243.column_orders; - encryption_algorithm = other243.encryption_algorithm; - footer_signing_key_metadata = other243.footer_signing_key_metadata; - __isset = other243.__isset; -} -FileMetaData& FileMetaData::operator=(const FileMetaData& other244) { - version = other244.version; - schema = other244.schema; - num_rows = other244.num_rows; - row_groups = other244.row_groups; - key_value_metadata = other244.key_value_metadata; - created_by = other244.created_by; - column_orders = other244.column_orders; - encryption_algorithm = other244.encryption_algorithm; - footer_signing_key_metadata = other244.footer_signing_key_metadata; - __isset = other244.__isset; +FileMetaData::FileMetaData(const FileMetaData& other195) { + version = other195.version; + schema = other195.schema; + num_rows = other195.num_rows; + row_groups = other195.row_groups; + key_value_metadata = other195.key_value_metadata; + created_by = other195.created_by; + column_orders = other195.column_orders; + encryption_algorithm = other195.encryption_algorithm; + footer_signing_key_metadata = other195.footer_signing_key_metadata; + __isset = other195.__isset; +} +FileMetaData& FileMetaData::operator=(const FileMetaData& other196) { + version = other196.version; + schema = other196.schema; + num_rows = other196.num_rows; + row_groups = other196.row_groups; + key_value_metadata = other196.key_value_metadata; + created_by = other196.created_by; + column_orders = other196.column_orders; + encryption_algorithm = other196.encryption_algorithm; + footer_signing_key_metadata = other196.footer_signing_key_metadata; + __isset = other196.__isset; return *this; } + void FileMetaData::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "FileMetaData("; out << "version=" << to_string(version); out << ", " << "schema=" << to_string(schema); @@ -8289,12 +6567,9 @@ void FileMetaData::printTo(std::ostream& out) const { } -FileCryptoMetaData::~FileCryptoMetaData() noexcept { +FileCryptoMetaData::~FileCryptoMetaData() throw() { } -FileCryptoMetaData::FileCryptoMetaData() noexcept - : key_metadata() { -} void FileCryptoMetaData::__set_encryption_algorithm(const EncryptionAlgorithm& val) { this->encryption_algorithm = val; @@ -8311,30 +6586,30 @@ std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj) } -uint32_t FileCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) { +uint32_t FileCryptoMetaData::read(::duckdb_apache::thrift::protocol::TProtocol* iprot) { - ::apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); + ::duckdb_apache::thrift::protocol::TInputRecursionTracker tracker(*iprot); uint32_t xfer = 0; std::string fname; - ::apache::thrift::protocol::TType ftype; + ::duckdb_apache::thrift::protocol::TType ftype; int16_t fid; xfer += iprot->readStructBegin(fname); - using ::apache::thrift::protocol::TProtocolException; + using ::duckdb_apache::thrift::protocol::TProtocolException; bool isset_encryption_algorithm = false; while (true) { xfer += iprot->readFieldBegin(fname, ftype, fid); - if (ftype == ::apache::thrift::protocol::T_STOP) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STOP) { break; } switch (fid) { case 1: - if (ftype == ::apache::thrift::protocol::T_STRUCT) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRUCT) { xfer += this->encryption_algorithm.read(iprot); isset_encryption_algorithm = true; } else { @@ -8342,7 +6617,7 @@ uint32_t FileCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) } break; case 2: - if (ftype == ::apache::thrift::protocol::T_STRING) { + if (ftype == ::duckdb_apache::thrift::protocol::T_STRING) { xfer += iprot->readBinary(this->key_metadata); this->__isset.key_metadata = true; } else { @@ -8363,17 +6638,17 @@ uint32_t FileCryptoMetaData::read(::apache::thrift::protocol::TProtocol* iprot) return xfer; } -uint32_t FileCryptoMetaData::write(::apache::thrift::protocol::TProtocol* oprot) const { +uint32_t FileCryptoMetaData::write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const { uint32_t xfer = 0; - ::apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); + ::duckdb_apache::thrift::protocol::TOutputRecursionTracker tracker(*oprot); xfer += oprot->writeStructBegin("FileCryptoMetaData"); - xfer += oprot->writeFieldBegin("encryption_algorithm", ::apache::thrift::protocol::T_STRUCT, 1); + xfer += oprot->writeFieldBegin("encryption_algorithm", ::duckdb_apache::thrift::protocol::T_STRUCT, 1); xfer += this->encryption_algorithm.write(oprot); xfer += oprot->writeFieldEnd(); if (this->__isset.key_metadata) { - xfer += oprot->writeFieldBegin("key_metadata", ::apache::thrift::protocol::T_STRING, 2); + xfer += oprot->writeFieldBegin("key_metadata", ::duckdb_apache::thrift::protocol::T_STRING, 2); xfer += oprot->writeBinary(this->key_metadata); xfer += oprot->writeFieldEnd(); } @@ -8389,23 +6664,24 @@ void swap(FileCryptoMetaData &a, FileCryptoMetaData &b) { swap(a.__isset, b.__isset); } -FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other245) { - encryption_algorithm = other245.encryption_algorithm; - key_metadata = other245.key_metadata; - __isset = other245.__isset; +FileCryptoMetaData::FileCryptoMetaData(const FileCryptoMetaData& other197) { + encryption_algorithm = other197.encryption_algorithm; + key_metadata = other197.key_metadata; + __isset = other197.__isset; } -FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData& other246) { - encryption_algorithm = other246.encryption_algorithm; - key_metadata = other246.key_metadata; - __isset = other246.__isset; +FileCryptoMetaData& FileCryptoMetaData::operator=(const FileCryptoMetaData& other198) { + encryption_algorithm = other198.encryption_algorithm; + key_metadata = other198.key_metadata; + __isset = other198.__isset; return *this; } void FileCryptoMetaData::printTo(std::ostream& out) const { - using ::apache::thrift::to_string; + using ::duckdb_apache::thrift::to_string; out << "FileCryptoMetaData("; out << "encryption_algorithm=" << to_string(encryption_algorithm); out << ", " << "key_metadata="; (__isset.key_metadata ? (out << to_string(key_metadata)) : (out << "")); out << ")"; } -} // namespace + +}} // namespace diff --git a/src/duckdb/third_party/parquet/parquet_types.h b/src/duckdb/third_party/parquet/parquet_types.h index df8cf5f17..af109ee97 100644 --- a/src/duckdb/third_party/parquet/parquet_types.h +++ b/src/duckdb/third_party/parquet/parquet_types.h @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.21.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -9,27 +9,20 @@ #include -#include -#include -#include -#include -#include +#include "duckdb/common/vector.hpp" -#include -#include +#include "thrift/Thrift.h" +#include "thrift/TApplicationException.h" +#include "thrift/TBase.h" +#include "thrift/protocol/TProtocol.h" +#include "thrift/transport/TTransport.h" +#include "thrift/stdcxx.h" #include "windows_compatibility.h" -namespace apache = duckdb_apache; -namespace duckdb_parquet { +namespace duckdb_parquet { namespace format { -/** - * Types supported by Parquet. These types are intended to be used in combination - * with the encodings to control the on disk storage format. - * For example INT16 is not included as a type since a good encoding of INT32 - * would handle this. - */ struct Type { enum type { BOOLEAN = 0, @@ -43,263 +36,66 @@ struct Type { }; }; -extern const std::map _Type_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const Type::type& val); -std::string to_string(const Type::type& val); - -/** - * DEPRECATED: Common types used by frameworks(e.g. hive, pig) using parquet. - * ConvertedType is superseded by LogicalType. This enum should not be extended. - * - * See LogicalTypes.md for conversion between ConvertedType and LogicalType. - */ struct ConvertedType { enum type { - /** - * a BYTE_ARRAY actually contains UTF8 encoded chars - */ UTF8 = 0, - /** - * a map is converted as an optional field containing a repeated key/value pair - */ MAP = 1, - /** - * a key/value pair is converted into a group of two fields - */ MAP_KEY_VALUE = 2, - /** - * a list is converted into an optional field containing a repeated field for its - * values - */ LIST = 3, - /** - * an enum is converted into a BYTE_ARRAY field - */ ENUM = 4, - /** - * A decimal value. - * - * This may be used to annotate BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY primitive - * types. The underlying byte array stores the unscaled value encoded as two's - * complement using big-endian byte order (the most significant byte is the - * zeroth element). The value of the decimal is the value * 10^{-scale}. - * - * This must be accompanied by a (maximum) precision and a scale in the - * SchemaElement. The precision specifies the number of digits in the decimal - * and the scale stores the location of the decimal point. For example 1.23 - * would have precision 3 (3 total digits) and scale 2 (the decimal point is - * 2 digits over). - */ DECIMAL = 5, - /** - * A Date - * - * Stored as days since Unix epoch, encoded as the INT32 physical type. - * - */ DATE = 6, - /** - * A time - * - * The total number of milliseconds since midnight. The value is stored - * as an INT32 physical type. - */ TIME_MILLIS = 7, - /** - * A time. - * - * The total number of microseconds since midnight. The value is stored as - * an INT64 physical type. - */ TIME_MICROS = 8, - /** - * A date/time combination - * - * Date and time recorded as milliseconds since the Unix epoch. Recorded as - * a physical type of INT64. - */ TIMESTAMP_MILLIS = 9, - /** - * A date/time combination - * - * Date and time recorded as microseconds since the Unix epoch. The value is - * stored as an INT64 physical type. - */ TIMESTAMP_MICROS = 10, - /** - * An unsigned integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ UINT_8 = 11, UINT_16 = 12, UINT_32 = 13, UINT_64 = 14, - /** - * A signed integer value. - * - * The number describes the maximum number of meaningful data bits in - * the stored value. 8, 16 and 32 bit values are stored using the - * INT32 physical type. 64 bit values are stored using the INT64 - * physical type. - * - */ INT_8 = 15, INT_16 = 16, INT_32 = 17, INT_64 = 18, - /** - * An embedded JSON document - * - * A JSON document embedded within a single UTF8 column. - */ JSON = 19, - /** - * An embedded BSON document - * - * A BSON document embedded within a single BYTE_ARRAY column. - */ BSON = 20, - /** - * An interval of time - * - * This type annotates data stored as a FIXED_LEN_BYTE_ARRAY of length 12 - * This data is composed of three separate little endian unsigned - * integers. Each stores a component of a duration of time. The first - * integer identifies the number of months associated with the duration, - * the second identifies the number of days associated with the duration - * and the third identifies the number of milliseconds associated with - * the provided duration. This duration of time is independent of any - * particular timezone or date. - */ - INTERVAL = 21 + INTERVAL = 21, + NULL_TYPE = 24 }; }; -extern const std::map _ConvertedType_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const ConvertedType::type& val); -std::string to_string(const ConvertedType::type& val); - -/** - * Representation of Schemas - */ struct FieldRepetitionType { enum type { - /** - * This field is required (can not be null) and each row has exactly 1 value. - */ REQUIRED = 0, - /** - * The field is optional (can be null) and each row has 0 or 1 values. - */ OPTIONAL = 1, - /** - * The field is repeated and can contain 0 or more values - */ REPEATED = 2 }; }; -extern const std::map _FieldRepetitionType_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const FieldRepetitionType::type& val); -std::string to_string(const FieldRepetitionType::type& val); - -/** - * Encodings supported by Parquet. Not all encodings are valid for all types. These - * enums are also used to specify the encoding of definition and repetition levels. - * See the accompanying doc for the details of the more complicated encodings. - */ struct Encoding { enum type { - /** - * Default encoding. - * BOOLEAN - 1 bit per value. 0 is false; 1 is true. - * INT32 - 4 bytes per value. Stored as little-endian. - * INT64 - 8 bytes per value. Stored as little-endian. - * FLOAT - 4 bytes per value. IEEE. Stored as little-endian. - * DOUBLE - 8 bytes per value. IEEE. Stored as little-endian. - * BYTE_ARRAY - 4 byte length stored as little endian, followed by bytes. - * FIXED_LEN_BYTE_ARRAY - Just the bytes. - */ PLAIN = 0, - /** - * Deprecated: Dictionary encoding. The values in the dictionary are encoded in the - * plain type. - * in a data page use RLE_DICTIONARY instead. - * in a Dictionary page use PLAIN instead - */ PLAIN_DICTIONARY = 2, - /** - * Group packed run length encoding. Usable for definition/repetition levels - * encoding and Booleans (on one bit: 0 is false; 1 is true.) - */ RLE = 3, - /** - * Bit packed encoding. This can only be used if the data has a known max - * width. Usable for definition/repetition levels encoding. - */ BIT_PACKED = 4, - /** - * Delta encoding for integers. This can be used for int columns and works best - * on sorted data - */ DELTA_BINARY_PACKED = 5, - /** - * Encoding for byte arrays to separate the length values and the data. The lengths - * are encoded using DELTA_BINARY_PACKED - */ DELTA_LENGTH_BYTE_ARRAY = 6, - /** - * Incremental-encoded byte array. Prefix lengths are encoded using DELTA_BINARY_PACKED. - * Suffixes are stored as delta length byte arrays. - */ DELTA_BYTE_ARRAY = 7, - /** - * Dictionary encoding: the ids are encoded using the RLE encoding - */ RLE_DICTIONARY = 8, - /** - * Encoding for fixed-width data (FLOAT, DOUBLE, INT32, INT64, FIXED_LEN_BYTE_ARRAY). - * K byte-streams are created where K is the size in bytes of the data type. - * The individual bytes of a value are scattered to the corresponding stream and - * the streams are concatenated. - * This itself does not reduce the size of the data but can lead to better compression - * afterwards. - * - * Added in 2.8 for FLOAT and DOUBLE. - * Support for INT32, INT64 and FIXED_LEN_BYTE_ARRAY added in 2.11. - */ - BYTE_STREAM_SPLIT = 9 + BYTE_STREAM_SPLIT = 9, }; }; -extern const std::map _Encoding_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const Encoding::type& val); -std::string to_string(const Encoding::type& val); - -/** - * Supported compression algorithms. - * - * Codecs added in format version X.Y can be read by readers based on X.Y and later. - * Codec support may vary between readers based on the format version and - * libraries available at runtime. - * - * See Compression.md for a detailed specification of these algorithms. - */ struct CompressionCodec { - enum type { + enum type : uint8_t { UNCOMPRESSED = 0, SNAPPY = 1, GZIP = 2, @@ -307,16 +103,12 @@ struct CompressionCodec { BROTLI = 4, LZ4 = 5, ZSTD = 6, - LZ4_RAW = 7 + LZ4_RAW = 7 }; }; -extern const std::map _CompressionCodec_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const CompressionCodec::type& val); -std::string to_string(const CompressionCodec::type& val); - struct PageType { enum type { DATA_PAGE = 0, @@ -326,16 +118,8 @@ struct PageType { }; }; -extern const std::map _PageType_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const PageType::type& val); -std::string to_string(const PageType::type& val); - -/** - * Enum to annotate whether lists of min/max elements inside ColumnIndex - * are ordered and if so, in which direction. - */ struct BoundaryOrder { enum type { UNORDERED = 0, @@ -344,14 +128,8 @@ struct BoundaryOrder { }; }; -extern const std::map _BoundaryOrder_VALUES_TO_NAMES; - std::ostream& operator<<(std::ostream& out, const BoundaryOrder::type& val); -std::string to_string(const BoundaryOrder::type& val); - -class SizeStatistics; - class Statistics; class StringType; @@ -366,8 +144,6 @@ class EnumType; class DateType; -class Float16Type; - class NullType; class DecimalType; @@ -402,20 +178,6 @@ class DictionaryPageHeader; class DataPageHeaderV2; -class SplitBlockAlgorithm; - -class BloomFilterAlgorithm; - -class XxHash; - -class BloomFilterHash; - -class Uncompressed; - -class BloomFilterCompression; - -class BloomFilterHeader; - class PageHeader; class KeyValue; @@ -456,159 +218,31 @@ class FileMetaData; class FileCryptoMetaData; -typedef struct _SizeStatistics__isset { - _SizeStatistics__isset() : unencoded_byte_array_data_bytes(false), repetition_level_histogram(false), definition_level_histogram(false) {} - bool unencoded_byte_array_data_bytes :1; - bool repetition_level_histogram :1; - bool definition_level_histogram :1; -} _SizeStatistics__isset; - -/** - * A structure for capturing metadata for estimating the unencoded, - * uncompressed size of data written. This is useful for readers to estimate - * how much memory is needed to reconstruct data in their memory model and for - * fine grained filter pushdown on nested structures (the histograms contained - * in this structure can help determine the number of nulls at a particular - * nesting level and maximum length of lists). - */ -class SizeStatistics : public virtual ::apache::thrift::TBase { - public: - - SizeStatistics(const SizeStatistics&); - SizeStatistics& operator=(const SizeStatistics&); - SizeStatistics() noexcept; - - virtual ~SizeStatistics() noexcept; - /** - * The number of physical bytes stored for BYTE_ARRAY data values assuming - * no encoding. This is exclusive of the bytes needed to store the length of - * each byte array. In other words, this field is equivalent to the `(size - * of PLAIN-ENCODING the byte array values) - (4 bytes * number of values - * written)`. To determine unencoded sizes of other types readers can use - * schema information multiplied by the number of non-null and null values. - * The number of null/non-null values can be inferred from the histograms - * below. - * - * For example, if a column chunk is dictionary-encoded with dictionary - * ["a", "bc", "cde"], and a data page contains the indices [0, 0, 1, 2], - * then this value for that data page should be 7 (1 + 1 + 2 + 3). - * - * This field should only be set for types that use BYTE_ARRAY as their - * physical type. - */ - int64_t unencoded_byte_array_data_bytes; - /** - * When present, there is expected to be one element corresponding to each - * repetition (i.e. size=max repetition_level+1) where each element - * represents the number of times the repetition level was observed in the - * data. - * - * This field may be omitted if max_repetition_level is 0 without loss - * of information. - * - */ - duckdb::vector repetition_level_histogram; - /** - * Same as repetition_level_histogram except for definition levels. - * - * This field may be omitted if max_definition_level is 0 or 1 without - * loss of information. - * - */ - duckdb::vector definition_level_histogram; - - _SizeStatistics__isset __isset; - - void __set_unencoded_byte_array_data_bytes(const int64_t val); - - void __set_repetition_level_histogram(const duckdb::vector & val); - - void __set_definition_level_histogram(const duckdb::vector & val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(SizeStatistics &a, SizeStatistics &b); - -std::ostream& operator<<(std::ostream& out, const SizeStatistics& obj); - typedef struct _Statistics__isset { - _Statistics__isset() : max(false), min(false), null_count(false), distinct_count(false), max_value(false), min_value(false), is_max_value_exact(false), is_min_value_exact(false) {} + _Statistics__isset() : max(false), min(false), null_count(false), distinct_count(false), max_value(false), min_value(false) {} bool max :1; bool min :1; bool null_count :1; bool distinct_count :1; bool max_value :1; bool min_value :1; - bool is_max_value_exact :1; - bool is_min_value_exact :1; } _Statistics__isset; -/** - * Statistics per row group and per page - * All fields are optional. - */ -class Statistics : public virtual ::apache::thrift::TBase { +class Statistics : public virtual ::duckdb_apache::thrift::TBase { public: Statistics(const Statistics&); Statistics& operator=(const Statistics&); - Statistics() noexcept; - - virtual ~Statistics() noexcept; - /** - * DEPRECATED: min and max value of the column. Use min_value and max_value. - * - * Values are encoded using PLAIN encoding, except that variable-length byte - * arrays do not include a length prefix. - * - * These fields encode min and max values determined by signed comparison - * only. New files should use the correct order for a column's logical type - * and store the values in the min_value and max_value fields. - * - * To support older readers, these may be set when the column order is - * signed. - */ + Statistics() : max(), min(), null_count(0), distinct_count(0), max_value(), min_value() { + } + + virtual ~Statistics() throw(); std::string max; std::string min; - /** - * Count of null values in the column. - * - * Writers SHOULD always write this field even if it is zero (i.e. no null value) - * or the column is not nullable. - * Readers MUST distinguish between null_count not being present and null_count == 0. - * If null_count is not present, readers MUST NOT assume null_count == 0. - */ int64_t null_count; - /** - * count of distinct values occurring - */ int64_t distinct_count; - /** - * Lower and upper bound values for the column, determined by its ColumnOrder. - * - * These may be the actual minimum and maximum values found on a page or column - * chunk, but can also be (more compact) values that do not exist on a page or - * column chunk. For example, instead of storing "Blart Versenwald III", a writer - * may set min_value="B", max_value="C". Such more compact values must still be - * valid values within the column's logical type. - * - * Values are encoded using PLAIN encoding, except that variable-length byte - * arrays do not include a length prefix. - */ std::string max_value; std::string min_value; - /** - * If true, max_value is the actual maximum value for a column - */ - bool is_max_value_exact; - /** - * If true, min_value is the actual minimum value for a column - */ - bool is_min_value_exact; _Statistics__isset __isset; @@ -624,12 +258,42 @@ class Statistics : public virtual ::apache::thrift::TBase { void __set_min_value(const std::string& val); - void __set_is_max_value_exact(const bool val); - - void __set_is_min_value_exact(const bool val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const Statistics & rhs) const + { + if (__isset.max != rhs.__isset.max) + return false; + else if (__isset.max && !(max == rhs.max)) + return false; + if (__isset.min != rhs.__isset.min) + return false; + else if (__isset.min && !(min == rhs.min)) + return false; + if (__isset.null_count != rhs.__isset.null_count) + return false; + else if (__isset.null_count && !(null_count == rhs.null_count)) + return false; + if (__isset.distinct_count != rhs.__isset.distinct_count) + return false; + else if (__isset.distinct_count && !(distinct_count == rhs.distinct_count)) + return false; + if (__isset.max_value != rhs.__isset.max_value) + return false; + else if (__isset.max_value && !(max_value == rhs.max_value)) + return false; + if (__isset.min_value != rhs.__isset.min_value) + return false; + else if (__isset.min_value && !(min_value == rhs.min_value)) + return false; + return true; + } + bool operator != (const Statistics &rhs) const { + return !(*this == rhs); + } + + bool operator < (const Statistics & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -639,20 +303,28 @@ void swap(Statistics &a, Statistics &b); std::ostream& operator<<(std::ostream& out, const Statistics& obj); -/** - * Empty structs to use as logical type annotations - */ -class StringType : public virtual ::apache::thrift::TBase { +class StringType : public virtual ::duckdb_apache::thrift::TBase { public: - StringType(const StringType&) noexcept; - StringType& operator=(const StringType&) noexcept; - StringType() noexcept; + StringType(const StringType&); + StringType& operator=(const StringType&); + StringType() { + } - virtual ~StringType() noexcept; + virtual ~StringType() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const StringType & /* rhs */) const + { + return true; + } + bool operator != (const StringType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const StringType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -662,17 +334,28 @@ void swap(StringType &a, StringType &b); std::ostream& operator<<(std::ostream& out, const StringType& obj); -class UUIDType : public virtual ::apache::thrift::TBase { +class UUIDType : public virtual ::duckdb_apache::thrift::TBase { public: - UUIDType(const UUIDType&) noexcept; - UUIDType& operator=(const UUIDType&) noexcept; - UUIDType() noexcept; + UUIDType(const UUIDType&); + UUIDType& operator=(const UUIDType&); + UUIDType() { + } + + virtual ~UUIDType() throw(); + + bool operator == (const UUIDType & /* rhs */) const + { + return true; + } + bool operator != (const UUIDType &rhs) const { + return !(*this == rhs); + } - virtual ~UUIDType() noexcept; + bool operator < (const UUIDType & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -682,17 +365,28 @@ void swap(UUIDType &a, UUIDType &b); std::ostream& operator<<(std::ostream& out, const UUIDType& obj); -class MapType : public virtual ::apache::thrift::TBase { +class MapType : public virtual ::duckdb_apache::thrift::TBase { public: - MapType(const MapType&) noexcept; - MapType& operator=(const MapType&) noexcept; - MapType() noexcept; + MapType(const MapType&); + MapType& operator=(const MapType&); + MapType() { + } - virtual ~MapType() noexcept; + virtual ~MapType() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const MapType & /* rhs */) const + { + return true; + } + bool operator != (const MapType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const MapType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -702,17 +396,28 @@ void swap(MapType &a, MapType &b); std::ostream& operator<<(std::ostream& out, const MapType& obj); -class ListType : public virtual ::apache::thrift::TBase { +class ListType : public virtual ::duckdb_apache::thrift::TBase { public: - ListType(const ListType&) noexcept; - ListType& operator=(const ListType&) noexcept; - ListType() noexcept; + ListType(const ListType&); + ListType& operator=(const ListType&); + ListType() { + } + + virtual ~ListType() throw(); + + bool operator == (const ListType & /* rhs */) const + { + return true; + } + bool operator != (const ListType &rhs) const { + return !(*this == rhs); + } - virtual ~ListType() noexcept; + bool operator < (const ListType & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -722,17 +427,28 @@ void swap(ListType &a, ListType &b); std::ostream& operator<<(std::ostream& out, const ListType& obj); -class EnumType : public virtual ::apache::thrift::TBase { +class EnumType : public virtual ::duckdb_apache::thrift::TBase { public: - EnumType(const EnumType&) noexcept; - EnumType& operator=(const EnumType&) noexcept; - EnumType() noexcept; + EnumType(const EnumType&); + EnumType& operator=(const EnumType&); + EnumType() { + } - virtual ~EnumType() noexcept; + virtual ~EnumType() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const EnumType & /* rhs */) const + { + return true; + } + bool operator != (const EnumType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const EnumType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -742,17 +458,28 @@ void swap(EnumType &a, EnumType &b); std::ostream& operator<<(std::ostream& out, const EnumType& obj); -class DateType : public virtual ::apache::thrift::TBase { +class DateType : public virtual ::duckdb_apache::thrift::TBase { public: - DateType(const DateType&) noexcept; - DateType& operator=(const DateType&) noexcept; - DateType() noexcept; + DateType(const DateType&); + DateType& operator=(const DateType&); + DateType() { + } + + virtual ~DateType() throw(); + + bool operator == (const DateType & /* rhs */) const + { + return true; + } + bool operator != (const DateType &rhs) const { + return !(*this == rhs); + } - virtual ~DateType() noexcept; + bool operator < (const DateType & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -762,44 +489,28 @@ void swap(DateType &a, DateType &b); std::ostream& operator<<(std::ostream& out, const DateType& obj); -class Float16Type : public virtual ::apache::thrift::TBase { +class NullType : public virtual ::duckdb_apache::thrift::TBase { public: - Float16Type(const Float16Type&) noexcept; - Float16Type& operator=(const Float16Type&) noexcept; - Float16Type() noexcept; + NullType(const NullType&); + NullType& operator=(const NullType&); + NullType() { + } - virtual ~Float16Type() noexcept; + virtual ~NullType() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const NullType & /* rhs */) const + { + return true; + } + bool operator != (const NullType &rhs) const { + return !(*this == rhs); + } - virtual void printTo(std::ostream& out) const; -}; - -void swap(Float16Type &a, Float16Type &b); - -std::ostream& operator<<(std::ostream& out, const Float16Type& obj); - - -/** - * Logical type to annotate a column that is always null. - * - * Sometimes when discovering the schema of existing data, values are always - * null and the physical type can't be determined. This annotation signals - * the case where the physical type was guessed from all null values. - */ -class NullType : public virtual ::apache::thrift::TBase { - public: + bool operator < (const NullType & ) const; - NullType(const NullType&) noexcept; - NullType& operator=(const NullType&) noexcept; - NullType() noexcept; - - virtual ~NullType() noexcept; - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -809,25 +520,15 @@ void swap(NullType &a, NullType &b); std::ostream& operator<<(std::ostream& out, const NullType& obj); -/** - * Decimal logical type annotation - * - * Scale must be zero or a positive integer less than or equal to the precision. - * Precision must be a non-zero positive integer. - * - * To maintain forward-compatibility in v1, implementations using this logical - * type must also set scale and precision on the annotated SchemaElement. - * - * Allowed for physical types: INT32, INT64, FIXED_LEN_BYTE_ARRAY, and BYTE_ARRAY. - */ -class DecimalType : public virtual ::apache::thrift::TBase { +class DecimalType : public virtual ::duckdb_apache::thrift::TBase { public: - DecimalType(const DecimalType&) noexcept; - DecimalType& operator=(const DecimalType&) noexcept; - DecimalType() noexcept; + DecimalType(const DecimalType&); + DecimalType& operator=(const DecimalType&); + DecimalType() : scale(0), precision(0) { + } - virtual ~DecimalType() noexcept; + virtual ~DecimalType() throw(); int32_t scale; int32_t precision; @@ -835,8 +536,22 @@ class DecimalType : public virtual ::apache::thrift::TBase { void __set_precision(const int32_t val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const DecimalType & rhs) const + { + if (!(scale == rhs.scale)) + return false; + if (!(precision == rhs.precision)) + return false; + return true; + } + bool operator != (const DecimalType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const DecimalType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -846,20 +561,28 @@ void swap(DecimalType &a, DecimalType &b); std::ostream& operator<<(std::ostream& out, const DecimalType& obj); -/** - * Time units for logical types - */ -class MilliSeconds : public virtual ::apache::thrift::TBase { +class MilliSeconds : public virtual ::duckdb_apache::thrift::TBase { public: - MilliSeconds(const MilliSeconds&) noexcept; - MilliSeconds& operator=(const MilliSeconds&) noexcept; - MilliSeconds() noexcept; + MilliSeconds(const MilliSeconds&); + MilliSeconds& operator=(const MilliSeconds&); + MilliSeconds() { + } - virtual ~MilliSeconds() noexcept; + virtual ~MilliSeconds() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const MilliSeconds & /* rhs */) const + { + return true; + } + bool operator != (const MilliSeconds &rhs) const { + return !(*this == rhs); + } + + bool operator < (const MilliSeconds & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -869,17 +592,28 @@ void swap(MilliSeconds &a, MilliSeconds &b); std::ostream& operator<<(std::ostream& out, const MilliSeconds& obj); -class MicroSeconds : public virtual ::apache::thrift::TBase { +class MicroSeconds : public virtual ::duckdb_apache::thrift::TBase { public: - MicroSeconds(const MicroSeconds&) noexcept; - MicroSeconds& operator=(const MicroSeconds&) noexcept; - MicroSeconds() noexcept; + MicroSeconds(const MicroSeconds&); + MicroSeconds& operator=(const MicroSeconds&); + MicroSeconds() { + } + + virtual ~MicroSeconds() throw(); + + bool operator == (const MicroSeconds & /* rhs */) const + { + return true; + } + bool operator != (const MicroSeconds &rhs) const { + return !(*this == rhs); + } - virtual ~MicroSeconds() noexcept; + bool operator < (const MicroSeconds & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -889,17 +623,28 @@ void swap(MicroSeconds &a, MicroSeconds &b); std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj); -class NanoSeconds : public virtual ::apache::thrift::TBase { +class NanoSeconds : public virtual ::duckdb_apache::thrift::TBase { public: - NanoSeconds(const NanoSeconds&) noexcept; - NanoSeconds& operator=(const NanoSeconds&) noexcept; - NanoSeconds() noexcept; + NanoSeconds(const NanoSeconds&); + NanoSeconds& operator=(const NanoSeconds&); + NanoSeconds() { + } - virtual ~NanoSeconds() noexcept; + virtual ~NanoSeconds() throw(); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const NanoSeconds & /* rhs */) const + { + return true; + } + bool operator != (const NanoSeconds &rhs) const { + return !(*this == rhs); + } + + bool operator < (const NanoSeconds & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -915,14 +660,15 @@ typedef struct _TimeUnit__isset { bool NANOS :1; } _TimeUnit__isset; -class TimeUnit : public virtual ::apache::thrift::TBase { +class TimeUnit : public virtual ::duckdb_apache::thrift::TBase { public: - TimeUnit(const TimeUnit&) noexcept; - TimeUnit& operator=(const TimeUnit&) noexcept; - TimeUnit() noexcept; + TimeUnit(const TimeUnit&); + TimeUnit& operator=(const TimeUnit&); + TimeUnit() { + } - virtual ~TimeUnit() noexcept; + virtual ~TimeUnit() throw(); MilliSeconds MILLIS; MicroSeconds MICROS; NanoSeconds NANOS; @@ -935,8 +681,30 @@ class TimeUnit : public virtual ::apache::thrift::TBase { void __set_NANOS(const NanoSeconds& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const TimeUnit & rhs) const + { + if (__isset.MILLIS != rhs.__isset.MILLIS) + return false; + else if (__isset.MILLIS && !(MILLIS == rhs.MILLIS)) + return false; + if (__isset.MICROS != rhs.__isset.MICROS) + return false; + else if (__isset.MICROS && !(MICROS == rhs.MICROS)) + return false; + if (__isset.NANOS != rhs.__isset.NANOS) + return false; + else if (__isset.NANOS && !(NANOS == rhs.NANOS)) + return false; + return true; + } + bool operator != (const TimeUnit &rhs) const { + return !(*this == rhs); + } + + bool operator < (const TimeUnit & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -946,19 +714,15 @@ void swap(TimeUnit &a, TimeUnit &b); std::ostream& operator<<(std::ostream& out, const TimeUnit& obj); -/** - * Timestamp logical type annotation - * - * Allowed for physical types: INT64 - */ -class TimestampType : public virtual ::apache::thrift::TBase { +class TimestampType : public virtual ::duckdb_apache::thrift::TBase { public: - TimestampType(const TimestampType&) noexcept; - TimestampType& operator=(const TimestampType&) noexcept; - TimestampType() noexcept; + TimestampType(const TimestampType&); + TimestampType& operator=(const TimestampType&); + TimestampType() : isAdjustedToUTC(0) { + } - virtual ~TimestampType() noexcept; + virtual ~TimestampType() throw(); bool isAdjustedToUTC; TimeUnit unit; @@ -966,8 +730,22 @@ class TimestampType : public virtual ::apache::thrift::TBase { void __set_unit(const TimeUnit& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const TimestampType & rhs) const + { + if (!(isAdjustedToUTC == rhs.isAdjustedToUTC)) + return false; + if (!(unit == rhs.unit)) + return false; + return true; + } + bool operator != (const TimestampType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const TimestampType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -977,19 +755,15 @@ void swap(TimestampType &a, TimestampType &b); std::ostream& operator<<(std::ostream& out, const TimestampType& obj); -/** - * Time logical type annotation - * - * Allowed for physical types: INT32 (millis), INT64 (micros, nanos) - */ -class TimeType : public virtual ::apache::thrift::TBase { +class TimeType : public virtual ::duckdb_apache::thrift::TBase { public: - TimeType(const TimeType&) noexcept; - TimeType& operator=(const TimeType&) noexcept; - TimeType() noexcept; + TimeType(const TimeType&); + TimeType& operator=(const TimeType&); + TimeType() : isAdjustedToUTC(0) { + } - virtual ~TimeType() noexcept; + virtual ~TimeType() throw(); bool isAdjustedToUTC; TimeUnit unit; @@ -997,8 +771,22 @@ class TimeType : public virtual ::apache::thrift::TBase { void __set_unit(const TimeUnit& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const TimeType & rhs) const + { + if (!(isAdjustedToUTC == rhs.isAdjustedToUTC)) + return false; + if (!(unit == rhs.unit)) + return false; + return true; + } + bool operator != (const TimeType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const TimeType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1008,21 +796,15 @@ void swap(TimeType &a, TimeType &b); std::ostream& operator<<(std::ostream& out, const TimeType& obj); -/** - * Integer logical type annotation - * - * bitWidth must be 8, 16, 32, or 64. - * - * Allowed for physical types: INT32, INT64 - */ -class IntType : public virtual ::apache::thrift::TBase { +class IntType : public virtual ::duckdb_apache::thrift::TBase { public: - IntType(const IntType&) noexcept; - IntType& operator=(const IntType&) noexcept; - IntType() noexcept; + IntType(const IntType&); + IntType& operator=(const IntType&); + IntType() : bitWidth(0), isSigned(0) { + } - virtual ~IntType() noexcept; + virtual ~IntType() throw(); int8_t bitWidth; bool isSigned; @@ -1030,8 +812,22 @@ class IntType : public virtual ::apache::thrift::TBase { void __set_isSigned(const bool val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const IntType & rhs) const + { + if (!(bitWidth == rhs.bitWidth)) + return false; + if (!(isSigned == rhs.isSigned)) + return false; + return true; + } + bool operator != (const IntType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const IntType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1041,22 +837,28 @@ void swap(IntType &a, IntType &b); std::ostream& operator<<(std::ostream& out, const IntType& obj); -/** - * Embedded JSON logical type annotation - * - * Allowed for physical types: BYTE_ARRAY - */ -class JsonType : public virtual ::apache::thrift::TBase { +class JsonType : public virtual ::duckdb_apache::thrift::TBase { public: - JsonType(const JsonType&) noexcept; - JsonType& operator=(const JsonType&) noexcept; - JsonType() noexcept; + JsonType(const JsonType&); + JsonType& operator=(const JsonType&); + JsonType() { + } + + virtual ~JsonType() throw(); - virtual ~JsonType() noexcept; + bool operator == (const JsonType & /* rhs */) const + { + return true; + } + bool operator != (const JsonType &rhs) const { + return !(*this == rhs); + } - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator < (const JsonType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1066,22 +868,28 @@ void swap(JsonType &a, JsonType &b); std::ostream& operator<<(std::ostream& out, const JsonType& obj); -/** - * Embedded BSON logical type annotation - * - * Allowed for physical types: BYTE_ARRAY - */ -class BsonType : public virtual ::apache::thrift::TBase { +class BsonType : public virtual ::duckdb_apache::thrift::TBase { public: - BsonType(const BsonType&) noexcept; - BsonType& operator=(const BsonType&) noexcept; - BsonType() noexcept; + BsonType(const BsonType&); + BsonType& operator=(const BsonType&); + BsonType() { + } + + virtual ~BsonType() throw(); - virtual ~BsonType() noexcept; + bool operator == (const BsonType & /* rhs */) const + { + return true; + } + bool operator != (const BsonType &rhs) const { + return !(*this == rhs); + } - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator < (const BsonType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1091,7 +899,7 @@ void swap(BsonType &a, BsonType &b); std::ostream& operator<<(std::ostream& out, const BsonType& obj); typedef struct _LogicalType__isset { - _LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false), FLOAT16(false) {} + _LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false) {} bool STRING :1; bool MAP :1; bool LIST :1; @@ -1105,24 +913,17 @@ typedef struct _LogicalType__isset { bool JSON :1; bool BSON :1; bool UUID :1; - bool FLOAT16 :1; } _LogicalType__isset; -/** - * LogicalType annotations to replace ConvertedType. - * - * To maintain compatibility, implementations using LogicalType for a - * SchemaElement must also set the corresponding ConvertedType (if any) - * from the following table. - */ -class LogicalType : public virtual ::apache::thrift::TBase { +class LogicalType : public virtual ::duckdb_apache::thrift::TBase { public: - LogicalType(const LogicalType&) noexcept; - LogicalType& operator=(const LogicalType&) noexcept; - LogicalType() noexcept; + LogicalType(const LogicalType&); + LogicalType& operator=(const LogicalType&); + LogicalType() { + } - virtual ~LogicalType() noexcept; + virtual ~LogicalType() throw(); StringType STRING; MapType MAP; ListType LIST; @@ -1136,7 +937,6 @@ class LogicalType : public virtual ::apache::thrift::TBase { JsonType JSON; BsonType BSON; UUIDType UUID; - Float16Type FLOAT16; _LogicalType__isset __isset; @@ -1166,10 +966,70 @@ class LogicalType : public virtual ::apache::thrift::TBase { void __set_UUID(const UUIDType& val); - void __set_FLOAT16(const Float16Type& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const LogicalType & rhs) const + { + if (__isset.STRING != rhs.__isset.STRING) + return false; + else if (__isset.STRING && !(STRING == rhs.STRING)) + return false; + if (__isset.MAP != rhs.__isset.MAP) + return false; + else if (__isset.MAP && !(MAP == rhs.MAP)) + return false; + if (__isset.LIST != rhs.__isset.LIST) + return false; + else if (__isset.LIST && !(LIST == rhs.LIST)) + return false; + if (__isset.ENUM != rhs.__isset.ENUM) + return false; + else if (__isset.ENUM && !(ENUM == rhs.ENUM)) + return false; + if (__isset.DECIMAL != rhs.__isset.DECIMAL) + return false; + else if (__isset.DECIMAL && !(DECIMAL == rhs.DECIMAL)) + return false; + if (__isset.DATE != rhs.__isset.DATE) + return false; + else if (__isset.DATE && !(DATE == rhs.DATE)) + return false; + if (__isset.TIME != rhs.__isset.TIME) + return false; + else if (__isset.TIME && !(TIME == rhs.TIME)) + return false; + if (__isset.TIMESTAMP != rhs.__isset.TIMESTAMP) + return false; + else if (__isset.TIMESTAMP && !(TIMESTAMP == rhs.TIMESTAMP)) + return false; + if (__isset.INTEGER != rhs.__isset.INTEGER) + return false; + else if (__isset.INTEGER && !(INTEGER == rhs.INTEGER)) + return false; + if (__isset.UNKNOWN != rhs.__isset.UNKNOWN) + return false; + else if (__isset.UNKNOWN && !(UNKNOWN == rhs.UNKNOWN)) + return false; + if (__isset.JSON != rhs.__isset.JSON) + return false; + else if (__isset.JSON && !(JSON == rhs.JSON)) + return false; + if (__isset.BSON != rhs.__isset.BSON) + return false; + else if (__isset.BSON && !(BSON == rhs.BSON)) + return false; + if (__isset.UUID != rhs.__isset.UUID) + return false; + else if (__isset.UUID && !(UUID == rhs.UUID)) + return false; + return true; + } + bool operator != (const LogicalType &rhs) const { + return !(*this == rhs); + } + + bool operator < (const LogicalType & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1191,79 +1051,24 @@ typedef struct _SchemaElement__isset { bool logicalType :1; } _SchemaElement__isset; -/** - * Represents a element inside a schema definition. - * - if it is a group (inner node) then type is undefined and num_children is defined - * - if it is a primitive type (leaf) then type is defined and num_children is undefined - * the nodes are listed in depth first traversal order. - */ -class SchemaElement : public virtual ::apache::thrift::TBase { +class SchemaElement : public virtual ::duckdb_apache::thrift::TBase { public: SchemaElement(const SchemaElement&); SchemaElement& operator=(const SchemaElement&); - SchemaElement() noexcept; - - virtual ~SchemaElement() noexcept; - /** - * Data type for this field. Not set if the current element is a non-leaf node - * - * @see Type - */ + SchemaElement() : type((Type::type)0), type_length(0), repetition_type((FieldRepetitionType::type)0), name(), num_children(0), converted_type((ConvertedType::type)0), scale(0), precision(0), field_id(0) { + } + + virtual ~SchemaElement() throw(); Type::type type; - /** - * If type is FIXED_LEN_BYTE_ARRAY, this is the byte length of the values. - * Otherwise, if specified, this is the maximum bit length to store any of the values. - * (e.g. a low cardinality INT col could have this set to 3). Note that this is - * in the schema, and therefore fixed for the entire file. - */ int32_t type_length; - /** - * repetition of the field. The root of the schema does not have a repetition_type. - * All other nodes must have one - * - * @see FieldRepetitionType - */ FieldRepetitionType::type repetition_type; - /** - * Name of the field in the schema - */ std::string name; - /** - * Nested fields. Since thrift does not support nested fields, - * the nesting is flattened to a single list by a depth-first traversal. - * The children count is used to construct the nested relationship. - * This field is not set when the element is a primitive type - */ int32_t num_children; - /** - * DEPRECATED: When the schema is the result of a conversion from another model. - * Used to record the original type to help with cross conversion. - * - * This is superseded by logicalType. - * - * @see ConvertedType - */ ConvertedType::type converted_type; - /** - * DEPRECATED: Used when this column contains decimal data. - * See the DECIMAL converted type for more details. - * - * This is superseded by using the DecimalType annotation in logicalType. - */ int32_t scale; int32_t precision; - /** - * When the original schema supports field ids, this will save the - * original field id in the parquet schema - */ int32_t field_id; - /** - * The logical type of this SchemaElement - * - * LogicalType replaces ConvertedType, but ConvertedType is still required - * for some logical types to ensure forward-compatibility in format v1. - */ LogicalType logicalType; _SchemaElement__isset __isset; @@ -1288,8 +1093,56 @@ class SchemaElement : public virtual ::apache::thrift::TBase { void __set_logicalType(const LogicalType& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const SchemaElement & rhs) const + { + if (__isset.type != rhs.__isset.type) + return false; + else if (__isset.type && !(type == rhs.type)) + return false; + if (__isset.type_length != rhs.__isset.type_length) + return false; + else if (__isset.type_length && !(type_length == rhs.type_length)) + return false; + if (__isset.repetition_type != rhs.__isset.repetition_type) + return false; + else if (__isset.repetition_type && !(repetition_type == rhs.repetition_type)) + return false; + if (!(name == rhs.name)) + return false; + if (__isset.num_children != rhs.__isset.num_children) + return false; + else if (__isset.num_children && !(num_children == rhs.num_children)) + return false; + if (__isset.converted_type != rhs.__isset.converted_type) + return false; + else if (__isset.converted_type && !(converted_type == rhs.converted_type)) + return false; + if (__isset.scale != rhs.__isset.scale) + return false; + else if (__isset.scale && !(scale == rhs.scale)) + return false; + if (__isset.precision != rhs.__isset.precision) + return false; + else if (__isset.precision && !(precision == rhs.precision)) + return false; + if (__isset.field_id != rhs.__isset.field_id) + return false; + else if (__isset.field_id && !(field_id == rhs.field_id)) + return false; + if (__isset.logicalType != rhs.__isset.logicalType) + return false; + else if (__isset.logicalType && !(logicalType == rhs.logicalType)) + return false; + return true; + } + bool operator != (const SchemaElement &rhs) const { + return !(*this == rhs); + } + + bool operator < (const SchemaElement & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1303,47 +1156,19 @@ typedef struct _DataPageHeader__isset { bool statistics :1; } _DataPageHeader__isset; -/** - * Data page header - */ -class DataPageHeader : public virtual ::apache::thrift::TBase { +class DataPageHeader : public virtual ::duckdb_apache::thrift::TBase { public: DataPageHeader(const DataPageHeader&); DataPageHeader& operator=(const DataPageHeader&); - DataPageHeader() noexcept; - - virtual ~DataPageHeader() noexcept; - /** - * Number of values, including NULLs, in this data page. - * - * If a OffsetIndex is present, a page must begin at a row - * boundary (repetition_level = 0). Otherwise, pages may begin - * within a row (repetition_level > 0). - * - */ + DataPageHeader() : num_values(0), encoding((Encoding::type)0), definition_level_encoding((Encoding::type)0), repetition_level_encoding((Encoding::type)0) { + } + + virtual ~DataPageHeader() throw(); int32_t num_values; - /** - * Encoding used for this data page * - * - * @see Encoding - */ Encoding::type encoding; - /** - * Encoding used for definition levels * - * - * @see Encoding - */ Encoding::type definition_level_encoding; - /** - * Encoding used for repetition levels * - * - * @see Encoding - */ Encoding::type repetition_level_encoding; - /** - * Optional statistics for the data in this page * - */ Statistics statistics; _DataPageHeader__isset __isset; @@ -1358,8 +1183,30 @@ class DataPageHeader : public virtual ::apache::thrift::TBase { void __set_statistics(const Statistics& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const DataPageHeader & rhs) const + { + if (!(num_values == rhs.num_values)) + return false; + if (!(encoding == rhs.encoding)) + return false; + if (!(definition_level_encoding == rhs.definition_level_encoding)) + return false; + if (!(repetition_level_encoding == rhs.repetition_level_encoding)) + return false; + if (__isset.statistics != rhs.__isset.statistics) + return false; + else if (__isset.statistics && !(statistics == rhs.statistics)) + return false; + return true; + } + bool operator != (const DataPageHeader &rhs) const { + return !(*this == rhs); + } + + bool operator < (const DataPageHeader & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1369,17 +1216,28 @@ void swap(DataPageHeader &a, DataPageHeader &b); std::ostream& operator<<(std::ostream& out, const DataPageHeader& obj); -class IndexPageHeader : public virtual ::apache::thrift::TBase { +class IndexPageHeader : public virtual ::duckdb_apache::thrift::TBase { public: - IndexPageHeader(const IndexPageHeader&) noexcept; - IndexPageHeader& operator=(const IndexPageHeader&) noexcept; - IndexPageHeader() noexcept; + IndexPageHeader(const IndexPageHeader&); + IndexPageHeader& operator=(const IndexPageHeader&); + IndexPageHeader() { + } + + virtual ~IndexPageHeader() throw(); + + bool operator == (const IndexPageHeader & /* rhs */) const + { + return true; + } + bool operator != (const IndexPageHeader &rhs) const { + return !(*this == rhs); + } - virtual ~IndexPageHeader() noexcept; + bool operator < (const IndexPageHeader & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1393,33 +1251,17 @@ typedef struct _DictionaryPageHeader__isset { bool is_sorted :1; } _DictionaryPageHeader__isset; -/** - * The dictionary page must be placed at the first position of the column chunk - * if it is partly or completely dictionary encoded. At most one dictionary page - * can be placed in a column chunk. - * - */ -class DictionaryPageHeader : public virtual ::apache::thrift::TBase { +class DictionaryPageHeader : public virtual ::duckdb_apache::thrift::TBase { public: - DictionaryPageHeader(const DictionaryPageHeader&) noexcept; - DictionaryPageHeader& operator=(const DictionaryPageHeader&) noexcept; - DictionaryPageHeader() noexcept; + DictionaryPageHeader(const DictionaryPageHeader&); + DictionaryPageHeader& operator=(const DictionaryPageHeader&); + DictionaryPageHeader() : num_values(0), encoding((Encoding::type)0), is_sorted(0) { + } - virtual ~DictionaryPageHeader() noexcept; - /** - * Number of values in the dictionary * - */ + virtual ~DictionaryPageHeader() throw(); int32_t num_values; - /** - * Encoding using this dictionary page * - * - * @see Encoding - */ Encoding::type encoding; - /** - * If true, the entries in the dictionary are sorted in ascending order * - */ bool is_sorted; _DictionaryPageHeader__isset __isset; @@ -1430,8 +1272,26 @@ class DictionaryPageHeader : public virtual ::apache::thrift::TBase { void __set_is_sorted(const bool val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const DictionaryPageHeader & rhs) const + { + if (!(num_values == rhs.num_values)) + return false; + if (!(encoding == rhs.encoding)) + return false; + if (__isset.is_sorted != rhs.__isset.is_sorted) + return false; + else if (__isset.is_sorted && !(is_sorted == rhs.is_sorted)) + return false; + return true; + } + bool operator != (const DictionaryPageHeader &rhs) const { + return !(*this == rhs); + } + + bool operator < (const DictionaryPageHeader & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1446,61 +1306,22 @@ typedef struct _DataPageHeaderV2__isset { bool statistics :1; } _DataPageHeaderV2__isset; -/** - * New page format allowing reading levels without decompressing the data - * Repetition and definition levels are uncompressed - * The remaining section containing the data is compressed if is_compressed is true - * - */ -class DataPageHeaderV2 : public virtual ::apache::thrift::TBase { +class DataPageHeaderV2 : public virtual ::duckdb_apache::thrift::TBase { public: DataPageHeaderV2(const DataPageHeaderV2&); DataPageHeaderV2& operator=(const DataPageHeaderV2&); - DataPageHeaderV2() noexcept; + DataPageHeaderV2() : num_values(0), num_nulls(0), num_rows(0), encoding((Encoding::type)0), definition_levels_byte_length(0), repetition_levels_byte_length(0), is_compressed(true) { + } - virtual ~DataPageHeaderV2() noexcept; - /** - * Number of values, including NULLs, in this data page. * - */ + virtual ~DataPageHeaderV2() throw(); int32_t num_values; - /** - * Number of NULL values, in this data page. - * Number of non-null = num_values - num_nulls which is also the number of values in the data section * - */ int32_t num_nulls; - /** - * Number of rows in this data page. Every page must begin at a - * row boundary (repetition_level = 0): rows must **not** be - * split across page boundaries when using V2 data pages. - * - */ int32_t num_rows; - /** - * Encoding used for data in this page * - * - * @see Encoding - */ Encoding::type encoding; - /** - * Length of the definition levels - */ int32_t definition_levels_byte_length; - /** - * Length of the repetition levels - */ int32_t repetition_levels_byte_length; - /** - * Whether the values are compressed. - * Which means the section of the page between - * definition_levels_byte_length + repetition_levels_byte_length + 1 and compressed_page_size (included) - * is compressed with the compression_codec. - * If missing it is considered compressed - */ bool is_compressed; - /** - * Optional statistics for the data in this page * - */ Statistics statistics; _DataPageHeaderV2__isset __isset; @@ -1521,8 +1342,38 @@ class DataPageHeaderV2 : public virtual ::apache::thrift::TBase { void __set_statistics(const Statistics& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const DataPageHeaderV2 & rhs) const + { + if (!(num_values == rhs.num_values)) + return false; + if (!(num_nulls == rhs.num_nulls)) + return false; + if (!(num_rows == rhs.num_rows)) + return false; + if (!(encoding == rhs.encoding)) + return false; + if (!(definition_levels_byte_length == rhs.definition_levels_byte_length)) + return false; + if (!(repetition_levels_byte_length == rhs.repetition_levels_byte_length)) + return false; + if (__isset.is_compressed != rhs.__isset.is_compressed) + return false; + else if (__isset.is_compressed && !(is_compressed == rhs.is_compressed)) + return false; + if (__isset.statistics != rhs.__isset.statistics) + return false; + else if (__isset.statistics && !(statistics == rhs.statistics)) + return false; + return true; + } + bool operator != (const DataPageHeaderV2 &rhs) const { + return !(*this == rhs); + } + + bool operator < (const DataPageHeaderV2 & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1531,228 +1382,6 @@ void swap(DataPageHeaderV2 &a, DataPageHeaderV2 &b); std::ostream& operator<<(std::ostream& out, const DataPageHeaderV2& obj); - -/** - * Block-based algorithm type annotation. * - */ -class SplitBlockAlgorithm : public virtual ::apache::thrift::TBase { - public: - - SplitBlockAlgorithm(const SplitBlockAlgorithm&) noexcept; - SplitBlockAlgorithm& operator=(const SplitBlockAlgorithm&) noexcept; - SplitBlockAlgorithm() noexcept; - - virtual ~SplitBlockAlgorithm() noexcept; - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(SplitBlockAlgorithm &a, SplitBlockAlgorithm &b); - -std::ostream& operator<<(std::ostream& out, const SplitBlockAlgorithm& obj); - -typedef struct _BloomFilterAlgorithm__isset { - _BloomFilterAlgorithm__isset() : BLOCK(false) {} - bool BLOCK :1; -} _BloomFilterAlgorithm__isset; - -/** - * The algorithm used in Bloom filter. * - */ -class BloomFilterAlgorithm : public virtual ::apache::thrift::TBase { - public: - - BloomFilterAlgorithm(const BloomFilterAlgorithm&) noexcept; - BloomFilterAlgorithm& operator=(const BloomFilterAlgorithm&) noexcept; - BloomFilterAlgorithm() noexcept; - - virtual ~BloomFilterAlgorithm() noexcept; - /** - * Block-based Bloom filter. * - */ - SplitBlockAlgorithm BLOCK; - - _BloomFilterAlgorithm__isset __isset; - - void __set_BLOCK(const SplitBlockAlgorithm& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(BloomFilterAlgorithm &a, BloomFilterAlgorithm &b); - -std::ostream& operator<<(std::ostream& out, const BloomFilterAlgorithm& obj); - - -/** - * Hash strategy type annotation. xxHash is an extremely fast non-cryptographic hash - * algorithm. It uses 64 bits version of xxHash. - * - */ -class XxHash : public virtual ::apache::thrift::TBase { - public: - - XxHash(const XxHash&) noexcept; - XxHash& operator=(const XxHash&) noexcept; - XxHash() noexcept; - - virtual ~XxHash() noexcept; - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(XxHash &a, XxHash &b); - -std::ostream& operator<<(std::ostream& out, const XxHash& obj); - -typedef struct _BloomFilterHash__isset { - _BloomFilterHash__isset() : XXHASH(false) {} - bool XXHASH :1; -} _BloomFilterHash__isset; - -/** - * The hash function used in Bloom filter. This function takes the hash of a column value - * using plain encoding. - * - */ -class BloomFilterHash : public virtual ::apache::thrift::TBase { - public: - - BloomFilterHash(const BloomFilterHash&) noexcept; - BloomFilterHash& operator=(const BloomFilterHash&) noexcept; - BloomFilterHash() noexcept; - - virtual ~BloomFilterHash() noexcept; - /** - * xxHash Strategy. * - */ - XxHash XXHASH; - - _BloomFilterHash__isset __isset; - - void __set_XXHASH(const XxHash& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(BloomFilterHash &a, BloomFilterHash &b); - -std::ostream& operator<<(std::ostream& out, const BloomFilterHash& obj); - - -/** - * The compression used in the Bloom filter. - * - */ -class Uncompressed : public virtual ::apache::thrift::TBase { - public: - - Uncompressed(const Uncompressed&) noexcept; - Uncompressed& operator=(const Uncompressed&) noexcept; - Uncompressed() noexcept; - - virtual ~Uncompressed() noexcept; - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(Uncompressed &a, Uncompressed &b); - -std::ostream& operator<<(std::ostream& out, const Uncompressed& obj); - -typedef struct _BloomFilterCompression__isset { - _BloomFilterCompression__isset() : UNCOMPRESSED(false) {} - bool UNCOMPRESSED :1; -} _BloomFilterCompression__isset; - -class BloomFilterCompression : public virtual ::apache::thrift::TBase { - public: - - BloomFilterCompression(const BloomFilterCompression&) noexcept; - BloomFilterCompression& operator=(const BloomFilterCompression&) noexcept; - BloomFilterCompression() noexcept; - - virtual ~BloomFilterCompression() noexcept; - Uncompressed UNCOMPRESSED; - - _BloomFilterCompression__isset __isset; - - void __set_UNCOMPRESSED(const Uncompressed& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(BloomFilterCompression &a, BloomFilterCompression &b); - -std::ostream& operator<<(std::ostream& out, const BloomFilterCompression& obj); - - -/** - * Bloom filter header is stored at beginning of Bloom filter data of each column - * and followed by its bitset. - * - */ -class BloomFilterHeader : public virtual ::apache::thrift::TBase { - public: - - BloomFilterHeader(const BloomFilterHeader&) noexcept; - BloomFilterHeader& operator=(const BloomFilterHeader&) noexcept; - BloomFilterHeader() noexcept; - - virtual ~BloomFilterHeader() noexcept; - /** - * The size of bitset in bytes * - */ - int32_t numBytes; - /** - * The algorithm for setting bits. * - */ - BloomFilterAlgorithm algorithm; - /** - * The hash function used for Bloom filter. * - */ - BloomFilterHash hash; - /** - * The compression used in the Bloom filter * - */ - BloomFilterCompression compression; - - void __set_numBytes(const int32_t val); - - void __set_algorithm(const BloomFilterAlgorithm& val); - - void __set_hash(const BloomFilterHash& val); - - void __set_compression(const BloomFilterCompression& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; - - virtual void printTo(std::ostream& out) const; -}; - -void swap(BloomFilterHeader &a, BloomFilterHeader &b); - -std::ostream& operator<<(std::ostream& out, const BloomFilterHeader& obj); - typedef struct _PageHeader__isset { _PageHeader__isset() : crc(false), data_page_header(false), index_page_header(false), dictionary_page_header(false), data_page_header_v2(false) {} bool crc :1; @@ -1762,46 +1391,18 @@ typedef struct _PageHeader__isset { bool data_page_header_v2 :1; } _PageHeader__isset; -class PageHeader : public virtual ::apache::thrift::TBase { +class PageHeader : public virtual ::duckdb_apache::thrift::TBase { public: PageHeader(const PageHeader&); PageHeader& operator=(const PageHeader&); - PageHeader() noexcept; - - virtual ~PageHeader() noexcept; - /** - * the type of the page: indicates which of the *_header fields is set * - * - * @see PageType - */ + PageHeader() : type((PageType::type)0), uncompressed_page_size(0), compressed_page_size(0), crc(0) { + } + + virtual ~PageHeader() throw(); PageType::type type; - /** - * Uncompressed page size in bytes (not including this header) * - */ int32_t uncompressed_page_size; - /** - * Compressed (and potentially encrypted) page size in bytes, not including this header * - */ int32_t compressed_page_size; - /** - * The 32-bit CRC checksum for the page, to be be calculated as follows: - * - * - The standard CRC32 algorithm is used (with polynomial 0x04C11DB7, - * the same as in e.g. GZip). - * - All page types can have a CRC (v1 and v2 data pages, dictionary pages, - * etc.). - * - The CRC is computed on the serialization binary representation of the page - * (as written to disk), excluding the page header. For example, for v1 - * data pages, the CRC is computed on the concatenation of repetition levels, - * definition levels and column values (optionally compressed, optionally - * encrypted). - * - The CRC computation therefore takes place after any compression - * and encryption steps, if any. - * - * If enabled, this allows for disabling checksumming in HDFS if only a few - * pages need to be read. - */ int32_t crc; DataPageHeader data_page_header; IndexPageHeader index_page_header; @@ -1826,8 +1427,44 @@ class PageHeader : public virtual ::apache::thrift::TBase { void __set_data_page_header_v2(const DataPageHeaderV2& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const PageHeader & rhs) const + { + if (!(type == rhs.type)) + return false; + if (!(uncompressed_page_size == rhs.uncompressed_page_size)) + return false; + if (!(compressed_page_size == rhs.compressed_page_size)) + return false; + if (__isset.crc != rhs.__isset.crc) + return false; + else if (__isset.crc && !(crc == rhs.crc)) + return false; + if (__isset.data_page_header != rhs.__isset.data_page_header) + return false; + else if (__isset.data_page_header && !(data_page_header == rhs.data_page_header)) + return false; + if (__isset.index_page_header != rhs.__isset.index_page_header) + return false; + else if (__isset.index_page_header && !(index_page_header == rhs.index_page_header)) + return false; + if (__isset.dictionary_page_header != rhs.__isset.dictionary_page_header) + return false; + else if (__isset.dictionary_page_header && !(dictionary_page_header == rhs.dictionary_page_header)) + return false; + if (__isset.data_page_header_v2 != rhs.__isset.data_page_header_v2) + return false; + else if (__isset.data_page_header_v2 && !(data_page_header_v2 == rhs.data_page_header_v2)) + return false; + return true; + } + bool operator != (const PageHeader &rhs) const { + return !(*this == rhs); + } + + bool operator < (const PageHeader & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1841,17 +1478,15 @@ typedef struct _KeyValue__isset { bool value :1; } _KeyValue__isset; -/** - * Wrapper struct to store key values - */ -class KeyValue : public virtual ::apache::thrift::TBase { +class KeyValue : public virtual ::duckdb_apache::thrift::TBase { public: KeyValue(const KeyValue&); KeyValue& operator=(const KeyValue&); - KeyValue() noexcept; + KeyValue() : key(), value() { + } - virtual ~KeyValue() noexcept; + virtual ~KeyValue() throw(); std::string key; std::string value; @@ -1861,8 +1496,24 @@ class KeyValue : public virtual ::apache::thrift::TBase { void __set_value(const std::string& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const KeyValue & rhs) const + { + if (!(key == rhs.key)) + return false; + if (__isset.value != rhs.__isset.value) + return false; + else if (__isset.value && !(value == rhs.value)) + return false; + return true; + } + bool operator != (const KeyValue &rhs) const { + return !(*this == rhs); + } + + bool operator < (const KeyValue & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1872,29 +1523,17 @@ void swap(KeyValue &a, KeyValue &b); std::ostream& operator<<(std::ostream& out, const KeyValue& obj); -/** - * Sort order within a RowGroup of a leaf column - */ -class SortingColumn : public virtual ::apache::thrift::TBase { +class SortingColumn : public virtual ::duckdb_apache::thrift::TBase { public: - SortingColumn(const SortingColumn&) noexcept; - SortingColumn& operator=(const SortingColumn&) noexcept; - SortingColumn() noexcept; + SortingColumn(const SortingColumn&); + SortingColumn& operator=(const SortingColumn&); + SortingColumn() : column_idx(0), descending(0), nulls_first(0) { + } - virtual ~SortingColumn() noexcept; - /** - * The ordinal position of the column (in this row group) * - */ + virtual ~SortingColumn() throw(); int32_t column_idx; - /** - * If true, indicates this column is sorted in descending order. * - */ bool descending; - /** - * If true, nulls will come before non-null values, otherwise, - * nulls go at the end. - */ bool nulls_first; void __set_column_idx(const int32_t val); @@ -1903,8 +1542,24 @@ class SortingColumn : public virtual ::apache::thrift::TBase { void __set_nulls_first(const bool val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const SortingColumn & rhs) const + { + if (!(column_idx == rhs.column_idx)) + return false; + if (!(descending == rhs.descending)) + return false; + if (!(nulls_first == rhs.nulls_first)) + return false; + return true; + } + bool operator != (const SortingColumn &rhs) const { + return !(*this == rhs); + } + + bool operator < (const SortingColumn & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1914,32 +1569,17 @@ void swap(SortingColumn &a, SortingColumn &b); std::ostream& operator<<(std::ostream& out, const SortingColumn& obj); -/** - * statistics of a given page type and encoding - */ -class PageEncodingStats : public virtual ::apache::thrift::TBase { +class PageEncodingStats : public virtual ::duckdb_apache::thrift::TBase { public: - PageEncodingStats(const PageEncodingStats&) noexcept; - PageEncodingStats& operator=(const PageEncodingStats&) noexcept; - PageEncodingStats() noexcept; + PageEncodingStats(const PageEncodingStats&); + PageEncodingStats& operator=(const PageEncodingStats&); + PageEncodingStats() : page_type((PageType::type)0), encoding((Encoding::type)0), count(0) { + } - virtual ~PageEncodingStats() noexcept; - /** - * the page type (data/dic/...) * - * - * @see PageType - */ + virtual ~PageEncodingStats() throw(); PageType::type page_type; - /** - * encoding of the page * - * - * @see Encoding - */ Encoding::type encoding; - /** - * number of pages of this type with this encoding * - */ int32_t count; void __set_page_type(const PageType::type val); @@ -1948,8 +1588,24 @@ class PageEncodingStats : public virtual ::apache::thrift::TBase { void __set_count(const int32_t val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const PageEncodingStats & rhs) const + { + if (!(page_type == rhs.page_type)) + return false; + if (!(encoding == rhs.encoding)) + return false; + if (!(count == rhs.count)) + return false; + return true; + } + bool operator != (const PageEncodingStats &rhs) const { + return !(*this == rhs); + } + + bool operator < (const PageEncodingStats & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -1959,107 +1615,36 @@ void swap(PageEncodingStats &a, PageEncodingStats &b); std::ostream& operator<<(std::ostream& out, const PageEncodingStats& obj); typedef struct _ColumnMetaData__isset { - _ColumnMetaData__isset() : key_value_metadata(false), index_page_offset(false), dictionary_page_offset(false), statistics(false), encoding_stats(false), bloom_filter_offset(false), bloom_filter_length(false), size_statistics(false) {} + _ColumnMetaData__isset() : key_value_metadata(false), index_page_offset(false), dictionary_page_offset(false), statistics(false), encoding_stats(false) {} bool key_value_metadata :1; bool index_page_offset :1; bool dictionary_page_offset :1; bool statistics :1; bool encoding_stats :1; - bool bloom_filter_offset :1; - bool bloom_filter_length :1; - bool size_statistics :1; } _ColumnMetaData__isset; -/** - * Description for column metadata - */ -class ColumnMetaData : public virtual ::apache::thrift::TBase { +class ColumnMetaData : public virtual ::duckdb_apache::thrift::TBase { public: ColumnMetaData(const ColumnMetaData&); ColumnMetaData& operator=(const ColumnMetaData&); - ColumnMetaData() noexcept; - - virtual ~ColumnMetaData() noexcept; - /** - * Type of this column * - * - * @see Type - */ + ColumnMetaData() : type((Type::type)0), codec((CompressionCodec::type)0), num_values(0), total_uncompressed_size(0), total_compressed_size(0), data_page_offset(0), index_page_offset(0), dictionary_page_offset(0) { + } + + virtual ~ColumnMetaData() throw(); Type::type type; - /** - * Set of all encodings used for this column. The purpose is to validate - * whether we can decode those pages. * - */ duckdb::vector encodings; - /** - * Path in schema * - */ duckdb::vector path_in_schema; - /** - * Compression codec * - * - * @see CompressionCodec - */ CompressionCodec::type codec; - /** - * Number of values in this column * - */ int64_t num_values; - /** - * total byte size of all uncompressed pages in this column chunk (including the headers) * - */ int64_t total_uncompressed_size; - /** - * total byte size of all compressed, and potentially encrypted, pages - * in this column chunk (including the headers) * - */ int64_t total_compressed_size; - /** - * Optional key/value metadata * - */ duckdb::vector key_value_metadata; - /** - * Byte offset from beginning of file to first data page * - */ int64_t data_page_offset; - /** - * Byte offset from beginning of file to root index page * - */ int64_t index_page_offset; - /** - * Byte offset from the beginning of file to first (only) dictionary page * - */ int64_t dictionary_page_offset; - /** - * optional statistics for this column chunk - */ Statistics statistics; - /** - * Set of all encodings used for pages in this column chunk. - * This information can be used to determine if all data pages are - * dictionary encoded for example * - */ duckdb::vector encoding_stats; - /** - * Byte offset from beginning of file to Bloom filter data. * - */ - int64_t bloom_filter_offset; - /** - * Size of Bloom filter data including the serialized header, in bytes. - * Added in 2.10 so readers may not read this field from old files and - * it can be obtained after the BloomFilterHeader has been deserialized. - * Writers should write this field so readers can read the bloom filter - * in a single I/O. - */ - int32_t bloom_filter_length; - /** - * Optional statistics to help estimate total memory when converted to in-memory - * representations. The histograms contained in these statistics can - * also be useful in some cases for more fine-grained nullability/list length - * filter pushdown. - */ - SizeStatistics size_statistics; _ColumnMetaData__isset __isset; @@ -2089,14 +1674,54 @@ class ColumnMetaData : public virtual ::apache::thrift::TBase { void __set_encoding_stats(const duckdb::vector & val); - void __set_bloom_filter_offset(const int64_t val); - - void __set_bloom_filter_length(const int32_t val); - - void __set_size_statistics(const SizeStatistics& val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const ColumnMetaData & rhs) const + { + if (!(type == rhs.type)) + return false; + if (!(encodings == rhs.encodings)) + return false; + if (!(path_in_schema == rhs.path_in_schema)) + return false; + if (!(codec == rhs.codec)) + return false; + if (!(num_values == rhs.num_values)) + return false; + if (!(total_uncompressed_size == rhs.total_uncompressed_size)) + return false; + if (!(total_compressed_size == rhs.total_compressed_size)) + return false; + if (__isset.key_value_metadata != rhs.__isset.key_value_metadata) + return false; + else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata)) + return false; + if (!(data_page_offset == rhs.data_page_offset)) + return false; + if (__isset.index_page_offset != rhs.__isset.index_page_offset) + return false; + else if (__isset.index_page_offset && !(index_page_offset == rhs.index_page_offset)) + return false; + if (__isset.dictionary_page_offset != rhs.__isset.dictionary_page_offset) + return false; + else if (__isset.dictionary_page_offset && !(dictionary_page_offset == rhs.dictionary_page_offset)) + return false; + if (__isset.statistics != rhs.__isset.statistics) + return false; + else if (__isset.statistics && !(statistics == rhs.statistics)) + return false; + if (__isset.encoding_stats != rhs.__isset.encoding_stats) + return false; + else if (__isset.encoding_stats && !(encoding_stats == rhs.encoding_stats)) + return false; + return true; + } + bool operator != (const ColumnMetaData &rhs) const { + return !(*this == rhs); + } + + bool operator < (const ColumnMetaData & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2106,17 +1731,28 @@ void swap(ColumnMetaData &a, ColumnMetaData &b); std::ostream& operator<<(std::ostream& out, const ColumnMetaData& obj); -class EncryptionWithFooterKey : public virtual ::apache::thrift::TBase { +class EncryptionWithFooterKey : public virtual ::duckdb_apache::thrift::TBase { public: - EncryptionWithFooterKey(const EncryptionWithFooterKey&) noexcept; - EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&) noexcept; - EncryptionWithFooterKey() noexcept; + EncryptionWithFooterKey(const EncryptionWithFooterKey&); + EncryptionWithFooterKey& operator=(const EncryptionWithFooterKey&); + EncryptionWithFooterKey() { + } + + virtual ~EncryptionWithFooterKey() throw(); - virtual ~EncryptionWithFooterKey() noexcept; + bool operator == (const EncryptionWithFooterKey & /* rhs */) const + { + return true; + } + bool operator != (const EncryptionWithFooterKey &rhs) const { + return !(*this == rhs); + } - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator < (const EncryptionWithFooterKey & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2130,21 +1766,16 @@ typedef struct _EncryptionWithColumnKey__isset { bool key_metadata :1; } _EncryptionWithColumnKey__isset; -class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase { +class EncryptionWithColumnKey : public virtual ::duckdb_apache::thrift::TBase { public: EncryptionWithColumnKey(const EncryptionWithColumnKey&); EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&); - EncryptionWithColumnKey() noexcept; + EncryptionWithColumnKey() : key_metadata() { + } - virtual ~EncryptionWithColumnKey() noexcept; - /** - * Column path in schema * - */ + virtual ~EncryptionWithColumnKey() throw(); duckdb::vector path_in_schema; - /** - * Retrieval metadata of column encryption key * - */ std::string key_metadata; _EncryptionWithColumnKey__isset __isset; @@ -2153,8 +1784,24 @@ class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase { void __set_key_metadata(const std::string& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const EncryptionWithColumnKey & rhs) const + { + if (!(path_in_schema == rhs.path_in_schema)) + return false; + if (__isset.key_metadata != rhs.__isset.key_metadata) + return false; + else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata)) + return false; + return true; + } + bool operator != (const EncryptionWithColumnKey &rhs) const { + return !(*this == rhs); + } + + bool operator < (const EncryptionWithColumnKey & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2169,14 +1816,15 @@ typedef struct _ColumnCryptoMetaData__isset { bool ENCRYPTION_WITH_COLUMN_KEY :1; } _ColumnCryptoMetaData__isset; -class ColumnCryptoMetaData : public virtual ::apache::thrift::TBase { +class ColumnCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { public: ColumnCryptoMetaData(const ColumnCryptoMetaData&); ColumnCryptoMetaData& operator=(const ColumnCryptoMetaData&); - ColumnCryptoMetaData() noexcept; + ColumnCryptoMetaData() { + } - virtual ~ColumnCryptoMetaData() noexcept; + virtual ~ColumnCryptoMetaData() throw(); EncryptionWithFooterKey ENCRYPTION_WITH_FOOTER_KEY; EncryptionWithColumnKey ENCRYPTION_WITH_COLUMN_KEY; @@ -2186,8 +1834,26 @@ class ColumnCryptoMetaData : public virtual ::apache::thrift::TBase { void __set_ENCRYPTION_WITH_COLUMN_KEY(const EncryptionWithColumnKey& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const ColumnCryptoMetaData & rhs) const + { + if (__isset.ENCRYPTION_WITH_FOOTER_KEY != rhs.__isset.ENCRYPTION_WITH_FOOTER_KEY) + return false; + else if (__isset.ENCRYPTION_WITH_FOOTER_KEY && !(ENCRYPTION_WITH_FOOTER_KEY == rhs.ENCRYPTION_WITH_FOOTER_KEY)) + return false; + if (__isset.ENCRYPTION_WITH_COLUMN_KEY != rhs.__isset.ENCRYPTION_WITH_COLUMN_KEY) + return false; + else if (__isset.ENCRYPTION_WITH_COLUMN_KEY && !(ENCRYPTION_WITH_COLUMN_KEY == rhs.ENCRYPTION_WITH_COLUMN_KEY)) + return false; + return true; + } + bool operator != (const ColumnCryptoMetaData &rhs) const { + return !(*this == rhs); + } + + bool operator < (const ColumnCryptoMetaData & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2208,62 +1874,23 @@ typedef struct _ColumnChunk__isset { bool encrypted_column_metadata :1; } _ColumnChunk__isset; -class ColumnChunk : public virtual ::apache::thrift::TBase { +class ColumnChunk : public virtual ::duckdb_apache::thrift::TBase { public: ColumnChunk(const ColumnChunk&); ColumnChunk& operator=(const ColumnChunk&); - ColumnChunk() noexcept; - - virtual ~ColumnChunk() noexcept; - /** - * File where column data is stored. If not set, assumed to be same file as - * metadata. This path is relative to the current file. - * - */ + ColumnChunk() : file_path(), file_offset(0), offset_index_offset(0), offset_index_length(0), column_index_offset(0), column_index_length(0), encrypted_column_metadata() { + } + + virtual ~ColumnChunk() throw(); std::string file_path; - /** - * Deprecated: Byte offset in file_path to the ColumnMetaData - * - * Past use of this field has been inconsistent, with some implementations - * using it to point to the ColumnMetaData and some using it to point to - * the first page in the column chunk. In many cases, the ColumnMetaData at this - * location is wrong. This field is now deprecated and should not be used. - * Writers should set this field to 0 if no ColumnMetaData has been written outside - * the footer. - */ int64_t file_offset; - /** - * Column metadata for this chunk. Some writers may also replicate this at the - * location pointed to by file_path/file_offset. - * Note: while marked as optional, this field is in fact required by most major - * Parquet implementations. As such, writers MUST populate this field. - * - */ ColumnMetaData meta_data; - /** - * File offset of ColumnChunk's OffsetIndex * - */ int64_t offset_index_offset; - /** - * Size of ColumnChunk's OffsetIndex, in bytes * - */ int32_t offset_index_length; - /** - * File offset of ColumnChunk's ColumnIndex * - */ int64_t column_index_offset; - /** - * Size of ColumnChunk's ColumnIndex, in bytes * - */ int32_t column_index_length; - /** - * Crypto metadata of encrypted columns * - */ ColumnCryptoMetaData crypto_metadata; - /** - * Encrypted column metadata for this chunk * - */ std::string encrypted_column_metadata; _ColumnChunk__isset __isset; @@ -2286,8 +1913,52 @@ class ColumnChunk : public virtual ::apache::thrift::TBase { void __set_encrypted_column_metadata(const std::string& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const ColumnChunk & rhs) const + { + if (__isset.file_path != rhs.__isset.file_path) + return false; + else if (__isset.file_path && !(file_path == rhs.file_path)) + return false; + if (!(file_offset == rhs.file_offset)) + return false; + if (__isset.meta_data != rhs.__isset.meta_data) + return false; + else if (__isset.meta_data && !(meta_data == rhs.meta_data)) + return false; + if (__isset.offset_index_offset != rhs.__isset.offset_index_offset) + return false; + else if (__isset.offset_index_offset && !(offset_index_offset == rhs.offset_index_offset)) + return false; + if (__isset.offset_index_length != rhs.__isset.offset_index_length) + return false; + else if (__isset.offset_index_length && !(offset_index_length == rhs.offset_index_length)) + return false; + if (__isset.column_index_offset != rhs.__isset.column_index_offset) + return false; + else if (__isset.column_index_offset && !(column_index_offset == rhs.column_index_offset)) + return false; + if (__isset.column_index_length != rhs.__isset.column_index_length) + return false; + else if (__isset.column_index_length && !(column_index_length == rhs.column_index_length)) + return false; + if (__isset.crypto_metadata != rhs.__isset.crypto_metadata) + return false; + else if (__isset.crypto_metadata && !(crypto_metadata == rhs.crypto_metadata)) + return false; + if (__isset.encrypted_column_metadata != rhs.__isset.encrypted_column_metadata) + return false; + else if (__isset.encrypted_column_metadata && !(encrypted_column_metadata == rhs.encrypted_column_metadata)) + return false; + return true; + } + bool operator != (const ColumnChunk &rhs) const { + return !(*this == rhs); + } + + bool operator < (const ColumnChunk & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2304,46 +1975,21 @@ typedef struct _RowGroup__isset { bool ordinal :1; } _RowGroup__isset; -class RowGroup : public virtual ::apache::thrift::TBase { +class RowGroup : public virtual ::duckdb_apache::thrift::TBase { public: RowGroup(const RowGroup&); RowGroup& operator=(const RowGroup&); - RowGroup() noexcept; - - virtual ~RowGroup() noexcept; - /** - * Metadata for each column chunk in this row group. - * This list must have the same order as the SchemaElement list in FileMetaData. - * - */ + RowGroup() : total_byte_size(0), num_rows(0), file_offset(0), total_compressed_size(0), ordinal(0) { + } + + virtual ~RowGroup() throw(); duckdb::vector columns; - /** - * Total byte size of all the uncompressed column data in this row group * - */ int64_t total_byte_size; - /** - * Number of rows in this row group * - */ int64_t num_rows; - /** - * If set, specifies a sort ordering of the rows in this RowGroup. - * The sorting columns can be a subset of all the columns. - */ duckdb::vector sorting_columns; - /** - * Byte offset from beginning of file to first page (data or dictionary) - * in this row group * - */ int64_t file_offset; - /** - * Total byte size of all compressed (and potentially encrypted) column data - * in this row group * - */ int64_t total_compressed_size; - /** - * Row group ordinal in the file * - */ int16_t ordinal; _RowGroup__isset __isset; @@ -2362,8 +2008,40 @@ class RowGroup : public virtual ::apache::thrift::TBase { void __set_ordinal(const int16_t val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const RowGroup & rhs) const + { + if (!(columns == rhs.columns)) + return false; + if (!(total_byte_size == rhs.total_byte_size)) + return false; + if (!(num_rows == rhs.num_rows)) + return false; + if (__isset.sorting_columns != rhs.__isset.sorting_columns) + return false; + else if (__isset.sorting_columns && !(sorting_columns == rhs.sorting_columns)) + return false; + if (__isset.file_offset != rhs.__isset.file_offset) + return false; + else if (__isset.file_offset && !(file_offset == rhs.file_offset)) + return false; + if (__isset.total_compressed_size != rhs.__isset.total_compressed_size) + return false; + else if (__isset.total_compressed_size && !(total_compressed_size == rhs.total_compressed_size)) + return false; + if (__isset.ordinal != rhs.__isset.ordinal) + return false; + else if (__isset.ordinal && !(ordinal == rhs.ordinal)) + return false; + return true; + } + bool operator != (const RowGroup &rhs) const { + return !(*this == rhs); + } + + bool operator < (const RowGroup & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2373,20 +2051,28 @@ void swap(RowGroup &a, RowGroup &b); std::ostream& operator<<(std::ostream& out, const RowGroup& obj); -/** - * Empty struct to signal the order defined by the physical or logical type - */ -class TypeDefinedOrder : public virtual ::apache::thrift::TBase { +class TypeDefinedOrder : public virtual ::duckdb_apache::thrift::TBase { public: - TypeDefinedOrder(const TypeDefinedOrder&) noexcept; - TypeDefinedOrder& operator=(const TypeDefinedOrder&) noexcept; - TypeDefinedOrder() noexcept; + TypeDefinedOrder(const TypeDefinedOrder&); + TypeDefinedOrder& operator=(const TypeDefinedOrder&); + TypeDefinedOrder() { + } + + virtual ~TypeDefinedOrder() throw(); - virtual ~TypeDefinedOrder() noexcept; + bool operator == (const TypeDefinedOrder & /* rhs */) const + { + return true; + } + bool operator != (const TypeDefinedOrder &rhs) const { + return !(*this == rhs); + } - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator < (const TypeDefinedOrder & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2400,84 +2086,37 @@ typedef struct _ColumnOrder__isset { bool TYPE_ORDER :1; } _ColumnOrder__isset; -/** - * Union to specify the order used for the min_value and max_value fields for a - * column. This union takes the role of an enhanced enum that allows rich - * elements (which will be needed for a collation-based ordering in the future). - * - * Possible values are: - * * TypeDefinedOrder - the column uses the order defined by its logical or - * physical type (if there is no logical type). - * - * If the reader does not support the value of this union, min and max stats - * for this column should be ignored. - */ -class ColumnOrder : public virtual ::apache::thrift::TBase { +class ColumnOrder : public virtual ::duckdb_apache::thrift::TBase { public: - ColumnOrder(const ColumnOrder&) noexcept; - ColumnOrder& operator=(const ColumnOrder&) noexcept; - ColumnOrder() noexcept; - - virtual ~ColumnOrder() noexcept; - /** - * The sort orders for logical types are: - * UTF8 - unsigned byte-wise comparison - * INT8 - signed comparison - * INT16 - signed comparison - * INT32 - signed comparison - * INT64 - signed comparison - * UINT8 - unsigned comparison - * UINT16 - unsigned comparison - * UINT32 - unsigned comparison - * UINT64 - unsigned comparison - * DECIMAL - signed comparison of the represented value - * DATE - signed comparison - * TIME_MILLIS - signed comparison - * TIME_MICROS - signed comparison - * TIMESTAMP_MILLIS - signed comparison - * TIMESTAMP_MICROS - signed comparison - * INTERVAL - undefined - * JSON - unsigned byte-wise comparison - * BSON - unsigned byte-wise comparison - * ENUM - unsigned byte-wise comparison - * LIST - undefined - * MAP - undefined - * - * In the absence of logical types, the sort order is determined by the physical type: - * BOOLEAN - false, true - * INT32 - signed comparison - * INT64 - signed comparison - * INT96 (only used for legacy timestamps) - undefined - * FLOAT - signed comparison of the represented value (*) - * DOUBLE - signed comparison of the represented value (*) - * BYTE_ARRAY - unsigned byte-wise comparison - * FIXED_LEN_BYTE_ARRAY - unsigned byte-wise comparison - * - * (*) Because the sorting order is not specified properly for floating - * point values (relations vs. total ordering) the following - * compatibility rules should be applied when reading statistics: - * - If the min is a NaN, it should be ignored. - * - If the max is a NaN, it should be ignored. - * - If the min is +0, the row group may contain -0 values as well. - * - If the max is -0, the row group may contain +0 values as well. - * - When looking for NaN values, min and max should be ignored. - * - * When writing statistics the following rules should be followed: - * - NaNs should not be written to min or max statistics fields. - * - If the computed max value is zero (whether negative or positive), - * `+0.0` should be written into the max statistics field. - * - If the computed min value is zero (whether negative or positive), - * `-0.0` should be written into the min statistics field. - */ + ColumnOrder(const ColumnOrder&); + ColumnOrder& operator=(const ColumnOrder&); + ColumnOrder() { + } + + virtual ~ColumnOrder() throw(); TypeDefinedOrder TYPE_ORDER; _ColumnOrder__isset __isset; void __set_TYPE_ORDER(const TypeDefinedOrder& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const ColumnOrder & rhs) const + { + if (__isset.TYPE_ORDER != rhs.__isset.TYPE_ORDER) + return false; + else if (__isset.TYPE_ORDER && !(TYPE_ORDER == rhs.TYPE_ORDER)) + return false; + return true; + } + bool operator != (const ColumnOrder &rhs) const { + return !(*this == rhs); + } + + bool operator < (const ColumnOrder & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2487,28 +2126,17 @@ void swap(ColumnOrder &a, ColumnOrder &b); std::ostream& operator<<(std::ostream& out, const ColumnOrder& obj); -class PageLocation : public virtual ::apache::thrift::TBase { +class PageLocation : public virtual ::duckdb_apache::thrift::TBase { public: - PageLocation(const PageLocation&) noexcept; - PageLocation& operator=(const PageLocation&) noexcept; - PageLocation() noexcept; + PageLocation(const PageLocation&); + PageLocation& operator=(const PageLocation&); + PageLocation() : offset(0), compressed_page_size(0), first_row_index(0) { + } - virtual ~PageLocation() noexcept; - /** - * Offset of the page in the file * - */ + virtual ~PageLocation() throw(); int64_t offset; - /** - * Size of the page, including header. Sum of compressed_page_size and header - * length - */ int32_t compressed_page_size; - /** - * Index within the RowGroup of the first row of the page. When an - * OffsetIndex is present, pages must begin on row boundaries - * (repetition_level = 0). - */ int64_t first_row_index; void __set_offset(const int64_t val); @@ -2517,8 +2145,24 @@ class PageLocation : public virtual ::apache::thrift::TBase { void __set_first_row_index(const int64_t val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const PageLocation & rhs) const + { + if (!(offset == rhs.offset)) + return false; + if (!(compressed_page_size == rhs.compressed_page_size)) + return false; + if (!(first_row_index == rhs.first_row_index)) + return false; + return true; + } + bool operator != (const PageLocation &rhs) const { + return !(*this == rhs); + } + + bool operator < (const PageLocation & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2527,47 +2171,34 @@ void swap(PageLocation &a, PageLocation &b); std::ostream& operator<<(std::ostream& out, const PageLocation& obj); -typedef struct _OffsetIndex__isset { - _OffsetIndex__isset() : unencoded_byte_array_data_bytes(false) {} - bool unencoded_byte_array_data_bytes :1; -} _OffsetIndex__isset; -/** - * Optional offsets for each data page in a ColumnChunk. - * - * Forms part of the page index, along with ColumnIndex. - * - * OffsetIndex may be present even if ColumnIndex is not. - */ -class OffsetIndex : public virtual ::apache::thrift::TBase { +class OffsetIndex : public virtual ::duckdb_apache::thrift::TBase { public: OffsetIndex(const OffsetIndex&); OffsetIndex& operator=(const OffsetIndex&); - OffsetIndex() noexcept; + OffsetIndex() { + } - virtual ~OffsetIndex() noexcept; - /** - * PageLocations, ordered by increasing PageLocation.offset. It is required - * that page_locations[i].first_row_index < page_locations[i+1].first_row_index. - */ + virtual ~OffsetIndex() throw(); duckdb::vector page_locations; - /** - * Unencoded/uncompressed size for BYTE_ARRAY types. - * - * See documention for unencoded_byte_array_data_bytes in SizeStatistics for - * more details on this field. - */ - duckdb::vector unencoded_byte_array_data_bytes; - - _OffsetIndex__isset __isset; void __set_page_locations(const duckdb::vector & val); - void __set_unencoded_byte_array_data_bytes(const duckdb::vector & val); + bool operator == (const OffsetIndex & rhs) const + { + if (!(page_locations == rhs.page_locations)) + return false; + return true; + } + bool operator != (const OffsetIndex &rhs) const { + return !(*this == rhs); + } + + bool operator < (const OffsetIndex & ) const; - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2577,89 +2208,24 @@ void swap(OffsetIndex &a, OffsetIndex &b); std::ostream& operator<<(std::ostream& out, const OffsetIndex& obj); typedef struct _ColumnIndex__isset { - _ColumnIndex__isset() : null_counts(false), repetition_level_histograms(false), definition_level_histograms(false) {} + _ColumnIndex__isset() : null_counts(false) {} bool null_counts :1; - bool repetition_level_histograms :1; - bool definition_level_histograms :1; } _ColumnIndex__isset; -/** - * Optional statistics for each data page in a ColumnChunk. - * - * Forms part the page index, along with OffsetIndex. - * - * If this structure is present, OffsetIndex must also be present. - * - * For each field in this structure, [i] refers to the page at - * OffsetIndex.page_locations[i] - */ -class ColumnIndex : public virtual ::apache::thrift::TBase { +class ColumnIndex : public virtual ::duckdb_apache::thrift::TBase { public: ColumnIndex(const ColumnIndex&); ColumnIndex& operator=(const ColumnIndex&); - ColumnIndex() noexcept; - - virtual ~ColumnIndex() noexcept; - /** - * A list of Boolean values to determine the validity of the corresponding - * min and max values. If true, a page contains only null values, and writers - * have to set the corresponding entries in min_values and max_values to - * byte[0], so that all lists have the same length. If false, the - * corresponding entries in min_values and max_values must be valid. - */ + ColumnIndex() : boundary_order((BoundaryOrder::type)0) { + } + + virtual ~ColumnIndex() throw(); duckdb::vector null_pages; - /** - * Two lists containing lower and upper bounds for the values of each page - * determined by the ColumnOrder of the column. These may be the actual - * minimum and maximum values found on a page, but can also be (more compact) - * values that do not exist on a page. For example, instead of storing ""Blart - * Versenwald III", a writer may set min_values[i]="B", max_values[i]="C". - * Such more compact values must still be valid values within the column's - * logical type. Readers must make sure that list entries are populated before - * using them by inspecting null_pages. - */ duckdb::vector min_values; duckdb::vector max_values; - /** - * Stores whether both min_values and max_values are ordered and if so, in - * which direction. This allows readers to perform binary searches in both - * lists. Readers cannot assume that max_values[i] <= min_values[i+1], even - * if the lists are ordered. - * - * @see BoundaryOrder - */ BoundaryOrder::type boundary_order; - /** - * A list containing the number of null values for each page - * - * Writers SHOULD always write this field even if no null values - * are present or the column is not nullable. - * Readers MUST distinguish between null_counts not being present - * and null_count being 0. - * If null_counts are not present, readers MUST NOT assume all - * null counts are 0. - */ duckdb::vector null_counts; - /** - * Contains repetition level histograms for each page - * concatenated together. The repetition_level_histogram field on - * SizeStatistics contains more details. - * - * When present the length should always be (number of pages * - * (max_repetition_level + 1)) elements. - * - * Element 0 is the first element of the histogram for the first page. - * Element (max_repetition_level + 1) is the first element of the histogram - * for the second page. - * - */ - duckdb::vector repetition_level_histograms; - /** - * Same as repetition_level_histograms except for definitions levels. - * - */ - duckdb::vector definition_level_histograms; _ColumnIndex__isset __isset; @@ -2673,12 +2239,30 @@ class ColumnIndex : public virtual ::apache::thrift::TBase { void __set_null_counts(const duckdb::vector & val); - void __set_repetition_level_histograms(const duckdb::vector & val); - - void __set_definition_level_histograms(const duckdb::vector & val); - - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const ColumnIndex & rhs) const + { + if (!(null_pages == rhs.null_pages)) + return false; + if (!(min_values == rhs.min_values)) + return false; + if (!(max_values == rhs.max_values)) + return false; + if (!(boundary_order == rhs.boundary_order)) + return false; + if (__isset.null_counts != rhs.__isset.null_counts) + return false; + else if (__isset.null_counts && !(null_counts == rhs.null_counts)) + return false; + return true; + } + bool operator != (const ColumnIndex &rhs) const { + return !(*this == rhs); + } + + bool operator < (const ColumnIndex & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2694,26 +2278,17 @@ typedef struct _AesGcmV1__isset { bool supply_aad_prefix :1; } _AesGcmV1__isset; -class AesGcmV1 : public virtual ::apache::thrift::TBase { +class AesGcmV1 : public virtual ::duckdb_apache::thrift::TBase { public: AesGcmV1(const AesGcmV1&); AesGcmV1& operator=(const AesGcmV1&); - AesGcmV1() noexcept; + AesGcmV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) { + } - virtual ~AesGcmV1() noexcept; - /** - * AAD prefix * - */ + virtual ~AesGcmV1() throw(); std::string aad_prefix; - /** - * Unique file identifier part of AAD suffix * - */ std::string aad_file_unique; - /** - * In files encrypted with AAD prefix without storing it, - * readers must supply the prefix * - */ bool supply_aad_prefix; _AesGcmV1__isset __isset; @@ -2724,8 +2299,30 @@ class AesGcmV1 : public virtual ::apache::thrift::TBase { void __set_supply_aad_prefix(const bool val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const AesGcmV1 & rhs) const + { + if (__isset.aad_prefix != rhs.__isset.aad_prefix) + return false; + else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix)) + return false; + if (__isset.aad_file_unique != rhs.__isset.aad_file_unique) + return false; + else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique)) + return false; + if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix) + return false; + else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix)) + return false; + return true; + } + bool operator != (const AesGcmV1 &rhs) const { + return !(*this == rhs); + } + + bool operator < (const AesGcmV1 & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2741,26 +2338,17 @@ typedef struct _AesGcmCtrV1__isset { bool supply_aad_prefix :1; } _AesGcmCtrV1__isset; -class AesGcmCtrV1 : public virtual ::apache::thrift::TBase { +class AesGcmCtrV1 : public virtual ::duckdb_apache::thrift::TBase { public: AesGcmCtrV1(const AesGcmCtrV1&); AesGcmCtrV1& operator=(const AesGcmCtrV1&); - AesGcmCtrV1() noexcept; + AesGcmCtrV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) { + } - virtual ~AesGcmCtrV1() noexcept; - /** - * AAD prefix * - */ + virtual ~AesGcmCtrV1() throw(); std::string aad_prefix; - /** - * Unique file identifier part of AAD suffix * - */ std::string aad_file_unique; - /** - * In files encrypted with AAD prefix without storing it, - * readers must supply the prefix * - */ bool supply_aad_prefix; _AesGcmCtrV1__isset __isset; @@ -2771,8 +2359,30 @@ class AesGcmCtrV1 : public virtual ::apache::thrift::TBase { void __set_supply_aad_prefix(const bool val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const AesGcmCtrV1 & rhs) const + { + if (__isset.aad_prefix != rhs.__isset.aad_prefix) + return false; + else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix)) + return false; + if (__isset.aad_file_unique != rhs.__isset.aad_file_unique) + return false; + else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique)) + return false; + if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix) + return false; + else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix)) + return false; + return true; + } + bool operator != (const AesGcmCtrV1 &rhs) const { + return !(*this == rhs); + } + + bool operator < (const AesGcmCtrV1 & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2787,14 +2397,15 @@ typedef struct _EncryptionAlgorithm__isset { bool AES_GCM_CTR_V1 :1; } _EncryptionAlgorithm__isset; -class EncryptionAlgorithm : public virtual ::apache::thrift::TBase { +class EncryptionAlgorithm : public virtual ::duckdb_apache::thrift::TBase { public: EncryptionAlgorithm(const EncryptionAlgorithm&); EncryptionAlgorithm& operator=(const EncryptionAlgorithm&); - EncryptionAlgorithm() noexcept; + EncryptionAlgorithm() { + } - virtual ~EncryptionAlgorithm() noexcept; + virtual ~EncryptionAlgorithm() throw(); AesGcmV1 AES_GCM_V1; AesGcmCtrV1 AES_GCM_CTR_V1; @@ -2804,8 +2415,26 @@ class EncryptionAlgorithm : public virtual ::apache::thrift::TBase { void __set_AES_GCM_CTR_V1(const AesGcmCtrV1& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const EncryptionAlgorithm & rhs) const + { + if (__isset.AES_GCM_V1 != rhs.__isset.AES_GCM_V1) + return false; + else if (__isset.AES_GCM_V1 && !(AES_GCM_V1 == rhs.AES_GCM_V1)) + return false; + if (__isset.AES_GCM_CTR_V1 != rhs.__isset.AES_GCM_CTR_V1) + return false; + else if (__isset.AES_GCM_CTR_V1 && !(AES_GCM_CTR_V1 == rhs.AES_GCM_CTR_V1)) + return false; + return true; + } + bool operator != (const EncryptionAlgorithm &rhs) const { + return !(*this == rhs); + } + + bool operator < (const EncryptionAlgorithm & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2823,76 +2452,23 @@ typedef struct _FileMetaData__isset { bool footer_signing_key_metadata :1; } _FileMetaData__isset; -/** - * Description for file metadata - */ -class FileMetaData : public virtual ::apache::thrift::TBase { +class FileMetaData : public virtual ::duckdb_apache::thrift::TBase { public: FileMetaData(const FileMetaData&); FileMetaData& operator=(const FileMetaData&); - FileMetaData() noexcept; + FileMetaData() : version(0), num_rows(0), created_by(), footer_signing_key_metadata() { + } - virtual ~FileMetaData() noexcept; - /** - * Version of this file * - */ + virtual ~FileMetaData() throw(); int32_t version; - /** - * Parquet schema for this file. This schema contains metadata for all the columns. - * The schema is represented as a tree with a single root. The nodes of the tree - * are flattened to a list by doing a depth-first traversal. - * The column metadata contains the path in the schema for that column which can be - * used to map columns to nodes in the schema. - * The first element is the root * - */ duckdb::vector schema; - /** - * Number of rows in this file * - */ int64_t num_rows; - /** - * Row groups in this file * - */ duckdb::vector row_groups; - /** - * Optional key/value metadata * - */ duckdb::vector key_value_metadata; - /** - * String for application that wrote this file. This should be in the format - * version (build ). - * e.g. impala version 1.0 (build 6cf94d29b2b7115df4de2c06e2ab4326d721eb55) - * - */ std::string created_by; - /** - * Sort order used for the min_value and max_value fields in the Statistics - * objects and the min_values and max_values fields in the ColumnIndex - * objects of each column in this file. Sort orders are listed in the order - * matching the columns in the schema. The indexes are not necessary the same - * though, because only leaf nodes of the schema are represented in the list - * of sort orders. - * - * Without column_orders, the meaning of the min_value and max_value fields - * in the Statistics object and the ColumnIndex object is undefined. To ensure - * well-defined behaviour, if these fields are written to a Parquet file, - * column_orders must be written as well. - * - * The obsolete min and max fields in the Statistics object are always sorted - * by signed comparison regardless of column_orders. - */ duckdb::vector column_orders; - /** - * Encryption algorithm. This field is set only in encrypted files - * with plaintext footer. Files with encrypted footer store algorithm id - * in FileCryptoMetaData structure. - */ EncryptionAlgorithm encryption_algorithm; - /** - * Retrieval metadata of key used for signing the footer. - * Used only in encrypted files with plaintext footer. - */ std::string footer_signing_key_metadata; _FileMetaData__isset __isset; @@ -2915,8 +2491,46 @@ class FileMetaData : public virtual ::apache::thrift::TBase { void __set_footer_signing_key_metadata(const std::string& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const FileMetaData & rhs) const + { + if (!(version == rhs.version)) + return false; + if (!(schema == rhs.schema)) + return false; + if (!(num_rows == rhs.num_rows)) + return false; + if (!(row_groups == rhs.row_groups)) + return false; + if (__isset.key_value_metadata != rhs.__isset.key_value_metadata) + return false; + else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata)) + return false; + if (__isset.created_by != rhs.__isset.created_by) + return false; + else if (__isset.created_by && !(created_by == rhs.created_by)) + return false; + if (__isset.column_orders != rhs.__isset.column_orders) + return false; + else if (__isset.column_orders && !(column_orders == rhs.column_orders)) + return false; + if (__isset.encryption_algorithm != rhs.__isset.encryption_algorithm) + return false; + else if (__isset.encryption_algorithm && !(encryption_algorithm == rhs.encryption_algorithm)) + return false; + if (__isset.footer_signing_key_metadata != rhs.__isset.footer_signing_key_metadata) + return false; + else if (__isset.footer_signing_key_metadata && !(footer_signing_key_metadata == rhs.footer_signing_key_metadata)) + return false; + return true; + } + bool operator != (const FileMetaData &rhs) const { + return !(*this == rhs); + } + + bool operator < (const FileMetaData & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2930,27 +2544,16 @@ typedef struct _FileCryptoMetaData__isset { bool key_metadata :1; } _FileCryptoMetaData__isset; -/** - * Crypto metadata for files with encrypted footer * - */ -class FileCryptoMetaData : public virtual ::apache::thrift::TBase { +class FileCryptoMetaData : public virtual ::duckdb_apache::thrift::TBase { public: FileCryptoMetaData(const FileCryptoMetaData&); FileCryptoMetaData& operator=(const FileCryptoMetaData&); - FileCryptoMetaData() noexcept; - - virtual ~FileCryptoMetaData() noexcept; - /** - * Encryption algorithm. This field is only used for files - * with encrypted footer. Files with plaintext footer store algorithm id - * inside footer (FileMetaData structure). - */ + FileCryptoMetaData() : key_metadata() { + } + + virtual ~FileCryptoMetaData() throw(); EncryptionAlgorithm encryption_algorithm; - /** - * Retrieval metadata of key used for encryption of footer, - * and (possibly) columns * - */ std::string key_metadata; _FileCryptoMetaData__isset __isset; @@ -2959,8 +2562,24 @@ class FileCryptoMetaData : public virtual ::apache::thrift::TBase { void __set_key_metadata(const std::string& val); - uint32_t read(::apache::thrift::protocol::TProtocol* iprot) override; - uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const override; + bool operator == (const FileCryptoMetaData & rhs) const + { + if (!(encryption_algorithm == rhs.encryption_algorithm)) + return false; + if (__isset.key_metadata != rhs.__isset.key_metadata) + return false; + else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata)) + return false; + return true; + } + bool operator != (const FileCryptoMetaData &rhs) const { + return !(*this == rhs); + } + + bool operator < (const FileCryptoMetaData & ) const; + + uint32_t read(::duckdb_apache::thrift::protocol::TProtocol* iprot); + uint32_t write(::duckdb_apache::thrift::protocol::TProtocol* oprot) const; virtual void printTo(std::ostream& out) const; }; @@ -2969,6 +2588,6 @@ void swap(FileCryptoMetaData &a, FileCryptoMetaData &b); std::ostream& operator<<(std::ostream& out, const FileCryptoMetaData& obj); -} // namespace +}} // namespace #endif diff --git a/src/duckdb/third_party/skiplist/SkipList.h b/src/duckdb/third_party/skiplist/SkipList.h index 5b015acc3..5cf27c204 100644 --- a/src/duckdb/third_party/skiplist/SkipList.h +++ b/src/duckdb/third_party/skiplist/SkipList.h @@ -446,6 +446,7 @@ #include #include // Used for HeadNode::_lacksIntegrityNodeReferencesNotInList() #include // Used for class Exception +#include #include "pcg_random.hpp" #ifdef DEBUG diff --git a/src/duckdb/third_party/snappy/snappy-stubs-internal.h b/src/duckdb/third_party/snappy/snappy-stubs-internal.h index d2426a74c..6b06b6ba1 100644 --- a/src/duckdb/third_party/snappy/snappy-stubs-internal.h +++ b/src/duckdb/third_party/snappy/snappy-stubs-internal.h @@ -31,19 +31,6 @@ #ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ #define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_ -// DuckDB - LNK: define here instead of in CMake -#ifdef __GNUC__ -#define HAVE_BUILTIN_EXPECT 1 -#define HAVE_BUILTIN_CTZ 1 -#define HAVE_BUILTIN_PREFETCH 1 -#endif - -// These should always be available on aarch64, but sadly not on iOS/Android -// #if defined(__aarch64__) -// #define SNAPPY_HAVE_NEON 1 -// #define SNAPPY_HAVE_NEON_CRC32 1 -// #endif - #include "snappy_version.hpp" #if SNAPPY_NEW_VERSION @@ -60,6 +47,14 @@ #include #include +// DuckDB - LNK: define here instead of in CMake +#ifdef __GNUC__ +#define HAVE_BUILTIN_EXPECT 1 +#define HAVE_BUILTIN_CTZ 1 +#define HAVE_BUILTIN_PREFETCH 1 +#endif + + #if HAVE_SYS_MMAN_H #include #endif @@ -557,6 +552,13 @@ inline char* string_as_array(std::string* str) { #include #include +// DuckDB - LNK: define here instead of in CMake +#ifdef __GNUC__ +#define HAVE_BUILTIN_EXPECT +#define HAVE_BUILTIN_CTZ +#define HAVE_BUILTIN_PREFETCH +#endif + #ifdef HAVE_SYS_MMAN_H #include #endif diff --git a/src/duckdb/third_party/zstd/common/debug.cpp b/src/duckdb/third_party/zstd/common/debug.cpp deleted file mode 100644 index 01010e4eb..000000000 --- a/src/duckdb/third_party/zstd/common/debug.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* ****************************************************************** - * debug - * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * You can contact the author at : - * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. -****************************************************************** */ - - -/* - * This module only hosts one global variable - * which can be used to dynamically influence the verbosity of traces, - * such as DEBUGLOG and RAWLOG - */ - -#include "zstd/common/debug.h" - -#if !defined(ZSTD_LINUX_KERNEL) || (DEBUGLEVEL>=2) - -namespace duckdb_zstd { - -/* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a - * translation unit is empty. So remove this from Linux kernel builds, but - * otherwise just leave it in. - */ -int g_debuglevel = DEBUGLEVEL; - -} // namespace duckdb_zstd - -#endif diff --git a/src/duckdb/third_party/zstd/common/entropy_common.cpp b/src/duckdb/third_party/zstd/common/entropy_common.cpp index 9a33c2dfc..bd41d220a 100644 --- a/src/duckdb/third_party/zstd/common/entropy_common.cpp +++ b/src/duckdb/third_party/zstd/common/entropy_common.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * Common functions of New Generation Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -17,10 +17,10 @@ ***************************************/ #include "zstd/common/mem.h" #include "zstd/common/error_private.h" /* ERR_*, ERROR */ -#define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/bits.h" /* ZSDT_highbit32, ZSTD_countTrailingZeros32 */ +#include "zstd/common/huf_static.h" namespace duckdb_zstd { @@ -39,9 +39,8 @@ const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); } /*-************************************************************** * FSE NCount encoding-decoding ****************************************************************/ -FORCE_INLINE_TEMPLATE -size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) +size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, + const void* headerBuffer, size_t hbSize) { const BYTE* const istart = (const BYTE*) headerBuffer; const BYTE* const iend = istart + hbSize; @@ -52,23 +51,23 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne U32 bitStream; int bitCount; unsigned charnum = 0; - unsigned const maxSV1 = *maxSVPtr + 1; int previous0 = 0; - if (hbSize < 8) { - /* This function only works when hbSize >= 8 */ - char buffer[8] = {0}; - ZSTD_memcpy(buffer, headerBuffer, hbSize); + if (hbSize < 4) { + /* This function only works when hbSize >= 4 */ + char buffer[4]; + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, headerBuffer, hbSize); { size_t const countSize = FSE_readNCount(normalizedCounter, maxSVPtr, tableLogPtr, buffer, sizeof(buffer)); if (FSE_isError(countSize)) return countSize; if (countSize > hbSize) return ERROR(corruption_detected); return countSize; } } - assert(hbSize >= 8); + assert(hbSize >= 4); /* init */ - ZSTD_memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ + memset(normalizedCounter, 0, (*maxSVPtr+1) * sizeof(normalizedCounter[0])); /* all symbols not present in NCount have a frequency of 0 */ bitStream = MEM_readLE32(ip); nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */ if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); @@ -79,58 +78,36 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne threshold = 1<1) & (charnum<=*maxSVPtr)) { if (previous0) { - /* Count the number of repeats. Each time the - * 2-bit repeat code is 0b11 there is another - * repeat. - * Avoid UB by setting the high bit to 1. - */ - int repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; - while (repeats >= 12) { - charnum += 3 * 12; - if (LIKELY(ip <= iend-7)) { - ip += 3; + unsigned n0 = charnum; + while ((bitStream & 0xFFFF) == 0xFFFF) { + n0 += 24; + if (ip < iend-5) { + ip += 2; + bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitCount -= (int)(8 * (iend - 7 - ip)); - bitCount &= 31; - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> bitCount; - repeats = ZSTD_countTrailingZeros32(~bitStream | 0x80000000) >> 1; + bitStream >>= 16; + bitCount += 16; + } } + while ((bitStream & 3) == 3) { + n0 += 3; + bitStream >>= 2; + bitCount += 2; } - charnum += 3 * repeats; - bitStream >>= 2 * repeats; - bitCount += 2 * repeats; - - /* Add the final repeat which isn't 0b11. */ - assert((bitStream & 3) < 3); - charnum += bitStream & 3; + n0 += bitStream & 3; bitCount += 2; - - /* This is an error, but break and return an error - * at the end, because returning out of a loop makes - * it harder for the compiler to optimize. - */ - if (charnum >= maxSV1) break; - - /* We don't need to set the normalized count to 0 - * because we already memset the whole buffer to 0. - */ - - if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); + while (charnum < n0) normalizedCounter[charnum++] = 0; + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { assert((bitCount >> 3) <= 3); /* For first condition to work */ ip += bitCount>>3; bitCount &= 7; + bitStream = MEM_readLE32(ip) >> bitCount; } else { - bitCount -= (int)(8 * (iend - 4 - ip)); - bitCount &= 31; - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> bitCount; - } - { - int const max = (2*threshold-1) - remaining; + bitStream >>= 2; + } } + { int const max = (2*threshold-1) - remaining; int count; if ((bitStream & (threshold-1)) < (U32)max) { @@ -143,43 +120,24 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne } count--; /* extra accuracy */ - /* When it matters (small blocks), this is a - * predictable branch, because we don't use -1. - */ - if (count >= 0) { - remaining -= count; - } else { - assert(count == -1); - remaining += count; - } + remaining -= count < 0 ? -count : count; /* -1 means +1 */ normalizedCounter[charnum++] = (short)count; previous0 = !count; - - assert(threshold > 1); - if (remaining < threshold) { - /* This branch can be folded into the - * threshold update condition because we - * know that threshold > 1. - */ - if (remaining <= 1) break; - nbBits = ZSTD_highbit32(remaining) + 1; - threshold = 1 << (nbBits - 1); + while (remaining < threshold) { + nbBits--; + threshold >>= 1; } - if (charnum >= maxSV1) break; - if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { ip += bitCount>>3; bitCount &= 7; } else { bitCount -= (int)(8 * (iend - 4 - ip)); - bitCount &= 31; ip = iend - 4; } - bitStream = MEM_readLE32(ip) >> bitCount; - } } + bitStream = MEM_readLE32(ip) >> (bitCount & 31); + } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */ if (remaining != 1) return ERROR(corruption_detected); - /* Only possible when there are too many zeros. */ - if (charnum > maxSV1) return ERROR(maxSymbolValue_tooSmall); if (bitCount > 32) return ERROR(corruption_detected); *maxSVPtr = charnum-1; @@ -187,43 +145,6 @@ size_t FSE_readNCount_body(short* normalizedCounter, unsigned* maxSVPtr, unsigne return ip-istart; } -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t FSE_readNCount_body_default( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} - -#if DYNAMIC_BMI2 -BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} -#endif - -size_t FSE_readNCount_bmi2( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize, int bmi2) -{ -#if DYNAMIC_BMI2 - if (bmi2) { - return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); - } -#endif - (void)bmi2; - return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); -} - -size_t FSE_readNCount( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize) -{ - return FSE_readNCount_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize, /* bmi2 */ 0); -} - /*! HUF_readStats() : Read compact Huffman tree, saved by HUF_writeCTable(). @@ -235,17 +156,6 @@ size_t FSE_readNCount( size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, const void* src, size_t srcSize) -{ - U32 wksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; - return HUF_readStats_wksp(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, wksp, sizeof(wksp), /* flags */ 0); -} - -FORCE_INLINE_TEMPLATE size_t -HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, - int bmi2) { U32 weightTotal; const BYTE* ip = (const BYTE*) src; @@ -254,7 +164,7 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (!srcSize) return ERROR(srcSize_wrong); iSize = ip[0]; - /* ZSTD_memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ oSize = iSize - 127; @@ -268,31 +178,31 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, huffWeight[n+1] = ip[n/2] & 15; } } } else { /* header compressed with FSE (normal case) */ + FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); - /* max (hwSize-1) values decoded, as last one is implied */ - oSize = FSE_decompress_wksp_bmi2(huffWeight, hwSize-1, ip+1, iSize, 6, workSpace, wkspSize, bmi2); + oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */ if (FSE_isError(oSize)) return oSize; } /* collect weight stats */ - ZSTD_memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); + memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32)); weightTotal = 0; { U32 n; for (n=0; n HUF_TABLELOG_MAX) return ERROR(corruption_detected); + if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; } } if (weightTotal == 0) return ERROR(corruption_detected); /* get last non-null symbol weight (implied, total must be 2^n) */ - { U32 const tableLog = ZSTD_highbit32(weightTotal) + 1; + { U32 const tableLog = BIT_highbit32(weightTotal) + 1; if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected); *tableLogPtr = tableLog; /* determine last weight */ { U32 const total = 1 << tableLog; U32 const rest = total - weightTotal; - U32 const verif = 1 << ZSTD_highbit32(rest); - U32 const lastWeight = ZSTD_highbit32(rest) + 1; + U32 const verif = 1 << BIT_highbit32(rest); + U32 const lastWeight = BIT_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; @@ -306,38 +216,4 @@ HUF_readStats_body(BYTE* huffWeight, size_t hwSize, U32* rankStats, return iSize+1; } -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t HUF_readStats_body_default(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize) -{ - return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 0); -} - -#if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize) -{ - return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); -} -#endif - -size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, - U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, - int flags) -{ -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); - } -#endif - (void)flags; - return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); } - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/error_private.cpp b/src/duckdb/third_party/zstd/common/error_private.cpp index c3ba4728b..207ef006d 100644 --- a/src/duckdb/third_party/zstd/common/error_private.cpp +++ b/src/duckdb/third_party/zstd/common/error_private.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -29,11 +29,9 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(version_unsupported): return "Version not supported"; case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; - case PREFIX(corruption_detected): return "Data corruption detected"; + case PREFIX(corruption_detected): return "Corrupted block detected"; case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; - case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; case PREFIX(parameter_unsupported): return "Unsupported parameter"; - case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; case PREFIX(init_missing): return "Context should be init first"; case PREFIX(memory_allocation): return "Allocation error : not enough memory"; @@ -42,26 +40,20 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; - case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(dictionary_wrong): return "Dictionary mismatch"; case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; case PREFIX(srcSize_wrong): return "Src size is incorrect"; case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; - case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; - case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; /* following error codes are not stable and may be removed or changed in a future version */ case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; - case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; - case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; - case PREFIX(externalSequences_invalid): return "External sequences are not valid"; case PREFIX(maxCode): default: return notErrorCode; } #endif } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/common/fse_decompress.cpp b/src/duckdb/third_party/zstd/common/fse_decompress.cpp index 9b6957409..8845948e0 100644 --- a/src/duckdb/third_party/zstd/common/fse_decompress.cpp +++ b/src/duckdb/third_party/zstd/common/fse_decompress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * FSE : Finite State Entropy decoder - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -16,21 +16,19 @@ /* ************************************************************** * Includes ****************************************************************/ -#include "zstd/common/debug.h" /* assert */ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ #include "zstd/common/bitstream.h" #include "zstd/common/compiler.h" -#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/error_private.h" -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy */ -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ -namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -#define FSE_isError ERR_isError +// #define FSE_isError ERR_isError #define FSE_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ @@ -56,19 +54,31 @@ namespace duckdb_zstd { #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) -static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize) +namespace duckdb_zstd { + +/* Function templates */ +FSE_DTable* FSE_createDTable (unsigned tableLog) +{ + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) ); +} + +void FSE_freeDTable (FSE_DTable* dt) +{ + free(dt); +} + +size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) { void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */ FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); - U16* symbolNext = (U16*)workSpace; - BYTE* spread = (BYTE*)(symbolNext + maxSymbolValue + 1); + U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; U32 highThreshold = tableSize-1; /* Sanity Checks */ - if (FSE_BUILD_DTABLE_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(maxSymbolValue_tooLarge); if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); @@ -84,57 +94,13 @@ static size_t FSE_buildDTable_internal(FSE_DTable* dt, const short* normalizedCo symbolNext[s] = 1; } else { if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0; - symbolNext[s] = (U16)normalizedCounter[s]; + symbolNext[s] = normalizedCounter[s]; } } } - ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - if (highThreshold == tableSize - 1) { - size_t const tableMask = tableSize-1; - size_t const step = FSE_TABLESTEP(tableSize); - /* First lay down the symbols in order. - * We use a uint64_t to lay down 8 bytes at a time. This reduces branch - * misses since small blocks generally have small table logs, so nearly - * all symbols have counts <= 8. We ensure we have 8 bytes at the end of - * our buffer to handle the over-write. - */ - { U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; stableLog = 0; + DTableH->fastMode = 0; + + cell->newState = 0; + cell->symbol = symbolValue; + cell->nbBits = 0; + + return 0; +} + + +size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSV1 = tableMask+1; + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* Build Decoding Table */ + DTableH->tableLog = (U16)nbBits; + DTableH->fastMode = 1; + for (s=0; s= ostart); - return (size_t)(op-ostart); + return op-ostart; } -typedef struct { - short ncount[FSE_MAX_SYMBOL_VALUE + 1]; -} FSE_DecompressWksp; + +size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize, + const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; + const U32 fastMode = DTableH->fastMode; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); + return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); +} -FORCE_INLINE_TEMPLATE size_t FSE_decompress_wksp_body( - void* dst, size_t dstCapacity, - const void* cSrc, size_t cSrcSize, - unsigned maxLog, void* workSpace, size_t wkspSize, - int bmi2) +size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog) { const BYTE* const istart = (const BYTE*)cSrc; const BYTE* ip = istart; + short counting[FSE_MAX_SYMBOL_VALUE+1]; unsigned tableLog; unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; - FSE_DecompressWksp* const wksp = (FSE_DecompressWksp*)workSpace; - size_t const dtablePos = sizeof(FSE_DecompressWksp) / sizeof(FSE_DTable); - FSE_DTable* const dtable = (FSE_DTable*)workSpace + dtablePos; - - FSE_STATIC_ASSERT((FSE_MAX_SYMBOL_VALUE + 1) % 2 == 0); - if (wkspSize < sizeof(*wksp)) return ERROR(GENERIC); - - /* correct offset to dtable depends on this property */ - FSE_STATIC_ASSERT(sizeof(FSE_DecompressWksp) % sizeof(FSE_DTable) == 0); /* normal FSE decoding mode */ - { size_t const NCountLength = - FSE_readNCount_bmi2(wksp->ncount, &maxSymbolValue, &tableLog, istart, cSrcSize, bmi2); - if (FSE_isError(NCountLength)) return NCountLength; - if (tableLog > maxLog) return ERROR(tableLog_tooLarge); - assert(NCountLength <= cSrcSize); - ip += NCountLength; - cSrcSize -= NCountLength; - } + size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); + if (FSE_isError(NCountLength)) return NCountLength; + /* if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); */ /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */ + if (tableLog > maxLog) return ERROR(tableLog_tooLarge); + ip += NCountLength; + cSrcSize -= NCountLength; - if (FSE_DECOMPRESS_WKSP_SIZE(tableLog, maxSymbolValue) > wkspSize) return ERROR(tableLog_tooLarge); - assert(sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog) <= wkspSize); - workSpace = (BYTE*)workSpace + sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); - wkspSize -= sizeof(*wksp) + FSE_DTABLE_SIZE(tableLog); + CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) ); - CHECK_F( FSE_buildDTable_internal(dtable, wksp->ncount, maxSymbolValue, tableLog, workSpace, wkspSize) ); + return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */ +} - { - const void* ptr = dtable; - const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; - /* select fast mode (static) */ - if (fastMode) return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 1); - return FSE_decompress_usingDTable_generic(dst, dstCapacity, ip, cSrcSize, dtable, 0); - } -} +typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; -/* Avoids the FORCE_INLINE of the _body() function. */ -static size_t FSE_decompress_wksp_body_default(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) +size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize) { - return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 0); + DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ + return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG); } -#if DYNAMIC_BMI2 -BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize) -{ - return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); -} -#endif - -size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) -{ -#if DYNAMIC_BMI2 - if (bmi2) { - return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); - } -#endif - (void)bmi2; - return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); } #endif /* FSE_COMMONDEFS_ONLY */ - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/pool.cpp b/src/duckdb/third_party/zstd/common/pool.cpp deleted file mode 100644 index 79df927e6..000000000 --- a/src/duckdb/third_party/zstd/common/pool.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - -/* ====== Dependencies ======= */ -#include "zstd/common/allocations.h" /* ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd/common/zstd_deps.h" /* size_t */ -#include "zstd/common/debug.h" /* assert */ -#include "zstd/common/pool.h" - -/* ====== Compiler specifics ====== */ -#if defined(_MSC_VER) -# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ -#endif - - -#ifdef ZSTD_MULTITHREAD -#include "zstd/common/threading.h" /* pthread adaptation */ -#endif - -namespace duckdb_zstd { - -#ifdef ZSTD_MULTITHREAD - -/* A job is a function and an opaque argument */ -typedef struct POOL_job_s { - POOL_function function; - void *opaque; -} POOL_job; - -struct POOL_ctx_s { - ZSTD_customMem customMem; - /* Keep track of the threads */ - ZSTD_pthread_t* threads; - size_t threadCapacity; - size_t threadLimit; - - /* The queue is a circular buffer */ - POOL_job *queue; - size_t queueHead; - size_t queueTail; - size_t queueSize; - - /* The number of threads working on jobs */ - size_t numThreadsBusy; - /* Indicates if the queue is empty */ - int queueEmpty; - - /* The mutex protects the queue */ - ZSTD_pthread_mutex_t queueMutex; - /* Condition variable for pushers to wait on when the queue is full */ - ZSTD_pthread_cond_t queuePushCond; - /* Condition variables for poppers to wait on when the queue is empty */ - ZSTD_pthread_cond_t queuePopCond; - /* Indicates if the queue is shutting down */ - int shutdown; -}; - -/* POOL_thread() : - * Work thread for the thread pool. - * Waits for jobs and executes them. - * @returns : NULL on failure else non-null. - */ -static void* POOL_thread(void* opaque) { - POOL_ctx* const ctx = (POOL_ctx*)opaque; - if (!ctx) { return NULL; } - for (;;) { - /* Lock the mutex and wait for a non-empty queue or until shutdown */ - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - - while ( ctx->queueEmpty - || (ctx->numThreadsBusy >= ctx->threadLimit) ) { - if (ctx->shutdown) { - /* even if !queueEmpty, (possible if numThreadsBusy >= threadLimit), - * a few threads will be shutdown while !queueEmpty, - * but enough threads will remain active to finish the queue */ - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - return opaque; - } - ZSTD_pthread_cond_wait(&ctx->queuePopCond, &ctx->queueMutex); - } - /* Pop a job off the queue */ - { POOL_job const job = ctx->queue[ctx->queueHead]; - ctx->queueHead = (ctx->queueHead + 1) % ctx->queueSize; - ctx->numThreadsBusy++; - ctx->queueEmpty = (ctx->queueHead == ctx->queueTail); - /* Unlock the mutex, signal a pusher, and run the job */ - ZSTD_pthread_cond_signal(&ctx->queuePushCond); - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - - job.function(job.opaque); - - /* If the intended queue size was 0, signal after finishing job */ - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - ctx->numThreadsBusy--; - ZSTD_pthread_cond_signal(&ctx->queuePushCond); - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - } - } /* for (;;) */ - assert(0); /* Unreachable */ -} - -/* ZSTD_createThreadPool() : public access point */ -POOL_ctx* ZSTD_createThreadPool(size_t numThreads) { - return POOL_create (numThreads, 0); -} - -POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { - return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); -} - -POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, - ZSTD_customMem customMem) -{ - POOL_ctx* ctx; - /* Check parameters */ - if (!numThreads) { return NULL; } - /* Allocate the context and zero initialize */ - ctx = (POOL_ctx*)ZSTD_customCalloc(sizeof(POOL_ctx), customMem); - if (!ctx) { return NULL; } - /* Initialize the job queue. - * It needs one extra space since one space is wasted to differentiate - * empty and full queues. - */ - ctx->queueSize = queueSize + 1; - ctx->queue = (POOL_job*)ZSTD_customCalloc(ctx->queueSize * sizeof(POOL_job), customMem); - ctx->queueHead = 0; - ctx->queueTail = 0; - ctx->numThreadsBusy = 0; - ctx->queueEmpty = 1; - { - int error = 0; - error |= ZSTD_pthread_mutex_init(&ctx->queueMutex, NULL); - error |= ZSTD_pthread_cond_init(&ctx->queuePushCond, NULL); - error |= ZSTD_pthread_cond_init(&ctx->queuePopCond, NULL); - if (error) { POOL_free(ctx); return NULL; } - } - ctx->shutdown = 0; - /* Allocate space for the thread handles */ - ctx->threads = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), customMem); - ctx->threadCapacity = 0; - ctx->customMem = customMem; - /* Check for errors */ - if (!ctx->threads || !ctx->queue) { POOL_free(ctx); return NULL; } - /* Initialize the threads */ - { size_t i; - for (i = 0; i < numThreads; ++i) { - if (ZSTD_pthread_create(&ctx->threads[i], NULL, &POOL_thread, ctx)) { - ctx->threadCapacity = i; - POOL_free(ctx); - return NULL; - } } - ctx->threadCapacity = numThreads; - ctx->threadLimit = numThreads; - } - return ctx; -} - -/*! POOL_join() : - Shutdown the queue, wake any sleeping threads, and join all of the threads. -*/ -static void POOL_join(POOL_ctx* ctx) { - /* Shut down the queue */ - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - ctx->shutdown = 1; - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - /* Wake up sleeping threads */ - ZSTD_pthread_cond_broadcast(&ctx->queuePushCond); - ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); - /* Join all of the threads */ - { size_t i; - for (i = 0; i < ctx->threadCapacity; ++i) { - ZSTD_pthread_join(ctx->threads[i]); /* note : could fail */ - } } -} - -void POOL_free(POOL_ctx *ctx) { - if (!ctx) { return; } - POOL_join(ctx); - ZSTD_pthread_mutex_destroy(&ctx->queueMutex); - ZSTD_pthread_cond_destroy(&ctx->queuePushCond); - ZSTD_pthread_cond_destroy(&ctx->queuePopCond); - ZSTD_customFree(ctx->queue, ctx->customMem); - ZSTD_customFree(ctx->threads, ctx->customMem); - ZSTD_customFree(ctx, ctx->customMem); -} - -/*! POOL_joinJobs() : - * Waits for all queued jobs to finish executing. - */ -void POOL_joinJobs(POOL_ctx* ctx) { - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - while(!ctx->queueEmpty || ctx->numThreadsBusy > 0) { - ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); - } - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); -} - -void ZSTD_freeThreadPool (ZSTD_threadPool* pool) { - POOL_free (pool); -} - -size_t POOL_sizeof(const POOL_ctx* ctx) { - if (ctx==NULL) return 0; /* supports sizeof NULL */ - return sizeof(*ctx) - + ctx->queueSize * sizeof(POOL_job) - + ctx->threadCapacity * sizeof(ZSTD_pthread_t); -} - - -/* @return : 0 on success, 1 on error */ -static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads) -{ - if (numThreads <= ctx->threadCapacity) { - if (!numThreads) return 1; - ctx->threadLimit = numThreads; - return 0; - } - /* numThreads > threadCapacity */ - { ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem); - if (!threadPool) return 1; - /* replace existing thread pool */ - ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(ZSTD_pthread_t)); - ZSTD_customFree(ctx->threads, ctx->customMem); - ctx->threads = threadPool; - /* Initialize additional threads */ - { size_t threadId; - for (threadId = ctx->threadCapacity; threadId < numThreads; ++threadId) { - if (ZSTD_pthread_create(&threadPool[threadId], NULL, &POOL_thread, ctx)) { - ctx->threadCapacity = threadId; - return 1; - } } - } } - /* successfully expanded */ - ctx->threadCapacity = numThreads; - ctx->threadLimit = numThreads; - return 0; -} - -/* @return : 0 on success, 1 on error */ -int POOL_resize(POOL_ctx* ctx, size_t numThreads) -{ - int result; - if (ctx==NULL) return 1; - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - result = POOL_resize_internal(ctx, numThreads); - ZSTD_pthread_cond_broadcast(&ctx->queuePopCond); - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - return result; -} - -/** - * Returns 1 if the queue is full and 0 otherwise. - * - * When queueSize is 1 (pool was created with an intended queueSize of 0), - * then a queue is empty if there is a thread free _and_ no job is waiting. - */ -static int isQueueFull(POOL_ctx const* ctx) { - if (ctx->queueSize > 1) { - return ctx->queueHead == ((ctx->queueTail + 1) % ctx->queueSize); - } else { - return (ctx->numThreadsBusy == ctx->threadLimit) || - !ctx->queueEmpty; - } -} - - -static void -POOL_add_internal(POOL_ctx* ctx, POOL_function function, void *opaque) -{ - POOL_job job; - job.function = function; - job.opaque = opaque; - assert(ctx != NULL); - if (ctx->shutdown) return; - - ctx->queueEmpty = 0; - ctx->queue[ctx->queueTail] = job; - ctx->queueTail = (ctx->queueTail + 1) % ctx->queueSize; - ZSTD_pthread_cond_signal(&ctx->queuePopCond); -} - -void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) -{ - assert(ctx != NULL); - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - /* Wait until there is space in the queue for the new job */ - while (isQueueFull(ctx) && (!ctx->shutdown)) { - ZSTD_pthread_cond_wait(&ctx->queuePushCond, &ctx->queueMutex); - } - POOL_add_internal(ctx, function, opaque); - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); -} - - -int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) -{ - assert(ctx != NULL); - ZSTD_pthread_mutex_lock(&ctx->queueMutex); - if (isQueueFull(ctx)) { - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - return 0; - } - POOL_add_internal(ctx, function, opaque); - ZSTD_pthread_mutex_unlock(&ctx->queueMutex); - return 1; -} - -#else /* ZSTD_MULTITHREAD not defined */ - -/* ========================== */ -/* No multi-threading support */ -/* ========================== */ - - -/* We don't need any data, but if it is empty, malloc() might return NULL. */ -struct POOL_ctx_s { - int dummy; -}; -static POOL_ctx g_poolCtx; - -POOL_ctx* POOL_create(size_t numThreads, size_t queueSize) { - return POOL_create_advanced(numThreads, queueSize, ZSTD_defaultCMem); -} - -POOL_ctx* -POOL_create_advanced(size_t numThreads, size_t queueSize, ZSTD_customMem customMem) -{ - (void)numThreads; - (void)queueSize; - (void)customMem; - return &g_poolCtx; -} - -void POOL_free(POOL_ctx* ctx) { - assert(!ctx || ctx == &g_poolCtx); - (void)ctx; -} - -void POOL_joinJobs(POOL_ctx* ctx){ - assert(!ctx || ctx == &g_poolCtx); - (void)ctx; -} - -int POOL_resize(POOL_ctx* ctx, size_t numThreads) { - (void)ctx; (void)numThreads; - return 0; -} - -void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque) { - (void)ctx; - function(opaque); -} - -int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque) { - (void)ctx; - function(opaque); - return 1; -} - -size_t POOL_sizeof(const POOL_ctx* ctx) { - if (ctx==NULL) return 0; /* supports sizeof NULL */ - assert(ctx == &g_poolCtx); - return sizeof(*ctx); -} - -#endif /* ZSTD_MULTITHREAD */ - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/common/threading.cpp b/src/duckdb/third_party/zstd/common/threading.cpp deleted file mode 100644 index 5c63f0af0..000000000 --- a/src/duckdb/third_party/zstd/common/threading.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Copyright (c) 2016 Tino Reichardt - * All rights reserved. - * - * You can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/** - * This file will hold wrapper for systems, which do not support pthreads - */ - -#include "zstd/common/threading.h" - -namespace duckdb_zstd { - -/* create fake symbol to avoid empty translation unit warning */ -int g_ZSTD_threading_useless_symbol; - -} // namespace duckdb_zstd - -#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) - -/** - * Windows minimalist Pthread Wrapper - */ - - -/* === Dependencies === */ -#include -#include - -namespace duckdb_zstd { - -/* === Implementation === */ - -typedef struct { - void* (*start_routine)(void*); - void* arg; - int initialized; - ZSTD_pthread_cond_t initialized_cond; - ZSTD_pthread_mutex_t initialized_mutex; -} ZSTD_thread_params_t; - -static unsigned __stdcall worker(void *arg) -{ - void* (*start_routine)(void*); - void* thread_arg; - - /* Initialized thread_arg and start_routine and signal main thread that we don't need it - * to wait any longer. - */ - { - ZSTD_thread_params_t* thread_param = (ZSTD_thread_params_t*)arg; - thread_arg = thread_param->arg; - start_routine = thread_param->start_routine; - - /* Signal main thread that we are running and do not depend on its memory anymore */ - ZSTD_pthread_mutex_lock(&thread_param->initialized_mutex); - thread_param->initialized = 1; - ZSTD_pthread_cond_signal(&thread_param->initialized_cond); - ZSTD_pthread_mutex_unlock(&thread_param->initialized_mutex); - } - - start_routine(thread_arg); - - return 0; -} - -int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, - void* (*start_routine) (void*), void* arg) -{ - ZSTD_thread_params_t thread_param; - (void)unused; - - if (thread==NULL) return -1; - *thread = NULL; - - thread_param.start_routine = start_routine; - thread_param.arg = arg; - thread_param.initialized = 0; - - /* Setup thread initialization synchronization */ - if(ZSTD_pthread_cond_init(&thread_param.initialized_cond, NULL)) { - /* Should never happen on Windows */ - return -1; - } - if(ZSTD_pthread_mutex_init(&thread_param.initialized_mutex, NULL)) { - /* Should never happen on Windows */ - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); - return -1; - } - - /* Spawn thread */ - *thread = (HANDLE)_beginthreadex(NULL, 0, worker, &thread_param, 0, NULL); - if (*thread==NULL) { - ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); - return errno; - } - - /* Wait for thread to be initialized */ - ZSTD_pthread_mutex_lock(&thread_param.initialized_mutex); - while(!thread_param.initialized) { - ZSTD_pthread_cond_wait(&thread_param.initialized_cond, &thread_param.initialized_mutex); - } - ZSTD_pthread_mutex_unlock(&thread_param.initialized_mutex); - ZSTD_pthread_mutex_destroy(&thread_param.initialized_mutex); - ZSTD_pthread_cond_destroy(&thread_param.initialized_cond); - - return 0; -} - -int ZSTD_pthread_join(ZSTD_pthread_t thread) -{ - DWORD result; - - if (!thread) return 0; - - result = WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - switch (result) { - case WAIT_OBJECT_0: - return 0; - case WAIT_ABANDONED: - return EINVAL; - default: - return GetLastError(); - } -} - -} // namespace duckdb_zstd - -#endif /* ZSTD_MULTITHREAD */ - -#if defined(ZSTD_MULTITHREAD) && DEBUGLEVEL >= 1 && !defined(_WIN32) - -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd/common/zstd_deps.h" - -namespace duckdb_zstd { - -int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr) -{ - assert(mutex != NULL); - *mutex = (pthread_mutex_t*)ZSTD_malloc(sizeof(pthread_mutex_t)); - if (!*mutex) - return 1; - return pthread_mutex_init(*mutex, attr); -} - -int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex) -{ - assert(mutex != NULL); - if (!*mutex) - return 0; - { - int const ret = pthread_mutex_destroy(*mutex); - ZSTD_free(*mutex); - return ret; - } -} - -int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr) -{ - assert(cond != NULL); - *cond = (pthread_cond_t*)ZSTD_malloc(sizeof(pthread_cond_t)); - if (!*cond) - return 1; - return pthread_cond_init(*cond, attr); -} - -int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond) -{ - assert(cond != NULL); - if (!*cond) - return 0; - { - int const ret = pthread_cond_destroy(*cond); - ZSTD_free(*cond); - return ret; - } -} - -} // namespace duckdb_zstd - -#endif diff --git a/src/duckdb/third_party/zstd/common/xxhash.cpp b/src/duckdb/third_party/zstd/common/xxhash.cpp index fc4d18b2e..9ec937522 100644 --- a/src/duckdb/third_party/zstd/common/xxhash.cpp +++ b/src/duckdb/third_party/zstd/common/xxhash.cpp @@ -83,8 +83,8 @@ /* for memcpy() */ #include -#include "zstd/common/xxhash.hpp" -#include "zstd/common/xxhash_static.hpp" +#include "zstd/common/xxhash.h" +#include "zstd/common/xxhash_static.h" /* ************************************* * Compiler Specific Options @@ -103,8 +103,7 @@ # define FORCE_INLINE_ATTR #endif -// DuckDB: prefixed with XXHASH_ to avoid name conflicts -#define XXHASH_FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR /* ************************************* @@ -170,7 +169,6 @@ static U64 XXH_read64(const void* memPtr) #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ -} // namespace duckdb_zstd /* **************************************** * Compiler-specific Functions and Macros @@ -191,8 +189,6 @@ static U64 XXH_read64(const void* memPtr) # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) #endif -namespace duckdb_zstd { - #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong # define XXH_swap64 _byteswap_uint64 @@ -238,7 +234,7 @@ typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; -XXHASH_FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); @@ -246,7 +242,7 @@ XXHASH_FORCE_INLINE_TEMPLATE U32 XXH_readLE32_align(const void* ptr, XXH_endiane return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); } -XXHASH_FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) +FORCE_INLINE_TEMPLATE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); } @@ -256,7 +252,7 @@ static U32 XXH_readBE32(const void* ptr) return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } -XXHASH_FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) +FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); @@ -264,7 +260,7 @@ XXHASH_FORCE_INLINE_TEMPLATE U64 XXH_readLE64_align(const void* ptr, XXH_endiane return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); } -XXHASH_FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) +FORCE_INLINE_TEMPLATE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) { return XXH_readLE64_align(ptr, endian, XXH_unaligned); } @@ -325,7 +321,7 @@ static U32 XXH32_round(U32 seed, U32 input) return seed; } -XXHASH_FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) +FORCE_INLINE_TEMPLATE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* bEnd = p + len; @@ -425,7 +421,7 @@ static U64 XXH64_mergeRound(U64 acc, U64 val) return acc; } -XXHASH_FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) +FORCE_INLINE_TEMPLATE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -574,7 +570,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long } -XXHASH_FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) +FORCE_INLINE_TEMPLATE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -644,7 +640,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* -XXHASH_FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) +FORCE_INLINE_TEMPLATE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) { const BYTE * p = (const BYTE*)state->mem32; const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize; @@ -694,7 +690,7 @@ XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) /* **** XXH64 **** */ -XXHASH_FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) +FORCE_INLINE_TEMPLATE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; @@ -763,7 +759,7 @@ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* -XXHASH_FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) +FORCE_INLINE_TEMPLATE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) { const BYTE * p = (const BYTE*)state->mem64; const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize; @@ -860,4 +856,4 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src return XXH_readBE64(src); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/common/zstd_common.cpp b/src/duckdb/third_party/zstd/common/zstd_common.cpp index e36727c0a..d7700be3b 100644 --- a/src/duckdb/third_party/zstd/common/zstd_common.cpp +++ b/src/duckdb/third_party/zstd/common/zstd_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,7 +13,8 @@ /*-************************************* * Dependencies ***************************************/ -#define ZSTD_DEPS_NEED_MALLOC +#include /* malloc, calloc, free */ +#include /* memset */ #include "zstd/common/error_private.h" #include "zstd/common/zstd_internal.h" @@ -48,4 +49,38 @@ ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } * provides error code string from enum */ const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } -} // namespace duckdb_zstd + + +/*=************************************************************** +* Custom allocator +****************************************************************/ +void* ZSTD_malloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) + return customMem.customAlloc(customMem.opaque, size); + return malloc(size); +} + +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem) +{ + if (customMem.customAlloc) { + /* calloc implemented as malloc+memset; + * not as efficient as calloc, but next best guess for custom malloc */ + void* const ptr = customMem.customAlloc(customMem.opaque, size); + memset(ptr, 0, size); + return ptr; + } + return calloc(1, size); +} + +void ZSTD_free(void* ptr, ZSTD_customMem customMem) +{ + if (ptr!=NULL) { + if (customMem.customFree) + customMem.customFree(customMem.opaque, ptr); + else + free(ptr); + } +} + +} diff --git a/src/duckdb/third_party/zstd/compress/fse_compress.cpp b/src/duckdb/third_party/zstd/compress/fse_compress.cpp index 495377f9f..378e2925c 100644 --- a/src/duckdb/third_party/zstd/compress/fse_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/fse_compress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * FSE : Finite State Entropy encoder - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -15,25 +15,22 @@ /* ************************************************************** * Includes ****************************************************************/ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ #include "zstd/common/compiler.h" #include "zstd/common/mem.h" /* U32, U16, etc. */ #include "zstd/common/debug.h" /* assert, DEBUGLOG */ #include "zstd/compress/hist.h" /* HIST_count_wksp */ #include "zstd/common/bitstream.h" -#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/error_private.h" -#define ZSTD_DEPS_NEED_MALLOC -#define ZSTD_DEPS_NEED_MATH64 -#include "zstd/common/zstd_deps.h" /* ZSTD_memset */ -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ -namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -#define FSE_isError ERR_isError +// #define FSE_isError ERR_isError /* ************************************************************** @@ -58,6 +55,7 @@ namespace duckdb_zstd { #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) +namespace duckdb_zstd { /* Function templates */ @@ -77,85 +75,41 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ; FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); U32 const step = FSE_TABLESTEP(tableSize); - U32 const maxSV1 = maxSymbolValue+1; - - U16* cumul = (U16*)workSpace; /* size = maxSV1 */ - FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)(cumul + (maxSV1+1)); /* size = tableSize */ + U32 cumul[FSE_MAX_SYMBOL_VALUE+2]; + FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace; U32 highThreshold = tableSize-1; - assert(((size_t)workSpace & 1) == 0); /* Must be 2 bytes-aligned */ - if (FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) > wkspSize) return ERROR(tableLog_tooLarge); /* CTable header */ + if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge); tableU16[-2] = (U16) tableLog; tableU16[-1] = (U16) maxSymbolValue; assert(tableLog < 16); /* required for threshold strategy to work */ /* For explanations on how to distribute symbol values over the table : - * https://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ + * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */ #ifdef __clang_analyzer__ - ZSTD_memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ + memset(tableSymbol, 0, sizeof(*tableSymbol) * tableSize); /* useless initialization, just to keep scan-build happy */ #endif /* symbol start positions */ { U32 u; cumul[0] = 0; - for (u=1; u <= maxSV1; u++) { + for (u=1; u <= maxSymbolValue+1; u++) { if (normalizedCounter[u-1]==-1) { /* Low proba symbol */ cumul[u] = cumul[u-1] + 1; tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1); } else { - assert(normalizedCounter[u-1] >= 0); - cumul[u] = cumul[u-1] + (U16)normalizedCounter[u-1]; - assert(cumul[u] >= cumul[u-1]); /* no overflow */ + cumul[u] = cumul[u-1] + normalizedCounter[u-1]; } } - cumul[maxSV1] = (U16)(tableSize+1); + cumul[maxSymbolValue+1] = tableSize+1; } /* Spread symbols */ - if (highThreshold == tableSize - 1) { - /* Case for no low prob count symbols. Lay down 8 bytes at a time - * to reduce branch misses since we are operating on a small block - */ - BYTE* const spread = tableSymbol + tableSize; /* size = tableSize + 8 (may write beyond tableSize) */ - { U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; s=0); - pos += (size_t)n; - } - } - /* Spread symbols across the table. Lack of lowprob symbols means that - * we don't need variable sized inner loop, so we can unroll the loop and - * reduce branch misses. - */ - { size_t position = 0; - size_t s; - size_t const unroll = 2; /* Experimentally determined optimal unroll */ - assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ - for (s = 0; s < (size_t)tableSize; s += unroll) { - size_t u; - for (u = 0; u < unroll; ++u) { - size_t const uPosition = (position + (u * step)) & tableMask; - tableSymbol[uPosition] = spread[s + u]; - } - position = (position + (unroll * step)) & tableMask; - } - assert(position == 0); /* Must have initialized all positions */ - } - } else { - U32 position = 0; + { U32 position = 0; U32 symbol; - for (symbol=0; symbol highThreshold) position = (position + step) & tableMask; /* Low proba area */ } } + assert(position==0); /* Must have initialized all positions */ } @@ -187,17 +142,16 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, case -1: case 1: symbolTT[s].deltaNbBits = (tableLog << 16) - (1< 1); - { U32 const maxBitsOut = tableLog - ZSTD_highbit32 ((U32)normalizedCounter[s]-1); - U32 const minStatePlus = (U32)normalizedCounter[s] << maxBitsOut; + { + U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1); + U32 const minStatePlus = normalizedCounter[s] << maxBitsOut; symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus; - symbolTT[s].deltaFindState = (int)(total - (unsigned)normalizedCounter[s]); - total += (unsigned)normalizedCounter[s]; + symbolTT[s].deltaFindState = total - normalizedCounter[s]; + total += normalizedCounter[s]; } } } } #if 0 /* debug : symbol costs */ @@ -208,26 +162,31 @@ size_t FSE_buildCTable_wksp(FSE_CTable* ct, symbol, normalizedCounter[symbol], FSE_getMaxNbBits(symbolTT, symbol), (double)FSE_bitCost(symbolTT, tableLog, symbol, 8) / 256); - } } + } + } #endif return 0; } +size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) +{ + FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */ + return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol)); +} + + #ifndef FSE_COMMONDEFS_ONLY + /*-************************************************************** * FSE NCount encoding ****************************************************************/ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) { - size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog - + 4 /* bitCount initialized at 4 */ - + 2 /* first two symbols may use one additional bit each */) / 8) - + 1 /* round up to whole nb bytes */ - + 2 /* additional two bytes for bitstream flush */; + size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3; return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ } @@ -256,7 +215,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, /* Init */ remaining = tableSize+1; /* +1 for extra accuracy */ threshold = tableSize; - nbBits = (int)tableLog+1; + nbBits = tableLog+1; while ((symbol < alphabetSize) && (remaining>1)) { /* stops at 1 */ if (previousIs0) { @@ -275,7 +234,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, } while (symbol >= start+3) { start+=3; - bitStream += 3U << bitCount; + bitStream += 3 << bitCount; bitCount += 2; } bitStream += (symbol-start) << bitCount; @@ -295,7 +254,7 @@ FSE_writeNCount_generic (void* header, size_t headerBufferSize, count++; /* +1 for extra accuracy */ if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */ - bitStream += (U32)count << bitCount; + bitStream += count << bitCount; bitCount += nbBits; bitCount -= (count>8); out+= (bitCount+7) /8; - assert(out >= ostart); - return (size_t)(out-ostart); + return (out-ostart); } @@ -345,11 +303,21 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize, * FSE Compression Code ****************************************************************/ +FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog) +{ + size_t size; + if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX; + size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32); + return (FSE_CTable*)malloc(size); +} + +void FSE_freeCTable (FSE_CTable* ct) { free(ct); } + /* provides the minimum logSize to safely represent a distribution */ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) { - U32 minBitsSrc = ZSTD_highbit32((U32)(srcSize)) + 1; - U32 minBitsSymbols = ZSTD_highbit32(maxSymbolValue) + 2; + U32 minBitsSrc = BIT_highbit32((U32)(srcSize)) + 1; + U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2; U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols; assert(srcSize > 1); /* Not supported, RLE should be used instead */ return minBits; @@ -357,7 +325,7 @@ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus) { - U32 maxBitsSrc = ZSTD_highbit32((U32)(srcSize - 1)) - minus; + U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus; U32 tableLog = maxTableLog; U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue); assert(srcSize > 1); /* Not supported, RLE should be used instead */ @@ -374,10 +342,11 @@ unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxS return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2); } + /* Secondary normalization method. To be used when primary method fails. */ -static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue, short lowProbCount) +static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue) { short const NOT_YET_ASSIGNED = -2; U32 s; @@ -394,7 +363,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, continue; } if (count[s] <= lowThreshold) { - norm[s] = lowProbCount; + norm[s] = -1; distributed++; total -= count[s]; continue; @@ -446,7 +415,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, { U64 const vStepLog = 62 - tableLog; U64 const mid = (1ULL << (vStepLog-1)) - 1; - U64 const rStep = ZSTD_div64((((U64)1<> scale); @@ -502,7 +471,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, } } if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) { /* corner case, need another normalization method */ - size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue, lowProbCount); + size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue); if (FSE_isError(errorCode)) return errorCode; } else normalizedCounter[largest] += (short)stillToDistribute; @@ -525,6 +494,40 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, return tableLog; } + +/* fake FSE_CTable, for raw (uncompressed) input */ +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) +{ + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSymbolValue = tableMask; + void* const ptr = ct; + U16* const tableU16 = ( (U16*) ptr) + 2; + void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */ + FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT); + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* header */ + tableU16[-2] = (U16) nbBits; + tableU16[-1] = (U16) maxSymbolValue; + + /* Build table */ + for (s=0; s not compressible */ + if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */ + } + + tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue); + CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) ); -} // namespace duckdb_zstd + /* Write table description header */ + { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); + op += nc_err; + } + + /* Compress */ + CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) ); + if (cSize == 0) return 0; /* not enough space for compressed data */ + op += cSize; + } + + /* check compressibility */ + if ( (size_t)(op-ostart) >= srcSize-1 ) return 0; + + return op-ostart; +} + +typedef struct { + FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)]; + BYTE scratchBuffer[1 << FSE_MAX_TABLELOG]; +} fseWkspMax_t; + +size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog) +{ + fseWkspMax_t scratchBuffer; + DEBUG_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */ + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer)); +} + +size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize) +{ + return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG); +} + +} + +#endif /* FSE_COMMONDEFS_ONLY */ diff --git a/src/duckdb/third_party/zstd/compress/hist.cpp b/src/duckdb/third_party/zstd/compress/hist.cpp index 6b7f82c90..0a3d04a00 100644 --- a/src/duckdb/third_party/zstd/compress/hist.cpp +++ b/src/duckdb/third_party/zstd/compress/hist.cpp @@ -1,7 +1,7 @@ /* ****************************************************************** * hist : Histogram functions * part of Finite State Entropy project - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -19,6 +19,7 @@ #include "zstd/common/error_private.h" /* ERROR */ #include "zstd/compress/hist.h" + namespace duckdb_zstd { /* --- Error management --- */ @@ -35,7 +36,7 @@ unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned largestCount=0; - ZSTD_memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); + memset(count, 0, (maxSymbolValue+1) * sizeof(*count)); if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; } while (ip= HIST_WKSP_SIZE_U32. + * `workSpace` size must be a table of size >= HIST_WKSP_SIZE_U32. * @return : largest histogram frequency, - * or an error code (notably when histogram's alphabet is larger than *maxSymbolValuePtr) */ + * or an error code (notably when histogram would be larger than *maxSymbolValuePtr). */ static size_t HIST_count_parallel_wksp( unsigned* count, unsigned* maxSymbolValuePtr, const void* source, size_t sourceSize, @@ -72,21 +73,22 @@ static size_t HIST_count_parallel_wksp( { const BYTE* ip = (const BYTE*)source; const BYTE* const iend = ip+sourceSize; - size_t const countSize = (*maxSymbolValuePtr + 1) * sizeof(*count); + unsigned maxSymbolValue = *maxSymbolValuePtr; unsigned max=0; U32* const Counting1 = workSpace; U32* const Counting2 = Counting1 + 256; U32* const Counting3 = Counting2 + 256; U32* const Counting4 = Counting3 + 256; + memset(workSpace, 0, 4*256*sizeof(unsigned)); + /* safety checks */ - assert(*maxSymbolValuePtr <= 255); if (!sourceSize) { - ZSTD_memset(count, 0, countSize); + memset(count, 0, maxSymbolValue + 1); *maxSymbolValuePtr = 0; return 0; } - ZSTD_memset(workSpace, 0, 4*256*sizeof(unsigned)); + if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ /* by stripes of 16 bytes */ { U32 cached = MEM_read32(ip); ip += 4; @@ -118,18 +120,21 @@ static size_t HIST_count_parallel_wksp( /* finish last symbols */ while (ipmaxSymbolValue; s--) { Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; - if (Counting1[s] > max) max = Counting1[s]; + if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); } } - { unsigned maxSymbolValue = 255; - while (!Counting1[maxSymbolValue]) maxSymbolValue--; - if (check && maxSymbolValue > *maxSymbolValuePtr) return ERROR(maxSymbolValue_tooSmall); - *maxSymbolValuePtr = maxSymbolValue; - ZSTD_memmove(count, Counting1, countSize); /* in case count & Counting1 are overlapping */ - } + { U32 s; + if (maxSymbolValue > 255) maxSymbolValue = 255; + for (s=0; s<=maxSymbolValue; s++) { + count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; + if (count[s] > max) max = count[s]; + } } + + while (!count[maxSymbolValue]) maxSymbolValue--; + *maxSymbolValuePtr = maxSymbolValue; return (size_t)max; } @@ -149,6 +154,14 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, trustInput, (U32*)workSpace); } +/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ +size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + unsigned tmpCounters[HIST_WKSP_SIZE_U32]; + return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); +} + /* HIST_count_wksp() : * Same as HIST_count(), but using an externally provided scratch buffer. * `workSpace` size must be table of >= HIST_WKSP_SIZE_U32 unsigned */ @@ -164,21 +177,11 @@ size_t HIST_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr, return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace, workSpaceSize); } -#ifndef ZSTD_NO_UNUSED_FUNCTIONS -/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ -size_t HIST_countFast(unsigned* count, unsigned* maxSymbolValuePtr, - const void* source, size_t sourceSize) -{ - unsigned tmpCounters[HIST_WKSP_SIZE_U32]; - return HIST_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters, sizeof(tmpCounters)); -} - size_t HIST_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize) { unsigned tmpCounters[HIST_WKSP_SIZE_U32]; return HIST_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters, sizeof(tmpCounters)); } -#endif -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/huf_compress.cpp b/src/duckdb/third_party/zstd/compress/huf_compress.cpp index c0c783166..a7fa092e4 100644 --- a/src/duckdb/third_party/zstd/compress/huf_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/huf_compress.cpp @@ -1,6 +1,6 @@ /* ****************************************************************** * Huffman encoder, part of New Generation Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -23,131 +23,45 @@ /* ************************************************************** * Includes ****************************************************************/ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include /* memcpy, memset */ +#include /* printf (debug) */ #include "zstd/common/compiler.h" #include "zstd/common/bitstream.h" #include "zstd/compress/hist.h" -#define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ #include "zstd/common/fse.h" /* header compression */ +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" +#include "zstd/common/huf_static.h" #include "zstd/common/error_private.h" -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ -namespace duckdb_zstd { /* ************************************************************** * Error Management ****************************************************************/ -#define HUF_isError ERR_isError +// #define HUF_isError ERR_isError #define HUF_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) /* use only *after* variable declarations */ +namespace duckdb_zstd { /* ************************************************************** -* Required declarations -****************************************************************/ -typedef struct nodeElt_s { - U32 count; - U16 parent; - BYTE byte; - BYTE nbBits; -} nodeElt; - - -/* ************************************************************** -* Debug Traces +* Utils ****************************************************************/ - -#if DEBUGLEVEL >= 2 - -static size_t showU32(const U32* arr, size_t size) +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) { - size_t u; - for (u=0; u= add) { - assert(add < align); - assert(((size_t)aligned & mask) == 0); - *workspaceSizePtr -= add; - return aligned; - } else { - *workspaceSizePtr = 0; - return NULL; - } -} - - /* HUF_compressWeights() : * Same as FSE_compress(), but dedicated to huff0's weights compression. * The use case needs much less stack memory. * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. */ #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 - -typedef struct { - FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; - U32 scratchBuffer[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(HUF_TABLELOG_MAX, MAX_FSE_TABLELOG_FOR_HUFF_HEADER)]; - unsigned count[HUF_TABLELOG_MAX+1]; - S16 norm[HUF_TABLELOG_MAX+1]; -} HUF_CompressWeightsWksp; - -static size_t -HUF_compressWeights(void* dst, size_t dstSize, - const void* weightTable, size_t wtSize, - void* workspace, size_t workspaceSize) +static size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) { BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; @@ -155,30 +69,33 @@ HUF_compressWeights(void* dst, size_t dstSize, unsigned maxSymbolValue = HUF_TABLELOG_MAX; U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER; - HUF_CompressWeightsWksp* wksp = (HUF_CompressWeightsWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - if (workspaceSize < sizeof(HUF_CompressWeightsWksp)) return ERROR(GENERIC); + FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; + BYTE scratchBuffer[1<count, &maxSymbolValue, weightTable, wtSize); /* never fails */ + { unsigned const maxCount = HIST_count_simple(count, &maxSymbolValue, weightTable, wtSize); /* never fails */ if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ } tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); - CHECK_F( FSE_normalizeCount(wksp->norm, tableLog, wksp->count, wtSize, maxSymbolValue, /* useLowProbCount */ 0) ); + CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) ); /* Write table description header */ - { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), wksp->norm, maxSymbolValue, tableLog) ); + { CHECK_V_F(hSize, FSE_writeNCount(op, (size_t)(oend-op), norm, maxSymbolValue, tableLog) ); op += hSize; } /* Compress */ - CHECK_F( FSE_buildCTable_wksp(wksp->CTable, wksp->norm, maxSymbolValue, tableLog, wksp->scratchBuffer, sizeof(wksp->scratchBuffer)) ); - { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, wksp->CTable) ); + CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) ); + { CHECK_V_F(cSize, FSE_compress_usingCTable(op, (size_t)(oend - op), weightTable, wtSize, CTable) ); if (cSize == 0) return 0; /* not enough space for compressed data */ op += cSize; } @@ -186,94 +103,35 @@ HUF_compressWeights(void* dst, size_t dstSize, return (size_t)(op-ostart); } -static size_t HUF_getNbBits(HUF_CElt elt) -{ - return elt & 0xFF; -} - -static size_t HUF_getNbBitsFast(HUF_CElt elt) -{ - return elt; -} - -static size_t HUF_getValue(HUF_CElt elt) -{ - return elt & ~(size_t)0xFF; -} - -static size_t HUF_getValueFast(HUF_CElt elt) -{ - return elt; -} - -static void HUF_setNbBits(HUF_CElt* elt, size_t nbBits) -{ - assert(nbBits <= HUF_TABLELOG_ABSOLUTEMAX); - *elt = nbBits; -} - -static void HUF_setValue(HUF_CElt* elt, size_t value) -{ - size_t const nbBits = HUF_getNbBits(*elt); - if (nbBits > 0) { - assert((value >> nbBits) == 0); - *elt |= value << (sizeof(HUF_CElt) * 8 - nbBits); - } -} -HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable) -{ - HUF_CTableHeader header; - ZSTD_memcpy(&header, ctable, sizeof(header)); - return header; -} +struct HUF_CElt_s { + U16 val; + BYTE nbBits; +}; /* typedef'd to HUF_CElt within "zstd/common/huf.h" */ -static void HUF_writeCTableHeader(HUF_CElt* ctable, U32 tableLog, U32 maxSymbolValue) +/*! HUF_writeCTable() : + `CTable` : Huffman tree to save, using huf representation. + @return : size of saved CTable */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, + const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog) { - HUF_CTableHeader header; - HUF_STATIC_ASSERT(sizeof(ctable[0]) == sizeof(header)); - ZSTD_memset(&header, 0, sizeof(header)); - assert(tableLog < 256); - header.tableLog = (BYTE)tableLog; - assert(maxSymbolValue < 256); - header.maxSymbolValue = (BYTE)maxSymbolValue; - ZSTD_memcpy(ctable, &header, sizeof(header)); -} - -typedef struct { - HUF_CompressWeightsWksp wksp; BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */ BYTE huffWeight[HUF_SYMBOLVALUE_MAX]; -} HUF_WriteCTableWksp; - -size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, - const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, - void* workspace, size_t workspaceSize) -{ - HUF_CElt const* const ct = CTable + 1; BYTE* op = (BYTE*)dst; U32 n; - HUF_WriteCTableWksp* wksp = (HUF_WriteCTableWksp*)HUF_alignUpWorkspace(workspace, &workspaceSize, ZSTD_ALIGNOF(U32)); - HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE >= sizeof(HUF_WriteCTableWksp)); - - assert(HUF_readCTableHeader(CTable).maxSymbolValue == maxSymbolValue); - assert(HUF_readCTableHeader(CTable).tableLog == huffLog); - - /* check conditions */ - if (workspaceSize < sizeof(HUF_WriteCTableWksp)) return ERROR(GENERIC); + /* check conditions */ if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); /* convert to weight */ - wksp->bitsToWeight[0] = 0; + bitsToWeight[0] = 0; for (n=1; nbitsToWeight[n] = (BYTE)(huffLog + 1 - n); + bitsToWeight[n] = (BYTE)(huffLog + 1 - n); for (n=0; nhuffWeight[n] = wksp->bitsToWeight[HUF_getNbBits(ct[n])]; + huffWeight[n] = bitsToWeight[CTable[n].nbBits]; /* attempt weights compression by FSE */ - if (maxDstSize < 1) return ERROR(dstSize_tooSmall); - { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, wksp->huffWeight, maxSymbolValue, &wksp->wksp, sizeof(wksp->wksp)) ); + { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) ); if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */ op[0] = (BYTE)hSize; return hSize+1; @@ -283,9 +141,9 @@ size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */ if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */ op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1)); - wksp->huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ + huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ for (n=0; nhuffWeight[n] << 4) + wksp->huffWeight[n+1]); + op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]); return ((maxSymbolValue+1)/2) + 1; } @@ -296,38 +154,34 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; U32 nbSymbols = 0; - HUF_CElt* const ct = CTable + 1; /* get symbol weights */ CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize)); - *hasZeroWeights = (rankVal[0] > 0); /* check result */ if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); - *maxSymbolValuePtr = nbSymbols - 1; - - HUF_writeCTableHeader(CTable, tableLog, *maxSymbolValuePtr); - /* Prepare base value per rank */ { U32 n, nextRankStart = 0; for (n=1; n<=tableLog; n++) { - U32 curr = nextRankStart; + U32 current = nextRankStart; nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = curr; + rankVal[n] = current; } } /* fill nbBits */ + *hasZeroWeights = 0; { U32 n; for (n=0; nn=tableLog+1 */ U16 valPerRank[HUF_TABLELOG_MAX+2] = {0}; - { U32 n; for (n=0; n>= 1; } } /* assign value within rank, symbol order */ - { U32 n; for (n=0; n HUF_readCTableHeader(CTable).maxSymbolValue) - return 0; - return (U32)HUF_getNbBits(ct[symbolValue]); + return table[symbolValue].nbBits; } -/** - * HUF_setMaxHeight(): - * Try to enforce @targetNbBits on the Huffman tree described in @huffNode. - * - * It attempts to convert all nodes with nbBits > @targetNbBits - * to employ @targetNbBits instead. Then it adjusts the tree - * so that it remains a valid canonical Huffman tree. - * - * @pre The sum of the ranks of each symbol == 2^largestBits, - * where largestBits == huffNode[lastNonNull].nbBits. - * @post The sum of the ranks of each symbol == 2^largestBits, - * where largestBits is the return value (expected <= targetNbBits). - * - * @param huffNode The Huffman tree modified in place to enforce targetNbBits. - * It's presumed sorted, from most frequent to rarest symbol. - * @param lastNonNull The symbol with the lowest count in the Huffman tree. - * @param targetNbBits The allowed number of bits, which the Huffman tree - * may not respect. After this function the Huffman tree will - * respect targetNbBits. - * @return The maximum number of bits of the Huffman tree after adjustment. - */ -static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits) +typedef struct nodeElt_s { + U32 count; + U16 parent; + BYTE byte; + BYTE nbBits; +} nodeElt; + +static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) { const U32 largestBits = huffNode[lastNonNull].nbBits; - /* early exit : no elt > targetNbBits, so the tree is already valid. */ - if (largestBits <= targetNbBits) return largestBits; - - DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits); + if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ /* there are several too large elements (at least >= 2) */ { int totalCost = 0; - const U32 baseCost = 1 << (largestBits - targetNbBits); + const U32 baseCost = 1 << (largestBits - maxNbBits); int n = (int)lastNonNull; - /* Adjust any ranks > targetNbBits to targetNbBits. - * Compute totalCost, which is how far the sum of the ranks is - * we are over 2^largestBits after adjust the offending ranks. - */ - while (huffNode[n].nbBits > targetNbBits) { + while (huffNode[n].nbBits > maxNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); - huffNode[n].nbBits = (BYTE)targetNbBits; - n--; - } - /* n stops at huffNode[n].nbBits <= targetNbBits */ - assert(huffNode[n].nbBits <= targetNbBits); - /* n end at index of smallest symbol using < targetNbBits */ - while (huffNode[n].nbBits == targetNbBits) --n; + huffNode[n].nbBits = (BYTE)maxNbBits; + n --; + } /* n stops at huffNode[n].nbBits <= maxNbBits */ + while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ - /* renorm totalCost from 2^largestBits to 2^targetNbBits - * note : totalCost is necessarily a multiple of baseCost */ - assert(((U32)totalCost & (baseCost - 1)) == 0); - totalCost >>= (largestBits - targetNbBits); - assert(totalCost > 0); + /* renorm totalCost */ + totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ /* repay normalized cost */ { U32 const noSymbol = 0xF0F0F0F0; U32 rankLast[HUF_TABLELOG_MAX+2]; - /* Get pos of last (smallest = lowest cum. count) symbol per rank */ - ZSTD_memset(rankLast, 0xF0, sizeof(rankLast)); - { U32 currentNbBits = targetNbBits; + /* Get pos of last (smallest) symbol per rank */ + memset(rankLast, 0xF0, sizeof(rankLast)); + { U32 currentNbBits = maxNbBits; int pos; for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */ - rankLast[targetNbBits-currentNbBits] = (U32)pos; + currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ + rankLast[maxNbBits-currentNbBits] = (U32)pos; } } while (totalCost > 0) { - /* Try to reduce the next power of 2 above totalCost because we - * gain back half the rank. - */ - U32 nBitsToDecrease = ZSTD_highbit32((U32)totalCost) + 1; + U32 nBitsToDecrease = BIT_highbit32((U32)totalCost) + 1; for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { U32 const highPos = rankLast[nBitsToDecrease]; U32 const lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; - /* Decrease highPos if no symbols of lowPos or if it is - * not cheaper to remove 2 lowPos than highPos. - */ if (lowPos == noSymbol) break; { U32 const highTotal = huffNode[highPos].count; U32 const lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ - assert(rankLast[nBitsToDecrease] != noSymbol || nBitsToDecrease == 1); /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) - nBitsToDecrease++; - assert(rankLast[nBitsToDecrease] != noSymbol); - /* Increase the number of bits to gain back half the rank cost. */ + nBitsToDecrease ++; totalCost -= 1 << (nBitsToDecrease-1); - huffNode[rankLast[nBitsToDecrease]].nbBits++; - - /* Fix up the new rank. - * If the new rank was empty, this symbol is now its smallest. - * Otherwise, this symbol will be the largest in the new rank so no adjustment. - */ if (rankLast[nBitsToDecrease-1] == noSymbol) - rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; - /* Fix up the old rank. - * If the symbol was at position 0, meaning it was the highest weight symbol in the tree, - * it must be the only symbol in its rank, so the old rank now has no symbols. - * Otherwise, since the Huffman nodes are sorted by count, the previous position is now - * the smallest node in the rank. If the previous position belongs to a different rank, - * then the rank is now empty. - */ + rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */ + huffNode[rankLast[nBitsToDecrease]].nbBits ++; if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ rankLast[nBitsToDecrease] = noSymbol; else { rankLast[nBitsToDecrease]--; - if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease) + if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } - } /* while (totalCost > 0) */ - - /* If we've removed too much weight, then we have to add it back. - * To avoid overshooting again, we only adjust the smallest rank. - * We take the largest nodes from the lowest rank 0 and move them - * to rank 1. There's guaranteed to be enough rank 0 symbols because - * TODO. - */ + } } /* while (totalCost > 0) */ + while (totalCost < 0) { /* Sometimes, cost correction overshoot */ - /* special case : no rank 1 symbol (using targetNbBits-1); - * let's create one from largest rank 0 (using targetNbBits). - */ - if (rankLast[1] == noSymbol) { - while (huffNode[n].nbBits == targetNbBits) n--; + if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ + while (huffNode[n].nbBits == maxNbBits) n--; huffNode[n+1].nbBits--; assert(n >= 0); rankLast[1] = (U32)(n+1); @@ -491,178 +286,47 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } - } /* repay normalized cost */ - } /* there are several too large elements (at least >= 2) */ + } } } /* there are several too large elements (at least >= 2) */ - return targetNbBits; + return maxNbBits; } typedef struct { - U16 base; - U16 curr; + U32 base; + U32 current; } rankPos; -typedef nodeElt huffNodeTable[2 * (HUF_SYMBOLVALUE_MAX + 1)]; +typedef nodeElt huffNodeTable[HUF_CTABLE_WORKSPACE_SIZE_U32]; -/* Number of buckets available for HUF_sort() */ -#define RANK_POSITION_TABLE_SIZE 192 +#define RANK_POSITION_TABLE_SIZE 32 typedef struct { huffNodeTable huffNodeTbl; rankPos rankPosition[RANK_POSITION_TABLE_SIZE]; } HUF_buildCTable_wksp_tables; -/* RANK_POSITION_DISTINCT_COUNT_CUTOFF == Cutoff point in HUF_sort() buckets for which we use log2 bucketing. - * Strategy is to use as many buckets as possible for representing distinct - * counts while using the remainder to represent all "large" counts. - * - * To satisfy this requirement for 192 buckets, we can do the following: - * Let buckets 0-166 represent distinct counts of [0, 166] - * Let buckets 166 to 192 represent all remaining counts up to RANK_POSITION_MAX_COUNT_LOG using log2 bucketing. - */ -#define RANK_POSITION_MAX_COUNT_LOG 32 -#define RANK_POSITION_LOG_BUCKETS_BEGIN ((RANK_POSITION_TABLE_SIZE - 1) - RANK_POSITION_MAX_COUNT_LOG - 1 /* == 158 */) -#define RANK_POSITION_DISTINCT_COUNT_CUTOFF (RANK_POSITION_LOG_BUCKETS_BEGIN + ZSTD_highbit32(RANK_POSITION_LOG_BUCKETS_BEGIN) /* == 166 */) - -/* Return the appropriate bucket index for a given count. See definition of - * RANK_POSITION_DISTINCT_COUNT_CUTOFF for explanation of bucketing strategy. - */ -static U32 HUF_getIndex(U32 const count) { - return (count < RANK_POSITION_DISTINCT_COUNT_CUTOFF) - ? count - : ZSTD_highbit32(count) + RANK_POSITION_LOG_BUCKETS_BEGIN; -} - -/* Helper swap function for HUF_quickSortPartition() */ -static void HUF_swapNodes(nodeElt* a, nodeElt* b) { - nodeElt tmp = *a; - *a = *b; - *b = tmp; -} - -/* Returns 0 if the huffNode array is not sorted by descending count */ -MEM_STATIC int HUF_isSorted(nodeElt huffNode[], U32 const maxSymbolValue1) { - U32 i; - for (i = 1; i < maxSymbolValue1; ++i) { - if (huffNode[i].count > huffNode[i-1].count) { - return 0; - } - } - return 1; -} - -/* Insertion sort by descending order */ -HINT_INLINE void HUF_insertionSort(nodeElt huffNode[], int const low, int const high) { - int i; - int const size = high-low+1; - huffNode += low; - for (i = 1; i < size; ++i) { - nodeElt const key = huffNode[i]; - int j = i - 1; - while (j >= 0 && huffNode[j].count < key.count) { - huffNode[j + 1] = huffNode[j]; - j--; - } - huffNode[j + 1] = key; - } -} - -/* Pivot helper function for quicksort. */ -static int HUF_quickSortPartition(nodeElt arr[], int const low, int const high) { - /* Simply select rightmost element as pivot. "Better" selectors like - * median-of-three don't experimentally appear to have any benefit. - */ - U32 const pivot = arr[high].count; - int i = low - 1; - int j = low; - for ( ; j < high; j++) { - if (arr[j].count > pivot) { - i++; - HUF_swapNodes(&arr[i], &arr[j]); - } - } - HUF_swapNodes(&arr[i + 1], &arr[high]); - return i + 1; -} - -/* Classic quicksort by descending with partially iterative calls - * to reduce worst case callstack size. - */ -static void HUF_simpleQuickSort(nodeElt arr[], int low, int high) { - int const kInsertionSortThreshold = 8; - if (high - low < kInsertionSortThreshold) { - HUF_insertionSort(arr, low, high); - return; - } - while (low < high) { - int const idx = HUF_quickSortPartition(arr, low, high); - if (idx - low < high - idx) { - HUF_simpleQuickSort(arr, low, idx - 1); - low = idx + 1; - } else { - HUF_simpleQuickSort(arr, idx + 1, high); - high = idx - 1; - } - } -} - -/** - * HUF_sort(): - * Sorts the symbols [0, maxSymbolValue] by count[symbol] in decreasing order. - * This is a typical bucket sorting strategy that uses either quicksort or insertion sort to sort each bucket. - * - * @param[out] huffNode Sorted symbols by decreasing count. Only members `.count` and `.byte` are filled. - * Must have (maxSymbolValue + 1) entries. - * @param[in] count Histogram of the symbols. - * @param[in] maxSymbolValue Maximum symbol value. - * @param rankPosition This is a scratch workspace. Must have RANK_POSITION_TABLE_SIZE entries. - */ -static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSymbolValue, rankPos rankPosition[]) { +static void HUF_sort(nodeElt* huffNode, const unsigned* count, U32 maxSymbolValue, rankPos* rankPosition) +{ U32 n; - U32 const maxSymbolValue1 = maxSymbolValue+1; - - /* Compute base and set curr to base. - * For symbol s let lowerRank = HUF_getIndex(count[n]) and rank = lowerRank + 1. - * See HUF_getIndex to see bucketing strategy. - * We attribute each symbol to lowerRank's base value, because we want to know where - * each rank begins in the output, so for rank R we want to count ranks R+1 and above. - */ - ZSTD_memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); - for (n = 0; n < maxSymbolValue1; ++n) { - U32 lowerRank = HUF_getIndex(count[n]); - assert(lowerRank < RANK_POSITION_TABLE_SIZE - 1); - rankPosition[lowerRank].base++; - } - assert(rankPosition[RANK_POSITION_TABLE_SIZE - 1].base == 0); - /* Set up the rankPosition table */ - for (n = RANK_POSITION_TABLE_SIZE - 1; n > 0; --n) { - rankPosition[n-1].base += rankPosition[n].base; - rankPosition[n-1].curr = rankPosition[n-1].base; + memset(rankPosition, 0, sizeof(*rankPosition) * RANK_POSITION_TABLE_SIZE); + for (n=0; n<=maxSymbolValue; n++) { + U32 r = BIT_highbit32(count[n] + 1); + rankPosition[r].base ++; } - - /* Insert each symbol into their appropriate bucket, setting up rankPosition table. */ - for (n = 0; n < maxSymbolValue1; ++n) { + for (n=30; n>0; n--) rankPosition[n-1].base += rankPosition[n].base; + for (n=0; n<32; n++) rankPosition[n].current = rankPosition[n].base; + for (n=0; n<=maxSymbolValue; n++) { U32 const c = count[n]; - U32 const r = HUF_getIndex(c) + 1; - U32 const pos = rankPosition[r].curr++; - assert(pos < maxSymbolValue1); + U32 const r = BIT_highbit32(c+1) + 1; + U32 pos = rankPosition[r].current++; + while ((pos > rankPosition[r].base) && (c > huffNode[pos-1].count)) { + huffNode[pos] = huffNode[pos-1]; + pos--; + } huffNode[pos].count = c; huffNode[pos].byte = (BYTE)n; } - - /* Sort each bucket. */ - for (n = RANK_POSITION_DISTINCT_COUNT_CUTOFF; n < RANK_POSITION_TABLE_SIZE - 1; ++n) { - int const bucketSize = rankPosition[n].curr - rankPosition[n].base; - U32 const bucketStartIdx = rankPosition[n].base; - if (bucketSize > 1) { - assert(bucketStartIdx < maxSymbolValue1); - HUF_simpleQuickSort(huffNode + bucketStartIdx, 0, bucketSize-1); - } - } - - assert(HUF_isSorted(huffNode, maxSymbolValue1)); } @@ -672,21 +336,28 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy */ #define STARTNODE (HUF_SYMBOLVALUE_MAX+1) -/* HUF_buildTree(): - * Takes the huffNode array sorted by HUF_sort() and builds an unlimited-depth Huffman tree. - * - * @param huffNode The array sorted by HUF_sort(). Builds the Huffman tree in this array. - * @param maxSymbolValue The maximum symbol value. - * @return The smallest node in the Huffman tree (by count). - */ -static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) { - nodeElt* const huffNode0 = huffNode - 1; + HUF_buildCTable_wksp_tables* const wksp_tables = (HUF_buildCTable_wksp_tables*)workSpace; + nodeElt* const huffNode0 = wksp_tables->huffNodeTbl; + nodeElt* const huffNode = huffNode0+1; int nonNullRank; int lowS, lowN; int nodeNb = STARTNODE; int n, nodeRoot; - DEBUGLOG(5, "HUF_buildTree (alphabet size = %u)", maxSymbolValue + 1); + + /* safety checks */ + if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ + if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) + return ERROR(workSpace_tooSmall); + if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; + if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) + return ERROR(maxSymbolValue_tooLarge); + memset(huffNode0, 0, sizeof(huffNodeTable)); + + /* sort, decreasing order */ + HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); + /* init for parents */ nonNullRank = (int)maxSymbolValue; while(huffNode[nonNullRank].count == 0) nonNullRank--; @@ -713,414 +384,127 @@ static int HUF_buildTree(nodeElt* huffNode, U32 maxSymbolValue) for (n=0; n<=nonNullRank; n++) huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; - DEBUGLOG(6, "Initial distribution of bits completed (%zu sorted symbols)", showHNodeBits(huffNode, maxSymbolValue+1)); - - return nonNullRank; -} + /* enforce maxTableLog */ + maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); -/** - * HUF_buildCTableFromTree(): - * Build the CTable given the Huffman tree in huffNode. - * - * @param[out] CTable The output Huffman CTable. - * @param huffNode The Huffman tree. - * @param nonNullRank The last and smallest node in the Huffman tree. - * @param maxSymbolValue The maximum symbol value. - * @param maxNbBits The exact maximum number of bits used in the Huffman tree. - */ -static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, int nonNullRank, U32 maxSymbolValue, U32 maxNbBits) -{ - HUF_CElt* const ct = CTable + 1; - /* fill result into ctable (val, nbBits) */ - int n; - U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; - U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; - int const alphabetSize = (int)(maxSymbolValue + 1); - for (n=0; n<=nonNullRank; n++) - nbPerRank[huffNode[n].nbBits]++; - /* determine starting value per rank */ - { U16 min = 0; - for (n=(int)maxNbBits; n>0; n--) { - valPerRank[n] = min; /* get starting value within each rank */ - min += nbPerRank[n]; - min >>= 1; - } } - for (n=0; n HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ + for (n=0; n<=nonNullRank; n++) + nbPerRank[huffNode[n].nbBits]++; + /* determine stating value per rank */ + { U16 min = 0; + for (n=(int)maxNbBits; n>0; n--) { + valPerRank[n] = min; /* get starting value within each rank */ + min += nbPerRank[n]; + min >>= 1; + } } + for (n=0; nhuffNodeTbl; - nodeElt* const huffNode = huffNode0+1; - int nonNullRank; - - HUF_STATIC_ASSERT(HUF_CTABLE_WORKSPACE_SIZE == sizeof(HUF_buildCTable_wksp_tables)); - - DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1); - - /* safety checks */ - if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) - return ERROR(workSpace_tooSmall); - if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; - if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) - return ERROR(maxSymbolValue_tooLarge); - ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable)); - - /* sort, decreasing order */ - HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); - DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); - - /* build tree */ - nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); - - /* determine and enforce maxTableLog */ - maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); - if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ - - HUF_buildCTableFromTree(CTable, huffNode, nonNullRank, maxSymbolValue, maxNbBits); - - return maxNbBits; + HUF_buildCTable_wksp_tables workspace; + return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, &workspace, sizeof(workspace)); } size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { - HUF_CElt const* ct = CTable + 1; size_t nbBits = 0; int s; for (s = 0; s <= (int)maxSymbolValue; ++s) { - nbBits += HUF_getNbBits(ct[s]) * count[s]; + nbBits += CTable[s].nbBits * count[s]; } return nbBits >> 3; } int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { - HUF_CTableHeader header = HUF_readCTableHeader(CTable); - HUF_CElt const* ct = CTable + 1; - int bad = 0; - int s; - - assert(header.tableLog <= HUF_TABLELOG_ABSOLUTEMAX); - - if (header.maxSymbolValue < maxSymbolValue) - return 0; - - for (s = 0; s <= (int)maxSymbolValue; ++s) { - bad |= (count[s] != 0) & (HUF_getNbBits(ct[s]) == 0); - } - return !bad; + int bad = 0; + int s; + for (s = 0; s <= (int)maxSymbolValue; ++s) { + bad |= (count[s] != 0) & (CTable[s].nbBits == 0); + } + return !bad; } size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } -/** HUF_CStream_t: - * Huffman uses its own BIT_CStream_t implementation. - * There are three major differences from BIT_CStream_t: - * 1. HUF_addBits() takes a HUF_CElt (size_t) which is - * the pair (nbBits, value) in the format: - * format: - * - Bits [0, 4) = nbBits - * - Bits [4, 64 - nbBits) = 0 - * - Bits [64 - nbBits, 64) = value - * 2. The bitContainer is built from the upper bits and - * right shifted. E.g. to add a new value of N bits - * you right shift the bitContainer by N, then or in - * the new value into the N upper bits. - * 3. The bitstream has two bit containers. You can add - * bits to the second container and merge them into - * the first container. - */ - -#define HUF_BITS_IN_CONTAINER (sizeof(size_t) * 8) - -typedef struct { - size_t bitContainer[2]; - size_t bitPos[2]; - - BYTE* startPtr; - BYTE* ptr; - BYTE* endPtr; -} HUF_CStream_t; - -/**! HUF_initCStream(): - * Initializes the bitstream. - * @returns 0 or an error code. - */ -static size_t HUF_initCStream(HUF_CStream_t* bitC, - void* startPtr, size_t dstCapacity) -{ - ZSTD_memset(bitC, 0, sizeof(*bitC)); - bitC->startPtr = (BYTE*)startPtr; - bitC->ptr = bitC->startPtr; - bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer[0]); - if (dstCapacity <= sizeof(bitC->bitContainer[0])) return ERROR(dstSize_tooSmall); - return 0; -} - -/*! HUF_addBits(): - * Adds the symbol stored in HUF_CElt elt to the bitstream. - * - * @param elt The element we're adding. This is a (nbBits, value) pair. - * See the HUF_CStream_t docs for the format. - * @param idx Insert into the bitstream at this idx. - * @param kFast This is a template parameter. If the bitstream is guaranteed - * to have at least 4 unused bits after this call it may be 1, - * otherwise it must be 0. HUF_addBits() is faster when fast is set. - */ -FORCE_INLINE_TEMPLATE void HUF_addBits(HUF_CStream_t* bitC, HUF_CElt elt, int idx, int kFast) -{ - assert(idx <= 1); - assert(HUF_getNbBits(elt) <= HUF_TABLELOG_ABSOLUTEMAX); - /* This is efficient on x86-64 with BMI2 because shrx - * only reads the low 6 bits of the register. The compiler - * knows this and elides the mask. When fast is set, - * every operation can use the same value loaded from elt. - */ - bitC->bitContainer[idx] >>= HUF_getNbBits(elt); - bitC->bitContainer[idx] |= kFast ? HUF_getValueFast(elt) : HUF_getValue(elt); - /* We only read the low 8 bits of bitC->bitPos[idx] so it - * doesn't matter that the high bits have noise from the value. - */ - bitC->bitPos[idx] += HUF_getNbBitsFast(elt); - assert((bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); - /* The last 4-bits of elt are dirty if fast is set, - * so we must not be overwriting bits that have already been - * inserted into the bit container. - */ -#if DEBUGLEVEL >= 1 - { - size_t const nbBits = HUF_getNbBits(elt); - size_t const dirtyBits = nbBits == 0 ? 0 : ZSTD_highbit32((U32)nbBits) + 1; - (void)dirtyBits; - /* Middle bits are 0. */ - assert(((elt >> dirtyBits) << (dirtyBits + nbBits)) == 0); - /* We didn't overwrite any bits in the bit container. */ - assert(!kFast || (bitC->bitPos[idx] & 0xFF) <= HUF_BITS_IN_CONTAINER); - (void)dirtyBits; - } -#endif -} - -FORCE_INLINE_TEMPLATE void HUF_zeroIndex1(HUF_CStream_t* bitC) -{ - bitC->bitContainer[1] = 0; - bitC->bitPos[1] = 0; -} - -/*! HUF_mergeIndex1() : - * Merges the bit container @ index 1 into the bit container @ index 0 - * and zeros the bit container @ index 1. - */ -FORCE_INLINE_TEMPLATE void HUF_mergeIndex1(HUF_CStream_t* bitC) -{ - assert((bitC->bitPos[1] & 0xFF) < HUF_BITS_IN_CONTAINER); - bitC->bitContainer[0] >>= (bitC->bitPos[1] & 0xFF); - bitC->bitContainer[0] |= bitC->bitContainer[1]; - bitC->bitPos[0] += bitC->bitPos[1]; - assert((bitC->bitPos[0] & 0xFF) <= HUF_BITS_IN_CONTAINER); -} - -/*! HUF_flushBits() : -* Flushes the bits in the bit container @ index 0. -* -* @post bitPos will be < 8. -* @param kFast If kFast is set then we must know a-priori that -* the bit container will not overflow. -*/ -FORCE_INLINE_TEMPLATE void HUF_flushBits(HUF_CStream_t* bitC, int kFast) -{ - /* The upper bits of bitPos are noisy, so we must mask by 0xFF. */ - size_t const nbBits = bitC->bitPos[0] & 0xFF; - size_t const nbBytes = nbBits >> 3; - /* The top nbBits bits of bitContainer are the ones we need. */ - size_t const bitContainer = bitC->bitContainer[0] >> (HUF_BITS_IN_CONTAINER - nbBits); - /* Mask bitPos to account for the bytes we consumed. */ - bitC->bitPos[0] &= 7; - assert(nbBits > 0); - assert(nbBits <= sizeof(bitC->bitContainer[0]) * 8); - assert(bitC->ptr <= bitC->endPtr); - MEM_writeLEST(bitC->ptr, bitContainer); - bitC->ptr += nbBytes; - assert(!kFast || bitC->ptr <= bitC->endPtr); - if (!kFast && bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; - /* bitContainer doesn't need to be modified because the leftover - * bits are already the top bitPos bits. And we don't care about - * noise in the lower values. - */ -} - -/*! HUF_endMark() - * @returns The Huffman stream end mark: A 1-bit value = 1. - */ -static HUF_CElt HUF_endMark(void) -{ - HUF_CElt endMark; - HUF_setNbBits(&endMark, 1); - HUF_setValue(&endMark, 1); - return endMark; -} - -/*! HUF_closeCStream() : - * @return Size of CStream, in bytes, - * or 0 if it could not fit into dstBuffer */ -static size_t HUF_closeCStream(HUF_CStream_t* bitC) -{ - HUF_addBits(bitC, HUF_endMark(), /* idx */ 0, /* kFast */ 0); - HUF_flushBits(bitC, /* kFast */ 0); - { - size_t const nbBits = bitC->bitPos[0] & 0xFF; - if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ - return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0); - } -} - FORCE_INLINE_TEMPLATE void -HUF_encodeSymbol(HUF_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable, int idx, int fast) +HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable) { - HUF_addBits(bitCPtr, CTable[symbol], idx, fast); + BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits); } -FORCE_INLINE_TEMPLATE void -HUF_compress1X_usingCTable_internal_body_loop(HUF_CStream_t* bitC, - const BYTE* ip, size_t srcSize, - const HUF_CElt* ct, - int kUnroll, int kFastFlush, int kLastFast) -{ - /* Join to kUnroll */ - int n = (int)srcSize; - int rem = n % kUnroll; - if (rem > 0) { - for (; rem > 0; --rem) { - HUF_encodeSymbol(bitC, ip[--n], ct, 0, /* fast */ 0); - } - HUF_flushBits(bitC, kFastFlush); - } - assert(n % kUnroll == 0); +#define HUF_FLUSHBITS(s) BIT_flushBits(s) - /* Join to 2 * kUnroll */ - if (n % (2 * kUnroll)) { - int u; - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - u], ct, 0, 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, 0, kLastFast); - HUF_flushBits(bitC, kFastFlush); - n -= kUnroll; - } - assert(n % (2 * kUnroll) == 0); - - for (; n>0; n-= 2 * kUnroll) { - /* Encode kUnroll symbols into the bitstream @ index 0. */ - int u; - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - u], ct, /* idx */ 0, /* fast */ 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll], ct, /* idx */ 0, /* fast */ kLastFast); - HUF_flushBits(bitC, kFastFlush); - /* Encode kUnroll symbols into the bitstream @ index 1. - * This allows us to start filling the bit container - * without any data dependencies. - */ - HUF_zeroIndex1(bitC); - for (u = 1; u < kUnroll; ++u) { - HUF_encodeSymbol(bitC, ip[n - kUnroll - u], ct, /* idx */ 1, /* fast */ 1); - } - HUF_encodeSymbol(bitC, ip[n - kUnroll - kUnroll], ct, /* idx */ 1, /* fast */ kLastFast); - /* Merge bitstream @ index 1 into the bitstream @ index 0 */ - HUF_mergeIndex1(bitC); - HUF_flushBits(bitC, kFastFlush); - } - assert(n == 0); - -} - -/** - * Returns a tight upper bound on the output space needed by Huffman - * with 8 bytes buffer to handle over-writes. If the output is at least - * this large we don't need to do bounds checks during Huffman encoding. - */ -static size_t HUF_tightCompressBound(size_t srcSize, size_t tableLog) -{ - return ((srcSize * tableLog) >> 3) + 8; -} +#define HUF_FLUSHBITS_1(stream) \ + if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream) +#define HUF_FLUSHBITS_2(stream) \ + if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream) FORCE_INLINE_TEMPLATE size_t HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - U32 const tableLog = HUF_readCTableHeader(CTable).tableLog; - HUF_CElt const* ct = CTable + 1; const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; - HUF_CStream_t bitC; + BYTE* op = ostart; + size_t n; + BIT_CStream_t bitC; /* init */ if (dstSize < 8) return 0; /* not enough space to compress */ - { BYTE* op = ostart; - size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op)); + { size_t const initErr = BIT_initCStream(&bitC, op, (size_t)(oend-op)); if (HUF_isError(initErr)) return 0; } - if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11) - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ MEM_32bits() ? 2 : 4, /* kFast */ 0, /* kLastFast */ 0); - else { - if (MEM_32bits()) { - switch (tableLog) { - case 11: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 10: ZSTD_FALLTHROUGH; - case 9: ZSTD_FALLTHROUGH; - case 8: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 2, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - case 7: ZSTD_FALLTHROUGH; - default: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 3, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - } - } else { - switch (tableLog) { - case 11: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 10: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 5, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - case 9: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 6, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 8: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 7, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 7: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 8, /* kFastFlush */ 1, /* kLastFast */ 0); - break; - case 6: ZSTD_FALLTHROUGH; - default: - HUF_compress1X_usingCTable_internal_body_loop(&bitC, ip, srcSize, ct, /* kUnroll */ 9, /* kFastFlush */ 1, /* kLastFast */ 1); - break; - } - } + n = srcSize & ~3; /* join to mod 4 */ + switch (srcSize & 3) + { + case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); + HUF_FLUSHBITS_2(&bitC); + /* fall-through */ + case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); + HUF_FLUSHBITS_1(&bitC); + /* fall-through */ + case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); + HUF_FLUSHBITS(&bitC); + /* fall-through */ + case 0 : /* fall-through */ + default: break; + } + + for (; n>0; n-=4) { /* note : n&3==0 at this stage */ + HUF_encodeSymbol(&bitC, ip[n- 1], CTable); + HUF_FLUSHBITS_1(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 2], CTable); + HUF_FLUSHBITS_2(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 3], CTable); + HUF_FLUSHBITS_1(&bitC); + HUF_encodeSymbol(&bitC, ip[n- 4], CTable); + HUF_FLUSHBITS(&bitC); } - assert(bitC.ptr <= bitC.endPtr); - return HUF_closeCStream(&bitC); + return BIT_closeCStream(&bitC); } #if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t HUF_compress1X_usingCTable_internal_bmi2(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) @@ -1139,9 +523,9 @@ HUF_compress1X_usingCTable_internal_default(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int flags) + const HUF_CElt* CTable, const int bmi2) { - if (flags & HUF_flags_bmi2) { + if (bmi2) { return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable); } return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable); @@ -1152,23 +536,24 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, static size_t HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, const int flags) + const HUF_CElt* CTable, const int bmi2) { - (void)flags; + (void)bmi2; return HUF_compress1X_usingCTable_internal_body(dst, dstSize, src, srcSize, CTable); } #endif -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); + return HUF_compress1X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); } + static size_t HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, const void* src, size_t srcSize, - const HUF_CElt* CTable, int flags) + const HUF_CElt* CTable, int bmi2) { size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */ const BYTE* ip = (const BYTE*) src; @@ -1182,24 +567,27 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, op += 6; /* jumpTable */ assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart, (U16)cSize); op += cSize; } ip += segmentSize; assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart+2, (U16)cSize); op += cSize; } ip += segmentSize; assert(op <= oend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, segmentSize, CTable, bmi2) ); + if (cSize==0) return 0; + assert(cSize <= 65535); MEM_writeLE16(ostart+4, (U16)cSize); op += cSize; } @@ -1207,17 +595,17 @@ HUF_compress4X_usingCTable_internal(void* dst, size_t dstSize, ip += segmentSize; assert(op <= oend); assert(ip <= iend); - { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, flags) ); - if (cSize == 0 || cSize > 65535) return 0; + { CHECK_V_F(cSize, HUF_compress1X_usingCTable_internal(op, (size_t)(oend-op), ip, (size_t)(iend-ip), CTable, bmi2) ); + if (cSize==0) return 0; op += cSize; } return (size_t)(op-ostart); } -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags) +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { - return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, flags); + return HUF_compress4X_usingCTable_internal(dst, dstSize, src, srcSize, CTable, /* bmi2 */ 0); } typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; @@ -1225,11 +613,11 @@ typedef enum { HUF_singleStream, HUF_fourStreams } HUF_nbStreams_e; static size_t HUF_compressCTable_internal( BYTE* const ostart, BYTE* op, BYTE* const oend, const void* src, size_t srcSize, - HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int flags) + HUF_nbStreams_e nbStreams, const HUF_CElt* CTable, const int bmi2) { size_t const cSize = (nbStreams==HUF_singleStream) ? - HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags) : - HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, flags); + HUF_compress1X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2) : + HUF_compress4X_usingCTable_internal(op, (size_t)(oend - op), src, srcSize, CTable, bmi2); if (HUF_isError(cSize)) { return cSize; } if (cSize==0) { return 0; } /* uncompressible */ op += cSize; @@ -1241,113 +629,31 @@ static size_t HUF_compressCTable_internal( typedef struct { unsigned count[HUF_SYMBOLVALUE_MAX + 1]; - HUF_CElt CTable[HUF_CTABLE_SIZE_ST(HUF_SYMBOLVALUE_MAX)]; - union { - HUF_buildCTable_wksp_tables buildCTable_wksp; - HUF_WriteCTableWksp writeCTable_wksp; - U32 hist_wksp[HIST_WKSP_SIZE_U32]; - } wksps; + HUF_CElt CTable[HUF_SYMBOLVALUE_MAX + 1]; + HUF_buildCTable_wksp_tables buildCTable_wksp; } HUF_compress_tables_t; -#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096 -#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */ - -unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue) -{ - unsigned cardinality = 0; - unsigned i; - - for (i = 0; i < maxSymbolValue + 1; i++) { - if (count[i] != 0) cardinality += 1; - } - - return cardinality; -} - -unsigned HUF_minTableLog(unsigned symbolCardinality) -{ - U32 minBitsSymbols = ZSTD_highbit32(symbolCardinality) + 1; - return minBitsSymbols; -} - -unsigned HUF_optimalTableLog( - unsigned maxTableLog, - size_t srcSize, - unsigned maxSymbolValue, - void* workSpace, size_t wkspSize, - HUF_CElt* table, - const unsigned* count, - int flags) -{ - assert(srcSize > 1); /* Not supported, RLE should be used instead */ - assert(wkspSize >= sizeof(HUF_buildCTable_wksp_tables)); - - if (!(flags & HUF_flags_optimalDepth)) { - /* cheap evaluation, based on FSE */ - return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); - } - - { BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); - size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp); - size_t hSize, newSize; - const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue); - const unsigned minTableLog = HUF_minTableLog(symbolCardinality); - size_t optSize = ((size_t) ~0) - 1; - unsigned optLog = maxTableLog, optLogGuess; - - DEBUGLOG(6, "HUF_optimalTableLog: probing huf depth (srcSize=%zu)", srcSize); - - /* Search until size increases */ - for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) { - DEBUGLOG(7, "checking for huffLog=%u", optLogGuess); - - { size_t maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize); - if (ERR_isError(maxBits)) continue; - - if (maxBits < optLogGuess && optLogGuess > minTableLog) break; - - hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize); - } - - if (ERR_isError(hSize)) continue; - - newSize = HUF_estimateCompressedSize(table, count, maxSymbolValue) + hSize; - - if (newSize > optSize + 1) { - break; - } - - if (newSize < optSize) { - optSize = newSize; - optLog = optLogGuess; - } - } - assert(optLog <= HUF_TABLELOG_MAX); - return optLog; - } -} - /* HUF_compress_internal() : - * `workSpace_align4` must be aligned on 4-bytes boundaries, - * and occupies the same space as a table of HUF_WORKSPACE_SIZE_U64 unsigned */ + * `workSpace` must a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ static size_t HUF_compress_internal (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, HUF_nbStreams_e nbStreams, void* workSpace, size_t wkspSize, - HUF_CElt* oldHufTable, HUF_repeat* repeat, int flags) + HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat, + const int bmi2) { - HUF_compress_tables_t* const table = (HUF_compress_tables_t*)HUF_alignUpWorkspace(workSpace, &wkspSize, ZSTD_ALIGNOF(size_t)); + HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstSize; BYTE* op = ostart; - DEBUGLOG(5, "HUF_compress_internal (srcSize=%zu)", srcSize); - HUF_STATIC_ASSERT(sizeof(*table) + HUF_WORKSPACE_MAX_ALIGNMENT <= HUF_WORKSPACE_SIZE); + HUF_STATIC_ASSERT(sizeof(*table) <= HUF_WORKSPACE_SIZE); /* checks & inits */ - if (wkspSize < sizeof(*table)) return ERROR(workSpace_tooSmall); + if (((size_t)workSpace & 3) != 0) return ERROR(GENERIC); /* must be aligned on 4-bytes boundaries */ + if (wkspSize < HUF_WORKSPACE_SIZE) return ERROR(workSpace_tooSmall); if (!srcSize) return 0; /* Uncompressed */ if (!dstSize) return 0; /* cannot fit anything within dst budget */ if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */ @@ -1357,34 +663,17 @@ HUF_compress_internal (void* dst, size_t dstSize, if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT; /* Heuristic : If old table is valid, use it for small inputs */ - if ((flags & HUF_flags_preferRepeat) && repeat && *repeat == HUF_repeat_valid) { + if (preferRepeat && repeat && *repeat == HUF_repeat_valid) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); - } - - /* If uncompressible data is suspected, do a smaller sampling first */ - DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2); - if ((flags & HUF_flags_suspectUncompressible) && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) { - size_t largestTotal = 0; - DEBUGLOG(5, "input suspected incompressible : sampling to check"); - { unsigned maxSymbolValueBegin = maxSymbolValue; - CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); - largestTotal += largestBegin; - } - { unsigned maxSymbolValueEnd = maxSymbolValue; - CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); - largestTotal += largestEnd; - } - if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */ + nbStreams, oldHufTable, bmi2); } /* Scan input and build symbol stats */ - { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, table->wksps.hist_wksp, sizeof(table->wksps.hist_wksp)) ); + { CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace, wkspSize) ); if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } - DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); /* Check validity of previous table */ if ( repeat @@ -1393,25 +682,26 @@ HUF_compress_internal (void* dst, size_t dstSize, *repeat = HUF_repeat_none; } /* Heuristic : use existing table for small inputs */ - if ((flags & HUF_flags_preferRepeat) && repeat && *repeat != HUF_repeat_none) { + if (preferRepeat && repeat && *repeat != HUF_repeat_none) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); + nbStreams, oldHufTable, bmi2); } /* Build Huffman Tree */ - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, &table->wksps, sizeof(table->wksps), table->CTable, table->count, flags); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); { size_t const maxBits = HUF_buildCTable_wksp(table->CTable, table->count, maxSymbolValue, huffLog, - &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); + &table->buildCTable_wksp, sizeof(table->buildCTable_wksp)); CHECK_F(maxBits); huffLog = (U32)maxBits; - DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); + /* Zero unused symbols in CTable, so we can check it for validity */ + memset(table->CTable + (maxSymbolValue + 1), 0, + sizeof(table->CTable) - ((maxSymbolValue + 1) * sizeof(HUF_CElt))); } /* Write table description header */ - { CHECK_V_F(hSize, HUF_writeCTable_wksp(op, dstSize, table->CTable, maxSymbolValue, huffLog, - &table->wksps.writeCTable_wksp, sizeof(table->wksps.writeCTable_wksp)) ); + { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table->CTable, maxSymbolValue, huffLog) ); /* Check if using previous huffman table is beneficial */ if (repeat && *repeat != HUF_repeat_none) { size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, table->count, maxSymbolValue); @@ -1419,7 +709,7 @@ HUF_compress_internal (void* dst, size_t dstSize, if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) { return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, oldHufTable, flags); + nbStreams, oldHufTable, bmi2); } } /* Use the new huffman table */ @@ -1427,41 +717,85 @@ HUF_compress_internal (void* dst, size_t dstSize, op += hSize; if (repeat) { *repeat = HUF_repeat_none; } if (oldHufTable) - ZSTD_memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ + memcpy(oldHufTable, table->CTable, sizeof(table->CTable)); /* Save new table */ } return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, - nbStreams, table->CTable, flags); + nbStreams, table->CTable, bmi2); +} + + +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog, + void* workSpace, size_t wkspSize) +{ + return HUF_compress_internal(dst, dstSize, src, srcSize, + maxSymbolValue, huffLog, HUF_singleStream, + workSpace, wkspSize, + NULL, NULL, 0, 0 /*bmi2*/); } size_t HUF_compress1X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int flags) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) { - DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, hufTable, - repeat, flags); + repeat, preferRepeat, bmi2); +} + +size_t HUF_compress1X (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; + return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); } /* HUF_compress4X_repeat(): * compress input using 4 streams. - * consider skipping quickly - * reuse an existing huffman compression table */ + * provide workspace to generate compression tables */ +size_t HUF_compress4X_wksp (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog, + void* workSpace, size_t wkspSize) +{ + return HUF_compress_internal(dst, dstSize, src, srcSize, + maxSymbolValue, huffLog, HUF_fourStreams, + workSpace, wkspSize, + NULL, NULL, 0, 0 /*bmi2*/); +} + +/* HUF_compress4X_repeat(): + * compress input using 4 streams. + * re-use an existing huffman compression table */ size_t HUF_compress4X_repeat (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize, - HUF_CElt* hufTable, HUF_repeat* repeat, int flags) + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2) { - DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, - hufTable, repeat, flags); + hufTable, repeat, preferRepeat, bmi2); +} + +size_t HUF_compress2 (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + unsigned workSpace[HUF_WORKSPACE_SIZE_U32]; + return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); } -} // namespace duckdb_zstd +size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize) +{ + return HUF_compress2(dst, maxDstSize, src, srcSize, 255, HUF_TABLELOG_DEFAULT); +} + +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress.cpp index df5626e5f..649e53571 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,13 +11,14 @@ /*-************************************* * Dependencies ***************************************/ -#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd/common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ +#include /* INT_MAX */ +#include /* memset */ #include "zstd/common/mem.h" #include "zstd/compress/hist.h" /* HIST_countFast_wksp */ -#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" +#include "zstd/common/huf_static.h" #include "zstd/compress/zstd_compress_internal.h" #include "zstd/compress/zstd_compress_sequences.h" #include "zstd/compress/zstd_compress_literals.h" @@ -27,51 +28,24 @@ #include "zstd/compress/zstd_opt.h" #include "zstd/compress/zstd_ldm.h" #include "zstd/compress/zstd_compress_superblock.h" -#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_rotateRight_U64 */ - -/* *************************************************************** -* Tuning parameters -*****************************************************************/ -/*! - * COMPRESS_HEAPMODE : - * Select how default decompression function ZSTD_compress() allocates its context, - * on stack (0, default), or into heap (1). - * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. - */ -#ifndef ZSTD_COMPRESS_HEAPMODE -# define ZSTD_COMPRESS_HEAPMODE 0 -#endif -/*! - * ZSTD_HASHLOG3_MAX : - * Maximum size of the hash table dedicated to find 3-bytes matches, - * in log format, aka 17 => 1 << 17 == 128Ki positions. - * This structure is only used in zstd_opt. - * Since allocation is centralized for all strategies, it has to be known here. - * The actual (selected) size of the hash table is then stored in ZSTD_matchState_t.hashLog3, - * so that zstd_opt.c doesn't need to know about this constant. - */ -#ifndef ZSTD_HASHLOG3_MAX -# define ZSTD_HASHLOG3_MAX 17 +#if defined (MEMORY_SANITIZER) +#include #endif namespace duckdb_zstd { - /*-************************************* * Helper functions ***************************************/ /* ZSTD_compressBound() - * Note that the result from this function is only valid for - * the one-pass compression functions. - * When employing the streaming mode, - * if flushes are frequently altering the size of blocks, - * the overhead from block headers can make the compressed data larger - * than the return value of ZSTD_compressBound(). + * Note that the result from this function is only compatible with the "normal" + * full-block strategy. + * When there are a lot of small blocks due to frequent flush in streaming mode + * the overhead of headers can make the compressed data to be larger than the + * return value of ZSTD_compressBound(). */ size_t ZSTD_compressBound(size_t srcSize) { - size_t const r = ZSTD_COMPRESSBOUND(srcSize); - if (r==0) return ERROR(srcSize_wrong); - return r; + return ZSTD_COMPRESSBOUND(srcSize); } @@ -81,7 +55,6 @@ size_t ZSTD_compressBound(size_t srcSize) { struct ZSTD_CDict_s { const void* dictContent; size_t dictContentSize; - ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ ZSTD_cwksp workspace; ZSTD_matchState_t matchState; @@ -89,23 +62,19 @@ struct ZSTD_CDict_s { ZSTD_customMem customMem; U32 dictID; int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ - ZSTD_paramSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use - * row-based matchfinder. Unless the cdict is reloaded, we will use - * the same greedy/lazy matchfinder at compression time. - */ }; /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void) { - return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); + return ZSTD_createCCtx_advanced({NULL, NULL, NULL}); } static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) { assert(cctx != NULL); - ZSTD_memset(cctx, 0, sizeof(*cctx)); + memset(cctx, 0, sizeof(*cctx)); cctx->customMem = memManager; - cctx->bmi2 = ZSTD_cpuSupportsBmi2(); + cctx->bmi2 = 0; { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); assert(!ZSTD_isError(err)); (void)err; @@ -116,8 +85,8 @@ ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) { ZSTD_STATIC_ASSERT(zcss_init==0); ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); if (!cctx) return NULL; ZSTD_initCCtx(cctx, customMem); return cctx; @@ -130,21 +99,21 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) ZSTD_CCtx* cctx; if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); if (cctx == NULL) return NULL; - ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); + memset(cctx, 0, sizeof(ZSTD_CCtx)); ZSTD_cwksp_move(&cctx->workspace, &ws); cctx->staticSize = workspaceSize; /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ - if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; + if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); - cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); - cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); + cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, HUF_WORKSPACE_SIZE); + cctx->bmi2 = 0; return cctx; } @@ -153,10 +122,10 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) */ static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) { - ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); + ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); ZSTD_freeCDict(cctx->localDict.cdict); - ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); - ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); + memset(&cctx->localDict, 0, sizeof(cctx->localDict)); + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); cctx->cdict = NULL; } @@ -180,13 +149,15 @@ static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) { - DEBUGLOG(3, "ZSTD_freeCCtx (address: %p)", (void*)cctx); if (cctx==NULL) return 0; /* support free on NULL */ RETURN_ERROR_IF(cctx->staticSize, memory_allocation, "not compatible with static CCtx"); - { int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); + { + int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); ZSTD_freeCCtxContent(cctx); - if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem); + if (!cctxInWorkspace) { + ZSTD_free(cctx, cctx->customMem); + } } return 0; } @@ -221,116 +192,15 @@ size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) /* private API call, for dictBuilder only */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } -/* Returns true if the strategy supports using a row based matchfinder */ -static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) { - return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2); -} - -/* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder - * for this compression. - */ -static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_paramSwitch_e mode) { - assert(mode != ZSTD_ps_auto); - return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable); -} - -/* Returns row matchfinder usage given an initial mode and cParams */ -static ZSTD_paramSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { -#if defined(ZSTD_ARCH_X86_SSE2) || defined(ZSTD_ARCH_ARM_NEON) - int const kHasSIMD128 = 1; -#else - int const kHasSIMD128 = 0; -#endif - if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ - mode = ZSTD_ps_disable; - if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; - if (kHasSIMD128) { - if (cParams->windowLog > 14) mode = ZSTD_ps_enable; - } else { - if (cParams->windowLog > 17) mode = ZSTD_ps_enable; - } - return mode; -} - -/* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */ -static ZSTD_paramSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { - if (mode != ZSTD_ps_auto) return mode; - return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable; -} - -/* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */ -static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, - const ZSTD_paramSwitch_e useRowMatchFinder, - const U32 forDDSDict) { - assert(useRowMatchFinder != ZSTD_ps_auto); - /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate. - * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder. - */ - return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder)); -} - -/* Returns ZSTD_ps_enable if compression parameters are such that we should - * enable long distance matching (wlog >= 27, strategy >= btopt). - * Returns ZSTD_ps_disable otherwise. - */ -static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { - if (mode != ZSTD_ps_auto) return mode; - return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; -} - -static int ZSTD_resolveExternalSequenceValidation(int mode) { - return mode; -} - -/* Resolves maxBlockSize to the default if no value is present. */ -static size_t ZSTD_resolveMaxBlockSize(size_t maxBlockSize) { - if (maxBlockSize == 0) { - return ZSTD_BLOCKSIZE_MAX; - } else { - return maxBlockSize; - } -} - -static ZSTD_paramSwitch_e ZSTD_resolveExternalRepcodeSearch(ZSTD_paramSwitch_e value, int cLevel) { - if (value != ZSTD_ps_auto) return value; - if (cLevel < 10) { - return ZSTD_ps_disable; - } else { - return ZSTD_ps_enable; - } -} - -/* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. - * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */ -static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) { - return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast; -} - static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( ZSTD_compressionParameters cParams) { ZSTD_CCtx_params cctxParams; - /* should not matter, as all cParams are presumed properly defined */ - ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); + memset(&cctxParams, 0, sizeof(cctxParams)); cctxParams.cParams = cParams; - - /* Adjust advanced params according to cParams */ - cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); - if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); - assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); - assert(cctxParams.ldmParams.hashRateLog < 32); - } - cctxParams.useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.useBlockSplitter, &cParams); - cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); - cctxParams.validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams.validateSequences); - cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize); - cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes, - cctxParams.compressionLevel); + cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ assert(!ZSTD_checkCParams(cParams)); + cctxParams.fParams.contentSizeFlag = 1; return cctxParams; } @@ -338,24 +208,25 @@ static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( ZSTD_customMem customMem) { ZSTD_CCtx_params* params; - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; - params = (ZSTD_CCtx_params*)ZSTD_customCalloc( + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; + params = (ZSTD_CCtx_params*)ZSTD_calloc( sizeof(ZSTD_CCtx_params), customMem); if (!params) { return NULL; } - ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); params->customMem = customMem; + params->compressionLevel = ZSTD_CLEVEL_DEFAULT; + params->fParams.contentSizeFlag = 1; return params; } ZSTD_CCtx_params* ZSTD_createCCtxParams(void) { - return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); + return ZSTD_createCCtxParams_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); } size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) { if (params == NULL) { return 0; } - ZSTD_customFree(params, params->customMem); + ZSTD_free(params, params->customMem); return 0; } @@ -366,63 +237,35 @@ size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); - ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); + memset(cctxParams, 0, sizeof(*cctxParams)); cctxParams->compressionLevel = compressionLevel; cctxParams->fParams.contentSizeFlag = 1; return 0; } -#define ZSTD_NO_CLEVEL 0 - -/** - * Initializes `cctxParams` from `params` and `compressionLevel`. - * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. - */ -static void -ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, - const ZSTD_parameters* params, - int compressionLevel) -{ - assert(!ZSTD_checkCParams(params->cParams)); - ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; - /* Should not matter, as all cParams are presumed properly defined. - * But, set it for tracing anyway. - */ - cctxParams->compressionLevel = compressionLevel; - cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); - cctxParams->useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->useBlockSplitter, ¶ms->cParams); - cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); - cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); - cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); - cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); - DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", - cctxParams->useRowMatchFinder, cctxParams->useBlockSplitter, cctxParams->ldmParams.enableLdm); -} - size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); + memset(cctxParams, 0, sizeof(*cctxParams)); + assert(!ZSTD_checkCParams(params.cParams)); + cctxParams->cParams = params.cParams; + cctxParams->fParams = params.fParams; + cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ return 0; } -/** - * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. - * @param params Validated zstd parameters. - */ -static void ZSTD_CCtxParams_setZstdParams( - ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) +/* ZSTD_assignParamsToCCtxParams() : + * params is presumed valid at this stage */ +static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( + const ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) { + ZSTD_CCtx_params ret = *cctxParams; assert(!ZSTD_checkCParams(params->cParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; - /* Should not matter, as all cParams are presumed properly defined. - * But, set it for tracing anyway. - */ - cctxParams->compressionLevel = ZSTD_NO_CLEVEL; + ret.cParams = params->cParams; + ret.fParams = params->fParams; + ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ + return ret; } ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) @@ -514,16 +357,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) #endif return bounds; - case ZSTD_c_enableDedicatedDictSearch: + case ZSTD_c_enableLongDistanceMatching: bounds.lowerBound = 0; bounds.upperBound = 1; return bounds; - case ZSTD_c_enableLongDistanceMatching: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - case ZSTD_c_ldmHashLog: bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; @@ -562,15 +400,15 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) return bounds; case ZSTD_c_forceAttachDict: - ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); + ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); bounds.lowerBound = ZSTD_dictDefaultAttach; bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ return bounds; case ZSTD_c_literalCompressionMode: - ZSTD_STATIC_ASSERT(ZSTD_ps_auto < ZSTD_ps_enable && ZSTD_ps_enable < ZSTD_ps_disable); - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; + ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); + bounds.lowerBound = ZSTD_lcm_auto; + bounds.upperBound = ZSTD_lcm_uncompressed; return bounds; case ZSTD_c_targetCBlockSize: @@ -583,57 +421,6 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; return bounds; - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - bounds.lowerBound = (int)ZSTD_bm_buffered; - bounds.upperBound = (int)ZSTD_bm_stable; - return bounds; - - case ZSTD_c_blockDelimiters: - bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; - bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; - return bounds; - - case ZSTD_c_validateSequences: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_useBlockSplitter: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_useRowMatchFinder: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_deterministicRefPrefix: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_prefetchCDictTables: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - - case ZSTD_c_enableSeqProducerFallback: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - - case ZSTD_c_maxBlockSize: - bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; - bounds.upperBound = ZSTD_BLOCKSIZE_MAX; - return bounds; - - case ZSTD_c_searchForExternalRepcodes: - bounds.lowerBound = (int)ZSTD_ps_auto; - bounds.upperBound = (int)ZSTD_ps_disable; - return bounds; - default: bounds.error = ERROR(parameter_unsupported); return bounds; @@ -652,11 +439,10 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) return 0; } -#define BOUNDCHECK(cParam, val) \ - do { \ - RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ - parameter_outOfBound, "Param out of bounds"); \ - } while (0) +#define BOUNDCHECK(cParam, val) { \ + RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ + parameter_outOfBound, "Param out of bounds"); \ +} static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) @@ -682,7 +468,6 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: - case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: @@ -692,17 +477,6 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_literalCompressionMode: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - case ZSTD_c_blockDelimiters: - case ZSTD_c_validateSequences: - case ZSTD_c_useBlockSplitter: - case ZSTD_c_useRowMatchFinder: - case ZSTD_c_deterministicRefPrefix: - case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableSeqProducerFallback: - case ZSTD_c_maxBlockSize: - case ZSTD_c_searchForExternalRepcodes: default: return 0; } @@ -715,7 +489,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) if (ZSTD_isUpdateAuthorized(param)) { cctx->cParamsChanged = 1; } else { - RETURN_ERROR(stage_wrong, "can only set params in cctx init stage"); + RETURN_ERROR(stage_wrong, "can only set params in ctx init stage"); } } switch(param) @@ -744,24 +518,12 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_jobSize: case ZSTD_c_overlapLog: case ZSTD_c_rsyncable: - case ZSTD_c_enableDedicatedDictSearch: case ZSTD_c_enableLongDistanceMatching: case ZSTD_c_ldmHashLog: case ZSTD_c_ldmMinMatch: case ZSTD_c_ldmBucketSizeLog: case ZSTD_c_targetCBlockSize: case ZSTD_c_srcSizeHint: - case ZSTD_c_stableInBuffer: - case ZSTD_c_stableOutBuffer: - case ZSTD_c_blockDelimiters: - case ZSTD_c_validateSequences: - case ZSTD_c_useBlockSplitter: - case ZSTD_c_useRowMatchFinder: - case ZSTD_c_deterministicRefPrefix: - case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableSeqProducerFallback: - case ZSTD_c_maxBlockSize: - case ZSTD_c_searchForExternalRepcodes: break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); @@ -782,10 +544,9 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_compressionLevel : { FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); - if (value == 0) - CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - else + if (value) { /* 0 : does not change current level */ CCtxParams->compressionLevel = value; + } if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; return 0; /* return type (size_t) cannot represent negative values */ } @@ -817,12 +578,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_minMatch : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_minMatch, value); - CCtxParams->cParams.minMatch = (U32)value; + CCtxParams->cParams.minMatch = value; return CCtxParams->cParams.minMatch; case ZSTD_c_targetLength : BOUNDCHECK(ZSTD_c_targetLength, value); - CCtxParams->cParams.targetLength = (U32)value; + CCtxParams->cParams.targetLength = value; return CCtxParams->cParams.targetLength; case ZSTD_c_strategy : @@ -835,12 +596,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Content size written in frame header _when known_ (default:1) */ DEBUGLOG(4, "set content size flag = %u", (value!=0)); CCtxParams->fParams.contentSizeFlag = value != 0; - return (size_t)CCtxParams->fParams.contentSizeFlag; + return CCtxParams->fParams.contentSizeFlag; case ZSTD_c_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ CCtxParams->fParams.checksumFlag = value != 0; - return (size_t)CCtxParams->fParams.checksumFlag; + return CCtxParams->fParams.checksumFlag; case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); @@ -849,18 +610,18 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_forceMaxWindow : CCtxParams->forceWindow = (value != 0); - return (size_t)CCtxParams->forceWindow; + return CCtxParams->forceWindow; case ZSTD_c_forceAttachDict : { const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; - BOUNDCHECK(ZSTD_c_forceAttachDict, (int)pref); + BOUNDCHECK(ZSTD_c_forceAttachDict, pref); CCtxParams->attachDictPref = pref; return CCtxParams->attachDictPref; } case ZSTD_c_literalCompressionMode : { - const ZSTD_paramSwitch_e lcm = (ZSTD_paramSwitch_e)value; - BOUNDCHECK(ZSTD_c_literalCompressionMode, (int)lcm); + const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; + BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); CCtxParams->literalCompressionMode = lcm; return CCtxParams->literalCompressionMode; } @@ -872,7 +633,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); CCtxParams->nbWorkers = value; - return (size_t)(CCtxParams->nbWorkers); + return CCtxParams->nbWorkers; #endif case ZSTD_c_jobSize : @@ -896,7 +657,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->overlapLog = value; - return (size_t)CCtxParams->overlapLog; + return CCtxParams->overlapLog; #endif case ZSTD_c_rsyncable : @@ -906,123 +667,60 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, #else FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); CCtxParams->rsyncable = value; - return (size_t)CCtxParams->rsyncable; + return CCtxParams->rsyncable; #endif - case ZSTD_c_enableDedicatedDictSearch : - CCtxParams->enableDedicatedDictSearch = (value!=0); - return (size_t)CCtxParams->enableDedicatedDictSearch; - case ZSTD_c_enableLongDistanceMatching : - BOUNDCHECK(ZSTD_c_enableLongDistanceMatching, value); - CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; + CCtxParams->ldmParams.enableLdm = (value!=0); return CCtxParams->ldmParams.enableLdm; case ZSTD_c_ldmHashLog : if (value!=0) /* 0 ==> auto */ BOUNDCHECK(ZSTD_c_ldmHashLog, value); - CCtxParams->ldmParams.hashLog = (U32)value; + CCtxParams->ldmParams.hashLog = value; return CCtxParams->ldmParams.hashLog; case ZSTD_c_ldmMinMatch : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmMinMatch, value); - CCtxParams->ldmParams.minMatchLength = (U32)value; + CCtxParams->ldmParams.minMatchLength = value; return CCtxParams->ldmParams.minMatchLength; case ZSTD_c_ldmBucketSizeLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); - CCtxParams->ldmParams.bucketSizeLog = (U32)value; + CCtxParams->ldmParams.bucketSizeLog = value; return CCtxParams->ldmParams.bucketSizeLog; case ZSTD_c_ldmHashRateLog : - if (value!=0) /* 0 ==> default */ - BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); - CCtxParams->ldmParams.hashRateLog = (U32)value; + RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, + parameter_outOfBound, "Param out of bounds!"); + CCtxParams->ldmParams.hashRateLog = value; return CCtxParams->ldmParams.hashRateLog; case ZSTD_c_targetCBlockSize : - if (value!=0) { /* 0 ==> default */ - value = MAX(value, ZSTD_TARGETCBLOCKSIZE_MIN); + if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_targetCBlockSize, value); - } - CCtxParams->targetCBlockSize = (U32)value; + CCtxParams->targetCBlockSize = value; return CCtxParams->targetCBlockSize; case ZSTD_c_srcSizeHint : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_srcSizeHint, value); CCtxParams->srcSizeHint = value; - return (size_t)CCtxParams->srcSizeHint; - - case ZSTD_c_stableInBuffer: - BOUNDCHECK(ZSTD_c_stableInBuffer, value); - CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; - return CCtxParams->inBufferMode; - - case ZSTD_c_stableOutBuffer: - BOUNDCHECK(ZSTD_c_stableOutBuffer, value); - CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; - return CCtxParams->outBufferMode; - - case ZSTD_c_blockDelimiters: - BOUNDCHECK(ZSTD_c_blockDelimiters, value); - CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; - return CCtxParams->blockDelimiters; - - case ZSTD_c_validateSequences: - BOUNDCHECK(ZSTD_c_validateSequences, value); - CCtxParams->validateSequences = value; - return (size_t)CCtxParams->validateSequences; - - case ZSTD_c_useBlockSplitter: - BOUNDCHECK(ZSTD_c_useBlockSplitter, value); - CCtxParams->useBlockSplitter = (ZSTD_paramSwitch_e)value; - return CCtxParams->useBlockSplitter; - - case ZSTD_c_useRowMatchFinder: - BOUNDCHECK(ZSTD_c_useRowMatchFinder, value); - CCtxParams->useRowMatchFinder = (ZSTD_paramSwitch_e)value; - return CCtxParams->useRowMatchFinder; - - case ZSTD_c_deterministicRefPrefix: - BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value); - CCtxParams->deterministicRefPrefix = !!value; - return (size_t)CCtxParams->deterministicRefPrefix; - - case ZSTD_c_prefetchCDictTables: - BOUNDCHECK(ZSTD_c_prefetchCDictTables, value); - CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; - return CCtxParams->prefetchCDictTables; - - case ZSTD_c_enableSeqProducerFallback: - BOUNDCHECK(ZSTD_c_enableSeqProducerFallback, value); - CCtxParams->enableMatchFinderFallback = value; - return (size_t)CCtxParams->enableMatchFinderFallback; - - case ZSTD_c_maxBlockSize: - if (value!=0) /* 0 ==> default */ - BOUNDCHECK(ZSTD_c_maxBlockSize, value); - CCtxParams->maxBlockSize = value; - return CCtxParams->maxBlockSize; - - case ZSTD_c_searchForExternalRepcodes: - BOUNDCHECK(ZSTD_c_searchForExternalRepcodes, value); - CCtxParams->searchForExternalRepcodes = (ZSTD_paramSwitch_e)value; - return CCtxParams->searchForExternalRepcodes; + return CCtxParams->srcSizeHint; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } } -size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) +size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) { return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); } size_t ZSTD_CCtxParams_getParameter( - ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) + ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) { switch(param) { @@ -1099,9 +797,6 @@ size_t ZSTD_CCtxParams_getParameter( *value = CCtxParams->rsyncable; break; #endif - case ZSTD_c_enableDedicatedDictSearch : - *value = CCtxParams->enableDedicatedDictSearch; - break; case ZSTD_c_enableLongDistanceMatching : *value = CCtxParams->ldmParams.enableLdm; break; @@ -1123,39 +818,6 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_srcSizeHint : *value = (int)CCtxParams->srcSizeHint; break; - case ZSTD_c_stableInBuffer : - *value = (int)CCtxParams->inBufferMode; - break; - case ZSTD_c_stableOutBuffer : - *value = (int)CCtxParams->outBufferMode; - break; - case ZSTD_c_blockDelimiters : - *value = (int)CCtxParams->blockDelimiters; - break; - case ZSTD_c_validateSequences : - *value = (int)CCtxParams->validateSequences; - break; - case ZSTD_c_useBlockSplitter : - *value = (int)CCtxParams->useBlockSplitter; - break; - case ZSTD_c_useRowMatchFinder : - *value = (int)CCtxParams->useRowMatchFinder; - break; - case ZSTD_c_deterministicRefPrefix: - *value = (int)CCtxParams->deterministicRefPrefix; - break; - case ZSTD_c_prefetchCDictTables: - *value = (int)CCtxParams->prefetchCDictTables; - break; - case ZSTD_c_enableSeqProducerFallback: - *value = CCtxParams->enableMatchFinderFallback; - break; - case ZSTD_c_maxBlockSize: - *value = (int)CCtxParams->maxBlockSize; - break; - case ZSTD_c_searchForExternalRepcodes: - *value = (int)CCtxParams->searchForExternalRepcodes; - break; default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); } return 0; @@ -1182,69 +844,25 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams( return 0; } -size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams) -{ - ZSTD_STATIC_ASSERT(sizeof(cparams) == 7 * 4 /* all params are listed below */); - DEBUGLOG(4, "ZSTD_CCtx_setCParams"); - /* only update if all parameters are valid */ - FORWARD_IF_ERROR(ZSTD_checkCParams(cparams), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, cparams.windowLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, cparams.chainLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, cparams.hashLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, cparams.searchLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, cparams.minMatch), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, cparams.targetLength), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, cparams.strategy), ""); - return 0; -} - -size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams) -{ - ZSTD_STATIC_ASSERT(sizeof(fparams) == 3 * 4 /* all params are listed below */); - DEBUGLOG(4, "ZSTD_CCtx_setFParams"); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, fparams.contentSizeFlag != 0), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, fparams.checksumFlag != 0), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, fparams.noDictIDFlag == 0), ""); - return 0; -} - -size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params) -{ - DEBUGLOG(4, "ZSTD_CCtx_setParams"); - /* First check cParams, because we want to update all or none. */ - FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - /* Next set fParams, because this could fail if the cctx isn't in init stage. */ - FORWARD_IF_ERROR(ZSTD_CCtx_setFParams(cctx, params.fParams), ""); - /* Finally set cParams, which should succeed. */ - FORWARD_IF_ERROR(ZSTD_CCtx_setCParams(cctx, params.cParams), ""); - return 0; -} - -size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) +ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) { - DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %llu bytes", pledgedSrcSize); + DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, "Can't set pledgedSrcSize when not in init stage."); cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; return 0; } -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( - int const compressionLevel, - size_t const dictSize); -static int ZSTD_dedicatedDictSearch_isSupported( - const ZSTD_compressionParameters* cParams); -static void ZSTD_dedicatedDictSearch_revertCParams( - ZSTD_compressionParameters* cParams); - /** - * Initializes the local dictionary using requested parameters. - * NOTE: Initialization does not employ the pledged src size, - * because the dictionary may be used for multiple compressions. + * Initializes the local dict using the requested parameters. + * NOTE: This does not use the pledged src size, because it may be used for more + * than one compression. */ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) { ZSTD_localDict* const dl = &cctx->localDict; + ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( + &cctx->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN, dl->dictSize); if (dl->dict == NULL) { /* No local dictionary. */ assert(dl->dictBuffer == NULL); @@ -1253,20 +871,20 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) return 0; } if (dl->cdict != NULL) { - /* Local dictionary already initialized. */ assert(cctx->cdict == dl->cdict); + /* Local dictionary already initialized. */ return 0; } assert(dl->dictSize > 0); assert(cctx->cdict == NULL); assert(cctx->prefixDict.dict == NULL); - dl->cdict = ZSTD_createCDict_advanced2( + dl->cdict = ZSTD_createCDict_advanced( dl->dict, dl->dictSize, ZSTD_dlm_byRef, dl->dictContentType, - &cctx->requestedParams, + cParams, cctx->customMem); RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); cctx->cdict = dl->cdict; @@ -1274,44 +892,39 @@ static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) } size_t ZSTD_CCtx_loadDictionary_advanced( - ZSTD_CCtx* cctx, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType) + ZSTD_CCtx* cctx, const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) { - DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't load a dictionary when cctx is not in init stage."); - ZSTD_clearAllDicts(cctx); /* erase any previously set dictionary */ - if (dict == NULL || dictSize == 0) /* no dictionary */ + "Can't load a dictionary when ctx is not in init stage."); + RETURN_ERROR_IF(cctx->staticSize, memory_allocation, + "no malloc for static CCtx"); + DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); + ZSTD_clearAllDicts(cctx); /* in case one already exists */ + if (dict == NULL || dictSize == 0) /* no dictionary mode */ return 0; if (dictLoadMethod == ZSTD_dlm_byRef) { cctx->localDict.dict = dict; } else { - /* copy dictionary content inside CCtx to own its lifetime */ - void* dictBuffer; - RETURN_ERROR_IF(cctx->staticSize, memory_allocation, - "static CCtx can't allocate for an internal copy of dictionary"); - dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); - RETURN_ERROR_IF(dictBuffer==NULL, memory_allocation, - "allocation failed for dictionary content"); - ZSTD_memcpy(dictBuffer, dict, dictSize); - cctx->localDict.dictBuffer = dictBuffer; /* owned ptr to free */ - cctx->localDict.dict = dictBuffer; /* read-only reference */ + void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); + RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!"); + memcpy(dictBuffer, dict, dictSize); + cctx->localDict.dictBuffer = dictBuffer; + cctx->localDict.dict = dictBuffer; } cctx->localDict.dictSize = dictSize; cctx->localDict.dictContentType = dictContentType; return 0; } -size_t ZSTD_CCtx_loadDictionary_byReference( +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); } -size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) { return ZSTD_CCtx_loadDictionary_advanced( cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); @@ -1328,14 +941,6 @@ size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) return 0; } -size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) -{ - RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Can't ref a pool when ctx not in init stage."); - cctx->pool = pool; - return 0; -} - size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) { return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); @@ -1367,7 +972,7 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, - "Reset parameters is only possible during init stage."); + "Can't reset parameters only when not in init stage."); ZSTD_clearAllDicts(cctx); return ZSTD_CCtxParams_reset(&cctx->requestedParams); } @@ -1396,12 +1001,11 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams) { -# define CLAMP_TYPE(cParam, val, type) \ - do { \ - ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ - if ((int)valbounds.upperBound) val=(type)bounds.upperBound; \ - } while (0) +# define CLAMP_TYPE(cParam, val, type) { \ + ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ + if ((int)valbounds.upperBound) val=(type)bounds.upperBound; \ + } # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) CLAMP(ZSTD_c_windowLog, cParams.windowLog); CLAMP(ZSTD_c_chainLog, cParams.chainLog); @@ -1421,183 +1025,42 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) return hashLog - btScale; } -/** ZSTD_dictAndWindowLog() : - * Returns an adjusted window log that is large enough to fit the source and the dictionary. - * The zstd format says that the entire dictionary is valid if one byte of the dictionary - * is within the window. So the hashLog and chainLog should be large enough to reference both - * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing - * the hashLog and windowLog. - * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. - */ -static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) -{ - const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; - /* No dictionary ==> No change */ - if (dictSize == 0) { - return windowLog; - } - assert(windowLog <= ZSTD_WINDOWLOG_MAX); - assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ - { - U64 const windowSize = 1ULL << windowLog; - U64 const dictAndWindowSize = dictSize + windowSize; - /* If the window size is already large enough to fit both the source and the dictionary - * then just use the window size. Otherwise adjust so that it fits the dictionary and - * the window. - */ - if (windowSize >= dictSize + srcSize) { - return windowLog; /* Window size large enough already */ - } else if (dictAndWindowSize >= maxWindowSize) { - return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ - } else { - return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; - } - } -} - /** ZSTD_adjustCParams_internal() : * optimize `cPar` for a specified input (`srcSize` and `dictSize`). * mostly downsize to reduce memory consumption and initialization latency. * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. - * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. * note : `srcSize==0` means 0! * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ static ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, - size_t dictSize, - ZSTD_cParamMode_e mode, - ZSTD_paramSwitch_e useRowMatchFinder) + size_t dictSize) { - const U64 minSrcSize = 513; /* (1<<9) + 1 */ - const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); + static const U64 minSrcSize = 513; /* (1<<9) + 1 */ + static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); assert(ZSTD_checkCParams(cPar)==0); - /* Cascade the selected strategy down to the next-highest one built into - * this binary. */ -#ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btultra2) { - cPar.strategy = ZSTD_btultra; - } - if (cPar.strategy == ZSTD_btultra) { - cPar.strategy = ZSTD_btopt; - } -#endif -#ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btopt) { - cPar.strategy = ZSTD_btlazy2; - } -#endif -#ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btlazy2) { - cPar.strategy = ZSTD_lazy2; - } -#endif -#ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_lazy2) { - cPar.strategy = ZSTD_lazy; - } -#endif -#ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_lazy) { - cPar.strategy = ZSTD_greedy; - } -#endif -#ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_greedy) { - cPar.strategy = ZSTD_dfast; - } -#endif -#ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_dfast) { - cPar.strategy = ZSTD_fast; - cPar.targetLength = 0; - } -#endif - - switch (mode) { - case ZSTD_cpm_unknown: - case ZSTD_cpm_noAttachDict: - /* If we don't know the source size, don't make any - * assumptions about it. We will already have selected - * smaller parameters if a dictionary is in use. - */ - break; - case ZSTD_cpm_createCDict: - /* Assume a small source size when creating a dictionary - * with an unknown source size. - */ - if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) - srcSize = minSrcSize; - break; - case ZSTD_cpm_attachDict: - /* Dictionary has its own dedicated parameters which have - * already been selected. We are selecting parameters - * for only the source. - */ - dictSize = 0; - break; - default: - assert(0); - break; - } + if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) + srcSize = minSrcSize; /* resize windowLog if input is small enough, to use less memory */ - if ( (srcSize <= maxWindowResize) - && (dictSize <= maxWindowResize) ) { + if ( (srcSize < maxWindowResize) + && (dictSize < maxWindowResize) ) { U32 const tSize = (U32)(srcSize + dictSize); static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : ZSTD_highbit32(tSize-1) + 1; if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; } - if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); - U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; - if (cycleLog > dictAndWindowLog) - cPar.chainLog -= (cycleLog - dictAndWindowLog); + if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; + { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); + if (cycleLog > cPar.windowLog) + cPar.chainLog -= (cycleLog - cPar.windowLog); } if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ - /* We can't use more than 32 bits of hash in total, so that means that we require: - * (hashLog + 8) <= 32 && (chainLog + 8) <= 32 - */ - if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { - U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; - if (cPar.hashLog > maxShortCacheHashLog) { - cPar.hashLog = maxShortCacheHashLog; - } - if (cPar.chainLog > maxShortCacheHashLog) { - cPar.chainLog = maxShortCacheHashLog; - } - } - - - /* At this point, we aren't 100% sure if we are using the row match finder. - * Unless it is explicitly disabled, conservatively assume that it is enabled. - * In this case it will only be disabled for small sources, so shrinking the - * hash log a little bit shouldn't result in any ratio loss. - */ - if (useRowMatchFinder == ZSTD_ps_auto) - useRowMatchFinder = ZSTD_ps_enable; - - /* We can't hash more than 32-bits in total. So that means that we require: - * (hashLog - rowLog + 8) <= 32 - */ - if (ZSTD_rowMatchFinderUsed(cPar.strategy, useRowMatchFinder)) { - /* Switch to 32-entry rows if searchLog is 5 (or more) */ - U32 const rowLog = BOUNDED(4, cPar.searchLog, 6); - U32 const maxRowHashLog = 32 - ZSTD_ROW_HASH_TAG_BITS; - U32 const maxHashLog = maxRowHashLog + rowLog; - assert(cPar.hashLog >= rowLog); - if (cPar.hashLog > maxHashLog) { - cPar.hashLog = maxHashLog; - } - } - return cPar; } @@ -1608,50 +1071,38 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar, { cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); + return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); } -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); - -static void ZSTD_overrideCParams( - ZSTD_compressionParameters* cParams, - const ZSTD_compressionParameters* overrides) -{ - if (overrides->windowLog) cParams->windowLog = overrides->windowLog; - if (overrides->hashLog) cParams->hashLog = overrides->hashLog; - if (overrides->chainLog) cParams->chainLog = overrides->chainLog; - if (overrides->searchLog) cParams->searchLog = overrides->searchLog; - if (overrides->minMatch) cParams->minMatch = overrides->minMatch; - if (overrides->targetLength) cParams->targetLength = overrides->targetLength; - if (overrides->strategy) cParams->strategy = overrides->strategy; -} +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize); +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize); ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) { ZSTD_compressionParameters cParams; if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { srcSizeHint = CCtxParams->srcSizeHint; } - cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); - if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; - ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); + cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize); + if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; + if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; + if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; + if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; + if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; + if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; + if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; + if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; assert(!ZSTD_checkCParams(cParams)); /* srcSizeHint == 0 means 0 */ - return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder); + return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); } static size_t ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, - const ZSTD_paramSwitch_e useRowMatchFinder, - const U32 enableDedicatedDictSearch, const U32 forCCtx) { - /* chain table size should be 0 for fast or row-hash strategies */ - size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx) - ? ((size_t)1 << cParams->chainLog) - : 0; + size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; @@ -1661,131 +1112,71 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, + hSize * sizeof(U32) + h3Size * sizeof(U32); size_t const optPotentialSpace = - ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32)) - + ZSTD_cwksp_aligned_alloc_size((1<strategy, useRowMatchFinder) - ? ZSTD_cwksp_aligned_alloc_size(hSize) - : 0; + ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) + + ZSTD_cwksp_alloc_size((1<strategy >= ZSTD_btopt)) ? optPotentialSpace : 0; - size_t const slackSpace = ZSTD_cwksp_slack_space_required(); - - /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */ - ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4); - assert(useRowMatchFinder != ZSTD_ps_auto); - DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", (U32)chainSize, (U32)hSize, (U32)h3Size); - return tableSpace + optSpace + slackSpace + lazyAdditionalSpace; -} - -/* Helper function for calculating memory requirements. - * Gives a tighter bound than ZSTD_sequenceBound() by taking minMatch into account. */ -static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequenceProducer) { - U32 const divider = (minMatch==3 || useSequenceProducer) ? 3 : 4; - return blockSize / divider; -} - -static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( - const ZSTD_compressionParameters* cParams, - const ldmParams_t* ldmParams, - const int isStatic, - const ZSTD_paramSwitch_e useRowMatchFinder, - const size_t buffInSize, - const size_t buffOutSize, - const U64 pledgedSrcSize, - int useSequenceProducer, - size_t maxBlockSize) -{ - size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); - size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) - + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) - + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); - size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); - size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); - - size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); - size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? - ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; - - - size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) - + ZSTD_cwksp_alloc_size(buffOutSize); - - size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; - - size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); - size_t const externalSeqSpace = useSequenceProducer - ? ZSTD_cwksp_aligned_alloc_size(maxNbExternalSeq * sizeof(ZSTD_Sequence)) - : 0; - - size_t const neededSpace = - cctxSpace + - entropySpace + - blockStateSpace + - ldmSpace + - ldmSeqSpace + - matchStateSize + - tokenSpace + - bufferSpace + - externalSeqSpace; - - DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); - return neededSpace; + return tableSpace + optSpace; } size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, - &cParams); - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); - /* estimateCCtxSize is for one-shot compression. So no buffers should - * be needed. However, we still allocate two 0-sized buffers, which can - * take space under ASAN. */ - return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + { ZSTD_compressionParameters const cParams = + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + U32 const divider = (cParams.minMatch==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); + + size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); + size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq)); + + /* estimateCCtxSize is for one-shot compression. So no buffers should + * be needed. However, we still allocate two 0-sized buffers, which can + * take space under ASAN. */ + size_t const bufferSpace = ZSTD_cwksp_alloc_size(0) + + ZSTD_cwksp_alloc_size(0); + + size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)); + + size_t const neededSpace = + cctxSpace + + entropySpace + + blockStateSpace + + ldmSpace + + ldmSeqSpace + + matchStateSize + + tokenSpace + + bufferSpace; + + DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); + return neededSpace; + } } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { - /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ - size_t noRowCCtxSize; - size_t rowCCtxSize; - initialParams.useRowMatchFinder = ZSTD_ps_disable; - noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - initialParams.useRowMatchFinder = ZSTD_ps_enable; - rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - return MAX(noRowCCtxSize, rowCCtxSize); - } else { - return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); - } + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); } static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) { - int tier = 0; - size_t largestSize = 0; - static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; - for (; tier < 4; ++tier) { - /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); - largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); - } - return largestSize; + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); + return ZSTD_estimateCCtxSize_usingCParams(cParams); } size_t ZSTD_estimateCCtxSize(int compressionLevel) @@ -1793,7 +1184,6 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) int level; size_t memBudget = 0; for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { - /* Ensure monotonically increasing memory usage as compression level increases */ size_t const newMB = ZSTD_estimateCCtxSize_internal(level); if (newMB > memBudget) memBudget = newMB; } @@ -1804,42 +1194,27 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) { RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); - size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) - ? ((size_t)1 << cParams.windowLog) + blockSize - : 0; - size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) - ? ZSTD_compressBound(blockSize) + 1 - : 0; - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); - - return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, - ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0); + size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); + size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; + size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; + size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize) + + ZSTD_cwksp_alloc_size(outBuffSize); + + return CCtxSize + streamingSize; } } size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { - /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ - size_t noRowCCtxSize; - size_t rowCCtxSize; - initialParams.useRowMatchFinder = ZSTD_ps_disable; - noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - initialParams.useRowMatchFinder = ZSTD_ps_enable; - rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - return MAX(noRowCCtxSize, rowCCtxSize); - } else { - return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); - } + ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); } static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0); return ZSTD_estimateCStreamSize_usingCParams(cParams); } @@ -1911,7 +1286,7 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) { int i; for (i = 0; i < ZSTD_REP_NUM; ++i) - bs->rep[i] = repStartValue[i]; + bs->rep[i] = ZSTDInternalConstants::repStartValue[i]; bs->entropy.huf.repeatMode = HUF_repeat_none; bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; @@ -1932,6 +1307,16 @@ static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) ms->dictMatchState = NULL; } +/** + * Indicates whether this compression proceeds directly from user-provided + * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or + * whether the context needs to buffer the input/output (ZSTDb_buffered). + */ +typedef enum { + ZSTDb_not_buffered, + ZSTDb_buffered +} ZSTD_buffered_policy_e; + /** * Controls, for this matchState reset, whether the tables need to be cleared / * prepared for the coming compression (ZSTDcrp_makeClean), or whether the @@ -1959,47 +1344,26 @@ typedef enum { ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; -/* Mixes bits in a 64 bits in a value, based on XXH3_rrmxmx */ -static U64 ZSTD_bitmix(U64 val, U64 len) { - val ^= ZSTD_rotateRight_U64(val, 49) ^ ZSTD_rotateRight_U64(val, 24); - val *= 0x9FB21C651E98DF25ULL; - val ^= (val >> 35) + len ; - val *= 0x9FB21C651E98DF25ULL; - return val ^ (val >> 28); -} - -/* Mixes in the hashSalt and hashSaltEntropy to create a new hashSalt */ -static void ZSTD_advanceHashSalt(ZSTD_matchState_t* ms) { - ms->hashSalt = ZSTD_bitmix(ms->hashSalt, 8) ^ ZSTD_bitmix((U64) ms->hashSaltEntropy, 4); -} - static size_t ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, const ZSTD_compressionParameters* cParams, - const ZSTD_paramSwitch_e useRowMatchFinder, const ZSTD_compResetPolicy_e crp, const ZSTD_indexResetPolicy_e forceResetIndex, const ZSTD_resetTarget_e forWho) { - /* disable chain table allocation for fast or row-based strategies */ - size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, - ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) - ? ((size_t)1 << cParams->chainLog) - : 0; + size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); size_t const hSize = ((size_t)1) << cParams->hashLog; U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); - assert(useRowMatchFinder != ZSTD_ps_auto); if (forceResetIndex == ZSTDirp_reset) { ZSTD_window_init(&ms->window); ZSTD_cwksp_mark_tables_dirty(ws); } ms->hashLog3 = hashLog3; - ms->lazySkipping = 0; ZSTD_invalidateMatchState(ms); @@ -2021,27 +1385,6 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ZSTD_cwksp_clean_tables(ws); } - if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) { - /* Row match finder needs an additional table of hashes ("tags") */ - size_t const tagTableSize = hSize; - /* We want to generate a new salt in case we reset a Cctx, but we always want to use - * 0 when we reset a Cdict */ - if(forWho == ZSTD_resetTarget_CCtx) { - ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned_init_once(ws, tagTableSize); - ZSTD_advanceHashSalt(ms); - } else { - /* When we are not salting we want to always memset the memory */ - ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned(ws, tagTableSize); - ZSTD_memset(ms->tagTable, 0, tagTableSize); - ms->hashSalt = 0; - } - { /* Switch to 32-entry rows if searchLog is 5 (or more) */ - U32 const rowLog = BOUNDED(4, cParams->searchLog, 6); - assert(cParams->hashLog >= rowLog); - ms->rowHashLog = cParams->hashLog - rowLog; - } - } - /* opt parser space */ if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { DEBUGLOG(4, "reserving optimal parser space"); @@ -2049,14 +1392,15 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms, ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned)); ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned)); ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned)); - ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_match_t)); - ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t)); + ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)); + ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); } ms->cParams = *cParams; RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, "failed a workspace allocation in ZSTD_reset_matchState"); + return 0; } @@ -2073,86 +1417,75 @@ static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); } -/** ZSTD_dictTooBig(): - * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in - * one go generically. So we ensure that in that case we reset the tables to zero, - * so that we can load as much of the dictionary as possible. - */ -static int ZSTD_dictTooBig(size_t const loadedDictSize) -{ - return loadedDictSize > ZSTD_CHUNKSIZE_MAX; -} - /*! ZSTD_resetCCtx_internal() : - * @param loadedDictSize The size of the dictionary to be loaded - * into the context, if any. If no dictionary is used, or the - * dictionary is being attached / copied, then pass 0. - * note : `params` are assumed fully validated at this stage. - */ + note : `params` are assumed fully validated at this stage */ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, - ZSTD_CCtx_params const* params, + ZSTD_CCtx_params params, U64 const pledgedSrcSize, - size_t const loadedDictSize, ZSTD_compResetPolicy_e const crp, ZSTD_buffered_policy_e const zbuff) { ZSTD_cwksp* const ws = &zc->workspace; - DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", - (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->useBlockSplitter); - assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); + DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", + (U32)pledgedSrcSize, params.cParams.windowLog); + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); zc->isFirstBlock = 1; - /* Set applied params early so we can modify them for LDM, - * and point params at the applied params. - */ - zc->appliedParams = *params; - params = &zc->appliedParams; - - assert(params->useRowMatchFinder != ZSTD_ps_auto); - assert(params->useBlockSplitter != ZSTD_ps_auto); - assert(params->ldmParams.enableLdm != ZSTD_ps_auto); - assert(params->maxBlockSize != 0); - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { /* Adjust long distance matching parameters */ - ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); - assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); - assert(params->ldmParams.hashRateLog < 32); - } - - { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); - size_t const blockSize = MIN(params->maxBlockSize, windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, ZSTD_hasExtSeqProd(params)); - size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) - ? ZSTD_compressBound(blockSize) + 1 - : 0; - size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered) - ? windowSize + blockSize - : 0; - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); - - int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); - int const dictTooBig = ZSTD_dictTooBig(loadedDictSize); - ZSTD_indexResetPolicy_e needsIndexReset = - (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue; - - size_t const neededSpace = - ZSTD_estimateCCtxSize_usingCCtxParams_internal( - ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, - buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize); - - FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); + ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); + assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); + assert(params.ldmParams.hashRateLog < 32); + zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); + } + + { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); + size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); + U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; + size_t const maxNbSeq = blockSize / divider; + size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) + + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); + size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; + size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; + size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); + + ZSTD_indexResetPolicy_e needsIndexReset = zc->initialized ? ZSTDirp_continue : ZSTDirp_reset; + + if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { + needsIndexReset = ZSTDirp_reset; + } if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); - { /* Check if workspace is large enough, alloc a new one if needed */ + /* Check if workspace is large enough, alloc a new one if needed */ + { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; + size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); + size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); + size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize); + size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); + size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)); + + size_t const neededSpace = + cctxSpace + + entropySpace + + blockStateSpace + + ldmSpace + + ldmSeqSpace + + matchStateSize + + tokenSpace + + bufferSpace; + int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); - int resizeWorkspace = workspaceTooSmall || workspaceWasteful; - DEBUGLOG(4, "Need %zu B workspace", neededSpace); + + DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", + neededSpace>>10, matchStateSize>>10, bufferSpace>>10); DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); - if (resizeWorkspace) { + if (workspaceTooSmall || workspaceWasteful) { DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", ZSTD_cwksp_sizeof(ws) >> 10, neededSpace >> 10); @@ -2173,15 +1506,15 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); - zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); - RETURN_ERROR_IF(zc->entropyWorkspace == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); + zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE); + RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); } } ZSTD_cwksp_clear(ws); /* init params */ - zc->blockState.matchState.cParams = params->cParams; - zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; + zc->appliedParams = params; + zc->blockState.matchState.cParams = params.cParams; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; zc->producedCSize = 0; @@ -2194,64 +1527,29 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, XXH64_reset(&zc->xxhState, 0); zc->stage = ZSTDcs_init; zc->dictID = 0; - zc->dictContentSize = 0; ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); - FORWARD_IF_ERROR(ZSTD_reset_matchState( - &zc->blockState.matchState, - ws, - ¶ms->cParams, - params->useRowMatchFinder, - crp, - needsIndexReset, - ZSTD_resetTarget_CCtx), ""); - - zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); - - /* ldm hash table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* TODO: avoid memset? */ - size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; - zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); - ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); - zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); - zc->maxNbLdmSequences = maxNbLdmSeq; - - ZSTD_window_init(&zc->ldmState.window); - zc->ldmState.loadedDictEnd = 0; - } - - /* reserve space for block-level external sequences */ - if (ZSTD_hasExtSeqProd(params)) { - size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); - zc->extSeqBufCapacity = maxNbExternalSeq; - zc->extSeqBuf = - (ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); - } - - /* buffers */ - /* ZSTD_wildcopy() is used to copy into the literals buffer, * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. */ zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); zc->seqStore.maxNbLit = blockSize; - zc->bufferedPolicy = zbuff; + /* buffers */ zc->inBuffSize = buffInSize; zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); zc->outBuffSize = buffOutSize; zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); /* ldm bucketOffsets table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + if (params.ldmParams.enableLdm) { /* TODO: avoid memset? */ - size_t const numBuckets = - ((size_t)1) << (params->ldmParams.hashLog - - params->ldmParams.bucketSizeLog); - zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); - ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); + size_t const ldmBucketSize = + ((size_t)1) << (params.ldmParams.hashLog - + params.ldmParams.bucketSizeLog); + zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize); + memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize); } /* sequences storage */ @@ -2260,14 +1558,35 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); + zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); - DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); - assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace)); + FORWARD_IF_ERROR(ZSTD_reset_matchState( + &zc->blockState.matchState, + ws, + ¶ms.cParams, + crp, + needsIndexReset, + ZSTD_resetTarget_CCtx), ""); - zc->initialized = 1; + /* ldm hash table */ + if (params.ldmParams.enableLdm) { + /* TODO: avoid memset? */ + size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; + zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); + memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); + zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); + zc->maxNbLdmSequences = maxNbLdmSeq; - return 0; - } + ZSTD_window_init(&zc->ldmState.window); + ZSTD_window_clear(&zc->ldmState.window); + zc->ldmState.loadedDictEnd = 0; + } + + DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); + zc->initialized = 1; + + return 0; + } } /* ZSTD_invalidateRepCodes() : @@ -2302,14 +1621,12 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, U64 pledgedSrcSize) { size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; - int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; - return dedicatedDictSearch - || ( ( pledgedSrcSize <= cutoff - || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || params->attachDictPref == ZSTD_dictForceAttach ) - && params->attachDictPref != ZSTD_dictForceCopy - && !params->forceWindow ); /* dictMatchState isn't correctly - * handled in _enforceMaxDist */ + return ( pledgedSrcSize <= cutoff + || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN + || params->attachDictPref == ZSTD_dictForceAttach ) + && params->attachDictPref != ZSTD_dictForceCopy + && !params->forceWindow; /* dictMatchState isn't correctly + * handled in _enforceMaxDist */ } static size_t @@ -2319,29 +1636,17 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", - (unsigned long long)pledgedSrcSize); - { - ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; + { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Resize working context table params for input only, since the dict * has its own tables. */ - /* pledgedSrcSize == 0 means 0! */ - - if (cdict->matchState.dedicatedDictSearch) { - ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); - } - - params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, - cdict->dictContentSize, ZSTD_cpm_attachDict, - params.useRowMatchFinder); + /* pledgeSrcSize == 0 means 0! */ + params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, ZSTDcrp_makeClean, zbuff), ""); - assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); + assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); } { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc @@ -2366,30 +1671,13 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, } } cctx->dictID = cdict->dictID; - cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } -static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize, - ZSTD_compressionParameters const* cParams) { - if (ZSTD_CDictIndicesAreTagged(cParams)){ - /* Remove tags from the CDict table if they are present. - * See docs on "short cache" in zstd_compress_internal.h for context. */ - size_t i; - for (i = 0; i < tableSize; i++) { - U32 const taggedIndex = src[i]; - U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS; - dst[i] = index; - } - } else { - ZSTD_memcpy(dst, src, tableSize * sizeof(U32)); - } -} - static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, ZSTD_CCtx_params params, @@ -2398,18 +1686,14 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, { const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; - assert(!cdict->matchState.dedicatedDictSearch); - DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", - (unsigned long long)pledgedSrcSize); + DEBUGLOG(4, "copying dictionary into context"); { unsigned const windowLog = params.cParams.windowLog; assert(windowLog != 0); /* Copy only compression parameters related to tables. */ params.cParams = *cdict_cParams; params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; - FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, + FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, ZSTDcrp_leaveDirty, zbuff), ""); assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); @@ -2417,39 +1701,24 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); - assert(params.useRowMatchFinder != ZSTD_ps_auto); /* copy tables */ - { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) - ? ((size_t)1 << cdict_cParams->chainLog) - : 0; + { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); size_t const hSize = (size_t)1 << cdict_cParams->hashLog; - ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.hashTable, - cdict->matchState.hashTable, - hSize, cdict_cParams); - - /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */ - if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) { - ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.chainTable, - cdict->matchState.chainTable, - chainSize, cdict_cParams); - } - /* copy tag table */ - if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { - size_t const tagTableSize = hSize; - ZSTD_memcpy(cctx->blockState.matchState.tagTable, - cdict->matchState.tagTable, - tagTableSize); - cctx->blockState.matchState.hashSalt = cdict->matchState.hashSalt; - } + memcpy(cctx->blockState.matchState.hashTable, + cdict->matchState.hashTable, + hSize * sizeof(U32)); + memcpy(cctx->blockState.matchState.chainTable, + cdict->matchState.chainTable, + chainSize * sizeof(U32)); } /* Zero the hashTable3, since the cdict never fills it */ { int const h3log = cctx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; assert(cdict->matchState.hashLog3 == 0); - ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); + memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); } ZSTD_cwksp_mark_tables_clean(&cctx->workspace); @@ -2463,10 +1732,9 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, } cctx->dictID = cdict->dictID; - cctx->dictContentSize = cdict->dictContentSize; /* copy block state */ - ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); + memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); return 0; } @@ -2506,23 +1774,16 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { + DEBUGLOG(5, "ZSTD_copyCCtx_internal"); RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, "Can't copy a ctx that's not in init stage."); - DEBUGLOG(5, "ZSTD_copyCCtx_internal"); - ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); + + memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); { ZSTD_CCtx_params params = dstCCtx->requestedParams; /* Copy only compression parameters related to tables. */ params.cParams = srcCCtx->appliedParams.cParams; - assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); - assert(srcCCtx->appliedParams.useBlockSplitter != ZSTD_ps_auto); - assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); - params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder; - params.useBlockSplitter = srcCCtx->appliedParams.useBlockSplitter; - params.ldmParams = srcCCtx->appliedParams.ldmParams; params.fParams = fParams; - params.maxBlockSize = srcCCtx->appliedParams.maxBlockSize; - ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize, - /* loadedDictSize */ 0, + ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_leaveDirty, zbuff); assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); @@ -2534,22 +1795,18 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); /* copy tables */ - { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy, - srcCCtx->appliedParams.useRowMatchFinder, - 0 /* forDDSDict */) - ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog) - : 0; + { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; int const h3log = srcCCtx->blockState.matchState.hashLog3; size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; - ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, + memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, hSize * sizeof(U32)); - ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, + memcpy(dstCCtx->blockState.matchState.chainTable, srcCCtx->blockState.matchState.chainTable, chainSize * sizeof(U32)); - ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, + memcpy(dstCCtx->blockState.matchState.hashTable3, srcCCtx->blockState.matchState.hashTable3, h3Size * sizeof(U32)); } @@ -2565,10 +1822,9 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; } dstCCtx->dictID = srcCCtx->dictID; - dstCCtx->dictContentSize = srcCCtx->dictContentSize; /* copy block state */ - ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); + memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); return 0; } @@ -2581,7 +1837,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) { ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; + ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); @@ -2605,25 +1861,31 @@ ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerVa int const nbRows = (int)size / ZSTD_ROWSIZE; int cellNb = 0; int rowNb; - /* Protect special index values < ZSTD_WINDOW_START_INDEX. */ - U32 const reducerThreshold = reducerValue + ZSTD_WINDOW_START_INDEX; assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ assert(size < (1U<<31)); /* can be casted to int */ +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) + /* To validate that the table re-use logic is sound, and that we don't + * access table space that we haven't cleaned, we re-"poison" the table + * space every time we mark it dirty. + * + * This function however is intended to operate on those dirty tables and + * re-clean them. So when this function is used correctly, we can unpoison + * the memory it operated on. This introduces a blind spot though, since + * if we now try to operate on __actually__ poisoned memory, we will not + * detect that. */ + __msan_unpoison(table, size * sizeof(U32)); +#endif + for (rowNb=0 ; rowNb < nbRows ; rowNb++) { int column; for (column=0; columnhashTable, hSize, reducerValue); } - if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { + if (params->cParams.strategy != ZSTD_fast) { U32 const chainSize = (U32)1 << params->cParams.chainLog; if (params->cParams.strategy == ZSTD_btlazy2) ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); @@ -2667,7 +1929,7 @@ static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* par /* See doc/zstd_compression_format.md for detailed format description */ -int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) { const seqDef* const sequences = seqStorePtr->sequencesStart; BYTE* const llCodeTable = seqStorePtr->llCode; @@ -2675,24 +1937,18 @@ int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) BYTE* const mlCodeTable = seqStorePtr->mlCode; U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); U32 u; - int longOffsets = 0; assert(nbSeq <= seqStorePtr->maxNbSeq); for (u=0; u= STREAM_ACCUMULATOR_MIN)); - if (MEM_32bits() && ofCode >= STREAM_ACCUMULATOR_MIN) - longOffsets = 1; } - if (seqStorePtr->longLengthType==ZSTD_llt_literalLength) + if (seqStorePtr->longLengthID==1) llCodeTable[seqStorePtr->longLengthPos] = MaxLL; - if (seqStorePtr->longLengthType==ZSTD_llt_matchLength) + if (seqStorePtr->longLengthID==2) mlCodeTable[seqStorePtr->longLengthPos] = MaxML; - return longOffsets; } /* ZSTD_useTargetCBlockSize(): @@ -2705,211 +1961,49 @@ static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) return (cctxParams->targetCBlockSize != 0); } -/* ZSTD_blockSplitterEnabled(): - * Returns if block splitting param is being used - * If used, compression will do best effort to split a block in order to improve compression ratio. - * At the time this function is called, the parameter must be finalized. - * Returns 1 if true, 0 otherwise. */ -static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams) -{ - DEBUGLOG(5, "ZSTD_blockSplitterEnabled (useBlockSplitter=%d)", cctxParams->useBlockSplitter); - assert(cctxParams->useBlockSplitter != ZSTD_ps_auto); - return (cctxParams->useBlockSplitter == ZSTD_ps_enable); -} - -/* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types - * and size of the sequences statistics - */ -typedef struct { - U32 LLtype; - U32 Offtype; - U32 MLtype; - size_t size; - size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ - int longOffsets; -} ZSTD_symbolEncodingTypeStats_t; - -/* ZSTD_buildSequencesStatistics(): - * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field. - * Modifies `nextEntropy` to have the appropriate values as a side effect. - * nbSeq must be greater than 0. - * - * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32) - */ -static ZSTD_symbolEncodingTypeStats_t -ZSTD_buildSequencesStatistics( - const seqStore_t* seqStorePtr, size_t nbSeq, - const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy, - BYTE* dst, const BYTE* const dstEnd, - ZSTD_strategy strategy, unsigned* countWorkspace, - void* entropyWorkspace, size_t entropyWkspSize) -{ - BYTE* const ostart = dst; - const BYTE* const oend = dstEnd; - BYTE* op = ostart; - FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; - FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; - FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; - const BYTE* const ofCodeTable = seqStorePtr->ofCode; - const BYTE* const llCodeTable = seqStorePtr->llCode; - const BYTE* const mlCodeTable = seqStorePtr->mlCode; - ZSTD_symbolEncodingTypeStats_t stats; - - stats.lastCountSize = 0; - /* convert length/distances into codes */ - stats.longOffsets = ZSTD_seqToCodes(seqStorePtr); - assert(op <= oend); - assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */ - /* build CTable for Literal Lengths */ - { unsigned max = MaxLL; - size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building LL table"); - nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; - stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - LLFSELog, prevEntropy->litlengthCTable, - LL_defaultNorm, LL_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(set_basic < set_compressed && set_rle < set_compressed); - assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype, - countWorkspace, max, llCodeTable, nbSeq, - LL_defaultNorm, LL_defaultNormLog, MaxLL, - prevEntropy->litlengthCTable, - sizeof(prevEntropy->litlengthCTable), - entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed"); - stats.size = countSize; - return stats; - } - if (stats.LLtype == set_compressed) - stats.lastCountSize = countSize; - op += countSize; - assert(op <= oend); - } } - /* build CTable for Offsets */ - { unsigned max = MaxOff; - size_t const mostFrequent = HIST_countFast_wksp( - countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ - ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; - DEBUGLOG(5, "Building OF table"); - nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; - stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - OffFSELog, prevEntropy->offcodeCTable, - OF_defaultNorm, OF_defaultNormLog, - defaultPolicy, strategy); - assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype, - countWorkspace, max, ofCodeTable, nbSeq, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - prevEntropy->offcodeCTable, - sizeof(prevEntropy->offcodeCTable), - entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed"); - stats.size = countSize; - return stats; - } - if (stats.Offtype == set_compressed) - stats.lastCountSize = countSize; - op += countSize; - assert(op <= oend); - } } - /* build CTable for MatchLengths */ - { unsigned max = MaxML; - size_t const mostFrequent = HIST_countFast_wksp( - countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ - DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); - nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; - stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, - countWorkspace, max, mostFrequent, nbSeq, - MLFSELog, prevEntropy->matchlengthCTable, - ML_defaultNorm, ML_defaultNormLog, - ZSTD_defaultAllowed, strategy); - assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ - { size_t const countSize = ZSTD_buildCTable( - op, (size_t)(oend - op), - CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype, - countWorkspace, max, mlCodeTable, nbSeq, - ML_defaultNorm, ML_defaultNormLog, MaxML, - prevEntropy->matchlengthCTable, - sizeof(prevEntropy->matchlengthCTable), - entropyWorkspace, entropyWkspSize); - if (ZSTD_isError(countSize)) { - DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed"); - stats.size = countSize; - return stats; - } - if (stats.MLtype == set_compressed) - stats.lastCountSize = countSize; - op += countSize; - assert(op <= oend); - } } - stats.size = (size_t)(op-ostart); - return stats; -} - -/* ZSTD_entropyCompressSeqStore_internal(): - * compresses both literals and sequences - * Returns compressed size of block, or a zstd error. - */ -#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20 +/* ZSTD_compressSequences_internal(): + * actually compresses both literals and sequences */ MEM_STATIC size_t -ZSTD_entropyCompressSeqStore_internal( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - void* entropyWorkspace, size_t entropyWkspSize, - const int bmi2) +ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + void* entropyWorkspace, size_t entropyWkspSize, + const int bmi2) { + const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; ZSTD_strategy const strategy = cctxParams->cParams.strategy; - unsigned* count = (unsigned*)entropyWorkspace; + unsigned count[MaxSeq+1]; FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; + U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ const seqDef* const sequences = seqStorePtr->sequencesStart; - const size_t nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); const BYTE* const ofCodeTable = seqStorePtr->ofCode; const BYTE* const llCodeTable = seqStorePtr->llCode; const BYTE* const mlCodeTable = seqStorePtr->mlCode; BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; BYTE* op = ostart; - size_t lastCountSize; - int longOffsets = 0; - - entropyWorkspace = count + (MaxSeq + 1); - entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); + size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); + BYTE* seqHead; + BYTE* lastNCount = NULL; - DEBUGLOG(5, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu, dstCapacity=%zu)", nbSeq, dstCapacity); + DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= HUF_WORKSPACE_SIZE); /* Compress literals */ { const BYTE* const literals = seqStorePtr->litStart; - size_t const numSequences = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - size_t const numLiterals = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); - /* Base suspicion of uncompressibility on ratio of literals to sequences */ - unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); size_t const litSize = (size_t)(seqStorePtr->lit - literals); - size_t const cSize = ZSTD_compressLiterals( + &prevEntropy->huf, &nextEntropy->huf, + cctxParams->cParams.strategy, + ZSTD_disableLiteralsCompression(cctxParams), op, dstCapacity, literals, litSize, entropyWorkspace, entropyWkspSize, - &prevEntropy->huf, &nextEntropy->huf, - cctxParams->cParams.strategy, - ZSTD_literalsCompressionIsDisabled(cctxParams), - suspectUncompressible, bmi2); + bmi2); FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); assert(cSize <= dstCapacity); op += cSize; @@ -2932,23 +2026,98 @@ ZSTD_entropyCompressSeqStore_internal( assert(op <= oend); if (nbSeq==0) { /* Copy the old tables over as if we repeated them */ - ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); + memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); return (size_t)(op - ostart); } - { BYTE* const seqHead = op++; - /* build stats for sequences */ - const ZSTD_symbolEncodingTypeStats_t stats = - ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, - &prevEntropy->fse, &nextEntropy->fse, - op, oend, - strategy, count, - entropyWorkspace, entropyWkspSize); - FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); - *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2)); - lastCountSize = stats.lastCountSize; - op += stats.size; - longOffsets = stats.longOffsets; - } + + /* seqHead : flags for FSE encoding type */ + seqHead = op++; + assert(op <= oend); + + /* convert length/distances into codes */ + ZSTD_seqToCodes(seqStorePtr); + /* build CTable for Literal Lengths */ + { unsigned max = MaxLL; + size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building LL table"); + nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; + LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, + count, max, mostFrequent, nbSeq, + LLFSELog, prevEntropy->fse.litlengthCTable, + ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(set_basic < set_compressed && set_rle < set_compressed); + assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, + count, max, llCodeTable, nbSeq, + ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, MaxLL, + prevEntropy->fse.litlengthCTable, + sizeof(prevEntropy->fse.litlengthCTable), + entropyWorkspace, entropyWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); + if (LLtype == set_compressed) + lastNCount = op; + op += countSize; + assert(op <= oend); + } } + /* build CTable for Offsets */ + { unsigned max = MaxOff; + size_t const mostFrequent = HIST_countFast_wksp( + count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ + ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; + DEBUGLOG(5, "Building OF table"); + nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; + Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, + count, max, mostFrequent, nbSeq, + OffFSELog, prevEntropy->fse.offcodeCTable, + ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, + defaultPolicy, strategy); + assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, + count, max, ofCodeTable, nbSeq, + ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, DefaultMaxOff, + prevEntropy->fse.offcodeCTable, + sizeof(prevEntropy->fse.offcodeCTable), + entropyWorkspace, entropyWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); + if (Offtype == set_compressed) + lastNCount = op; + op += countSize; + assert(op <= oend); + } } + /* build CTable for MatchLengths */ + { unsigned max = MaxML; + size_t const mostFrequent = HIST_countFast_wksp( + count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ + DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); + nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; + MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, + count, max, mostFrequent, nbSeq, + MLFSELog, prevEntropy->fse.matchlengthCTable, + ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable( + op, (size_t)(oend - op), + CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, + count, max, mlCodeTable, nbSeq, + ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, MaxML, + prevEntropy->fse.matchlengthCTable, + sizeof(prevEntropy->fse.matchlengthCTable), + entropyWorkspace, entropyWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); + if (MLtype == set_compressed) + lastNCount = op; + op += countSize; + assert(op <= oend); + } } + + *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); { size_t const bitstreamSize = ZSTD_encodeSequences( op, (size_t)(oend - op), @@ -2968,9 +2137,9 @@ ZSTD_entropyCompressSeqStore_internal( * In this exceedingly rare case, we will simply emit an uncompressed * block, since it isn't worth optimizing. */ - if (lastCountSize && (lastCountSize + bitstreamSize) < 4) { - /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ - assert(lastCountSize + bitstreamSize == 3); + if (lastNCount && (op - lastNCount) < 4) { + /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ + assert(op - lastNCount == 3); DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " "emitting an uncompressed block."); return 0; @@ -2982,17 +2151,16 @@ ZSTD_entropyCompressSeqStore_internal( } MEM_STATIC size_t -ZSTD_entropyCompressSeqStore( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - size_t srcSize, - void* entropyWorkspace, size_t entropyWkspSize, - int bmi2) -{ - size_t const cSize = ZSTD_entropyCompressSeqStore_internal( +ZSTD_compressSequences(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + size_t srcSize, + void* entropyWorkspace, size_t entropyWkspSize, + int bmi2) +{ + size_t const cSize = ZSTD_compressSequences_internal( seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, entropyWorkspace, entropyWkspSize, bmi2); @@ -3000,108 +2168,60 @@ ZSTD_entropyCompressSeqStore( /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. */ - if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) { - DEBUGLOG(4, "not enough dstCapacity (%zu) for ZSTD_entropyCompressSeqStore_internal()=> do not compress block", dstCapacity); + if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) return 0; /* block not compressed */ - } - FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed"); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSequences_internal failed"); /* Check compressibility */ { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); if (cSize >= maxCSize) return 0; /* block not compressed */ } - DEBUGLOG(5, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize); - /* libzstd decoder before > v1.5.4 is not compatible with compressed blocks of size ZSTD_BLOCKSIZE_MAX exactly. - * This restriction is indirectly already fulfilled by respecting ZSTD_minGain() condition above. - */ - assert(cSize < ZSTD_BLOCKSIZE_MAX); + return cSize; } /* ZSTD_selectBlockCompressor() : * Not static, but internal use only (used by long distance matcher) * assumption : strat is a valid strategy */ -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode) +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) { - static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { + static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { { ZSTD_compressBlock_fast /* default for 0 */, ZSTD_compressBlock_fast, - ZSTD_COMPRESSBLOCK_DOUBLEFAST, - ZSTD_COMPRESSBLOCK_GREEDY, - ZSTD_COMPRESSBLOCK_LAZY, - ZSTD_COMPRESSBLOCK_LAZY2, - ZSTD_COMPRESSBLOCK_BTLAZY2, - ZSTD_COMPRESSBLOCK_BTOPT, - ZSTD_COMPRESSBLOCK_BTULTRA, - ZSTD_COMPRESSBLOCK_BTULTRA2 - }, + ZSTD_compressBlock_doubleFast, + ZSTD_compressBlock_greedy, + ZSTD_compressBlock_lazy, + ZSTD_compressBlock_lazy2, + ZSTD_compressBlock_btlazy2, + ZSTD_compressBlock_btopt, + ZSTD_compressBlock_btultra, + ZSTD_compressBlock_btultra2 }, { ZSTD_compressBlock_fast_extDict /* default for 0 */, ZSTD_compressBlock_fast_extDict, - ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT, - ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT, - ZSTD_COMPRESSBLOCK_LAZY_EXTDICT, - ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT, - ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT, - ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT, - ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT, - ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT - }, + ZSTD_compressBlock_doubleFast_extDict, + ZSTD_compressBlock_greedy_extDict, + ZSTD_compressBlock_lazy_extDict, + ZSTD_compressBlock_lazy2_extDict, + ZSTD_compressBlock_btlazy2_extDict, + ZSTD_compressBlock_btopt_extDict, + ZSTD_compressBlock_btultra_extDict, + ZSTD_compressBlock_btultra_extDict }, { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, ZSTD_compressBlock_fast_dictMatchState, - ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE, - ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE - }, - { NULL /* default for 0 */, - NULL, - NULL, - ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH, - ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH, - ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH, - NULL, - NULL, - NULL, - NULL } + ZSTD_compressBlock_doubleFast_dictMatchState, + ZSTD_compressBlock_greedy_dictMatchState, + ZSTD_compressBlock_lazy_dictMatchState, + ZSTD_compressBlock_lazy2_dictMatchState, + ZSTD_compressBlock_btlazy2_dictMatchState, + ZSTD_compressBlock_btopt_dictMatchState, + ZSTD_compressBlock_btultra_dictMatchState, + ZSTD_compressBlock_btultra_dictMatchState } }; ZSTD_blockCompressor selectedCompressor; ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); - DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder); - if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) { - static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = { - { - ZSTD_COMPRESSBLOCK_GREEDY_ROW, - ZSTD_COMPRESSBLOCK_LAZY_ROW, - ZSTD_COMPRESSBLOCK_LAZY2_ROW - }, - { - ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW, - ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW, - ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW - }, - { - ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW, - ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW, - ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW - }, - { - ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW, - ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW, - ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW - } - }; - DEBUGLOG(4, "Selecting a row-based matchfinder"); - assert(useRowMatchFinder != ZSTD_ps_auto); - selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy]; - } else { - selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; - } + selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; assert(selectedCompressor != NULL); return selectedCompressor; } @@ -3109,7 +2229,7 @@ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramS static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize) { - ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); + memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -3117,73 +2237,7 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) { ssPtr->lit = ssPtr->litStart; ssPtr->sequences = ssPtr->sequencesStart; - ssPtr->longLengthType = ZSTD_llt_none; -} - -/* ZSTD_postProcessSequenceProducerResult() : - * Validates and post-processes sequences obtained through the external matchfinder API: - * - Checks whether nbExternalSeqs represents an error condition. - * - Appends a block delimiter to outSeqs if one is not already present. - * See zstd.h for context regarding block delimiters. - * Returns the number of sequences after post-processing, or an error code. */ -static size_t ZSTD_postProcessSequenceProducerResult( - ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize -) { - RETURN_ERROR_IF( - nbExternalSeqs > outSeqsCapacity, - sequenceProducer_failed, - "External sequence producer returned error code %lu", - (unsigned long)nbExternalSeqs - ); - - RETURN_ERROR_IF( - nbExternalSeqs == 0 && srcSize > 0, - sequenceProducer_failed, - "Got zero sequences from external sequence producer for a non-empty src buffer!" - ); - - if (srcSize == 0) { - ZSTD_memset(&outSeqs[0], 0, sizeof(ZSTD_Sequence)); - return 1; - } - - { - ZSTD_Sequence const lastSeq = outSeqs[nbExternalSeqs - 1]; - - /* We can return early if lastSeq is already a block delimiter. */ - if (lastSeq.offset == 0 && lastSeq.matchLength == 0) { - return nbExternalSeqs; - } - - /* This error condition is only possible if the external matchfinder - * produced an invalid parse, by definition of ZSTD_sequenceBound(). */ - RETURN_ERROR_IF( - nbExternalSeqs == outSeqsCapacity, - sequenceProducer_failed, - "nbExternalSeqs == outSeqsCapacity but lastSeq is not a block delimiter!" - ); - - /* lastSeq is not a block delimiter, so we need to append one. */ - ZSTD_memset(&outSeqs[nbExternalSeqs], 0, sizeof(ZSTD_Sequence)); - return nbExternalSeqs + 1; - } -} - -/* ZSTD_fastSequenceLengthSum() : - * Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*. - * Similar to another function in zstd_compress.c (determine_blockSize), - * except it doesn't check for a block delimiter to end summation. - * Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P). - * This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */ -static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) { - size_t matchLenSum, litLenSum, i; - matchLenSum = 0; - litLenSum = 0; - for (i = 0; i < seqBufSize; i++) { - litLenSum += seqBuf[i].litLength; - matchLenSum += seqBuf[i].matchLength; - } - return litLenSum + matchLenSum; + ssPtr->longLengthID = 0; } typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; @@ -3195,14 +2249,8 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) assert(srcSize <= ZSTD_BLOCKSIZE_MAX); /* Assert that we have correctly flushed the ctx params into the ms's copy */ ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { - if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { - ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); - } else { - ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); - } + if (srcSize < MIN_CBLOCK_SIZE+ZSTDInternalConstants::ZSTD_blockHeaderSize+1) { + ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ } ZSTD_resetSeqStore(&(zc->seqStore)); @@ -3218,10 +2266,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* limited update after a very long match */ { const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const U32 curr = (U32)(istart-base); + const U32 current = (U32)(istart-base); if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ - if (curr > ms->nextToUpdate + 384) - ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); + if (current > ms->nextToUpdate + 384) + ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); } /* select and store sequences */ @@ -3232,34 +2280,16 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; } if (zc->externSeqStore.pos < zc->externSeqStore.size) { - assert(zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_disable); - - /* External matchfinder + LDM is technically possible, just not implemented yet. - * We need to revisit soon and implement it. */ - RETURN_ERROR_IF( - ZSTD_hasExtSeqProd(&zc->appliedParams), - parameter_combination_unsupported, - "Long-distance matching with external sequence producer enabled is not currently supported." - ); - + assert(!zc->appliedParams.ldmParams.enableLdm); /* Updates ldmSeqStore.pos */ lastLLSize = ZSTD_ldm_blockCompress(&zc->externSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, - zc->appliedParams.useRowMatchFinder, src, srcSize); assert(zc->externSeqStore.pos <= zc->externSeqStore.size); - } else if (zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { - rawSeqStore_t ldmSeqStore = kNullRawSeqStore; - - /* External matchfinder + LDM is technically possible, just not implemented yet. - * We need to revisit soon and implement it. */ - RETURN_ERROR_IF( - ZSTD_hasExtSeqProd(&zc->appliedParams), - parameter_combination_unsupported, - "Long-distance matching with external sequence producer enabled is not currently supported." - ); + } else if (zc->appliedParams.ldmParams.enableLdm) { + rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; ldmSeqStore.seq = zc->ldmSequences; ldmSeqStore.capacity = zc->maxNbLdmSequences; @@ -3272,78 +2302,10 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) ZSTD_ldm_blockCompress(&ldmSeqStore, ms, &zc->seqStore, zc->blockState.nextCBlock->rep, - zc->appliedParams.useRowMatchFinder, src, srcSize); assert(ldmSeqStore.pos == ldmSeqStore.size); - } else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) { - assert( - zc->extSeqBufCapacity >= ZSTD_sequenceBound(srcSize) - ); - assert(zc->appliedParams.extSeqProdFunc != NULL); - - { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog; - - size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)( - zc->appliedParams.extSeqProdState, - zc->extSeqBuf, - zc->extSeqBufCapacity, - src, srcSize, - NULL, 0, /* dict and dictSize, currently not supported */ - zc->appliedParams.compressionLevel, - windowSize - ); - - size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult( - zc->extSeqBuf, - nbExternalSeqs, - zc->extSeqBufCapacity, - srcSize - ); - - /* Return early if there is no error, since we don't need to worry about last literals */ - if (!ZSTD_isError(nbPostProcessedSeqs)) { - ZSTD_sequencePosition seqPos = {0,0,0}; - size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->extSeqBuf, nbPostProcessedSeqs); - RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!"); - FORWARD_IF_ERROR( - ZSTD_copySequencesToSeqStoreExplicitBlockDelim( - zc, &seqPos, - zc->extSeqBuf, nbPostProcessedSeqs, - src, srcSize, - zc->appliedParams.searchForExternalRepcodes - ), - "Failed to copy external sequences to seqStore!" - ); - ms->ldmSeqStore = NULL; - DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.", (unsigned long)nbExternalSeqs); - return ZSTDbss_compress; - } - - /* Propagate the error if fallback is disabled */ - if (!zc->appliedParams.enableMatchFinderFallback) { - return nbPostProcessedSeqs; - } - - /* Fallback to software matchfinder */ - { ZSTD_blockCompressor const blockCompressor = - ZSTD_selectBlockCompressor( - zc->appliedParams.cParams.strategy, - zc->appliedParams.useRowMatchFinder, - dictMode); - ms->ldmSeqStore = NULL; - DEBUGLOG( - 5, - "External sequence producer returned error code %lu. Falling back to internal parser.", - (unsigned long)nbExternalSeqs - ); - lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); - } } - } else { /* not long range mode and no external matchfinder */ - ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor( - zc->appliedParams.cParams.strategy, - zc->appliedParams.useRowMatchFinder, - dictMode); - ms->ldmSeqStore = NULL; + } else { /* not long range mode */ + ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); } { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; @@ -3352,113 +2314,63 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) return ZSTDbss_compress; } -static size_t ZSTD_copyBlockSequences(SeqCollector* seqCollector, const seqStore_t* seqStore, const U32 prevRepcodes[ZSTD_REP_NUM]) +static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) { - const seqDef* inSeqs = seqStore->sequencesStart; - const size_t nbInSequences = seqStore->sequences - inSeqs; - const size_t nbInLiterals = (size_t)(seqStore->lit - seqStore->litStart); + const seqStore_t* seqStore = ZSTD_getSeqStore(zc); + const seqDef* seqs = seqStore->sequencesStart; + size_t seqsSize = seqStore->sequences - seqs; - ZSTD_Sequence* outSeqs = seqCollector->seqIndex == 0 ? seqCollector->seqStart : seqCollector->seqStart + seqCollector->seqIndex; - const size_t nbOutSequences = nbInSequences + 1; - size_t nbOutLiterals = 0; - repcodes_t repcodes; - size_t i; + ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; + size_t i; size_t position; int repIdx; + + assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); + for (i = 0, position = 0; i < seqsSize; ++i) { + outSeqs[i].offset = seqs[i].offset; + outSeqs[i].litLength = seqs[i].litLength; + outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH; - /* Bounds check that we have enough space for every input sequence - * and the block delimiter - */ - assert(seqCollector->seqIndex <= seqCollector->maxSequences); - RETURN_ERROR_IF( - nbOutSequences > (size_t)(seqCollector->maxSequences - seqCollector->seqIndex), - dstSize_tooSmall, - "Not enough space to copy sequences"); - - ZSTD_memcpy(&repcodes, prevRepcodes, sizeof(repcodes)); - for (i = 0; i < nbInSequences; ++i) { - U32 rawOffset; - outSeqs[i].litLength = inSeqs[i].litLength; - outSeqs[i].matchLength = inSeqs[i].mlBase + MINMATCH; - outSeqs[i].rep = 0; - - /* Handle the possible single length >= 64K - * There can only be one because we add MINMATCH to every match length, - * and blocks are at most 128K. - */ if (i == seqStore->longLengthPos) { - if (seqStore->longLengthType == ZSTD_llt_literalLength) { + if (seqStore->longLengthID == 1) { outSeqs[i].litLength += 0x10000; - } else if (seqStore->longLengthType == ZSTD_llt_matchLength) { + } else if (seqStore->longLengthID == 2) { outSeqs[i].matchLength += 0x10000; } } - /* Determine the raw offset given the offBase, which may be a repcode. */ - if (OFFBASE_IS_REPCODE(inSeqs[i].offBase)) { - const U32 repcode = OFFBASE_TO_REPCODE(inSeqs[i].offBase); - assert(repcode > 0); - outSeqs[i].rep = repcode; - if (outSeqs[i].litLength != 0) { - rawOffset = repcodes.rep[repcode - 1]; - } else { - if (repcode == 3) { - assert(repcodes.rep[0] > 1); - rawOffset = repcodes.rep[0] - 1; + if (outSeqs[i].offset <= ZSTD_REP_NUM) { + outSeqs[i].rep = outSeqs[i].offset; + repIdx = (unsigned int)i - outSeqs[i].offset; + + if (outSeqs[i].litLength == 0) { + if (outSeqs[i].offset < 3) { + --repIdx; } else { - rawOffset = repcodes.rep[repcode]; + repIdx = (unsigned int)i - 1; } + ++outSeqs[i].rep; + } + assert(repIdx >= -3); + outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : ZSTDInternalConstants::repStartValue[-repIdx - 1]; + if (outSeqs[i].rep == 4) { + --outSeqs[i].offset; } } else { - rawOffset = OFFBASE_TO_OFFSET(inSeqs[i].offBase); + outSeqs[i].offset -= ZSTD_REP_NUM; } - outSeqs[i].offset = rawOffset; - /* Update repcode history for the sequence */ - ZSTD_updateRep(repcodes.rep, - inSeqs[i].offBase, - inSeqs[i].litLength == 0); - - nbOutLiterals += outSeqs[i].litLength; - } - /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. - * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker - * for the block boundary, according to the API. - */ - assert(nbInLiterals >= nbOutLiterals); - { - const size_t lastLLSize = nbInLiterals - nbOutLiterals; - outSeqs[nbInSequences].litLength = (U32)lastLLSize; - outSeqs[nbInSequences].matchLength = 0; - outSeqs[nbInSequences].offset = 0; - assert(nbOutSequences == nbInSequences + 1); + position += outSeqs[i].litLength; + outSeqs[i].matchPos = (unsigned int)position; + position += outSeqs[i].matchLength; } - seqCollector->seqIndex += nbOutSequences; - assert(seqCollector->seqIndex <= seqCollector->maxSequences); - - return 0; + zc->seqCollector.seqIndex += seqsSize; } -size_t ZSTD_sequenceBound(size_t srcSize) { - const size_t maxNbSeq = (srcSize / ZSTD_MINMATCH_MIN) + 1; - const size_t maxNbDelims = (srcSize / ZSTD_BLOCKSIZE_MAX_MIN) + 1; - return maxNbSeq + maxNbDelims; -} - -size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, - size_t outSeqsSize, const void* src, size_t srcSize) +size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize) { const size_t dstCapacity = ZSTD_compressBound(srcSize); - void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); + void* dst = ZSTD_malloc(dstCapacity, ZSTDInternalConstants::ZSTD_defaultCMem); SeqCollector seqCollector; - { - int targetCBlockSize; - FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetCBlockSize, &targetCBlockSize), ""); - RETURN_ERROR_IF(targetCBlockSize != 0, parameter_unsupported, "targetCBlockSize != 0"); - } - { - int nbWorkers; - FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers), ""); - RETURN_ERROR_IF(nbWorkers != 0, parameter_unsupported, "nbWorkers != 0"); - } RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); @@ -3468,51 +2380,18 @@ size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, seqCollector.maxSequences = outSeqsSize; zc->seqCollector = seqCollector; - { - const size_t ret = ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); - ZSTD_customFree(dst, ZSTD_defaultCMem); - FORWARD_IF_ERROR(ret, "ZSTD_compress2 failed"); - } - assert(zc->seqCollector.seqIndex <= ZSTD_sequenceBound(srcSize)); + ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); + ZSTD_free(dst, ZSTDInternalConstants::ZSTD_defaultCMem); return zc->seqCollector.seqIndex; } -size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { - size_t in = 0; - size_t out = 0; - for (; in < seqsSize; ++in) { - if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { - if (in != seqsSize - 1) { - sequences[in+1].litLength += sequences[in].litLength; - } - } else { - sequences[out] = sequences[in]; - ++out; - } - } - return out; -} - -/* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ -static int ZSTD_isRLE(const BYTE* src, size_t length) { - const BYTE* ip = src; - const BYTE value = ip[0]; - const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); - const size_t unrollSize = sizeof(size_t) * 4; - const size_t unrollMask = unrollSize - 1; - const size_t prefixLength = length & unrollMask; +/* Returns true if the given block is a RLE block */ +static int ZSTD_isRLE(const BYTE *ip, size_t length) { size_t i; - if (length == 1) return 1; - /* Check if prefix is RLE first before using unrolled loop */ - if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { - return 0; + if (length < 2) return 1; + for (i = 1; i < length; ++i) { + if (ip[0] != ip[i]) return 0; } - for (i = prefixLength; i != length; i += unrollSize) { - size_t u; - for (u = 0; u < unrollSize; u += sizeof(size_t)) { - if (MEM_readST(ip + i + u) != valueST) { - return 0; - } } } return 1; } @@ -3528,848 +2407,73 @@ static int ZSTD_maybeRLE(seqStore_t const* seqStore) return nbSeqs < 4 && nbLits < 10; } -static void -ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) +static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc) { - ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; - bs->prevCBlock = bs->nextCBlock; - bs->nextCBlock = tmp; + ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; + zc->blockState.prevCBlock = zc->blockState.nextCBlock; + zc->blockState.nextCBlock = tmp; } -/* Writes the block header */ -static void -writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) +static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, U32 frame) { - U32 const cBlockHeader = cSize == 1 ? - lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : - lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); - MEM_writeLE24(op, cBlockHeader); - DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock); -} + /* This the upper bound for the length of an rle block. + * This isn't the actual upper bound. Finding the real threshold + * needs further investigation. + */ + const U32 rleMaxLength = 25; + size_t cSize; + const BYTE* ip = (const BYTE*)src; + BYTE* op = (BYTE*)dst; + DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", + (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, + (unsigned)zc->blockState.matchState.nextToUpdate); -/** ZSTD_buildBlockEntropyStats_literals() : - * Builds entropy for the literals. - * Stores literals block type (raw, rle, compressed, repeat) and - * huffman description table to hufMetadata. - * Requires ENTROPY_WORKSPACE_SIZE workspace - * @return : size of huffman description table, or an error code - */ -static size_t -ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize, - const ZSTD_hufCTables_t* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_hufCTablesMetadata_t* hufMetadata, - const int literalsCompressionIsDisabled, - void* workspace, size_t wkspSize, - int hufFlags) -{ - BYTE* const wkspStart = (BYTE*)workspace; - BYTE* const wkspEnd = wkspStart + wkspSize; - BYTE* const countWkspStart = wkspStart; - unsigned* const countWksp = (unsigned*)workspace; - const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); - BYTE* const nodeWksp = countWkspStart + countWkspSize; - const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); - unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; - unsigned huffLog = LitHufLog; - HUF_repeat repeat = prevHuf->repeatMode; - DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); - - /* Prepare nextEntropy assuming reusing the existing table */ - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - - if (literalsCompressionIsDisabled) { - DEBUGLOG(5, "set_basic - disabled"); - hufMetadata->hType = set_basic; - return 0; + { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); + FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); + if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } } - /* small ? don't even attempt compression (speed opt) */ -#ifndef COMPRESS_LITERALS_SIZE_MIN -# define COMPRESS_LITERALS_SIZE_MIN 63 /* heuristic */ -#endif - { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; - if (srcSize <= minLitSize) { - DEBUGLOG(5, "set_basic - too small"); - hufMetadata->hType = set_basic; - return 0; - } } + if (zc->seqCollector.collectSequences) { + ZSTD_copyBlockSequences(zc); + return 0; + } - /* Scan input and build symbol stats */ - { size_t const largest = - HIST_count_wksp (countWksp, &maxSymbolValue, - (const BYTE*)src, srcSize, - workspace, wkspSize); - FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); - if (largest == srcSize) { - /* only one literal symbol */ - DEBUGLOG(5, "set_rle"); - hufMetadata->hType = set_rle; - return 0; - } - if (largest <= (srcSize >> 7)+4) { - /* heuristic: likely not compressible */ - DEBUGLOG(5, "set_basic - no gain"); - hufMetadata->hType = set_basic; - return 0; - } } + /* encode sequences and literals */ + cSize = ZSTD_compressSequences(&zc->seqStore, + &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, + &zc->appliedParams, + dst, dstCapacity, + srcSize, + zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, + zc->bmi2); - /* Validate the previous Huffman table */ - if (repeat == HUF_repeat_check - && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { - repeat = HUF_repeat_none; + if (frame && + /* We don't want to emit our first block as a RLE even if it qualifies because + * doing so will cause the decoder (cli only) to throw a "should consume all input error." + * This is only an issue for zstd <= v1.4.3 + */ + !zc->isFirstBlock && + cSize < rleMaxLength && + ZSTD_isRLE(ip, srcSize)) + { + cSize = 1; + op[0] = ip[0]; } - /* Build Huffman Tree */ - ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); - huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, nodeWksp, nodeWkspSize, nextHuf->CTable, countWksp, hufFlags); - assert(huffLog <= LitHufLog); - { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, - maxSymbolValue, huffLog, - nodeWksp, nodeWkspSize); - FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); - huffLog = (U32)maxBits; - } - { /* Build and write the CTable */ - size_t const newCSize = HUF_estimateCompressedSize( - (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); - size_t const hSize = HUF_writeCTable_wksp( - hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), - (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog, - nodeWksp, nodeWkspSize); - /* Check against repeating the previous CTable */ - if (repeat != HUF_repeat_none) { - size_t const oldCSize = HUF_estimateCompressedSize( - (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); - if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { - DEBUGLOG(5, "set_repeat - smaller"); - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_repeat; - return 0; - } } - if (newCSize + hSize >= srcSize) { - DEBUGLOG(5, "set_basic - no gains"); - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - hufMetadata->hType = set_basic; - return 0; - } - DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); - hufMetadata->hType = set_compressed; - nextHuf->repeatMode = HUF_repeat_check; - return hSize; +out: + if (!ZSTD_isError(cSize) && cSize > 1) { + ZSTD_confirmRepcodesAndEntropyTables(zc); } -} - + /* We check that dictionaries have offset codes available for the first + * block. After the first block, the offcode table might not have large + * enough codes to represent the offsets in the data. + */ + if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) + zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; -/* ZSTD_buildDummySequencesStatistics(): - * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic, - * and updates nextEntropy to the appropriate repeatMode. - */ -static ZSTD_symbolEncodingTypeStats_t -ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) -{ - ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0, 0}; - nextEntropy->litlength_repeatMode = FSE_repeat_none; - nextEntropy->offcode_repeatMode = FSE_repeat_none; - nextEntropy->matchlength_repeatMode = FSE_repeat_none; - return stats; -} - -/** ZSTD_buildBlockEntropyStats_sequences() : - * Builds entropy for the sequences. - * Stores symbol compression modes and fse table to fseMetadata. - * Requires ENTROPY_WORKSPACE_SIZE wksp. - * @return : size of fse tables or error code */ -static size_t -ZSTD_buildBlockEntropyStats_sequences( - const seqStore_t* seqStorePtr, - const ZSTD_fseCTables_t* prevEntropy, - ZSTD_fseCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize) -{ - ZSTD_strategy const strategy = cctxParams->cParams.strategy; - size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - BYTE* const ostart = fseMetadata->fseTablesBuffer; - BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); - BYTE* op = ostart; - unsigned* countWorkspace = (unsigned*)workspace; - unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1); - size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace); - ZSTD_symbolEncodingTypeStats_t stats; - - DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq); - stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, - prevEntropy, nextEntropy, op, oend, - strategy, countWorkspace, - entropyWorkspace, entropyWorkspaceSize) - : ZSTD_buildDummySequencesStatistics(nextEntropy); - FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); - fseMetadata->llType = (symbolEncodingType_e) stats.LLtype; - fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype; - fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype; - fseMetadata->lastCountSize = stats.lastCountSize; - return stats.size; -} - - -/** ZSTD_buildBlockEntropyStats() : - * Builds entropy for the block. - * Requires workspace size ENTROPY_WORKSPACE_SIZE - * @return : 0 on success, or an error code - * Note : also employed in superblock - */ -size_t ZSTD_buildBlockEntropyStats( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize) -{ - size_t const litSize = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); - int const huf_useOptDepth = (cctxParams->cParams.strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD); - int const hufFlags = huf_useOptDepth ? HUF_flags_optimalDepth : 0; - - entropyMetadata->hufMetadata.hufDesSize = - ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize, - &prevEntropy->huf, &nextEntropy->huf, - &entropyMetadata->hufMetadata, - ZSTD_literalsCompressionIsDisabled(cctxParams), - workspace, wkspSize, hufFlags); - - FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed"); - entropyMetadata->fseMetadata.fseTablesSize = - ZSTD_buildBlockEntropyStats_sequences(seqStorePtr, - &prevEntropy->fse, &nextEntropy->fse, - cctxParams, - &entropyMetadata->fseMetadata, - workspace, wkspSize); - FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed"); - return 0; -} - -/* Returns the size estimate for the literals section (header + content) of a block */ -static size_t -ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize, - const ZSTD_hufCTables_t* huf, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - unsigned* const countWksp = (unsigned*)workspace; - unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; - size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB); - U32 singleStream = litSize < 256; - - if (hufMetadata->hType == set_basic) return litSize; - else if (hufMetadata->hType == set_rle) return 1; - else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { - size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); - if (ZSTD_isError(largest)) return litSize; - { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); - if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; - if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */ - return cLitSizeEstimate + literalSectionHeaderSize; - } } - assert(0); /* impossible */ - return 0; -} - -/* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */ -static size_t -ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type, - const BYTE* codeTable, size_t nbSeq, unsigned maxCode, - const FSE_CTable* fseCTable, - const U8* additionalBits, - short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, - void* workspace, size_t wkspSize) -{ - unsigned* const countWksp = (unsigned*)workspace; - const BYTE* ctp = codeTable; - const BYTE* const ctStart = ctp; - const BYTE* const ctEnd = ctStart + nbSeq; - size_t cSymbolTypeSizeEstimateInBits = 0; - unsigned max = maxCode; - - HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ - if (type == set_basic) { - /* We selected this encoding type, so it must be valid. */ - assert(max <= defaultMax); - (void)defaultMax; - cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); - } else if (type == set_rle) { - cSymbolTypeSizeEstimateInBits = 0; - } else if (type == set_compressed || type == set_repeat) { - cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); - } - if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) { - return nbSeq * 10; - } - while (ctp < ctEnd) { - if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; - else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ - ctp++; - } - return cSymbolTypeSizeEstimateInBits >> 3; -} - -/* Returns the size estimate for the sequences section (header + content) of a block */ -static size_t -ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_fseCTables_t* fseTables, - const ZSTD_fseCTablesMetadata_t* fseMetadata, - void* workspace, size_t wkspSize, - int writeEntropy) -{ - size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ); - size_t cSeqSizeEstimate = 0; - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff, - fseTables->offcodeCTable, NULL, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL, - fseTables->litlengthCTable, LL_bits, - LL_defaultNorm, LL_defaultNormLog, MaxLL, - workspace, wkspSize); - cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML, - fseTables->matchlengthCTable, ML_bits, - ML_defaultNorm, ML_defaultNormLog, MaxML, - workspace, wkspSize); - if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; - return cSeqSizeEstimate + sequencesSectionHeaderSize; -} - -/* Returns the size estimate for a given stream of literals, of, ll, ml */ -static size_t -ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize, - const BYTE* ofCodeTable, - const BYTE* llCodeTable, - const BYTE* mlCodeTable, - size_t nbSeq, - const ZSTD_entropyCTables_t* entropy, - const ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize, - int writeLitEntropy, int writeSeqEntropy) -{ - size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize, - &entropy->huf, &entropyMetadata->hufMetadata, - workspace, wkspSize, writeLitEntropy); - size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, - nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, - workspace, wkspSize, writeSeqEntropy); - return seqSize + literalsSize + ZSTD_blockHeaderSize; -} - -/* Builds entropy statistics and uses them for blocksize estimation. - * - * @return: estimated compressed size of the seqStore, or a zstd error. - */ -static size_t -ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, ZSTD_CCtx* zc) -{ - ZSTD_entropyCTablesMetadata_t* const entropyMetadata = &zc->blockSplitCtx.entropyMetadata; - DEBUGLOG(6, "ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize()"); - FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore, - &zc->blockState.prevCBlock->entropy, - &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE), ""); - return ZSTD_estimateBlockSize( - seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart), - seqStore->ofCode, seqStore->llCode, seqStore->mlCode, - (size_t)(seqStore->sequences - seqStore->sequencesStart), - &zc->blockState.nextCBlock->entropy, - entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE, - (int)(entropyMetadata->hufMetadata.hType == set_compressed), 1); -} - -/* Returns literals bytes represented in a seqStore */ -static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) -{ - size_t literalsBytes = 0; - size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); - size_t i; - for (i = 0; i < nbSeqs; ++i) { - seqDef const seq = seqStore->sequencesStart[i]; - literalsBytes += seq.litLength; - if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) { - literalsBytes += 0x10000; - } } - return literalsBytes; -} - -/* Returns match bytes represented in a seqStore */ -static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) -{ - size_t matchBytes = 0; - size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); - size_t i; - for (i = 0; i < nbSeqs; ++i) { - seqDef seq = seqStore->sequencesStart[i]; - matchBytes += seq.mlBase + MINMATCH; - if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) { - matchBytes += 0x10000; - } } - return matchBytes; -} - -/* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx). - * Stores the result in resultSeqStore. - */ -static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore, - const seqStore_t* originalSeqStore, - size_t startIdx, size_t endIdx) -{ - *resultSeqStore = *originalSeqStore; - if (startIdx > 0) { - resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx; - resultSeqStore->litStart += ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); - } - - /* Move longLengthPos into the correct position if necessary */ - if (originalSeqStore->longLengthType != ZSTD_llt_none) { - if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) { - resultSeqStore->longLengthType = ZSTD_llt_none; - } else { - resultSeqStore->longLengthPos -= (U32)startIdx; - } - } - resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx; - resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx; - if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) { - /* This accounts for possible last literals if the derived chunk reaches the end of the block */ - assert(resultSeqStore->lit == originalSeqStore->lit); - } else { - size_t const literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); - resultSeqStore->lit = resultSeqStore->litStart + literalsBytes; - } - resultSeqStore->llCode += startIdx; - resultSeqStore->mlCode += startIdx; - resultSeqStore->ofCode += startIdx; -} - -/** - * Returns the raw offset represented by the combination of offBase, ll0, and repcode history. - * offBase must represent a repcode in the numeric representation of ZSTD_storeSeq(). - */ -static U32 -ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0) -{ - U32 const adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; /* [ 0 - 3 ] */ - assert(OFFBASE_IS_REPCODE(offBase)); - if (adjustedRepCode == ZSTD_REP_NUM) { - assert(ll0); - /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 - * This is only valid if it results in a valid offset value, aka > 0. - * Note : it may happen that `rep[0]==1` in exceptional circumstances. - * In which case this function will return 0, which is an invalid offset. - * It's not an issue though, since this value will be - * compared and discarded within ZSTD_seqStore_resolveOffCodes(). - */ - return rep[0] - 1; - } - return rep[adjustedRepCode]; -} - -/** - * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise - * due to emission of RLE/raw blocks that disturb the offset history, - * and replaces any repcodes within the seqStore that may be invalid. - * - * dRepcodes are updated as would be on the decompression side. - * cRepcodes are updated exactly in accordance with the seqStore. - * - * Note : this function assumes seq->offBase respects the following numbering scheme : - * 0 : invalid - * 1-3 : repcode 1-3 - * 4+ : real_offset+3 - */ -static void -ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes, - const seqStore_t* const seqStore, U32 const nbSeq) -{ - U32 idx = 0; - U32 const longLitLenIdx = seqStore->longLengthType == ZSTD_llt_literalLength ? seqStore->longLengthPos : nbSeq; - for (; idx < nbSeq; ++idx) { - seqDef* const seq = seqStore->sequencesStart + idx; - U32 const ll0 = (seq->litLength == 0) && (idx != longLitLenIdx); - U32 const offBase = seq->offBase; - assert(offBase > 0); - if (OFFBASE_IS_REPCODE(offBase)) { - U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0); - U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0); - /* Adjust simulated decompression repcode history if we come across a mismatch. Replace - * the repcode with the offset it actually references, determined by the compression - * repcode history. - */ - if (dRawOffset != cRawOffset) { - seq->offBase = OFFSET_TO_OFFBASE(cRawOffset); - } - } - /* Compression repcode history is always updated with values directly from the unmodified seqStore. - * Decompression repcode history may use modified seq->offset value taken from compression repcode history. - */ - ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0); - ZSTD_updateRep(cRepcodes->rep, offBase, ll0); - } -} - -/* ZSTD_compressSeqStore_singleBlock(): - * Compresses a seqStore into a block with a block header, into the buffer dst. - * - * Returns the total size of that block (including header) or a ZSTD error code. - */ -static size_t -ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, - const seqStore_t* const seqStore, - repcodes_t* const dRep, repcodes_t* const cRep, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - U32 lastBlock, U32 isPartition) -{ - const U32 rleMaxLength = 25; - BYTE* op = (BYTE*)dst; - const BYTE* ip = (const BYTE*)src; - size_t cSize; - size_t cSeqsSize; - - /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */ - repcodes_t const dRepOriginal = *dRep; - DEBUGLOG(5, "ZSTD_compressSeqStore_singleBlock"); - if (isPartition) - ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart)); - - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "Block header doesn't fit"); - cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore, - &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, - srcSize, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - zc->bmi2); - FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); - - if (!zc->isFirstBlock && - cSeqsSize < rleMaxLength && - ZSTD_isRLE((BYTE const*)src, srcSize)) { - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - cSeqsSize = 1; - } - - /* Sequence collection not supported when block splitting */ - if (zc->seqCollector.collectSequences) { - FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, seqStore, dRepOriginal.rep), "copyBlockSequences failed"); - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - return 0; - } - - if (cSeqsSize == 0) { - cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "Nocompress block failed"); - DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize); - *dRep = dRepOriginal; /* reset simulated decompression repcode history */ - } else if (cSeqsSize == 1) { - cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "RLE compress block failed"); - DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize); - *dRep = dRepOriginal; /* reset simulated decompression repcode history */ - } else { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - writeBlockHeader(op, cSeqsSize, srcSize, lastBlock); - cSize = ZSTD_blockHeaderSize + cSeqsSize; - DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize); - } - - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - return cSize; -} - -/* Struct to keep track of where we are in our recursive calls. */ -typedef struct { - U32* splitLocations; /* Array of split indices */ - size_t idx; /* The current index within splitLocations being worked on */ -} seqStoreSplits; - -#define MIN_SEQUENCES_BLOCK_SPLITTING 300 - -/* Helper function to perform the recursive search for block splits. - * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half. - * If advantageous to split, then we recurse down the two sub-blocks. - * If not, or if an error occurred in estimation, then we do not recurse. - * - * Note: The recursion depth is capped by a heuristic minimum number of sequences, - * defined by MIN_SEQUENCES_BLOCK_SPLITTING. - * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING). - * In practice, recursion depth usually doesn't go beyond 4. - * - * Furthermore, the number of splits is capped by ZSTD_MAX_NB_BLOCK_SPLITS. - * At ZSTD_MAX_NB_BLOCK_SPLITS == 196 with the current existing blockSize - * maximum of 128 KB, this value is actually impossible to reach. - */ -static void -ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx, - ZSTD_CCtx* zc, const seqStore_t* origSeqStore) -{ - seqStore_t* const fullSeqStoreChunk = &zc->blockSplitCtx.fullSeqStoreChunk; - seqStore_t* const firstHalfSeqStore = &zc->blockSplitCtx.firstHalfSeqStore; - seqStore_t* const secondHalfSeqStore = &zc->blockSplitCtx.secondHalfSeqStore; - size_t estimatedOriginalSize; - size_t estimatedFirstHalfSize; - size_t estimatedSecondHalfSize; - size_t midIdx = (startIdx + endIdx)/2; - - DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); - assert(endIdx >= startIdx); - if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { - DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences (%zu)", endIdx - startIdx); - return; - } - ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); - ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); - ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); - estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(fullSeqStoreChunk, zc); - estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(firstHalfSeqStore, zc); - estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(secondHalfSeqStore, zc); - DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu", - estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize); - if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) { - return; - } - if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) { - DEBUGLOG(5, "split decided at seqNb:%zu", midIdx); - ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore); - splits->splitLocations[splits->idx] = (U32)midIdx; - splits->idx++; - ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore); - } -} - -/* Base recursive function. - * Populates a table with intra-block partition indices that can improve compression ratio. - * - * @return: number of splits made (which equals the size of the partition table - 1). - */ -static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) -{ - seqStoreSplits splits; - splits.splitLocations = partitions; - splits.idx = 0; - if (nbSeq <= 4) { - DEBUGLOG(5, "ZSTD_deriveBlockSplits: Too few sequences to split (%u <= 4)", nbSeq); - /* Refuse to try and split anything with less than 4 sequences */ - return 0; - } - ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore); - splits.splitLocations[splits.idx] = nbSeq; - DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1); - return splits.idx; -} - -/* ZSTD_compressBlock_splitBlock(): - * Attempts to split a given block into multiple blocks to improve compression ratio. - * - * Returns combined size of all blocks (which includes headers), or a ZSTD error code. - */ -static size_t -ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t blockSize, - U32 lastBlock, U32 nbSeq) -{ - size_t cSize = 0; - const BYTE* ip = (const BYTE*)src; - BYTE* op = (BYTE*)dst; - size_t i = 0; - size_t srcBytesTotal = 0; - U32* const partitions = zc->blockSplitCtx.partitions; /* size == ZSTD_MAX_NB_BLOCK_SPLITS */ - seqStore_t* const nextSeqStore = &zc->blockSplitCtx.nextSeqStore; - seqStore_t* const currSeqStore = &zc->blockSplitCtx.currSeqStore; - size_t const numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq); - - /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history - * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two - * separate repcode histories that simulate repcode history on compression and decompression side, - * and use the histories to determine whether we must replace a particular repcode with its raw offset. - * - * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed - * or RLE. This allows us to retrieve the offset value that an invalid repcode references within - * a nocompress/RLE block. - * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use - * the replacement offset value rather than the original repcode to update the repcode history. - * dRep also will be the final repcode history sent to the next block. - * - * See ZSTD_seqStore_resolveOffCodes() for more details. - */ - repcodes_t dRep; - repcodes_t cRep; - ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); - ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); - ZSTD_memset(nextSeqStore, 0, sizeof(seqStore_t)); - - DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, - (unsigned)zc->blockState.matchState.nextToUpdate); - - if (numSplits == 0) { - size_t cSizeSingleBlock = - ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore, - &dRep, &cRep, - op, dstCapacity, - ip, blockSize, - lastBlock, 0 /* isPartition */); - FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!"); - DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits"); - assert(zc->blockSize <= ZSTD_BLOCKSIZE_MAX); - assert(cSizeSingleBlock <= zc->blockSize + ZSTD_blockHeaderSize); - return cSizeSingleBlock; - } - - ZSTD_deriveSeqStoreChunk(currSeqStore, &zc->seqStore, 0, partitions[0]); - for (i = 0; i <= numSplits; ++i) { - size_t cSizeChunk; - U32 const lastPartition = (i == numSplits); - U32 lastBlockEntireSrc = 0; - - size_t srcBytes = ZSTD_countSeqStoreLiteralsBytes(currSeqStore) + ZSTD_countSeqStoreMatchBytes(currSeqStore); - srcBytesTotal += srcBytes; - if (lastPartition) { - /* This is the final partition, need to account for possible last literals */ - srcBytes += blockSize - srcBytesTotal; - lastBlockEntireSrc = lastBlock; - } else { - ZSTD_deriveSeqStoreChunk(nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]); - } - - cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, currSeqStore, - &dRep, &cRep, - op, dstCapacity, - ip, srcBytes, - lastBlockEntireSrc, 1 /* isPartition */); - DEBUGLOG(5, "Estimated size: %zu vs %zu : actual size", - ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(currSeqStore, zc), cSizeChunk); - FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!"); - - ip += srcBytes; - op += cSizeChunk; - dstCapacity -= cSizeChunk; - cSize += cSizeChunk; - *currSeqStore = *nextSeqStore; - assert(cSizeChunk <= zc->blockSize + ZSTD_blockHeaderSize); - } - /* cRep and dRep may have diverged during the compression. - * If so, we use the dRep repcodes for the next block. - */ - ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t)); - return cSize; -} - -static size_t -ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 lastBlock) -{ - U32 nbSeq; - size_t cSize; - DEBUGLOG(4, "ZSTD_compressBlock_splitBlock"); - assert(zc->appliedParams.useBlockSplitter == ZSTD_ps_enable); - - { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - if (bss == ZSTDbss_noCompress) { - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); - cSize = ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); - DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block"); - return cSize; - } - nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart); - } - - cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq); - FORWARD_IF_ERROR(cSize, "Splitting blocks failed!"); - return cSize; -} - -static size_t -ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, U32 frame) -{ - /* This is an estimated upper bound for the length of an rle block. - * This isn't the actual upper bound. - * Finding the real threshold needs further investigation. - */ - const U32 rleMaxLength = 25; - size_t cSize; - const BYTE* ip = (const BYTE*)src; - BYTE* op = (BYTE*)dst; - DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", - (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, - (unsigned)zc->blockState.matchState.nextToUpdate); - - { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); - FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); - if (bss == ZSTDbss_noCompress) { - RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); - cSize = 0; - goto out; - } - } - - if (zc->seqCollector.collectSequences) { - FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, ZSTD_getSeqStore(zc), zc->blockState.prevCBlock->rep), "copyBlockSequences failed"); - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - return 0; - } - - /* encode sequences and literals */ - cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore, - &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, - &zc->appliedParams, - dst, dstCapacity, - srcSize, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - zc->bmi2); - - if (frame && - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - !zc->isFirstBlock && - cSize < rleMaxLength && - ZSTD_isRLE(ip, srcSize)) - { - cSize = 1; - op[0] = ip[0]; - } - -out: - if (!ZSTD_isError(cSize) && cSize > 1) { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); - } - /* We check that dictionaries have offset codes available for the first - * block. After the first block, the offcode table might not have large - * enough codes to represent the offsets in the data. - */ - if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - return cSize; + return cSize; } static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, @@ -4407,19 +2511,18 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, * * cSize >= blockBound(srcSize): We have expanded the block too much so * emit an uncompressed block. */ - { size_t const cSize = - ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); + { + size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); if (cSize != ERROR(dstSize_tooSmall)) { - size_t const maxCSize = - srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); + size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); - if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { - ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); + if (cSize != 0 && cSize < maxCSize + ZSTDInternalConstants::ZSTD_blockHeaderSize) { + ZSTD_confirmRepcodesAndEntropyTables(zc); return cSize; } } } - } /* if (bss == ZSTDbss_compress)*/ + } DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); /* Superblock compression failed, attempt to emit a single no compress block. @@ -4454,9 +2557,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, void const* ip, void const* iend) { - U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); - U32 const maxDist = (U32)1 << params->cParams.windowLog; - if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { + if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { + U32 const maxDist = (U32)1 << params->cParams.windowLog; + U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); @@ -4477,9 +2580,9 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, * All blocks will be terminated, all input will be consumed. * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. * Frame is supposed already started (header already produced) -* @return : compressed size, or an error code +* @return : compressed size, or an error code */ -static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, +static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastFrameChunk) @@ -4493,7 +2596,7 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); - DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); + DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); if (cctx->appliedParams.fParams.checksumFlag && srcSize) XXH64_update(&cctx->xxhState, src, srcSize); @@ -4501,9 +2604,7 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, ZSTD_matchState_t* const ms = &cctx->blockState.matchState; U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE + 1, + RETURN_ERROR_IF(dstCapacity < ZSTDInternalConstants::ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, dstSize_tooSmall, "not enough space to store compressed block"); if (remaining < blockSize) blockSize = remaining; @@ -4511,7 +2612,6 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, ZSTD_overflowCorrectIfNeeded( ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); - ZSTD_window_enforceMaxDist(&ms->window, ip, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; @@ -4521,14 +2621,10 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); assert(cSize > 0); - assert(cSize <= blockSize + ZSTD_blockHeaderSize); - } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) { - cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed"); - assert(cSize > 0 || cctx->seqCollector.collectSequences == 1); + assert(cSize <= blockSize + ZSTDInternalConstants::ZSTD_blockHeaderSize); } else { cSize = ZSTD_compressBlock_internal(cctx, - op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, + op+ZSTDInternalConstants::ZSTD_blockHeaderSize, dstCapacity-ZSTDInternalConstants::ZSTD_blockHeaderSize, ip, blockSize, 1 /* frame */); FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); @@ -4540,9 +2636,9 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); MEM_writeLE24(op, cBlockHeader); - cSize += ZSTD_blockHeaderSize; + cSize += ZSTDInternalConstants::ZSTD_blockHeaderSize; } - } /* if (ZSTD_useTargetCBlockSize(&cctx->appliedParams))*/ + } ip += blockSize; @@ -4580,6 +2676,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, "dst buf is too small to fit worst-case frame header size."); DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); + if (params->format == ZSTD_f_zstd1) { MEM_writeLE32(dst, ZSTD_MAGICNUMBER); pos = 4; @@ -4588,9 +2685,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, if (!singleSegment) op[pos++] = windowLogByte; switch(dictIDSizeCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : break; case 1 : op[pos] = (BYTE)(dictID); pos++; break; case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; @@ -4598,9 +2693,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, } switch(fcsCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; @@ -4609,26 +2702,6 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, return pos; } -/* ZSTD_writeSkippableFrame_advanced() : - * Writes out a skippable frame with the specified magic number variant (16 are supported), - * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. - * - * Returns the total number of bytes written, or a ZSTD error code. - */ -size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, - const void* src, size_t srcSize, unsigned magicVariant) { - BYTE* op = (BYTE*)dst; - RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, - dstSize_tooSmall, "Not enough room for skippable frame"); - RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); - RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); - - MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); - MEM_writeLE32(op+4, (U32)srcSize); - ZSTD_memcpy(op+8, src, srcSize); - return srcSize + ZSTD_SKIPPABLEHEADERSIZE; -} - /* ZSTD_writeLastEmptyBlock() : * output an empty Block with end-of-frame mark to complete a frame * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) @@ -4636,23 +2709,26 @@ size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, */ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) { - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, + RETURN_ERROR_IF(dstCapacity < ZSTDInternalConstants::ZSTD_blockHeaderSize, dstSize_tooSmall, "dst buf is too small to write frame trailer empty block."); { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ MEM_writeLE24(dst, cBlockHeader24); - return ZSTD_blockHeaderSize; + return ZSTDInternalConstants::ZSTD_blockHeaderSize; } } -void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) +size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) { - assert(cctx->stage == ZSTDcs_init); - assert(nbSeq == 0 || cctx->appliedParams.ldmParams.enableLdm != ZSTD_ps_enable); + RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong, + "wrong cctx stage"); + RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, + parameter_unsupported, + "incompatible with ldm"); cctx->externSeqStore.seq = seq; cctx->externSeqStore.size = nbSeq; cctx->externSeqStore.capacity = nbSeq; cctx->externSeqStore.pos = 0; - cctx->externSeqStore.posInSequence = 0; + return 0; } @@ -4681,12 +2757,11 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, if (!srcSize) return fhSize; /* do not generate an empty block if no input */ - if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) { - ms->forceNonContiguous = 0; + if (!ZSTD_window_update(&ms->window, src, srcSize)) { ms->nextToUpdate = ms->window.dictLimit; } - if (cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0); + if (cctx->appliedParams.ldmParams.enableLdm) { + ZSTD_window_update(&cctx->ldmState.window, src, srcSize); } if (!frame) { @@ -4717,51 +2792,31 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, } } -size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); } -/* NOTE: Must just wrap ZSTD_compressContinue_public() */ -size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - return ZSTD_compressContinue_public(cctx, dst, dstCapacity, src, srcSize); -} -static size_t ZSTD_getBlockSize_deprecated(const ZSTD_CCtx* cctx) +size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) { ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; assert(!ZSTD_checkCParams(cParams)); - return MIN(cctx->appliedParams.maxBlockSize, (size_t)1 << cParams.windowLog); + return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); } -/* NOTE: Must just wrap ZSTD_getBlockSize_deprecated() */ -size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) -{ - return ZSTD_getBlockSize_deprecated(cctx); -} - -/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ -size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) +size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); - { size_t const blockSizeMax = ZSTD_getBlockSize_deprecated(cctx); + { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); } -/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ -size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) -{ - return ZSTD_compressBlock_deprecated(cctx, dst, dstCapacity, src, srcSize); -} - /*! ZSTD_loadDictionaryContent() : * @return : 0, or an error code */ @@ -4770,133 +2825,63 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_cwksp* ws, ZSTD_CCtx_params const* params, const void* src, size_t srcSize, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) + ZSTD_dictTableLoadMethod_e dtlm) { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; - int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; - - /* Assert that the ms params match the params we're being given */ - ZSTD_assertEqualCParams(params->cParams, ms->cParams); - - { /* Ensure large dictionaries can't cause index overflow */ - /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX. - * Dictionaries right at the edge will immediately trigger overflow - * correction, but I don't want to insert extra constraints here. - */ - U32 maxDictSize = ZSTD_CURRENT_MAX - ZSTD_WINDOW_START_INDEX; - - int const CDictTaggedIndices = ZSTD_CDictIndicesAreTagged(¶ms->cParams); - if (CDictTaggedIndices && tfp == ZSTD_tfp_forCDict) { - /* Some dictionary matchfinders in zstd use "short cache", - * which treats the lower ZSTD_SHORT_CACHE_TAG_BITS of each - * CDict hashtable entry as a tag rather than as part of an index. - * When short cache is used, we need to truncate the dictionary - * so that its indices don't overlap with the tag. */ - U32 const shortCacheMaxDictSize = (1u << (32 - ZSTD_SHORT_CACHE_TAG_BITS)) - ZSTD_WINDOW_START_INDEX; - maxDictSize = MIN(maxDictSize, shortCacheMaxDictSize); - assert(!loadLdmDict); - } + ZSTD_window_update(&ms->window, src, srcSize); + ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); - /* If the dictionary is too large, only load the suffix of the dictionary. */ - if (srcSize > maxDictSize) { - ip = iend - maxDictSize; - src = ip; - srcSize = maxDictSize; - } + if (params->ldmParams.enableLdm && ls != NULL) { + ZSTD_window_update(&ls->window, src, srcSize); + ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); } - if (srcSize > ZSTD_CHUNKSIZE_MAX) { - /* We must have cleared our windows when our source is this large. */ - assert(ZSTD_window_isEmpty(ms->window)); - if (loadLdmDict) assert(ZSTD_window_isEmpty(ls->window)); - } - ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0); + /* Assert that we the ms params match the params we're being given */ + ZSTD_assertEqualCParams(params->cParams, ms->cParams); - DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder); + if (srcSize <= HASH_READ_SIZE) return 0; - if (loadLdmDict) { /* Load the entire dict into LDM matchfinders. */ - ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0); - ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); - ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams); - } + while (iend - ip > HASH_READ_SIZE) { + size_t const remaining = (size_t)(iend - ip); + size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); + const BYTE* const ichunk = ip + chunk; - /* If the dict is larger than we can reasonably index in our tables, only load the suffix. */ - if (params->cParams.strategy < ZSTD_btultra) { - U32 maxDictSize = 8U << MIN(MAX(params->cParams.hashLog, params->cParams.chainLog), 28); - if (srcSize > maxDictSize) { - ip = iend - maxDictSize; - src = ip; - srcSize = maxDictSize; - } - } + ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); - ms->nextToUpdate = (U32)(ip - ms->window.base); - ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); - ms->forceNonContiguous = params->deterministicRefPrefix; + if (params->ldmParams.enableLdm && ls != NULL) + ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, ¶ms->ldmParams); - if (srcSize <= HASH_READ_SIZE) return 0; + switch(params->cParams.strategy) + { + case ZSTD_fast: + ZSTD_fillHashTable(ms, ichunk, dtlm); + break; + case ZSTD_dfast: + ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); + break; - ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend); + case ZSTD_greedy: + case ZSTD_lazy: + case ZSTD_lazy2: + if (chunk >= HASH_READ_SIZE) + ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); + break; - switch(params->cParams.strategy) - { - case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, dtlm, tfp); - break; - case ZSTD_dfast: -#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - ZSTD_fillDoubleHashTable(ms, iend, dtlm, tfp); -#else - assert(0); /* shouldn't be called: cparams should've been adjusted. */ -#endif - break; + case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ + case ZSTD_btopt: + case ZSTD_btultra: + case ZSTD_btultra2: + if (chunk >= HASH_READ_SIZE) + ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); + break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: -#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) - assert(srcSize >= HASH_READ_SIZE); - if (ms->dedicatedDictSearch) { - assert(ms->chainTable != NULL); - ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE); - } else { - assert(params->useRowMatchFinder != ZSTD_ps_auto); - if (params->useRowMatchFinder == ZSTD_ps_enable) { - size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog); - ZSTD_memset(ms->tagTable, 0, tagTableSize); - ZSTD_row_update(ms, iend-HASH_READ_SIZE); - DEBUGLOG(4, "Using row-based hash table for lazy dict"); - } else { - ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); - DEBUGLOG(4, "Using chain-based hash table for lazy dict"); - } + default: + assert(0); /* not possible : not a valid strategy id */ } -#else - assert(0); /* shouldn't be called: cparams should've been adjusted. */ -#endif - break; - case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: -#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) - assert(srcSize >= HASH_READ_SIZE); - ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); -#else - assert(0); /* shouldn't be called: cparams should've been adjusted. */ -#endif - break; - - default: - assert(0); /* not possible : not a valid strategy id */ + ip = ichunk; } ms->nextToUpdate = (U32)(iend - ms->window.base); @@ -4905,28 +2890,22 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, /* Dictionaries that assign zero probability to symbols that show up causes problems - * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check - * and only dictionaries with 100% valid symbols can be assumed valid. - */ -static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) -{ + when FSE encoding. Refuse dictionaries that assign zero probability to symbols + that we may encounter during compression. + NOTE: This behavior is not standard and could be improved in the future. */ +static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { U32 s; - if (dictMaxSymbolValue < maxSymbolValue) { - return FSE_repeat_check; - } + RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted, "dict fse tables don't have all symbols"); for (s = 0; s <= maxSymbolValue; ++s) { - if (normalizedCounter[s] == 0) { - return FSE_repeat_check; - } + RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted, "dict fse tables don't have all symbols"); } - return FSE_repeat_valid; + return 0; } size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, + short* offcodeNCount, unsigned* offcodeMaxValue, const void* const dict, size_t dictSize) { - short offcodeNCount[MaxOff+1]; - unsigned offcodeMaxValue = MaxOff; const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ const BYTE* const dictEnd = dictPtr + dictSize; dictPtr += 8; @@ -4939,24 +2918,25 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, /* We only set the loaded table as valid if it contains all non-zero * weights. Otherwise, we set it to check */ - if (!hasZeroWeights && maxSymbolValue == 255) + if (!hasZeroWeights) bs->entropy.huf.repeatMode = HUF_repeat_valid; RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); + RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, ""); dictPtr += hufHeaderSize; } { unsigned offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); + /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ /* fill all offset symbols to avoid garbage at end of table */ RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); - /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ dictPtr += offcodeHeaderSize; } @@ -4965,12 +2945,13 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); + /* Every match length code must have non-zero probability */ + FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML), ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); - bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); dictPtr += matchlengthHeaderSize; } @@ -4979,12 +2960,13 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); + /* Every literal length code must have non-zero probability */ + FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL), ""); RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE)), dictionary_corrupted, ""); - bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); dictPtr += litlengthHeaderSize; } @@ -4994,28 +2976,12 @@ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, bs->rep[2] = MEM_readLE32(dictPtr+8); dictPtr += 12; - { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); - U32 offcodeMax = MaxOff; - if (dictContentSize <= ((U32)-1) - 128 KB) { - U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ - offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ - } - /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ - bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); - - /* All repCodes must be <= dictContentSize and != 0 */ - { U32 u; - for (u=0; u<3; u++) { - RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); - RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); - } } } - return dictPtr - (const BYTE*)dict; } /* Dictionary format : * See : - * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format + * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format */ /*! ZSTD_loadZstdDictionary() : * @return : dictID, or an error code @@ -5028,28 +2994,46 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp, void* workspace) { const BYTE* dictPtr = (const BYTE*)dict; const BYTE* const dictEnd = dictPtr + dictSize; + short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff; size_t dictID; size_t eSize; + ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<= 8); assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); - eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); + eSize = ZSTD_loadCEntropy(bs, workspace, offcodeNCount, &offcodeMaxValue, dict, dictSize); FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); dictPtr += eSize; - { - size_t const dictContentSize = (size_t)(dictEnd - dictPtr); + { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); + U32 offcodeMax = MaxOff; + if (dictContentSize <= ((U32)-1) - 128 KB) { + U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ + offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ + } + /* All offset values <= dictContentSize + 128 KB must be representable */ + FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)), ""); + /* All repCodes must be <= dictContentSize and != 0*/ + { U32 u; + for (u=0; u<3; u++) { + RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); + RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); + } } + + bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; + bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; + bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( - ms, NULL, ws, params, dictPtr, dictContentSize, dtlm, tfp), ""); + ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), ""); + return dictID; } - return dictID; } /** ZSTD_compress_insertDictionary() : @@ -5063,7 +3047,6 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp, void* workspace) { DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); @@ -5076,13 +3059,13 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict restricted modes */ if (dictContentType == ZSTD_dct_rawContent) - return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm, tfp); + return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm); if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { if (dictContentType == ZSTD_dct_auto) { DEBUGLOG(4, "raw content dictionary detected"); return ZSTD_loadDictionaryContent( - ms, ls, ws, params, dict, dictSize, dtlm, tfp); + ms, ls, ws, params, dict, dictSize, dtlm); } RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); assert(0); /* impossible */ @@ -5090,14 +3073,13 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, /* dict as full zstd dictionary */ return ZSTD_loadZstdDictionary( - bs, ms, ws, params, dict, dictSize, dtlm, tfp, workspace); + bs, ms, ws, params, dict, dictSize, dtlm, workspace); } #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) -#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) +#define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6) /*! ZSTD_compressBegin_internal() : - * Assumption : either @dict OR @cdict (or none) is non-NULL, never both * @return : 0, or an error code */ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, @@ -5107,10 +3089,6 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize; -#if ZSTD_TRACE - cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; -#endif DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); /* params are supposed to be fully validated at this point */ assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); @@ -5125,23 +3103,21 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); } - FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, - dictContentSize, + FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, ZSTDcrp_makeClean, zbuff) , ""); { size_t const dictID = cdict ? ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, - cdict->dictContentSize, cdict->dictContentType, dtlm, - ZSTD_tfp_forCCtx, cctx->entropyWorkspace) + cdict->dictContentSize, dictContentType, dtlm, + cctx->entropyWorkspace) : ZSTD_compress_insertDictionary( cctx->blockState.prevCBlock, &cctx->blockState.matchState, &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, - dictContentType, dtlm, ZSTD_tfp_forCCtx, cctx->entropyWorkspace); + dictContentType, dtlm, cctx->entropyWorkspace); FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= UINT_MAX); cctx->dictID = (U32)dictID; - cctx->dictContentSize = dictContentSize; } return 0; } @@ -5170,35 +3146,27 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize) { - ZSTD_CCtx_params cctxParams; - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); return ZSTD_compressBegin_advanced_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL /*cdict*/, &cctxParams, pledgedSrcSize); } -static size_t -ZSTD_compressBegin_usingDict_deprecated(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) +size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_CCtx_params cctxParams; - { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); - } + ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); } -size_t -ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) -{ - return ZSTD_compressBegin_usingDict_deprecated(cctx, dict, dictSize, compressionLevel); -} - size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) { - return ZSTD_compressBegin_usingDict_deprecated(cctx, NULL, 0, compressionLevel); + return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); } @@ -5209,13 +3177,14 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) { BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; + size_t fhSize = 0; DEBUGLOG(4, "ZSTD_writeEpilogue"); RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); /* special case : empty frame */ if (cctx->stage == ZSTDcs_init) { - size_t fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); + fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); dstCapacity -= fhSize; op += fhSize; @@ -5225,11 +3194,10 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) if (cctx->stage != ZSTDcs_ending) { /* write one last empty block, make it the "last" block */ U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; - ZSTD_STATIC_ASSERT(ZSTD_BLOCKHEADERSIZE == 3); - RETURN_ERROR_IF(dstCapacity<3, dstSize_tooSmall, "no room for epilogue"); - MEM_writeLE24(op, cBlockHeader24); - op += ZSTD_blockHeaderSize; - dstCapacity -= ZSTD_blockHeaderSize; + RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue"); + MEM_writeLE32(op, cBlockHeader24); + op += ZSTDInternalConstants::ZSTD_blockHeaderSize; + dstCapacity -= ZSTDInternalConstants::ZSTD_blockHeaderSize; } if (cctx->appliedParams.fParams.checksumFlag) { @@ -5244,33 +3212,9 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) return op-ostart; } -void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) -{ -#if ZSTD_TRACE - if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) { - int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0; - ZSTD_Trace trace; - ZSTD_memset(&trace, 0, sizeof(trace)); - trace.version = ZSTD_VERSION_NUMBER; - trace.streaming = streaming; - trace.dictionaryID = cctx->dictID; - trace.dictionarySize = cctx->dictContentSize; - trace.uncompressedSize = cctx->consumedSrcSize; - trace.compressedSize = cctx->producedCSize + extraCSize; - trace.params = &cctx->appliedParams; - trace.cctx = cctx; - ZSTD_trace_compress_end(cctx->traceCtx, &trace); - } - cctx->traceCtx = 0; -#else - (void)cctx; - (void)extraCSize; -#endif -} - -size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t endResult; size_t const cSize = ZSTD_compressContinue_internal(cctx, @@ -5290,16 +3234,24 @@ size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, (unsigned)cctx->pledgedSrcSizePlusOne-1, (unsigned)cctx->consumedSrcSize); } - ZSTD_CCtx_trace(cctx, endResult); return cSize + endResult; } -/* NOTE: Must just wrap ZSTD_compressEnd_public() */ -size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) + +static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + const ZSTD_parameters* params) { - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + ZSTD_CCtx_params const cctxParams = + ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); + DEBUGLOG(4, "ZSTD_compress_internal"); + return ZSTD_compress_advanced_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + &cctxParams); } size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, @@ -5310,12 +3262,11 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, { DEBUGLOG(4, "ZSTD_compress_advanced"); FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL); - return ZSTD_compress_advanced_internal(cctx, - dst, dstCapacity, - src, srcSize, - dict, dictSize, - &cctx->simpleApiParams); + return ZSTD_compress_internal(cctx, + dst, dstCapacity, + src, srcSize, + dict, dictSize, + ¶ms); } /* Internal */ @@ -5330,7 +3281,7 @@ size_t ZSTD_compress_advanced_internal( FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, params, srcSize, ZSTDb_not_buffered) , ""); - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, @@ -5339,13 +3290,11 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { - { - ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); - assert(params.fParams.contentSizeFlag == 1); - ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); - } + ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0); + ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, ¶ms); DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); - return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); + assert(params.fParams.contentSizeFlag == 1); + return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); } size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, @@ -5363,17 +3312,10 @@ size_t ZSTD_compress(void* dst, size_t dstCapacity, int compressionLevel) { size_t result; -#if ZSTD_COMPRESS_HEAPMODE - ZSTD_CCtx* cctx = ZSTD_createCCtx(); - RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); - result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); - ZSTD_freeCCtx(cctx); -#else ZSTD_CCtx ctxBody; - ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); + ZSTD_initCCtx(&ctxBody, ZSTDInternalConstants::ZSTD_defaultCMem); result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ -#endif return result; } @@ -5389,17 +3331,14 @@ size_t ZSTD_estimateCDictSize_advanced( DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) - /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small - * in case we are using DDS with row-hash. */ - + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams), - /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); } size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); } @@ -5417,22 +3356,20 @@ static size_t ZSTD_initCDict_internal( const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, - ZSTD_CCtx_params params) + ZSTD_compressionParameters cParams) { DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); - assert(!ZSTD_checkCParams(params.cParams)); - cdict->matchState.cParams = params.cParams; - cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; + assert(!ZSTD_checkCParams(cParams)); + cdict->matchState.cParams = cParams; if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictContent = dictBuffer; } else { void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); cdict->dictContent = internalBuffer; - ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); + memcpy(internalBuffer, dictBuffer, dictSize); } cdict->dictContentSize = dictSize; - cdict->dictContentType = dictContentType; cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); @@ -5442,20 +3379,22 @@ static size_t ZSTD_initCDict_internal( FORWARD_IF_ERROR(ZSTD_reset_matchState( &cdict->matchState, &cdict->workspace, - ¶ms.cParams, - params.useRowMatchFinder, + &cParams, ZSTDcrp_makeClean, ZSTDirp_reset, ZSTD_resetTarget_CDict), ""); /* (Maybe) load the dictionary * Skips loading the dictionary if it is < 8 bytes. */ - { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; + { ZSTD_CCtx_params params; + memset(¶ms, 0, sizeof(params)); + params.compressionLevel = ZSTD_CLEVEL_DEFAULT; params.fParams.contentSizeFlag = 1; + params.cParams = cParams; { size_t const dictID = ZSTD_compress_insertDictionary( &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, ¶ms, cdict->dictContent, cdict->dictContentSize, - dictContentType, ZSTD_dtlm_full, ZSTD_tfp_forCDict, cdict->entropyWorkspace); + dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); assert(dictID <= (size_t)(U32)-1); cdict->dictID = (U32)dictID; @@ -5465,129 +3404,66 @@ static size_t ZSTD_initCDict_internal( return 0; } -static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, +ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_compressionParameters cParams, - ZSTD_paramSwitch_e useRowMatchFinder, - U32 enableDedicatedDictSearch, - ZSTD_customMem customMem) + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; { size_t const workspaceSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + - ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) + + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); - void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); + void* const workspace = ZSTD_malloc(workspaceSize, customMem); ZSTD_cwksp ws; ZSTD_CDict* cdict; if (!workspace) { - ZSTD_customFree(workspace, customMem); + ZSTD_free(workspace, customMem); return NULL; } - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); assert(cdict != NULL); ZSTD_cwksp_move(&cdict->workspace, &ws); cdict->customMem = customMem; - cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ - cdict->useRowMatchFinder = useRowMatchFinder; - return cdict; - } -} - -ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, - ZSTD_customMem customMem) -{ - ZSTD_CCtx_params cctxParams; - ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); - ZSTD_CCtxParams_init(&cctxParams, 0); - cctxParams.cParams = cParams; - cctxParams.customMem = customMem; - return ZSTD_createCDict_advanced2( - dictBuffer, dictSize, - dictLoadMethod, dictContentType, - &cctxParams, customMem); -} - -ZSTD_CDict* ZSTD_createCDict_advanced2( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - const ZSTD_CCtx_params* originalCctxParams, - ZSTD_customMem customMem) -{ - ZSTD_CCtx_params cctxParams = *originalCctxParams; - ZSTD_compressionParameters cParams; - ZSTD_CDict* cdict; - - DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); - if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - - if (cctxParams.enableDedicatedDictSearch) { - cParams = ZSTD_dedicatedDictSearch_getCParams( - cctxParams.compressionLevel, dictSize); - ZSTD_overrideCParams(&cParams, &cctxParams.cParams); - } else { - cParams = ZSTD_getCParamsFromCCtxParams( - &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - } + cdict->compressionLevel = 0; /* signals advanced API usage */ - if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { - /* Fall back to non-DDSS params */ - cctxParams.enableDedicatedDictSearch = 0; - cParams = ZSTD_getCParamsFromCCtxParams( - &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - } + if (ZSTD_isError( ZSTD_initCDict_internal(cdict, + dictBuffer, dictSize, + dictLoadMethod, dictContentType, + cParams) )) { + ZSTD_freeCDict(cdict); + return NULL; + } - DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch); - cctxParams.cParams = cParams; - cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); - - cdict = ZSTD_createCDict_advanced_internal(dictSize, - dictLoadMethod, cctxParams.cParams, - cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, - customMem); - - if (!cdict || ZSTD_isError( ZSTD_initCDict_internal(cdict, - dict, dictSize, - dictLoadMethod, dictContentType, - cctxParams) )) { - ZSTD_freeCDict(cdict); - return NULL; + return cdict; } - - return cdict; } ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); + ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, - cParams, ZSTD_defaultCMem); + cParams, ZSTDInternalConstants::ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, + ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); + return ZSTD_createCDict_advanced(dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, - cParams, ZSTD_defaultCMem); - if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; - return cdict; + cParams, ZSTDInternalConstants::ZSTD_defaultCMem); } size_t ZSTD_freeCDict(ZSTD_CDict* cdict) @@ -5597,7 +3473,7 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict) int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); ZSTD_cwksp_free(&cdict->workspace, cMem); if (!cdictInWorkspace) { - ZSTD_customFree(cdict, cMem); + ZSTD_free(cdict, cMem); } return 0; } @@ -5623,22 +3499,19 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_dictContentType_e dictContentType, ZSTD_compressionParameters cParams) { - ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams); - /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */ - size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0); + size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + matchStateSize; ZSTD_CDict* cdict; - ZSTD_CCtx_params params; if ((size_t)workspace & 7) return NULL; /* 8-aligned */ { ZSTD_cwksp ws; - ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); + ZSTD_cwksp_init(&ws, workspace, workspaceSize); cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); if (cdict == NULL) return NULL; ZSTD_cwksp_move(&cdict->workspace, &ws); @@ -5648,16 +3521,10 @@ const ZSTD_CDict* ZSTD_initStaticCDict( (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); if (workspaceSize < neededSize) return NULL; - ZSTD_CCtxParams_init(¶ms, 0); - params.cParams = cParams; - params.useRowMatchFinder = useRowMatchFinder; - cdict->useRowMatchFinder = useRowMatchFinder; - cdict->compressionLevel = ZSTD_NO_CLEVEL; - if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, dictLoadMethod, dictContentType, - params) )) + cParams) )) return NULL; return cdict; @@ -5669,101 +3536,59 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) return cdict->matchState.cParams; } -/*! ZSTD_getDictID_fromCDict() : - * Provides the dictID of the dictionary loaded into `cdict`. - * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. - * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ -unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) -{ - if (cdict==NULL) return 0; - return cdict->dictID; -} - -/* ZSTD_compressBegin_usingCDict_internal() : - * Implementation of various ZSTD_compressBegin_usingCDict* functions. - */ -static size_t ZSTD_compressBegin_usingCDict_internal( +/* ZSTD_compressBegin_usingCDict_advanced() : + * cdict must be != NULL */ +size_t ZSTD_compressBegin_usingCDict_advanced( ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { - ZSTD_CCtx_params cctxParams; - DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); - /* Initialize the cctxParams from the cdict */ - { - ZSTD_parameters params; - params.fParams = fParams; + { ZSTD_CCtx_params params = cctx->requestedParams; params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) ? + || cdict->compressionLevel == 0 ) + && (params.attachDictPref != ZSTD_dictForceLoad) ? ZSTD_getCParamsFromCDict(cdict) : ZSTD_getCParams(cdict->compressionLevel, pledgedSrcSize, cdict->dictContentSize); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); - } - /* Increase window log to fit the entire dictionary and source if the - * source size is known. Limit the increase to 19, which is the - * window log for compression level 1 with the largest source size. - */ - if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); + /* Increase window log to fit the entire dictionary and source if the + * source size is known. Limit the increase to 19, which is the + * window log for compression level 1 with the largest source size. + */ + if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { + U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); + U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; + params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); + } + params.fParams = fParams; + return ZSTD_compressBegin_internal(cctx, + NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, + cdict, + ¶ms, pledgedSrcSize, + ZSTDb_not_buffered); } - return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, - cdict, - &cctxParams, pledgedSrcSize, - ZSTDb_not_buffered); } - -/* ZSTD_compressBegin_usingCDict_advanced() : - * This function is DEPRECATED. - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_advanced( - ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, - ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) -{ - return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize); -} - -/* ZSTD_compressBegin_usingCDict() : - * cdict must be != NULL */ -size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) -{ - ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); -} - -size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) -{ - return ZSTD_compressBegin_usingCDict_deprecated(cctx, cdict); -} - -/*! ZSTD_compress_usingCDict_internal(): - * Implementation of various ZSTD_compress_usingCDict* functions. - */ -static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) +/* ZSTD_compressBegin_usingCDict() : + * pledgedSrcSize=0 means "unknown" + * if pledgedSrcSize>0, it will enable contentSizeFlag */ +size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { - FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ - return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); + ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; + DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); + return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); } -/*! ZSTD_compress_usingCDict_advanced(): - * This function is DEPRECATED. - */ size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) { - return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ + return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); } /*! ZSTD_compress_usingCDict() : @@ -5777,7 +3602,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) { ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; - return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); + return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); } @@ -5789,7 +3614,7 @@ size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, ZSTD_CStream* ZSTD_createCStream(void) { DEBUGLOG(3, "ZSTD_createCStream"); - return ZSTD_createCStream_advanced(ZSTD_defaultCMem); + return ZSTD_createCStream_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); } ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) @@ -5815,15 +3640,35 @@ size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_CStreamOutSize(void) { - return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; + return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTDInternalConstants::ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } -static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) +static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, + const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, + const ZSTD_CDict* const cdict, + ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) { - if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) - return ZSTD_cpm_attachDict; - else - return ZSTD_cpm_noAttachDict; + DEBUGLOG(4, "ZSTD_resetCStream_internal"); + /* Finalize the compression parameters */ + params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); + /* params are supposed to be fully validated at this point */ + assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!((dict) && (cdict))); /* either dict or cdict, not both */ + + FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, + dict, dictSize, dictContentType, ZSTD_dtlm_fast, + cdict, + ¶ms, pledgedSrcSize, + ZSTDb_buffered) , ""); + + cctx->inToCompress = 0; + cctx->inBuffPos = 0; + cctx->inBuffTarget = cctx->blockSize + + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */ + cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; + cctx->streamStage = zcss_load; + cctx->frameEnded = 0; + return 0; /* ready to go */ } /* ZSTD_resetCStream(): @@ -5907,7 +3752,7 @@ size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); - ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); + zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, ¶ms); FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); return 0; } @@ -5949,54 +3794,36 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) { - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - return cctx->blockSize - cctx->stableIn_notConsumed; - } - assert(cctx->appliedParams.inBufferMode == ZSTD_bm_buffered); - { size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; - if (hintInSize==0) hintInSize = cctx->blockSize; - return hintInSize; - } + size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; + if (hintInSize==0) hintInSize = cctx->blockSize; + return hintInSize; } /** ZSTD_compressStream_generic(): * internal function for all *compressStream*() variants - * @return : hint size for next input to complete ongoing block */ + * non-static, because can be called from zstdmt_compress.c + * @return : hint size for next input */ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input, ZSTD_EndDirective const flushMode) { - const char* const istart = (assert(input != NULL), (const char*)input->src); - const char* const iend = (istart != NULL) ? istart + input->size : istart; - const char* ip = (istart != NULL) ? istart + input->pos : istart; - char* const ostart = (assert(output != NULL), (char*)output->dst); - char* const oend = (ostart != NULL) ? ostart + output->size : ostart; - char* op = (ostart != NULL) ? ostart + output->pos : ostart; + const char* const istart = (const char*)input->src; + const char* const iend = input->size != 0 ? istart + input->size : istart; + const char* ip = input->pos != 0 ? istart + input->pos : istart; + char* const ostart = (char*)output->dst; + char* const oend = output->size != 0 ? ostart + output->size : ostart; + char* op = output->pos != 0 ? ostart + output->pos : ostart; U32 someMoreWork = 1; /* check expectations */ - DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%i, srcSize = %zu", (int)flushMode, input->size - input->pos); - assert(zcs != NULL); - if (zcs->appliedParams.inBufferMode == ZSTD_bm_stable) { - assert(input->pos >= zcs->stableIn_notConsumed); - input->pos -= zcs->stableIn_notConsumed; - if (ip) ip -= zcs->stableIn_notConsumed; - zcs->stableIn_notConsumed = 0; - } - if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { - assert(zcs->inBuff != NULL); - assert(zcs->inBuffSize > 0); - } - if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { - assert(zcs->outBuff != NULL); - assert(zcs->outBuffSize > 0); - } - if (input->src == NULL) assert(input->size == 0); - assert(input->pos <= input->size); - if (output->dst == NULL) assert(output->size == 0); + DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); + assert(zcs->inBuff != NULL); + assert(zcs->inBuffSize > 0); + assert(zcs->outBuff != NULL); + assert(zcs->outBuffSize > 0); assert(output->pos <= output->size); - assert((U32)flushMode <= (U32)ZSTD_e_end); + assert(input->pos <= input->size); while (someMoreWork) { switch(zcs->streamStage) @@ -6006,11 +3833,10 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, case zcss_load: if ( (flushMode == ZSTD_e_end) - && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ - || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ + && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ && (zcs->inBuffPos == 0) ) { /* shortcut to compression pass directly into output buffer */ - size_t const cSize = ZSTD_compressEnd_public(zcs, + size_t const cSize = ZSTD_compressEnd(zcs, op, oend-op, ip, iend-ip); DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); @@ -6020,14 +3846,14 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); someMoreWork = 0; break; } - /* complete loading into inBuffer in buffered mode */ - if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { - size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; + /* complete loading into inBuffer */ + { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; size_t const loaded = ZSTD_limitCopy( zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); zcs->inBuffPos += loaded; - if (ip) ip += loaded; + if (loaded != 0) + ip += loaded; if ( (flushMode == ZSTD_e_continue) && (zcs->inBuffPos < zcs->inBuffTarget) ) { /* not enough input to fill full block : stop here */ @@ -6038,62 +3864,34 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, /* empty */ someMoreWork = 0; break; } - } else { - assert(zcs->appliedParams.inBufferMode == ZSTD_bm_stable); - if ( (flushMode == ZSTD_e_continue) - && ( (size_t)(iend - ip) < zcs->blockSize) ) { - /* can't compress a full block : stop here */ - zcs->stableIn_notConsumed = (size_t)(iend - ip); - ip = iend; /* pretend to have consumed input */ - someMoreWork = 0; break; - } - if ( (flushMode == ZSTD_e_flush) - && (ip == iend) ) { - /* empty */ - someMoreWork = 0; break; - } } /* compress current block (note : this stage cannot be stopped in the middle) */ DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); - { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); - void* cDst; + { void* cDst; size_t cSize; + size_t const iSize = zcs->inBuffPos - zcs->inToCompress; size_t oSize = oend-op; - size_t const iSize = inputBuffered ? zcs->inBuffPos - zcs->inToCompress - : MIN((size_t)(iend - ip), zcs->blockSize); - if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) + unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); + if (oSize >= ZSTD_compressBound(iSize)) cDst = op; /* compress into output buffer, to skip flush stage */ else cDst = zcs->outBuff, oSize = zcs->outBuffSize; - if (inputBuffered) { - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); - cSize = lastBlock ? - ZSTD_compressEnd_public(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize) : - ZSTD_compressContinue_public(zcs, cDst, oSize, - zcs->inBuff + zcs->inToCompress, iSize); - FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); - zcs->frameEnded = lastBlock; - /* prepare next block */ - zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; - if (zcs->inBuffTarget > zcs->inBuffSize) - zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; - DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", - (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); - if (!lastBlock) - assert(zcs->inBuffTarget <= zcs->inBuffSize); - zcs->inToCompress = zcs->inBuffPos; - } else { /* !inputBuffered, hence ZSTD_bm_stable */ - unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip + iSize == iend); - cSize = lastBlock ? - ZSTD_compressEnd_public(zcs, cDst, oSize, ip, iSize) : - ZSTD_compressContinue_public(zcs, cDst, oSize, ip, iSize); - /* Consume the input prior to error checking to mirror buffered mode. */ - if (ip) ip += iSize; - FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); - zcs->frameEnded = lastBlock; - if (lastBlock) assert(ip == iend); - } + cSize = lastBlock ? + ZSTD_compressEnd(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize) : + ZSTD_compressContinue(zcs, cDst, oSize, + zcs->inBuff + zcs->inToCompress, iSize); + FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); + zcs->frameEnded = lastBlock; + /* prepare next block */ + zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; + if (zcs->inBuffTarget > zcs->inBuffSize) + zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; + DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", + (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); + if (!lastBlock) + assert(zcs->inBuffTarget <= zcs->inBuffSize); + zcs->inToCompress = zcs->inBuffPos; if (cDst == op) { /* no need to flush */ op += cSize; if (zcs->frameEnded) { @@ -6107,10 +3905,9 @@ static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, zcs->outBuffFlushedSize = 0; zcs->streamStage = zcss_flush; /* pass-through to flush stage */ } - ZSTD_FALLTHROUGH; + /* fall-through */ case zcss_flush: DEBUGLOG(5, "flush stage"); - assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), zcs->outBuff + zcs->outBuffFlushedSize, toFlush); @@ -6165,141 +3962,7 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf return ZSTD_nextInputSizeHint_MTorST(zcs); } -/* After a compression call set the expected input/output buffer. - * This is validated at the start of the next compression call. - */ -static void -ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, const ZSTD_outBuffer* output, const ZSTD_inBuffer* input) -{ - DEBUGLOG(5, "ZSTD_setBufferExpectations (for advanced stable in/out modes)"); - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - cctx->expectedInBuffer = *input; - } - if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { - cctx->expectedOutBufferSize = output->size - output->pos; - } -} - -/* Validate that the input/output buffers match the expectations set by - * ZSTD_setBufferExpectations. - */ -static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, - ZSTD_outBuffer const* output, - ZSTD_inBuffer const* input, - ZSTD_EndDirective endOp) -{ - if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { - ZSTD_inBuffer const expect = cctx->expectedInBuffer; - if (expect.src != input->src || expect.pos != input->pos) - RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableInBuffer enabled but input differs!"); - } - (void)endOp; - if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { - size_t const outBufferSize = output->size - output->pos; - if (cctx->expectedOutBufferSize != outBufferSize) - RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableOutBuffer enabled but output size differs!"); - } - return 0; -} - -static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, - ZSTD_EndDirective endOp, - size_t inSize) -{ - ZSTD_CCtx_params params = cctx->requestedParams; - ZSTD_prefixDict const prefixDict = cctx->prefixDict; - FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ - ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ - assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ - if (cctx->cdict && !cctx->localDict.cdict) { - /* Let the cdict's compression level take priority over the requested params. - * But do not take the cdict's compression level if the "cdict" is actually a localDict - * generated from ZSTD_initLocalDict(). - */ - params.compressionLevel = cctx->cdict->compressionLevel; - } - DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); - if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ - - { size_t const dictSize = prefixDict.dict - ? prefixDict.dictSize - : (cctx->cdict ? cctx->cdict->dictContentSize : 0); - ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); - params.cParams = ZSTD_getCParamsFromCCtxParams( - ¶ms, cctx->pledgedSrcSizePlusOne-1, - dictSize, mode); - } - - params.useBlockSplitter = ZSTD_resolveBlockSplitterMode(params.useBlockSplitter, ¶ms.cParams); - params.ldmParams.enableLdm = ZSTD_resolveEnableLdm(params.ldmParams.enableLdm, ¶ms.cParams); - params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams); - params.validateSequences = ZSTD_resolveExternalSequenceValidation(params.validateSequences); - params.maxBlockSize = ZSTD_resolveMaxBlockSize(params.maxBlockSize); - params.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(params.searchForExternalRepcodes, params.compressionLevel); - -#ifdef ZSTD_MULTITHREAD - /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ - RETURN_ERROR_IF( - ZSTD_hasExtSeqProd(¶ms) && params.nbWorkers >= 1, - parameter_combination_unsupported, - "External sequence producer isn't supported with nbWorkers >= 1" - ); - - if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { - params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ - } - if (params.nbWorkers > 0) { -#if ZSTD_TRACE - cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; -#endif - /* mt context creation */ - if (cctx->mtctx == NULL) { - DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", - params.nbWorkers); - cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool); - RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); - } - /* mt compression */ - DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); - FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( - cctx->mtctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, - cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); - cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0; - cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize; - cctx->consumedSrcSize = 0; - cctx->producedCSize = 0; - cctx->streamStage = zcss_load; - cctx->appliedParams = params; - } else -#endif /* ZSTD_MULTITHREAD */ - { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, - prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, - cctx->cdict, - ¶ms, pledgedSrcSize, - ZSTDb_buffered) , ""); - assert(cctx->appliedParams.nbWorkers == 0); - cctx->inToCompress = 0; - cctx->inBuffPos = 0; - if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { - /* for small input: avoid automatic flush on reaching end of block, since - * it would require to add a 3-bytes null block to end frame - */ - cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); - } else { - cctx->inBuffTarget = 0; - } - cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; - cctx->streamStage = zcss_load; - cctx->frameEnded = 0; - } - return 0; -} -/* @return provides a minimum amount of data remaining to be flushed from internal buffers - */ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, @@ -6307,95 +3970,82 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, { DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); /* check conditions */ - RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); - RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); - RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); - assert(cctx != NULL); + RETURN_ERROR_IF(output->pos > output->size, GENERIC, "invalid buffer"); + RETURN_ERROR_IF(input->pos > input->size, GENERIC, "invalid buffer"); + assert(cctx!=NULL); /* transparent initialization stage */ if (cctx->streamStage == zcss_init) { - size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */ - size_t const totalInputSize = inputSize + cctx->stableIn_notConsumed; - if ( (cctx->requestedParams.inBufferMode == ZSTD_bm_stable) /* input is presumed stable, across invocations */ - && (endOp == ZSTD_e_continue) /* no flush requested, more input to come */ - && (totalInputSize < ZSTD_BLOCKSIZE_MAX) ) { /* not even reached one block yet */ - if (cctx->stableIn_notConsumed) { /* not the first time */ - /* check stable source guarantees */ - RETURN_ERROR_IF(input->src != cctx->expectedInBuffer.src, stabilityCondition_notRespected, "stableInBuffer condition not respected: wrong src pointer"); - RETURN_ERROR_IF(input->pos != cctx->expectedInBuffer.size, stabilityCondition_notRespected, "stableInBuffer condition not respected: externally modified pos"); - } - /* pretend input was consumed, to give a sense forward progress */ - input->pos = input->size; - /* save stable inBuffer, for later control, and flush/end */ - cctx->expectedInBuffer = *input; - /* but actually input wasn't consumed, so keep track of position from where compression shall resume */ - cctx->stableIn_notConsumed += inputSize; - /* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */ - return ZSTD_FRAMEHEADERSIZE_MIN(cctx->requestedParams.format); /* at least some header to produce */ + ZSTD_CCtx_params params = cctx->requestedParams; + ZSTD_prefixDict const prefixDict = cctx->prefixDict; + FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ + memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ + assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ + DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); + if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ + params.cParams = ZSTD_getCParamsFromCCtxParams( + &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); + + +#ifdef ZSTD_MULTITHREAD + if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { + params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ } - FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, totalInputSize), "compressStream2 initialization failed"); - ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ - } + if (params.nbWorkers > 0) { + /* mt context creation */ + if (cctx->mtctx == NULL) { + DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", + params.nbWorkers); + cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem); + RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); + } + /* mt compression */ + DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); + FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( + cctx->mtctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, + cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); + cctx->streamStage = zcss_load; + cctx->appliedParams.nbWorkers = params.nbWorkers; + } else +#endif + { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, + prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, + cctx->cdict, + params, cctx->pledgedSrcSizePlusOne-1) , ""); + assert(cctx->streamStage == zcss_load); + assert(cctx->appliedParams.nbWorkers == 0); + } } /* end of transparent initialization stage */ - FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); /* compression stage */ #ifdef ZSTD_MULTITHREAD if (cctx->appliedParams.nbWorkers > 0) { + int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); size_t flushMin; + assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); if (cctx->cParamsChanged) { ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); cctx->cParamsChanged = 0; } - if (cctx->stableIn_notConsumed) { - assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable); - /* some early data was skipped - make it available for consumption */ - assert(input->pos >= cctx->stableIn_notConsumed); - input->pos -= cctx->stableIn_notConsumed; - cctx->stableIn_notConsumed = 0; - } - for (;;) { - size_t const ipos = input->pos; - size_t const opos = output->pos; + do { flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); - cctx->consumedSrcSize += (U64)(input->pos - ipos); - cctx->producedCSize += (U64)(output->pos - opos); if ( ZSTD_isError(flushMin) || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ - if (flushMin == 0) - ZSTD_CCtx_trace(cctx, 0); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); } FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed"); - - if (endOp == ZSTD_e_continue) { - /* We only require some progress with ZSTD_e_continue, not maximal progress. - * We're done if we've consumed or produced any bytes, or either buffer is - * full. - */ - if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size) - break; - } else { - assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end); - /* We require maximal progress. We're done when the flush is complete or the - * output buffer is full. - */ - if (flushMin == 0 || output->pos == output->size) - break; - } - } + } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); /* Either we don't require maximum forward progress, we've finished the * flush, or we are out of output space. */ - assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size); - ZSTD_setBufferExpectations(cctx, output, input); + assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); return flushMin; } -#endif /* ZSTD_MULTITHREAD */ +#endif FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); DEBUGLOG(5, "completed ZSTD_compressStream2"); - ZSTD_setBufferExpectations(cctx, output, input); return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ } @@ -6405,43 +4055,27 @@ size_t ZSTD_compressStream2_simpleArgs ( const void* src, size_t srcSize, size_t* srcPos, ZSTD_EndDirective endOp) { - ZSTD_outBuffer output; - ZSTD_inBuffer input; - output.dst = dst; - output.size = dstCapacity; - output.pos = *dstPos; - input.src = src; - input.size = srcSize; - input.pos = *srcPos; + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ - { size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; - } + size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; } size_t ZSTD_compress2(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; - ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); - /* Enable stable input/output buffers. */ - cctx->requestedParams.inBufferMode = ZSTD_bm_stable; - cctx->requestedParams.outBufferMode = ZSTD_bm_stable; { size_t oPos = 0; size_t iPos = 0; size_t const result = ZSTD_compressStream2_simpleArgs(cctx, dst, dstCapacity, &oPos, src, srcSize, &iPos, ZSTD_e_end); - /* Reset to the original values. */ - cctx->requestedParams.inBufferMode = originalInBufferMode; - cctx->requestedParams.outBufferMode = originalOutBufferMode; - FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); if (result != 0) { /* compression not completed, due to lack of output space */ assert(oPos == dstCapacity); @@ -6452,512 +4086,22 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx, } } -/* ZSTD_validateSequence() : - * @offCode : is presumed to follow format required by ZSTD_storeSeq() - * @returns a ZSTD error code if sequence is not valid - */ -static size_t -ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, - size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) -{ - U32 const windowSize = 1u << windowLog; - /* posInSrc represents the amount of data the decoder would decode up to this point. - * As long as the amount of data decoded is less than or equal to window size, offsets may be - * larger than the total length of output decoded in order to reference the dict, even larger than - * window size. After output surpasses windowSize, we're limited to windowSize offsets again. - */ - size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; - size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; - RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); - /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ - RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); - return 0; -} - -/* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ -static U32 ZSTD_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) -{ - U32 offBase = OFFSET_TO_OFFBASE(rawOffset); - - if (!ll0 && rawOffset == rep[0]) { - offBase = REPCODE1_TO_OFFBASE; - } else if (rawOffset == rep[1]) { - offBase = REPCODE_TO_OFFBASE(2 - ll0); - } else if (rawOffset == rep[2]) { - offBase = REPCODE_TO_OFFBASE(3 - ll0); - } else if (ll0 && rawOffset == rep[0] - 1) { - offBase = REPCODE3_TO_OFFBASE; - } - return offBase; -} - -size_t -ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, - ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, - ZSTD_paramSwitch_e externalRepSearch) -{ - U32 idx = seqPos->idx; - U32 const startIdx = idx; - BYTE const* ip = (BYTE const*)(src); - const BYTE* const iend = ip + blockSize; - repcodes_t updatedRepcodes; - U32 dictSize; - - DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreExplicitBlockDelim (blockSize = %zu)", blockSize); - - if (cctx->cdict) { - dictSize = (U32)cctx->cdict->dictContentSize; - } else if (cctx->prefixDict.dict) { - dictSize = (U32)cctx->prefixDict.dictSize; - } else { - dictSize = 0; - } - ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); - for (; idx < inSeqsSize && (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0); ++idx) { - U32 const litLength = inSeqs[idx].litLength; - U32 const matchLength = inSeqs[idx].matchLength; - U32 offBase; - - if (externalRepSearch == ZSTD_ps_disable) { - offBase = OFFSET_TO_OFFBASE(inSeqs[idx].offset); - } else { - U32 const ll0 = (litLength == 0); - offBase = ZSTD_finalizeOffBase(inSeqs[idx].offset, updatedRepcodes.rep, ll0); - ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); - } - - DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); - if (cctx->appliedParams.validateSequences) { - seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), - "Sequence validation failed"); - } - RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, - "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); - ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); - ip += matchLength + litLength; - } - - /* If we skipped repcode search while parsing, we need to update repcodes now */ - assert(externalRepSearch != ZSTD_ps_auto); - assert(idx >= startIdx); - if (externalRepSearch == ZSTD_ps_disable && idx != startIdx) { - U32* const rep = updatedRepcodes.rep; - U32 lastSeqIdx = idx - 1; /* index of last non-block-delimiter sequence */ - - if (lastSeqIdx >= startIdx + 2) { - rep[2] = inSeqs[lastSeqIdx - 2].offset; - rep[1] = inSeqs[lastSeqIdx - 1].offset; - rep[0] = inSeqs[lastSeqIdx].offset; - } else if (lastSeqIdx == startIdx + 1) { - rep[2] = rep[0]; - rep[1] = inSeqs[lastSeqIdx - 1].offset; - rep[0] = inSeqs[lastSeqIdx].offset; - } else { - assert(lastSeqIdx == startIdx); - rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = inSeqs[lastSeqIdx].offset; - } - } - - ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); - - if (inSeqs[idx].litLength) { - DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); - ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); - ip += inSeqs[idx].litLength; - seqPos->posInSrc += inSeqs[idx].litLength; - } - RETURN_ERROR_IF(ip != iend, externalSequences_invalid, "Blocksize doesn't agree with block delimiter!"); - seqPos->idx = idx+1; - return 0; -} - -size_t -ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch) -{ - U32 idx = seqPos->idx; - U32 startPosInSequence = seqPos->posInSequence; - U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; - size_t dictSize; - BYTE const* ip = (BYTE const*)(src); - BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ - repcodes_t updatedRepcodes; - U32 bytesAdjustment = 0; - U32 finalMatchSplit = 0; - - /* TODO(embg) support fast parsing mode in noBlockDelim mode */ - (void)externalRepSearch; - - if (cctx->cdict) { - dictSize = cctx->cdict->dictContentSize; - } else if (cctx->prefixDict.dict) { - dictSize = cctx->prefixDict.dictSize; - } else { - dictSize = 0; - } - DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); - DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); - ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); - while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { - const ZSTD_Sequence currSeq = inSeqs[idx]; - U32 litLength = currSeq.litLength; - U32 matchLength = currSeq.matchLength; - U32 const rawOffset = currSeq.offset; - U32 offBase; - - /* Modify the sequence depending on where endPosInSequence lies */ - if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { - if (startPosInSequence >= litLength) { - startPosInSequence -= litLength; - litLength = 0; - matchLength -= startPosInSequence; - } else { - litLength -= startPosInSequence; - } - /* Move to the next sequence */ - endPosInSequence -= currSeq.litLength + currSeq.matchLength; - startPosInSequence = 0; - } else { - /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence - does not reach the end of the match. So, we have to split the sequence */ - DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", - currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); - if (endPosInSequence > litLength) { - U32 firstHalfMatchLength; - litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; - firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; - if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { - /* Only ever split the match if it is larger than the block size */ - U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; - if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { - /* Move the endPosInSequence backward so that it creates match of minMatch length */ - endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; - bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; - firstHalfMatchLength -= bytesAdjustment; - } - matchLength = firstHalfMatchLength; - /* Flag that we split the last match - after storing the sequence, exit the loop, - but keep the value of endPosInSequence */ - finalMatchSplit = 1; - } else { - /* Move the position in sequence backwards so that we don't split match, and break to store - * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence - * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so - * would cause the first half of the match to be too small - */ - bytesAdjustment = endPosInSequence - currSeq.litLength; - endPosInSequence = currSeq.litLength; - break; - } - } else { - /* This sequence ends inside the literals, break to store the last literals */ - break; - } - } - /* Check if this offset can be represented with a repcode */ - { U32 const ll0 = (litLength == 0); - offBase = ZSTD_finalizeOffBase(rawOffset, updatedRepcodes.rep, ll0); - ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); - } - - if (cctx->appliedParams.validateSequences) { - seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), - "Sequence validation failed"); - } - DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); - RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, - "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); - ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); - ip += matchLength + litLength; - if (!finalMatchSplit) - idx++; /* Next Sequence */ - } - DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); - assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); - seqPos->idx = idx; - seqPos->posInSequence = endPosInSequence; - ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); - - iend -= bytesAdjustment; - if (ip != iend) { - /* Store any last literals */ - U32 lastLLSize = (U32)(iend - ip); - assert(ip <= iend); - DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); - ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); - seqPos->posInSrc += lastLLSize; - } - - return bytesAdjustment; -} - -typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); -static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) -{ - ZSTD_sequenceCopier sequenceCopier = NULL; - assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); - if (mode == ZSTD_sf_explicitBlockDelimiters) { - return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; - } else if (mode == ZSTD_sf_noBlockDelimiters) { - return ZSTD_copySequencesToSeqStoreNoBlockDelim; - } - assert(sequenceCopier != NULL); - return sequenceCopier; -} - -/* Discover the size of next block by searching for the delimiter. - * Note that a block delimiter **must** exist in this mode, - * otherwise it's an input error. - * The block size retrieved will be later compared to ensure it remains within bounds */ -static size_t -blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) -{ - int end = 0; - size_t blockSize = 0; - size_t spos = seqPos.idx; - DEBUGLOG(6, "blockSize_explicitDelimiter : seq %zu / %zu", spos, inSeqsSize); - assert(spos <= inSeqsSize); - while (spos < inSeqsSize) { - end = (inSeqs[spos].offset == 0); - blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength; - if (end) { - if (inSeqs[spos].matchLength != 0) - RETURN_ERROR(externalSequences_invalid, "delimiter format error : both matchlength and offset must be == 0"); - break; - } - spos++; - } - if (!end) - RETURN_ERROR(externalSequences_invalid, "Reached end of sequences without finding a block delimiter"); - return blockSize; -} - -/* More a "target" block size */ -static size_t blockSize_noDelimiter(size_t blockSize, size_t remaining) -{ - int const lastBlock = (remaining <= blockSize); - return lastBlock ? remaining : blockSize; -} - -static size_t determine_blockSize(ZSTD_sequenceFormat_e mode, - size_t blockSize, size_t remaining, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) -{ - DEBUGLOG(6, "determine_blockSize : remainingSize = %zu", remaining); - if (mode == ZSTD_sf_noBlockDelimiters) - return blockSize_noDelimiter(blockSize, remaining); - { size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos); - FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters"); - if (explicitBlockSize > blockSize) - RETURN_ERROR(externalSequences_invalid, "sequences incorrectly define a too large block"); - if (explicitBlockSize > remaining) - RETURN_ERROR(externalSequences_invalid, "sequences define a frame longer than source"); - return explicitBlockSize; - } -} - -/* Compress, block-by-block, all of the sequences given. - * - * Returns the cumulative size of all compressed blocks (including their headers), - * otherwise a ZSTD error. - */ -static size_t -ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize) -{ - size_t cSize = 0; - size_t remaining = srcSize; - ZSTD_sequencePosition seqPos = {0, 0, 0}; - - BYTE const* ip = (BYTE const*)src; - BYTE* op = (BYTE*)dst; - ZSTD_sequenceCopier const sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); - - DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); - /* Special case: empty frame */ - if (remaining == 0) { - U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); - MEM_writeLE32(op, cBlockHeader24); - op += ZSTD_blockHeaderSize; - dstCapacity -= ZSTD_blockHeaderSize; - cSize += ZSTD_blockHeaderSize; - } - - while (remaining) { - size_t compressedSeqsSize; - size_t cBlockSize; - size_t additionalByteAdjustment; - size_t blockSize = determine_blockSize(cctx->appliedParams.blockDelimiters, - cctx->blockSize, remaining, - inSeqs, inSeqsSize, seqPos); - U32 const lastBlock = (blockSize == remaining); - FORWARD_IF_ERROR(blockSize, "Error while trying to determine block size"); - assert(blockSize <= remaining); - ZSTD_resetSeqStore(&cctx->seqStore); - DEBUGLOG(5, "Working on new block. Blocksize: %zu (total:%zu)", blockSize, (ip - (const BYTE*)src) + blockSize); - - additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize, cctx->appliedParams.searchForExternalRepcodes); - FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); - blockSize -= additionalByteAdjustment; - - /* If blocks are too small, emit as a nocompress block */ - /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding - * additional 1. We need to revisit and change this logic to be more consistent */ - if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { - cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); - DEBUGLOG(5, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); - cSize += cBlockSize; - ip += blockSize; - op += cBlockSize; - remaining -= blockSize; - dstCapacity -= cBlockSize; - continue; - } - - RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "not enough dstCapacity to write a new compressed block"); - compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore, - &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, - &cctx->appliedParams, - op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, - blockSize, - cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, - cctx->bmi2); - FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); - DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); - - if (!cctx->isFirstBlock && - ZSTD_maybeRLE(&cctx->seqStore) && - ZSTD_isRLE(ip, blockSize)) { - /* We don't want to emit our first block as a RLE even if it qualifies because - * doing so will cause the decoder (cli only) to throw a "should consume all input error." - * This is only an issue for zstd <= v1.4.3 - */ - compressedSeqsSize = 1; - } - - if (compressedSeqsSize == 0) { - /* ZSTD_noCompressBlock writes the block header as well */ - cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "ZSTD_noCompressBlock failed"); - DEBUGLOG(5, "Writing out nocompress block, size: %zu", cBlockSize); - } else if (compressedSeqsSize == 1) { - cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); - FORWARD_IF_ERROR(cBlockSize, "ZSTD_rleCompressBlock failed"); - DEBUGLOG(5, "Writing out RLE block, size: %zu", cBlockSize); - } else { - U32 cBlockHeader; - /* Error checking and repcodes update */ - ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState); - if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) - cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; - - /* Write block header into beginning of block*/ - cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); - MEM_writeLE24(op, cBlockHeader); - cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; - DEBUGLOG(5, "Writing out compressed block, size: %zu", cBlockSize); - } - - cSize += cBlockSize; - - if (lastBlock) { - break; - } else { - ip += blockSize; - op += cBlockSize; - remaining -= blockSize; - dstCapacity -= cBlockSize; - cctx->isFirstBlock = 0; - } - DEBUGLOG(5, "cSize running total: %zu (remaining dstCapacity=%zu)", cSize, dstCapacity); - } - - DEBUGLOG(4, "cSize final total: %zu", cSize); - return cSize; -} - -size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize) -{ - BYTE* op = (BYTE*)dst; - size_t cSize = 0; - size_t compressedBlocksSize = 0; - size_t frameHeaderSize = 0; - - /* Transparent initialization stage, same as compressStream2() */ - DEBUGLOG(4, "ZSTD_compressSequences (dstCapacity=%zu)", dstCapacity); - assert(cctx != NULL); - FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); - /* Begin writing output, starting with frame header */ - frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); - op += frameHeaderSize; - dstCapacity -= frameHeaderSize; - cSize += frameHeaderSize; - if (cctx->appliedParams.fParams.checksumFlag && srcSize) { - XXH64_update(&cctx->xxhState, src, srcSize); - } - /* cSize includes block header size and compressed sequences size */ - compressedBlocksSize = ZSTD_compressSequences_internal(cctx, - op, dstCapacity, - inSeqs, inSeqsSize, - src, srcSize); - FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); - cSize += compressedBlocksSize; - dstCapacity -= compressedBlocksSize; - - if (cctx->appliedParams.fParams.checksumFlag) { - U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); - RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); - DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); - MEM_writeLE32((char*)dst + cSize, checksum); - cSize += 4; - } - - DEBUGLOG(4, "Final compressed size: %zu", cSize); - return cSize; -} - /*====== Finalize ======*/ -static ZSTD_inBuffer inBuffer_forEndFlush(const ZSTD_CStream* zcs) -{ - const ZSTD_inBuffer nullInput = { NULL, 0, 0 }; - const int stableInput = (zcs->appliedParams.inBufferMode == ZSTD_bm_stable); - return stableInput ? zcs->expectedInBuffer : nullInput; -} - /*! ZSTD_flushStream() : * @return : amount of data remaining to flush */ size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); - input.size = input.pos; /* do not ingest more input during flush */ + ZSTD_inBuffer input = { NULL, 0, 0 }; return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); } size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) { - ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); + ZSTD_inBuffer input = { NULL, 0, 0 }; size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); - FORWARD_IF_ERROR(remainingToFlush , "ZSTD_compressStream2(,,ZSTD_e_end) failed"); + FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed"); if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ /* single thread mode : attempt to calculate remaining to flush more precisely */ { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; @@ -6968,121 +4112,139 @@ size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) } } -} // namespace duckdb_zstd /*-===== Pre-defined compression levels =====-*/ -#include "zstd/compress/clevels.h" - -namespace duckdb_zstd { +#define ZSTD_MAX_CLEVEL 22 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } -int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } - -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) -{ - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); - switch (cParams.strategy) { - case ZSTD_fast: - case ZSTD_dfast: - break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; - break; - case ZSTD_btlazy2: - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - break; - } - return cParams; -} - -static int ZSTD_dedicatedDictSearch_isSupported( - ZSTD_compressionParameters const* cParams) -{ - return (cParams->strategy >= ZSTD_greedy) - && (cParams->strategy <= ZSTD_lazy2) - && (cParams->hashLog > cParams->chainLog) - && (cParams->chainLog <= 24); -} -/** - * Reverses the adjustment applied to cparams when enabling dedicated dict - * search. This is used to recover the params set to be used in the working - * context. (Otherwise, those tables would also grow.) - */ -static void ZSTD_dedicatedDictSearch_revertCParams( - ZSTD_compressionParameters* cParams) { - switch (cParams->strategy) { - case ZSTD_fast: - case ZSTD_dfast: - break; - case ZSTD_greedy: - case ZSTD_lazy: - case ZSTD_lazy2: - cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; - if (cParams->hashLog < ZSTD_HASHLOG_MIN) { - cParams->hashLog = ZSTD_HASHLOG_MIN; - } - break; - case ZSTD_btlazy2: - case ZSTD_btopt: - case ZSTD_btultra: - case ZSTD_btultra2: - break; - } -} - -static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) -{ - switch (mode) { - case ZSTD_cpm_unknown: - case ZSTD_cpm_noAttachDict: - case ZSTD_cpm_createCDict: - break; - case ZSTD_cpm_attachDict: - dictSize = 0; - break; - default: - assert(0); - break; - } - { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; - size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; - return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; - } -} +static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { +{ /* "default" - for any srcSize > 256 KB */ + /* W, C, H, S, L, TL, strat */ + { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ + { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ + { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ + { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ + { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ + { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ + { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ + { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ + { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ + { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ + { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ + { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ + { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ + { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ + { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ + { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ + { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ + { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ + { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ + { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ + { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ + { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ + { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ +}, +{ /* for srcSize <= 256 KB */ + /* W, C, H, S, L, T, strat */ + { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ + { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ + { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ + { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ + { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ + { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ + { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ + { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ + { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ + { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 128 KB */ + /* W, C, H, S, L, T, strat */ + { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ + { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ + { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ + { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ + { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ + { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ + { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ + { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ + { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ + { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ + { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ + { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ + { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ + { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ + { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ + { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ + { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +{ /* for srcSize <= 16 KB */ + /* W, C, H, S, L, T, strat */ + { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ + { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ + { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ + { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ + { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ + { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ + { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ + { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ + { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ + { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ + { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ + { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ + { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ + { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ + { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ + { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ + { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ + { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ + { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ + { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ + { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ + { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ +}, +}; /*! ZSTD_getCParams_internal() : * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. - * Use dictSize == 0 for unknown or unused. - * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) + * Use dictSize == 0 for unknown or unused. */ +static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { - U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); + int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; + size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; + U64 const rSize = unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); - int row; + int row = compressionLevel; DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); - - /* row */ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ - else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ - else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; - else row = compressionLevel; - + if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ + if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; - DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); - /* acceleration factor */ - if (compressionLevel < 0) { - int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); - cp.targetLength = (unsigned)(-clampedCompressionLevel); - } + if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ /* refine parameters based on srcSize & dictSize */ - return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode, ZSTD_ps_auto); + return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); } } @@ -7092,18 +4254,18 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); + return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize); } /*! ZSTD_getParams() : * same idea as ZSTD_getCParams() * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). * Fields of `ZSTD_frameParameters` are set to default values */ -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { +static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); + ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize); DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); - ZSTD_memset(¶ms, 0, sizeof(params)); + memset(¶ms, 0, sizeof(params)); params.cParams = cParams; params.fParams.contentSizeFlag = 1; return params; @@ -7115,33 +4277,7 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned lo * Fields of `ZSTD_frameParameters` are set to default values */ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); -} - -void ZSTD_registerSequenceProducer( - ZSTD_CCtx* zc, - void* extSeqProdState, - ZSTD_sequenceProducer_F extSeqProdFunc -) { - assert(zc != NULL); - ZSTD_CCtxParams_registerSequenceProducer( - &zc->requestedParams, extSeqProdState, extSeqProdFunc - ); -} - -void ZSTD_CCtxParams_registerSequenceProducer( - ZSTD_CCtx_params* params, - void* extSeqProdState, - ZSTD_sequenceProducer_F extSeqProdFunc -) { - assert(params != NULL); - if (extSeqProdFunc != NULL) { - params->extSeqProdFunc = extSeqProdFunc; - params->extSeqProdState = extSeqProdState; - } else { - params->extSeqProdFunc = NULL; - params->extSeqProdState = NULL; - } + return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp index b68340da7..ab9dfb459 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_literals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,36 +14,11 @@ #include "zstd/compress/zstd_compress_literals.h" namespace duckdb_zstd { - -/* ************************************************************** -* Debug Traces -****************************************************************/ -#if DEBUGLEVEL >= 2 - -static size_t showHexa(const void* src, size_t srcSize) -{ - const BYTE* const ip = (const BYTE*)src; - size_t u; - for (u=0; u31) + (srcSize>4095); - DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity); - RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, ""); switch(flSize) @@ -61,31 +36,17 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, assert(0); } - ZSTD_memcpy(ostart + flSize, src, srcSize); - DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); + memcpy(ostart + flSize, src, srcSize); + DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); return srcSize + flSize; } -static int allBytesIdentical(const void* src, size_t srcSize) -{ - assert(srcSize >= 1); - assert(src != NULL); - { const BYTE b = ((const BYTE*)src)[0]; - size_t p; - for (p=1; p31) + (srcSize>4095); - assert(dstCapacity >= 4); (void)dstCapacity; - assert(allBytesIdentical(src, srcSize)); + (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ switch(flSize) { @@ -103,103 +64,68 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* } ostart[flSize] = *(const BYTE*)src; - DEBUGLOG(5, "RLE : Repeated Literal (%02X: %u times) -> %u bytes encoded", ((const BYTE*)src)[0], (U32)srcSize, (U32)flSize + 1); + DEBUGLOG(5, "RLE literals: %u -> %u", (U32)srcSize, (U32)flSize + 1); return flSize+1; } -/* ZSTD_minLiteralsToCompress() : - * returns minimal amount of literals - * for literal compression to even be attempted. - * Minimum is made tighter as compression strategy increases. - */ -static size_t -ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat) -{ - assert((int)strategy >= 0); - assert((int)strategy <= 9); - /* btultra2 : min 8 bytes; - * then 2x larger for each successive compression strategy - * max threshold 64 bytes */ - { int const shift = MIN(9-(int)strategy, 3); - size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : (size_t)8 << shift; - DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc); - return mintc; - } -} - -size_t ZSTD_compressLiterals ( - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const ZSTD_hufCTables_t* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, - int disableLiteralCompression, - int suspectUncompressible, - int bmi2) +size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, int disableLiteralCompression, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const int bmi2) { + size_t const minGain = ZSTD_minGain(srcSize, strategy); size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); BYTE* const ostart = (BYTE*)dst; U32 singleStream = srcSize < 256; symbolEncodingType_e hType = set_compressed; size_t cLitSize; - DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)", - disableLiteralCompression, (U32)srcSize, dstCapacity); - - DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize)); + DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i srcSize=%u)", + disableLiteralCompression, (U32)srcSize); /* Prepare nextEntropy assuming reusing the existing table */ - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); if (disableLiteralCompression) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - /* if too small, don't even attempt compression (speed opt) */ - if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode)) - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + /* small ? don't even attempt compression (speed opt) */ +# define COMPRESS_LITERALS_SIZE_MIN 63 + { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; + if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); { HUF_repeat repeat = prevHuf->repeatMode; - int const flags = 0 - | (bmi2 ? HUF_flags_bmi2 : 0) - | (strategy < ZSTD_lazy && srcSize <= 1024 ? HUF_flags_preferRepeat : 0) - | (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_flags_optimalDepth : 0) - | (suspectUncompressible ? HUF_flags_suspectUncompressible : 0); - - typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int); - huf_compress_f huf_compress; + int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; - huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; - cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, - src, srcSize, - HUF_SYMBOLVALUE_MAX, LitHufLog, - entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, - &repeat, flags); - DEBUGLOG(5, "%zu literals compressed into %zu bytes (before header)", srcSize, cLitSize); + cLitSize = singleStream ? + HUF_compress1X_repeat( + ostart+lhSize, dstCapacity-lhSize, src, srcSize, + HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) : + HUF_compress4X_repeat( + ostart+lhSize, dstCapacity-lhSize, src, srcSize, + HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); if (repeat != HUF_repeat_none) { /* reused the existing table */ - DEBUGLOG(5, "reusing statistics from previous huffman block"); + DEBUGLOG(5, "Reusing previous huffman table"); hType = set_repeat; } } - { size_t const minGain = ZSTD_minGain(srcSize, strategy); - if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } } + if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } if (cLitSize==1) { - /* A return value of 1 signals that the alphabet consists of a single symbol. - * However, in some rare circumstances, it could be the compressed size (a single byte). - * For that outcome to have a chance to happen, it's necessary that `srcSize < 8`. - * (it's also necessary to not generate statistics). - * Therefore, in such a case, actively check that all bytes are identical. */ - if ((srcSize >= 8) || allBytesIdentical(src, srcSize)) { - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); - } } + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); + } if (hType == set_compressed) { /* using a newly constructed table */ @@ -210,19 +136,16 @@ size_t ZSTD_compressLiterals ( switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - if (!singleStream) assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); - { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); + { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } case 4: /* 2 - 2 - 14 - 14 */ - assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); MEM_writeLE32(ostart, lhc); break; } case 5: /* 2 - 2 - 18 - 18 */ - assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); MEM_writeLE32(ostart, lhc); ostart[4] = (BYTE)(cLitSize >> 10); @@ -235,4 +158,4 @@ size_t ZSTD_compressLiterals ( return lhSize+cLitSize; } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp index 0ab822622..e1cc14597 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_sequences.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,7 +14,6 @@ #include "zstd/compress/zstd_compress_sequences.h" namespace duckdb_zstd { - /** * -log2(x / 256) lookup table for x in [0, 256). * If x == 0: Return 0 @@ -52,19 +51,6 @@ static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { return maxSymbolValue; } -/** - * Returns true if we should use ncount=-1 else we should - * use ncount=1 for low probability symbols instead. - */ -static unsigned ZSTD_useLowProbCount(size_t const nbSeq) -{ - /* Heuristic: This should cover most blocks <= 16K and - * start to fade out after 16K to about 32K depending on - * compressibility. - */ - return nbSeq >= 2048; -} - /** * Returns the cost in bytes of encoding the normalized count header. * Returns an error if any of the helper functions return an error. @@ -75,7 +61,7 @@ static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, BYTE wksp[FSE_NCOUNTBOUND]; S16 norm[MaxSeq + 1]; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); - FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max, ZSTD_useLowProbCount(nbSeq)), ""); + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max), ""); return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); } @@ -87,8 +73,6 @@ static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t { unsigned cost = 0; unsigned s; - - assert(total > 0); for (s = 0; s <= max; ++s) { unsigned norm = (unsigned)((256 * count[s]) / total); if (count[s] != 0 && norm == 0) @@ -168,7 +152,7 @@ ZSTD_selectEncodingType( if (mostFrequent == nbSeq) { *repeatMode = FSE_repeat_none; if (isDefaultAllowed && nbSeq <= 2) { - /* Prefer set_basic over set_rle when there are 2 or fewer symbols, + /* Prefer set_basic over set_rle when there are 2 or less symbols, * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. * If basic encoding isn't possible, always choose RLE. */ @@ -236,11 +220,6 @@ ZSTD_selectEncodingType( return set_compressed; } -typedef struct { - S16 norm[MaxSeq + 1]; - U32 wksp[FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(MaxSeq, MaxFSELog)]; -} ZSTD_BuildCTableWksp; - size_t ZSTD_buildCTable(void* dst, size_t dstCapacity, FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, @@ -261,13 +240,13 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, *op = codeTable[0]; return 1; case set_repeat: - ZSTD_memcpy(nextCTable, prevCTable, prevCTableSize); + memcpy(nextCTable, prevCTable, prevCTableSize); return 0; case set_basic: FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, entropyWorkspace, entropyWorkspaceSize), ""); /* note : could be pre-calculated */ return 0; case set_compressed: { - ZSTD_BuildCTableWksp* wksp = (ZSTD_BuildCTableWksp*)entropyWorkspace; + S16 norm[MaxSeq + 1]; size_t nbSeq_1 = nbSeq; const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); if (count[codeTable[nbSeq-1]] > 1) { @@ -275,13 +254,10 @@ ZSTD_buildCTable(void* dst, size_t dstCapacity, nbSeq_1--; } assert(nbSeq_1 > 1); - assert(entropyWorkspaceSize >= sizeof(ZSTD_BuildCTableWksp)); - (void)entropyWorkspaceSize; - FORWARD_IF_ERROR(FSE_normalizeCount(wksp->norm, tableLog, count, nbSeq_1, max, ZSTD_useLowProbCount(nbSeq_1)), "FSE_normalizeCount failed"); - assert(oend >= op); - { size_t const NCountSize = FSE_writeNCount(op, (size_t)(oend - op), wksp->norm, max, tableLog); /* overflow protected */ + FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max), ""); + { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ FORWARD_IF_ERROR(NCountSize, "FSE_writeNCount failed"); - FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, wksp->norm, max, tableLog, wksp->wksp, sizeof(wksp->wksp)), "FSE_buildCTable_wksp failed"); + FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, entropyWorkspace, entropyWorkspaceSize), ""); return NCountSize; } } @@ -313,21 +289,21 @@ ZSTD_encodeSequences_body( FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); - BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, ZSTDInternalConstants::LL_bits[llCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[nbSeq-1].mlBase, ML_bits[mlCodeTable[nbSeq-1]]); + BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ZSTDInternalConstants::ML_bits[mlCodeTable[nbSeq-1]]); if (MEM_32bits()) BIT_flushBits(&blockStream); if (longOffsets) { U32 const ofBits = ofCodeTable[nbSeq-1]; unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, extraBits); + BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); BIT_flushBits(&blockStream); } - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase >> extraBits, + BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, ofBits - extraBits); } else { - BIT_addBits(&blockStream, sequences[nbSeq-1].offBase, ofCodeTable[nbSeq-1]); + BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); } BIT_flushBits(&blockStream); @@ -336,13 +312,13 @@ ZSTD_encodeSequences_body( BYTE const llCode = llCodeTable[n]; BYTE const ofCode = ofCodeTable[n]; BYTE const mlCode = mlCodeTable[n]; - U32 const llBits = LL_bits[llCode]; + U32 const llBits = ZSTDInternalConstants::LL_bits[llCode]; U32 const ofBits = ofCode; - U32 const mlBits = ML_bits[mlCode]; + U32 const mlBits = ZSTDInternalConstants::ML_bits[mlCode]; DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", (unsigned)sequences[n].litLength, - (unsigned)sequences[n].mlBase + MINMATCH, - (unsigned)sequences[n].offBase); + (unsigned)sequences[n].matchLength + MINMATCH, + (unsigned)sequences[n].offset); /* 32b*/ /* 64b*/ /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ @@ -353,18 +329,18 @@ ZSTD_encodeSequences_body( BIT_flushBits(&blockStream); /* (7)*/ BIT_addBits(&blockStream, sequences[n].litLength, llBits); if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); - BIT_addBits(&blockStream, sequences[n].mlBase, mlBits); + BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); if (longOffsets) { unsigned const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); if (extraBits) { - BIT_addBits(&blockStream, sequences[n].offBase, extraBits); + BIT_addBits(&blockStream, sequences[n].offset, extraBits); BIT_flushBits(&blockStream); /* (7)*/ } - BIT_addBits(&blockStream, sequences[n].offBase >> extraBits, + BIT_addBits(&blockStream, sequences[n].offset >> extraBits, ofBits - extraBits); /* 31 */ } else { - BIT_addBits(&blockStream, sequences[n].offBase, ofBits); /* 31 */ + BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ } BIT_flushBits(&blockStream); /* (7)*/ DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr)); @@ -401,7 +377,7 @@ ZSTD_encodeSequences_default( #if DYNAMIC_BMI2 -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t ZSTD_encodeSequences_bmi2( void* dst, size_t dstCapacity, FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, @@ -443,4 +419,4 @@ size_t ZSTD_encodeSequences( sequences, nbSeq, longOffsets); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp b/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp index 1ad0d3aa0..559a3a0cd 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_compress_superblock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,11 +15,288 @@ #include "zstd/common/zstd_internal.h" /* ZSTD_getSequenceLength */ #include "zstd/compress/hist.h" /* HIST_countFast_wksp */ -#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */ +#include "zstd/compress/zstd_compress_internal.h" #include "zstd/compress/zstd_compress_sequences.h" #include "zstd/compress/zstd_compress_literals.h" namespace duckdb_zstd { +/*-************************************* +* Superblock entropy buffer structs +***************************************/ +/** ZSTD_hufCTablesMetadata_t : + * Stores Literals Block Type for a super-block in hType, and + * huffman tree description in hufDesBuffer. + * hufDesSize refers to the size of huffman tree description in bytes. + * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */ +typedef struct { + symbolEncodingType_e hType; + BYTE hufDesBuffer[500]; /* TODO give name to this value */ + size_t hufDesSize; +} ZSTD_hufCTablesMetadata_t; + +/** ZSTD_fseCTablesMetadata_t : + * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and + * fse tables in fseTablesBuffer. + * fseTablesSize refers to the size of fse tables in bytes. + * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */ +typedef struct { + symbolEncodingType_e llType; + symbolEncodingType_e ofType; + symbolEncodingType_e mlType; + BYTE fseTablesBuffer[500]; /* TODO give name to this value */ + size_t fseTablesSize; + size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */ +} ZSTD_fseCTablesMetadata_t; + +typedef struct { + ZSTD_hufCTablesMetadata_t hufMetadata; + ZSTD_fseCTablesMetadata_t fseMetadata; +} ZSTD_entropyCTablesMetadata_t; + + +/** ZSTD_buildSuperBlockEntropy_literal() : + * Builds entropy for the super-block literals. + * Stores literals block type (raw, rle, compressed, repeat) and + * huffman description table to hufMetadata. + * @return : size of huffman description table or error code */ +static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize, + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_hufCTablesMetadata_t* hufMetadata, + const int disableLiteralsCompression, + void* workspace, size_t wkspSize) +{ + BYTE* const wkspStart = (BYTE*)workspace; + BYTE* const wkspEnd = wkspStart + wkspSize; + BYTE* const countWkspStart = wkspStart; + unsigned* const countWksp = (unsigned*)workspace; + const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); + BYTE* const nodeWksp = countWkspStart + countWkspSize; + const size_t nodeWkspSize = wkspEnd-nodeWksp; + unsigned maxSymbolValue = 255; + unsigned huffLog = HUF_TABLELOG_DEFAULT; + HUF_repeat repeat = prevHuf->repeatMode; + + DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize); + + /* Prepare nextEntropy assuming reusing the existing table */ + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + + if (disableLiteralsCompression) { + DEBUGLOG(5, "set_basic - disabled"); + hufMetadata->hType = set_basic; + return 0; + } + + /* small ? don't even attempt compression (speed opt) */ +# define COMPRESS_LITERALS_SIZE_MIN 63 + { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; + if (srcSize <= minLitSize) { + DEBUGLOG(5, "set_basic - too small"); + hufMetadata->hType = set_basic; + return 0; + } + } + + /* Scan input and build symbol stats */ + { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize); + FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); + if (largest == srcSize) { + DEBUGLOG(5, "set_rle"); + hufMetadata->hType = set_rle; + return 0; + } + if (largest <= (srcSize >> 7)+4) { + DEBUGLOG(5, "set_basic - no gain"); + hufMetadata->hType = set_basic; + return 0; + } + } + + /* Validate the previous Huffman table */ + if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { + repeat = HUF_repeat_none; + } + + /* Build Huffman Tree */ + memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); + huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); + { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, + maxSymbolValue, huffLog, + nodeWksp, nodeWkspSize); + FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); + huffLog = (U32)maxBits; + { /* Build and write the CTable */ + size_t const newCSize = HUF_estimateCompressedSize( + (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); + size_t const hSize = HUF_writeCTable( + hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), + (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog); + /* Check against repeating the previous CTable */ + if (repeat != HUF_repeat_none) { + size_t const oldCSize = HUF_estimateCompressedSize( + (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); + if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { + DEBUGLOG(5, "set_repeat - smaller"); + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_repeat; + return 0; + } + } + if (newCSize + hSize >= srcSize) { + DEBUGLOG(5, "set_basic - no gains"); + memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + hufMetadata->hType = set_basic; + return 0; + } + DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); + hufMetadata->hType = set_compressed; + nextHuf->repeatMode = HUF_repeat_check; + return hSize; + } + } +} + +/** ZSTD_buildSuperBlockEntropy_sequences() : + * Builds entropy for the super-block sequences. + * Stores symbol compression modes and fse table to fseMetadata. + * @return : size of fse tables or error code */ +static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr, + const ZSTD_fseCTables_t* prevEntropy, + ZSTD_fseCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_fseCTablesMetadata_t* fseMetadata, + void* workspace, size_t wkspSize) +{ + BYTE* const wkspStart = (BYTE*)workspace; + BYTE* const wkspEnd = wkspStart + wkspSize; + BYTE* const countWkspStart = wkspStart; + unsigned* const countWksp = (unsigned*)workspace; + const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned); + BYTE* const cTableWksp = countWkspStart + countWkspSize; + const size_t cTableWkspSize = wkspEnd-cTableWksp; + ZSTD_strategy const strategy = cctxParams->cParams.strategy; + FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; + FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; + FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; + const BYTE* const ofCodeTable = seqStorePtr->ofCode; + const BYTE* const llCodeTable = seqStorePtr->llCode; + const BYTE* const mlCodeTable = seqStorePtr->mlCode; + size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; + BYTE* const ostart = fseMetadata->fseTablesBuffer; + BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); + BYTE* op = ostart; + + assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE)); + DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq); + memset(workspace, 0, wkspSize); + + fseMetadata->lastCountSize = 0; + /* convert length/distances into codes */ + ZSTD_seqToCodes(seqStorePtr); + /* build CTable for Literal Lengths */ + { U32 LLtype; + unsigned max = MaxLL; + size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ + DEBUGLOG(5, "Building LL table"); + nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; + LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, + countWksp, max, mostFrequent, nbSeq, + LLFSELog, prevEntropy->litlengthCTable, + ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(set_basic < set_compressed && set_rle < set_compressed); + assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, + countWksp, max, llCodeTable, nbSeq, ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, MaxLL, + prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable), + cTableWksp, cTableWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); + if (LLtype == set_compressed) + fseMetadata->lastCountSize = countSize; + op += countSize; + fseMetadata->llType = (symbolEncodingType_e) LLtype; + } } + /* build CTable for Offsets */ + { U32 Offtype; + unsigned max = MaxOff; + size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ + /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ + ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; + DEBUGLOG(5, "Building OF table"); + nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; + Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, + countWksp, max, mostFrequent, nbSeq, + OffFSELog, prevEntropy->offcodeCTable, + ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, + defaultPolicy, strategy); + assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, + countWksp, max, ofCodeTable, nbSeq, ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, DefaultMaxOff, + prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable), + cTableWksp, cTableWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); + if (Offtype == set_compressed) + fseMetadata->lastCountSize = countSize; + op += countSize; + fseMetadata->ofType = (symbolEncodingType_e) Offtype; + } } + /* build CTable for MatchLengths */ + { U32 MLtype; + unsigned max = MaxML; + size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ + DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); + nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; + MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, + countWksp, max, mostFrequent, nbSeq, + MLFSELog, prevEntropy->matchlengthCTable, + ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, + ZSTD_defaultAllowed, strategy); + assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ + { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, + countWksp, max, mlCodeTable, nbSeq, ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, MaxML, + prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable), + cTableWksp, cTableWkspSize); + FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); + if (MLtype == set_compressed) + fseMetadata->lastCountSize = countSize; + op += countSize; + fseMetadata->mlType = (symbolEncodingType_e) MLtype; + } } + assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer)); + return op-ostart; +} + + +/** ZSTD_buildSuperBlockEntropy() : + * Builds entropy for the super-block. + * @return : 0 on success or error code */ +static size_t +ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr, + const ZSTD_entropyCTables_t* prevEntropy, + ZSTD_entropyCTables_t* nextEntropy, + const ZSTD_CCtx_params* cctxParams, + ZSTD_entropyCTablesMetadata_t* entropyMetadata, + void* workspace, size_t wkspSize) +{ + size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart; + DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy"); + entropyMetadata->hufMetadata.hufDesSize = + ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize, + &prevEntropy->huf, &nextEntropy->huf, + &entropyMetadata->hufMetadata, + ZSTD_disableLiteralsCompression(cctxParams), + workspace, wkspSize); + FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed"); + entropyMetadata->fseMetadata.fseTablesSize = + ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr, + &prevEntropy->fse, &nextEntropy->fse, + cctxParams, + &entropyMetadata->fseMetadata, + workspace, wkspSize); + FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed"); + return 0; +} /** ZSTD_compressSubBlock_literal() : * Compresses literals section for a sub-block. @@ -28,7 +305,7 @@ namespace duckdb_zstd { * before we know the table size + compressed size, so we have a bound on the * table size. If we guessed incorrectly, we fall back to uncompressed literals. * - * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded + * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded * in writing the header, otherwise it is set to 0. * * hufMetadata->hType has literals block type info. @@ -38,14 +315,13 @@ namespace duckdb_zstd { * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block * and the following sub-blocks' literals sections will be Treeless_Literals_Block. * @return : compressed size of literals section of a sub-block - * Or 0 if unable to compress. + * Or 0 if it unable to compress. * Or error code */ -static size_t -ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, - const ZSTD_hufCTablesMetadata_t* hufMetadata, - const BYTE* literals, size_t litSize, - void* dst, size_t dstSize, - const int bmi2, int writeEntropy, int* entropyWritten) +static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, + const ZSTD_hufCTablesMetadata_t* hufMetadata, + const BYTE* literals, size_t litSize, + void* dst, size_t dstSize, + const int bmi2, int writeEntropy, int* entropyWritten) { size_t const header = writeEntropy ? 200 : 0; size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); @@ -56,6 +332,8 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; size_t cLitSize = 0; + (void)bmi2; /* TODO bmi2... */ + DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); *entropyWritten = 0; @@ -71,15 +349,15 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); if (writeEntropy && hufMetadata->hType == set_compressed) { - ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); + memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); op += hufMetadata->hufDesSize; cLitSize += hufMetadata->hufDesSize; DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); } - { int const flags = bmi2 ? HUF_flags_bmi2 : 0; - const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags) - : HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags); + /* TODO bmi2 */ + { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable) + : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable); op += cSize; cLitSize += cSize; if (cSize == 0 || ERR_isError(cSize)) { @@ -104,7 +382,7 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); + { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); MEM_writeLE24(ostart, lhc); break; } @@ -124,30 +402,19 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, } *entropyWritten = 1; DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); - return (size_t)(op-ostart); + return op-ostart; } -static size_t -ZSTD_seqDecompressedSize(seqStore_t const* seqStore, - const seqDef* sequences, size_t nbSeqs, - size_t litSize, int lastSubBlock) -{ +static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) { + const seqDef* const sstart = sequences; + const seqDef* const send = sequences + nbSeq; + const seqDef* sp = sstart; size_t matchLengthSum = 0; - size_t litLengthSum = 0; - size_t n; - for (n=0; n 0) { + ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); matchLengthSum += seqLen.matchLength; + sp++; } - DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength", - (unsigned)nbSeqs, (const void*)sequences, - (unsigned)litLengthSum, (unsigned)matchLengthSum); - if (!lastSubBlock) - assert(litLengthSum == litSize); - else - assert(litLengthSum <= litSize); - (void)litLengthSum; return matchLengthSum + litSize; } @@ -161,14 +428,13 @@ ZSTD_seqDecompressedSize(seqStore_t const* seqStore, * @return : compressed size of sequences section of a sub-block * Or 0 if it is unable to compress * Or error code. */ -static size_t -ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, - const ZSTD_fseCTablesMetadata_t* fseMetadata, - const seqDef* sequences, size_t nbSeq, - const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, - const ZSTD_CCtx_params* cctxParams, - void* dst, size_t dstCapacity, - const int bmi2, int writeEntropy, int* entropyWritten) +static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, + const ZSTD_fseCTablesMetadata_t* fseMetadata, + const seqDef* sequences, size_t nbSeq, + const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, + const ZSTD_CCtx_params* cctxParams, + void* dst, size_t dstCapacity, + const int bmi2, int writeEntropy, int* entropyWritten) { const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; BYTE* const ostart = (BYTE*)dst; @@ -182,14 +448,14 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, /* Sequences Header */ RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, dstSize_tooSmall, ""); - if (nbSeq < 128) + if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq; else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; if (nbSeq==0) { - return (size_t)(op - ostart); + return op - ostart; } /* seqHead : flags for FSE encoding type */ @@ -203,7 +469,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, const U32 MLtype = fseMetadata->mlType; DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); - ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); + memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); op += fseMetadata->fseTablesSize; } else { const U32 repeat = set_repeat; @@ -211,7 +477,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, } { size_t const bitstreamSize = ZSTD_encodeSequences( - op, (size_t)(oend - op), + op, oend - op, fseTables->matchlengthCTable, mlCode, fseTables->offcodeCTable, ofCode, fseTables->litlengthCTable, llCode, @@ -255,7 +521,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, #endif *entropyWritten = 1; - return (size_t)(op - ostart); + return op - ostart; } /** ZSTD_compressSubBlock() : @@ -276,13 +542,12 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, { BYTE* const ostart = (BYTE*)dst; BYTE* const oend = ostart + dstCapacity; - BYTE* op = ostart + ZSTD_blockHeaderSize; + BYTE* op = ostart + ZSTDInternalConstants::ZSTD_blockHeaderSize; DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, &entropyMetadata->hufMetadata, literals, litSize, - op, (size_t)(oend-op), - bmi2, writeLitEntropy, litEntropyWritten); + op, oend-op, bmi2, writeLitEntropy, litEntropyWritten); FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); if (cLitSize == 0) return 0; op += cLitSize; @@ -292,18 +557,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, sequences, nbSeq, llCode, mlCode, ofCode, cctxParams, - op, (size_t)(oend-op), + op, oend-op, bmi2, writeSeqEntropy, seqEntropyWritten); FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); if (cSeqSize == 0) return 0; op += cSeqSize; } /* Write block header */ - { size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize; + { size_t cSize = (op-ostart)-ZSTDInternalConstants::ZSTD_blockHeaderSize; U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); MEM_writeLE24(ostart, cBlockHeader24); } - return (size_t)(op-ostart); + return op-ostart; } static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, @@ -332,8 +597,8 @@ static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t lit static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, const BYTE* codeTable, unsigned maxCode, size_t nbSeq, const FSE_CTable* fseCTable, - const U8* additionalBits, - short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, + const U32* additionalBits, + short const* defaultNorm, U32 defaultNormLog, void* workspace, size_t wkspSize) { unsigned* const countWksp = (unsigned*)workspace; @@ -345,11 +610,7 @@ static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ if (type == set_basic) { - /* We selected this encoding type, so it must be valid. */ - assert(max <= defaultMax); - cSymbolTypeSizeEstimateInBits = max <= defaultMax - ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max) - : ERROR(GENERIC); + cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); } else if (type == set_rle) { cSymbolTypeSizeEstimateInBits = 0; } else if (type == set_compressed || type == set_repeat) { @@ -373,30 +634,25 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, void* workspace, size_t wkspSize, int writeEntropy) { - size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ + size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ size_t cSeqSizeEstimate = 0; - if (nbSeq == 0) return sequencesSectionHeaderSize; cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, nbSeq, fseTables->offcodeCTable, NULL, - OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, + ZSTDInternalConstants::OF_defaultNorm, ZSTDInternalConstants::OF_defaultNormLog, workspace, wkspSize); cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, - nbSeq, fseTables->litlengthCTable, LL_bits, - LL_defaultNorm, LL_defaultNormLog, MaxLL, + nbSeq, fseTables->litlengthCTable, ZSTDInternalConstants::LL_bits, + ZSTDInternalConstants::LL_defaultNorm, ZSTDInternalConstants::LL_defaultNormLog, workspace, wkspSize); cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, - nbSeq, fseTables->matchlengthCTable, ML_bits, - ML_defaultNorm, ML_defaultNormLog, MaxML, + nbSeq, fseTables->matchlengthCTable, ZSTDInternalConstants::ML_bits, + ZSTDInternalConstants::ML_defaultNorm, ZSTDInternalConstants::ML_defaultNormLog, workspace, wkspSize); if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; return cSeqSizeEstimate + sequencesSectionHeaderSize; } -typedef struct { - size_t estLitSize; - size_t estBlockSize; -} EstimatedBlockSize; -static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, +static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, const BYTE* ofCodeTable, const BYTE* llCodeTable, const BYTE* mlCodeTable, @@ -404,17 +660,15 @@ static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t const ZSTD_entropyCTables_t* entropy, const ZSTD_entropyCTablesMetadata_t* entropyMetadata, void* workspace, size_t wkspSize, - int writeLitEntropy, int writeSeqEntropy) -{ - EstimatedBlockSize ebs; - ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize, - &entropy->huf, &entropyMetadata->hufMetadata, - workspace, wkspSize, writeLitEntropy); - ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, + int writeLitEntropy, int writeSeqEntropy) { + size_t cSizeEstimate = 0; + cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, + &entropy->huf, &entropyMetadata->hufMetadata, + workspace, wkspSize, writeLitEntropy); + cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, workspace, wkspSize, writeSeqEntropy); - ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize; - return ebs; + return cSizeEstimate + ZSTDInternalConstants::ZSTD_blockHeaderSize; } static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) @@ -428,56 +682,13 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe return 0; } -static size_t countLiterals(seqStore_t const* seqStore, const seqDef* sp, size_t seqCount) -{ - size_t n, total = 0; - assert(sp != NULL); - for (n=0; n %zu bytes", seqCount, (const void*)sp, total); - return total; -} - -#define BYTESCALE 256 - -static size_t sizeBlockSequences(const seqDef* sp, size_t nbSeqs, - size_t targetBudget, size_t avgLitCost, size_t avgSeqCost, - int firstSubBlock) -{ - size_t n, budget = 0, inSize=0; - /* entropy headers */ - size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */ - assert(firstSubBlock==0 || firstSubBlock==1); - budget += headerSize; - - /* first sequence => at least one sequence*/ - budget += sp[0].litLength * avgLitCost + avgSeqCost; - if (budget > targetBudget) return 1; - inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH); - - /* loop over sequences */ - for (n=1; n targetBudget) - /* though continue to expand until the sub-block is deemed compressible */ - && (budget < inSize * BYTESCALE) ) - break; - } - - return n; -} - /** ZSTD_compressSubBlock_multi() : * Breaks super-block into multiple sub-blocks and compresses them. - * Entropy will be written into the first block. - * The following blocks use repeat_mode to compress. - * Sub-blocks are all compressed, except the last one when beneficial. - * @return : compressed size of the super block (which features multiple ZSTD blocks) - * or 0 if it failed to compress. */ + * Entropy will be written to the first block. + * The following blocks will use repeat mode to compress. + * All sub-blocks are compressed blocks (no raw or rle blocks). + * @return : compressed size of the super block (which is multiple ZSTD blocks) + * Or 0 if it failed to compress. */ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, const ZSTD_compressedBlockState_t* prevCBlock, ZSTD_compressedBlockState_t* nextCBlock, @@ -490,12 +701,10 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, { const seqDef* const sstart = seqStorePtr->sequencesStart; const seqDef* const send = seqStorePtr->sequences; - const seqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */ - size_t const nbSeqs = (size_t)(send - sstart); + const seqDef* sp = sstart; const BYTE* const lstart = seqStorePtr->litStart; const BYTE* const lend = seqStorePtr->lit; const BYTE* lp = lstart; - size_t const nbLiterals = (size_t)(lend - lstart); BYTE const* ip = (BYTE const*)src; BYTE const* const iend = ip + srcSize; BYTE* const ostart = (BYTE*)dst; @@ -504,179 +713,120 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, const BYTE* llCodePtr = seqStorePtr->llCode; const BYTE* mlCodePtr = seqStorePtr->mlCode; const BYTE* ofCodePtr = seqStorePtr->ofCode; - size_t const minTarget = ZSTD_TARGETCBLOCKSIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */ - size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize); - int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed); + size_t targetCBlockSize = cctxParams->targetCBlockSize; + size_t litSize, seqCount; + int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; int writeSeqEntropy = 1; - - DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)", - (unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart)); - - /* let's start by a general estimation for the full block */ - if (nbSeqs > 0) { - EstimatedBlockSize const ebs = - ZSTD_estimateSubBlockSize(lp, nbLiterals, - ofCodePtr, llCodePtr, mlCodePtr, nbSeqs, - &nextCBlock->entropy, entropyMetadata, - workspace, wkspSize, - writeLitEntropy, writeSeqEntropy); - /* quick estimation */ - size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE; - size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs; - const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1); - size_t n, avgBlockBudget, blockBudgetSupp=0; - avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks; - DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes", - (unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE, - (unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE); - /* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately - * this will result in the production of a single uncompressed block covering @srcSize.*/ - if (ebs.estBlockSize > srcSize) return 0; - - /* compress and write sub-blocks */ - assert(nbSubBlocks>0); - for (n=0; n < nbSubBlocks-1; n++) { - /* determine nb of sequences for current sub-block + nbLiterals from next sequence */ - size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp), - avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0); - /* if reached last sequence : break to last sub-block (simplification) */ - assert(seqCount <= (size_t)(send-sp)); - if (sp + seqCount == send) break; - assert(seqCount > 0); - /* compress sub-block */ - { int litEntropyWritten = 0; - int seqEntropyWritten = 0; - size_t litSize = countLiterals(seqStorePtr, sp, seqCount); - const size_t decompressedSize = - ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0); - size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, - sp, seqCount, - lp, litSize, - llCodePtr, mlCodePtr, ofCodePtr, - cctxParams, - op, (size_t)(oend-op), - bmi2, writeLitEntropy, writeSeqEntropy, - &litEntropyWritten, &seqEntropyWritten, - 0); - FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); - - /* check compressibility, update state components */ - if (cSize > 0 && cSize < decompressedSize) { - DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes", - (unsigned)decompressedSize, (unsigned)cSize); - assert(ip + decompressedSize <= iend); - ip += decompressedSize; - lp += litSize; - op += cSize; - llCodePtr += seqCount; - mlCodePtr += seqCount; - ofCodePtr += seqCount; - /* Entropy only needs to be written once */ - if (litEntropyWritten) { - writeLitEntropy = 0; - } - if (seqEntropyWritten) { - writeSeqEntropy = 0; - } - sp += seqCount; - blockBudgetSupp = 0; - } } - /* otherwise : do not compress yet, coalesce current sub-block with following one */ + int lastSequence = 0; + + DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", + (unsigned)(lend-lp), (unsigned)(send-sstart)); + + litSize = 0; + seqCount = 0; + do { + size_t cBlockSizeEstimate = 0; + if (sstart == send) { + lastSequence = 1; + } else { + const seqDef* const sequence = sp + seqCount; + lastSequence = sequence == send - 1; + litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; + seqCount++; } - } /* if (nbSeqs > 0) */ - - /* write last block */ - DEBUGLOG(5, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp)); - { int litEntropyWritten = 0; - int seqEntropyWritten = 0; - size_t litSize = (size_t)(lend - lp); - size_t seqCount = (size_t)(send - sp); - const size_t decompressedSize = - ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1); - size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, - sp, seqCount, - lp, litSize, - llCodePtr, mlCodePtr, ofCodePtr, - cctxParams, - op, (size_t)(oend-op), - bmi2, writeLitEntropy, writeSeqEntropy, - &litEntropyWritten, &seqEntropyWritten, - lastBlock); - FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); - - /* update pointers, the nb of literals borrowed from next sequence must be preserved */ - if (cSize > 0 && cSize < decompressedSize) { - DEBUGLOG(5, "Last sub-block compressed %u bytes => %u bytes", - (unsigned)decompressedSize, (unsigned)cSize); - assert(ip + decompressedSize <= iend); - ip += decompressedSize; - lp += litSize; - op += cSize; - llCodePtr += seqCount; - mlCodePtr += seqCount; - ofCodePtr += seqCount; - /* Entropy only needs to be written once */ - if (litEntropyWritten) { - writeLitEntropy = 0; - } - if (seqEntropyWritten) { - writeSeqEntropy = 0; + if (lastSequence) { + assert(lp <= lend); + assert(litSize <= (size_t)(lend - lp)); + litSize = (size_t)(lend - lp); + } + /* I think there is an optimization opportunity here. + * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful + * since it recalculates estimate from scratch. + * For example, it would recount literal distribution and symbol codes everytime. + */ + cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, + &nextCBlock->entropy, entropyMetadata, + workspace, wkspSize, writeLitEntropy, writeSeqEntropy); + if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { + int litEntropyWritten = 0; + int seqEntropyWritten = 0; + const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); + const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, + sp, seqCount, + lp, litSize, + llCodePtr, mlCodePtr, ofCodePtr, + cctxParams, + op, oend-op, + bmi2, writeLitEntropy, writeSeqEntropy, + &litEntropyWritten, &seqEntropyWritten, + lastBlock && lastSequence); + FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); + if (cSize > 0 && cSize < decompressedSize) { + DEBUGLOG(5, "Committed the sub-block"); + assert(ip + decompressedSize <= iend); + ip += decompressedSize; + sp += seqCount; + lp += litSize; + op += cSize; + llCodePtr += seqCount; + mlCodePtr += seqCount; + ofCodePtr += seqCount; + litSize = 0; + seqCount = 0; + /* Entropy only needs to be written once */ + if (litEntropyWritten) { + writeLitEntropy = 0; + } + if (seqEntropyWritten) { + writeSeqEntropy = 0; + } } - sp += seqCount; } - } - - + } while (!lastSequence); if (writeLitEntropy) { - DEBUGLOG(5, "Literal entropy tables were never written"); - ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); + DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten"); + memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); } if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { /* If we haven't written our entropy tables, then we've violated our contract and * must emit an uncompressed block. */ - DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block"); + DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten"); return 0; } - if (ip < iend) { - /* some data left : last part of the block sent uncompressed */ - size_t const rSize = (size_t)((iend - ip)); - size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock); - DEBUGLOG(5, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize)); + size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); + DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); assert(cSize != 0); op += cSize; /* We have to regenerate the repcodes because we've skipped some sequences */ if (sp < send) { - const seqDef* seq; + seqDef const* seq; repcodes_t rep; - ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); + memcpy(&rep, prevCBlock->rep, sizeof(rep)); for (seq = sstart; seq < sp; ++seq) { - ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); + rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); } - ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep)); + memcpy(nextCBlock->rep, &rep, sizeof(rep)); } } - - DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u", - (unsigned)(op-ostart)); - return (size_t)(op-ostart); + DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed"); + return op-ostart; } size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - unsigned lastBlock) -{ + void const* src, size_t srcSize, + unsigned lastBlock) { ZSTD_entropyCTablesMetadata_t entropyMetadata; - FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, + FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore, &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, &zc->appliedParams, &entropyMetadata, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); + zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); return ZSTD_compressSubBlock_multi(&zc->seqStore, zc->blockState.prevCBlock, @@ -686,7 +836,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, dst, dstCapacity, src, srcSize, zc->bmi2, lastBlock, - zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */); + zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp b/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp index d791b724b..ecc1cdb77 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_double_fast.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,49 +13,7 @@ namespace duckdb_zstd { -#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_fillDoubleHashTableForCDict(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm) -{ - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32* const hashLarge = ms->hashTable; - U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - U32 const mls = cParams->minMatch; - U32* const hashSmall = ms->chainTable; - U32 const hBitsS = cParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; - const BYTE* const base = ms->window.base; - const BYTE* ip = base + ms->nextToUpdate; - const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; - const U32 fastHashFillStep = 3; - - /* Always insert every fastHashFillStep position into the hash tables. - * Insert the other positions into the large hash table if their entry - * is empty. - */ - for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); - U32 i; - for (i = 0; i < fastHashFillStep; ++i) { - size_t const smHashAndTag = ZSTD_hashPtr(ip + i, hBitsS, mls); - size_t const lgHashAndTag = ZSTD_hashPtr(ip + i, hBitsL, 8); - if (i == 0) { - ZSTD_writeTaggedIndex(hashSmall, smHashAndTag, curr + i); - } - if (i == 0 || hashLarge[lgHashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { - ZSTD_writeTaggedIndex(hashLarge, lgHashAndTag, curr + i); - } - /* Only load extra positions for ZSTD_dtlm_full */ - if (dtlm == ZSTD_dtlm_fast) - break; - } } -} - -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, +void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -74,251 +32,27 @@ void ZSTD_fillDoubleHashTableForCCtx(ZSTD_matchState_t* ms, * is empty. */ for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); + U32 const current = (U32)(ip - base); U32 i; for (i = 0; i < fastHashFillStep; ++i) { size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls); size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8); if (i == 0) - hashSmall[smHash] = curr + i; + hashSmall[smHash] = current + i; if (i == 0 || hashLarge[lgHash] == 0) - hashLarge[lgHash] = curr + i; + hashLarge[lgHash] = current + i; /* Only load extra positions for ZSTD_dtlm_full */ if (dtlm == ZSTD_dtlm_fast) break; - } } -} - -void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) -{ - if (tfp == ZSTD_tfp_forCDict) { - ZSTD_fillDoubleHashTableForCDict(ms, end, dtlm); - } else { - ZSTD_fillDoubleHashTableForCCtx(ms, end, dtlm); - } -} - - -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_doubleFast_noDict_generic( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls /* template */) -{ - ZSTD_compressionParameters const* cParams = &ms->cParams; - U32* const hashLong = ms->hashTable; - const U32 hBitsL = cParams->hashLog; - U32* const hashSmall = ms->chainTable; - const U32 hBitsS = cParams->chainLog; - const BYTE* const base = ms->window.base; - const BYTE* const istart = (const BYTE*)src; - const BYTE* anchor = istart; - const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); - const BYTE* const prefixLowest = base + prefixLowestIndex; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - HASH_READ_SIZE; - U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - size_t mLength; - U32 offset; - U32 curr; - - /* how many positions to search before increasing step size */ - const size_t kStepIncr = 1 << kSearchStrength; - /* the position at which to increment the step size if no match is found */ - const BYTE* nextStep; - size_t step; /* the current step size */ - - size_t hl0; /* the long hash at ip */ - size_t hl1; /* the long hash at ip1 */ - - U32 idxl0; /* the long match index for ip */ - U32 idxl1; /* the long match index for ip1 */ - - const BYTE* matchl0; /* the long match for ip */ - const BYTE* matchs0; /* the short match for ip */ - const BYTE* matchl1; /* the long match for ip1 */ - - const BYTE* ip = istart; /* the current position */ - const BYTE* ip1; /* the next position */ - - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic"); - - /* init */ - ip += ((ip - prefixLowest) == 0); - { - U32 const current = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); - U32 const maxRep = current - windowLow; - if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; - } - - /* Outer Loop: one iteration per match found and stored */ - while (1) { - step = 1; - nextStep = ip + kStepIncr; - ip1 = ip + step; - - if (ip1 > ilimit) { - goto _cleanup; - } - - hl0 = ZSTD_hashPtr(ip, hBitsL, 8); - idxl0 = hashLong[hl0]; - matchl0 = base + idxl0; - - /* Inner Loop: one iteration per search / position */ - do { - const size_t hs0 = ZSTD_hashPtr(ip, hBitsS, mls); - const U32 idxs0 = hashSmall[hs0]; - curr = (U32)(ip-base); - matchs0 = base + idxs0; - - hashLong[hl0] = hashSmall[hs0] = curr; /* update hash tables */ - - /* check noDict repcode */ - if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { - mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; - ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); - goto _match_stored; - } - - hl1 = ZSTD_hashPtr(ip1, hBitsL, 8); - - if (idxl0 > prefixLowestIndex) { - /* check prefix long match */ - if (MEM_read64(matchl0) == MEM_read64(ip)) { - mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8; - offset = (U32)(ip-matchl0); - while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */ - goto _match_found; - } - } - - idxl1 = hashLong[hl1]; - matchl1 = base + idxl1; - - if (idxs0 > prefixLowestIndex) { - /* check prefix short match */ - if (MEM_read32(matchs0) == MEM_read32(ip)) { - goto _search_next_long; - } - } - - if (ip1 >= nextStep) { - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - step++; - nextStep += kStepIncr; - } - ip = ip1; - ip1 += step; - - hl0 = hl1; - idxl0 = idxl1; - matchl0 = matchl1; - #if defined(__aarch64__) - PREFETCH_L1(ip+256); - #endif - } while (ip1 <= ilimit); - -_cleanup: - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; - - /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; - - /* Return the last literals size */ - return (size_t)(iend - anchor); - -_search_next_long: - - /* check prefix long +1 match */ - if (idxl1 > prefixLowestIndex) { - if (MEM_read64(matchl1) == MEM_read64(ip1)) { - ip = ip1; - mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8; - offset = (U32)(ip-matchl1); - while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */ - goto _match_found; - } - } - - /* if no long +1 match, explore the short match we found */ - mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4; - offset = (U32)(ip - matchs0); - while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */ - - /* fall-through */ - -_match_found: /* requires ip, offset, mLength */ - offset_2 = offset_1; - offset_1 = offset; - - if (step < 4) { - /* It is unsafe to write this value back to the hashtable when ip1 is - * greater than or equal to the new ip we will have after we're done - * processing this match. Rather than perform that test directly - * (ip1 >= ip + mLength), which costs speed in practice, we do a simpler - * more predictable test. The minmatch even if we take a short match is - * 4 bytes, so as long as step, the distance between ip and ip1 - * (initially) is less than 4, we know ip1 < new ip. */ - hashLong[hl1] = (U32)(ip1 - base); - } - - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - -_match_stored: - /* match found */ - ip += mLength; - anchor = ip; - - if (ip <= ilimit) { - /* Complementary insertion */ - /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; - hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; - hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); - hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; - hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base); - } - - /* check immediate repcode */ - while ( (ip <= ilimit) - && ( (offset_2>0) - & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, rLength); - ip += rLength; - anchor = ip; - continue; /* faster when present ... (?) */ - } - } - } + } } } FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( +size_t ZSTD_compressBlock_doubleFast_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls /* template */) + U32 const mls /* template */, ZSTD_dictMode_e const dictMode) { ZSTD_compressionParameters const* cParams = &ms->cParams; U32* const hashLong = ms->hashTable; @@ -336,39 +70,57 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = &dms->cParams; - const U32* const dictHashLong = dms->hashTable; - const U32* const dictHashSmall = dms->chainTable; - const U32 dictStartIndex = dms->window.dictLimit; - const BYTE* const dictBase = dms->window.base; - const BYTE* const dictStart = dictBase + dictStartIndex; - const BYTE* const dictEnd = dms->window.nextSrc; - const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase); - const U32 dictHBitsL = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - const U32 dictHBitsS = dictCParams->chainLog + ZSTD_SHORT_CACHE_TAG_BITS; + const ZSTD_compressionParameters* const dictCParams = + dictMode == ZSTD_dictMatchState ? + &dms->cParams : NULL; + const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ? + dms->hashTable : NULL; + const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ? + dms->chainTable : NULL; + const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ? + dms->window.dictLimit : 0; + const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? + dms->window.base : NULL; + const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ? + dictBase + dictStartIndex : NULL; + const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? + dms->window.nextSrc : NULL; + const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? + prefixLowestIndex - (U32)(dictEnd - dictBase) : + 0; + const U32 dictHBitsL = dictMode == ZSTD_dictMatchState ? + dictCParams->hashLog : hBitsL; + const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ? + dictCParams->chainLog : hBitsS; const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart)); - DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic"); + DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic"); - /* if a dictionary is attached, it must be within window range */ - assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); + assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState); - if (ms->prefetchCDictTables) { - size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); - size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32); - PREFETCH_AREA(dictHashLong, hashTableBytes); - PREFETCH_AREA(dictHashSmall, chainTableBytes); + /* if a dictionary is attached, it must be within window range */ + if (dictMode == ZSTD_dictMatchState) { + assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); } /* init */ ip += (dictAndPrefixLength == 0); - - /* dictMatchState repCode checks don't currently handle repCode == 0 - * disabling. */ - assert(offset_1 <= dictAndPrefixLength); - assert(offset_2 <= dictAndPrefixLength); + if (dictMode == ZSTD_noDict) { + U32 const current = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); + U32 const maxRep = current - windowLow; + if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; + } + if (dictMode == ZSTD_dictMatchState) { + /* dictMatchState repCode checks don't currently handle repCode == 0 + * disabling. */ + assert(offset_1 <= dictAndPrefixLength); + assert(offset_2 <= dictAndPrefixLength); + } /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ @@ -376,30 +128,37 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( U32 offset; size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8); size_t const h = ZSTD_hashPtr(ip, hBitsS, mls); - size_t const dictHashAndTagL = ZSTD_hashPtr(ip, dictHBitsL, 8); - size_t const dictHashAndTagS = ZSTD_hashPtr(ip, dictHBitsS, mls); - U32 const dictMatchIndexAndTagL = dictHashLong[dictHashAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS]; - U32 const dictMatchIndexAndTagS = dictHashSmall[dictHashAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS]; - int const dictTagsMatchL = ZSTD_comparePackedTags(dictMatchIndexAndTagL, dictHashAndTagL); - int const dictTagsMatchS = ZSTD_comparePackedTags(dictMatchIndexAndTagS, dictHashAndTagS); - U32 const curr = (U32)(ip-base); + size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8); + size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls); + U32 const current = (U32)(ip-base); U32 const matchIndexL = hashLong[h2]; U32 matchIndexS = hashSmall[h]; const BYTE* matchLong = base + matchIndexL; const BYTE* match = base + matchIndexS; - const U32 repIndex = curr + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixLowestIndex) ? + const U32 repIndex = current + 1 - offset_1; + const BYTE* repMatch = (dictMode == ZSTD_dictMatchState + && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; - hashLong[h2] = hashSmall[h] = curr; /* update hash tables */ + hashLong[h2] = hashSmall[h] = current; /* update hash tables */ - /* check repcode */ - if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) + /* check dictMatchState repcode */ + if (dictMode == ZSTD_dictMatchState + && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + goto _match_stored; + } + + /* check noDict repcode */ + if ( dictMode == ZSTD_noDict + && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) { + mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); goto _match_stored; } @@ -411,15 +170,15 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictTagsMatchL) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dictMatchState long match */ - U32 const dictMatchIndexL = dictMatchIndexAndTagL >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexL = dictHashLong[dictHL]; const BYTE* dictMatchL = dictBase + dictMatchIndexL; assert(dictMatchL < dictEnd); if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) { mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8; - offset = (U32)(curr - dictMatchIndexL - dictIndexDelta); + offset = (U32)(current - dictMatchIndexL - dictIndexDelta); while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */ goto _match_found; } } @@ -429,9 +188,9 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( if (MEM_read32(match) == MEM_read32(ip)) { goto _search_next_long; } - } else if (dictTagsMatchS) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dictMatchState short match */ - U32 const dictMatchIndexS = dictMatchIndexAndTagS >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexS = dictHashSmall[dictHS]; match = dictBase + dictMatchIndexS; matchIndexS = dictMatchIndexS + dictIndexDelta; @@ -446,13 +205,12 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( continue; _search_next_long: + { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8); - size_t const dictHashAndTagL3 = ZSTD_hashPtr(ip+1, dictHBitsL, 8); + size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8); U32 const matchIndexL3 = hashLong[hl3]; - U32 const dictMatchIndexAndTagL3 = dictHashLong[dictHashAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS]; - int const dictTagsMatchL3 = ZSTD_comparePackedTags(dictMatchIndexAndTagL3, dictHashAndTagL3); const BYTE* matchL3 = base + matchIndexL3; - hashLong[hl3] = curr + 1; + hashLong[hl3] = current + 1; /* check prefix long +1 match */ if (matchIndexL3 > prefixLowestIndex) { @@ -463,23 +221,23 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */ goto _match_found; } - } else if (dictTagsMatchL3) { + } else if (dictMode == ZSTD_dictMatchState) { /* check dict long +1 match */ - U32 const dictMatchIndexL3 = dictMatchIndexAndTagL3 >> ZSTD_SHORT_CACHE_TAG_BITS; + U32 const dictMatchIndexL3 = dictHashLong[dictHLNext]; const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3; assert(dictMatchL3 < dictEnd); if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) { mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8; ip++; - offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta); + offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta); while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */ goto _match_found; } } } /* if no long +1 match, explore the short match we found */ - if (matchIndexS < prefixLowestIndex) { + if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) { mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4; - offset = (U32)(curr - matchIndexS); + offset = (U32)(current - matchIndexS); while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } else { mLength = ZSTD_count(ip+4, match+4, iend) + 4; @@ -487,11 +245,13 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } + /* fall-through */ + _match_found: offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); _match_stored: /* match found */ @@ -501,7 +261,7 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; + { U32 const indexToInsert = current+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -509,55 +269,53 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( } /* check immediate repcode */ - while (ip <= ilimit) { - U32 const current2 = (U32)(ip-base); - U32 const repIndex2 = current2 - offset_2; - const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ? - dictBase + repIndex2 - dictIndexDelta : - base + repIndex2; - if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; - U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; - hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; - ip += repLength2; + if (dictMode == ZSTD_dictMatchState) { + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState + && repIndex2 < prefixLowestIndex ? + dictBase + repIndex2 - dictIndexDelta : + base + repIndex2; + if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4; + U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; + ip += repLength2; + anchor = ip; + continue; + } + break; + } } + + if (dictMode == ZSTD_noDict) { + while ( (ip <= ilimit) + && ( (offset_2>0) + & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; + U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ + hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base); + hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base); + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, rLength-MINMATCH); + ip += rLength; anchor = ip; - continue; - } - break; - } - } + continue; /* faster when present ... (?) */ + } } } } /* while (ip < ilimit) */ /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ return (size_t)(iend - anchor); } -#define ZSTD_GEN_DFAST_FN(dictMode, mls) \ - static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \ - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ - void const* src, size_t srcSize) \ - { \ - return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \ - } - -ZSTD_GEN_DFAST_FN(noDict, 4) -ZSTD_GEN_DFAST_FN(noDict, 5) -ZSTD_GEN_DFAST_FN(noDict, 6) -ZSTD_GEN_DFAST_FN(noDict, 7) - -ZSTD_GEN_DFAST_FN(dictMatchState, 4) -ZSTD_GEN_DFAST_FN(dictMatchState, 5) -ZSTD_GEN_DFAST_FN(dictMatchState, 6) -ZSTD_GEN_DFAST_FN(dictMatchState, 7) - size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -568,13 +326,13 @@ size_t ZSTD_compressBlock_doubleFast( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_noDict_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict); case 5 : - return ZSTD_compressBlock_doubleFast_noDict_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict); case 6 : - return ZSTD_compressBlock_doubleFast_noDict_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict); case 7 : - return ZSTD_compressBlock_doubleFast_noDict_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict); } } @@ -588,20 +346,18 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_dictMatchState_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState); case 5 : - return ZSTD_compressBlock_doubleFast_dictMatchState_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState); case 6 : - return ZSTD_compressBlock_doubleFast_dictMatchState_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState); case 7 : - return ZSTD_compressBlock_doubleFast_dictMatchState_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState); } } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_doubleFast_extDict_generic( +static size_t ZSTD_compressBlock_doubleFast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, U32 const mls /* template */) @@ -632,7 +388,7 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( /* if extDict is invalidated due to maxDistance, switch to "regular" variant */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_doubleFast(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, src, srcSize, mls, ZSTD_noDict); /* Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ @@ -646,31 +402,31 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base; const BYTE* matchLong = matchLongBase + matchLongIndex; - const U32 curr = (U32)(ip-base); - const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */ + const U32 current = (U32)(ip-base); + const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; size_t mLength; - hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */ + hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */ - & (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */ + & (repIndex > dictStartIndex)) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; ip++; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); } else { if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) { const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart; U32 offset; mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8; - offset = curr - matchLongIndex; + offset = current - matchLongIndex; while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) { size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8); @@ -678,24 +434,24 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base; const BYTE* match3 = match3Base + matchIndex3; U32 offset; - hashLong[h3] = curr + 1; + hashLong[h3] = current + 1; if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) { const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8; ip++; - offset = curr+1 - matchIndex3; + offset = current+1 - matchIndex3; while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */ } else { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; - offset = curr - matchIndex; + offset = current - matchIndex; while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ } offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } else { ip += ((ip-anchor) >> kSearchStrength) + 1; @@ -709,7 +465,7 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( if (ip <= ilimit) { /* Complementary insertion */ /* done after iLimit test, as candidates could be > iend-8 */ - { U32 const indexToInsert = curr+2; + { U32 const indexToInsert = current+2; hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert; hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base); hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert; @@ -722,12 +478,12 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */ - & (offset_2 <= current2 - dictStartIndex)) + & (repIndex2 > dictStartIndex)) && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2; hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2; ip += repLength2; @@ -745,10 +501,6 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( return (size_t)(iend - anchor); } -ZSTD_GEN_DFAST_FN(extDict, 4) -ZSTD_GEN_DFAST_FN(extDict, 5) -ZSTD_GEN_DFAST_FN(extDict, 6) -ZSTD_GEN_DFAST_FN(extDict, 7) size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -759,16 +511,14 @@ size_t ZSTD_compressBlock_doubleFast_extDict( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_doubleFast_extDict_4(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_doubleFast_extDict_5(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_doubleFast_extDict_6(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_doubleFast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); } } -#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */ - -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_fast.cpp b/src/duckdb/third_party/zstd/compress/zstd_fast.cpp index f45c4d8e1..31da71d85 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_fast.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_fast.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -13,46 +13,7 @@ namespace duckdb_zstd { -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_fillHashTableForCDict(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm) -{ - const ZSTD_compressionParameters* const cParams = &ms->cParams; - U32* const hashTable = ms->hashTable; - U32 const hBits = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; - U32 const mls = cParams->minMatch; - const BYTE* const base = ms->window.base; - const BYTE* ip = base + ms->nextToUpdate; - const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; - const U32 fastHashFillStep = 3; - - /* Currently, we always use ZSTD_dtlm_full for filling CDict tables. - * Feel free to remove this assert if there's a good reason! */ - assert(dtlm == ZSTD_dtlm_full); - - /* Always insert every fastHashFillStep position into the hash table. - * Insert the other positions if their hash entry is empty. - */ - for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); - { size_t const hashAndTag = ZSTD_hashPtr(ip, hBits, mls); - ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr); } - - if (dtlm == ZSTD_dtlm_fast) continue; - /* Only load extra positions for ZSTD_dtlm_full */ - { U32 p; - for (p = 1; p < fastHashFillStep; ++p) { - size_t const hashAndTag = ZSTD_hashPtr(ip + p, hBits, mls); - if (hashTable[hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS] == 0) { /* not yet filled */ - ZSTD_writeTaggedIndex(hashTable, hashAndTag, curr + p); - } } } } -} - -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, +void ZSTD_fillHashTable(ZSTD_matchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { @@ -65,366 +26,163 @@ void ZSTD_fillHashTableForCCtx(ZSTD_matchState_t* ms, const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; const U32 fastHashFillStep = 3; - /* Currently, we always use ZSTD_dtlm_fast for filling CCtx tables. - * Feel free to remove this assert if there's a good reason! */ - assert(dtlm == ZSTD_dtlm_fast); - /* Always insert every fastHashFillStep position into the hash table. * Insert the other positions if their hash entry is empty. */ for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { - U32 const curr = (U32)(ip - base); + U32 const current = (U32)(ip - base); size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); - hashTable[hash0] = curr; + hashTable[hash0] = current; if (dtlm == ZSTD_dtlm_fast) continue; /* Only load extra positions for ZSTD_dtlm_full */ { U32 p; for (p = 1; p < fastHashFillStep; ++p) { size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); if (hashTable[hash] == 0) { /* not yet filled */ - hashTable[hash] = curr + p; + hashTable[hash] = current + p; } } } } } -void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - const void* const end, - ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp) -{ - if (tfp == ZSTD_tfp_forCDict) { - ZSTD_fillHashTableForCDict(ms, end, dtlm); - } else { - ZSTD_fillHashTableForCCtx(ms, end, dtlm); - } -} - -/** - * If you squint hard enough (and ignore repcodes), the search operation at any - * given position is broken into 4 stages: - * - * 1. Hash (map position to hash value via input read) - * 2. Lookup (map hash val to index via hashtable read) - * 3. Load (map index to value at that position via input read) - * 4. Compare - * - * Each of these steps involves a memory read at an address which is computed - * from the previous step. This means these steps must be sequenced and their - * latencies are cumulative. - * - * Rather than do 1->2->3->4 sequentially for a single position before moving - * onto the next, this implementation interleaves these operations across the - * next few positions: - * - * R = Repcode Read & Compare - * H = Hash - * T = Table Lookup - * M = Match Read & Compare - * - * Pos | Time --> - * ----+------------------- - * N | ... M - * N+1 | ... TM - * N+2 | R H T M - * N+3 | H TM - * N+4 | R H T M - * N+5 | H ... - * N+6 | R ... - * - * This is very much analogous to the pipelining of execution in a CPU. And just - * like a CPU, we have to dump the pipeline when we find a match (i.e., take a - * branch). - * - * When this happens, we throw away our current state, and do the following prep - * to re-enter the loop: - * - * Pos | Time --> - * ----+------------------- - * N | H T - * N+1 | H - * - * This is also the work we do at the beginning to enter the loop initially. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_fast_noDict_generic( +FORCE_INLINE_TEMPLATE size_t +ZSTD_compressBlock_fast_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, - U32 const mls, U32 const hasStep) + U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = hasStep ? (cParams->targetLength + !(cParams->targetLength) + 1) : 2; + size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; + /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */ + const BYTE* ip0 = istart; + const BYTE* ip1; + const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; + U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; - const BYTE* anchor = istart; - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* ip2; - const BYTE* ip3; - U32 current0; - - U32 rep_offset1 = rep[0]; - U32 rep_offset2 = rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - size_t hash0; /* hash for ip0 */ - size_t hash1; /* hash for ip1 */ - U32 idx; /* match idx for ip0 */ - U32 mval; /* src value at match idx */ - - U32 offcode; - const BYTE* match0; - size_t mLength; - - /* ip0 and ip1 are always adjacent. The targetLength skipping and - * uncompressibility acceleration is applied to every other position, - * matching the behavior of #1562. step therefore represents the gap - * between pairs of positions, from ip0 to ip2 or ip1 to ip3. */ - size_t step; - const BYTE* nextStep; - const size_t kStepIncr = (1 << (kSearchStrength - 1)); - + /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); ip0 += (ip0 == prefixStart); - { U32 const curr = (U32)(ip0 - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); - U32 const maxRep = curr - windowLow; - if (rep_offset2 > maxRep) offsetSaved2 = rep_offset2, rep_offset2 = 0; - if (rep_offset1 > maxRep) offsetSaved1 = rep_offset1, rep_offset1 = 0; - } - - /* start each op */ -_start: /* Requires: ip0 */ - - step = stepSize; - nextStep = ip0 + kStepIncr; - - /* calculate positions, ip0 - anchor == 0, so we skip step calc */ ip1 = ip0 + 1; - ip2 = ip0 + step; - ip3 = ip2 + 1; - - if (ip3 >= ilimit) { - goto _cleanup; + { U32 const current = (U32)(ip0 - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); + U32 const maxRep = current - windowLow; + if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; + if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; } - hash0 = ZSTD_hashPtr(ip0, hlog, mls); - hash1 = ZSTD_hashPtr(ip1, hlog, mls); - - idx = hashTable[hash0]; - - do { - /* load repcode match for ip[2]*/ - const U32 rval = MEM_read32(ip2 - rep_offset1); - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* check repcode at ip[2] */ - if ((MEM_read32(ip2) == rval) & (rep_offset1 > 0)) { - ip0 = ip2; - match0 = ip0 - rep_offset1; - mLength = ip0[-1] == match0[-1]; - ip0 -= mLength; - match0 -= mLength; - offcode = REPCODE1_TO_OFFBASE; + /* Main Search Loop */ +#ifdef __INTEL_COMPILER + /* From intel 'The vector pragma indicates that the loop should be + * vectorized if it is legal to do so'. Can be used together with + * #pragma ivdep (but have opted to exclude that because intel + * warns against using it).*/ + #pragma vector always +#endif + while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */ + size_t mLength; + BYTE const* ip2 = ip0 + 2; + size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls); + U32 const val0 = MEM_read32(ip0); + size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls); + U32 const val1 = MEM_read32(ip1); + U32 const current0 = (U32)(ip0-base); + U32 const current1 = (U32)(ip1-base); + U32 const matchIndex0 = hashTable[h0]; + U32 const matchIndex1 = hashTable[h1]; + BYTE const* repMatch = ip2 - offset_1; + const BYTE* match0 = base + matchIndex0; + const BYTE* match1 = base + matchIndex1; + U32 offcode; + +#if defined(__aarch64__) + PREFETCH_L1(ip0+256); +#endif + + hashTable[h0] = current0; /* update hash table */ + hashTable[h1] = current1; /* update hash table */ + + assert(ip0 + 1 == ip1); + + if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) { + mLength = (ip2[-1] == repMatch[-1]) ? 1 : 0; + ip0 = ip2 - mLength; + match0 = repMatch - mLength; mLength += 4; - - /* First write next hash table entry; we've already calculated it. - * This write is known to be safe because the ip1 is before the - * repcode (ip2). */ - hashTable[hash1] = (U32)(ip1 - base); - + offcode = 0; goto _match; } - - /* load match for ip[0] */ - if (idx >= prefixStartIndex) { - mval = MEM_read32(base + idx); - } else { - mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ + if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) { + /* found a regular match */ + goto _offset; } - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - - /* First write next hash table entry; we've already calculated it. - * This write is known to be safe because the ip1 == ip0 + 1, so - * we know we will resume searching after ip1 */ - hashTable[hash1] = (U32)(ip1 - base); - + if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) { + /* found a regular match after one literal */ + ip0 = ip1; + match0 = match1; goto _offset; } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip3; - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* load match for ip[0] */ - if (idx >= prefixStartIndex) { - mval = MEM_read32(base + idx); - } else { - mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ + { size_t const step = ((size_t)(ip0-anchor) >> (kSearchStrength - 1)) + stepSize; + assert(step >= 2); + ip0 += step; + ip1 += step; + continue; } +_offset: /* Requires: ip0, match0 */ + /* Compute the offset code */ + offset_2 = offset_1; + offset_1 = (U32)(ip0-match0); + offcode = offset_1 + ZSTD_REP_MOVE; + mLength = 4; + /* Count the backwards match length */ + while (((ip0>anchor) & (match0>prefixStart)) + && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */ - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - - /* first write next hash table entry; we've already calculated it */ - if (step <= 4) { - /* We need to avoid writing an index into the hash table >= the - * position at which we will pick up our searching after we've - * taken this match. - * - * The minimum possible match has length 4, so the earliest ip0 - * can be after we take this match will be the current ip0 + 4. - * ip1 is ip0 + step - 1. If ip1 is >= ip0 + 4, we can't safely - * write this position. - */ - hashTable[hash1] = (U32)(ip1 - base); - } +_match: /* Requires: ip0, match0, offcode */ + /* Count the forward length */ + mLength += ZSTD_count(ip0+mLength, match0+mLength, iend); + ZSTD_storeSeq(seqStore, (size_t)(ip0-anchor), anchor, iend, offcode, mLength-MINMATCH); + /* match found */ + ip0 += mLength; + anchor = ip0; - goto _offset; - } + if (ip0 <= ilimit) { + /* Fill Table */ + assert(base+current0+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); - /* lookup ip[1] */ - idx = hashTable[hash1]; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip0 + step; - ip3 = ip1 + step; - - /* calculate step */ - if (ip2 >= nextStep) { - step++; - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - nextStep += kStepIncr; - } - } while (ip3 < ilimit); - -_cleanup: - /* Note that there are probably still a couple positions we could search. - * However, it seems to be a meaningful performance hit to try to search - * them. So let's not. */ - - /* When the repcodes are outside of the prefix, we set them to zero before the loop. - * When the offsets are still zero, we need to restore them after the block to have a correct - * repcode history. If only one offset was invalid, it is easy. The tricky case is when both - * offsets were invalid. We need to figure out which offset to refill with. - * - If both offsets are zero they are in the same order. - * - If both offsets are non-zero, we won't restore the offsets from `offsetSaved[12]`. - * - If only one is zero, we need to decide which offset to restore. - * - If rep_offset1 is non-zero, then rep_offset2 must be offsetSaved1. - * - It is impossible for rep_offset2 to be non-zero. - * - * So if rep_offset1 started invalid (offsetSaved1 != 0) and became valid (rep_offset1 != 0), then - * set rep[0] = rep_offset1 and rep[1] = offsetSaved1. - */ - offsetSaved2 = ((offsetSaved1 != 0) && (rep_offset1 != 0)) ? offsetSaved1 : offsetSaved2; + if (offset_2 > 0) { /* offset_2==0 means offset_2 is invalidated */ + while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) ) { + /* store sequence */ + size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4; + { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ + hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); + ip0 += rLength; + ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, 0 /*offCode*/, rLength-MINMATCH); + anchor = ip0; + continue; /* faster when present (confirmed on gcc-8) ... (?) */ + } } } + ip1 = ip0 + 1; + } /* save reps for next block */ - rep[0] = rep_offset1 ? rep_offset1 : offsetSaved1; - rep[1] = rep_offset2 ? rep_offset2 : offsetSaved2; + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ return (size_t)(iend - anchor); - -_offset: /* Requires: ip0, idx */ - - /* Compute the offset code. */ - match0 = base + idx; - rep_offset2 = rep_offset1; - rep_offset1 = (U32)(ip0-match0); - offcode = OFFSET_TO_OFFBASE(rep_offset1); - mLength = 4; - - /* Count the backwards match length. */ - while (((ip0>anchor) & (match0>prefixStart)) && (ip0[-1] == match0[-1])) { - ip0--; - match0--; - mLength++; - } - -_match: /* Requires: ip0, match0, offcode */ - - /* Count the forward length. */ - mLength += ZSTD_count(ip0 + mLength, match0 + mLength, iend); - - ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); - - ip0 += mLength; - anchor = ip0; - - /* Fill table and check for immediate repcode. */ - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); - - if (rep_offset2 > 0) { /* rep_offset2==0 means rep_offset2 is invalidated */ - while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - rep_offset2)) ) { - /* store sequence */ - size_t const rLength = ZSTD_count(ip0+4, ip0+4-rep_offset2, iend) + 4; - { U32 const tmpOff = rep_offset2; rep_offset2 = rep_offset1; rep_offset1 = tmpOff; } /* swap rep_offset2 <=> rep_offset1 */ - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); - ip0 += rLength; - ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, REPCODE1_TO_OFFBASE, rLength); - anchor = ip0; - continue; /* faster when present (confirmed on gcc-8) ... (?) */ - } } } - - goto _start; } -#define ZSTD_GEN_FAST_FN(dictMode, mls, step) \ - static size_t ZSTD_compressBlock_fast_##dictMode##_##mls##_##step( \ - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ - void const* src, size_t srcSize) \ - { \ - return ZSTD_compressBlock_fast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls, step); \ - } - -ZSTD_GEN_FAST_FN(noDict, 4, 1) -ZSTD_GEN_FAST_FN(noDict, 5, 1) -ZSTD_GEN_FAST_FN(noDict, 6, 1) -ZSTD_GEN_FAST_FN(noDict, 7, 1) - -ZSTD_GEN_FAST_FN(noDict, 4, 0) -ZSTD_GEN_FAST_FN(noDict, 5, 0) -ZSTD_GEN_FAST_FN(noDict, 6, 0) -ZSTD_GEN_FAST_FN(noDict, 7, 0) size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -432,41 +190,24 @@ size_t ZSTD_compressBlock_fast( { U32 const mls = ms->cParams.minMatch; assert(ms->dictMatchState == NULL); - if (ms->cParams.targetLength > 1) { - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_noDict_4_1(ms, seqStore, rep, src, srcSize); - case 5 : - return ZSTD_compressBlock_fast_noDict_5_1(ms, seqStore, rep, src, srcSize); - case 6 : - return ZSTD_compressBlock_fast_noDict_6_1(ms, seqStore, rep, src, srcSize); - case 7 : - return ZSTD_compressBlock_fast_noDict_7_1(ms, seqStore, rep, src, srcSize); - } - } else { - switch(mls) - { - default: /* includes case 3 */ - case 4 : - return ZSTD_compressBlock_fast_noDict_4_0(ms, seqStore, rep, src, srcSize); - case 5 : - return ZSTD_compressBlock_fast_noDict_5_0(ms, seqStore, rep, src, srcSize); - case 6 : - return ZSTD_compressBlock_fast_noDict_6_0(ms, seqStore, rep, src, srcSize); - case 7 : - return ZSTD_compressBlock_fast_noDict_7_0(ms, seqStore, rep, src, srcSize); - } - + switch(mls) + { + default: /* includes case 3 */ + case 4 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4); + case 5 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5); + case 6 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6); + case 7 : + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7); } } FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_compressBlock_fast_dictMatchState_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls, U32 const hasStep) + void const* src, size_t srcSize, U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; @@ -475,14 +216,14 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; - const BYTE* ip0 = istart; - const BYTE* ip1 = ip0 + stepSize; /* we assert below that stepSize >= 1 */ + const BYTE* ip = istart; const BYTE* anchor = istart; const U32 prefixStartIndex = ms->window.dictLimit; const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; + U32 offsetSaved = 0; const ZSTD_matchState_t* const dms = ms->dictMatchState; const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; @@ -492,182 +233,125 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( const BYTE* const dictStart = dictBase + dictStartIndex; const BYTE* const dictEnd = dms->window.nextSrc; const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); - const U32 dictAndPrefixLength = (U32)(istart - prefixStart + dictEnd - dictStart); - const U32 dictHBits = dictCParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; + const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); + const U32 dictHLog = dictCParams->hashLog; /* if a dictionary is still attached, it necessarily means that * it is within window size. So we just check it. */ const U32 maxDistance = 1U << cParams->windowLog; - const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); + const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); assert(endIndex - prefixStartIndex <= maxDistance); (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ - (void)hasStep; /* not currently specialized on whether it's accelerated */ - - /* ensure there will be no underflow + /* ensure there will be no no underflow * when translating a dict index into a local index */ assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); - if (ms->prefetchCDictTables) { - size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); - PREFETCH_AREA(dictHashTable, hashTableBytes); - } - /* init */ DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic"); - ip0 += (dictAndPrefixLength == 0); + ip += (dictAndPrefixLength == 0); /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); - /* Outer search loop */ - assert(stepSize >= 1); - while (ip1 <= ilimit) { /* repcode check at (ip0 + 1) is safe because ip0 < ip1 */ + /* Main Search Loop */ + while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ size_t mLength; - size_t hash0 = ZSTD_hashPtr(ip0, hlog, mls); - - size_t const dictHashAndTag0 = ZSTD_hashPtr(ip0, dictHBits, mls); - U32 dictMatchIndexAndTag = dictHashTable[dictHashAndTag0 >> ZSTD_SHORT_CACHE_TAG_BITS]; - int dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag0); - - U32 matchIndex = hashTable[hash0]; - U32 curr = (U32)(ip0 - base); - size_t step = stepSize; - const size_t kStepIncr = 1 << kSearchStrength; - const BYTE* nextStep = ip0 + kStepIncr; - - /* Inner search loop */ - while (1) { - const BYTE* match = base + matchIndex; - const U32 repIndex = curr + 1 - offset_1; - const BYTE* repMatch = (repIndex < prefixStartIndex) ? - dictBase + (repIndex - dictIndexDelta) : - base + repIndex; - const size_t hash1 = ZSTD_hashPtr(ip1, hlog, mls); - size_t const dictHashAndTag1 = ZSTD_hashPtr(ip1, dictHBits, mls); - hashTable[hash0] = curr; /* update hash table */ - - if (((U32) ((prefixStartIndex - 1) - repIndex) >= - 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ - && (MEM_read32(repMatch) == MEM_read32(ip0 + 1))) { - const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - mLength = ZSTD_count_2segments(ip0 + 1 + 4, repMatch + 4, iend, repMatchEnd, prefixStart) + 4; - ip0++; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, REPCODE1_TO_OFFBASE, mLength); - break; - } - - if (dictTagsMatch) { - /* Found a possible dict match */ - const U32 dictMatchIndex = dictMatchIndexAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; - const BYTE* dictMatch = dictBase + dictMatchIndex; - if (dictMatchIndex > dictStartIndex && - MEM_read32(dictMatch) == MEM_read32(ip0)) { - /* To replicate extDict parse behavior, we only use dict matches when the normal matchIndex is invalid */ - if (matchIndex <= prefixStartIndex) { - U32 const offset = (U32) (curr - dictMatchIndex - dictIndexDelta); - mLength = ZSTD_count_2segments(ip0 + 4, dictMatch + 4, iend, dictEnd, prefixStart) + 4; - while (((ip0 > anchor) & (dictMatch > dictStart)) - && (ip0[-1] == dictMatch[-1])) { - ip0--; - dictMatch--; - mLength++; - } /* catch up */ - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - break; - } - } - } - - if (matchIndex > prefixStartIndex && MEM_read32(match) == MEM_read32(ip0)) { - /* found a regular match */ - U32 const offset = (U32) (ip0 - match); - mLength = ZSTD_count(ip0 + 4, match + 4, iend) + 4; - while (((ip0 > anchor) & (match > prefixStart)) - && (ip0[-1] == match[-1])) { - ip0--; - match--; - mLength++; + size_t const h = ZSTD_hashPtr(ip, hlog, mls); + U32 const current = (U32)(ip-base); + U32 const matchIndex = hashTable[h]; + const BYTE* match = base + matchIndex; + const U32 repIndex = current + 1 - offset_1; + const BYTE* repMatch = (repIndex < prefixStartIndex) ? + dictBase + (repIndex - dictIndexDelta) : + base + repIndex; + hashTable[h] = current; /* update hash table */ + + if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ + && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, mLength-MINMATCH); + } else if ( (matchIndex <= prefixStartIndex) ) { + size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); + U32 const dictMatchIndex = dictHashTable[dictHash]; + const BYTE* dictMatch = dictBase + dictMatchIndex; + if (dictMatchIndex <= dictStartIndex || + MEM_read32(dictMatch) != MEM_read32(ip)) { + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; + } else { + /* found a dict match */ + U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); + mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; + while (((ip>anchor) & (dictMatch>dictStart)) + && (ip[-1] == dictMatch[-1])) { + ip--; dictMatch--; mLength++; } /* catch up */ offset_2 = offset_1; offset_1 = offset; - ZSTD_storeSeq(seqStore, (size_t) (ip0 - anchor), anchor, iend, OFFSET_TO_OFFBASE(offset), mLength); - break; - } - - /* Prepare for next iteration */ - dictMatchIndexAndTag = dictHashTable[dictHashAndTag1 >> ZSTD_SHORT_CACHE_TAG_BITS]; - dictTagsMatch = ZSTD_comparePackedTags(dictMatchIndexAndTag, dictHashAndTag1); - matchIndex = hashTable[hash1]; - - if (ip1 >= nextStep) { - step++; - nextStep += kStepIncr; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); } - ip0 = ip1; - ip1 = ip1 + step; - if (ip1 > ilimit) goto _cleanup; - - curr = (U32)(ip0 - base); - hash0 = hash1; - } /* end inner search loop */ + } else if (MEM_read32(match) != MEM_read32(ip)) { + /* it's not a match, and we're not going to check the dictionary */ + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; + } else { + /* found a regular match */ + U32 const offset = (U32)(ip-match); + mLength = ZSTD_count(ip+4, match+4, iend) + 4; + while (((ip>anchor) & (match>prefixStart)) + && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + } /* match found */ - assert(mLength); - ip0 += mLength; - anchor = ip0; + ip += mLength; + anchor = ip; - if (ip0 <= ilimit) { + if (ip <= ilimit) { /* Fill Table */ - assert(base+curr+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; /* here because curr+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); + assert(base+current+2 > istart); /* check base overflow */ + hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ + hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); /* check immediate repcode */ - while (ip0 <= ilimit) { - U32 const current2 = (U32)(ip0-base); + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); U32 const repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase - dictIndexDelta + repIndex2 : base + repIndex2; if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) - && (MEM_read32(repMatch2) == MEM_read32(ip0))) { + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = current2; - ip0 += repLength2; - anchor = ip0; + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, repLength2-MINMATCH); + hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; + ip += repLength2; + anchor = ip; continue; } break; } } - - /* Prepare for next iteration */ - assert(ip0 == anchor); - ip1 = ip0 + stepSize; } -_cleanup: /* save reps for next block */ - rep[0] = offset_1; - rep[1] = offset_2; + rep[0] = offset_1 ? offset_1 : offsetSaved; + rep[1] = offset_2 ? offset_2 : offsetSaved; /* Return the last literals size */ return (size_t)(iend - anchor); } - -ZSTD_GEN_FAST_FN(dictMatchState, 4, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 5, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 6, 0) -ZSTD_GEN_FAST_FN(dictMatchState, 7, 0) - size_t ZSTD_compressBlock_fast_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -678,31 +362,30 @@ size_t ZSTD_compressBlock_fast_dictMatchState( { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_dictMatchState_4_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_fast_dictMatchState_5_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_fast_dictMatchState_6_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_fast_dictMatchState_7_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7); } } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_fast_extDict_generic( +static size_t ZSTD_compressBlock_fast_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize, U32 const mls, U32 const hasStep) + void const* src, size_t srcSize, U32 const mls) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ - size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; + U32 const stepSize = cParams->targetLength + !(cParams->targetLength); const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); @@ -715,258 +398,102 @@ size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; U32 offset_1=rep[0], offset_2=rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; - - const BYTE* ip0 = istart; - const BYTE* ip1; - const BYTE* ip2; - const BYTE* ip3; - U32 current0; - - - size_t hash0; /* hash for ip0 */ - size_t hash1; /* hash for ip1 */ - U32 idx; /* match idx for ip0 */ - const BYTE* idxBase; /* base pointer for idx */ - - U32 offcode; - const BYTE* match0; - size_t mLength; - const BYTE* matchEnd = 0; /* initialize to avoid warning, assert != 0 later */ - - size_t step; - const BYTE* nextStep; - const size_t kStepIncr = (1 << (kSearchStrength - 1)); - - (void)hasStep; /* not currently specialized on whether it's accelerated */ DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1); /* switch to "regular" variant if extDict is invalidated due to maxDistance */ if (prefixStartIndex == dictStartIndex) - return ZSTD_compressBlock_fast(ms, seqStore, rep, src, srcSize); - - { U32 const curr = (U32)(ip0 - base); - U32 const maxRep = curr - dictStartIndex; - if (offset_2 >= maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 >= maxRep) offsetSaved1 = offset_1, offset_1 = 0; - } - - /* start each op */ -_start: /* Requires: ip0 */ - - step = stepSize; - nextStep = ip0 + kStepIncr; - - /* calculate positions, ip0 - anchor == 0, so we skip step calc */ - ip1 = ip0 + 1; - ip2 = ip0 + step; - ip3 = ip2 + 1; - - if (ip3 >= ilimit) { - goto _cleanup; - } - - hash0 = ZSTD_hashPtr(ip0, hlog, mls); - hash1 = ZSTD_hashPtr(ip1, hlog, mls); - - idx = hashTable[hash0]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - do { - { /* load repcode match for ip[2] */ - U32 const current2 = (U32)(ip2 - base); - U32 const repIndex = current2 - offset_1; - const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; - U32 rval; - if ( ((U32)(prefixStartIndex - repIndex) >= 4) /* intentional underflow */ - & (offset_1 > 0) ) { - rval = MEM_read32(repBase + repIndex); - } else { - rval = MEM_read32(ip2) ^ 1; /* guaranteed to not match. */ + return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); + + /* Search Loop */ + while (ip < ilimit) { /* < instead of <=, because (ip+1) */ + const size_t h = ZSTD_hashPtr(ip, hlog, mls); + const U32 matchIndex = hashTable[h]; + const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; + const BYTE* match = matchBase + matchIndex; + const U32 current = (U32)(ip-base); + const U32 repIndex = current + 1 - offset_1; + const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + hashTable[h] = current; /* update hash table */ + DEBUGLOG(7, "offset_1 = %u , current = %u", offset_1, current); + assert(offset_1 <= current +1); /* check repIndex */ + + if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) + && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { + const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; + size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4; + ip++; + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, 0, rLength-MINMATCH); + ip += rLength; + anchor = ip; + } else { + if ( (matchIndex < dictStartIndex) || + (MEM_read32(match) != MEM_read32(ip)) ) { + assert(stepSize >= 1); + ip += ((ip-anchor) >> kSearchStrength) + stepSize; + continue; } - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - /* check repcode at ip[2] */ - if (MEM_read32(ip2) == rval) { - ip0 = ip2; - match0 = repBase + repIndex; - matchEnd = repIndex < prefixStartIndex ? dictEnd : iend; - assert((match0 != prefixStart) & (match0 != dictStart)); - mLength = ip0[-1] == match0[-1]; - ip0 -= mLength; - match0 -= mLength; - offcode = REPCODE1_TO_OFFBASE; - mLength += 4; - goto _match; - } } - - { /* load match for ip[0] */ - U32 const mval = idx >= dictStartIndex ? - MEM_read32(idxBase + idx) : - MEM_read32(ip0) ^ 1; /* guaranteed not to match */ - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - goto _offset; + { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; + const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; + U32 const offset = current - matchIndex; + size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; + while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ + offset_2 = offset_1; offset_1 = offset; /* update offset history */ + ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, offset + ZSTD_REP_MOVE, mLength-MINMATCH); + ip += mLength; + anchor = ip; } } - /* lookup ip[1] */ - idx = hashTable[hash1]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip3; - - /* write back hash table entry */ - current0 = (U32)(ip0 - base); - hashTable[hash0] = current0; - - { /* load match for ip[0] */ - U32 const mval = idx >= dictStartIndex ? - MEM_read32(idxBase + idx) : - MEM_read32(ip0) ^ 1; /* guaranteed not to match */ - - /* check match at ip[0] */ - if (MEM_read32(ip0) == mval) { - /* found a match! */ - goto _offset; - } } - - /* lookup ip[1] */ - idx = hashTable[hash1]; - idxBase = idx < prefixStartIndex ? dictBase : base; - - /* hash ip[2] */ - hash0 = hash1; - hash1 = ZSTD_hashPtr(ip2, hlog, mls); - - /* advance to next positions */ - ip0 = ip1; - ip1 = ip2; - ip2 = ip0 + step; - ip3 = ip1 + step; - - /* calculate step */ - if (ip2 >= nextStep) { - step++; - PREFETCH_L1(ip1 + 64); - PREFETCH_L1(ip1 + 128); - nextStep += kStepIncr; - } - } while (ip3 < ilimit); - -_cleanup: - /* Note that there are probably still a couple positions we could search. - * However, it seems to be a meaningful performance hit to try to search - * them. So let's not. */ - - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; + if (ip <= ilimit) { + /* Fill Table */ + hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; + hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); + /* check immediate repcode */ + while (ip <= ilimit) { + U32 const current2 = (U32)(ip-base); + U32 const repIndex2 = current2 - offset_2; + const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; + if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { + const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; + size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; + { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, 0 /*offcode*/, repLength2-MINMATCH); + hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; + ip += repLength2; + anchor = ip; + continue; + } + break; + } } } /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; + rep[0] = offset_1; + rep[1] = offset_2; /* Return the last literals size */ return (size_t)(iend - anchor); - -_offset: /* Requires: ip0, idx, idxBase */ - - /* Compute the offset code. */ - { U32 const offset = current0 - idx; - const BYTE* const lowMatchPtr = idx < prefixStartIndex ? dictStart : prefixStart; - matchEnd = idx < prefixStartIndex ? dictEnd : iend; - match0 = idxBase + idx; - offset_2 = offset_1; - offset_1 = offset; - offcode = OFFSET_TO_OFFBASE(offset); - mLength = 4; - - /* Count the backwards match length. */ - while (((ip0>anchor) & (match0>lowMatchPtr)) && (ip0[-1] == match0[-1])) { - ip0--; - match0--; - mLength++; - } } - -_match: /* Requires: ip0, match0, offcode, matchEnd */ - - /* Count the forward length. */ - assert(matchEnd != 0); - mLength += ZSTD_count_2segments(ip0 + mLength, match0 + mLength, iend, matchEnd, prefixStart); - - ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); - - ip0 += mLength; - anchor = ip0; - - /* write next hash table entry */ - if (ip1 < ip0) { - hashTable[hash1] = (U32)(ip1 - base); - } - - /* Fill table and check for immediate repcode. */ - if (ip0 <= ilimit) { - /* Fill Table */ - assert(base+current0+2 > istart); /* check base overflow */ - hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ - hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); - - while (ip0 <= ilimit) { - U32 const repIndex2 = (U32)(ip0-base) - offset_2; - const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; - if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 > 0)) /* intentional underflow */ - && (MEM_read32(repMatch2) == MEM_read32(ip0)) ) { - const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; - size_t const repLength2 = ZSTD_count_2segments(ip0+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; - { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, REPCODE1_TO_OFFBASE, repLength2); - hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); - ip0 += repLength2; - anchor = ip0; - continue; - } - break; - } } - - goto _start; } -ZSTD_GEN_FAST_FN(extDict, 4, 0) -ZSTD_GEN_FAST_FN(extDict, 5, 0) -ZSTD_GEN_FAST_FN(extDict, 6, 0) -ZSTD_GEN_FAST_FN(extDict, 7, 0) size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { U32 const mls = ms->cParams.minMatch; - assert(ms->dictMatchState == NULL); switch(mls) { default: /* includes case 3 */ case 4 : - return ZSTD_compressBlock_fast_extDict_4_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_fast_extDict_5_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_fast_extDict_6_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_fast_extDict_7_0(ms, seqStore, rep, src, srcSize); + return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); } } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp b/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp index 1e9152823..af2d3b703 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_lazy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -10,25 +10,16 @@ #include "zstd/compress/zstd_compress_internal.h" #include "zstd/compress/zstd_lazy.h" -#include "zstd/common/bits.h" /* ZSTD_countTrailingZeros64 */ - -namespace duckdb_zstd { - -#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) - -#define kLazySkippingStep 8 /*-************************************* * Binary Tree search ***************************************/ -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_updateDUBT(ZSTD_matchState_t* ms, +namespace duckdb_zstd { + +static void +ZSTD_updateDUBT(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend, U32 mls) { @@ -69,12 +60,11 @@ void ZSTD_updateDUBT(ZSTD_matchState_t* ms, /** ZSTD_insertDUBT1() : * sort one already inserted but unsorted position - * assumption : curr >= btlow == (curr - btmask) + * assumption : current >= btlow == (current - btmask) * doesn't fail */ -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, - U32 curr, const BYTE* inputEnd, +static void +ZSTD_insertDUBT1(ZSTD_matchState_t* ms, + U32 current, const BYTE* inputEnd, U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) { @@ -86,41 +76,41 @@ void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const U32 dictLimit = ms->window.dictLimit; - const BYTE* const ip = (curr>=dictLimit) ? base + curr : dictBase + curr; - const BYTE* const iend = (curr>=dictLimit) ? inputEnd : dictBase + dictLimit; + const BYTE* const ip = (current>=dictLimit) ? base + current : dictBase + current; + const BYTE* const iend = (current>=dictLimit) ? inputEnd : dictBase + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - U32* smallerPtr = bt + 2*(curr&btMask); + U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = smallerPtr + 1; U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ U32 const windowValid = ms->window.lowLimit; U32 const maxDistance = 1U << cParams->windowLog; - U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid; + U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid; DEBUGLOG(8, "ZSTD_insertDUBT1(%u) (dictLimit=%u, lowLimit=%u)", - curr, dictLimit, windowLow); - assert(curr >= btLow); + current, dictLimit, windowLow); + assert(current >= btLow); assert(ip < iend); /* condition for ZSTD_count */ - for (; nbCompares && (matchIndex > windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex > windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < curr); + assert(matchIndex < current); /* note : all candidates are now supposed sorted, * but it's still possible to have nextPtr[1] == ZSTD_DUBT_UNSORTED_MARK * when a real index has the same value as ZSTD_DUBT_UNSORTED_MARK */ if ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit) /* both in current segment*/ - || (curr < dictLimit) /* both in extDict */) { + || (current < dictLimit) /* both in extDict */) { const BYTE* const mBase = ( (dictMode != ZSTD_extDict) || (matchIndex+matchLength >= dictLimit)) ? base : dictBase; assert( (matchIndex+matchLength >= dictLimit) /* might be wrong if extDict is incorrectly set to 0 */ - || (curr < dictLimit) ); + || (current < dictLimit) ); match = mBase + matchIndex; matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend); } else { @@ -131,7 +121,7 @@ void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, } DEBUGLOG(8, "ZSTD_insertDUBT1: comparing %u with %u : found %u common bytes ", - curr, matchIndex, (U32)matchLength); + current, matchIndex, (U32)matchLength); if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */ @@ -161,10 +151,9 @@ void ZSTD_insertDUBT1(const ZSTD_matchState_t* ms, } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_DUBT_findBetterDictMatch ( - const ZSTD_matchState_t* ms, +static size_t +ZSTD_DUBT_findBetterDictMatch ( + ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, size_t* offsetPtr, size_t bestLength, @@ -181,7 +170,7 @@ size_t ZSTD_DUBT_findBetterDictMatch ( const BYTE* const base = ms->window.base; const BYTE* const prefixStart = base + ms->window.dictLimit; - U32 const curr = (U32)(ip-base); + U32 const current = (U32)(ip-base); const BYTE* const dictBase = dms->window.base; const BYTE* const dictEnd = dms->window.nextSrc; U32 const dictHighLimit = (U32)(dms->window.nextSrc - dms->window.base); @@ -198,7 +187,7 @@ size_t ZSTD_DUBT_findBetterDictMatch ( (void)dictMode; assert(dictMode == ZSTD_dictMatchState); - for (; nbCompares && (dictMatchIndex > dictLowLimit); --nbCompares) { + while (nbCompares-- && (dictMatchIndex > dictLowLimit)) { U32* const nextPtr = dictBt + 2*(dictMatchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dictBase + dictMatchIndex; @@ -208,10 +197,10 @@ size_t ZSTD_DUBT_findBetterDictMatch ( if (matchLength > bestLength) { U32 matchIndex = dictMatchIndex + dictIndexDelta; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) { DEBUGLOG(9, "ZSTD_DUBT_findBetterDictMatch(%u) : found better match length %u -> %u and offsetCode %u -> %u (dictMatchIndex %u, matchIndex %u)", - curr, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, OFFSET_TO_OFFBASE(curr - matchIndex), dictMatchIndex, matchIndex); - bestLength = matchLength, *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + current, (U32)bestLength, (U32)matchLength, (U32)*offsetPtr, ZSTD_REP_MOVE + current - matchIndex, dictMatchIndex, matchIndex); + bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; } if (ip+matchLength == iend) { /* reached end of input : ip[matchLength] is not valid, no way to know if it's larger or smaller than match */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ @@ -231,20 +220,19 @@ size_t ZSTD_DUBT_findBetterDictMatch ( } if (bestLength >= MINMATCH) { - U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offsetPtr); (void)mIndex; + U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBetterDictMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - curr, (U32)bestLength, (U32)*offsetPtr, mIndex); + current, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, +static size_t +ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - size_t* offBasePtr, + size_t* offsetPtr, U32 const mls, const ZSTD_dictMode_e dictMode) { @@ -255,13 +243,13 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 matchIndex = hashTable[h]; const BYTE* const base = ms->window.base; - U32 const curr = (U32)(ip-base); - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const current = (U32)(ip-base); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; U32 const btMask = (1 << btLog) - 1; - U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; + U32 const btLow = (btMask >= current) ? 0 : current - btMask; U32 const unsortLimit = MAX(btLow, windowLow); U32* nextCandidate = bt + 2*(matchIndex&btMask); @@ -270,9 +258,8 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, U32 nbCandidates = nbCompares; U32 previousCandidate = 0; - DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", curr); + DEBUGLOG(7, "ZSTD_DUBT_findBestMatch (%u) ", current); assert(ip <= iend-8); /* required for h calculation */ - assert(dictMode != ZSTD_dedicatedDictSearch); /* reach end of unsorted candidates list */ while ( (matchIndex > unsortLimit) @@ -314,16 +301,16 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, const U32 dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32* smallerPtr = bt + 2*(curr&btMask); - U32* largerPtr = bt + 2*(curr&btMask) + 1; - U32 matchEndIdx = curr + 8 + 1; + U32* smallerPtr = bt + 2*(current&btMask); + U32* largerPtr = bt + 2*(current&btMask) + 1; + U32 matchEndIdx = current + 8 + 1; U32 dummy32; /* to be nullified at the end */ size_t bestLength = 0; matchIndex = hashTable[h]; - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ - for (; nbCompares && (matchIndex > windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex > windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match; @@ -341,8 +328,8 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(curr - matchIndex + 1) - ZSTD_highbit32((U32)*offBasePtr)) ) - bestLength = matchLength, *offBasePtr = OFFSET_TO_OFFBASE(curr - matchIndex); + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) ) + bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */ if (dictMode == ZSTD_dictMatchState) { nbCompares = 0; /* in addition to avoiding checking any @@ -371,20 +358,19 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, *smallerPtr = *largerPtr = 0; - assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { bestLength = ZSTD_DUBT_findBetterDictMatch( ms, ip, iend, - offBasePtr, bestLength, nbCompares, + offsetPtr, bestLength, nbCompares, mls, dictMode); } - assert(matchEndIdx > curr+8); /* ensure nextToUpdate is increased */ + assert(matchEndIdx > current+8); /* ensure nextToUpdate is increased */ ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ if (bestLength >= MINMATCH) { - U32 const mIndex = curr - (U32)OFFBASE_TO_OFFSET(*offBasePtr); (void)mIndex; + U32 const mIndex = current - ((U32)*offsetPtr - ZSTD_REP_MOVE); (void)mIndex; DEBUGLOG(8, "ZSTD_DUBT_findBestMatch(%u) : found match of length %u and offsetCode %u (pos %u)", - curr, (U32)bestLength, (U32)*offBasePtr, mIndex); + current, (U32)bestLength, (U32)*offsetPtr, mIndex); } return bestLength; } @@ -392,236 +378,69 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms, /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, +FORCE_INLINE_TEMPLATE size_t +ZSTD_BtFindBestMatch( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, - size_t* offBasePtr, + size_t* offsetPtr, const U32 mls /* template */, const ZSTD_dictMode_e dictMode) { DEBUGLOG(7, "ZSTD_BtFindBestMatch"); if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ ZSTD_updateDUBT(ms, ip, iLimit, mls); - return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offBasePtr, mls, dictMode); + return ZSTD_DUBT_findBestMatch(ms, ip, iLimit, offsetPtr, mls, dictMode); } -/*********************************** -* Dedicated dict search -***********************************/ -void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip) +static size_t +ZSTD_BtFindBestMatch_selectMLS ( ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - const BYTE* const base = ms->window.base; - U32 const target = (U32)(ip - base); - U32* const hashTable = ms->hashTable; - U32* const chainTable = ms->chainTable; - U32 const chainSize = 1 << ms->cParams.chainLog; - U32 idx = ms->nextToUpdate; - U32 const minChain = chainSize < target - idx ? target - chainSize : idx; - U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 const cacheSize = bucketSize - 1; - U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize; - U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts; - - /* We know the hashtable is oversized by a factor of `bucketSize`. - * We are going to temporarily pretend `bucketSize == 1`, keeping only a - * single entry. We will use the rest of the space to construct a temporary - * chaintable. - */ - U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; - U32* const tmpHashTable = hashTable; - U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog); - U32 const tmpChainSize = (U32)((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog; - U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx; - U32 hashIdx; - - assert(ms->cParams.chainLog <= 24); - assert(ms->cParams.hashLog > ms->cParams.chainLog); - assert(idx != 0); - assert(tmpMinChain <= minChain); - - /* fill conventional hash table and conventional chain table */ - for ( ; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch); - if (idx >= tmpMinChain) { - tmpChainTable[idx - tmpMinChain] = hashTable[h]; - } - tmpHashTable[h] = idx; - } - - /* sort chains into ddss chain table */ + switch(ms->cParams.minMatch) { - U32 chainPos = 0; - for (hashIdx = 0; hashIdx < (1U << hashLog); hashIdx++) { - U32 count; - U32 countBeyondMinChain = 0; - U32 i = tmpHashTable[hashIdx]; - for (count = 0; i >= tmpMinChain && count < cacheSize; count++) { - /* skip through the chain to the first position that won't be - * in the hash cache bucket */ - if (i < minChain) { - countBeyondMinChain++; - } - i = tmpChainTable[i - tmpMinChain]; - } - if (count == cacheSize) { - for (count = 0; count < chainLimit;) { - if (i < minChain) { - if (!i || ++countBeyondMinChain > cacheSize) { - /* only allow pulling `cacheSize` number of entries - * into the cache or chainTable beyond `minChain`, - * to replace the entries pulled out of the - * chainTable into the cache. This lets us reach - * back further without increasing the total number - * of entries in the chainTable, guaranteeing the - * DDSS chain table will fit into the space - * allocated for the regular one. */ - break; - } - } - chainTable[chainPos++] = i; - count++; - if (i < tmpMinChain) { - break; - } - i = tmpChainTable[i - tmpMinChain]; - } - } else { - count = 0; - } - if (count) { - tmpHashTable[hashIdx] = ((chainPos - count) << 8) + count; - } else { - tmpHashTable[hashIdx] = 0; - } - } - assert(chainPos <= chainSize); /* I believe this is guaranteed... */ - } - - /* move chain pointers into the last entry of each hash bucket */ - for (hashIdx = (1 << hashLog); hashIdx; ) { - U32 const bucketIdx = --hashIdx << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 const chainPackedPointer = tmpHashTable[hashIdx]; - U32 i; - for (i = 0; i < cacheSize; i++) { - hashTable[bucketIdx + i] = 0; - } - hashTable[bucketIdx + bucketSize - 1] = chainPackedPointer; - } - - /* fill the buckets of the hash table */ - for (idx = ms->nextToUpdate; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch) - << ZSTD_LAZY_DDSS_BUCKET_LOG; - U32 i; - /* Shift hash cache down 1. */ - for (i = cacheSize - 1; i; i--) - hashTable[h + i] = hashTable[h + i - 1]; - hashTable[h] = idx; + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); } - - ms->nextToUpdate = target; } -/* Returns the longest match length found in the dedicated dict search structure. - * If none are longer than the argument ml, then ml will be returned. - */ -FORCE_INLINE_TEMPLATE -size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nbAttempts, - const ZSTD_matchState_t* const dms, - const BYTE* const ip, const BYTE* const iLimit, - const BYTE* const prefixStart, const U32 curr, - const U32 dictLimit, const size_t ddsIdx) { - const U32 ddsLowestIndex = dms->window.dictLimit; - const BYTE* const ddsBase = dms->window.base; - const BYTE* const ddsEnd = dms->window.nextSrc; - const U32 ddsSize = (U32)(ddsEnd - ddsBase); - const U32 ddsIndexDelta = dictLimit - ddsSize; - const U32 bucketSize = (1 << ZSTD_LAZY_DDSS_BUCKET_LOG); - const U32 bucketLimit = nbAttempts < bucketSize - 1 ? nbAttempts : bucketSize - 1; - U32 ddsAttempt; - U32 matchIndex; - - for (ddsAttempt = 0; ddsAttempt < bucketSize - 1; ddsAttempt++) { - PREFETCH_L1(ddsBase + dms->hashTable[ddsIdx + ddsAttempt]); - } +static size_t ZSTD_BtFindBestMatch_dictMatchState_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) +{ + switch(ms->cParams.minMatch) { - U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; - U32 const chainIndex = chainPackedPointer >> 8; - - PREFETCH_L1(&dms->chainTable[chainIndex]); + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); } +} - for (ddsAttempt = 0; ddsAttempt < bucketLimit; ddsAttempt++) { - size_t currentMl=0; - const BYTE* match; - matchIndex = dms->hashTable[ddsIdx + ddsAttempt]; - match = ddsBase + matchIndex; - - if (!matchIndex) { - return ml; - } - - /* guaranteed by table construction */ - (void)ddsLowestIndex; - assert(matchIndex >= ddsLowestIndex); - assert(match+4 <= ddsEnd); - if (MEM_read32(match) == MEM_read32(ip)) { - /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; - } - - /* save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); - if (ip+currentMl == iLimit) { - /* best possible, avoids read overflow on next attempt */ - return ml; - } - } - } +static size_t ZSTD_BtFindBestMatch_extDict_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) +{ + switch(ms->cParams.minMatch) { - U32 const chainPackedPointer = dms->hashTable[ddsIdx + bucketSize - 1]; - U32 chainIndex = chainPackedPointer >> 8; - U32 const chainLength = chainPackedPointer & 0xFF; - U32 const chainAttempts = nbAttempts - ddsAttempt; - U32 const chainLimit = chainAttempts > chainLength ? chainLength : chainAttempts; - U32 chainAttempt; - - for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++) { - PREFETCH_L1(ddsBase + dms->chainTable[chainIndex + chainAttempt]); - } - - for (chainAttempt = 0 ; chainAttempt < chainLimit; chainAttempt++, chainIndex++) { - size_t currentMl=0; - const BYTE* match; - matchIndex = dms->chainTable[chainIndex]; - match = ddsBase + matchIndex; - - /* guaranteed by table construction */ - assert(matchIndex >= ddsLowestIndex); - assert(match+4 <= ddsEnd); - if (MEM_read32(match) == MEM_read32(ip)) { - /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, ddsEnd, prefixStart) + 4; - } - - /* save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + ddsIndexDelta)); - if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ - } - } + default : /* includes case 3 */ + case 4 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); + case 5 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); + case 7 : + case 6 : return ZSTD_BtFindBestMatch(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); } - return ml; } + /* ********************************* * Hash Chain ***********************************/ @@ -629,12 +448,10 @@ size_t ZSTD_dedicatedDictSearch_lazy_search(size_t* offsetPtr, size_t ml, U32 nb /* Update chains up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_insertAndFindFirstIndex_internal( +static U32 ZSTD_insertAndFindFirstIndex_internal( ZSTD_matchState_t* ms, const ZSTD_compressionParameters* const cParams, - const BYTE* ip, U32 const mls, U32 const lazySkipping) + const BYTE* ip, U32 const mls) { U32* const hashTable = ms->hashTable; const U32 hashLog = cParams->hashLog; @@ -649,9 +466,6 @@ U32 ZSTD_insertAndFindFirstIndex_internal( NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; hashTable[h] = idx; idx++; - /* Stop inserting every position when in the lazy skipping mode. */ - if (lazySkipping) - break; } ms->nextToUpdate = target; @@ -660,13 +474,13 @@ U32 ZSTD_insertAndFindFirstIndex_internal( U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip) { const ZSTD_compressionParameters* const cParams = &ms->cParams; - return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch, /* lazySkipping*/ 0); + return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch); } + /* inlining is important to hardwire a hot branch (template emulation) */ FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_HcFindBestMatch( +size_t ZSTD_HcFindBestMatch_generic ( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -681,39 +495,25 @@ size_t ZSTD_HcFindBestMatch( const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const U32 curr = (U32)(ip-base); + const U32 current = (U32)(ip-base); const U32 maxDistance = 1U << cParams->windowLog; const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 minChain = curr > chainSize ? curr - chainSize : 0; + const U32 minChain = current > chainSize ? current - chainSize : 0; U32 nbAttempts = 1U << cParams->searchLog; size_t ml=4-1; - const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch - ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; - const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch - ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0; - - U32 matchIndex; - - if (dictMode == ZSTD_dedicatedDictSearch) { - const U32* entry = &dms->hashTable[ddsIdx]; - PREFETCH_L1(entry); - } - /* HC4 match finder */ - matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls, ms->lazySkipping); + U32 matchIndex = ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, mls); - for ( ; (matchIndex>=lowLimit) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { const BYTE* const match = base + matchIndex; assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ - /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ - if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ + if (match[ml] == ip[ml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iLimit); } else { const BYTE* const match = dictBase + matchIndex; @@ -725,7 +525,7 @@ size_t ZSTD_HcFindBestMatch( /* save best solution */ if (currentMl > ml) { ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); + *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } @@ -733,11 +533,8 @@ size_t ZSTD_HcFindBestMatch( matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); } - assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ - if (dictMode == ZSTD_dedicatedDictSearch) { - ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts, dms, - ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); - } else if (dictMode == ZSTD_dictMatchState) { + if (dictMode == ZSTD_dictMatchState) { + const ZSTD_matchState_t* const dms = ms->dictMatchState; const U32* const dmsChainTable = dms->chainTable; const U32 dmsChainSize = (1 << dms->cParams.chainLog); const U32 dmsChainMask = dmsChainSize - 1; @@ -750,7 +547,7 @@ size_t ZSTD_HcFindBestMatch( matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; - for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { + for ( ; (matchIndex>dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; const BYTE* const match = dmsBase + matchIndex; assert(match+4 <= dmsEnd); @@ -760,13 +557,11 @@ size_t ZSTD_HcFindBestMatch( /* save best solution */ if (currentMl > ml) { ml = currentMl; - assert(curr > matchIndex + dmsIndexDelta); - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); + *offsetPtr = current - (matchIndex + dmsIndexDelta) + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ } if (matchIndex <= dmsMinChain) break; - matchIndex = dmsChainTable[matchIndex & dmsChainMask]; } } @@ -774,748 +569,62 @@ size_t ZSTD_HcFindBestMatch( return ml; } -/* ********************************* -* (SIMD) Row-based matchfinder -***********************************/ -/* Constants for row-based hash */ -#define ZSTD_ROW_HASH_TAG_MASK ((1u << ZSTD_ROW_HASH_TAG_BITS) - 1) -#define ZSTD_ROW_HASH_MAX_ENTRIES 64 /* absolute maximum number of entries per row, for all configurations */ - -#define ZSTD_ROW_HASH_CACHE_MASK (ZSTD_ROW_HASH_CACHE_SIZE - 1) - -typedef U64 ZSTD_VecMask; /* Clarifies when we are interacting with a U64 representing a mask of matches */ - -/* ZSTD_VecMask_next(): - * Starting from the LSB, returns the idx of the next non-zero bit. - * Basically counting the nb of trailing zeroes. - */ -MEM_STATIC U32 ZSTD_VecMask_next(ZSTD_VecMask val) { - return ZSTD_countTrailingZeros64(val); -} - -/* ZSTD_row_nextIndex(): - * Returns the next index to insert at within a tagTable row, and updates the "head" - * value to reflect the update. Essentially cycles backwards from [1, {entries per row}) - */ -FORCE_INLINE_TEMPLATE U32 ZSTD_row_nextIndex(BYTE* const tagRow, U32 const rowMask) { - U32 next = (*tagRow-1) & rowMask; - next += (next == 0) ? rowMask : 0; /* skip first position */ - *tagRow = (BYTE)next; - return next; -} - -/* ZSTD_isAligned(): - * Checks that a pointer is aligned to "align" bytes which must be a power of 2. - */ -MEM_STATIC int ZSTD_isAligned(void const* ptr, size_t align) { - assert((align & (align - 1)) == 0); - return (((size_t)ptr) & (align - 1)) == 0; -} - -/* ZSTD_row_prefetch(): - * Performs prefetching for the hashTable and tagTable at a given row. - */ -FORCE_INLINE_TEMPLATE void ZSTD_row_prefetch(U32 const* hashTable, BYTE const* tagTable, U32 const relRow, U32 const rowLog) { - PREFETCH_L1(hashTable + relRow); - if (rowLog >= 5) { - PREFETCH_L1(hashTable + relRow + 16); - /* Note: prefetching more of the hash table does not appear to be beneficial for 128-entry rows */ - } - PREFETCH_L1(tagTable + relRow); - if (rowLog == 6) { - PREFETCH_L1(tagTable + relRow + 32); - } - assert(rowLog == 4 || rowLog == 5 || rowLog == 6); - assert(ZSTD_isAligned(hashTable + relRow, 64)); /* prefetched hash row always 64-byte aligned */ - assert(ZSTD_isAligned(tagTable + relRow, (size_t)1 << rowLog)); /* prefetched tagRow sits on correct multiple of bytes (32,64,128) */ -} - -/* ZSTD_row_fillHashCache(): - * Fill up the hash cache starting at idx, prefetching up to ZSTD_ROW_HASH_CACHE_SIZE entries, - * but not beyond iLimit. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_row_fillHashCache(ZSTD_matchState_t* ms, const BYTE* base, - U32 const rowLog, U32 const mls, - U32 idx, const BYTE* const iLimit) -{ - U32 const* const hashTable = ms->hashTable; - BYTE const* const tagTable = ms->tagTable; - U32 const hashLog = ms->rowHashLog; - U32 const maxElemsToPrefetch = (base + idx) > iLimit ? 0 : (U32)(iLimit - (base + idx) + 1); - U32 const lim = idx + MIN(ZSTD_ROW_HASH_CACHE_SIZE, maxElemsToPrefetch); - - for (; idx < lim; ++idx) { - U32 const hash = (U32)ZSTD_hashPtrSalted(base + idx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); - U32 const row = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); - ms->hashCache[idx & ZSTD_ROW_HASH_CACHE_MASK] = hash; - } - - DEBUGLOG(6, "ZSTD_row_fillHashCache(): [%u %u %u %u %u %u %u %u]", ms->hashCache[0], ms->hashCache[1], - ms->hashCache[2], ms->hashCache[3], ms->hashCache[4], - ms->hashCache[5], ms->hashCache[6], ms->hashCache[7]); -} - -/* ZSTD_row_nextCachedHash(): - * Returns the hash of base + idx, and replaces the hash in the hash cache with the byte at - * base + idx + ZSTD_ROW_HASH_CACHE_SIZE. Also prefetches the appropriate rows from hashTable and tagTable. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_row_nextCachedHash(U32* cache, U32 const* hashTable, - BYTE const* tagTable, BYTE const* base, - U32 idx, U32 const hashLog, - U32 const rowLog, U32 const mls, - U64 const hashSalt) -{ - U32 const newHash = (U32)ZSTD_hashPtrSalted(base+idx+ZSTD_ROW_HASH_CACHE_SIZE, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); - U32 const row = (newHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - ZSTD_row_prefetch(hashTable, tagTable, row, rowLog); - { U32 const hash = cache[idx & ZSTD_ROW_HASH_CACHE_MASK]; - cache[idx & ZSTD_ROW_HASH_CACHE_MASK] = newHash; - return hash; - } -} -/* ZSTD_row_update_internalImpl(): - * Updates the hash table with positions starting from updateStartIdx until updateEndIdx. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_row_update_internalImpl(ZSTD_matchState_t* ms, - U32 updateStartIdx, U32 const updateEndIdx, - U32 const mls, U32 const rowLog, - U32 const rowMask, U32 const useCache) -{ - U32* const hashTable = ms->hashTable; - BYTE* const tagTable = ms->tagTable; - U32 const hashLog = ms->rowHashLog; - const BYTE* const base = ms->window.base; - - DEBUGLOG(6, "ZSTD_row_update_internalImpl(): updateStartIdx=%u, updateEndIdx=%u", updateStartIdx, updateEndIdx); - for (; updateStartIdx < updateEndIdx; ++updateStartIdx) { - U32 const hash = useCache ? ZSTD_row_nextCachedHash(ms->hashCache, hashTable, tagTable, base, updateStartIdx, hashLog, rowLog, mls, ms->hashSalt) - : (U32)ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt); - U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - U32* const row = hashTable + relRow; - BYTE* tagRow = tagTable + relRow; - U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); - - assert(hash == ZSTD_hashPtrSalted(base + updateStartIdx, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, ms->hashSalt)); - tagRow[pos] = hash & ZSTD_ROW_HASH_TAG_MASK; - row[pos] = updateStartIdx; - } -} - -/* ZSTD_row_update_internal(): - * Inserts the byte at ip into the appropriate position in the hash table, and updates ms->nextToUpdate. - * Skips sections of long matches as is necessary. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_row_update_internal(ZSTD_matchState_t* ms, const BYTE* ip, - U32 const mls, U32 const rowLog, - U32 const rowMask, U32 const useCache) -{ - U32 idx = ms->nextToUpdate; - const BYTE* const base = ms->window.base; - const U32 target = (U32)(ip - base); - const U32 kSkipThreshold = 384; - const U32 kMaxMatchStartPositionsToUpdate = 96; - const U32 kMaxMatchEndPositionsToUpdate = 32; - - if (useCache) { - /* Only skip positions when using hash cache, i.e. - * if we are loading a dict, don't skip anything. - * If we decide to skip, then we only update a set number - * of positions at the beginning and end of the match. - */ - if (UNLIKELY(target - idx > kSkipThreshold)) { - U32 const bound = idx + kMaxMatchStartPositionsToUpdate; - ZSTD_row_update_internalImpl(ms, idx, bound, mls, rowLog, rowMask, useCache); - idx = target - kMaxMatchEndPositionsToUpdate; - ZSTD_row_fillHashCache(ms, base, rowLog, mls, idx, ip+1); - } - } - assert(target >= idx); - ZSTD_row_update_internalImpl(ms, idx, target, mls, rowLog, rowMask, useCache); - ms->nextToUpdate = target; -} - -/* ZSTD_row_update(): - * External wrapper for ZSTD_row_update_internal(). Used for filling the hashtable during dictionary - * processing. - */ -void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip) { - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - const U32 rowMask = (1u << rowLog) - 1; - const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */); - - DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog); - ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* don't use cache */); -} - -/* Returns the mask width of bits group of which will be set to 1. Given not all - * architectures have easy movemask instruction, this helps to iterate over - * groups of bits easier and faster. - */ -FORCE_INLINE_TEMPLATE U32 -ZSTD_row_matchMaskGroupWidth(const U32 rowEntries) +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS ( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); - assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); - (void)rowEntries; -#if defined(ZSTD_ARCH_ARM_NEON) - /* NEON path only works for little endian */ - if (!MEM_isLittleEndian()) { - return 1; - } - if (rowEntries == 16) { - return 4; - } - if (rowEntries == 32) { - return 2; - } - if (rowEntries == 64) { - return 1; + switch(ms->cParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_noDict); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_noDict); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_noDict); } -#endif - return 1; } -#if defined(ZSTD_ARCH_X86_SSE2) -FORCE_INLINE_TEMPLATE ZSTD_VecMask -ZSTD_row_getSSEMask(int nbChunks, const BYTE* const src, const BYTE tag, const U32 head) -{ - const __m128i comparisonMask = _mm_set1_epi8((char)tag); - int matches[4] = {0}; - int i; - assert(nbChunks == 1 || nbChunks == 2 || nbChunks == 4); - for (i=0; icParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_dictMatchState); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_dictMatchState); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_dictMatchState); } } -#endif - -/* Returns a ZSTD_VecMask (U64) that has the nth group (determined by - * ZSTD_row_matchMaskGroupWidth) of bits set to 1 if the newly-computed "tag" - * matches the hash at the nth position in a row of the tagTable. - * Each row is a circular buffer beginning at the value of "headGrouped". So we - * must rotate the "matches" bitfield to match up with the actual layout of the - * entries within the hashTable */ -FORCE_INLINE_TEMPLATE ZSTD_VecMask -ZSTD_row_getMatchMask(const BYTE* const tagRow, const BYTE tag, const U32 headGrouped, const U32 rowEntries) -{ - const BYTE* const src = tagRow; - assert((rowEntries == 16) || (rowEntries == 32) || rowEntries == 64); - assert(rowEntries <= ZSTD_ROW_HASH_MAX_ENTRIES); - assert(ZSTD_row_matchMaskGroupWidth(rowEntries) * rowEntries <= sizeof(ZSTD_VecMask) * 8); - -#if defined(ZSTD_ARCH_X86_SSE2) - - return ZSTD_row_getSSEMask(rowEntries / 16, src, tag, headGrouped); - -#else /* SW or NEON-LE */ -# if defined(ZSTD_ARCH_ARM_NEON) - /* This NEON path only works for little endian - otherwise use SWAR below */ - if (MEM_isLittleEndian()) { - return ZSTD_row_getNEONMask(rowEntries, src, tag, headGrouped); - } -# endif /* ZSTD_ARCH_ARM_NEON */ - /* SWAR */ - { const int chunkSize = sizeof(size_t); - const size_t shiftAmount = ((chunkSize * 8) - chunkSize); - const size_t xFF = ~((size_t)0); - const size_t x01 = xFF / 0xFF; - const size_t x80 = x01 << 7; - const size_t splatChar = tag * x01; - ZSTD_VecMask matches = 0; - int i = rowEntries - chunkSize; - assert((sizeof(size_t) == 4) || (sizeof(size_t) == 8)); - if (MEM_isLittleEndian()) { /* runtime check so have two loops */ - const size_t extractMagic = (xFF / 0x7F) >> chunkSize; - do { - size_t chunk = MEM_readST(&src[i]); - chunk ^= splatChar; - chunk = (((chunk | x80) - x01) | chunk) & x80; - matches <<= chunkSize; - matches |= (chunk * extractMagic) >> shiftAmount; - i -= chunkSize; - } while (i >= 0); - } else { /* big endian: reverse bits during extraction */ - const size_t msb = xFF ^ (xFF >> 1); - const size_t extractMagic = (msb / 0x1FF) | msb; - do { - size_t chunk = MEM_readST(&src[i]); - chunk ^= splatChar; - chunk = (((chunk | x80) - x01) | chunk) & x80; - matches <<= chunkSize; - matches |= ((chunk >> 7) * extractMagic) >> shiftAmount; - i -= chunkSize; - } while (i >= 0); - } - matches = ~matches; - if (rowEntries == 16) { - return ZSTD_rotateRight_U16((U16)matches, headGrouped); - } else if (rowEntries == 32) { - return ZSTD_rotateRight_U32((U32)matches, headGrouped); - } else { - return ZSTD_rotateRight_U64((U64)matches, headGrouped); - } - } -#endif -} -/* The high-level approach of the SIMD row based match finder is as follows: - * - Figure out where to insert the new entry: - * - Generate a hash for current input posistion and split it into a one byte of tag and `rowHashLog` bits of index. - * - The hash is salted by a value that changes on every contex reset, so when the same table is used - * we will avoid collisions that would otherwise slow us down by intorducing phantom matches. - * - The hashTable is effectively split into groups or "rows" of 15 or 31 entries of U32, and the index determines - * which row to insert into. - * - Determine the correct position within the row to insert the entry into. Each row of 15 or 31 can - * be considered as a circular buffer with a "head" index that resides in the tagTable (overall 16 or 32 bytes - * per row). - * - Use SIMD to efficiently compare the tags in the tagTable to the 1-byte tag calculated for the position and - * generate a bitfield that we can cycle through to check the collisions in the hash table. - * - Pick the longest match. - * - Insert the tag into the equivalent row and position in the tagTable. - */ -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_RowFindBestMatch( +FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( ZSTD_matchState_t* ms, - const BYTE* const ip, const BYTE* const iLimit, - size_t* offsetPtr, - const U32 mls, const ZSTD_dictMode_e dictMode, - const U32 rowLog) + const BYTE* ip, const BYTE* const iLimit, + size_t* offsetPtr) { - U32* const hashTable = ms->hashTable; - BYTE* const tagTable = ms->tagTable; - U32* const hashCache = ms->hashCache; - const U32 hashLog = ms->rowHashLog; - const ZSTD_compressionParameters* const cParams = &ms->cParams; - const BYTE* const base = ms->window.base; - const BYTE* const dictBase = ms->window.dictBase; - const U32 dictLimit = ms->window.dictLimit; - const BYTE* const prefixStart = base + dictLimit; - const BYTE* const dictEnd = dictBase + dictLimit; - const U32 curr = (U32)(ip-base); - const U32 maxDistance = 1U << cParams->windowLog; - const U32 lowestValid = ms->window.lowLimit; - const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; - const U32 isDictionary = (ms->loadedDictEnd != 0); - const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance; - const U32 rowEntries = (1U << rowLog); - const U32 rowMask = rowEntries - 1; - const U32 cappedSearchLog = MIN(cParams->searchLog, rowLog); /* nb of searches is capped at nb entries per row */ - const U32 groupWidth = ZSTD_row_matchMaskGroupWidth(rowEntries); - const U64 hashSalt = ms->hashSalt; - U32 nbAttempts = 1U << cappedSearchLog; - size_t ml=4-1; - U32 hash; - - /* DMS/DDS variables that may be referenced laster */ - const ZSTD_matchState_t* const dms = ms->dictMatchState; - - /* Initialize the following variables to satisfy static analyzer */ - size_t ddsIdx = 0; - U32 ddsExtraAttempts = 0; /* cctx hash tables are limited in searches, but allow extra searches into DDS */ - U32 dmsTag = 0; - U32* dmsRow = NULL; - BYTE* dmsTagRow = NULL; - - if (dictMode == ZSTD_dedicatedDictSearch) { - const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; - { /* Prefetch DDS hashtable entry */ - ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG; - PREFETCH_L1(&dms->hashTable[ddsIdx]); - } - ddsExtraAttempts = cParams->searchLog > rowLog ? 1U << (cParams->searchLog - rowLog) : 0; - } - - if (dictMode == ZSTD_dictMatchState) { - /* Prefetch DMS rows */ - U32* const dmsHashTable = dms->hashTable; - BYTE* const dmsTagTable = dms->tagTable; - U32 const dmsHash = (U32)ZSTD_hashPtr(ip, dms->rowHashLog + ZSTD_ROW_HASH_TAG_BITS, mls); - U32 const dmsRelRow = (dmsHash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - dmsTag = dmsHash & ZSTD_ROW_HASH_TAG_MASK; - dmsTagRow = (BYTE*)(dmsTagTable + dmsRelRow); - dmsRow = dmsHashTable + dmsRelRow; - ZSTD_row_prefetch(dmsHashTable, dmsTagTable, dmsRelRow, rowLog); - } - - /* Update the hashTable and tagTable up to (but not including) ip */ - if (!ms->lazySkipping) { - ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 1 /* useCache */); - hash = ZSTD_row_nextCachedHash(hashCache, hashTable, tagTable, base, curr, hashLog, rowLog, mls, hashSalt); - } else { - /* Stop inserting every position when in the lazy skipping mode. - * The hash cache is also not kept up to date in this mode. - */ - hash = (U32)ZSTD_hashPtrSalted(ip, hashLog + ZSTD_ROW_HASH_TAG_BITS, mls, hashSalt); - ms->nextToUpdate = curr; - } - ms->hashSaltEntropy += hash; /* collect salt entropy */ - - { /* Get the hash for ip, compute the appropriate row */ - U32 const relRow = (hash >> ZSTD_ROW_HASH_TAG_BITS) << rowLog; - U32 const tag = hash & ZSTD_ROW_HASH_TAG_MASK; - U32* const row = hashTable + relRow; - BYTE* tagRow = (BYTE*)(tagTable + relRow); - U32 const headGrouped = (*tagRow & rowMask) * groupWidth; - U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; - size_t numMatches = 0; - size_t currMatch = 0; - ZSTD_VecMask matches = ZSTD_row_getMatchMask(tagRow, (BYTE)tag, headGrouped, rowEntries); - - /* Cycle through the matches and prefetch */ - for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { - U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; - U32 const matchIndex = row[matchPos]; - if(matchPos == 0) continue; - assert(numMatches < rowEntries); - if (matchIndex < lowLimit) - break; - if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { - PREFETCH_L1(base + matchIndex); - } else { - PREFETCH_L1(dictBase + matchIndex); - } - matchBuffer[numMatches++] = matchIndex; - --nbAttempts; - } - - /* Speed opt: insert current byte into hashtable too. This allows us to avoid one iteration of the loop - in ZSTD_row_update_internal() at the next search. */ - { - U32 const pos = ZSTD_row_nextIndex(tagRow, rowMask); - tagRow[pos] = (BYTE)tag; - row[pos] = ms->nextToUpdate++; - } - - /* Return the longest match */ - for (; currMatch < numMatches; ++currMatch) { - U32 const matchIndex = matchBuffer[currMatch]; - size_t currentMl=0; - assert(matchIndex < curr); - assert(matchIndex >= lowLimit); - - if ((dictMode != ZSTD_extDict) || matchIndex >= dictLimit) { - const BYTE* const match = base + matchIndex; - assert(matchIndex >= dictLimit); /* ensures this is true if dictMode != ZSTD_extDict */ - /* read 4B starting from (match + ml + 1 - sizeof(U32)) */ - if (MEM_read32(match + ml - 3) == MEM_read32(ip + ml - 3)) /* potentially better */ - currentMl = ZSTD_count(ip, match, iLimit); - } else { - const BYTE* const match = dictBase + matchIndex; - assert(match+4 <= dictEnd); - if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4; - } - - /* Save best solution */ - if (currentMl > ml) { - ml = currentMl; - *offsetPtr = OFFSET_TO_OFFBASE(curr - matchIndex); - if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */ - } - } - } - - assert(nbAttempts <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ - if (dictMode == ZSTD_dedicatedDictSearch) { - ml = ZSTD_dedicatedDictSearch_lazy_search(offsetPtr, ml, nbAttempts + ddsExtraAttempts, dms, - ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); - } else if (dictMode == ZSTD_dictMatchState) { - /* TODO: Measure and potentially add prefetching to DMS */ - const U32 dmsLowestIndex = dms->window.dictLimit; - const BYTE* const dmsBase = dms->window.base; - const BYTE* const dmsEnd = dms->window.nextSrc; - const U32 dmsSize = (U32)(dmsEnd - dmsBase); - const U32 dmsIndexDelta = dictLimit - dmsSize; - - { U32 const headGrouped = (*dmsTagRow & rowMask) * groupWidth; - U32 matchBuffer[ZSTD_ROW_HASH_MAX_ENTRIES]; - size_t numMatches = 0; - size_t currMatch = 0; - ZSTD_VecMask matches = ZSTD_row_getMatchMask(dmsTagRow, (BYTE)dmsTag, headGrouped, rowEntries); - - for (; (matches > 0) && (nbAttempts > 0); matches &= (matches - 1)) { - U32 const matchPos = ((headGrouped + ZSTD_VecMask_next(matches)) / groupWidth) & rowMask; - U32 const matchIndex = dmsRow[matchPos]; - if(matchPos == 0) continue; - if (matchIndex < dmsLowestIndex) - break; - PREFETCH_L1(dmsBase + matchIndex); - matchBuffer[numMatches++] = matchIndex; - --nbAttempts; - } - - /* Return the longest match */ - for (; currMatch < numMatches; ++currMatch) { - U32 const matchIndex = matchBuffer[currMatch]; - size_t currentMl=0; - assert(matchIndex >= dmsLowestIndex); - assert(matchIndex < curr); - - { const BYTE* const match = dmsBase + matchIndex; - assert(match+4 <= dmsEnd); - if (MEM_read32(match) == MEM_read32(ip)) - currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dmsEnd, prefixStart) + 4; - } - - if (currentMl > ml) { - ml = currentMl; - assert(curr > matchIndex + dmsIndexDelta); - *offsetPtr = OFFSET_TO_OFFBASE(curr - (matchIndex + dmsIndexDelta)); - if (ip+currentMl == iLimit) break; - } - } - } + switch(ms->cParams.minMatch) + { + default : /* includes case 3 */ + case 4 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 4, ZSTD_extDict); + case 5 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 5, ZSTD_extDict); + case 7 : + case 6 : return ZSTD_HcFindBestMatch_generic(ms, ip, iLimit, offsetPtr, 6, ZSTD_extDict); } - return ml; } -/** - * Generate search functions templated on (dictMode, mls, rowLog). - * These functions are outlined for code size & compilation time. - * ZSTD_searchMax() dispatches to the correct implementation function. - * - * TODO: The start of the search function involves loading and calculating a - * bunch of constants from the ZSTD_matchState_t. These computations could be - * done in an initialization function, and saved somewhere in the match state. - * Then we could pass a pointer to the saved state instead of the match state, - * and avoid duplicate computations. - * - * TODO: Move the match re-winding into searchMax. This improves compression - * ratio, and unlocks further simplifications with the next TODO. - * - * TODO: Try moving the repcode search into searchMax. After the re-winding - * and repcode search are in searchMax, there is no more logic in the match - * finder loop that requires knowledge about the dictMode. So we should be - * able to avoid force inlining it, and we can join the extDict loop with - * the single segment loop. It should go in searchMax instead of its own - * function to avoid having multiple virtual function calls per search. - */ - -#define ZSTD_BT_SEARCH_FN(dictMode, mls) ZSTD_BtFindBestMatch_##dictMode##_##mls -#define ZSTD_HC_SEARCH_FN(dictMode, mls) ZSTD_HcFindBestMatch_##dictMode##_##mls -#define ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) ZSTD_RowFindBestMatch_##dictMode##_##mls##_##rowLog - -#define ZSTD_SEARCH_FN_ATTRS FORCE_NOINLINE - -#define GEN_ZSTD_BT_SEARCH_FN(dictMode, mls) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_BT_SEARCH_FN(dictMode, mls)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offBasePtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - return ZSTD_BtFindBestMatch(ms, ip, iLimit, offBasePtr, mls, ZSTD_##dictMode); \ - } \ - -#define GEN_ZSTD_HC_SEARCH_FN(dictMode, mls) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_HC_SEARCH_FN(dictMode, mls)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offsetPtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - return ZSTD_HcFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode); \ - } \ - -#define GEN_ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog) \ - ZSTD_SEARCH_FN_ATTRS size_t ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)( \ - ZSTD_matchState_t* ms, \ - const BYTE* ip, const BYTE* const iLimit, \ - size_t* offsetPtr) \ - { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - assert(MAX(4, MIN(6, ms->cParams.searchLog)) == rowLog); \ - return ZSTD_RowFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode, rowLog); \ - } \ - -#define ZSTD_FOR_EACH_ROWLOG(X, dictMode, mls) \ - X(dictMode, mls, 4) \ - X(dictMode, mls, 5) \ - X(dictMode, mls, 6) - -#define ZSTD_FOR_EACH_MLS_ROWLOG(X, dictMode) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 4) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 5) \ - ZSTD_FOR_EACH_ROWLOG(X, dictMode, 6) - -#define ZSTD_FOR_EACH_MLS(X, dictMode) \ - X(dictMode, 4) \ - X(dictMode, 5) \ - X(dictMode, 6) - -#define ZSTD_FOR_EACH_DICT_MODE(X, ...) \ - X(__VA_ARGS__, noDict) \ - X(__VA_ARGS__, extDict) \ - X(__VA_ARGS__, dictMatchState) \ - X(__VA_ARGS__, dedicatedDictSearch) - -/* Generate row search fns for each combination of (dictMode, mls, rowLog) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS_ROWLOG, GEN_ZSTD_ROW_SEARCH_FN) -/* Generate binary Tree search fns for each combination of (dictMode, mls) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_BT_SEARCH_FN) -/* Generate hash chain search fns for each combination of (dictMode, mls) */ -ZSTD_FOR_EACH_DICT_MODE(ZSTD_FOR_EACH_MLS, GEN_ZSTD_HC_SEARCH_FN) - -typedef enum { search_hashChain=0, search_binaryTree=1, search_rowHash=2 } searchMethod_e; - -#define GEN_ZSTD_CALL_BT_SEARCH_FN(dictMode, mls) \ - case mls: \ - return ZSTD_BT_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); -#define GEN_ZSTD_CALL_HC_SEARCH_FN(dictMode, mls) \ - case mls: \ - return ZSTD_HC_SEARCH_FN(dictMode, mls)(ms, ip, iend, offsetPtr); -#define GEN_ZSTD_CALL_ROW_SEARCH_FN(dictMode, mls, rowLog) \ - case rowLog: \ - return ZSTD_ROW_SEARCH_FN(dictMode, mls, rowLog)(ms, ip, iend, offsetPtr); - -#define ZSTD_SWITCH_MLS(X, dictMode) \ - switch (mls) { \ - ZSTD_FOR_EACH_MLS(X, dictMode) \ - } - -#define ZSTD_SWITCH_ROWLOG(dictMode, mls) \ - case mls: \ - switch (rowLog) { \ - ZSTD_FOR_EACH_ROWLOG(GEN_ZSTD_CALL_ROW_SEARCH_FN, dictMode, mls) \ - } \ - ZSTD_UNREACHABLE; \ - break; - -#define ZSTD_SWITCH_SEARCH_METHOD(dictMode) \ - switch (searchMethod) { \ - case search_hashChain: \ - ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_HC_SEARCH_FN, dictMode) \ - break; \ - case search_binaryTree: \ - ZSTD_SWITCH_MLS(GEN_ZSTD_CALL_BT_SEARCH_FN, dictMode) \ - break; \ - case search_rowHash: \ - ZSTD_SWITCH_MLS(ZSTD_SWITCH_ROWLOG, dictMode) \ - break; \ - } \ - ZSTD_UNREACHABLE; - -/** - * Searches for the longest match at @p ip. - * Dispatches to the correct implementation function based on the - * (searchMethod, dictMode, mls, rowLog). We use switch statements - * here instead of using an indirect function call through a function - * pointer because after Spectre and Meltdown mitigations, indirect - * function calls can be very costly, especially in the kernel. - * - * NOTE: dictMode and searchMethod should be templated, so those switch - * statements should be optimized out. Only the mls & rowLog switches - * should be left. - * - * @param ms The match state. - * @param ip The position to search at. - * @param iend The end of the input data. - * @param[out] offsetPtr Stores the match offset into this pointer. - * @param mls The minimum search length, in the range [4, 6]. - * @param rowLog The row log (if applicable), in the range [4, 6]. - * @param searchMethod The search method to use (templated). - * @param dictMode The dictMode (templated). - * - * @returns The length of the longest match found, or < mls if no match is found. - * If a match is found its offset is stored in @p offsetPtr. - */ -FORCE_INLINE_TEMPLATE size_t ZSTD_searchMax( - ZSTD_matchState_t* ms, - const BYTE* ip, - const BYTE* iend, - size_t* offsetPtr, - U32 const mls, - U32 const rowLog, - searchMethod_e const searchMethod, - ZSTD_dictMode_e const dictMode) -{ - if (dictMode == ZSTD_noDict) { - ZSTD_SWITCH_SEARCH_METHOD(noDict) - } else if (dictMode == ZSTD_extDict) { - ZSTD_SWITCH_SEARCH_METHOD(extDict) - } else if (dictMode == ZSTD_dictMatchState) { - ZSTD_SWITCH_SEARCH_METHOD(dictMatchState) - } else if (dictMode == ZSTD_dedicatedDictSearch) { - ZSTD_SWITCH_SEARCH_METHOD(dedicatedDictSearch) - } - ZSTD_UNREACHABLE; - return 0; -} - /* ******************************* * Common parser - lazy strategy *********************************/ +typedef enum { search_hashChain, search_binaryTree } searchMethod_e; -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_compressBlock_lazy_generic( +FORCE_INLINE_TEMPLATE size_t +ZSTD_compressBlock_lazy_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize, @@ -1526,52 +635,53 @@ size_t ZSTD_compressBlock_lazy_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = (searchMethod == search_rowHash) ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; + const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const U32 prefixLowestIndex = ms->window.dictLimit; const BYTE* const prefixLowest = base + prefixLowestIndex; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - U32 offset_1 = rep[0], offset_2 = rep[1]; - U32 offsetSaved1 = 0, offsetSaved2 = 0; + typedef size_t (*searchMax_f)( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); + searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ? + (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS + : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) : + (searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS + : ZSTD_HcFindBestMatch_selectMLS); + U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0; - const int isDMS = dictMode == ZSTD_dictMatchState; - const int isDDS = dictMode == ZSTD_dedicatedDictSearch; - const int isDxS = isDMS || isDDS; const ZSTD_matchState_t* const dms = ms->dictMatchState; - const U32 dictLowestIndex = isDxS ? dms->window.dictLimit : 0; - const BYTE* const dictBase = isDxS ? dms->window.base : NULL; - const BYTE* const dictLowest = isDxS ? dictBase + dictLowestIndex : NULL; - const BYTE* const dictEnd = isDxS ? dms->window.nextSrc : NULL; - const U32 dictIndexDelta = isDxS ? + const U32 dictLowestIndex = dictMode == ZSTD_dictMatchState ? + dms->window.dictLimit : 0; + const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ? + dms->window.base : NULL; + const BYTE* const dictLowest = dictMode == ZSTD_dictMatchState ? + dictBase + dictLowestIndex : NULL; + const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ? + dms->window.nextSrc : NULL; + const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ? prefixLowestIndex - (U32)(dictEnd - dictBase) : 0; const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest)); - DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u) (searchFunc=%u)", (U32)dictMode, (U32)searchMethod); + DEBUGLOG(5, "ZSTD_compressBlock_lazy_generic (dictMode=%u)", (U32)dictMode); + + /* init */ ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { - U32 const curr = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog); - U32 const maxRep = curr - windowLow; - if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; - if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; + U32 const current = (U32)(ip - base); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, ms->cParams.windowLog); + U32 const maxRep = current - windowLow; + if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0; + if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { /* dictMatchState repCode checks don't currently handle repCode == 0 * disabling. */ assert(offset_1 <= dictAndPrefixLength); assert(offset_2 <= dictAndPrefixLength); } - /* Reset the lazy skipping state */ - ms->lazySkipping = 0; - - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - /* Match Loop */ #if defined(__GNUC__) && defined(__x86_64__) /* I've measured random a 5% speed loss on levels 5 & 6 (greedy) when the @@ -1581,14 +691,13 @@ size_t ZSTD_compressBlock_lazy_generic( #endif while (ip < ilimit) { size_t matchLength=0; - size_t offBase = REPCODE1_TO_OFFBASE; + size_t offset=0; const BYTE* start=ip+1; - DEBUGLOG(7, "search baseline (depth 0)"); /* check repCode */ - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) + 1 - offset_1; - const BYTE* repMatch = ((dictMode == ZSTD_dictMatchState || dictMode == ZSTD_dedicatedDictSearch) + const BYTE* repMatch = (dictMode == ZSTD_dictMatchState && repIndex < prefixLowestIndex) ? dictBase + (repIndex - dictIndexDelta) : base + repIndex; @@ -1606,40 +715,30 @@ size_t ZSTD_compressBlock_lazy_generic( } /* first search (depth 0) */ - { size_t offbaseFound = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &offbaseFound, mls, rowLog, searchMethod, dictMode); + { size_t offsetFound = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); if (ml2 > matchLength) - matchLength = ml2, start = ip, offBase = offbaseFound; + matchLength = ml2, start = ip, offset=offsetFound; } if (matchLength < 4) { - size_t const step = ((size_t)(ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */; - ip += step; - /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. - * In this mode we stop inserting every position into our tables, and only insert - * positions that we search, which is one in step positions. - * The exact cutoff is flexible, I've just chosen a number that is reasonably high, - * so we minimize the compression ratio loss in "normal" scenarios. This mode gets - * triggered once we've gone 2KB without finding any matches. - */ - ms->lazySkipping = step > kLazySkippingStep; + ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ continue; } /* let's try to find a better solution */ if (depth>=1) while (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -1649,33 +748,32 @@ size_t ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } } - { size_t ofbCandidate=999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { + && (offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) { size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { const U32 repIndex = (U32)(ip - base) - offset_1; const BYTE* repMatch = repIndex < prefixLowestIndex ? dictBase + (repIndex - dictIndexDelta) : @@ -1685,69 +783,64 @@ size_t ZSTD_compressBlock_lazy_generic( const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend; size_t const mlRep = ZSTD_count_2segments(ip+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4; int const gain2 = (int)(mlRep * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((mlRep >= 4) && (gain2 > gain1)) - matchLength = mlRep, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = mlRep, offset = 0, start = ip; } } - { size_t ofbCandidate=999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, dictMode); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* NOTE: - * Pay attention that `start[-value]` can lead to strange undefined behavior - * notably if `value` is unsigned, resulting in a large positive `-value`. + * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior. + * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which + * overflows the pointer, which is undefined behavior. */ /* catch up */ - if (OFFBASE_IS_OFFSET(offBase)) { + if (offset) { if (dictMode == ZSTD_noDict) { - while ( ((start > anchor) & (start - OFFBASE_TO_OFFSET(offBase) > prefixLowest)) - && (start[-1] == (start-OFFBASE_TO_OFFSET(offBase))[-1]) ) /* only search for offset within prefix */ + while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > prefixLowest)) + && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */ { start--; matchLength++; } } - if (isDxS) { - U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); + if (dictMode == ZSTD_dictMatchState) { + U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); const BYTE* match = (matchIndex < prefixLowestIndex) ? dictBase + matchIndex - dictIndexDelta : base + matchIndex; const BYTE* const mStart = (matchIndex < prefixLowestIndex) ? dictLowest : prefixLowest; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ } - offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); + offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); } /* store sequence */ _storeSequence: - { size_t const litLength = (size_t)(start - anchor); - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); + { size_t const litLength = start - anchor; + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } - if (ms->lazySkipping) { - /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - ms->lazySkipping = 0; - } /* check immediate repcode */ - if (isDxS) { + if (dictMode == ZSTD_dictMatchState) { while (ip <= ilimit) { U32 const current2 = (U32)(ip-base); U32 const repIndex = current2 - offset_2; - const BYTE* repMatch = repIndex < prefixLowestIndex ? + const BYTE* repMatch = dictMode == ZSTD_dictMatchState + && repIndex < prefixLowestIndex ? dictBase - dictIndexDelta + repIndex : base + repIndex; if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex) >= 3 /* intentional overflow */) && (MEM_read32(repMatch) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex < prefixLowestIndex ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd2, prefixLowest) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset_2 <=> offset_1 */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset_2 <=> offset_1 */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; @@ -1761,72 +854,36 @@ size_t ZSTD_compressBlock_lazy_generic( && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap repcodes */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ } } } - /* If offset_1 started invalid (offsetSaved1 != 0) and became valid (offset_1 != 0), - * rotate saved offsets. See comment in ZSTD_compressBlock_fast_noDict for more context. */ - offsetSaved2 = ((offsetSaved1 != 0) && (offset_1 != 0)) ? offsetSaved1 : offsetSaved2; - - /* save reps for next block */ - rep[0] = offset_1 ? offset_1 : offsetSaved1; - rep[1] = offset_2 ? offset_2 : offsetSaved2; + /* Save reps for next block */ + rep[0] = offset_1 ? offset_1 : savedOffset; + rep[1] = offset_2 ? offset_2 : savedOffset; /* Return the last literals size */ return (size_t)(iend - anchor); } -#endif /* build exclusions */ - - -#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_greedy( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict); -} -size_t ZSTD_compressBlock_greedy_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_greedy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_noDict); -} -size_t ZSTD_compressBlock_greedy_dictMatchState_row( +size_t ZSTD_compressBlock_btlazy2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dictMatchState); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict); } -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( +size_t ZSTD_compressBlock_lazy2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0, ZSTD_dedicatedDictSearch); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict); } -#endif -#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -1834,48 +891,18 @@ size_t ZSTD_compressBlock_lazy( return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict); } -size_t ZSTD_compressBlock_lazy_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_lazy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_noDict); -} - -size_t ZSTD_compressBlock_lazy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( +size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1, ZSTD_dedicatedDictSearch); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict); } -#endif -#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_lazy2( +size_t ZSTD_compressBlock_btlazy2_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState); } size_t ZSTD_compressBlock_lazy2_dictMatchState( @@ -1885,57 +912,22 @@ size_t ZSTD_compressBlock_lazy2_dictMatchState( return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dedicatedDictSearch); -} - -size_t ZSTD_compressBlock_lazy2_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_noDict); -} - -size_t ZSTD_compressBlock_lazy2_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dictMatchState); -} - -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( +size_t ZSTD_compressBlock_lazy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2, ZSTD_dedicatedDictSearch); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState); } -#endif -#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_btlazy2( +size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict); + return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_btlazy2_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState); -} -#endif -#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_compressBlock_lazy_extDict_generic( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -1946,7 +938,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* ip = istart; const BYTE* anchor = istart; const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = searchMethod == search_rowHash ? iend - 8 - ZSTD_ROW_HASH_CACHE_SIZE : iend - 8; + const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; @@ -1954,21 +946,18 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const dictStart = dictBase + ms->window.lowLimit; const U32 windowLog = ms->cParams.windowLog; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); - U32 offset_1 = rep[0], offset_2 = rep[1]; + typedef size_t (*searchMax_f)( + ZSTD_matchState_t* ms, + const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr); + searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS; - DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic (searchFunc=%u)", (U32)searchMethod); + U32 offset_1 = rep[0], offset_2 = rep[1]; - /* Reset the lazy skipping state */ - ms->lazySkipping = 0; + DEBUGLOG(5, "ZSTD_compressBlock_lazy_extDict_generic"); /* init */ ip += (ip == prefixStart); - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } /* Match Loop */ #if defined(__GNUC__) && defined(__x86_64__) @@ -1979,17 +968,16 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( #endif while (ip < ilimit) { size_t matchLength=0; - size_t offBase = REPCODE1_TO_OFFBASE; + size_t offset=0; const BYTE* start=ip+1; - U32 curr = (U32)(ip-base); + U32 current = (U32)(ip-base); /* check repCode */ - { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog); - const U32 repIndex = (U32)(curr+1 - offset_1); + { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, current+1, windowLog); + const U32 repIndex = (U32)(current+1 - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - & (offset_1 <= curr+1 - windowLow) ) /* note: we are searching at curr+1 */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ if (MEM_read32(ip+1) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; @@ -1998,23 +986,14 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( } } /* first search (depth 0) */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); + { size_t offsetFound = 999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offsetFound); if (ml2 > matchLength) - matchLength = ml2, start = ip, offBase = ofbCandidate; + matchLength = ml2, start = ip, offset=offsetFound; } - if (matchLength < 4) { - size_t const step = ((size_t)(ip-anchor) >> kSearchStrength); - ip += step + 1; /* jump faster over incompressible sections */ - /* Enter the lazy skipping mode once we are skipping more than 8 bytes at a time. - * In this mode we stop inserting every position into our tables, and only insert - * positions that we search, which is one in step positions. - * The exact cutoff is flexible, I've just chosen a number that is reasonably high, - * so we minimize the compression ratio loss in "normal" scenarios. This mode gets - * triggered once we've gone 2KB without finding any matches. - */ - ms->lazySkipping = step > kLazySkippingStep; + if (matchLength < 4) { + ip += ((ip-anchor) >> kSearchStrength) + 1; /* jump faster over incompressible sections */ continue; } @@ -2022,91 +1001,82 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( if (depth>=1) while (ip= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 3); - int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = repLength, offset = 0, start = ip; } } /* search match, depth 1 */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 4); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ } } /* let's find an even better one */ if ((depth==2) && (ip= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_1 <= curr - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; int const gain2 = (int)(repLength * 4); - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 1); + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1); if ((repLength >= 4) && (gain2 > gain1)) - matchLength = repLength, offBase = REPCODE1_TO_OFFBASE, start = ip; + matchLength = repLength, offset = 0, start = ip; } } /* search match, depth 2 */ - { size_t ofbCandidate = 999999999; - size_t const ml2 = ZSTD_searchMax(ms, ip, iend, &ofbCandidate, mls, rowLog, searchMethod, ZSTD_extDict); - int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)ofbCandidate)); /* raw approx */ - int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offBase) + 7); + { size_t offset2=999999999; + size_t const ml2 = searchMax(ms, ip, iend, &offset2); + int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7); if ((ml2 >= 4) && (gain2 > gain1)) { - matchLength = ml2, offBase = ofbCandidate, start = ip; + matchLength = ml2, offset = offset2, start = ip; continue; } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (OFFBASE_IS_OFFSET(offBase)) { - U32 const matchIndex = (U32)((size_t)(start-base) - OFFBASE_TO_OFFSET(offBase)); + if (offset) { + U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE)); const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */ - offset_2 = offset_1; offset_1 = (U32)OFFBASE_TO_OFFSET(offBase); + offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE); } /* store sequence */ _storeSequence: - { size_t const litLength = (size_t)(start - anchor); - ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offBase, matchLength); + { size_t const litLength = start - anchor; + ZSTD_storeSeq(seqStore, litLength, anchor, iend, (U32)offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } - if (ms->lazySkipping) { - /* We've found a match, disable lazy skipping mode, and refill the hash cache. */ - if (searchMethod == search_rowHash) { - ZSTD_row_fillHashCache(ms, base, rowLog, mls, ms->nextToUpdate, ilimit); - } - ms->lazySkipping = 0; - } /* check immediate repcode */ while (ip <= ilimit) { @@ -2115,14 +1085,13 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const U32 repIndex = repCurrent - offset_2; const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow : do not test positions overlapping 2 memory segments */ - & (offset_2 <= repCurrent - windowLow) ) /* equivalent to `curr > repIndex >= windowLow` */ + if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > windowLow)) /* intentional overflow */ if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4; - offBase = offset_2; offset_2 = offset_1; offset_1 = (U32)offBase; /* swap offset history */ - ZSTD_storeSeq(seqStore, 0, anchor, iend, REPCODE1_TO_OFFBASE, matchLength); + offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */ + ZSTD_storeSeq(seqStore, 0, anchor, iend, 0, matchLength-MINMATCH); ip += matchLength; anchor = ip; continue; /* faster when present ... (?) */ @@ -2137,9 +1106,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( /* Return the last literals size */ return (size_t)(iend - anchor); } -#endif /* build exclusions */ -#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR + size_t ZSTD_compressBlock_greedy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -2147,15 +1115,6 @@ size_t ZSTD_compressBlock_greedy_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0); } -size_t ZSTD_compressBlock_greedy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 0); -} -#endif - -#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -2164,16 +1123,6 @@ size_t ZSTD_compressBlock_lazy_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1); } -size_t ZSTD_compressBlock_lazy_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) - -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 1); -} -#endif - -#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -2182,15 +1131,6 @@ size_t ZSTD_compressBlock_lazy2_extDict( return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2); } -size_t ZSTD_compressBlock_lazy2_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize) -{ - return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_rowHash, 2); -} -#endif - -#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) @@ -2198,6 +1138,5 @@ size_t ZSTD_compressBlock_btlazy2_extDict( { return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2); } -#endif -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp b/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp index a83bf7415..ee2480bfb 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_ldm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,130 +11,16 @@ #include "zstd/compress/zstd_ldm.h" #include "zstd/common/debug.h" -#include "zstd/common/xxhash.hpp" -#include "zstd/common/xxhash_static.hpp" #include "zstd/compress/zstd_fast.h" /* ZSTD_fillHashTable() */ #include "zstd/compress/zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ -#include "zstd/compress/zstd_ldm_geartab.h" #define LDM_BUCKET_SIZE_LOG 3 #define LDM_MIN_MATCH_LENGTH 64 #define LDM_HASH_RLOG 7 +#define LDM_HASH_CHAR_OFFSET 10 namespace duckdb_zstd { -typedef struct { - U64 rolling; - U64 stopMask; -} ldmRollingHashState_t; - -/** ZSTD_ldm_gear_init(): - * - * Initializes the rolling hash state such that it will honor the - * settings in params. */ -static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params) -{ - unsigned maxBitsInMask = MIN(params->minMatchLength, 64); - unsigned hashRateLog = params->hashRateLog; - - state->rolling = ~(U32)0; - - /* The choice of the splitting criterion is subject to two conditions: - * 1. it has to trigger on average every 2^(hashRateLog) bytes; - * 2. ideally, it has to depend on a window of minMatchLength bytes. - * - * In the gear hash algorithm, bit n depends on the last n bytes; - * so in order to obtain a good quality splitting criterion it is - * preferable to use bits with high weight. - * - * To match condition 1 we use a mask with hashRateLog bits set - * and, because of the previous remark, we make sure these bits - * have the highest possible weight while still respecting - * condition 2. - */ - if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) { - state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog); - } else { - /* In this degenerate case we simply honor the hash rate. */ - state->stopMask = ((U64)1 << hashRateLog) - 1; - } -} - -/** ZSTD_ldm_gear_reset() - * Feeds [data, data + minMatchLength) into the hash without registering any - * splits. This effectively resets the hash state. This is used when skipping - * over data, either at the beginning of a block, or skipping sections. - */ -static void ZSTD_ldm_gear_reset(ldmRollingHashState_t* state, - BYTE const* data, size_t minMatchLength) -{ - U64 hash = state->rolling; - size_t n = 0; - -#define GEAR_ITER_ONCE() do { \ - hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ - n += 1; \ - } while (0) - while (n + 3 < minMatchLength) { - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - } - while (n < minMatchLength) { - GEAR_ITER_ONCE(); - } -#undef GEAR_ITER_ONCE -} - -/** ZSTD_ldm_gear_feed(): - * - * Registers in the splits array all the split points found in the first - * size bytes following the data pointer. This function terminates when - * either all the data has been processed or LDM_BATCH_SIZE splits are - * present in the splits array. - * - * Precondition: The splits array must not be full. - * Returns: The number of bytes processed. */ -static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state, - BYTE const* data, size_t size, - size_t* splits, unsigned* numSplits) -{ - size_t n; - U64 hash, mask; - - hash = state->rolling; - mask = state->stopMask; - n = 0; - -#define GEAR_ITER_ONCE() do { \ - hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \ - n += 1; \ - if (UNLIKELY((hash & mask) == 0)) { \ - splits[*numSplits] = n; \ - *numSplits += 1; \ - if (*numSplits == LDM_BATCH_SIZE) \ - goto done; \ - } \ - } while (0) - - while (n + 3 < size) { - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - GEAR_ITER_ONCE(); - } - while (n < size) { - GEAR_ITER_ONCE(); - } - -#undef GEAR_ITER_ONCE - -done: - state->rolling = hash; - return n; -} - void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams) { @@ -143,6 +29,13 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH; + if (cParams->strategy >= ZSTD_btopt) { + /* Get out of the way of the optimal parser */ + U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength); + assert(minMatch >= ZSTD_LDM_MINMATCH_MIN); + assert(minMatch <= ZSTD_LDM_MINMATCH_MAX); + params->minMatchLength = minMatch; + } if (params->hashLog == 0) { params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG); assert(params->hashLog <= ZSTD_HASHLOG_MAX); @@ -162,12 +55,47 @@ size_t ZSTD_ldm_getTableSize(ldmParams_t params) size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog); size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize) + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t)); - return params.enableLdm == ZSTD_ps_enable ? totalSize : 0; + return params.enableLdm ? totalSize : 0; } size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize) { - return params.enableLdm == ZSTD_ps_enable ? (maxChunkSize / params.minMatchLength) : 0; + return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0; +} + +/** ZSTD_ldm_getSmallHash() : + * numBits should be <= 32 + * If numBits==0, returns 0. + * @return : the most significant numBits of value. */ +static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) +{ + assert(numBits <= 32); + return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); +} + +/** ZSTD_ldm_getChecksum() : + * numBitsToDiscard should be <= 32 + * @return : the next most significant 32 bits after numBitsToDiscard */ +static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) +{ + assert(numBitsToDiscard <= 32); + return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; +} + +/** ZSTD_ldm_getTag() ; + * Given the hash, returns the most significant numTagBits bits + * after (32 + hbits) bits. + * + * If there are not enough bits remaining, return the last + * numTagBits bits. */ +static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) +{ + assert(numTagBits < 32 && hbits <= 32); + if (32 - hbits < numTagBits) { + return hash & (((U32)1 << numTagBits) - 1); + } else { + return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); + } } /** ZSTD_ldm_getBucket() : @@ -184,12 +112,38 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, size_t const hash, const ldmEntry_t entry, ldmParams_t const ldmParams) { - BYTE* const pOffset = ldmState->bucketOffsets + hash; - unsigned const offset = *pOffset; - - *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry; - *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1)); + BYTE* const bucketOffsets = ldmState->bucketOffsets; + *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; + bucketOffsets[hash]++; + bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; +} +/** ZSTD_ldm_makeEntryAndInsertByTag() : + * + * Gets the small hash, checksum, and tag from the rollingHash. + * + * If the tag matches (1 << ldmParams.hashRateLog)-1, then + * creates an ldmEntry from the offset, and inserts it into the hash table. + * + * hBits is the length of the small hash, which is the most significant hBits + * of rollingHash. The checksum is the next 32 most significant bits, followed + * by ldmParams.hashRateLog bits that make up the tag. */ +static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, + U64 const rollingHash, + U32 const hBits, + U32 const offset, + ldmParams_t const ldmParams) +{ + U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog); + U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1; + if (tag == tagMask) { + U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + ldmEntry_t entry; + entry.offset = offset; + entry.checksum = checksum; + ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); + } } /** ZSTD_ldm_countBackwardsMatch() : @@ -198,10 +152,10 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ static size_t ZSTD_ldm_countBackwardsMatch( const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pMatchBase) + const BYTE* pMatch, const BYTE* pBase) { size_t matchLength = 0; - while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) { + while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { pIn--; pMatch--; matchLength++; @@ -209,27 +163,6 @@ static size_t ZSTD_ldm_countBackwardsMatch( return matchLength; } -/** ZSTD_ldm_countBackwardsMatch_2segments() : - * Returns the number of bytes that match backwards from pMatch, - * even with the backwards match spanning 2 different segments. - * - * On reaching `pMatchBase`, start counting from mEnd */ -static size_t ZSTD_ldm_countBackwardsMatch_2segments( - const BYTE* pIn, const BYTE* pAnchor, - const BYTE* pMatch, const BYTE* pMatchBase, - const BYTE* pExtDictStart, const BYTE* pExtDictEnd) -{ - size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase); - if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) { - /* If backwards match is entirely in the extDict or prefix, immediately return */ - return matchLength; - } - DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength); - matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart); - DEBUGLOG(7, "final backwards match length = %zu", matchLength); - return matchLength; -} - /** ZSTD_ldm_fillFastTables() : * * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. @@ -245,15 +178,11 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, switch(ms->cParams.strategy) { case ZSTD_fast: - ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); + ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast); break; case ZSTD_dfast: -#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); -#else - assert(0); /* shouldn't be called: cparams should've been adjusted. */ -#endif + ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast); break; case ZSTD_greedy: @@ -271,42 +200,43 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms, return 0; } +/** ZSTD_ldm_fillLdmHashTable() : + * + * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). + * lastHash is the rolling hash that corresponds to lastHashed. + * + * Returns the rolling hash corresponding to position iend-1. */ +static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, + U64 lastHash, const BYTE* lastHashed, + const BYTE* iend, const BYTE* base, + U32 hBits, ldmParams_t const ldmParams) +{ + U64 rollingHash = lastHash; + const BYTE* cur = lastHashed + 1; + + while (cur < iend) { + rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1], + cur[ldmParams.minMatchLength-1], + state->hashPower); + ZSTD_ldm_makeEntryAndInsertByTag(state, + rollingHash, hBits, + (U32)(cur - base), ldmParams); + ++cur; + } + return rollingHash; +} + void ZSTD_ldm_fillHashTable( - ldmState_t* ldmState, const BYTE* ip, + ldmState_t* state, const BYTE* ip, const BYTE* iend, ldmParams_t const* params) { - U32 const minMatchLength = params->minMatchLength; - U32 const hBits = params->hashLog - params->bucketSizeLog; - BYTE const* const base = ldmState->window.base; - BYTE const* const istart = ip; - ldmRollingHashState_t hashState; - size_t* const splits = ldmState->splitIndices; - unsigned numSplits; - DEBUGLOG(5, "ZSTD_ldm_fillHashTable"); - - ZSTD_ldm_gear_init(&hashState, params); - while (ip < iend) { - size_t hashed; - unsigned n; - - numSplits = 0; - hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits); - - for (n = 0; n < numSplits; n++) { - if (ip + splits[n] >= istart + minMatchLength) { - BYTE const* const split = ip + splits[n] - minMatchLength; - U64 const xxhash = XXH64(split, minMatchLength, 0); - U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); - ldmEntry_t entry; - - entry.offset = (U32)(split - base); - entry.checksum = (U32)(xxhash >> 32); - ZSTD_ldm_insertEntry(ldmState, hash, entry, *params); - } - } - - ip += hashed; + if ((size_t)(iend - ip) >= params->minMatchLength) { + U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength); + ZSTD_ldm_fillLdmHashTable( + state, startingHash, ip, iend - params->minMatchLength, state->window.base, + params->hashLog - params->bucketSizeLog, + *params); } } @@ -318,24 +248,25 @@ void ZSTD_ldm_fillHashTable( * (after a long match, only update tables a limited amount). */ static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor) { - U32 const curr = (U32)(anchor - ms->window.base); - if (curr > ms->nextToUpdate + 1024) { + U32 const current = (U32)(anchor - ms->window.base); + if (current > ms->nextToUpdate + 1024) { ms->nextToUpdate = - curr - MIN(512, curr - ms->nextToUpdate - 1024); + current - MIN(512, current - ms->nextToUpdate - 1024); } } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_ldm_generateSequences_internal( +static size_t ZSTD_ldm_generateSequences_internal( ldmState_t* ldmState, rawSeqStore_t* rawSeqStore, ldmParams_t const* params, void const* src, size_t srcSize) { /* LDM parameters */ int const extDict = ZSTD_window_hasExtDict(ldmState->window); U32 const minMatchLength = params->minMatchLength; - U32 const entsPerBucket = 1U << params->bucketSizeLog; + U64 const hashPower = ldmState->hashPower; U32 const hBits = params->hashLog - params->bucketSizeLog; + U32 const ldmBucketSize = 1U << params->bucketSizeLog; + U32 const hashRateLog = params->hashRateLog; + U32 const ldmTagMask = (1U << params->hashRateLog) - 1; /* Prefix and extDict parameters */ U32 const dictLimit = ldmState->window.dictLimit; U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit; @@ -347,69 +278,45 @@ size_t ZSTD_ldm_generateSequences_internal( /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; - BYTE const* const ilimit = iend - HASH_READ_SIZE; + BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE); /* Input positions */ BYTE const* anchor = istart; BYTE const* ip = istart; - /* Rolling hash state */ - ldmRollingHashState_t hashState; - /* Arrays for staged-processing */ - size_t* const splits = ldmState->splitIndices; - ldmMatchCandidate_t* const candidates = ldmState->matchCandidates; - unsigned numSplits; - - if (srcSize < minMatchLength) - return iend - anchor; - - /* Initialize the rolling hash state with the first minMatchLength bytes */ - ZSTD_ldm_gear_init(&hashState, params); - ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength); - ip += minMatchLength; - - while (ip < ilimit) { - size_t hashed; - unsigned n; - - numSplits = 0; - hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip, - splits, &numSplits); - - for (n = 0; n < numSplits; n++) { - BYTE const* const split = ip + splits[n] - minMatchLength; - U64 const xxhash = XXH64(split, minMatchLength, 0); - U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1)); - - candidates[n].split = split; - candidates[n].hash = hash; - candidates[n].checksum = (U32)(xxhash >> 32); - candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params); - PREFETCH_L1(candidates[n].bucket); + /* Rolling hash */ + BYTE const* lastHashed = NULL; + U64 rollingHash = 0; + + while (ip <= ilimit) { + size_t mLength; + U32 const current = (U32)(ip - base); + size_t forwardMatchLength = 0, backwardMatchLength = 0; + ldmEntry_t* bestEntry = NULL; + if (ip != istart) { + rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0], + lastHashed[minMatchLength], + hashPower); + } else { + rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength); } + lastHashed = ip; - for (n = 0; n < numSplits; n++) { - size_t forwardMatchLength = 0, backwardMatchLength = 0, - bestMatchLength = 0, mLength; - U32 offset; - BYTE const* const split = candidates[n].split; - U32 const checksum = candidates[n].checksum; - U32 const hash = candidates[n].hash; - ldmEntry_t* const bucket = candidates[n].bucket; - ldmEntry_t const* cur; - ldmEntry_t const* bestEntry = NULL; - ldmEntry_t newEntry; - - newEntry.offset = (U32)(split - base); - newEntry.checksum = checksum; - - /* If a split point would generate a sequence overlapping with - * the previous one, we merely register it in the hash table and - * move on */ - if (split < anchor) { - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - continue; - } + /* Do not insert and do not look for a match */ + if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) { + ip++; + continue; + } - for (cur = bucket; cur < bucket + entsPerBucket; cur++) { + /* Get the best entry and compute the match lengths */ + { + ldmEntry_t* const bucket = + ZSTD_ldm_getBucket(ldmState, + ZSTD_ldm_getSmallHash(rollingHash, hBits), + *params); + ldmEntry_t* cur; + size_t bestMatchLength = 0; + U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); + + for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { size_t curForwardMatchLength, curBackwardMatchLength, curTotalMatchLength; if (cur->checksum != checksum || cur->offset <= lowestIndex) { @@ -423,23 +330,30 @@ size_t ZSTD_ldm_generateSequences_internal( cur->offset < dictLimit ? dictEnd : iend; BYTE const* const lowMatchPtr = cur->offset < dictLimit ? dictStart : lowPrefixPtr; - curForwardMatchLength = - ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr); + + curForwardMatchLength = ZSTD_count_2segments( + ip, pMatch, iend, + matchEnd, lowPrefixPtr); if (curForwardMatchLength < minMatchLength) { continue; } - curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments( - split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd); + curBackwardMatchLength = + ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, + lowMatchPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; } else { /* !extDict */ BYTE const* const pMatch = base + cur->offset; - curForwardMatchLength = ZSTD_count(split, pMatch, iend); + curForwardMatchLength = ZSTD_count(ip, pMatch, iend); if (curForwardMatchLength < minMatchLength) { continue; } curBackwardMatchLength = - ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr); + ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch, + lowPrefixPtr); + curTotalMatchLength = curForwardMatchLength + + curBackwardMatchLength; } - curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength; if (curTotalMatchLength > bestMatchLength) { bestMatchLength = curTotalMatchLength; @@ -448,54 +362,57 @@ size_t ZSTD_ldm_generateSequences_internal( bestEntry = cur; } } + } - /* No match found -- insert an entry into the hash table - * and process the next candidate match */ - if (bestEntry == NULL) { - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); - continue; - } - - /* Match found */ - offset = (U32)(split - base) - bestEntry->offset; - mLength = forwardMatchLength + backwardMatchLength; - { - rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; - - /* Out of sequence storage */ - if (rawSeqStore->size == rawSeqStore->capacity) - return ERROR(dstSize_tooSmall); - seq->litLength = (U32)(split - backwardMatchLength - anchor); - seq->matchLength = (U32)mLength; - seq->offset = offset; - rawSeqStore->size++; - } - - /* Insert the current entry into the hash table --- it must be - * done after the previous block to avoid clobbering bestEntry */ - ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params); + /* No match found -- continue searching */ + if (bestEntry == NULL) { + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, + hBits, current, + *params); + ip++; + continue; + } - anchor = split + forwardMatchLength; + /* Match found */ + mLength = forwardMatchLength + backwardMatchLength; + ip -= backwardMatchLength; - /* If we find a match that ends after the data that we've hashed - * then we have a repeating, overlapping, pattern. E.g. all zeros. - * If one repetition of the pattern matches our `stopMask` then all - * repetitions will. We don't need to insert them all into out table, - * only the first one. So skip over overlapping matches. - * This is a major speed boost (20x) for compressing a single byte - * repeated, when that byte ends up in the table. + { + /* Store the sequence: + * ip = current - backwardMatchLength + * The match is at (bestEntry->offset - backwardMatchLength) */ - if (anchor > ip + hashed) { - ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength); - /* Continue the outer loop at anchor (ip + hashed == anchor). */ - ip = anchor - hashed; - break; - } + U32 const matchIndex = bestEntry->offset; + U32 const offset = current - matchIndex; + rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size; + + /* Out of sequence storage */ + if (rawSeqStore->size == rawSeqStore->capacity) + return ERROR(dstSize_tooSmall); + seq->litLength = (U32)(ip - anchor); + seq->matchLength = (U32)mLength; + seq->offset = offset; + rawSeqStore->size++; } - ip += hashed; - } + /* Insert the current entry into the hash table */ + ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, + (U32)(lastHashed - base), + *params); + assert(ip + backwardMatchLength == lastHashed); + + /* Fill the hash table from lastHashed+1 to ip+mLength*/ + /* Heuristic: don't need to fill the entire table at end of block */ + if (ip + mLength <= ilimit) { + rollingHash = ZSTD_ldm_fillLdmHashTable( + ldmState, rollingHash, lastHashed, + ip + mLength, base, hBits, *params); + lastHashed = ip + mLength - 1; + } + ip += mLength; + anchor = ip; + } return iend - anchor; } @@ -544,7 +461,7 @@ size_t ZSTD_ldm_generateSequences( assert(chunkStart < iend); /* 1. Perform overflow correction if necessary. */ - if (ZSTD_window_needOverflowCorrection(ldmState->window, 0, maxDist, ldmState->loadedDictEnd, chunkStart, chunkEnd)) { + if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) { U32 const ldmHSize = 1U << params->hashLog; U32 const correction = ZSTD_window_correctOverflow( &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart); @@ -558,7 +475,7 @@ size_t ZSTD_ldm_generateSequences( * the window through early invalidation. * TODO: * Test the chunk size. * * Try invalidation after the sequence generation and test the - * offset against maxDist directly. + * the offset against maxDist directly. * * NOTE: Because of dictionaries + sequence splitting we MUST make sure * that any offset used is valid at the END of the sequence, since it may @@ -588,9 +505,7 @@ size_t ZSTD_ldm_generateSequences( return 0; } -void -ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) -{ +void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) { while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) { rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos; if (srcSize <= seq->litLength) { @@ -649,32 +564,14 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore, return sequence; } -void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) { - U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); - while (currPos && rawSeqStore->pos < rawSeqStore->size) { - rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; - if (currPos >= currSeq.litLength + currSeq.matchLength) { - currPos -= currSeq.litLength + currSeq.matchLength; - rawSeqStore->pos++; - } else { - rawSeqStore->posInSequence = currPos; - break; - } - } - if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { - rawSeqStore->posInSequence = 0; - } -} - size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize) { const ZSTD_compressionParameters* const cParams = &ms->cParams; unsigned const minMatch = cParams->minMatch; ZSTD_blockCompressor const blockCompressor = - ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms)); + ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms)); /* Input bounds */ BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; @@ -682,22 +579,14 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, BYTE const* ip = istart; DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize); - /* If using opt parser, use LDMs only as candidates rather than always accepting them */ - if (cParams->strategy >= ZSTD_btopt) { - size_t lastLLSize; - ms->ldmSeqStore = rawSeqStore; - lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize); - ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize); - return lastLLSize; - } - assert(rawSeqStore->pos <= rawSeqStore->size); assert(rawSeqStore->size <= rawSeqStore->capacity); - /* Loop through each sequence and apply the block compressor to the literals */ + /* Loop through each sequence and apply the block compressor to the lits */ while (rawSeqStore->pos < rawSeqStore->size && ip < iend) { /* maybeSplitSequence updates rawSeqStore->pos */ rawSeq const sequence = maybeSplitSequence(rawSeqStore, (U32)(iend - ip), minMatch); + int i; /* End signal */ if (sequence.offset == 0) break; @@ -710,7 +599,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, /* Run the block compressor */ DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength); { - int i; size_t const newLitLength = blockCompressor(ms, seqStore, rep, ip, sequence.litLength); ip += sequence.litLength; @@ -720,8 +608,8 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, rep[0] = sequence.offset; /* Store the sequence */ ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend, - OFFSET_TO_OFFBASE(sequence.offset), - sequence.matchLength); + sequence.offset + ZSTD_REP_MOVE, + sequence.matchLength - MINMATCH); ip += sequence.matchLength; } } @@ -732,4 +620,4 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, return blockCompressor(ms, seqStore, rep, ip, iend - ip); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstd_opt.cpp b/src/duckdb/third_party/zstd/compress/zstd_opt.cpp index 12cf55793..09e9bff21 100644 --- a/src/duckdb/third_party/zstd/compress/zstd_opt.cpp +++ b/src/duckdb/third_party/zstd/compress/zstd_opt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Przemyslaw Skibinski, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -12,54 +12,44 @@ #include "zstd/compress/hist.h" #include "zstd/compress/zstd_opt.h" -namespace duckdb_zstd { - -#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ +#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */ #define ZSTD_MAX_PRICE (1<<30) -#define ZSTD_PREDEF_THRESHOLD 8 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ +#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ /*-************************************* * Price functions for optimal parser ***************************************/ -#if 0 /* approximation at bit level (for tests) */ +#if 0 /* approximation at bit level */ # define BITCOST_ACCURACY 0 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat, opt) ((void)(opt), ZSTD_bitWeight(stat)) -#elif 0 /* fractional bit accuracy (for tests) */ +# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat)) +#elif 0 /* fractional bit accuracy */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) ((void)(opt), ZSTD_fracWeight(stat)) +# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) #else /* opt==approx, ultra==accurate */ # define BITCOST_ACCURACY 8 # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) -# define WEIGHT(stat,opt) ((opt) ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) +# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) #endif -/* ZSTD_bitWeight() : - * provide estimated "cost" of a stat in full bits only */ +namespace duckdb_zstd { + MEM_STATIC U32 ZSTD_bitWeight(U32 stat) { return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER); } -/* ZSTD_fracWeight() : - * provide fractional-bit "cost" of a stat, - * using linear interpolation approximation */ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) { U32 const stat = rawStat + 1; U32 const hb = ZSTD_highbit32(stat); U32 const BWeight = hb * BITCOST_MULTIPLIER; - /* Fweight was meant for "Fractional weight" - * but it's effectively a value between 1 and 2 - * using fixed point arithmetic */ U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb; U32 const weight = BWeight + FWeight; assert(hb + BITCOST_ACCURACY < 31); @@ -70,7 +60,7 @@ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) /* debugging function, * @return price in bytes as fractional value * for debug messages only */ -MEM_STATIC double ZSTD_fCost(int price) +MEM_STATIC double ZSTD_fCost(U32 price) { return (double)price / (BITCOST_MULTIPLIER*8); } @@ -78,7 +68,7 @@ MEM_STATIC double ZSTD_fCost(int price) static int ZSTD_compressedLiterals(optState_t const* const optPtr) { - return optPtr->literalCompressionMode != ZSTD_ps_disable; + return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed; } static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) @@ -91,52 +81,25 @@ static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel) } -static U32 sum_u32(const unsigned table[], size_t nbElts) -{ - size_t n; - U32 total = 0; - for (n=0; n 0 && ZSTD_FREQ_DIV+malus < 31); for (s=0; s0); - unsigned const newStat = base + (table[s] >> shift); - sum += newStat; - table[s] = newStat; + table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus)); + sum += table[s]; } return sum; } -/* ZSTD_scaleStats() : - * reduce all elt frequencies in table if sum too large - * return the resulting sum of elements */ -static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) -{ - U32 const prevsum = sum_u32(table, lastEltIndex+1); - U32 const factor = prevsum >> logTarget; - DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget); - assert(logTarget < 30); - if (factor <= 1) return prevsum; - return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor), base_1guaranteed); -} - /* ZSTD_rescaleFreqs() : * if first block (detected by optPtr->litLengthSum == 0) : init statistics * take hints from dictionary if there is one - * and init from zero if there is none, - * using src for literals stats, and baseline stats for sequence symbols + * or init from zero, using src for literals stats, or flat 1 for match symbols * otherwise downscale existing stats, to be used as seed for next block. */ static void @@ -148,28 +111,24 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize); optPtr->priceType = zop_dynamic; - if (optPtr->litLengthSum == 0) { /* no literals stats collected -> first block assumed -> init */ - - /* heuristic: use pre-defined stats for too small inputs */ - if (srcSize <= ZSTD_PREDEF_THRESHOLD) { - DEBUGLOG(5, "srcSize <= %i : use predefined stats", ZSTD_PREDEF_THRESHOLD); + if (optPtr->litLengthSum == 0) { /* first block : init */ + if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */ + DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef"); optPtr->priceType = zop_predef; } assert(optPtr->symbolCosts != NULL); if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { - - /* huffman stats covering the full value set : table presumed generated by dictionary */ + /* huffman table presumed generated by dictionary */ optPtr->priceType = zop_dynamic; if (compressedLiterals) { - /* generate literals statistics from huffman table */ unsigned lit; assert(optPtr->litFreq != NULL); optPtr->litSum = 0; for (lit=0; lit<=MaxLit; lit++) { U32 const scaleLog = 11; /* scale to 2K */ - U32 const bitCost = HUF_getNbBitsFromCTable(optPtr->symbolCosts->huf.CTable, lit); + U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit); assert(bitCost <= scaleLog); optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/; optPtr->litSum += optPtr->litFreq[lit]; @@ -211,26 +170,20 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, optPtr->offCodeSum += optPtr->offCodeFreq[of]; } } - } else { /* first block, no dictionary */ + } else { /* not a dictionary */ assert(optPtr->litFreq != NULL); if (compressedLiterals) { - /* base initial cost of literals on direct frequency within src */ unsigned lit = MaxLit; HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ - optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8, base_0possible); + optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); } - { unsigned const baseLLfreqs[MaxLL+1] = { - 4, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1 - }; - ZSTD_memcpy(optPtr->litLengthFreq, baseLLfreqs, sizeof(baseLLfreqs)); - optPtr->litLengthSum = sum_u32(baseLLfreqs, MaxLL+1); + { unsigned ll; + for (ll=0; ll<=MaxLL; ll++) + optPtr->litLengthFreq[ll] = 1; } + optPtr->litLengthSum = MaxLL+1; { unsigned ml; for (ml=0; ml<=MaxML; ml++) @@ -238,25 +191,21 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, } optPtr->matchLengthSum = MaxML+1; - { unsigned const baseOFCfreqs[MaxOff+1] = { - 6, 2, 1, 1, 2, 3, 4, 4, - 4, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 - }; - ZSTD_memcpy(optPtr->offCodeFreq, baseOFCfreqs, sizeof(baseOFCfreqs)); - optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1); + { unsigned of; + for (of=0; of<=MaxOff; of++) + optPtr->offCodeFreq[of] = 1; } + optPtr->offCodeSum = MaxOff+1; } - } else { /* new block : scale down accumulated statistics */ + } else { /* new block : re-use previous statistics, scaled down */ if (compressedLiterals) - optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12); - optPtr->litLengthSum = ZSTD_scaleStats(optPtr->litLengthFreq, MaxLL, 11); - optPtr->matchLengthSum = ZSTD_scaleStats(optPtr->matchLengthFreq, MaxML, 11); - optPtr->offCodeSum = ZSTD_scaleStats(optPtr->offCodeFreq, MaxOff, 11); + optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1); + optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0); + optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0); + optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0); } ZSTD_setBasePrices(optPtr, optLevel); @@ -269,7 +218,6 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, const optState_t* const optPtr, int optLevel) { - DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength); if (litLength == 0) return 0; if (!ZSTD_compressedLiterals(optPtr)) @@ -279,14 +227,11 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */ /* dynamic statistics */ - { U32 price = optPtr->litSumBasePrice * litLength; - U32 const litPriceMax = optPtr->litSumBasePrice - BITCOST_MULTIPLIER; + { U32 price = litLength * optPtr->litSumBasePrice; U32 u; - assert(optPtr->litSumBasePrice >= BITCOST_MULTIPLIER); for (u=0; u < litLength; u++) { - U32 litPrice = WEIGHT(optPtr->litFreq[literals[u]], optLevel); - if (UNLIKELY(litPrice > litPriceMax)) litPrice = litPriceMax; - price -= litPrice; + assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */ + price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel); } return price; } @@ -296,46 +241,33 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength, * cost of literalLength symbol */ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel) { - assert(litLength <= ZSTD_BLOCKSIZE_MAX); - if (optPtr->priceType == zop_predef) - return WEIGHT(litLength, optLevel); - - /* ZSTD_LLcode() can't compute litLength price for sizes >= ZSTD_BLOCKSIZE_MAX - * because it isn't representable in the zstd format. - * So instead just pretend it would cost 1 bit more than ZSTD_BLOCKSIZE_MAX - 1. - * In such a case, the block would be all literals. - */ - if (litLength == ZSTD_BLOCKSIZE_MAX) - return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel); + if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel); /* dynamic statistics */ { U32 const llCode = ZSTD_LLcode(litLength); - return (LL_bits[llCode] * BITCOST_MULTIPLIER) + return (ZSTDInternalConstants::LL_bits[llCode] * BITCOST_MULTIPLIER) + optPtr->litLengthSumBasePrice - WEIGHT(optPtr->litLengthFreq[llCode], optLevel); } } /* ZSTD_getMatchPrice() : - * Provides the cost of the match part (offset + matchLength) of a sequence. + * Provides the cost of the match part (offset + matchLength) of a sequence * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. - * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq() - * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) - */ + * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */ FORCE_INLINE_TEMPLATE U32 -ZSTD_getMatchPrice(U32 const offBase, +ZSTD_getMatchPrice(U32 const offset, U32 const matchLength, const optState_t* const optPtr, int const optLevel) { U32 price; - U32 const offCode = ZSTD_highbit32(offBase); + U32 const offCode = ZSTD_highbit32(offset+1); U32 const mlBase = matchLength - MINMATCH; assert(matchLength >= MINMATCH); - if (optPtr->priceType == zop_predef) /* fixed scheme, does not use statistics */ - return WEIGHT(mlBase, optLevel) - + ((16 + offCode) * BITCOST_MULTIPLIER); /* emulated offset cost */ + if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */ + return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER); /* dynamic statistics */ price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel)); @@ -344,7 +276,7 @@ ZSTD_getMatchPrice(U32 const offBase, /* match Length */ { U32 const mlCode = ZSTD_MLcode(mlBase); - price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel)); + price += (ZSTDInternalConstants::ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel)); } price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */ @@ -354,10 +286,10 @@ ZSTD_getMatchPrice(U32 const offBase, } /* ZSTD_updateStats() : - * assumption : literals + litLength <= iend */ + * assumption : literals + litLengtn <= iend */ static void ZSTD_updateStats(optState_t* const optPtr, U32 litLength, const BYTE* literals, - U32 offBase, U32 matchLength) + U32 offsetCode, U32 matchLength) { /* literals */ if (ZSTD_compressedLiterals(optPtr)) { @@ -373,8 +305,8 @@ static void ZSTD_updateStats(optState_t* const optPtr, optPtr->litLengthSum++; } - /* offset code : follows storeSeq() numeric representation */ - { U32 const offCode = ZSTD_highbit32(offBase); + /* match offset code (0-2=>repCode; 3+=>offset+2) */ + { U32 const offCode = ZSTD_highbit32(offsetCode+1); assert(offCode <= MaxOff); optPtr->offCodeFreq[offCode]++; optPtr->offCodeSum++; @@ -408,11 +340,9 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length) /* Update hashTable3 up to ip (excluded) Assumption : always within prefix (i.e. not within extDict) */ -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip) +static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip) { U32* const hashTable3 = ms->hashTable3; U32 const hashLog3 = ms->hashLog3; @@ -436,15 +366,11 @@ U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_matchState_t* ms, * Binary Tree search ***************************************/ /** ZSTD_insertBt1() : add one or multiple positions to tree. - * @param ip assumed <= iend-8 . - * @param target The target of ZSTD_updateTree_internal() - we are filling to this position + * ip : assumed <= iend-8 . * @return : nb of positions added */ -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_insertBt1( - const ZSTD_matchState_t* ms, +static U32 ZSTD_insertBt1( + ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, - U32 const target, U32 const mls, const int extDict) { const ZSTD_compressionParameters* const cParams = &ms->cParams; @@ -462,36 +388,32 @@ U32 ZSTD_insertBt1( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* match; - const U32 curr = (U32)(ip-base); - const U32 btLow = btMask >= curr ? 0 : curr - btMask; - U32* smallerPtr = bt + 2*(curr&btMask); + const U32 current = (U32)(ip-base); + const U32 btLow = btMask >= current ? 0 : current - btMask; + U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = smallerPtr + 1; U32 dummy32; /* to be nullified at the end */ - /* windowLow is based on target because - * we only need positions that will be in the window at the end of the tree update. - */ - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog); - U32 matchEndIdx = curr+8+1; + U32 const windowLow = ms->window.lowLimit; + U32 matchEndIdx = current+8+1; size_t bestLength = 8; U32 nbCompares = 1U << cParams->searchLog; #ifdef ZSTD_C_PREDICT - U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0); - U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1); + U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); + U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); predictedSmall += (predictedSmall>0); predictedLarge += (predictedLarge>0); #endif /* ZSTD_C_PREDICT */ - DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr); + DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current); - assert(curr <= target); assert(ip <= iend-8); /* required for h calculation */ - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ assert(windowLow > 0); - for (; nbCompares && (matchIndex >= windowLow); --nbCompares) { + while (nbCompares-- && (matchIndex >= windowLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(matchIndex < curr); + assert(matchIndex < current); #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ @@ -554,13 +476,12 @@ U32 ZSTD_insertBt1( *smallerPtr = *largerPtr = 0; { U32 positions = 0; if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384)); /* speed optimization */ - assert(matchEndIdx > curr + 8); - return MAX(positions, matchEndIdx - (curr + 8)); + assert(matchEndIdx > current + 8); + return MAX(positions, matchEndIdx - (current + 8)); } } FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR void ZSTD_updateTree_internal( ZSTD_matchState_t* ms, const BYTE* const ip, const BYTE* const iend, @@ -569,11 +490,11 @@ void ZSTD_updateTree_internal( const BYTE* const base = ms->window.base; U32 const target = (U32)(ip - base); U32 idx = ms->nextToUpdate; - DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", + DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)", idx, target, dictMode); while(idx < target) { - U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, target, mls, dictMode == ZSTD_extDict); + U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict); assert(idx < (U32)(idx + forward)); idx += forward; } @@ -587,23 +508,20 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { } FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 -ZSTD_insertBtAndGetAllMatches ( - ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip, const BYTE* const iLimit, - const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - const U32 ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ - const U32 lengthToBeat, - const U32 mls /* template */) +U32 ZSTD_insertBtAndGetAllMatches ( + ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ + const U32 lengthToBeat, + U32 const mls /* template */) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); const BYTE* const base = ms->window.base; - U32 const curr = (U32)(ip-base); + U32 const current = (U32)(ip-base); U32 const hashLog = cParams->hashLog; U32 const minMatch = (mls==3) ? 3 : 4; U32* const hashTable = ms->hashTable; @@ -617,12 +535,12 @@ ZSTD_insertBtAndGetAllMatches ( U32 const dictLimit = ms->window.dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const btLow = (btMask >= current) ? 0 : current - btMask; + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog); U32 const matchLow = windowLow ? windowLow : 1; - U32* smallerPtr = bt + 2*(curr&btMask); - U32* largerPtr = bt + 2*(curr&btMask) + 1; - U32 matchEndIdx = curr+8+1; /* farthest referenced position of any match => detects repetitive patterns */ + U32* smallerPtr = bt + 2*(current&btMask); + U32* largerPtr = bt + 2*(current&btMask) + 1; + U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */ U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; U32 nbCompares = 1U << cParams->searchLog; @@ -641,7 +559,7 @@ ZSTD_insertBtAndGetAllMatches ( U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit; size_t bestLength = lengthToBeat-1; - DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr); + DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current); /* check repCode */ assert(ll0 <= 1); /* necessarily 1 or 0 */ @@ -649,29 +567,29 @@ ZSTD_insertBtAndGetAllMatches ( U32 repCode; for (repCode = ll0; repCode < lastR; repCode++) { U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - U32 const repIndex = curr - repOffset; + U32 const repIndex = current - repOffset; U32 repLen = 0; - assert(curr >= dictLimit); - if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) { /* equivalent to `curr > repIndex >= dictLimit` */ + assert(current >= dictLimit); + if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) { /* equivalent to `current > repIndex >= dictLimit` */ /* We must validate the repcode offset because when we're using a dictionary the * valid offset range shrinks when the dictionary goes out of bounds. */ if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) { repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch; } - } else { /* repIndex < dictLimit || repIndex >= curr */ + } else { /* repIndex < dictLimit || repIndex >= current */ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ? dmsBase + repIndex - dmsIndexDelta : dictBase + repIndex; - assert(curr >= windowLow); + assert(current >= windowLow); if ( dictMode == ZSTD_extDict - && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow) /* equivalent to `curr > repIndex >= windowLow` */ + && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */ & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */) && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch; } if (dictMode == ZSTD_dictMatchState - && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `curr > repIndex >= dmsLowLimit` */ + && ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */ & ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */ && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) { repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch; @@ -681,7 +599,7 @@ ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u", repCode, ll0, repOffset, repLen); bestLength = repLen; - matches[mnum].off = REPCODE_TO_OFFBASE(repCode - ll0 + 1); /* expect value between 1 and 3 */ + matches[mnum].off = repCode - ll0; matches[mnum].len = (U32)repLen; mnum++; if ( (repLen > sufficient_len) @@ -693,7 +611,7 @@ ZSTD_insertBtAndGetAllMatches ( if ((mls == 3) /*static*/ && (bestLength < mls)) { U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip); if ((matchIndex3 >= matchLow) - & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { + & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) { size_t mlen; if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) { const BYTE* const match = base + matchIndex3; @@ -708,26 +626,26 @@ ZSTD_insertBtAndGetAllMatches ( DEBUGLOG(8, "found small match with hlog3, of length %u", (U32)mlen); bestLength = mlen; - assert(curr > matchIndex3); + assert(current > matchIndex3); assert(mnum==0); /* no prior solution */ - matches[0].off = OFFSET_TO_OFFBASE(curr - matchIndex3); + matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE; matches[0].len = (U32)mlen; mnum = 1; if ( (mlen > sufficient_len) | (ip+mlen == iLimit) ) { /* best possible length */ - ms->nextToUpdate = curr+1; /* skip insertion */ + ms->nextToUpdate = current+1; /* skip insertion */ return 1; } } } /* no dictMatchState lookup: dicts don't have a populated HC3 table */ - } /* if (mls == 3) */ + } - hashTable[h] = curr; /* Update Hash Table */ + hashTable[h] = current; /* Update Hash Table */ - for (; nbCompares && (matchIndex >= matchLow); --nbCompares) { + while (nbCompares-- && (matchIndex >= matchLow)) { U32* const nextPtr = bt + 2*(matchIndex & btMask); const BYTE* match; size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - assert(curr > matchIndex); + assert(current > matchIndex); if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) { assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */ @@ -743,20 +661,21 @@ ZSTD_insertBtAndGetAllMatches ( } if (matchLength > bestLength) { - DEBUGLOG(8, "found match of length %u at distance %u (offBase=%u)", - (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); + DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)", + (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); assert(matchEndIdx > matchIndex); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); + matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */ break; /* drop, to preserve bt consistency (miss a little bit of compression) */ - } } + } + } if (match[matchLength] < ip[matchLength]) { /* match smaller than current */ @@ -775,13 +694,12 @@ ZSTD_insertBtAndGetAllMatches ( *smallerPtr = *largerPtr = 0; - assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */ if (dictMode == ZSTD_dictMatchState && nbCompares) { size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls); U32 dictMatchIndex = dms->hashTable[dmsH]; const U32* const dmsBt = dms->chainTable; commonLengthSmaller = commonLengthLarger = 0; - for (; nbCompares && (dictMatchIndex > dmsLowLimit); --nbCompares) { + while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) { const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ const BYTE* match = dmsBase + dictMatchIndex; @@ -791,18 +709,19 @@ ZSTD_insertBtAndGetAllMatches ( if (matchLength > bestLength) { matchIndex = dictMatchIndex + dmsIndexDelta; - DEBUGLOG(8, "found dms match of length %u at distance %u (offBase=%u)", - (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex)); + DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)", + (U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE); if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; bestLength = matchLength; - matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex); + matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE; matches[mnum].len = (U32)matchLength; mnum++; if ( (matchLength > ZSTD_OPT_NUM) | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) { break; /* drop, to guarantee consistency (miss a little bit of compression) */ - } } + } + } if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */ if (match[matchLength] < ip[matchLength]) { @@ -812,244 +731,52 @@ ZSTD_insertBtAndGetAllMatches ( /* match is larger than current */ commonLengthLarger = matchLength; dictMatchIndex = nextPtr[0]; - } } } /* if (dictMode == ZSTD_dictMatchState) */ + } + } + } - assert(matchEndIdx > curr+8); + assert(matchEndIdx > current+8); ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */ return mnum; } -typedef U32 (*ZSTD_getAllMatchesFn)( - ZSTD_match_t*, - ZSTD_matchState_t*, - U32*, - const BYTE*, - const BYTE*, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat); -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_btGetAllMatches_internal( - ZSTD_match_t* matches, - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* ip, - const BYTE* const iHighLimit, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, - U32 const lengthToBeat, - const ZSTD_dictMode_e dictMode, - const U32 mls) +FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches ( + ZSTD_match_t* matches, /* store result (match found, increasing size) in this table */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + U32 const ll0, + U32 const lengthToBeat) { - assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls); - DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls); - if (ip < ms->window.base + ms->nextToUpdate) - return 0; /* skipped area */ - ZSTD_updateTree_internal(ms, ip, iHighLimit, mls, dictMode); - return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, mls); -} - -#define ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls) ZSTD_btGetAllMatches_##dictMode##_##mls - -#define GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, mls) \ - static U32 ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls)( \ - ZSTD_match_t* matches, \ - ZSTD_matchState_t* ms, \ - U32* nextToUpdate3, \ - const BYTE* ip, \ - const BYTE* const iHighLimit, \ - const U32 rep[ZSTD_REP_NUM], \ - U32 const ll0, \ - U32 const lengthToBeat) \ - { \ - return ZSTD_btGetAllMatches_internal( \ - matches, ms, nextToUpdate3, ip, iHighLimit, \ - rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \ - } - -#define GEN_ZSTD_BT_GET_ALL_MATCHES(dictMode) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 3) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 4) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 5) \ - GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 6) - -GEN_ZSTD_BT_GET_ALL_MATCHES(noDict) -GEN_ZSTD_BT_GET_ALL_MATCHES(extDict) -GEN_ZSTD_BT_GET_ALL_MATCHES(dictMatchState) - -#define ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMode) \ - { \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 3), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 4), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 5), \ - ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 6) \ - } - -static ZSTD_getAllMatchesFn -ZSTD_selectBtGetAllMatches(ZSTD_matchState_t const* ms, ZSTD_dictMode_e const dictMode) -{ - ZSTD_getAllMatchesFn const getAllMatchesFns[3][4] = { - ZSTD_BT_GET_ALL_MATCHES_ARRAY(noDict), - ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict), - ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState) - }; - U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6); - assert((U32)dictMode < 3); - assert(mls - 3 < 4); - return getAllMatchesFns[(int)dictMode][mls - 3]; -} - -/************************* -* LDM helper functions * -*************************/ - -/* Struct containing info needed to make decision about ldm inclusion */ -typedef struct { - rawSeqStore_t seqStore; /* External match candidates store for this block */ - U32 startPosInBlock; /* Start position of the current match candidate */ - U32 endPosInBlock; /* End position of the current match candidate */ - U32 offset; /* Offset of the match candidate */ -} ZSTD_optLdm_t; - -/* ZSTD_optLdm_skipRawSeqStoreBytes(): - * Moves forward in @rawSeqStore by @nbBytes, - * which will update the fields 'pos' and 'posInSequence'. - */ -static void ZSTD_optLdm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) -{ - U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes); - while (currPos && rawSeqStore->pos < rawSeqStore->size) { - rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos]; - if (currPos >= currSeq.litLength + currSeq.matchLength) { - currPos -= currSeq.litLength + currSeq.matchLength; - rawSeqStore->pos++; - } else { - rawSeqStore->posInSequence = currPos; - break; - } - } - if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) { - rawSeqStore->posInSequence = 0; + const ZSTD_compressionParameters* const cParams = &ms->cParams; + U32 const matchLengthSearch = cParams->minMatch; + DEBUGLOG(8, "ZSTD_BtGetAllMatches"); + if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ + ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode); + switch(matchLengthSearch) + { + case 3 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 3); + default : + case 4 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 4); + case 5 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 5); + case 7 : + case 6 : return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, 6); } } -/* ZSTD_opt_getNextMatchAndUpdateSeqStore(): - * Calculates the beginning and end of the next match in the current block. - * Updates 'pos' and 'posInSequence' of the ldmSeqStore. - */ -static void -ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock, - U32 blockBytesRemaining) -{ - rawSeq currSeq; - U32 currBlockEndPos; - U32 literalsBytesRemaining; - U32 matchBytesRemaining; - - /* Setting match end position to MAX to ensure we never use an LDM during this block */ - if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { - optLdm->startPosInBlock = UINT_MAX; - optLdm->endPosInBlock = UINT_MAX; - return; - } - /* Calculate appropriate bytes left in matchLength and litLength - * after adjusting based on ldmSeqStore->posInSequence */ - currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos]; - assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength); - currBlockEndPos = currPosInBlock + blockBytesRemaining; - literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ? - currSeq.litLength - (U32)optLdm->seqStore.posInSequence : - 0; - matchBytesRemaining = (literalsBytesRemaining == 0) ? - currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) : - currSeq.matchLength; - - /* If there are more literal bytes than bytes remaining in block, no ldm is possible */ - if (literalsBytesRemaining >= blockBytesRemaining) { - optLdm->startPosInBlock = UINT_MAX; - optLdm->endPosInBlock = UINT_MAX; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining); - return; - } - - /* Matches may be < MINMATCH by this process. In that case, we will reject them - when we are deciding whether or not to add the ldm */ - optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining; - optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining; - optLdm->offset = currSeq.offset; - - if (optLdm->endPosInBlock > currBlockEndPos) { - /* Match ends after the block ends, we can't use the whole match */ - optLdm->endPosInBlock = currBlockEndPos; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock); - } else { - /* Consume nb of bytes equal to size of sequence left */ - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining); - } -} -/* ZSTD_optLdm_maybeAddMatch(): - * Adds a match if it's long enough, - * based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock', - * into 'matches'. Maintains the correct ordering of 'matches'. - */ -static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches, - const ZSTD_optLdm_t* optLdm, U32 currPosInBlock) -{ - U32 const posDiff = currPosInBlock - optLdm->startPosInBlock; - /* Note: ZSTD_match_t actually contains offBase and matchLength (before subtracting MINMATCH) */ - U32 const candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff; - - /* Ensure that current block position is not outside of the match */ - if (currPosInBlock < optLdm->startPosInBlock - || currPosInBlock >= optLdm->endPosInBlock - || candidateMatchLength < MINMATCH) { - return; - } +/*-******************************* +* Optimal parser +*********************************/ - if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) { - U32 const candidateOffBase = OFFSET_TO_OFFBASE(optLdm->offset); - DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offBase: %u matchLength %u) at block position=%u", - candidateOffBase, candidateMatchLength, currPosInBlock); - matches[*nbMatches].len = candidateMatchLength; - matches[*nbMatches].off = candidateOffBase; - (*nbMatches)++; - } -} -/* ZSTD_optLdm_processMatchCandidate(): - * Wrapper function to update ldm seq store and call ldm functions as necessary. - */ -static void -ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm, - ZSTD_match_t* matches, U32* nbMatches, - U32 currPosInBlock, U32 remainingBytes) +static U32 ZSTD_totalLen(ZSTD_optimal_t sol) { - if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) { - return; - } - - if (currPosInBlock >= optLdm->endPosInBlock) { - if (currPosInBlock > optLdm->endPosInBlock) { - /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily - * at the end of a match from the ldm seq store, and will often be some bytes - * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots" - */ - U32 const posOvershoot = currPosInBlock - optLdm->endPosInBlock; - ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot); - } - ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes); - } - ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock); + return sol.litlen + sol.mlen; } - -/*-******************************* -* Optimal parser -*********************************/ - #if 0 /* debug */ static void @@ -1067,13 +794,7 @@ listStats(const U32* table, int lastEltID) #endif -#define LIT_PRICE(_p) (int)ZSTD_rawLiteralsCost(_p, 1, optStatePtr, optLevel) -#define LL_PRICE(_l) (int)ZSTD_litLengthPrice(_l, optStatePtr, optLevel) -#define LL_INCPRICE(_l) (LL_PRICE(_l) - LL_PRICE(_l-1)) - -FORCE_INLINE_TEMPLATE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t +FORCE_INLINE_TEMPLATE size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], @@ -1091,22 +812,13 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, const BYTE* const prefixStart = base + ms->window.dictLimit; const ZSTD_compressionParameters* const cParams = &ms->cParams; - ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode); - U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4; U32 nextToUpdate3 = ms->nextToUpdate; ZSTD_optimal_t* const opt = optStatePtr->priceTable; ZSTD_match_t* const matches = optStatePtr->matchTable; - ZSTD_optimal_t lastStretch; - ZSTD_optLdm_t optLdm; - - ZSTD_memset(&lastStretch, 0, sizeof(ZSTD_optimal_t)); - - optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore; - optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0; - ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip)); + ZSTD_optimal_t lastSequence; /* init */ DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u", @@ -1122,141 +834,102 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* find first match */ { U32 const litlen = (U32)(ip - anchor); U32 const ll0 = !litlen; - U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch); - ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, - (U32)(ip-istart), (U32)(iend-ip)); - if (!nbMatches) { - DEBUGLOG(8, "no match found at cPos %u", (unsigned)(ip-istart)); - ip++; - continue; - } - - /* Match found: let's store this solution, and eventually find more candidates. - * During this forward pass, @opt is used to store stretches, - * defined as "a match followed by N literals". - * Note how this is different from a Sequence, which is "N literals followed by a match". - * Storing stretches allows us to store different match predecessors - * for each literal position part of a literals run. */ + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, ip, iend, dictMode, rep, ll0, minMatch); + if (!nbMatches) { ip++; continue; } /* initialize opt[0] */ - opt[0].mlen = 0; /* there are only literals so far */ + { U32 i ; for (i=0; i immediate encoding */ { U32 const maxML = matches[nbMatches-1].len; - U32 const maxOffBase = matches[nbMatches-1].off; - DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffBase=%u at cPos=%u => start new series", - nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart)); + U32 const maxOffset = matches[nbMatches-1].off; + DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series", + nbMatches, maxML, maxOffset, (U32)(ip-prefixStart)); if (maxML > sufficient_len) { - lastStretch.litlen = 0; - lastStretch.mlen = maxML; - lastStretch.off = maxOffBase; - DEBUGLOG(6, "large match (%u>%u) => immediate encoding", + lastSequence.litlen = litlen; + lastSequence.mlen = maxML; + lastSequence.off = maxOffset; + DEBUGLOG(6, "large match (%u>%u), immediate encoding", maxML, sufficient_len); cur = 0; - last_pos = maxML; + last_pos = ZSTD_totalLen(lastSequence); goto _shortestPath; } } /* set prices for first matches starting position == 0 */ - assert(opt[0].price >= 0); - { U32 pos; + { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel); + U32 pos; U32 matchNb; for (pos = 1; pos < minMatch; pos++) { - opt[pos].price = ZSTD_MAX_PRICE; - opt[pos].mlen = 0; - opt[pos].litlen = litlen + pos; + opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */ } for (matchNb = 0; matchNb < nbMatches; matchNb++) { - U32 const offBase = matches[matchNb].off; + U32 const offset = matches[matchNb].off; U32 const end = matches[matchNb].len; for ( ; pos <= end ; pos++ ) { - int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); - int const sequencePrice = opt[0].price + matchPrice; + U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel); + U32 const sequencePrice = literalsPrice + matchPrice; DEBUGLOG(7, "rPos:%u => set initial price : %.2f", pos, ZSTD_fCost(sequencePrice)); opt[pos].mlen = pos; - opt[pos].off = offBase; - opt[pos].litlen = 0; /* end of match */ - opt[pos].price = sequencePrice + LL_PRICE(0); - } - } + opt[pos].off = offset; + opt[pos].litlen = litlen; + opt[pos].price = sequencePrice; + } } last_pos = pos-1; - opt[pos].price = ZSTD_MAX_PRICE; } } /* check further positions */ for (cur = 1; cur <= last_pos; cur++) { const BYTE* const inr = ip + cur; - assert(cur <= ZSTD_OPT_NUM); - DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur); + assert(cur < ZSTD_OPT_NUM); + DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur) /* Fix current position with one literal if cheaper */ - { U32 const litlen = opt[cur-1].litlen + 1; + { U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1; int const price = opt[cur-1].price - + LIT_PRICE(ip+cur-1) - + LL_INCPRICE(litlen); + + ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel) + + ZSTD_litLengthPrice(litlen, optStatePtr, optLevel) + - ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel); assert(price < 1000000000); /* overflow check */ if (price <= opt[cur].price) { - ZSTD_optimal_t const prevMatch = opt[cur]; DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)", inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen, opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]); - opt[cur] = opt[cur-1]; + opt[cur].mlen = 0; + opt[cur].off = 0; opt[cur].litlen = litlen; opt[cur].price = price; - if ( (optLevel >= 1) /* additional check only for higher modes */ - && (prevMatch.litlen == 0) /* replace a match */ - && (LL_INCPRICE(1) < 0) /* ll1 is cheaper than ll0 */ - && LIKELY(ip + cur < iend) - ) { - /* check next position, in case it would be cheaper */ - int with1literal = prevMatch.price + LIT_PRICE(ip+cur) + LL_INCPRICE(1); - int withMoreLiterals = price + LIT_PRICE(ip+cur) + LL_INCPRICE(litlen+1); - DEBUGLOG(7, "then at next rPos %u : match+1lit %.2f vs %ulits %.2f", - cur+1, ZSTD_fCost(with1literal), litlen+1, ZSTD_fCost(withMoreLiterals)); - if ( (with1literal < withMoreLiterals) - && (with1literal < opt[cur+1].price) ) { - /* update offset history - before it disappears */ - U32 const prev = cur - prevMatch.mlen; - repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, prevMatch.off, opt[prev].litlen==0); - assert(cur >= prevMatch.mlen); - DEBUGLOG(7, "==> match+1lit is cheaper (%.2f < %.2f) (hist:%u,%u,%u) !", - ZSTD_fCost(with1literal), ZSTD_fCost(withMoreLiterals), - newReps.rep[0], newReps.rep[1], newReps.rep[2] ); - opt[cur+1] = prevMatch; /* mlen & offbase */ - ZSTD_memcpy(opt[cur+1].rep, &newReps, sizeof(repcodes_t)); - opt[cur+1].litlen = 1; - opt[cur+1].price = with1literal; - if (last_pos < cur+1) last_pos = cur+1; - } - } } else { - DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f)", - inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price)); + DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)", + inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), + opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]); } } - /* Offset history is not updated during match comparison. - * Do it here, now that the match is selected and confirmed. + /* Set the repcodes of the current position. We must do it here + * because we rely on the repcodes of the 2nd to last sequence being + * correct to set the next chunks repcodes during the backward + * traversal. */ ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t)); assert(cur >= opt[cur].mlen); - if (opt[cur].litlen == 0) { - /* just finished a match => alter offset history */ + if (opt[cur].mlen != 0) { U32 const prev = cur - opt[cur].mlen; - repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[prev].litlen==0); - ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); + repcodes_t newReps = ZSTD_updateRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0); + memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t)); + } else { + memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t)); } /* last match must start at a minimum distance of 8 from oend */ @@ -1266,36 +939,33 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, if ( (optLevel==0) /*static_test*/ && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) { - DEBUGLOG(7, "skip current position : next rPos(%u) price is cheaper", cur+1); + DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1); continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */ } - assert(opt[cur].price >= 0); - { U32 const ll0 = (opt[cur].litlen == 0); - int const previousPrice = opt[cur].price; - int const basePrice = previousPrice + LL_PRICE(0); - U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch); + { U32 const ll0 = (opt[cur].mlen != 0); + U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0; + U32 const previousPrice = opt[cur].price; + U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel); + U32 const nbMatches = ZSTD_BtGetAllMatches(matches, ms, &nextToUpdate3, inr, iend, dictMode, opt[cur].rep, ll0, minMatch); U32 matchNb; - - ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches, - (U32)(inr-istart), (U32)(iend-inr)); - if (!nbMatches) { DEBUGLOG(7, "rPos:%u : no match found", cur); continue; } - { U32 const longestML = matches[nbMatches-1].len; - DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of longest ML=%u", - inr-istart, cur, nbMatches, longestML); - - if ( (longestML > sufficient_len) - || (cur + longestML >= ZSTD_OPT_NUM) - || (ip + cur + longestML >= iend) ) { - lastStretch.mlen = longestML; - lastStretch.off = matches[nbMatches-1].off; - lastStretch.litlen = 0; - last_pos = cur + longestML; + { U32 const maxML = matches[nbMatches-1].len; + DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u", + inr-istart, cur, nbMatches, maxML); + + if ( (maxML > sufficient_len) + || (cur + maxML >= ZSTD_OPT_NUM) ) { + lastSequence.mlen = maxML; + lastSequence.off = matches[nbMatches-1].off; + lastSequence.litlen = litlen; + cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */ + last_pos = cur + ZSTD_totalLen(lastSequence); + if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */ goto _shortestPath; } } @@ -1306,25 +976,20 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch; U32 mlen; - DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u", - matchNb, matches[matchNb].off, lastML, opt[cur].litlen); + DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u", + matchNb, matches[matchNb].off, lastML, litlen); for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */ U32 const pos = cur + mlen; - int const price = basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); + int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel); if ((pos > last_pos) || (price < opt[pos].price)) { DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)", pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price)); - while (last_pos < pos) { - /* fill empty positions, for future comparisons */ - last_pos++; - opt[last_pos].price = ZSTD_MAX_PRICE; - opt[last_pos].litlen = !0; /* just needs to be != 0, to mean "not an end of match" */ - } + while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */ opt[pos].mlen = mlen; opt[pos].off = offset; - opt[pos].litlen = 0; + opt[pos].litlen = litlen; opt[pos].price = price; } else { DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)", @@ -1332,86 +997,52 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */ } } } } - opt[last_pos+1].price = ZSTD_MAX_PRICE; } /* for (cur = 1; cur <= last_pos; cur++) */ - lastStretch = opt[last_pos]; - assert(cur >= lastStretch.mlen); - cur = last_pos - lastStretch.mlen; + lastSequence = opt[last_pos]; + cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */ + assert(cur < ZSTD_OPT_NUM); /* control overflow*/ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */ assert(opt[0].mlen == 0); - assert(last_pos >= lastStretch.mlen); - assert(cur == last_pos - lastStretch.mlen); - if (lastStretch.mlen==0) { - /* no solution : all matches have been converted into literals */ - assert(lastStretch.litlen == (ip - anchor) + last_pos); - ip += last_pos; - continue; - } - assert(lastStretch.off > 0); - - /* Update offset history */ - if (lastStretch.litlen == 0) { - /* finishing on a match : update offset history */ - repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastStretch.off, opt[cur].litlen==0); - ZSTD_memcpy(rep, &reps, sizeof(repcodes_t)); + /* Set the next chunk's repcodes based on the repcodes of the beginning + * of the last match, and the last sequence. This avoids us having to + * update them while traversing the sequences. + */ + if (lastSequence.mlen != 0) { + repcodes_t reps = ZSTD_updateRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0); + memcpy(rep, &reps, sizeof(reps)); } else { - ZSTD_memcpy(rep, lastStretch.rep, sizeof(repcodes_t)); - assert(cur >= lastStretch.litlen); - cur -= lastStretch.litlen; + memcpy(rep, opt[cur].rep, sizeof(repcodes_t)); } - /* Let's write the shortest path solution. - * It is stored in @opt in reverse order, - * starting from @storeEnd (==cur+2), - * effectively partially @opt overwriting. - * Content is changed too: - * - So far, @opt stored stretches, aka a match followed by literals - * - Now, it will store sequences, aka literals followed by a match - */ - { U32 const storeEnd = cur + 2; + { U32 const storeEnd = cur + 1; U32 storeStart = storeEnd; - U32 stretchPos = cur; + U32 seqPos = cur; DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)", last_pos, cur); (void)last_pos; - assert(storeEnd < ZSTD_OPT_SIZE); - DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", - storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off); - if (lastStretch.litlen > 0) { - /* last "sequence" is unfinished: just a bunch of literals */ - opt[storeEnd].litlen = lastStretch.litlen; - opt[storeEnd].mlen = 0; - storeStart = storeEnd-1; - opt[storeStart] = lastStretch; - } { - opt[storeEnd] = lastStretch; /* note: litlen will be fixed */ - storeStart = storeEnd; - } - while (1) { - ZSTD_optimal_t nextStretch = opt[stretchPos]; - opt[storeStart].litlen = nextStretch.litlen; - DEBUGLOG(6, "selected sequence (llen=%u,mlen=%u,ofc=%u)", - opt[storeStart].litlen, opt[storeStart].mlen, opt[storeStart].off); - if (nextStretch.mlen == 0) { - /* reaching beginning of segment */ - break; - } + assert(storeEnd < ZSTD_OPT_NUM); + DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", + storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off); + opt[storeEnd] = lastSequence; + while (seqPos > 0) { + U32 const backDist = ZSTD_totalLen(opt[seqPos]); storeStart--; - opt[storeStart] = nextStretch; /* note: litlen will be fixed */ - assert(nextStretch.litlen + nextStretch.mlen <= stretchPos); - stretchPos -= nextStretch.litlen + nextStretch.mlen; + DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)", + seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off); + opt[storeStart] = opt[seqPos]; + seqPos = (seqPos > backDist) ? seqPos - backDist : 0; } /* save sequences */ - DEBUGLOG(6, "sending selected sequences into seqStore"); + DEBUGLOG(6, "sending selected sequences into seqStore") { U32 storePos; for (storePos=storeStart; storePos <= storeEnd; storePos++) { U32 const llen = opt[storePos].litlen; U32 const mlen = opt[storePos].mlen; - U32 const offBase = opt[storePos].off; + U32 const offCode = opt[storePos].off; U32 const advance = llen + mlen; DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u", anchor - istart, (unsigned)llen, (unsigned)mlen); @@ -1423,14 +1054,11 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, } assert(anchor + llen <= iend); - ZSTD_updateStats(optStatePtr, llen, anchor, offBase, mlen); - ZSTD_storeSeq(seqStore, llen, anchor, iend, offBase, mlen); + ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen); + ZSTD_storeSeq(seqStore, llen, anchor, iend, offCode, mlen-MINMATCH); anchor += advance; ip = anchor; } } - DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]); - - /* update all costs */ ZSTD_setBasePrices(optStatePtr, optLevel); } } /* while (ip < ilimit) */ @@ -1438,54 +1066,53 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, /* Return the last literals size */ return (size_t)(iend - anchor); } -#endif /* build exclusions */ - -#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR -static size_t ZSTD_compressBlock_opt0( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) -{ - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode); -} -#endif -#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR -static size_t ZSTD_compressBlock_opt2( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode) -{ - return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode); -} -#endif -#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btopt"); - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict); } -#endif +/* used in 2-pass strategy */ +static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus) +{ + U32 s, sum=0; + assert(ZSTD_FREQ_DIV+bonus >= 0); + for (s=0; slitSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0); + optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0); + optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0); + optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0); +} -#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR /* ZSTD_initStats_ultra(): * make a first compression pass, just to seed stats with more accurate starting values. * only works on first block, with no dictionary and no ldm. - * this function cannot error out, its narrow contract must be respected. + * this function cannot error, hence its contract must be respected. */ -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_initStats_ultra(ZSTD_matchState_t* ms, - seqStore_t* seqStore, - U32 rep[ZSTD_REP_NUM], - const void* src, size_t srcSize) +static void +ZSTD_initStats_ultra(ZSTD_matchState_t* ms, + seqStore_t* seqStore, + U32 rep[ZSTD_REP_NUM], + const void* src, size_t srcSize) { U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */ - ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep)); + memcpy(tmpRep, rep, sizeof(tmpRep)); DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize); assert(ms->opt.litLengthSum == 0); /* first block */ @@ -1493,15 +1120,17 @@ void ZSTD_initStats_ultra(ZSTD_matchState_t* ms, assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */ assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */ - ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/ + ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/ - /* invalidate first scan from history, only keep entropy stats */ + /* invalidate first scan from history */ ZSTD_resetSeqStore(seqStore); ms->window.base -= srcSize; ms->window.dictLimit += (U32)srcSize; ms->window.lowLimit = ms->window.dictLimit; ms->nextToUpdate = ms->window.dictLimit; + /* re-inforce weight of collected statistics */ + ZSTD_upscaleStats(&ms->opt); } size_t ZSTD_compressBlock_btultra( @@ -1509,20 +1138,20 @@ size_t ZSTD_compressBlock_btultra( const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize); - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); } size_t ZSTD_compressBlock_btultra2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - U32 const curr = (U32)((const BYTE*)src - ms->window.base); + U32 const current = (U32)((const BYTE*)src - ms->window.base); DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize); - /* 2-passes strategy: + /* 2-pass strategy: * this strategy makes a first pass over first block to collect statistics - * in order to seed next round's statistics with it. - * After 1st pass, function forgets history, and starts a new block. + * and seed next round's statistics with it. + * After 1st pass, function forgets everything, and starts a new block. * Consequently, this can only work if no data has been previously loaded in tables, * aka, no dictionary, no prefix, no ldm preprocessing. * The compression ratio gain is generally small (~0.5% on first block), @@ -1531,50 +1160,45 @@ size_t ZSTD_compressBlock_btultra2( if ( (ms->opt.litLengthSum==0) /* first block */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */ - && (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ - && (srcSize > ZSTD_PREDEF_THRESHOLD) /* input large enough to not employ default stats */ + && (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ + && (srcSize > ZSTD_PREDEF_THRESHOLD) ) { ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize); } - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); } -#endif -#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState); } -size_t ZSTD_compressBlock_btopt_extDict( +size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState); } -#endif -#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_btultra_dictMatchState( +size_t ZSTD_compressBlock_btopt_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict); } size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], const void* src, size_t srcSize) { - return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict); + return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict); } -#endif /* note : no btultra2 variant for extDict nor dictMatchState, * because btultra2 is not meant to work with dictionaries * and is only specific for the first block (no prefix) */ -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp b/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp deleted file mode 100644 index f0522c8ff..000000000 --- a/src/duckdb/third_party/zstd/compress/zstdmt_compress.cpp +++ /dev/null @@ -1,1885 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - -/* ====== Compiler specifics ====== */ -#if defined(_MSC_VER) -# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ -#endif - - -/* ====== Dependencies ====== */ -#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset, INT_MAX, UINT_MAX */ -#include "zstd/common/mem.h" /* MEM_STATIC */ -#include "zstd/common/pool.h" /* threadpool */ -#include "zstd/common/threading.h" /* mutex */ -#include "zstd/compress/zstd_compress_internal.h" /* MIN, ERROR, ZSTD_*, ZSTD_highbit32 */ -#include "zstd/compress/zstd_ldm.h" -#include "zstd/compress/zstdmt_compress.h" - -/* Guards code to support resizing the SeqPool. - * We will want to resize the SeqPool to save memory in the future. - * Until then, comment the code out since it is unused. - */ -#define ZSTD_RESIZE_SEQPOOL 0 - -/* ====== Debug ====== */ -#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=2) \ - && !defined(_MSC_VER) \ - && !defined(__MINGW32__) - -# include -# include -# include - -# define DEBUG_PRINTHEX(l,p,n) \ - do { \ - unsigned debug_u; \ - for (debug_u=0; debug_u<(n); debug_u++) \ - RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \ - RAWLOG(l, " \n"); \ - } while (0) - -static unsigned long long GetCurrentClockTimeMicroseconds(void) -{ - static clock_t _ticksPerSecond = 0; - if (_ticksPerSecond <= 0) _ticksPerSecond = sysconf(_SC_CLK_TCK); - - { struct tms junk; clock_t newTicks = (clock_t) times(&junk); - return ((((unsigned long long)newTicks)*(1000000))/_ticksPerSecond); -} } - -#define MUTEX_WAIT_TIME_DLEVEL 6 -#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) \ - do { \ - if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \ - unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \ - ZSTD_pthread_mutex_lock(mutex); \ - { unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \ - unsigned long long const elapsedTime = (afterTime-beforeTime); \ - if (elapsedTime > 1000) { \ - /* or whatever threshold you like; I'm using 1 millisecond here */ \ - DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, \ - "Thread took %llu microseconds to acquire mutex %s \n", \ - elapsedTime, #mutex); \ - } } \ - } else { \ - ZSTD_pthread_mutex_lock(mutex); \ - } \ - } while (0) - -#else - -# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m) -# define DEBUG_PRINTHEX(l,p,n) do { } while (0) - -#endif - -namespace duckdb_zstd { - -/* ===== Buffer Pool ===== */ -/* a single Buffer Pool can be invoked from multiple threads in parallel */ - -typedef struct buffer_s { - void* start; - size_t capacity; -} buffer_t; - -static const buffer_t g_nullBuffer = { NULL, 0 }; - -typedef struct ZSTDMT_bufferPool_s { - ZSTD_pthread_mutex_t poolMutex; - size_t bufferSize; - unsigned totalBuffers; - unsigned nbBuffers; - ZSTD_customMem cMem; - buffer_t* buffers; -} ZSTDMT_bufferPool; - -static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool) -{ - DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool); - if (!bufPool) return; /* compatibility with free on NULL */ - if (bufPool->buffers) { - unsigned u; - for (u=0; utotalBuffers; u++) { - DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start); - ZSTD_customFree(bufPool->buffers[u].start, bufPool->cMem); - } - ZSTD_customFree(bufPool->buffers, bufPool->cMem); - } - ZSTD_pthread_mutex_destroy(&bufPool->poolMutex); - ZSTD_customFree(bufPool, bufPool->cMem); -} - -static ZSTDMT_bufferPool* ZSTDMT_createBufferPool(unsigned maxNbBuffers, ZSTD_customMem cMem) -{ - ZSTDMT_bufferPool* const bufPool = - (ZSTDMT_bufferPool*)ZSTD_customCalloc(sizeof(ZSTDMT_bufferPool), cMem); - if (bufPool==NULL) return NULL; - if (ZSTD_pthread_mutex_init(&bufPool->poolMutex, NULL)) { - ZSTD_customFree(bufPool, cMem); - return NULL; - } - bufPool->buffers = (buffer_t*)ZSTD_customCalloc(maxNbBuffers * sizeof(buffer_t), cMem); - if (bufPool->buffers==NULL) { - ZSTDMT_freeBufferPool(bufPool); - return NULL; - } - bufPool->bufferSize = 64 KB; - bufPool->totalBuffers = maxNbBuffers; - bufPool->nbBuffers = 0; - bufPool->cMem = cMem; - return bufPool; -} - -/* only works at initialization, not during compression */ -static size_t ZSTDMT_sizeof_bufferPool(ZSTDMT_bufferPool* bufPool) -{ - size_t const poolSize = sizeof(*bufPool); - size_t const arraySize = bufPool->totalBuffers * sizeof(buffer_t); - unsigned u; - size_t totalBufferSize = 0; - ZSTD_pthread_mutex_lock(&bufPool->poolMutex); - for (u=0; utotalBuffers; u++) - totalBufferSize += bufPool->buffers[u].capacity; - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); - - return poolSize + arraySize + totalBufferSize; -} - -/* ZSTDMT_setBufferSize() : - * all future buffers provided by this buffer pool will have _at least_ this size - * note : it's better for all buffers to have same size, - * as they become freely interchangeable, reducing malloc/free usages and memory fragmentation */ -static void ZSTDMT_setBufferSize(ZSTDMT_bufferPool* const bufPool, size_t const bSize) -{ - ZSTD_pthread_mutex_lock(&bufPool->poolMutex); - DEBUGLOG(4, "ZSTDMT_setBufferSize: bSize = %u", (U32)bSize); - bufPool->bufferSize = bSize; - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); -} - - -static ZSTDMT_bufferPool* ZSTDMT_expandBufferPool(ZSTDMT_bufferPool* srcBufPool, unsigned maxNbBuffers) -{ - if (srcBufPool==NULL) return NULL; - if (srcBufPool->totalBuffers >= maxNbBuffers) /* good enough */ - return srcBufPool; - /* need a larger buffer pool */ - { ZSTD_customMem const cMem = srcBufPool->cMem; - size_t const bSize = srcBufPool->bufferSize; /* forward parameters */ - ZSTDMT_bufferPool* newBufPool; - ZSTDMT_freeBufferPool(srcBufPool); - newBufPool = ZSTDMT_createBufferPool(maxNbBuffers, cMem); - if (newBufPool==NULL) return newBufPool; - ZSTDMT_setBufferSize(newBufPool, bSize); - return newBufPool; - } -} - -/** ZSTDMT_getBuffer() : - * assumption : bufPool must be valid - * @return : a buffer, with start pointer and size - * note: allocation may fail, in this case, start==NULL and size==0 */ -static buffer_t ZSTDMT_getBuffer(ZSTDMT_bufferPool* bufPool) -{ - size_t const bSize = bufPool->bufferSize; - DEBUGLOG(5, "ZSTDMT_getBuffer: bSize = %u", (U32)bufPool->bufferSize); - ZSTD_pthread_mutex_lock(&bufPool->poolMutex); - if (bufPool->nbBuffers) { /* try to use an existing buffer */ - buffer_t const buf = bufPool->buffers[--(bufPool->nbBuffers)]; - size_t const availBufferSize = buf.capacity; - bufPool->buffers[bufPool->nbBuffers] = g_nullBuffer; - if ((availBufferSize >= bSize) & ((availBufferSize>>3) <= bSize)) { - /* large enough, but not too much */ - DEBUGLOG(5, "ZSTDMT_getBuffer: provide buffer %u of size %u", - bufPool->nbBuffers, (U32)buf.capacity); - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); - return buf; - } - /* size conditions not respected : scratch this buffer, create new one */ - DEBUGLOG(5, "ZSTDMT_getBuffer: existing buffer does not meet size conditions => freeing"); - ZSTD_customFree(buf.start, bufPool->cMem); - } - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); - /* create new buffer */ - DEBUGLOG(5, "ZSTDMT_getBuffer: create a new buffer"); - { buffer_t buffer; - void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); - buffer.start = start; /* note : start can be NULL if malloc fails ! */ - buffer.capacity = (start==NULL) ? 0 : bSize; - if (start==NULL) { - DEBUGLOG(5, "ZSTDMT_getBuffer: buffer allocation failure !!"); - } else { - DEBUGLOG(5, "ZSTDMT_getBuffer: created buffer of size %u", (U32)bSize); - } - return buffer; - } -} - -#if ZSTD_RESIZE_SEQPOOL -/** ZSTDMT_resizeBuffer() : - * assumption : bufPool must be valid - * @return : a buffer that is at least the buffer pool buffer size. - * If a reallocation happens, the data in the input buffer is copied. - */ -static buffer_t ZSTDMT_resizeBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buffer) -{ - size_t const bSize = bufPool->bufferSize; - if (buffer.capacity < bSize) { - void* const start = ZSTD_customMalloc(bSize, bufPool->cMem); - buffer_t newBuffer; - newBuffer.start = start; - newBuffer.capacity = start == NULL ? 0 : bSize; - if (start != NULL) { - assert(newBuffer.capacity >= buffer.capacity); - ZSTD_memcpy(newBuffer.start, buffer.start, buffer.capacity); - DEBUGLOG(5, "ZSTDMT_resizeBuffer: created buffer of size %u", (U32)bSize); - return newBuffer; - } - DEBUGLOG(5, "ZSTDMT_resizeBuffer: buffer allocation failure !!"); - } - return buffer; -} -#endif - -/* store buffer for later re-use, up to pool capacity */ -static void ZSTDMT_releaseBuffer(ZSTDMT_bufferPool* bufPool, buffer_t buf) -{ - DEBUGLOG(5, "ZSTDMT_releaseBuffer"); - if (buf.start == NULL) return; /* compatible with release on NULL */ - ZSTD_pthread_mutex_lock(&bufPool->poolMutex); - if (bufPool->nbBuffers < bufPool->totalBuffers) { - bufPool->buffers[bufPool->nbBuffers++] = buf; /* stored for later use */ - DEBUGLOG(5, "ZSTDMT_releaseBuffer: stored buffer of size %u in slot %u", - (U32)buf.capacity, (U32)(bufPool->nbBuffers-1)); - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); - return; - } - ZSTD_pthread_mutex_unlock(&bufPool->poolMutex); - /* Reached bufferPool capacity (note: should not happen) */ - DEBUGLOG(5, "ZSTDMT_releaseBuffer: pool capacity reached => freeing "); - ZSTD_customFree(buf.start, bufPool->cMem); -} - -/* We need 2 output buffers per worker since each dstBuff must be flushed after it is released. - * The 3 additional buffers are as follows: - * 1 buffer for input loading - * 1 buffer for "next input" when submitting current one - * 1 buffer stuck in queue */ -#define BUF_POOL_MAX_NB_BUFFERS(nbWorkers) (2*(nbWorkers) + 3) - -/* After a worker releases its rawSeqStore, it is immediately ready for reuse. - * So we only need one seq buffer per worker. */ -#define SEQ_POOL_MAX_NB_BUFFERS(nbWorkers) (nbWorkers) - -/* ===== Seq Pool Wrapper ====== */ - -typedef ZSTDMT_bufferPool ZSTDMT_seqPool; - -static size_t ZSTDMT_sizeof_seqPool(ZSTDMT_seqPool* seqPool) -{ - return ZSTDMT_sizeof_bufferPool(seqPool); -} - -static rawSeqStore_t bufferToSeq(buffer_t buffer) -{ - rawSeqStore_t seq = kNullRawSeqStore; - seq.seq = (rawSeq*)buffer.start; - seq.capacity = buffer.capacity / sizeof(rawSeq); - return seq; -} - -static buffer_t seqToBuffer(rawSeqStore_t seq) -{ - buffer_t buffer; - buffer.start = seq.seq; - buffer.capacity = seq.capacity * sizeof(rawSeq); - return buffer; -} - -static rawSeqStore_t ZSTDMT_getSeq(ZSTDMT_seqPool* seqPool) -{ - if (seqPool->bufferSize == 0) { - return kNullRawSeqStore; - } - return bufferToSeq(ZSTDMT_getBuffer(seqPool)); -} - -#if ZSTD_RESIZE_SEQPOOL -static rawSeqStore_t ZSTDMT_resizeSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq) -{ - return bufferToSeq(ZSTDMT_resizeBuffer(seqPool, seqToBuffer(seq))); -} -#endif - -static void ZSTDMT_releaseSeq(ZSTDMT_seqPool* seqPool, rawSeqStore_t seq) -{ - ZSTDMT_releaseBuffer(seqPool, seqToBuffer(seq)); -} - -static void ZSTDMT_setNbSeq(ZSTDMT_seqPool* const seqPool, size_t const nbSeq) -{ - ZSTDMT_setBufferSize(seqPool, nbSeq * sizeof(rawSeq)); -} - -static ZSTDMT_seqPool* ZSTDMT_createSeqPool(unsigned nbWorkers, ZSTD_customMem cMem) -{ - ZSTDMT_seqPool* const seqPool = ZSTDMT_createBufferPool(SEQ_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); - if (seqPool == NULL) return NULL; - ZSTDMT_setNbSeq(seqPool, 0); - return seqPool; -} - -static void ZSTDMT_freeSeqPool(ZSTDMT_seqPool* seqPool) -{ - ZSTDMT_freeBufferPool(seqPool); -} - -static ZSTDMT_seqPool* ZSTDMT_expandSeqPool(ZSTDMT_seqPool* pool, U32 nbWorkers) -{ - return ZSTDMT_expandBufferPool(pool, SEQ_POOL_MAX_NB_BUFFERS(nbWorkers)); -} - - -/* ===== CCtx Pool ===== */ -/* a single CCtx Pool can be invoked from multiple threads in parallel */ - -typedef struct { - ZSTD_pthread_mutex_t poolMutex; - int totalCCtx; - int availCCtx; - ZSTD_customMem cMem; - ZSTD_CCtx** cctxs; -} ZSTDMT_CCtxPool; - -/* note : all CCtx borrowed from the pool must be reverted back to the pool _before_ freeing the pool */ -static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool) -{ - if (!pool) return; - ZSTD_pthread_mutex_destroy(&pool->poolMutex); - if (pool->cctxs) { - int cid; - for (cid=0; cidtotalCCtx; cid++) - ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */ - ZSTD_customFree(pool->cctxs, pool->cMem); - } - ZSTD_customFree(pool, pool->cMem); -} - -/* ZSTDMT_createCCtxPool() : - * implies nbWorkers >= 1 , checked by caller ZSTDMT_createCCtx() */ -static ZSTDMT_CCtxPool* ZSTDMT_createCCtxPool(int nbWorkers, - ZSTD_customMem cMem) -{ - ZSTDMT_CCtxPool* const cctxPool = - (ZSTDMT_CCtxPool*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtxPool), cMem); - assert(nbWorkers > 0); - if (!cctxPool) return NULL; - if (ZSTD_pthread_mutex_init(&cctxPool->poolMutex, NULL)) { - ZSTD_customFree(cctxPool, cMem); - return NULL; - } - cctxPool->totalCCtx = nbWorkers; - cctxPool->cctxs = (ZSTD_CCtx**)ZSTD_customCalloc(nbWorkers * sizeof(ZSTD_CCtx*), cMem); - if (!cctxPool->cctxs) { - ZSTDMT_freeCCtxPool(cctxPool); - return NULL; - } - cctxPool->cMem = cMem; - cctxPool->cctxs[0] = ZSTD_createCCtx_advanced(cMem); - if (!cctxPool->cctxs[0]) { ZSTDMT_freeCCtxPool(cctxPool); return NULL; } - cctxPool->availCCtx = 1; /* at least one cctx for single-thread mode */ - DEBUGLOG(3, "cctxPool created, with %u workers", nbWorkers); - return cctxPool; -} - -static ZSTDMT_CCtxPool* ZSTDMT_expandCCtxPool(ZSTDMT_CCtxPool* srcPool, - int nbWorkers) -{ - if (srcPool==NULL) return NULL; - if (nbWorkers <= srcPool->totalCCtx) return srcPool; /* good enough */ - /* need a larger cctx pool */ - { ZSTD_customMem const cMem = srcPool->cMem; - ZSTDMT_freeCCtxPool(srcPool); - return ZSTDMT_createCCtxPool(nbWorkers, cMem); - } -} - -/* only works during initialization phase, not during compression */ -static size_t ZSTDMT_sizeof_CCtxPool(ZSTDMT_CCtxPool* cctxPool) -{ - ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); - { unsigned const nbWorkers = cctxPool->totalCCtx; - size_t const poolSize = sizeof(*cctxPool); - size_t const arraySize = cctxPool->totalCCtx * sizeof(ZSTD_CCtx*); - size_t totalCCtxSize = 0; - unsigned u; - for (u=0; ucctxs[u]); - } - ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); - assert(nbWorkers > 0); - return poolSize + arraySize + totalCCtxSize; - } -} - -static ZSTD_CCtx* ZSTDMT_getCCtx(ZSTDMT_CCtxPool* cctxPool) -{ - DEBUGLOG(5, "ZSTDMT_getCCtx"); - ZSTD_pthread_mutex_lock(&cctxPool->poolMutex); - if (cctxPool->availCCtx) { - cctxPool->availCCtx--; - { ZSTD_CCtx* const cctx = cctxPool->cctxs[cctxPool->availCCtx]; - ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); - return cctx; - } } - ZSTD_pthread_mutex_unlock(&cctxPool->poolMutex); - DEBUGLOG(5, "create one more CCtx"); - return ZSTD_createCCtx_advanced(cctxPool->cMem); /* note : can be NULL, when creation fails ! */ -} - -static void ZSTDMT_releaseCCtx(ZSTDMT_CCtxPool* pool, ZSTD_CCtx* cctx) -{ - if (cctx==NULL) return; /* compatibility with release on NULL */ - ZSTD_pthread_mutex_lock(&pool->poolMutex); - if (pool->availCCtx < pool->totalCCtx) - pool->cctxs[pool->availCCtx++] = cctx; - else { - /* pool overflow : should not happen, since totalCCtx==nbWorkers */ - DEBUGLOG(4, "CCtx pool overflow : free cctx"); - ZSTD_freeCCtx(cctx); - } - ZSTD_pthread_mutex_unlock(&pool->poolMutex); -} - -/* ==== Serial State ==== */ - -typedef struct { - void const* start; - size_t size; -} range_t; - -typedef struct { - /* All variables in the struct are protected by mutex. */ - ZSTD_pthread_mutex_t mutex; - ZSTD_pthread_cond_t cond; - ZSTD_CCtx_params params; - ldmState_t ldmState; - XXH64_state_t xxhState; - unsigned nextJobID; - /* Protects ldmWindow. - * Must be acquired after the main mutex when acquiring both. - */ - ZSTD_pthread_mutex_t ldmWindowMutex; - ZSTD_pthread_cond_t ldmWindowCond; /* Signaled when ldmWindow is updated */ - ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */ -} serialState_t; - -static int -ZSTDMT_serialState_reset(serialState_t* serialState, - ZSTDMT_seqPool* seqPool, - ZSTD_CCtx_params params, - size_t jobSize, - const void* dict, size_t const dictSize, - ZSTD_dictContentType_e dictContentType) -{ - /* Adjust parameters */ - if (params.ldmParams.enableLdm == ZSTD_ps_enable) { - DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10); - ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); - assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); - assert(params.ldmParams.hashRateLog < 32); - } else { - ZSTD_memset(¶ms.ldmParams, 0, sizeof(params.ldmParams)); - } - serialState->nextJobID = 0; - if (params.fParams.checksumFlag) - XXH64_reset(&serialState->xxhState, 0); - if (params.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_customMem cMem = params.customMem; - unsigned const hashLog = params.ldmParams.hashLog; - size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t); - unsigned const bucketLog = - params.ldmParams.hashLog - params.ldmParams.bucketSizeLog; - unsigned const prevBucketLog = - serialState->params.ldmParams.hashLog - - serialState->params.ldmParams.bucketSizeLog; - size_t const numBuckets = (size_t)1 << bucketLog; - /* Size the seq pool tables */ - ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize)); - /* Reset the window */ - ZSTD_window_init(&serialState->ldmState.window); - /* Resize tables and output space if necessary. */ - if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) { - ZSTD_customFree(serialState->ldmState.hashTable, cMem); - serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem); - } - if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) { - ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); - serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem); - } - if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets) - return 1; - /* Zero the tables */ - ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize); - ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets); - - /* Update window state and fill hash table with dict */ - serialState->ldmState.loadedDictEnd = 0; - if (dictSize > 0) { - if (dictContentType == ZSTD_dct_rawContent) { - BYTE const* const dictEnd = (const BYTE*)dict + dictSize; - ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0); - ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, ¶ms.ldmParams); - serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base); - } else { - /* don't even load anything */ - } - } - - /* Initialize serialState's copy of ldmWindow. */ - serialState->ldmWindow = serialState->ldmState.window; - } - - serialState->params = params; - serialState->params.jobSize = (U32)jobSize; - return 0; -} - -static int ZSTDMT_serialState_init(serialState_t* serialState) -{ - int initError = 0; - ZSTD_memset(serialState, 0, sizeof(*serialState)); - initError |= ZSTD_pthread_mutex_init(&serialState->mutex, NULL); - initError |= ZSTD_pthread_cond_init(&serialState->cond, NULL); - initError |= ZSTD_pthread_mutex_init(&serialState->ldmWindowMutex, NULL); - initError |= ZSTD_pthread_cond_init(&serialState->ldmWindowCond, NULL); - return initError; -} - -static void ZSTDMT_serialState_free(serialState_t* serialState) -{ - ZSTD_customMem cMem = serialState->params.customMem; - ZSTD_pthread_mutex_destroy(&serialState->mutex); - ZSTD_pthread_cond_destroy(&serialState->cond); - ZSTD_pthread_mutex_destroy(&serialState->ldmWindowMutex); - ZSTD_pthread_cond_destroy(&serialState->ldmWindowCond); - ZSTD_customFree(serialState->ldmState.hashTable, cMem); - ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem); -} - -static void ZSTDMT_serialState_update(serialState_t* serialState, - ZSTD_CCtx* jobCCtx, rawSeqStore_t seqStore, - range_t src, unsigned jobID) -{ - /* Wait for our turn */ - ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex); - while (serialState->nextJobID < jobID) { - DEBUGLOG(5, "wait for serialState->cond"); - ZSTD_pthread_cond_wait(&serialState->cond, &serialState->mutex); - } - /* A future job may error and skip our job */ - if (serialState->nextJobID == jobID) { - /* It is now our turn, do any processing necessary */ - if (serialState->params.ldmParams.enableLdm == ZSTD_ps_enable) { - size_t error; - assert(seqStore.seq != NULL && seqStore.pos == 0 && - seqStore.size == 0 && seqStore.capacity > 0); - assert(src.size <= serialState->params.jobSize); - ZSTD_window_update(&serialState->ldmState.window, src.start, src.size, /* forceNonContiguous */ 0); - error = ZSTD_ldm_generateSequences( - &serialState->ldmState, &seqStore, - &serialState->params.ldmParams, src.start, src.size); - /* We provide a large enough buffer to never fail. */ - assert(!ZSTD_isError(error)); (void)error; - /* Update ldmWindow to match the ldmState.window and signal the main - * thread if it is waiting for a buffer. - */ - ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex); - serialState->ldmWindow = serialState->ldmState.window; - ZSTD_pthread_cond_signal(&serialState->ldmWindowCond); - ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex); - } - if (serialState->params.fParams.checksumFlag && src.size > 0) - XXH64_update(&serialState->xxhState, src.start, src.size); - } - /* Now it is the next jobs turn */ - serialState->nextJobID++; - ZSTD_pthread_cond_broadcast(&serialState->cond); - ZSTD_pthread_mutex_unlock(&serialState->mutex); - - if (seqStore.size > 0) { - ZSTD_referenceExternalSequences(jobCCtx, seqStore.seq, seqStore.size); - assert(serialState->params.ldmParams.enableLdm == ZSTD_ps_enable); - } -} - -static void ZSTDMT_serialState_ensureFinished(serialState_t* serialState, - unsigned jobID, size_t cSize) -{ - ZSTD_PTHREAD_MUTEX_LOCK(&serialState->mutex); - if (serialState->nextJobID <= jobID) { - assert(ZSTD_isError(cSize)); (void)cSize; - DEBUGLOG(5, "Skipping past job %u because of error", jobID); - serialState->nextJobID = jobID + 1; - ZSTD_pthread_cond_broadcast(&serialState->cond); - - ZSTD_PTHREAD_MUTEX_LOCK(&serialState->ldmWindowMutex); - ZSTD_window_clear(&serialState->ldmWindow); - ZSTD_pthread_cond_signal(&serialState->ldmWindowCond); - ZSTD_pthread_mutex_unlock(&serialState->ldmWindowMutex); - } - ZSTD_pthread_mutex_unlock(&serialState->mutex); - -} - - -/* ------------------------------------------ */ -/* ===== Worker thread ===== */ -/* ------------------------------------------ */ - -static const range_t kNullRange = { NULL, 0 }; - -typedef struct { - size_t consumed; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx */ - size_t cSize; /* SHARED - set0 by mtctx, then modified by worker AND read by mtctx, then set0 by mtctx */ - ZSTD_pthread_mutex_t job_mutex; /* Thread-safe - used by mtctx and worker */ - ZSTD_pthread_cond_t job_cond; /* Thread-safe - used by mtctx and worker */ - ZSTDMT_CCtxPool* cctxPool; /* Thread-safe - used by mtctx and (all) workers */ - ZSTDMT_bufferPool* bufPool; /* Thread-safe - used by mtctx and (all) workers */ - ZSTDMT_seqPool* seqPool; /* Thread-safe - used by mtctx and (all) workers */ - serialState_t* serial; /* Thread-safe - used by mtctx and (all) workers */ - buffer_t dstBuff; /* set by worker (or mtctx), then read by worker & mtctx, then modified by mtctx => no barrier */ - range_t prefix; /* set by mtctx, then read by worker & mtctx => no barrier */ - range_t src; /* set by mtctx, then read by worker & mtctx => no barrier */ - unsigned jobID; /* set by mtctx, then read by worker => no barrier */ - unsigned firstJob; /* set by mtctx, then read by worker => no barrier */ - unsigned lastJob; /* set by mtctx, then read by worker => no barrier */ - ZSTD_CCtx_params params; /* set by mtctx, then read by worker => no barrier */ - const ZSTD_CDict* cdict; /* set by mtctx, then read by worker => no barrier */ - unsigned long long fullFrameSize; /* set by mtctx, then read by worker => no barrier */ - size_t dstFlushed; /* used only by mtctx */ - unsigned frameChecksumNeeded; /* used only by mtctx */ -} ZSTDMT_jobDescription; - -#define JOB_ERROR(e) \ - do { \ - ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \ - job->cSize = e; \ - ZSTD_pthread_mutex_unlock(&job->job_mutex); \ - goto _endJob; \ - } while (0) - -/* ZSTDMT_compressionJob() is a POOL_function type */ -static void ZSTDMT_compressionJob(void* jobDescription) -{ - ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription; - ZSTD_CCtx_params jobParams = job->params; /* do not modify job->params ! copy it, modify the copy */ - ZSTD_CCtx* const cctx = ZSTDMT_getCCtx(job->cctxPool); - rawSeqStore_t rawSeqStore = ZSTDMT_getSeq(job->seqPool); - buffer_t dstBuff = job->dstBuff; - size_t lastCBlockSize = 0; - - /* resources */ - if (cctx==NULL) JOB_ERROR(ERROR(memory_allocation)); - if (dstBuff.start == NULL) { /* streaming job : doesn't provide a dstBuffer */ - dstBuff = ZSTDMT_getBuffer(job->bufPool); - if (dstBuff.start==NULL) JOB_ERROR(ERROR(memory_allocation)); - job->dstBuff = dstBuff; /* this value can be read in ZSTDMT_flush, when it copies the whole job */ - } - if (jobParams.ldmParams.enableLdm == ZSTD_ps_enable && rawSeqStore.seq == NULL) - JOB_ERROR(ERROR(memory_allocation)); - - /* Don't compute the checksum for chunks, since we compute it externally, - * but write it in the header. - */ - if (job->jobID != 0) jobParams.fParams.checksumFlag = 0; - /* Don't run LDM for the chunks, since we handle it externally */ - jobParams.ldmParams.enableLdm = ZSTD_ps_disable; - /* Correct nbWorkers to 0. */ - jobParams.nbWorkers = 0; - - - /* init */ - if (job->cdict) { - size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, job->cdict, &jobParams, job->fullFrameSize); - assert(job->firstJob); /* only allowed for first job */ - if (ZSTD_isError(initError)) JOB_ERROR(initError); - } else { /* srcStart points at reloaded section */ - U64 const pledgedSrcSize = job->firstJob ? job->fullFrameSize : job->src.size; - { size_t const forceWindowError = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_forceMaxWindow, !job->firstJob); - if (ZSTD_isError(forceWindowError)) JOB_ERROR(forceWindowError); - } - if (!job->firstJob) { - size_t const err = ZSTD_CCtxParams_setParameter(&jobParams, ZSTD_c_deterministicRefPrefix, 0); - if (ZSTD_isError(err)) JOB_ERROR(err); - } - { size_t const initError = ZSTD_compressBegin_advanced_internal(cctx, - job->prefix.start, job->prefix.size, ZSTD_dct_rawContent, /* load dictionary in "content-only" mode (no header analysis) */ - ZSTD_dtlm_fast, - NULL, /*cdict*/ - &jobParams, pledgedSrcSize); - if (ZSTD_isError(initError)) JOB_ERROR(initError); - } } - - /* Perform serial step as early as possible, but after CCtx initialization */ - ZSTDMT_serialState_update(job->serial, cctx, rawSeqStore, job->src, job->jobID); - - if (!job->firstJob) { /* flush and overwrite frame header when it's not first job */ - size_t const hSize = ZSTD_compressContinue_public(cctx, dstBuff.start, dstBuff.capacity, job->src.start, 0); - if (ZSTD_isError(hSize)) JOB_ERROR(hSize); - DEBUGLOG(5, "ZSTDMT_compressionJob: flush and overwrite %u bytes of frame header (not first job)", (U32)hSize); - ZSTD_invalidateRepCodes(cctx); - } - - /* compress */ - { size_t const chunkSize = 4*ZSTD_BLOCKSIZE_MAX; - int const nbChunks = (int)((job->src.size + (chunkSize-1)) / chunkSize); - const BYTE* ip = (const BYTE*) job->src.start; - BYTE* const ostart = (BYTE*)dstBuff.start; - BYTE* op = ostart; - BYTE* oend = op + dstBuff.capacity; - int chunkNb; - if (sizeof(size_t) > sizeof(int)) assert(job->src.size < ((size_t)INT_MAX) * chunkSize); /* check overflow */ - DEBUGLOG(5, "ZSTDMT_compressionJob: compress %u bytes in %i blocks", (U32)job->src.size, nbChunks); - assert(job->cSize == 0); - for (chunkNb = 1; chunkNb < nbChunks; chunkNb++) { - size_t const cSize = ZSTD_compressContinue_public(cctx, op, oend-op, ip, chunkSize); - if (ZSTD_isError(cSize)) JOB_ERROR(cSize); - ip += chunkSize; - op += cSize; assert(op < oend); - /* stats */ - ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); - job->cSize += cSize; - job->consumed = chunkSize * chunkNb; - DEBUGLOG(5, "ZSTDMT_compressionJob: compress new block : cSize==%u bytes (total: %u)", - (U32)cSize, (U32)job->cSize); - ZSTD_pthread_cond_signal(&job->job_cond); /* warns some more data is ready to be flushed */ - ZSTD_pthread_mutex_unlock(&job->job_mutex); - } - /* last block */ - assert(chunkSize > 0); - assert((chunkSize & (chunkSize - 1)) == 0); /* chunkSize must be power of 2 for mask==(chunkSize-1) to work */ - if ((nbChunks > 0) | job->lastJob /*must output a "last block" flag*/ ) { - size_t const lastBlockSize1 = job->src.size & (chunkSize-1); - size_t const lastBlockSize = ((lastBlockSize1==0) & (job->src.size>=chunkSize)) ? chunkSize : lastBlockSize1; - size_t const cSize = (job->lastJob) ? - ZSTD_compressEnd_public(cctx, op, oend-op, ip, lastBlockSize) : - ZSTD_compressContinue_public(cctx, op, oend-op, ip, lastBlockSize); - if (ZSTD_isError(cSize)) JOB_ERROR(cSize); - lastCBlockSize = cSize; - } } - if (!job->firstJob) { - /* Double check that we don't have an ext-dict, because then our - * repcode invalidation doesn't work. - */ - assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); - } - ZSTD_CCtx_trace(cctx, 0); - -_endJob: - ZSTDMT_serialState_ensureFinished(job->serial, job->jobID, job->cSize); - if (job->prefix.size > 0) - DEBUGLOG(5, "Finished with prefix: %zx", (size_t)job->prefix.start); - DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start); - /* release resources */ - ZSTDMT_releaseSeq(job->seqPool, rawSeqStore); - ZSTDMT_releaseCCtx(job->cctxPool, cctx); - /* report */ - ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); - if (ZSTD_isError(job->cSize)) assert(lastCBlockSize == 0); - job->cSize += lastCBlockSize; - job->consumed = job->src.size; /* when job->consumed == job->src.size , compression job is presumed completed */ - ZSTD_pthread_cond_signal(&job->job_cond); - ZSTD_pthread_mutex_unlock(&job->job_mutex); -} - - -/* ------------------------------------------ */ -/* ===== Multi-threaded compression ===== */ -/* ------------------------------------------ */ - -typedef struct { - range_t prefix; /* read-only non-owned prefix buffer */ - buffer_t buffer; - size_t filled; -} inBuff_t; - -typedef struct { - BYTE* buffer; /* The round input buffer. All jobs get references - * to pieces of the buffer. ZSTDMT_tryGetInputRange() - * handles handing out job input buffers, and makes - * sure it doesn't overlap with any pieces still in use. - */ - size_t capacity; /* The capacity of buffer. */ - size_t pos; /* The position of the current inBuff in the round - * buffer. Updated past the end if the inBuff once - * the inBuff is sent to the worker thread. - * pos <= capacity. - */ -} roundBuff_t; - -static const roundBuff_t kNullRoundBuff = {NULL, 0, 0}; - -#define RSYNC_LENGTH 32 -/* Don't create chunks smaller than the zstd block size. - * This stops us from regressing compression ratio too much, - * and ensures our output fits in ZSTD_compressBound(). - * - * If this is shrunk < ZSTD_BLOCKSIZELOG_MIN then - * ZSTD_COMPRESSBOUND() will need to be updated. - */ -#define RSYNC_MIN_BLOCK_LOG ZSTD_BLOCKSIZELOG_MAX -#define RSYNC_MIN_BLOCK_SIZE (1< one job is already prepared, but pool has shortage of workers. Don't create a new job. */ - inBuff_t inBuff; - roundBuff_t roundBuff; - serialState_t serial; - rsyncState_t rsync; - unsigned jobIDMask; - unsigned doneJobID; - unsigned nextJobID; - unsigned frameEnded; - unsigned allJobsCompleted; - unsigned long long frameContentSize; - unsigned long long consumed; - unsigned long long produced; - ZSTD_customMem cMem; - ZSTD_CDict* cdictLocal; - const ZSTD_CDict* cdict; - unsigned providedFactory: 1; -}; - -static void ZSTDMT_freeJobsTable(ZSTDMT_jobDescription* jobTable, U32 nbJobs, ZSTD_customMem cMem) -{ - U32 jobNb; - if (jobTable == NULL) return; - for (jobNb=0; jobNb mtctx->jobIDMask+1) { /* need more job capacity */ - ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); - mtctx->jobIDMask = 0; - mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, mtctx->cMem); - if (mtctx->jobs==NULL) return ERROR(memory_allocation); - assert((nbJobs != 0) && ((nbJobs & (nbJobs - 1)) == 0)); /* ensure nbJobs is a power of 2 */ - mtctx->jobIDMask = nbJobs - 1; - } - return 0; -} - - -/* ZSTDMT_CCtxParam_setNbWorkers(): - * Internal use only */ -static size_t ZSTDMT_CCtxParam_setNbWorkers(ZSTD_CCtx_params* params, unsigned nbWorkers) -{ - return ZSTD_CCtxParams_setParameter(params, ZSTD_c_nbWorkers, (int)nbWorkers); -} - -MEM_STATIC ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced_internal(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) -{ - ZSTDMT_CCtx* mtctx; - U32 nbJobs = nbWorkers + 2; - int initError; - DEBUGLOG(3, "ZSTDMT_createCCtx_advanced (nbWorkers = %u)", nbWorkers); - - if (nbWorkers < 1) return NULL; - nbWorkers = MIN(nbWorkers , ZSTDMT_NBWORKERS_MAX); - if ((cMem.customAlloc!=NULL) ^ (cMem.customFree!=NULL)) - /* invalid custom allocator */ - return NULL; - - mtctx = (ZSTDMT_CCtx*) ZSTD_customCalloc(sizeof(ZSTDMT_CCtx), cMem); - if (!mtctx) return NULL; - ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers); - mtctx->cMem = cMem; - mtctx->allJobsCompleted = 1; - if (pool != NULL) { - mtctx->factory = pool; - mtctx->providedFactory = 1; - } - else { - mtctx->factory = POOL_create_advanced(nbWorkers, 0, cMem); - mtctx->providedFactory = 0; - } - mtctx->jobs = ZSTDMT_createJobsTable(&nbJobs, cMem); - assert(nbJobs > 0); assert((nbJobs & (nbJobs - 1)) == 0); /* ensure nbJobs is a power of 2 */ - mtctx->jobIDMask = nbJobs - 1; - mtctx->bufPool = ZSTDMT_createBufferPool(BUF_POOL_MAX_NB_BUFFERS(nbWorkers), cMem); - mtctx->cctxPool = ZSTDMT_createCCtxPool(nbWorkers, cMem); - mtctx->seqPool = ZSTDMT_createSeqPool(nbWorkers, cMem); - initError = ZSTDMT_serialState_init(&mtctx->serial); - mtctx->roundBuff = kNullRoundBuff; - if (!mtctx->factory | !mtctx->jobs | !mtctx->bufPool | !mtctx->cctxPool | !mtctx->seqPool | initError) { - ZSTDMT_freeCCtx(mtctx); - return NULL; - } - DEBUGLOG(3, "mt_cctx created, for %u threads", nbWorkers); - return mtctx; -} - -ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, ZSTD_customMem cMem, ZSTD_threadPool* pool) -{ -#ifdef ZSTD_MULTITHREAD - return ZSTDMT_createCCtx_advanced_internal(nbWorkers, cMem, pool); -#else - (void)nbWorkers; - (void)cMem; - (void)pool; - return NULL; -#endif -} - - -/* ZSTDMT_releaseAllJobResources() : - * note : ensure all workers are killed first ! */ -static void ZSTDMT_releaseAllJobResources(ZSTDMT_CCtx* mtctx) -{ - unsigned jobID; - DEBUGLOG(3, "ZSTDMT_releaseAllJobResources"); - for (jobID=0; jobID <= mtctx->jobIDMask; jobID++) { - /* Copy the mutex/cond out */ - ZSTD_pthread_mutex_t const mutex = mtctx->jobs[jobID].job_mutex; - ZSTD_pthread_cond_t const cond = mtctx->jobs[jobID].job_cond; - - DEBUGLOG(4, "job%02u: release dst address %08X", jobID, (U32)(size_t)mtctx->jobs[jobID].dstBuff.start); - ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[jobID].dstBuff); - - /* Clear the job description, but keep the mutex/cond */ - ZSTD_memset(&mtctx->jobs[jobID], 0, sizeof(mtctx->jobs[jobID])); - mtctx->jobs[jobID].job_mutex = mutex; - mtctx->jobs[jobID].job_cond = cond; - } - mtctx->inBuff.buffer = g_nullBuffer; - mtctx->inBuff.filled = 0; - mtctx->allJobsCompleted = 1; -} - -static void ZSTDMT_waitForAllJobsCompleted(ZSTDMT_CCtx* mtctx) -{ - DEBUGLOG(4, "ZSTDMT_waitForAllJobsCompleted"); - while (mtctx->doneJobID < mtctx->nextJobID) { - unsigned const jobID = mtctx->doneJobID & mtctx->jobIDMask; - ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[jobID].job_mutex); - while (mtctx->jobs[jobID].consumed < mtctx->jobs[jobID].src.size) { - DEBUGLOG(4, "waiting for jobCompleted signal from job %u", mtctx->doneJobID); /* we want to block when waiting for data to flush */ - ZSTD_pthread_cond_wait(&mtctx->jobs[jobID].job_cond, &mtctx->jobs[jobID].job_mutex); - } - ZSTD_pthread_mutex_unlock(&mtctx->jobs[jobID].job_mutex); - mtctx->doneJobID++; - } -} - -size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx) -{ - if (mtctx==NULL) return 0; /* compatible with free on NULL */ - if (!mtctx->providedFactory) - POOL_free(mtctx->factory); /* stop and free worker threads */ - ZSTDMT_releaseAllJobResources(mtctx); /* release job resources into pools first */ - ZSTDMT_freeJobsTable(mtctx->jobs, mtctx->jobIDMask+1, mtctx->cMem); - ZSTDMT_freeBufferPool(mtctx->bufPool); - ZSTDMT_freeCCtxPool(mtctx->cctxPool); - ZSTDMT_freeSeqPool(mtctx->seqPool); - ZSTDMT_serialState_free(&mtctx->serial); - ZSTD_freeCDict(mtctx->cdictLocal); - if (mtctx->roundBuff.buffer) - ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); - ZSTD_customFree(mtctx, mtctx->cMem); - return 0; -} - -size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx) -{ - if (mtctx == NULL) return 0; /* supports sizeof NULL */ - return sizeof(*mtctx) - + POOL_sizeof(mtctx->factory) - + ZSTDMT_sizeof_bufferPool(mtctx->bufPool) - + (mtctx->jobIDMask+1) * sizeof(ZSTDMT_jobDescription) - + ZSTDMT_sizeof_CCtxPool(mtctx->cctxPool) - + ZSTDMT_sizeof_seqPool(mtctx->seqPool) - + ZSTD_sizeof_CDict(mtctx->cdictLocal) - + mtctx->roundBuff.capacity; -} - - -/* ZSTDMT_resize() : - * @return : error code if fails, 0 on success */ -static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers) -{ - if (POOL_resize(mtctx->factory, nbWorkers)) return ERROR(memory_allocation); - FORWARD_IF_ERROR( ZSTDMT_expandJobsTable(mtctx, nbWorkers) , ""); - mtctx->bufPool = ZSTDMT_expandBufferPool(mtctx->bufPool, BUF_POOL_MAX_NB_BUFFERS(nbWorkers)); - if (mtctx->bufPool == NULL) return ERROR(memory_allocation); - mtctx->cctxPool = ZSTDMT_expandCCtxPool(mtctx->cctxPool, nbWorkers); - if (mtctx->cctxPool == NULL) return ERROR(memory_allocation); - mtctx->seqPool = ZSTDMT_expandSeqPool(mtctx->seqPool, nbWorkers); - if (mtctx->seqPool == NULL) return ERROR(memory_allocation); - ZSTDMT_CCtxParam_setNbWorkers(&mtctx->params, nbWorkers); - return 0; -} - - -/*! ZSTDMT_updateCParams_whileCompressing() : - * Updates a selected set of compression parameters, remaining compatible with currently active frame. - * New parameters will be applied to next compression job. */ -void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams) -{ - U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */ - int const compressionLevel = cctxParams->compressionLevel; - DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)", - compressionLevel); - mtctx->params.compressionLevel = compressionLevel; - { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - cParams.windowLog = saved_wlog; - mtctx->params.cParams = cParams; - } -} - -/* ZSTDMT_getFrameProgression(): - * tells how much data has been consumed (input) and produced (output) for current frame. - * able to count progression inside worker threads. - * Note : mutex will be acquired during statistics collection inside workers. */ -ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx) -{ - ZSTD_frameProgression fps; - DEBUGLOG(5, "ZSTDMT_getFrameProgression"); - fps.ingested = mtctx->consumed + mtctx->inBuff.filled; - fps.consumed = mtctx->consumed; - fps.produced = fps.flushed = mtctx->produced; - fps.currentJobID = mtctx->nextJobID; - fps.nbActiveWorkers = 0; - { unsigned jobNb; - unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1); - DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)", - mtctx->doneJobID, lastJobNb, mtctx->jobReady); - for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) { - unsigned const wJobID = jobNb & mtctx->jobIDMask; - ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID]; - ZSTD_pthread_mutex_lock(&jobPtr->job_mutex); - { size_t const cResult = jobPtr->cSize; - size_t const produced = ZSTD_isError(cResult) ? 0 : cResult; - size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed; - assert(flushed <= produced); - fps.ingested += jobPtr->src.size; - fps.consumed += jobPtr->consumed; - fps.produced += produced; - fps.flushed += flushed; - fps.nbActiveWorkers += (jobPtr->consumed < jobPtr->src.size); - } - ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); - } - } - return fps; -} - - -size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx) -{ - size_t toFlush; - unsigned const jobID = mtctx->doneJobID; - assert(jobID <= mtctx->nextJobID); - if (jobID == mtctx->nextJobID) return 0; /* no active job => nothing to flush */ - - /* look into oldest non-fully-flushed job */ - { unsigned const wJobID = jobID & mtctx->jobIDMask; - ZSTDMT_jobDescription* const jobPtr = &mtctx->jobs[wJobID]; - ZSTD_pthread_mutex_lock(&jobPtr->job_mutex); - { size_t const cResult = jobPtr->cSize; - size_t const produced = ZSTD_isError(cResult) ? 0 : cResult; - size_t const flushed = ZSTD_isError(cResult) ? 0 : jobPtr->dstFlushed; - assert(flushed <= produced); - assert(jobPtr->consumed <= jobPtr->src.size); - toFlush = produced - flushed; - /* if toFlush==0, nothing is available to flush. - * However, jobID is expected to still be active: - * if jobID was already completed and fully flushed, - * ZSTDMT_flushProduced() should have already moved onto next job. - * Therefore, some input has not yet been consumed. */ - if (toFlush==0) { - assert(jobPtr->consumed < jobPtr->src.size); - } - } - ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); - } - - return toFlush; -} - - -/* ------------------------------------------ */ -/* ===== Multi-threaded compression ===== */ -/* ------------------------------------------ */ - -static unsigned ZSTDMT_computeTargetJobLog(const ZSTD_CCtx_params* params) -{ - unsigned jobLog; - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* In Long Range Mode, the windowLog is typically oversized. - * In which case, it's preferable to determine the jobSize - * based on cycleLog instead. */ - jobLog = MAX(21, ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy) + 3); - } else { - jobLog = MAX(20, params->cParams.windowLog + 2); - } - return MIN(jobLog, (unsigned)ZSTDMT_JOBLOG_MAX); -} - -static int ZSTDMT_overlapLog_default(ZSTD_strategy strat) -{ - switch(strat) - { - case ZSTD_btultra2: - return 9; - case ZSTD_btultra: - case ZSTD_btopt: - return 8; - case ZSTD_btlazy2: - case ZSTD_lazy2: - return 7; - case ZSTD_lazy: - case ZSTD_greedy: - case ZSTD_dfast: - case ZSTD_fast: - default:; - } - return 6; -} - -static int ZSTDMT_overlapLog(int ovlog, ZSTD_strategy strat) -{ - assert(0 <= ovlog && ovlog <= 9); - if (ovlog == 0) return ZSTDMT_overlapLog_default(strat); - return ovlog; -} - -static size_t ZSTDMT_computeOverlapSize(const ZSTD_CCtx_params* params) -{ - int const overlapRLog = 9 - ZSTDMT_overlapLog(params->overlapLog, params->cParams.strategy); - int ovLog = (overlapRLog >= 8) ? 0 : (params->cParams.windowLog - overlapRLog); - assert(0 <= overlapRLog && overlapRLog <= 8); - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* In Long Range Mode, the windowLog is typically oversized. - * In which case, it's preferable to determine the jobSize - * based on chainLog instead. - * Then, ovLog becomes a fraction of the jobSize, rather than windowSize */ - ovLog = MIN(params->cParams.windowLog, ZSTDMT_computeTargetJobLog(params) - 2) - - overlapRLog; - } - assert(0 <= ovLog && ovLog <= ZSTD_WINDOWLOG_MAX); - DEBUGLOG(4, "overlapLog : %i", params->overlapLog); - DEBUGLOG(4, "overlap size : %i", 1 << ovLog); - return (ovLog==0) ? 0 : (size_t)1 << ovLog; -} - -/* ====================================== */ -/* ======= Streaming API ======= */ -/* ====================================== */ - -size_t ZSTDMT_initCStream_internal( - ZSTDMT_CCtx* mtctx, - const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, - const ZSTD_CDict* cdict, ZSTD_CCtx_params params, - unsigned long long pledgedSrcSize) -{ - DEBUGLOG(4, "ZSTDMT_initCStream_internal (pledgedSrcSize=%u, nbWorkers=%u, cctxPool=%u)", - (U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx); - - /* params supposed partially fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); - assert(!((dict) && (cdict))); /* either dict or cdict, not both */ - - /* init */ - if (params.nbWorkers != mtctx->params.nbWorkers) - FORWARD_IF_ERROR( ZSTDMT_resize(mtctx, params.nbWorkers) , ""); - - if (params.jobSize != 0 && params.jobSize < ZSTDMT_JOBSIZE_MIN) params.jobSize = ZSTDMT_JOBSIZE_MIN; - if (params.jobSize > (size_t)ZSTDMT_JOBSIZE_MAX) params.jobSize = (size_t)ZSTDMT_JOBSIZE_MAX; - - DEBUGLOG(4, "ZSTDMT_initCStream_internal: %u workers", params.nbWorkers); - - if (mtctx->allJobsCompleted == 0) { /* previous compression not correctly finished */ - ZSTDMT_waitForAllJobsCompleted(mtctx); - ZSTDMT_releaseAllJobResources(mtctx); - mtctx->allJobsCompleted = 1; - } - - mtctx->params = params; - mtctx->frameContentSize = pledgedSrcSize; - if (dict) { - ZSTD_freeCDict(mtctx->cdictLocal); - mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */ - params.cParams, mtctx->cMem); - mtctx->cdict = mtctx->cdictLocal; - if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation); - } else { - ZSTD_freeCDict(mtctx->cdictLocal); - mtctx->cdictLocal = NULL; - mtctx->cdict = cdict; - } - - mtctx->targetPrefixSize = ZSTDMT_computeOverlapSize(¶ms); - DEBUGLOG(4, "overlapLog=%i => %u KB", params.overlapLog, (U32)(mtctx->targetPrefixSize>>10)); - mtctx->targetSectionSize = params.jobSize; - if (mtctx->targetSectionSize == 0) { - mtctx->targetSectionSize = 1ULL << ZSTDMT_computeTargetJobLog(¶ms); - } - assert(mtctx->targetSectionSize <= (size_t)ZSTDMT_JOBSIZE_MAX); - - if (params.rsyncable) { - /* Aim for the targetsectionSize as the average job size. */ - U32 const jobSizeKB = (U32)(mtctx->targetSectionSize >> 10); - U32 const rsyncBits = (assert(jobSizeKB >= 1), ZSTD_highbit32(jobSizeKB) + 10); - /* We refuse to create jobs < RSYNC_MIN_BLOCK_SIZE bytes, so make sure our - * expected job size is at least 4x larger. */ - assert(rsyncBits >= RSYNC_MIN_BLOCK_LOG + 2); - DEBUGLOG(4, "rsyncLog = %u", rsyncBits); - mtctx->rsync.hash = 0; - mtctx->rsync.hitMask = (1ULL << rsyncBits) - 1; - mtctx->rsync.primePower = ZSTD_rollingHash_primePower(RSYNC_LENGTH); - } - if (mtctx->targetSectionSize < mtctx->targetPrefixSize) mtctx->targetSectionSize = mtctx->targetPrefixSize; /* job size must be >= overlap size */ - DEBUGLOG(4, "Job Size : %u KB (note : set to %u)", (U32)(mtctx->targetSectionSize>>10), (U32)params.jobSize); - DEBUGLOG(4, "inBuff Size : %u KB", (U32)(mtctx->targetSectionSize>>10)); - ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize)); - { - /* If ldm is enabled we need windowSize space. */ - size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? (1U << mtctx->params.cParams.windowLog) : 0; - /* Two buffers of slack, plus extra space for the overlap - * This is the minimum slack that LDM works with. One extra because - * flush might waste up to targetSectionSize-1 bytes. Another extra - * for the overlap (if > 0), then one to fill which doesn't overlap - * with the LDM window. - */ - size_t const nbSlackBuffers = 2 + (mtctx->targetPrefixSize > 0); - size_t const slackSize = mtctx->targetSectionSize * nbSlackBuffers; - /* Compute the total size, and always have enough slack */ - size_t const nbWorkers = MAX(mtctx->params.nbWorkers, 1); - size_t const sectionsSize = mtctx->targetSectionSize * nbWorkers; - size_t const capacity = MAX(windowSize, sectionsSize) + slackSize; - if (mtctx->roundBuff.capacity < capacity) { - if (mtctx->roundBuff.buffer) - ZSTD_customFree(mtctx->roundBuff.buffer, mtctx->cMem); - mtctx->roundBuff.buffer = (BYTE*)ZSTD_customMalloc(capacity, mtctx->cMem); - if (mtctx->roundBuff.buffer == NULL) { - mtctx->roundBuff.capacity = 0; - return ERROR(memory_allocation); - } - mtctx->roundBuff.capacity = capacity; - } - } - DEBUGLOG(4, "roundBuff capacity : %u KB", (U32)(mtctx->roundBuff.capacity>>10)); - mtctx->roundBuff.pos = 0; - mtctx->inBuff.buffer = g_nullBuffer; - mtctx->inBuff.filled = 0; - mtctx->inBuff.prefix = kNullRange; - mtctx->doneJobID = 0; - mtctx->nextJobID = 0; - mtctx->frameEnded = 0; - mtctx->allJobsCompleted = 0; - mtctx->consumed = 0; - mtctx->produced = 0; - if (ZSTDMT_serialState_reset(&mtctx->serial, mtctx->seqPool, params, mtctx->targetSectionSize, - dict, dictSize, dictContentType)) - return ERROR(memory_allocation); - return 0; -} - - -/* ZSTDMT_writeLastEmptyBlock() - * Write a single empty block with an end-of-frame to finish a frame. - * Job must be created from streaming variant. - * This function is always successful if expected conditions are fulfilled. - */ -static void ZSTDMT_writeLastEmptyBlock(ZSTDMT_jobDescription* job) -{ - assert(job->lastJob == 1); - assert(job->src.size == 0); /* last job is empty -> will be simplified into a last empty block */ - assert(job->firstJob == 0); /* cannot be first job, as it also needs to create frame header */ - assert(job->dstBuff.start == NULL); /* invoked from streaming variant only (otherwise, dstBuff might be user's output) */ - job->dstBuff = ZSTDMT_getBuffer(job->bufPool); - if (job->dstBuff.start == NULL) { - job->cSize = ERROR(memory_allocation); - return; - } - assert(job->dstBuff.capacity >= ZSTD_blockHeaderSize); /* no buffer should ever be that small */ - job->src = kNullRange; - job->cSize = ZSTD_writeLastEmptyBlock(job->dstBuff.start, job->dstBuff.capacity); - assert(!ZSTD_isError(job->cSize)); - assert(job->consumed == 0); -} - -static size_t ZSTDMT_createCompressionJob(ZSTDMT_CCtx* mtctx, size_t srcSize, ZSTD_EndDirective endOp) -{ - unsigned const jobID = mtctx->nextJobID & mtctx->jobIDMask; - int const endFrame = (endOp == ZSTD_e_end); - - if (mtctx->nextJobID > mtctx->doneJobID + mtctx->jobIDMask) { - DEBUGLOG(5, "ZSTDMT_createCompressionJob: will not create new job : table is full"); - assert((mtctx->nextJobID & mtctx->jobIDMask) == (mtctx->doneJobID & mtctx->jobIDMask)); - return 0; - } - - if (!mtctx->jobReady) { - BYTE const* src = (BYTE const*)mtctx->inBuff.buffer.start; - DEBUGLOG(5, "ZSTDMT_createCompressionJob: preparing job %u to compress %u bytes with %u preload ", - mtctx->nextJobID, (U32)srcSize, (U32)mtctx->inBuff.prefix.size); - mtctx->jobs[jobID].src.start = src; - mtctx->jobs[jobID].src.size = srcSize; - assert(mtctx->inBuff.filled >= srcSize); - mtctx->jobs[jobID].prefix = mtctx->inBuff.prefix; - mtctx->jobs[jobID].consumed = 0; - mtctx->jobs[jobID].cSize = 0; - mtctx->jobs[jobID].params = mtctx->params; - mtctx->jobs[jobID].cdict = mtctx->nextJobID==0 ? mtctx->cdict : NULL; - mtctx->jobs[jobID].fullFrameSize = mtctx->frameContentSize; - mtctx->jobs[jobID].dstBuff = g_nullBuffer; - mtctx->jobs[jobID].cctxPool = mtctx->cctxPool; - mtctx->jobs[jobID].bufPool = mtctx->bufPool; - mtctx->jobs[jobID].seqPool = mtctx->seqPool; - mtctx->jobs[jobID].serial = &mtctx->serial; - mtctx->jobs[jobID].jobID = mtctx->nextJobID; - mtctx->jobs[jobID].firstJob = (mtctx->nextJobID==0); - mtctx->jobs[jobID].lastJob = endFrame; - mtctx->jobs[jobID].frameChecksumNeeded = mtctx->params.fParams.checksumFlag && endFrame && (mtctx->nextJobID>0); - mtctx->jobs[jobID].dstFlushed = 0; - - /* Update the round buffer pos and clear the input buffer to be reset */ - mtctx->roundBuff.pos += srcSize; - mtctx->inBuff.buffer = g_nullBuffer; - mtctx->inBuff.filled = 0; - /* Set the prefix */ - if (!endFrame) { - size_t const newPrefixSize = MIN(srcSize, mtctx->targetPrefixSize); - mtctx->inBuff.prefix.start = src + srcSize - newPrefixSize; - mtctx->inBuff.prefix.size = newPrefixSize; - } else { /* endFrame==1 => no need for another input buffer */ - mtctx->inBuff.prefix = kNullRange; - mtctx->frameEnded = endFrame; - if (mtctx->nextJobID == 0) { - /* single job exception : checksum is already calculated directly within worker thread */ - mtctx->params.fParams.checksumFlag = 0; - } } - - if ( (srcSize == 0) - && (mtctx->nextJobID>0)/*single job must also write frame header*/ ) { - DEBUGLOG(5, "ZSTDMT_createCompressionJob: creating a last empty block to end frame"); - assert(endOp == ZSTD_e_end); /* only possible case : need to end the frame with an empty last block */ - ZSTDMT_writeLastEmptyBlock(mtctx->jobs + jobID); - mtctx->nextJobID++; - return 0; - } - } - - DEBUGLOG(5, "ZSTDMT_createCompressionJob: posting job %u : %u bytes (end:%u, jobNb == %u (mod:%u))", - mtctx->nextJobID, - (U32)mtctx->jobs[jobID].src.size, - mtctx->jobs[jobID].lastJob, - mtctx->nextJobID, - jobID); - if (POOL_tryAdd(mtctx->factory, ZSTDMT_compressionJob, &mtctx->jobs[jobID])) { - mtctx->nextJobID++; - mtctx->jobReady = 0; - } else { - DEBUGLOG(5, "ZSTDMT_createCompressionJob: no worker available for job %u", mtctx->nextJobID); - mtctx->jobReady = 1; - } - return 0; -} - - -/*! ZSTDMT_flushProduced() : - * flush whatever data has been produced but not yet flushed in current job. - * move to next job if current one is fully flushed. - * `output` : `pos` will be updated with amount of data flushed . - * `blockToFlush` : if >0, the function will block and wait if there is no data available to flush . - * @return : amount of data remaining within internal buffer, 0 if no more, 1 if unknown but > 0, or an error code */ -static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, unsigned blockToFlush, ZSTD_EndDirective end) -{ - unsigned const wJobID = mtctx->doneJobID & mtctx->jobIDMask; - DEBUGLOG(5, "ZSTDMT_flushProduced (blocking:%u , job %u <= %u)", - blockToFlush, mtctx->doneJobID, mtctx->nextJobID); - assert(output->size >= output->pos); - - ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex); - if ( blockToFlush - && (mtctx->doneJobID < mtctx->nextJobID) ) { - assert(mtctx->jobs[wJobID].dstFlushed <= mtctx->jobs[wJobID].cSize); - while (mtctx->jobs[wJobID].dstFlushed == mtctx->jobs[wJobID].cSize) { /* nothing to flush */ - if (mtctx->jobs[wJobID].consumed == mtctx->jobs[wJobID].src.size) { - DEBUGLOG(5, "job %u is completely consumed (%u == %u) => don't wait for cond, there will be none", - mtctx->doneJobID, (U32)mtctx->jobs[wJobID].consumed, (U32)mtctx->jobs[wJobID].src.size); - break; - } - DEBUGLOG(5, "waiting for something to flush from job %u (currently flushed: %u bytes)", - mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed); - ZSTD_pthread_cond_wait(&mtctx->jobs[wJobID].job_cond, &mtctx->jobs[wJobID].job_mutex); /* block when nothing to flush but some to come */ - } } - - /* try to flush something */ - { size_t cSize = mtctx->jobs[wJobID].cSize; /* shared */ - size_t const srcConsumed = mtctx->jobs[wJobID].consumed; /* shared */ - size_t const srcSize = mtctx->jobs[wJobID].src.size; /* read-only, could be done after mutex lock, but no-declaration-after-statement */ - ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); - if (ZSTD_isError(cSize)) { - DEBUGLOG(5, "ZSTDMT_flushProduced: job %u : compression error detected : %s", - mtctx->doneJobID, ZSTD_getErrorName(cSize)); - ZSTDMT_waitForAllJobsCompleted(mtctx); - ZSTDMT_releaseAllJobResources(mtctx); - return cSize; - } - /* add frame checksum if necessary (can only happen once) */ - assert(srcConsumed <= srcSize); - if ( (srcConsumed == srcSize) /* job completed -> worker no longer active */ - && mtctx->jobs[wJobID].frameChecksumNeeded ) { - U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState); - DEBUGLOG(4, "ZSTDMT_flushProduced: writing checksum : %08X \n", checksum); - MEM_writeLE32((char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].cSize, checksum); - cSize += 4; - mtctx->jobs[wJobID].cSize += 4; /* can write this shared value, as worker is no longer active */ - mtctx->jobs[wJobID].frameChecksumNeeded = 0; - } - - if (cSize > 0) { /* compression is ongoing or completed */ - size_t const toFlush = MIN(cSize - mtctx->jobs[wJobID].dstFlushed, output->size - output->pos); - DEBUGLOG(5, "ZSTDMT_flushProduced: Flushing %u bytes from job %u (completion:%u/%u, generated:%u)", - (U32)toFlush, mtctx->doneJobID, (U32)srcConsumed, (U32)srcSize, (U32)cSize); - assert(mtctx->doneJobID < mtctx->nextJobID); - assert(cSize >= mtctx->jobs[wJobID].dstFlushed); - assert(mtctx->jobs[wJobID].dstBuff.start != NULL); - if (toFlush > 0) { - ZSTD_memcpy((char*)output->dst + output->pos, - (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed, - toFlush); - } - output->pos += toFlush; - mtctx->jobs[wJobID].dstFlushed += toFlush; /* can write : this value is only used by mtctx */ - - if ( (srcConsumed == srcSize) /* job is completed */ - && (mtctx->jobs[wJobID].dstFlushed == cSize) ) { /* output buffer fully flushed => free this job position */ - DEBUGLOG(5, "Job %u completed (%u bytes), moving to next one", - mtctx->doneJobID, (U32)mtctx->jobs[wJobID].dstFlushed); - ZSTDMT_releaseBuffer(mtctx->bufPool, mtctx->jobs[wJobID].dstBuff); - DEBUGLOG(5, "dstBuffer released"); - mtctx->jobs[wJobID].dstBuff = g_nullBuffer; - mtctx->jobs[wJobID].cSize = 0; /* ensure this job slot is considered "not started" in future check */ - mtctx->consumed += srcSize; - mtctx->produced += cSize; - mtctx->doneJobID++; - } } - - /* return value : how many bytes left in buffer ; fake it to 1 when unknown but >0 */ - if (cSize > mtctx->jobs[wJobID].dstFlushed) return (cSize - mtctx->jobs[wJobID].dstFlushed); - if (srcSize > srcConsumed) return 1; /* current job not completely compressed */ - } - if (mtctx->doneJobID < mtctx->nextJobID) return 1; /* some more jobs ongoing */ - if (mtctx->jobReady) return 1; /* one job is ready to push, just not yet in the list */ - if (mtctx->inBuff.filled > 0) return 1; /* input is not empty, and still needs to be converted into a job */ - mtctx->allJobsCompleted = mtctx->frameEnded; /* all jobs are entirely flushed => if this one is last one, frame is completed */ - if (end == ZSTD_e_end) return !mtctx->frameEnded; /* for ZSTD_e_end, question becomes : is frame completed ? instead of : are internal buffers fully flushed ? */ - return 0; /* internal buffers fully flushed */ -} - -/** - * Returns the range of data used by the earliest job that is not yet complete. - * If the data of the first job is broken up into two segments, we cover both - * sections. - */ -static range_t ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx) -{ - unsigned const firstJobID = mtctx->doneJobID; - unsigned const lastJobID = mtctx->nextJobID; - unsigned jobID; - - for (jobID = firstJobID; jobID < lastJobID; ++jobID) { - unsigned const wJobID = jobID & mtctx->jobIDMask; - size_t consumed; - - ZSTD_PTHREAD_MUTEX_LOCK(&mtctx->jobs[wJobID].job_mutex); - consumed = mtctx->jobs[wJobID].consumed; - ZSTD_pthread_mutex_unlock(&mtctx->jobs[wJobID].job_mutex); - - if (consumed < mtctx->jobs[wJobID].src.size) { - range_t range = mtctx->jobs[wJobID].prefix; - if (range.size == 0) { - /* Empty prefix */ - range = mtctx->jobs[wJobID].src; - } - /* Job source in multiple segments not supported yet */ - assert(range.start <= mtctx->jobs[wJobID].src.start); - return range; - } - } - return kNullRange; -} - -/** - * Returns non-zero iff buffer and range overlap. - */ -static int ZSTDMT_isOverlapped(buffer_t buffer, range_t range) -{ - BYTE const* const bufferStart = (BYTE const*)buffer.start; - BYTE const* const rangeStart = (BYTE const*)range.start; - - if (rangeStart == NULL || bufferStart == NULL) - return 0; - - { - BYTE const* const bufferEnd = bufferStart + buffer.capacity; - BYTE const* const rangeEnd = rangeStart + range.size; - - /* Empty ranges cannot overlap */ - if (bufferStart == bufferEnd || rangeStart == rangeEnd) - return 0; - - return bufferStart < rangeEnd && rangeStart < bufferEnd; - } -} - -static int ZSTDMT_doesOverlapWindow(buffer_t buffer, ZSTD_window_t window) -{ - range_t extDict; - range_t prefix; - - DEBUGLOG(5, "ZSTDMT_doesOverlapWindow"); - extDict.start = window.dictBase + window.lowLimit; - extDict.size = window.dictLimit - window.lowLimit; - - prefix.start = window.base + window.dictLimit; - prefix.size = window.nextSrc - (window.base + window.dictLimit); - DEBUGLOG(5, "extDict [0x%zx, 0x%zx)", - (size_t)extDict.start, - (size_t)extDict.start + extDict.size); - DEBUGLOG(5, "prefix [0x%zx, 0x%zx)", - (size_t)prefix.start, - (size_t)prefix.start + prefix.size); - - return ZSTDMT_isOverlapped(buffer, extDict) - || ZSTDMT_isOverlapped(buffer, prefix); -} - -static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, buffer_t buffer) -{ - if (mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_pthread_mutex_t* mutex = &mtctx->serial.ldmWindowMutex; - DEBUGLOG(5, "ZSTDMT_waitForLdmComplete"); - DEBUGLOG(5, "source [0x%zx, 0x%zx)", - (size_t)buffer.start, - (size_t)buffer.start + buffer.capacity); - ZSTD_PTHREAD_MUTEX_LOCK(mutex); - while (ZSTDMT_doesOverlapWindow(buffer, mtctx->serial.ldmWindow)) { - DEBUGLOG(5, "Waiting for LDM to finish..."); - ZSTD_pthread_cond_wait(&mtctx->serial.ldmWindowCond, mutex); - } - DEBUGLOG(6, "Done waiting for LDM to finish"); - ZSTD_pthread_mutex_unlock(mutex); - } -} - -/** - * Attempts to set the inBuff to the next section to fill. - * If any part of the new section is still in use we give up. - * Returns non-zero if the buffer is filled. - */ -static int ZSTDMT_tryGetInputRange(ZSTDMT_CCtx* mtctx) -{ - range_t const inUse = ZSTDMT_getInputDataInUse(mtctx); - size_t const spaceLeft = mtctx->roundBuff.capacity - mtctx->roundBuff.pos; - size_t const target = mtctx->targetSectionSize; - buffer_t buffer; - - DEBUGLOG(5, "ZSTDMT_tryGetInputRange"); - assert(mtctx->inBuff.buffer.start == NULL); - assert(mtctx->roundBuff.capacity >= target); - - if (spaceLeft < target) { - /* ZSTD_invalidateRepCodes() doesn't work for extDict variants. - * Simply copy the prefix to the beginning in that case. - */ - BYTE* const start = (BYTE*)mtctx->roundBuff.buffer; - size_t const prefixSize = mtctx->inBuff.prefix.size; - - buffer.start = start; - buffer.capacity = prefixSize; - if (ZSTDMT_isOverlapped(buffer, inUse)) { - DEBUGLOG(5, "Waiting for buffer..."); - return 0; - } - ZSTDMT_waitForLdmComplete(mtctx, buffer); - ZSTD_memmove(start, mtctx->inBuff.prefix.start, prefixSize); - mtctx->inBuff.prefix.start = start; - mtctx->roundBuff.pos = prefixSize; - } - buffer.start = mtctx->roundBuff.buffer + mtctx->roundBuff.pos; - buffer.capacity = target; - - if (ZSTDMT_isOverlapped(buffer, inUse)) { - DEBUGLOG(5, "Waiting for buffer..."); - return 0; - } - assert(!ZSTDMT_isOverlapped(buffer, mtctx->inBuff.prefix)); - - ZSTDMT_waitForLdmComplete(mtctx, buffer); - - DEBUGLOG(5, "Using prefix range [%zx, %zx)", - (size_t)mtctx->inBuff.prefix.start, - (size_t)mtctx->inBuff.prefix.start + mtctx->inBuff.prefix.size); - DEBUGLOG(5, "Using source range [%zx, %zx)", - (size_t)buffer.start, - (size_t)buffer.start + buffer.capacity); - - - mtctx->inBuff.buffer = buffer; - mtctx->inBuff.filled = 0; - assert(mtctx->roundBuff.pos + buffer.capacity <= mtctx->roundBuff.capacity); - return 1; -} - -typedef struct { - size_t toLoad; /* The number of bytes to load from the input. */ - int flush; /* Boolean declaring if we must flush because we found a synchronization point. */ -} syncPoint_t; - -/** - * Searches through the input for a synchronization point. If one is found, we - * will instruct the caller to flush, and return the number of bytes to load. - * Otherwise, we will load as many bytes as possible and instruct the caller - * to continue as normal. - */ -static syncPoint_t -findSynchronizationPoint(ZSTDMT_CCtx const* mtctx, ZSTD_inBuffer const input) -{ - BYTE const* const istart = (BYTE const*)input.src + input.pos; - U64 const primePower = mtctx->rsync.primePower; - U64 const hitMask = mtctx->rsync.hitMask; - - syncPoint_t syncPoint; - U64 hash; - BYTE const* prev; - size_t pos; - - syncPoint.toLoad = MIN(input.size - input.pos, mtctx->targetSectionSize - mtctx->inBuff.filled); - syncPoint.flush = 0; - if (!mtctx->params.rsyncable) - /* Rsync is disabled. */ - return syncPoint; - if (mtctx->inBuff.filled + input.size - input.pos < RSYNC_MIN_BLOCK_SIZE) - /* We don't emit synchronization points if it would produce too small blocks. - * We don't have enough input to find a synchronization point, so don't look. - */ - return syncPoint; - if (mtctx->inBuff.filled + syncPoint.toLoad < RSYNC_LENGTH) - /* Not enough to compute the hash. - * We will miss any synchronization points in this RSYNC_LENGTH byte - * window. However, since it depends only in the internal buffers, if the - * state is already synchronized, we will remain synchronized. - * Additionally, the probability that we miss a synchronization point is - * low: RSYNC_LENGTH / targetSectionSize. - */ - return syncPoint; - /* Initialize the loop variables. */ - if (mtctx->inBuff.filled < RSYNC_MIN_BLOCK_SIZE) { - /* We don't need to scan the first RSYNC_MIN_BLOCK_SIZE positions - * because they can't possibly be a sync point. So we can start - * part way through the input buffer. - */ - pos = RSYNC_MIN_BLOCK_SIZE - mtctx->inBuff.filled; - if (pos >= RSYNC_LENGTH) { - prev = istart + pos - RSYNC_LENGTH; - hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); - } else { - assert(mtctx->inBuff.filled >= RSYNC_LENGTH); - prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; - hash = ZSTD_rollingHash_compute(prev + pos, (RSYNC_LENGTH - pos)); - hash = ZSTD_rollingHash_append(hash, istart, pos); - } - } else { - /* We have enough bytes buffered to initialize the hash, - * and have processed enough bytes to find a sync point. - * Start scanning at the beginning of the input. - */ - assert(mtctx->inBuff.filled >= RSYNC_MIN_BLOCK_SIZE); - assert(RSYNC_MIN_BLOCK_SIZE >= RSYNC_LENGTH); - pos = 0; - prev = (BYTE const*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled - RSYNC_LENGTH; - hash = ZSTD_rollingHash_compute(prev, RSYNC_LENGTH); - if ((hash & hitMask) == hitMask) { - /* We're already at a sync point so don't load any more until - * we're able to flush this sync point. - * This likely happened because the job table was full so we - * couldn't add our job. - */ - syncPoint.toLoad = 0; - syncPoint.flush = 1; - return syncPoint; - } - } - /* Starting with the hash of the previous RSYNC_LENGTH bytes, roll - * through the input. If we hit a synchronization point, then cut the - * job off, and tell the compressor to flush the job. Otherwise, load - * all the bytes and continue as normal. - * If we go too long without a synchronization point (targetSectionSize) - * then a block will be emitted anyways, but this is okay, since if we - * are already synchronized we will remain synchronized. - */ - assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); - for (; pos < syncPoint.toLoad; ++pos) { - BYTE const toRemove = pos < RSYNC_LENGTH ? prev[pos] : istart[pos - RSYNC_LENGTH]; - /* This assert is very expensive, and Debian compiles with asserts enabled. - * So disable it for now. We can get similar coverage by checking it at the - * beginning & end of the loop. - * assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); - */ - hash = ZSTD_rollingHash_rotate(hash, toRemove, istart[pos], primePower); - assert(mtctx->inBuff.filled + pos >= RSYNC_MIN_BLOCK_SIZE); - if ((hash & hitMask) == hitMask) { - syncPoint.toLoad = pos + 1; - syncPoint.flush = 1; - ++pos; /* for assert */ - break; - } - } - assert(pos < RSYNC_LENGTH || ZSTD_rollingHash_compute(istart + pos - RSYNC_LENGTH, RSYNC_LENGTH) == hash); - return syncPoint; -} - -size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx) -{ - size_t hintInSize = mtctx->targetSectionSize - mtctx->inBuff.filled; - if (hintInSize==0) hintInSize = mtctx->targetSectionSize; - return hintInSize; -} - -/** ZSTDMT_compressStream_generic() : - * internal use only - exposed to be invoked from zstd_compress.c - * assumption : output and input are valid (pos <= size) - * @return : minimum amount of data remaining to flush, 0 if none */ -size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, - ZSTD_outBuffer* output, - ZSTD_inBuffer* input, - ZSTD_EndDirective endOp) -{ - unsigned forwardInputProgress = 0; - DEBUGLOG(5, "ZSTDMT_compressStream_generic (endOp=%u, srcSize=%u)", - (U32)endOp, (U32)(input->size - input->pos)); - assert(output->pos <= output->size); - assert(input->pos <= input->size); - - if ((mtctx->frameEnded) && (endOp==ZSTD_e_continue)) { - /* current frame being ended. Only flush/end are allowed */ - return ERROR(stage_wrong); - } - - /* fill input buffer */ - if ( (!mtctx->jobReady) - && (input->size > input->pos) ) { /* support NULL input */ - if (mtctx->inBuff.buffer.start == NULL) { - assert(mtctx->inBuff.filled == 0); /* Can't fill an empty buffer */ - if (!ZSTDMT_tryGetInputRange(mtctx)) { - /* It is only possible for this operation to fail if there are - * still compression jobs ongoing. - */ - DEBUGLOG(5, "ZSTDMT_tryGetInputRange failed"); - assert(mtctx->doneJobID != mtctx->nextJobID); - } else - DEBUGLOG(5, "ZSTDMT_tryGetInputRange completed successfully : mtctx->inBuff.buffer.start = %p", mtctx->inBuff.buffer.start); - } - if (mtctx->inBuff.buffer.start != NULL) { - syncPoint_t const syncPoint = findSynchronizationPoint(mtctx, *input); - if (syncPoint.flush && endOp == ZSTD_e_continue) { - endOp = ZSTD_e_flush; - } - assert(mtctx->inBuff.buffer.capacity >= mtctx->targetSectionSize); - DEBUGLOG(5, "ZSTDMT_compressStream_generic: adding %u bytes on top of %u to buffer of size %u", - (U32)syncPoint.toLoad, (U32)mtctx->inBuff.filled, (U32)mtctx->targetSectionSize); - ZSTD_memcpy((char*)mtctx->inBuff.buffer.start + mtctx->inBuff.filled, (const char*)input->src + input->pos, syncPoint.toLoad); - input->pos += syncPoint.toLoad; - mtctx->inBuff.filled += syncPoint.toLoad; - forwardInputProgress = syncPoint.toLoad>0; - } - } - if ((input->pos < input->size) && (endOp == ZSTD_e_end)) { - /* Can't end yet because the input is not fully consumed. - * We are in one of these cases: - * - mtctx->inBuff is NULL & empty: we couldn't get an input buffer so don't create a new job. - * - We filled the input buffer: flush this job but don't end the frame. - * - We hit a synchronization point: flush this job but don't end the frame. - */ - assert(mtctx->inBuff.filled == 0 || mtctx->inBuff.filled == mtctx->targetSectionSize || mtctx->params.rsyncable); - endOp = ZSTD_e_flush; - } - - if ( (mtctx->jobReady) - || (mtctx->inBuff.filled >= mtctx->targetSectionSize) /* filled enough : let's compress */ - || ((endOp != ZSTD_e_continue) && (mtctx->inBuff.filled > 0)) /* something to flush : let's go */ - || ((endOp == ZSTD_e_end) && (!mtctx->frameEnded)) ) { /* must finish the frame with a zero-size block */ - size_t const jobSize = mtctx->inBuff.filled; - assert(mtctx->inBuff.filled <= mtctx->targetSectionSize); - FORWARD_IF_ERROR( ZSTDMT_createCompressionJob(mtctx, jobSize, endOp) , ""); - } - - /* check for potential compressed data ready to be flushed */ - { size_t const remainingToFlush = ZSTDMT_flushProduced(mtctx, output, !forwardInputProgress, endOp); /* block if there was no forward input progress */ - if (input->pos < input->size) return MAX(remainingToFlush, 1); /* input not consumed : do not end flush yet */ - DEBUGLOG(5, "end of ZSTDMT_compressStream_generic: remainingToFlush = %u", (U32)remainingToFlush); - return remainingToFlush; - } -} - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp b/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp index 736e2f06d..3c9a8cdff 100644 --- a/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp +++ b/src/duckdb/third_party/zstd/decompress/huf_decompress.cpp @@ -1,7 +1,7 @@ /* ****************************************************************** * huff0 huffman decoder, * part of Finite State Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -15,31 +15,19 @@ /* ************************************************************** * Dependencies ****************************************************************/ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ +#include /* memcpy, memset */ #include "zstd/common/compiler.h" #include "zstd/common/bitstream.h" /* BIT_* */ #include "zstd/common/fse.h" /* to compress headers */ #include "zstd/common/huf.h" +#include "zstd/common/huf_static.h" #include "zstd/common/error_private.h" -#include "zstd/common/zstd_internal.h" -#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_countTrailingZeros64 */ - -/* ************************************************************** -* Constants -****************************************************************/ - -#define HUF_DECODER_FAST_TABLELOG 11 +namespace duckdb_zstd { /* ************************************************************** * Macros ****************************************************************/ -#ifdef HUF_DISABLE_FAST_DECODE -# define HUF_ENABLE_FAST_DECODE 0 -#else -# define HUF_ENABLE_FAST_DECODE 1 -#endif - /* These two optional macros force the use one way or another of the two * Huffman decompression implementations. You can't force in both directions * at the same time. @@ -49,33 +37,11 @@ #error "Cannot force the use of the X1 and X2 decoders at the same time!" #endif -/* When DYNAMIC_BMI2 is enabled, fast decoders are only called when bmi2 is - * supported at runtime, so we can add the BMI2 target attribute. - * When it is disabled, we will still get BMI2 if it is enabled statically. - */ -#if DYNAMIC_BMI2 -# define HUF_FAST_BMI2_ATTRS BMI2_TARGET_ATTRIBUTE -#else -# define HUF_FAST_BMI2_ATTRS -#endif - -#ifdef __cplusplus -# define HUF_EXTERN_C extern "C" -#else -# define HUF_EXTERN_C -#endif -#define HUF_ASM_DECL HUF_EXTERN_C - -#if DYNAMIC_BMI2 -# define HUF_NEED_BMI2_FUNCTION 1 -#else -# define HUF_NEED_BMI2_FUNCTION 0 -#endif /* ************************************************************** * Error Management ****************************************************************/ -#define HUF_isError ERR_isError +// #define HUF_isError ERR_isError /* ************************************************************** @@ -84,16 +50,10 @@ #define HUF_ALIGN(x, a) HUF_ALIGN_MASK((x), (a) - 1) #define HUF_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) -namespace duckdb_zstd { /* ************************************************************** * BMI2 Variant Wrappers ****************************************************************/ -typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, - const void *cSrc, - size_t cSrcSize, - const HUF_DTable *DTable); - #if DYNAMIC_BMI2 #define HUF_DGEN(fn) \ @@ -106,7 +66,7 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ \ - static BMI2_TARGET_ATTRIBUTE size_t fn##_bmi2( \ + static TARGET_ATTRIBUTE("bmi2") size_t fn##_bmi2( \ void* dst, size_t dstSize, \ const void* cSrc, size_t cSrcSize, \ const HUF_DTable* DTable) \ @@ -115,9 +75,9 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, } \ \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ { \ - if (flags & HUF_flags_bmi2) { \ + if (bmi2) { \ return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ } \ return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ @@ -127,9 +87,9 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, #define HUF_DGEN(fn) \ static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int flags) \ + size_t cSrcSize, HUF_DTable const* DTable, int bmi2) \ { \ - (void)flags; \ + (void)bmi2; \ return fn##_body(dst, dstSize, cSrc, cSrcSize, DTable); \ } @@ -144,381 +104,94 @@ typedef struct { BYTE maxTableLog; BYTE tableType; BYTE tableLog; BYTE reserved; static DTableDesc HUF_getDTableDesc(const HUF_DTable* table) { DTableDesc dtd; - ZSTD_memcpy(&dtd, table, sizeof(dtd)); + memcpy(&dtd, table, sizeof(dtd)); return dtd; } -static size_t HUF_initFastDStream(BYTE const* ip) { - BYTE const lastByte = ip[7]; - size_t const bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; - size_t const value = MEM_readLEST(ip) | 1; - assert(bitsConsumed <= 8); - assert(sizeof(size_t) == 8); - return value << bitsConsumed; -} - - -/** - * The input/output arguments to the Huffman fast decoding loop: - * - * ip [in/out] - The input pointers, must be updated to reflect what is consumed. - * op [in/out] - The output pointers, must be updated to reflect what is written. - * bits [in/out] - The bitstream containers, must be updated to reflect the current state. - * dt [in] - The decoding table. - * ilowest [in] - The beginning of the valid range of the input. Decoders may read - * down to this pointer. It may be below iend[0]. - * oend [in] - The end of the output stream. op[3] must not cross oend. - * iend [in] - The end of each input stream. ip[i] may cross iend[i], - * as long as it is above ilowest, but that indicates corruption. - */ -typedef struct { - BYTE const* ip[4]; - BYTE* op[4]; - U64 bits[4]; - void const* dt; - BYTE const* ilowest; - BYTE* oend; - BYTE const* iend[4]; -} HUF_DecompressFastArgs; - -typedef void (*HUF_DecompressFastLoopFn)(HUF_DecompressFastArgs*); - -/** - * Initializes args for the fast decoding loop. - * @returns 1 on success - * 0 if the fallback implementation should be used. - * Or an error code on failure. - */ -static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* dst, size_t dstSize, void const* src, size_t srcSize, const HUF_DTable* DTable) -{ - void const* dt = DTable + 1; - U32 const dtLog = HUF_getDTableDesc(DTable).tableLog; - - const BYTE* const istart = (const BYTE*)src; - - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); - - /* The fast decoding loop assumes 64-bit little-endian. - * This condition is false on x32. - */ - if (!MEM_isLittleEndian() || MEM_32bits()) - return 0; - - /* Avoid nullptr addition */ - if (dstSize == 0) - return 0; - assert(dst != NULL); - - /* strict minimum : jump table + 1 byte per stream */ - if (srcSize < 10) - return ERROR(corruption_detected); - - /* Must have at least 8 bytes per stream because we don't handle initializing smaller bit containers. - * If table log is not correct at this point, fallback to the old decoder. - * On small inputs we don't have enough data to trigger the fast loop, so use the old decoder. - */ - if (dtLog != HUF_DECODER_FAST_TABLELOG) - return 0; - - /* Read the jump table. */ - { - size_t const length1 = MEM_readLE16(istart); - size_t const length2 = MEM_readLE16(istart+2); - size_t const length3 = MEM_readLE16(istart+4); - size_t const length4 = srcSize - (length1 + length2 + length3 + 6); - args->iend[0] = istart + 6; /* jumpTable */ - args->iend[1] = args->iend[0] + length1; - args->iend[2] = args->iend[1] + length2; - args->iend[3] = args->iend[2] + length3; - - /* HUF_initFastDStream() requires this, and this small of an input - * won't benefit from the ASM loop anyways. - */ - if (length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8) - return 0; - if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */ - } - /* ip[] contains the position that is currently loaded into bits[]. */ - args->ip[0] = args->iend[1] - sizeof(U64); - args->ip[1] = args->iend[2] - sizeof(U64); - args->ip[2] = args->iend[3] - sizeof(U64); - args->ip[3] = (BYTE const*)src + srcSize - sizeof(U64); - - /* op[] contains the output pointers. */ - args->op[0] = (BYTE*)dst; - args->op[1] = args->op[0] + (dstSize+3)/4; - args->op[2] = args->op[1] + (dstSize+3)/4; - args->op[3] = args->op[2] + (dstSize+3)/4; - - /* No point to call the ASM loop for tiny outputs. */ - if (args->op[3] >= oend) - return 0; - - /* bits[] is the bit container. - * It is read from the MSB down to the LSB. - * It is shifted left as it is read, and zeros are - * shifted in. After the lowest valid bit a 1 is - * set, so that CountTrailingZeros(bits[]) can be used - * to count how many bits we've consumed. - */ - args->bits[0] = HUF_initFastDStream(args->ip[0]); - args->bits[1] = HUF_initFastDStream(args->ip[1]); - args->bits[2] = HUF_initFastDStream(args->ip[2]); - args->bits[3] = HUF_initFastDStream(args->ip[3]); - - /* The decoders must be sure to never read beyond ilowest. - * This is lower than iend[0], but allowing decoders to read - * down to ilowest can allow an extra iteration or two in the - * fast loop. - */ - args->ilowest = istart; - - args->oend = oend; - args->dt = dt; - - return 1; -} - -static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArgs const* args, int stream, BYTE* segmentEnd) -{ - /* Validate that we haven't overwritten. */ - if (args->op[stream] > segmentEnd) - return ERROR(corruption_detected); - /* Validate that we haven't read beyond iend[]. - * Note that ip[] may be < iend[] because the MSB is - * the next bit to read, and we may have consumed 100% - * of the stream, so down to iend[i] - 8 is valid. - */ - if (args->ip[stream] < args->iend[stream] - 8) - return ERROR(corruption_detected); - - /* Construct the BIT_DStream_t. */ - assert(sizeof(size_t) == 8); - bit->bitContainer = MEM_readLEST(args->ip[stream]); - bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]); - bit->start = (const char*)args->ilowest; - bit->limitPtr = bit->start + sizeof(size_t); - bit->ptr = (const char*)args->ip[stream]; - - return 0; -} - -/* Calls X(N) for each stream 0, 1, 2, 3. */ -#define HUF_4X_FOR_EACH_STREAM(X) \ - do { \ - X(0); \ - X(1); \ - X(2); \ - X(3); \ - } while (0) - -/* Calls X(N, var) for each stream 0, 1, 2, 3. */ -#define HUF_4X_FOR_EACH_STREAM_WITH_VAR(X, var) \ - do { \ - X(0, (var)); \ - X(1, (var)); \ - X(2, (var)); \ - X(3, (var)); \ - } while (0) - #ifndef HUF_FORCE_DECOMPRESS_X2 /*-***************************/ /* single-symbol decoding */ /*-***************************/ -typedef struct { BYTE nbBits; BYTE byte; } HUF_DEltX1; /* single-symbol decoding */ - -/** - * Packs 4 HUF_DEltX1 structs into a U64. This is used to lay down 4 entries at - * a time. - */ -static U64 HUF_DEltX1_set4(BYTE symbol, BYTE nbBits) { - U64 D4; - if (MEM_isLittleEndian()) { - D4 = (U64)((symbol << 8) + nbBits); - } else { - D4 = (U64)(symbol + (nbBits << 8)); - } - assert(D4 < (1U << 16)); - D4 *= 0x0001000100010001ULL; - return D4; -} +typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX1; /* single-symbol decoding */ -/** - * Increase the tableLog to targetTableLog and rescales the stats. - * If tableLog > targetTableLog this is a no-op. - * @returns New tableLog - */ -static U32 HUF_rescaleStats(BYTE* huffWeight, U32* rankVal, U32 nbSymbols, U32 tableLog, U32 targetTableLog) -{ - if (tableLog > targetTableLog) - return tableLog; - if (tableLog < targetTableLog) { - U32 const scale = targetTableLog - tableLog; - U32 s; - /* Increase the weight for all non-zero probability symbols by scale. */ - for (s = 0; s < nbSymbols; ++s) { - huffWeight[s] += (BYTE)((huffWeight[s] == 0) ? 0 : scale); - } - /* Update rankVal to reflect the new weights. - * All weights except 0 get moved to weight + scale. - * Weights [1, scale] are empty. - */ - for (s = targetTableLog; s > scale; --s) { - rankVal[s] = rankVal[s - scale]; - } - for (s = scale; s > 0; --s) { - rankVal[s] = 0; - } - } - return targetTableLog; -} - -typedef struct { - U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; - U32 rankStart[HUF_TABLELOG_ABSOLUTEMAX + 1]; - U32 statsWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; - BYTE symbols[HUF_SYMBOLVALUE_MAX + 1]; - BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; -} HUF_ReadDTableX1_Workspace; - -size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize) { U32 tableLog = 0; U32 nbSymbols = 0; size_t iSize; void* const dtPtr = DTable + 1; HUF_DEltX1* const dt = (HUF_DEltX1*)dtPtr; - HUF_ReadDTableX1_Workspace* wksp = (HUF_ReadDTableX1_Workspace*)workSpace; - DEBUG_STATIC_ASSERT(HUF_DECOMPRESS_WORKSPACE_SIZE >= sizeof(*wksp)); - if (sizeof(*wksp) > wkspSize) return ERROR(tableLog_tooLarge); + U32* rankVal; + BYTE* huffWeight; + size_t spaceUsed32 = 0; + + rankVal = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_ABSOLUTEMAX + 1; + huffWeight = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); DEBUG_STATIC_ASSERT(sizeof(DTableDesc) == sizeof(HUF_DTable)); - /* ZSTD_memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ + /* memset(huffWeight, 0, sizeof(huffWeight)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats_wksp(wksp->huffWeight, HUF_SYMBOLVALUE_MAX + 1, wksp->rankVal, &nbSymbols, &tableLog, src, srcSize, wksp->statsWksp, sizeof(wksp->statsWksp), flags); + iSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); if (HUF_isError(iSize)) return iSize; - /* Table header */ { DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 const maxTableLog = dtd.maxTableLog + 1; - U32 const targetTableLog = MIN(maxTableLog, HUF_DECODER_FAST_TABLELOG); - tableLog = HUF_rescaleStats(wksp->huffWeight, wksp->rankVal, nbSymbols, tableLog, targetTableLog); if (tableLog > (U32)(dtd.maxTableLog+1)) return ERROR(tableLog_tooLarge); /* DTable too small, Huffman tree cannot fit in */ dtd.tableType = 0; dtd.tableLog = (BYTE)tableLog; - ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + memcpy(DTable, &dtd, sizeof(dtd)); } - /* Compute symbols and rankStart given rankVal: - * - * rankVal already contains the number of values of each weight. - * - * symbols contains the symbols ordered by weight. First are the rankVal[0] - * weight 0 symbols, followed by the rankVal[1] weight 1 symbols, and so on. - * symbols[0] is filled (but unused) to avoid a branch. - * - * rankStart contains the offset where each rank belongs in the DTable. - * rankStart[0] is not filled because there are no entries in the table for - * weight 0. - */ - { int n; - U32 nextRankStart = 0; - int const unroll = 4; - int const nLimit = (int)nbSymbols - unroll + 1; - for (n=0; n<(int)tableLog+1; n++) { - U32 const curr = nextRankStart; - nextRankStart += wksp->rankVal[n]; - wksp->rankStart[n] = curr; - } - for (n=0; n < nLimit; n += unroll) { - int u; - for (u=0; u < unroll; ++u) { - size_t const w = wksp->huffWeight[n+u]; - wksp->symbols[wksp->rankStart[w]++] = (BYTE)(n+u); - } - } - for (; n < (int)nbSymbols; ++n) { - size_t const w = wksp->huffWeight[n]; - wksp->symbols[wksp->rankStart[w]++] = (BYTE)n; - } - } - - /* fill DTable - * We fill all entries of each weight in order. - * That way length is a constant for each iteration of the outer loop. - * We can switch based on the length to a different inner loop which is - * optimized for that particular case. - */ - { U32 w; - int symbol = wksp->rankVal[0]; - int rankStart = 0; - for (w=1; wrankVal[w]; - int const length = (1 << w) >> 1; - int uStart = rankStart; - BYTE const nbBits = (BYTE)(tableLog + 1 - w); - int s; - int u; - switch (length) { - case 1: - for (s=0; ssymbols[symbol + s]; - D.nbBits = nbBits; - dt[uStart] = D; - uStart += 1; - } - break; - case 2: - for (s=0; ssymbols[symbol + s]; - D.nbBits = nbBits; - dt[uStart+0] = D; - dt[uStart+1] = D; - uStart += 2; - } - break; - case 4: - for (s=0; ssymbols[symbol + s], nbBits); - MEM_write64(dt + uStart, D4); - uStart += 4; - } - break; - case 8: - for (s=0; ssymbols[symbol + s], nbBits); - MEM_write64(dt + uStart, D4); - MEM_write64(dt + uStart + 4, D4); - uStart += 8; - } - break; - default: - for (s=0; ssymbols[symbol + s], nbBits); - for (u=0; u < length; u += 16) { - MEM_write64(dt + uStart + u + 0, D4); - MEM_write64(dt + uStart + u + 4, D4); - MEM_write64(dt + uStart + u + 8, D4); - MEM_write64(dt + uStart + u + 12, D4); - } - assert(u == length); - uStart += length; - } - break; - } - symbol += symbolCount; - rankStart += symbolCount * length; - } - } + /* Calculate starting value for each rank */ + { U32 n, nextRankStart = 0; + for (n=1; n> 1; + size_t const uStart = rankVal[w]; + size_t const uEnd = uStart + length; + size_t u; + HUF_DEltX1 D; + D.byte = (BYTE)n; + D.nbBits = (BYTE)(tableLog + 1 - w); + rankVal[w] = (U32)uEnd; + if (length < 4) { + /* Use length in the loop bound so the compiler knows it is short. */ + for (u = 0; u < length; ++u) + dt[uStart + u] = D; + } else { + /* Unroll the loop 4 times, we know it is a power of 2. */ + for (u = uStart; u < uEnd; u += 4) { + dt[u + 0] = D; + dt[u + 1] = D; + dt[u + 2] = D; + dt[u + 3] = D; + } } } } return iSize; } +size_t HUF_readDTableX1(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX1_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + FORCE_INLINE_TEMPLATE BYTE HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog) { @@ -529,19 +202,15 @@ HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog } #define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \ - do { *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog); } while (0) + *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog) -#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ - do { \ - if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ - HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \ - } while (0) +#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) -#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ - do { \ - if (MEM_64bits()) \ - HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \ - } while (0) +#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) HINT_INLINE size_t HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog) @@ -549,15 +218,11 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons BYTE* const pStart = p; /* up to 4 symbols at a time */ - if ((pEnd - p) > 3) { - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_1(p, bitDPtr); - HUF_DECODE_SYMBOLX1_2(p, bitDPtr); - HUF_DECODE_SYMBOLX1_0(p, bitDPtr); - } - } else { - BIT_reloadDStream(bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-3)) { + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_1(p, bitDPtr); + HUF_DECODE_SYMBOLX1_2(p, bitDPtr); + HUF_DECODE_SYMBOLX1_0(p, bitDPtr); } /* [0-3] symbols remaining */ @@ -569,7 +234,7 @@ HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, cons while (p < pEnd) HUF_DECODE_SYMBOLX1_0(p, bitDPtr); - return (size_t)(pEnd-pStart); + return pEnd-pStart; } FORCE_INLINE_TEMPLATE size_t @@ -579,7 +244,7 @@ HUF_decompress1X1_usingDTable_internal_body( const HUF_DTable* DTable) { BYTE* op = (BYTE*)dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(op, dstSize); + BYTE* const oend = op + dstSize; const void* dtPtr = DTable + 1; const HUF_DEltX1* const dt = (const HUF_DEltX1*)dtPtr; BIT_DStream_t bitD; @@ -595,10 +260,6 @@ HUF_decompress1X1_usingDTable_internal_body( return dstSize; } -/* HUF_decompress4X1_usingDTable_internal_body(): - * Conditions : - * @dstSize >= 6 - */ FORCE_INLINE_TEMPLATE size_t HUF_decompress4X1_usingDTable_internal_body( void* dst, size_t dstSize, @@ -607,7 +268,6 @@ HUF_decompress4X1_usingDTable_internal_body( { /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; @@ -642,37 +302,33 @@ HUF_decompress4X1_usingDTable_internal_body( U32 endSignal = 1; if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ - assert(dstSize >= 6); /* validated above */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* up to 16 symbols per loop (4 symbols per stream) in 64-bit mode */ - if ((size_t)(oend - op4) >= sizeof(size_t)) { - for ( ; (endSignal) & (op4 < olimit) ; ) { - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_1(op1, &bitD1); - HUF_DECODE_SYMBOLX1_1(op2, &bitD2); - HUF_DECODE_SYMBOLX1_1(op3, &bitD3); - HUF_DECODE_SYMBOLX1_1(op4, &bitD4); - HUF_DECODE_SYMBOLX1_2(op1, &bitD1); - HUF_DECODE_SYMBOLX1_2(op2, &bitD2); - HUF_DECODE_SYMBOLX1_2(op3, &bitD3); - HUF_DECODE_SYMBOLX1_2(op4, &bitD4); - HUF_DECODE_SYMBOLX1_0(op1, &bitD1); - HUF_DECODE_SYMBOLX1_0(op2, &bitD2); - HUF_DECODE_SYMBOLX1_0(op3, &bitD3); - HUF_DECODE_SYMBOLX1_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; - } + for ( ; (endSignal) & (op4 < olimit) ; ) { + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_1(op1, &bitD1); + HUF_DECODE_SYMBOLX1_1(op2, &bitD2); + HUF_DECODE_SYMBOLX1_1(op3, &bitD3); + HUF_DECODE_SYMBOLX1_1(op4, &bitD4); + HUF_DECODE_SYMBOLX1_2(op1, &bitD1); + HUF_DECODE_SYMBOLX1_2(op2, &bitD2); + HUF_DECODE_SYMBOLX1_2(op3, &bitD3); + HUF_DECODE_SYMBOLX1_2(op4, &bitD4); + HUF_DECODE_SYMBOLX1_0(op1, &bitD1); + HUF_DECODE_SYMBOLX1_0(op2, &bitD2); + HUF_DECODE_SYMBOLX1_0(op3, &bitD3); + HUF_DECODE_SYMBOLX1_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; } /* check corruption */ @@ -698,230 +354,99 @@ HUF_decompress4X1_usingDTable_internal_body( } } -#if HUF_NEED_BMI2_FUNCTION -static BMI2_TARGET_ATTRIBUTE -size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} -#endif -static -size_t HUF_decompress4X1_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} +typedef size_t (*HUF_decompress_usingDTable_t)(void *dst, size_t dstSize, + const void *cSrc, + size_t cSrcSize, + const HUF_DTable *DTable); -static HUF_FAST_BMI2_ATTRS -void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) -{ - U64 bits[4]; - BYTE const* ip[4]; - BYTE* op[4]; - U16 const* const dtable = (U16 const*)args->dt; - BYTE* const oend = args->oend; - BYTE const* const ilowest = args->ilowest; - - /* Copy the arguments to local variables */ - ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); - ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); - ZSTD_memcpy(&op, &args->op, sizeof(op)); - - assert(MEM_isLittleEndian()); - assert(!MEM_32bits()); - - for (;;) { - BYTE* olimit; - int stream; - - /* Assert loop preconditions */ -#ifndef NDEBUG - for (stream = 0; stream < 4; ++stream) { - assert(op[stream] <= (stream == 3 ? oend : op[stream + 1])); - assert(ip[stream] >= ilowest); - } -#endif - /* Compute olimit */ - { - /* Each iteration produces 5 output symbols per stream */ - size_t const oiters = (size_t)(oend - op[3]) / 5; - /* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes - * per stream. - */ - size_t const iiters = (size_t)(ip[0] - ilowest) / 7; - /* We can safely run iters iterations before running bounds checks */ - size_t const iters = MIN(oiters, iiters); - size_t const symbols = iters * 5; - - /* We can simply check that op[3] < olimit, instead of checking all - * of our bounds, since we can't hit the other bounds until we've run - * iters iterations, which only happens when op[3] == olimit. - */ - olimit = op[3] + symbols; - - /* Exit fast decoding loop once we reach the end. */ - if (op[3] == olimit) - break; - - /* Exit the decoding loop if any input pointer has crossed the - * previous one. This indicates corruption, and a precondition - * to our loop is that ip[i] >= ip[0]. - */ - for (stream = 1; stream < 4; ++stream) { - if (ip[stream] < ip[stream - 1]) - goto _out; - } - } - -#ifndef NDEBUG - for (stream = 1; stream < 4; ++stream) { - assert(ip[stream] >= ip[stream - 1]); - } -#endif +HUF_DGEN(HUF_decompress1X1_usingDTable_internal) +HUF_DGEN(HUF_decompress4X1_usingDTable_internal) -#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \ - do { \ - int const index = (int)(bits[(_stream)] >> 53); \ - int const entry = (int)dtable[index]; \ - bits[(_stream)] <<= (entry & 0x3F); \ - op[(_stream)][(_symbol)] = (BYTE)((entry >> 8) & 0xFF); \ - } while (0) - -#define HUF_4X1_RELOAD_STREAM(_stream) \ - do { \ - int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ - int const nbBits = ctz & 7; \ - int const nbBytes = ctz >> 3; \ - op[(_stream)] += 5; \ - ip[(_stream)] -= nbBytes; \ - bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ - bits[(_stream)] <<= nbBits; \ - } while (0) - - /* Manually unroll the loop because compilers don't consistently - * unroll the inner loops, which destroys performance. - */ - do { - /* Decode 5 symbols in each of the 4 streams */ - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 1); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 2); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 3); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4); - - /* Reload each of the 4 the bitstreams */ - HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM); - } while (op[3] < olimit); - -#undef HUF_4X1_DECODE_SYMBOL -#undef HUF_4X1_RELOAD_STREAM - } -_out: - /* Save the final values of each of the state variables back to args. */ - ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); - ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); - ZSTD_memcpy(&args->op, &op, sizeof(op)); -} - -/** - * @returns @p dstSize on success (>= 6) - * 0 if the fallback implementation should be used - * An error if an error occurred - */ -static HUF_FAST_BMI2_ATTRS -size_t -HUF_decompress4X1_usingDTable_internal_fast( +size_t HUF_decompress1X1_usingDTable( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable, - HUF_DecompressFastLoopFn loopFn) + const HUF_DTable* DTable) { - void const* dt = DTable + 1; - BYTE const* const ilowest = (BYTE const*)cSrc; - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); - HUF_DecompressFastArgs args; - { size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); - FORWARD_IF_ERROR(ret, "Failed to init fast loop args"); - if (ret == 0) - return 0; - } + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +} - assert(args.ip[0] >= args.ilowest); - loopFn(&args); - - /* Our loop guarantees that ip[] >= ilowest and that we haven't - * overwritten any op[]. - */ - assert(args.ip[0] >= ilowest); - assert(args.ip[0] >= ilowest); - assert(args.ip[1] >= ilowest); - assert(args.ip[2] >= ilowest); - assert(args.ip[3] >= ilowest); - assert(args.op[3] <= oend); - - assert(ilowest == args.ilowest); - assert(ilowest + 6 == args.iend[0]); - (void)ilowest; - - /* finish bit streams one by one. */ - { size_t const segmentSize = (dstSize+3) / 4; - BYTE* segmentEnd = (BYTE*)dst; - int i; - for (i = 0; i < 4; ++i) { - BIT_DStream_t bit; - if (segmentSize <= (size_t)(oend - segmentEnd)) - segmentEnd += segmentSize; - else - segmentEnd = oend; - FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); - /* Decompress and validate that we've produced exactly the expected length. */ - args.op[i] += HUF_decodeStreamX1(args.op[i], &bit, segmentEnd, (HUF_DEltX1 const*)dt, HUF_DECODER_FAST_TABLELOG); - if (args.op[i] != segmentEnd) return ERROR(corruption_detected); - } - } +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + const BYTE* ip = (const BYTE*) cSrc; - /* decoded size */ - assert(dstSize != 0); - return dstSize; + size_t const hSize = HUF_readDTableX1_wksp(DCtx, cSrc, cSrcSize, workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; + + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); } -HUF_DGEN(HUF_decompress1X1_usingDTable_internal) -static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable, int flags) +size_t HUF_decompress1X1_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) { - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X1_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X1_usingDTable_internal_fast_c_loop; + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X1_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - fallbackFn = HUF_decompress4X1_usingDTable_internal_bmi2; - } else { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } -#endif - if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) { - size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); - if (ret != 0) - return ret; - } - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X1_DCtx (DTable, dst, dstSize, cSrc, cSrcSize); +} + +size_t HUF_decompress4X1_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 0) return ERROR(GENERIC); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, +static size_t HUF_decompress4X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + size_t const hSize = HUF_readDTableX1_wksp (dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); + return HUF_decompress4X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); +} + +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) +{ + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, 0); +} + + +size_t HUF_decompress4X1_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX1(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X1_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); } #endif /* HUF_FORCE_DECOMPRESS_X2 */ @@ -934,322 +459,209 @@ static size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t ds /* *************************/ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX2; /* double-symbols decoding */ -typedef struct { BYTE symbol; } sortedSymbol_t; +typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; typedef U32 rankValCol_t[HUF_TABLELOG_MAX + 1]; typedef rankValCol_t rankVal_t[HUF_TABLELOG_MAX]; -/** - * Constructs a HUF_DEltX2 in a U32. - */ -static U32 HUF_buildDEltX2U32(U32 symbol, U32 nbBits, U32 baseSeq, int level) -{ - U32 seq; - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, sequence) == 0); - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, nbBits) == 2); - DEBUG_STATIC_ASSERT(offsetof(HUF_DEltX2, length) == 3); - DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U32)); - if (MEM_isLittleEndian()) { - seq = level == 1 ? symbol : (baseSeq + (symbol << 8)); - return seq + (nbBits << 16) + ((U32)level << 24); - } else { - seq = level == 1 ? (symbol << 8) : ((baseSeq << 8) + symbol); - return (seq << 16) + (nbBits << 8) + (U32)level; - } -} - -/** - * Constructs a HUF_DEltX2. - */ -static HUF_DEltX2 HUF_buildDEltX2(U32 symbol, U32 nbBits, U32 baseSeq, int level) -{ - HUF_DEltX2 DElt; - U32 const val = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); - DEBUG_STATIC_ASSERT(sizeof(DElt) == sizeof(val)); - ZSTD_memcpy(&DElt, &val, sizeof(val)); - return DElt; -} - -/** - * Constructs 2 HUF_DEltX2s and packs them into a U64. - */ -static U64 HUF_buildDEltX2U64(U32 symbol, U32 nbBits, U16 baseSeq, int level) -{ - U32 DElt = HUF_buildDEltX2U32(symbol, nbBits, baseSeq, level); - return (U64)DElt + ((U64)DElt << 32); -} - -/** - * Fills the DTable rank with all the symbols from [begin, end) that are each - * nbBits long. - * - * @param DTableRank The start of the rank in the DTable. - * @param begin The first symbol to fill (inclusive). - * @param end The last symbol to fill (exclusive). - * @param nbBits Each symbol is nbBits long. - * @param tableLog The table log. - * @param baseSeq If level == 1 { 0 } else { the first level symbol } - * @param level The level in the table. Must be 1 or 2. - */ -static void HUF_fillDTableX2ForWeight( - HUF_DEltX2* DTableRank, - sortedSymbol_t const* begin, sortedSymbol_t const* end, - U32 nbBits, U32 tableLog, - U16 baseSeq, int const level) -{ - U32 const length = 1U << ((tableLog - nbBits) & 0x1F /* quiet static-analyzer */); - const sortedSymbol_t* ptr; - assert(level >= 1 && level <= 2); - switch (length) { - case 1: - for (ptr = begin; ptr != end; ++ptr) { - HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); - *DTableRank++ = DElt; - } - break; - case 2: - for (ptr = begin; ptr != end; ++ptr) { - HUF_DEltX2 const DElt = HUF_buildDEltX2(ptr->symbol, nbBits, baseSeq, level); - DTableRank[0] = DElt; - DTableRank[1] = DElt; - DTableRank += 2; - } - break; - case 4: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - DTableRank += 4; - } - break; - case 8: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); - DTableRank += 8; - } - break; - default: - for (ptr = begin; ptr != end; ++ptr) { - U64 const DEltX2 = HUF_buildDEltX2U64(ptr->symbol, nbBits, baseSeq, level); - HUF_DEltX2* const DTableRankEnd = DTableRank + length; - for (; DTableRank != DTableRankEnd; DTableRank += 8) { - ZSTD_memcpy(DTableRank + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTableRank + 6, &DEltX2, sizeof(DEltX2)); - } - } - break; - } -} /* HUF_fillDTableX2Level2() : * `rankValOrigin` must be a table of at least (HUF_TABLELOG_MAX + 1) U32 */ -static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 targetLog, const U32 consumedBits, - const U32* rankVal, const int minWeight, const int maxWeight1, - const sortedSymbol_t* sortedSymbols, U32 const* rankStart, +static void HUF_fillDTableX2Level2(HUF_DEltX2* DTable, U32 sizeLog, const U32 consumed, + const U32* rankValOrigin, const int minWeight, + const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, U32 nbBitsBaseline, U16 baseSeq) { - /* Fill skipped values (all positions up to rankVal[minWeight]). - * These are positions only get a single symbol because the combined weight - * is too large. - */ + HUF_DEltX2 DElt; + U32 rankVal[HUF_TABLELOG_MAX + 1]; + + /* get pre-calculated rankVal */ + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill skipped values */ if (minWeight>1) { - U32 const length = 1U << ((targetLog - consumedBits) & 0x1F /* quiet static-analyzer */); - U64 const DEltX2 = HUF_buildDEltX2U64(baseSeq, consumedBits, /* baseSeq */ 0, /* level */ 1); - int const skipSize = rankVal[minWeight]; - assert(length > 1); - assert((U32)skipSize < length); - switch (length) { - case 2: - assert(skipSize == 1); - ZSTD_memcpy(DTable, &DEltX2, sizeof(DEltX2)); - break; - case 4: - assert(skipSize <= 4); - ZSTD_memcpy(DTable + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + 2, &DEltX2, sizeof(DEltX2)); - break; - default: - { - int i; - for (i = 0; i < skipSize; i += 8) { - ZSTD_memcpy(DTable + i + 0, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 2, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 4, &DEltX2, sizeof(DEltX2)); - ZSTD_memcpy(DTable + i + 6, &DEltX2, sizeof(DEltX2)); - } - } - } + U32 i, skipSize = rankVal[minWeight]; + MEM_writeLE16(&(DElt.sequence), baseSeq); + DElt.nbBits = (BYTE)(consumed); + DElt.length = 1; + for (i = 0; i < skipSize; i++) + DTable[i] = DElt; } - /* Fill each of the second level symbols by weight. */ - { - int w; - for (w = minWeight; w < maxWeight1; ++w) { - int const begin = rankStart[w]; - int const end = rankStart[w+1]; - U32 const nbBits = nbBitsBaseline - w; - U32 const totalBits = nbBits + consumedBits; - HUF_fillDTableX2ForWeight( - DTable + rankVal[w], - sortedSymbols + begin, sortedSymbols + end, - totalBits, targetLog, - baseSeq, /* level */ 2); - } - } + /* fill DTable */ + { U32 s; for (s=0; s= 1 */ + + rankVal[weight] += length; + } } } + static void HUF_fillDTableX2(HUF_DEltX2* DTable, const U32 targetLog, - const sortedSymbol_t* sortedList, - const U32* rankStart, rankValCol_t* rankValOrigin, const U32 maxWeight, + const sortedSymbol_t* sortedList, const U32 sortedListSize, + const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, const U32 nbBitsBaseline) { - U32* const rankVal = rankValOrigin[0]; + U32 rankVal[HUF_TABLELOG_MAX + 1]; const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ const U32 minBits = nbBitsBaseline - maxWeight; - int w; - int const wEnd = (int)maxWeight + 1; - - /* Fill DTable in order of weight. */ - for (w = 1; w < wEnd; ++w) { - int const begin = (int)rankStart[w]; - int const end = (int)rankStart[w+1]; - U32 const nbBits = nbBitsBaseline - w; - - if (targetLog-nbBits >= minBits) { - /* Enough room for a second symbol. */ - int start = rankVal[w]; - U32 const length = 1U << ((targetLog - nbBits) & 0x1F /* quiet static-analyzer */); + U32 s; + + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill DTable */ + for (s=0; s= minBits) { /* enough room for a second symbol */ + U32 sortedRank; int minWeight = nbBits + scaleLog; - int s; if (minWeight < 1) minWeight = 1; - /* Fill the DTable for every symbol of weight w. - * These symbols get at least 1 second symbol. - */ - for (s = begin; s != end; ++s) { - HUF_fillDTableX2Level2( - DTable + start, targetLog, nbBits, - rankValOrigin[nbBits], minWeight, wEnd, - sortedList, rankStart, - nbBitsBaseline, sortedList[s].symbol); - start += length; - } + sortedRank = rankStart[minWeight]; + HUF_fillDTableX2Level2(DTable+start, targetLog-nbBits, nbBits, + rankValOrigin[nbBits], minWeight, + sortedList+sortedRank, sortedListSize-sortedRank, + nbBitsBaseline, symbol); } else { - /* Only a single symbol. */ - HUF_fillDTableX2ForWeight( - DTable + rankVal[w], - sortedList + begin, sortedList + end, - nbBits, targetLog, - /* baseSeq */ 0, /* level */ 1); - } + HUF_DEltX2 DElt; + MEM_writeLE16(&(DElt.sequence), symbol); + DElt.nbBits = (BYTE)(nbBits); + DElt.length = 1; + { U32 const end = start + length; + U32 u; + for (u = start; u < end; u++) DTable[u] = DElt; + } } + rankVal[weight] += length; } } -typedef struct { - rankValCol_t rankVal[HUF_TABLELOG_MAX]; - U32 rankStats[HUF_TABLELOG_MAX + 1]; - U32 rankStart0[HUF_TABLELOG_MAX + 3]; - sortedSymbol_t sortedSymbol[HUF_SYMBOLVALUE_MAX + 1]; - BYTE weightList[HUF_SYMBOLVALUE_MAX + 1]; - U32 calleeWksp[HUF_READ_STATS_WORKSPACE_SIZE_U32]; -} HUF_ReadDTableX2_Workspace; - size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { - U32 tableLog, maxW, nbSymbols; + U32 tableLog, maxW, sizeOfSort, nbSymbols; DTableDesc dtd = HUF_getDTableDesc(DTable); - U32 maxTableLog = dtd.maxTableLog; + U32 const maxTableLog = dtd.maxTableLog; size_t iSize; void* dtPtr = DTable+1; /* force compiler to avoid strict-aliasing */ HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; U32 *rankStart; - HUF_ReadDTableX2_Workspace* const wksp = (HUF_ReadDTableX2_Workspace*)workSpace; - - if (sizeof(*wksp) > wkspSize) return ERROR(GENERIC); - - rankStart = wksp->rankStart0 + 1; - ZSTD_memset(wksp->rankStats, 0, sizeof(wksp->rankStats)); - ZSTD_memset(wksp->rankStart0, 0, sizeof(wksp->rankStart0)); + rankValCol_t* rankVal; + U32* rankStats; + U32* rankStart0; + sortedSymbol_t* sortedSymbol; + BYTE* weightList; + size_t spaceUsed32 = 0; + + rankVal = (rankValCol_t *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += (sizeof(rankValCol_t) * HUF_TABLELOG_MAX) >> 2; + rankStats = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 1; + rankStart0 = (U32 *)workSpace + spaceUsed32; + spaceUsed32 += HUF_TABLELOG_MAX + 2; + sortedSymbol = (sortedSymbol_t *)workSpace + (spaceUsed32 * sizeof(U32)) / sizeof(sortedSymbol_t); + spaceUsed32 += HUF_ALIGN(sizeof(sortedSymbol_t) * (HUF_SYMBOLVALUE_MAX + 1), sizeof(U32)) >> 2; + weightList = (BYTE *)((U32 *)workSpace + spaceUsed32); + spaceUsed32 += HUF_ALIGN(HUF_SYMBOLVALUE_MAX + 1, sizeof(U32)) >> 2; + + if ((spaceUsed32 << 2) > wkspSize) return ERROR(tableLog_tooLarge); + + rankStart = rankStart0 + 1; + memset(rankStats, 0, sizeof(U32) * (2 * HUF_TABLELOG_MAX + 2 + 1)); DEBUG_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(HUF_DTable)); /* if compiler fails here, assertion is wrong */ if (maxTableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); - /* ZSTD_memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ + /* memset(weightList, 0, sizeof(weightList)); */ /* is not necessary, even though some analyzer complain ... */ - iSize = HUF_readStats_wksp(wksp->weightList, HUF_SYMBOLVALUE_MAX + 1, wksp->rankStats, &nbSymbols, &tableLog, src, srcSize, wksp->calleeWksp, sizeof(wksp->calleeWksp), flags); + iSize = HUF_readStats(weightList, HUF_SYMBOLVALUE_MAX + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); if (HUF_isError(iSize)) return iSize; /* check result */ if (tableLog > maxTableLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ - if (tableLog <= HUF_DECODER_FAST_TABLELOG && maxTableLog > HUF_DECODER_FAST_TABLELOG) maxTableLog = HUF_DECODER_FAST_TABLELOG; /* find maxWeight */ - for (maxW = tableLog; wksp->rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ { U32 w, nextRankStart = 0; for (w=1; wrankStats[w]; - rankStart[w] = curr; + U32 current = nextRankStart; + nextRankStart += rankStats[w]; + rankStart[w] = current; } rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ - rankStart[maxW+1] = nextRankStart; + sizeOfSort = nextRankStart; } /* sort symbols by weight */ { U32 s; for (s=0; sweightList[s]; + U32 const w = weightList[s]; U32 const r = rankStart[w]++; - wksp->sortedSymbol[r].symbol = (BYTE)s; + sortedSymbol[r].symbol = (BYTE)s; + sortedSymbol[r].weight = (BYTE)w; } rankStart[0] = 0; /* forget 0w symbols; this is beginning of weight(1) */ } /* Build rankVal */ - { U32* const rankVal0 = wksp->rankVal[0]; + { U32* const rankVal0 = rankVal[0]; { int const rescale = (maxTableLog-tableLog) - 1; /* tableLog <= maxTableLog */ U32 nextRankVal = 0; U32 w; for (w=1; wrankStats[w] << (w+rescale); - rankVal0[w] = curr; + U32 current = nextRankVal; + nextRankVal += rankStats[w] << (w+rescale); + rankVal0[w] = current; } } { U32 const minBits = tableLog+1 - maxW; U32 consumed; for (consumed = minBits; consumed < maxTableLog - minBits + 1; consumed++) { - U32* const rankValPtr = wksp->rankVal[consumed]; + U32* const rankValPtr = rankVal[consumed]; U32 w; for (w = 1; w < maxW+1; w++) { rankValPtr[w] = rankVal0[w] >> consumed; } } } } HUF_fillDTableX2(dt, maxTableLog, - wksp->sortedSymbol, - wksp->rankStart0, wksp->rankVal, maxW, + sortedSymbol, sizeOfSort, + rankStart0, rankVal, maxW, tableLog+1); dtd.tableLog = (BYTE)maxTableLog; dtd.tableType = 1; - ZSTD_memcpy(DTable, &dtd, sizeof(dtd)); + memcpy(DTable, &dtd, sizeof(dtd)); return iSize; } +size_t HUF_readDTableX2(HUF_DTable* DTable, const void* src, size_t srcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_readDTableX2_wksp(DTable, src, srcSize, + workSpace, sizeof(workSpace)); +} + FORCE_INLINE_TEMPLATE U32 HUF_decodeSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - ZSTD_memcpy(op, &dt[val].sequence, 2); + memcpy(op, dt+val, 2); BIT_skipBits(DStream, dt[val].nbBits); return dt[val].length; } @@ -1258,34 +670,28 @@ FORCE_INLINE_TEMPLATE U32 HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, const U32 dtLog) { size_t const val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ - ZSTD_memcpy(op, &dt[val].sequence, 1); - if (dt[val].length==1) { - BIT_skipBits(DStream, dt[val].nbBits); - } else { + memcpy(op, dt+val, 1); + if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); + else { if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); - } - } + } } return 1; } #define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ - do { ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); } while (0) + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) -#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ - do { \ - if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ - ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \ - } while (0) +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) -#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ - do { \ - if (MEM_64bits()) \ - ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \ - } while (0) +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog) HINT_INLINE size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, @@ -1294,37 +700,19 @@ HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, BYTE* const pStart = p; /* up to 8 symbols at a time */ - if ((size_t)(pEnd - p) >= sizeof(bitDPtr->bitContainer)) { - if (dtLog <= 11 && MEM_64bits()) { - /* up to 10 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-9)) { - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - } - } else { - /* up to 8 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_1(p, bitDPtr); - HUF_DECODE_SYMBOLX2_2(p, bitDPtr); - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - } - } - } else { - BIT_reloadDStream(bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p < pEnd-(sizeof(bitDPtr->bitContainer)-1))) { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); } /* closer to end : up to 2 symbols at a time */ - if ((size_t)(pEnd - p) >= 2) { - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) & (p <= pEnd-2)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); - while (p <= pEnd-2) - HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ - } + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ if (p < pEnd) p += HUF_decodeLastSymbolX2(p, bitDPtr, dt, dtLog); @@ -1345,7 +733,7 @@ HUF_decompress1X2_usingDTable_internal_body( /* decode */ { BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, dstSize); + BYTE* const oend = ostart + dstSize; const void* const dtPtr = DTable+1; /* force compiler to not use strict-aliasing */ const HUF_DEltX2* const dt = (const HUF_DEltX2*)dtPtr; DTableDesc const dtd = HUF_getDTableDesc(DTable); @@ -1359,10 +747,6 @@ HUF_decompress1X2_usingDTable_internal_body( return dstSize; } -/* HUF_decompress4X2_usingDTable_internal_body(): - * Conditions: - * @dstSize >= 6 - */ FORCE_INLINE_TEMPLATE size_t HUF_decompress4X2_usingDTable_internal_body( void* dst, size_t dstSize, @@ -1370,7 +754,6 @@ HUF_decompress4X2_usingDTable_internal_body( const HUF_DTable* DTable) { if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - if (dstSize < 6) return ERROR(corruption_detected); /* stream 4-split doesn't work */ { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; @@ -1404,62 +787,58 @@ HUF_decompress4X2_usingDTable_internal_body( DTableDesc const dtd = HUF_getDTableDesc(DTable); U32 const dtLog = dtd.tableLog; - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - if (opStart4 > oend) return ERROR(corruption_detected); /* overflow */ - assert(dstSize >= 6 /* validated above */); + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ CHECK_F( BIT_initDStream(&bitD1, istart1, length1) ); CHECK_F( BIT_initDStream(&bitD2, istart2, length2) ); CHECK_F( BIT_initDStream(&bitD3, istart3, length3) ); CHECK_F( BIT_initDStream(&bitD4, istart4, length4) ); /* 16-32 symbols per loop (4-8 symbols per stream) */ - if ((size_t)(oend - op4) >= sizeof(size_t)) { - for ( ; (endSignal) & (op4 < olimit); ) { + for ( ; (endSignal) & (op4 < olimit); ) { #if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; - endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + endSignal &= BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished; + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal &= BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished; + endSignal &= BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished; #else - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - endSignal = (U32)LIKELY((U32) - (BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) - & (BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + endSignal = (U32)LIKELY( + (U32)(BIT_reloadDStreamFast(&bitD1) == BIT_DStream_unfinished) + & (U32)(BIT_reloadDStreamFast(&bitD2) == BIT_DStream_unfinished) + & (U32)(BIT_reloadDStreamFast(&bitD3) == BIT_DStream_unfinished) + & (U32)(BIT_reloadDStreamFast(&bitD4) == BIT_DStream_unfinished)); #endif - } } /* check corruption */ @@ -1483,268 +862,94 @@ HUF_decompress4X2_usingDTable_internal_body( } } -#if HUF_NEED_BMI2_FUNCTION -static BMI2_TARGET_ATTRIBUTE -size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); -} -#endif +HUF_DGEN(HUF_decompress1X2_usingDTable_internal) +HUF_DGEN(HUF_decompress4X2_usingDTable_internal) -static -size_t HUF_decompress4X2_usingDTable_internal_default(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); +size_t HUF_decompress1X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -static HUF_FAST_BMI2_ATTRS -void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs* args) +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + void* workSpace, size_t wkspSize) { - U64 bits[4]; - BYTE const* ip[4]; - BYTE* op[4]; - BYTE* oend[4]; - HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt; - BYTE const* const ilowest = args->ilowest; - - /* Copy the arguments to local registers. */ - ZSTD_memcpy(&bits, &args->bits, sizeof(bits)); - ZSTD_memcpy((void*)(&ip), &args->ip, sizeof(ip)); - ZSTD_memcpy(&op, &args->op, sizeof(op)); - - oend[0] = op[1]; - oend[1] = op[2]; - oend[2] = op[3]; - oend[3] = args->oend; - - assert(MEM_isLittleEndian()); - assert(!MEM_32bits()); - - for (;;) { - BYTE* olimit; - int stream; - - /* Assert loop preconditions */ -#ifndef NDEBUG - for (stream = 0; stream < 4; ++stream) { - assert(op[stream] <= oend[stream]); - assert(ip[stream] >= ilowest); - } -#endif - /* Compute olimit */ - { - /* Each loop does 5 table lookups for each of the 4 streams. - * Each table lookup consumes up to 11 bits of input, and produces - * up to 2 bytes of output. - */ - /* We can consume up to 7 bytes of input per iteration per stream. - * We also know that each input pointer is >= ip[0]. So we can run - * iters loops before running out of input. - */ - size_t iters = (size_t)(ip[0] - ilowest) / 7; - /* Each iteration can produce up to 10 bytes of output per stream. - * Each output stream my advance at different rates. So take the - * minimum number of safe iterations among all the output streams. - */ - for (stream = 0; stream < 4; ++stream) { - size_t const oiters = (size_t)(oend[stream] - op[stream]) / 10; - iters = MIN(iters, oiters); - } - - /* Each iteration produces at least 5 output symbols. So until - * op[3] crosses olimit, we know we haven't executed iters - * iterations yet. This saves us maintaining an iters counter, - * at the expense of computing the remaining # of iterations - * more frequently. - */ - olimit = op[3] + (iters * 5); - - /* Exit the fast decoding loop once we reach the end. */ - if (op[3] == olimit) - break; - - /* Exit the decoding loop if any input pointer has crossed the - * previous one. This indicates corruption, and a precondition - * to our loop is that ip[i] >= ip[0]. - */ - for (stream = 1; stream < 4; ++stream) { - if (ip[stream] < ip[stream - 1]) - goto _out; - } - } - -#ifndef NDEBUG - for (stream = 1; stream < 4; ++stream) { - assert(ip[stream] >= ip[stream - 1]); - } -#endif + const BYTE* ip = (const BYTE*) cSrc; -#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \ - do { \ - if ((_decode3) || (_stream) != 3) { \ - int const index = (int)(bits[(_stream)] >> 53); \ - HUF_DEltX2 const entry = dtable[index]; \ - MEM_write16(op[(_stream)], entry.sequence); \ - bits[(_stream)] <<= (entry.nbBits) & 0x3F; \ - op[(_stream)] += (entry.length); \ - } \ - } while (0) - -#define HUF_4X2_RELOAD_STREAM(_stream) \ - do { \ - HUF_4X2_DECODE_SYMBOL(3, 1); \ - { \ - int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \ - int const nbBits = ctz & 7; \ - int const nbBytes = ctz >> 3; \ - ip[(_stream)] -= nbBytes; \ - bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \ - bits[(_stream)] <<= nbBits; \ - } \ - } while (0) - - /* Manually unroll the loop because compilers don't consistently - * unroll the inner loops, which destroys performance. - */ - do { - /* Decode 5 symbols from each of the first 3 streams. - * The final stream will be decoded during the reload phase - * to reduce register pressure. - */ - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0); - - /* Decode one symbol from the final stream */ - HUF_4X2_DECODE_SYMBOL(3, 1); - - /* Decode 4 symbols from the final stream & reload bitstreams. - * The final stream is reloaded last, meaning that all 5 symbols - * are decoded from the final stream before it is reloaded. - */ - HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM); - } while (op[3] < olimit); - } + size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, + workSpace, wkspSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; cSrcSize -= hSize; -#undef HUF_4X2_DECODE_SYMBOL -#undef HUF_4X2_RELOAD_STREAM + return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, /* bmi2 */ 0); +} -_out: - /* Save the final values of each of the state variables back to args. */ - ZSTD_memcpy(&args->bits, &bits, sizeof(bits)); - ZSTD_memcpy((void*)(&args->ip), &ip, sizeof(ip)); - ZSTD_memcpy(&args->op, &op, sizeof(op)); +size_t HUF_decompress1X2_DCtx(HUF_DTable* DCtx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X2_DCtx_wksp(DCtx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); } +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress1X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); +} -static HUF_FAST_BMI2_ATTRS size_t -HUF_decompress4X2_usingDTable_internal_fast( +size_t HUF_decompress4X2_usingDTable( void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - const HUF_DTable* DTable, - HUF_DecompressFastLoopFn loopFn) { - void const* dt = DTable + 1; - const BYTE* const ilowest = (const BYTE*)cSrc; - BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize); - HUF_DecompressFastArgs args; - { - size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable); - FORWARD_IF_ERROR(ret, "Failed to init asm args"); - if (ret == 0) - return 0; - } - - assert(args.ip[0] >= args.ilowest); - loopFn(&args); - - /* note : op4 already verified within main loop */ - assert(args.ip[0] >= ilowest); - assert(args.ip[1] >= ilowest); - assert(args.ip[2] >= ilowest); - assert(args.ip[3] >= ilowest); - assert(args.op[3] <= oend); - - assert(ilowest == args.ilowest); - assert(ilowest + 6 == args.iend[0]); - (void)ilowest; - - /* finish bitStreams one by one */ - { - size_t const segmentSize = (dstSize+3) / 4; - BYTE* segmentEnd = (BYTE*)dst; - int i; - for (i = 0; i < 4; ++i) { - BIT_DStream_t bit; - if (segmentSize <= (size_t)(oend - segmentEnd)) - segmentEnd += segmentSize; - else - segmentEnd = oend; - FORWARD_IF_ERROR(HUF_initRemainingDStream(&bit, &args, i, segmentEnd), "corruption"); - args.op[i] += HUF_decodeStreamX2(args.op[i], &bit, segmentEnd, (HUF_DEltX2 const*)dt, HUF_DECODER_FAST_TABLELOG); - if (args.op[i] != segmentEnd) - return ERROR(corruption_detected); - } - } - - /* decoded size */ - return dstSize; -} - -static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, void const* cSrc, - size_t cSrcSize, HUF_DTable const* DTable, int flags) + const HUF_DTable* DTable) { - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X2_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X2_usingDTable_internal_fast_c_loop; - -#if DYNAMIC_BMI2 - if (flags & HUF_flags_bmi2) { - fallbackFn = HUF_decompress4X2_usingDTable_internal_bmi2; - } else { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } -#endif - - if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) { - size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn); - if (ret != 0) - return ret; - } - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); + DTableDesc dtd = HUF_getDTableDesc(DTable); + if (dtd.tableType != 1) return ERROR(GENERIC); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); } -HUF_DGEN(HUF_decompress1X2_usingDTable_internal) - -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* DCtx, void* dst, size_t dstSize, +static size_t HUF_decompress4X2_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX2_wksp(DCtx, cSrc, cSrcSize, - workSpace, wkspSize, flags); + size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, + workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress1X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, DCtx, flags); + return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); } -static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { - const BYTE* ip = (const BYTE*) cSrc; + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, /* bmi2 */ 0); +} - size_t hSize = HUF_readDTableX2_wksp(dctx, cSrc, cSrcSize, - workSpace, wkspSize, flags); - if (HUF_isError(hSize)) return hSize; - if (hSize >= cSrcSize) return ERROR(srcSize_wrong); - ip += hSize; cSrcSize -= hSize; - return HUF_decompress4X2_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_TABLELOG_MAX); + return HUF_decompress4X2_DCtx(DTable, dst, dstSize, cSrc, cSrcSize); } #endif /* HUF_FORCE_DECOMPRESS_X1 */ @@ -1754,28 +959,66 @@ static size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t ds /* Universal decompression selectors */ /* ***********************************/ +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const HUF_DTable* DTable) +{ + DTableDesc const dtd = HUF_getDTableDesc(DTable); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)dtd; + assert(dtd.tableType == 0); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)dtd; + assert(dtd.tableType == 1); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#else + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, /* bmi2 */ 0); +#endif +} + #if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; -static const algo_time_t algoTime[16 /* Quantization */][2 /* single, double */] = +static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = { /* single, double, quad */ - {{0,0}, {1,1}}, /* Q==0 : impossible */ - {{0,0}, {1,1}}, /* Q==1 : impossible */ - {{ 150,216}, { 381,119}}, /* Q == 2 : 12-18% */ - {{ 170,205}, { 514,112}}, /* Q == 3 : 18-25% */ - {{ 177,199}, { 539,110}}, /* Q == 4 : 25-32% */ - {{ 197,194}, { 644,107}}, /* Q == 5 : 32-38% */ - {{ 221,192}, { 735,107}}, /* Q == 6 : 38-44% */ - {{ 256,189}, { 881,106}}, /* Q == 7 : 44-50% */ - {{ 359,188}, {1167,109}}, /* Q == 8 : 50-56% */ - {{ 582,187}, {1570,114}}, /* Q == 9 : 56-62% */ - {{ 688,187}, {1712,122}}, /* Q ==10 : 62-69% */ - {{ 825,186}, {1965,136}}, /* Q ==11 : 69-75% */ - {{ 976,185}, {2131,150}}, /* Q ==12 : 75-81% */ - {{1180,186}, {2070,175}}, /* Q ==13 : 81-87% */ - {{1377,185}, {1731,202}}, /* Q ==14 : 87-93% */ - {{1412,185}, {1695,202}}, /* Q ==15 : 93-99% */ + {{0,0}, {1,1}, {2,2}}, /* Q==0 : impossible */ + {{0,0}, {1,1}, {2,2}}, /* Q==1 : impossible */ + {{ 38,130}, {1313, 74}, {2151, 38}}, /* Q == 2 : 12-18% */ + {{ 448,128}, {1353, 74}, {2238, 41}}, /* Q == 3 : 18-25% */ + {{ 556,128}, {1353, 74}, {2238, 47}}, /* Q == 4 : 25-32% */ + {{ 714,128}, {1418, 74}, {2436, 53}}, /* Q == 5 : 32-38% */ + {{ 883,128}, {1437, 74}, {2464, 61}}, /* Q == 6 : 38-44% */ + {{ 897,128}, {1515, 75}, {2622, 68}}, /* Q == 7 : 44-50% */ + {{ 926,128}, {1613, 75}, {2730, 75}}, /* Q == 8 : 50-56% */ + {{ 947,128}, {1729, 77}, {3359, 77}}, /* Q == 9 : 56-62% */ + {{1107,128}, {2083, 81}, {4006, 84}}, /* Q ==10 : 62-69% */ + {{1177,128}, {2379, 87}, {4785, 88}}, /* Q ==11 : 69-75% */ + {{1242,128}, {2415, 93}, {5155, 84}}, /* Q ==12 : 75-81% */ + {{1349,128}, {2644,106}, {5260,106}}, /* Q ==13 : 81-87% */ + {{1455,128}, {2422,124}, {4174,124}}, /* Q ==14 : 87-93% */ + {{ 722,128}, {1891,145}, {1936,146}}, /* Q ==15 : 93-99% */ }; #endif @@ -1802,92 +1045,188 @@ U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize) U32 const D256 = (U32)(dstSize >> 8); U32 const DTime0 = algoTime[Q][0].tableTime + (algoTime[Q][0].decode256Time * D256); U32 DTime1 = algoTime[Q][1].tableTime + (algoTime[Q][1].decode256Time * D256); - DTime1 += DTime1 >> 5; /* small advantage to algorithm using less memory, to reduce cache eviction */ + DTime1 += DTime1 >> 3; /* advantage to algorithm using less memory, to reduce cache eviction */ return DTime1 < DTime0; } #endif } + +typedef size_t (*decompressionAlgo)(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); + +size_t HUF_decompress (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ +#if !defined(HUF_FORCE_DECOMPRESS_X1) && !defined(HUF_FORCE_DECOMPRESS_X2) + static const decompressionAlgo decompress[2] = { HUF_decompress4X1, HUF_decompress4X2 }; +#endif + + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1(dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2(dst, dstSize, cSrc, cSrcSize); +#else + return decompress[algoNb](dst, dstSize, cSrc, cSrcSize); +#endif + } +} + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize); +#else + return algoNb ? HUF_decompress4X2_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) : + HUF_decompress4X1_DCtx(dctx, dst, dstSize, cSrc, cSrcSize) ; +#endif + } +} + +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress4X_hufOnly_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} + + +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, + size_t dstSize, const void* cSrc, + size_t cSrcSize, void* workSpace, + size_t wkspSize) +{ + /* validation checks */ + if (dstSize == 0) return ERROR(dstSize_tooSmall); + if (cSrcSize == 0) return ERROR(corruption_detected); + + { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); +#if defined(HUF_FORCE_DECOMPRESS_X1) + (void)algoNb; + assert(algoNb == 0); + return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#elif defined(HUF_FORCE_DECOMPRESS_X2) + (void)algoNb; + assert(algoNb == 1); + return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#else + return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, + cSrcSize, workSpace, wkspSize): + HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize); +#endif + } +} + size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, - void* workSpace, size_t wkspSize, int flags) + void* workSpace, size_t wkspSize) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); if (cSrcSize > dstSize) return ERROR(corruption_detected); /* invalid */ - if (cSrcSize == dstSize) { ZSTD_memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ - if (cSrcSize == 1) { ZSTD_memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ + if (cSrcSize == dstSize) { memcpy(dst, cSrc, dstSize); return dstSize; } /* not compressed */ + if (cSrcSize == 1) { memset(dst, *(const BYTE*)cSrc, dstSize); return dstSize; } /* RLE */ { U32 const algoNb = HUF_selectDecoder(dstSize, cSrcSize); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); return HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); return HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #else return algoNb ? HUF_decompress1X2_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags): + cSrcSize, workSpace, wkspSize): HUF_decompress1X1_DCtx_wksp(dctx, dst, dstSize, cSrc, - cSrcSize, workSpace, wkspSize, flags); + cSrcSize, workSpace, wkspSize); #endif } } +size_t HUF_decompress1X_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize) +{ + U32 workSpace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; + return HUF_decompress1X_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, + workSpace, sizeof(workSpace)); +} -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) + +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #else - return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : - HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return dtd.tableType ? HUF_decompress1X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress1X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #endif } #ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) { const BYTE* ip = (const BYTE*) cSrc; - size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize, flags); + size_t const hSize = HUF_readDTableX1_wksp(dctx, cSrc, cSrcSize, workSpace, wkspSize); if (HUF_isError(hSize)) return hSize; if (hSize >= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; cSrcSize -= hSize; - return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, flags); + return HUF_decompress1X1_usingDTable_internal(dst, dstSize, ip, cSrcSize, dctx, bmi2); } #endif -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags) +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2) { DTableDesc const dtd = HUF_getDTableDesc(DTable); #if defined(HUF_FORCE_DECOMPRESS_X1) (void)dtd; assert(dtd.tableType == 0); - return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)dtd; assert(dtd.tableType == 1); - return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #else - return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags) : - HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, flags); + return dtd.tableType ? HUF_decompress4X2_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2) : + HUF_decompress4X1_usingDTable_internal(dst, maxDstSize, cSrc, cSrcSize, DTable, bmi2); #endif } -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags) +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2) { /* validation checks */ if (dstSize == 0) return ERROR(dstSize_tooSmall); @@ -1897,16 +1236,16 @@ size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize #if defined(HUF_FORCE_DECOMPRESS_X1) (void)algoNb; assert(algoNb == 0); - return HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #elif defined(HUF_FORCE_DECOMPRESS_X2) (void)algoNb; assert(algoNb == 1); - return HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #else - return algoNb ? HUF_decompress4X2_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags) : - HUF_decompress4X1_DCtx_wksp(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, flags); + return algoNb ? HUF_decompress4X2_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2) : + HUF_decompress4X1_DCtx_wksp_bmi2(dctx, dst, dstSize, cSrc, cSrcSize, workSpace, wkspSize, bmi2); #endif } } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp b/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp index 2c6c0ded6..ecb71145f 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_ddict.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,19 +14,18 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ -#include "zstd/common/cpu.h" /* bmi2 */ +#include /* memcpy, memmove, memset */ #include "zstd/common/mem.h" /* low level memory routines */ -#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" +#include "zstd/common/huf_static.h" #include "zstd/decompress/zstd_decompress_internal.h" #include "zstd/decompress/zstd_ddict.h" -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -// # include "zstd/legacy/zstd_legacy.h" // DuckDB: comment out otherwise amalgamation won't be happy -#endif +// #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +// # include "../legacy/zstd_legacy.h" +// #endif namespace duckdb_zstd { @@ -127,14 +126,14 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, ddict->dictContent = dict; if (!dict) dictSize = 0; } else { - void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); + void* const internalBuffer = ZSTD_malloc(dictSize, ddict->cMem); ddict->dictBuffer = internalBuffer; ddict->dictContent = internalBuffer; if (!internalBuffer) return ERROR(memory_allocation); - ZSTD_memcpy(internalBuffer, dict, dictSize); + memcpy(internalBuffer, dict, dictSize); } ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ /* parse dictionary content */ FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); @@ -147,9 +146,9 @@ ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); + { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_malloc(sizeof(ZSTD_DDict), customMem); if (ddict == NULL) return NULL; ddict->cMem = customMem; { size_t const initResult = ZSTD_initDDict_internal(ddict, @@ -198,7 +197,7 @@ const ZSTD_DDict* ZSTD_initStaticDDict( if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ if (sBufferSize < neededSpace) return NULL; if (dictLoadMethod == ZSTD_dlm_byCopy) { - ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ + memcpy(ddict+1, dict, dictSize); /* local copy */ dict = ddict+1; } if (ZSTD_isError( ZSTD_initDDict_internal(ddict, @@ -213,8 +212,8 @@ size_t ZSTD_freeDDict(ZSTD_DDict* ddict) { if (ddict==NULL) return 0; /* support free on NULL */ { ZSTD_customMem const cMem = ddict->cMem; - ZSTD_customFree(ddict->dictBuffer, cMem); - ZSTD_customFree(ddict, cMem); + ZSTD_free(ddict->dictBuffer, cMem); + ZSTD_free(ddict, cMem); return 0; } } @@ -240,7 +239,7 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) { if (ddict==NULL) return 0; - return ddict->dictID; + return ZSTD_getDictID_fromDict(ddict->dictContent, ddict->dictSize); } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp b/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp index 1a10de56d..19ebd9078 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_decompress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -55,167 +55,88 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ -#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ -#include "zstd/common/error_private.h" -#include "zstd/common/zstd_internal.h" /* blockProperties_t */ +#include /* memcpy, memmove, memset */ #include "zstd/common/mem.h" /* low level memory routines */ -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ -#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#include "zstd/common/xxhash.hpp" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ -#include "zstd/common/xxhash_static.hpp" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */ +#include "zstd/common/huf_static.h" +#include "zstd/common/zstd_internal.h" /* blockProperties_t */ #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd/decompress/zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd/decompress/zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */ -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) -// # include "zstd/legacy/zstd_legacy.h" // DuckDB: comment out otherwise amalgamation won't be happy -#endif - - - -/************************************* - * Multiple DDicts Hashset internals * - *************************************/ - -#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 4 -#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float. */ - /* Currently, that means a 0.75 load factor. */ - /* So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded */ - /* the load factor of the ddict hash set. */ - -#define DDICT_HASHSET_TABLE_BASE_SIZE 64 -#define DDICT_HASHSET_RESIZE_FACTOR 2 - +// #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) +// # include "../legacy/zstd_legacy.h" +// #endif namespace duckdb_zstd { - -/* Hash function to determine starting position of dict insertion within the table - * Returns an index between [0, hashSet->ddictPtrTableSize] - */ -static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) { - const U64 hash = XXH64(&dictID, sizeof(U32), 0); - /* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */ - return hash & (hashSet->ddictPtrTableSize - 1); -} - -/* Adds DDict to a hashset without resizing it. - * If inserting a DDict with a dictID that already exists in the set, replaces the one in the set. - * Returns 0 if successful, or a zstd error code if something went wrong. - */ -static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) { - const U32 dictID = ZSTD_getDictID_fromDDict(ddict); - size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); - const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; - RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!"); - DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); - while (hashSet->ddictPtrTable[idx] != NULL) { - /* Replace existing ddict if inserting ddict with same dictID */ - if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) { - DEBUGLOG(4, "DictID already exists, replacing rather than adding"); - hashSet->ddictPtrTable[idx] = ddict; - return 0; - } - idx &= idxRangeMask; - idx++; - } - DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); - hashSet->ddictPtrTable[idx] = ddict; - hashSet->ddictPtrCount++; - return 0; -} - -/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and - * rehashes all values, allocates new table, frees old table. - * Returns 0 on success, otherwise a zstd error code. - */ -static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { - size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR; - const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem); - const ZSTD_DDict** oldTable = hashSet->ddictPtrTable; - size_t oldTableSize = hashSet->ddictPtrTableSize; - size_t i; - - DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize); - RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!"); - hashSet->ddictPtrTable = newTable; - hashSet->ddictPtrTableSize = newTableSize; - hashSet->ddictPtrCount = 0; - for (i = 0; i < oldTableSize; ++i) { - if (oldTable[i] != NULL) { - FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), ""); - } - } - ZSTD_customFree((void*)oldTable, customMem); - DEBUGLOG(4, "Finished re-hash"); - return 0; -} - -/* Fetches a DDict with the given dictID - * Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL. - */ -static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) { - size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID); - const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1; - DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx); - for (;;) { - size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]); - if (currDictID == dictID || currDictID == 0) { - /* currDictID == 0 implies a NULL ddict entry */ - break; - } else { - idx &= idxRangeMask; /* Goes to start of table when we reach the end */ - idx++; - } - } - DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx); - return hashSet->ddictPtrTable[idx]; -} - -/* Allocates space for and returns a ddict hash set - * The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with. - * Returns NULL if allocation failed. - */ -static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) { - ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem); - DEBUGLOG(4, "Allocating new hash set"); - if (!ret) - return NULL; - ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem); - if (!ret->ddictPtrTable) { - ZSTD_customFree(ret, customMem); - return NULL; - } - ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE; - ret->ddictPtrCount = 0; - return ret; -} - -/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself. - * Note: The ZSTD_DDict* within the table are NOT freed. - */ -static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) { - DEBUGLOG(4, "Freeing ddict hash set"); - if (hashSet && hashSet->ddictPtrTable) { - ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem); - } - if (hashSet) { - ZSTD_customFree(hashSet, customMem); - } -} - -/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set. - * Returns 0 on success, or a ZSTD error. - */ -static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) { - DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize); - if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) { - FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), ""); - } - FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), ""); - return 0; -} +const U32 ZSTDConstants::LL_base[MaxLL+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, + 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 }; + +const U32 ZSTDConstants::OF_base[MaxOff+1] = { + 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, + 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, + 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, + 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; + +const U32 ZSTDConstants::OF_bits[MaxOff+1] = { + 0, 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 }; + +const U32 ZSTDConstants::ML_base[MaxML+1] = { + 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, 37, 39, 41, 43, 47, 51, 59, + 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; + +const size_t ZSTDInternalConstants::ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +const U32 ZSTDInternalConstants::LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, + 4, 6, 7, 8, 9,10,11,12, + 13,14,15,16 }; +const S16 ZSTDInternalConstants::LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 2, 1, 1, 1, 1, 1, + -1,-1,-1,-1 }; +#define LL_DEFAULTNORMLOG 6 /* for static allocation */ +const U32 ZSTDInternalConstants::LL_defaultNormLog = LL_DEFAULTNORMLOG; +const U32 ZSTDInternalConstants::ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 7, 8, 9,10,11, + 12,13,14,15,16 }; +const S16 ZSTDInternalConstants::ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1,-1,-1, + -1,-1,-1,-1,-1 }; +#define ML_DEFAULTNORMLOG 6 /* for static allocation */ +const U32 ZSTDInternalConstants::ML_defaultNormLog = ML_DEFAULTNORMLOG; + +const S16 ZSTDInternalConstants::OF_defaultNorm[DefaultMaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + -1,-1,-1,-1,-1 }; +#define OF_DEFAULTNORMLOG 5 /* for static allocation */ +const U32 ZSTDInternalConstants::OF_defaultNormLog = OF_DEFAULTNORMLOG; +const U32 ZSTDInternalConstants::repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; + +const ZSTD_customMem ZSTDInternalConstants::ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ /*-************************************************************* * Context management @@ -239,21 +160,11 @@ static size_t ZSTD_startingInputLength(ZSTD_format_e format) return startingInputLength; } -static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx) -{ - assert(dctx->streamStage == zdss_init); - dctx->format = ZSTD_f_zstd1; - dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; - dctx->outBufferMode = ZSTD_bm_buffered; - dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum; - dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict; - dctx->disableHufAsm = 0; - dctx->maxBlockSizeParam = 0; -} - static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) { + dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */ dctx->staticSize = 0; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; dctx->ddict = NULL; dctx->ddictLocal = NULL; dctx->dictEnd = NULL; @@ -263,18 +174,12 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) dctx->inBuffSize = 0; dctx->outBuffSize = 0; dctx->streamStage = zdss_init; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) dctx->legacyContext = NULL; dctx->previousLegacyVersion = 0; -#endif dctx->noForwardProgress = 0; dctx->oversizedDuration = 0; - dctx->isFrameDecompression = 1; -#if DYNAMIC_BMI2 - dctx->bmi2 = ZSTD_cpuSupportsBmi2(); -#endif - dctx->ddictSet = NULL; - ZSTD_DCtx_resetParameters(dctx); + dctx->bmi2 = 0; + dctx->outBufferMode = ZSTD_obm_buffered; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION dctx->dictContentEndForFuzzing = NULL; #endif @@ -293,10 +198,11 @@ ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize) return dctx; } -static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { - if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; +ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) +{ + if (!customMem.customAlloc ^ !customMem.customFree) return NULL; - { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem); + { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem); if (!dctx) return NULL; dctx->customMem = customMem; ZSTD_initDCtx_internal(dctx); @@ -304,15 +210,10 @@ static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) { } } -ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem) -{ - return ZSTD_createDCtx_internal(customMem); -} - ZSTD_DCtx* ZSTD_createDCtx(void) { DEBUGLOG(3, "ZSTD_createDCtx"); - return ZSTD_createDCtx_internal(ZSTD_defaultCMem); + return ZSTD_createDCtx_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); } static void ZSTD_clearDict(ZSTD_DCtx* dctx) @@ -329,17 +230,13 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx"); { ZSTD_customMem const cMem = dctx->customMem; ZSTD_clearDict(dctx); - ZSTD_customFree(dctx->inBuff, cMem); + ZSTD_free(dctx->inBuff, cMem); dctx->inBuff = NULL; #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (dctx->legacyContext) ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); #endif - if (dctx->ddictSet) { - ZSTD_freeDDictHashSet(dctx->ddictSet, cMem); - dctx->ddictSet = NULL; - } - ZSTD_customFree(dctx, cMem); + ZSTD_free(dctx, cMem); return 0; } } @@ -348,30 +245,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx); - ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ -} - -/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on - * the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then - * accordingly sets the ddict to be used to decompress the frame. - * - * If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is. - * - * ZSTD_d_refMultipleDDicts must be enabled for this function to be called. - */ -static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) { - assert(dctx->refMultipleDDicts && dctx->ddictSet); - DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame"); - if (dctx->ddict) { - const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID); - if (frameDDict) { - DEBUGLOG(4, "DDict found!"); - ZSTD_clearDict(dctx); - dctx->dictID = dctx->fParams.dictID; - dctx->ddict = frameDDict; - dctx->dictUses = ZSTD_use_indefinitely; - } - } + memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */ } @@ -397,19 +271,8 @@ unsigned ZSTD_isFrame(const void* buffer, size_t size) return 0; } -/*! ZSTD_isSkippableFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. - * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. - */ -unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size) -{ - if (size < ZSTD_FRAMEIDSIZE) return 0; - { U32 const magic = MEM_readLE32(buffer); - if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1; - } - return 0; -} - +static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; +static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; /** ZSTD_frameHeaderSize_internal() : * srcSize must be large enough to reach header size fields. * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless. @@ -445,47 +308,23 @@ size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless * @return : 0, `zfhPtr` is correctly filled, * >0, `srcSize` is too small, value is wanted `srcSize` amount, -** or an error code, which can be tested using ZSTD_isError() */ + * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format) { const BYTE* ip = (const BYTE*)src; size_t const minInputSize = ZSTD_startingInputLength(format); - DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize); - - if (srcSize > 0) { - /* note : technically could be considered an assert(), since it's an invalid entry */ - RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0"); - } - if (srcSize < minInputSize) { - if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) { - /* when receiving less than @minInputSize bytes, - * control these bytes at least correspond to a supported magic number - * in order to error out early if they don't. - **/ - size_t const toCopy = MIN(4, srcSize); - unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER); - assert(src != NULL); - ZSTD_memcpy(hbuf, src, toCopy); - if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) { - /* not a zstd frame : let's check if it's a skippable frame */ - MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START); - ZSTD_memcpy(hbuf, src, toCopy); - if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) { - RETURN_ERROR(prefix_unknown, - "first bytes don't correspond to any supported magic number"); - } } } - return minInputSize; - } + memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */ + if (srcSize < minInputSize) return minInputSize; + RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter"); - ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */ if ( (format != ZSTD_f_zstd1_magicless) && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) { if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ if (srcSize < ZSTD_SKIPPABLEHEADERSIZE) return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */ - ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); + memset(zfhPtr, 0, sizeof(*zfhPtr)); zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE); zfhPtr->frameType = ZSTD_skippableFrame; return 0; @@ -520,9 +359,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(dictIDSizeCode) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : break; case 1 : dictID = ip[pos]; pos++; break; case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break; @@ -530,9 +367,7 @@ size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, s } switch(fcsID) { - default: - assert(0); /* impossible */ - ZSTD_FALLTHROUGH; + default: assert(0); /* impossible */ case 0 : if (singleSegment) frameContentSize = ip[pos]; break; case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break; case 2 : frameContentSize = MEM_readLE32(ip+pos); break; @@ -561,6 +396,7 @@ size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t src return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1); } + /** ZSTD_getFrameContentSize() : * compatible with legacy mode * @return : decompressed size of the single frame pointed to be `src` if known, otherwise @@ -594,52 +430,18 @@ static size_t readSkippableFrameSize(void const* src, size_t srcSize) sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE); RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32, frameParameter_unsupported, ""); - { size_t const skippableSize = skippableHeaderSize + sizeU32; + { + size_t const skippableSize = skippableHeaderSize + sizeU32; RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, ""); return skippableSize; } } -/*! ZSTD_readSkippableFrame() : - * Retrieves content of a skippable frame, and writes it to dst buffer. - * - * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, - * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested - * in the magicVariant. - * - * Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame. - * - * @return : number of bytes written or a ZSTD error. - */ -size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, - unsigned* magicVariant, /* optional, can be NULL */ - const void* src, size_t srcSize) -{ - RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, ""); - - { U32 const magicNumber = MEM_readLE32(src); - size_t skippableFrameSize = readSkippableFrameSize(src, srcSize); - size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE; - - /* check input validity */ - RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, ""); - RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, ""); - RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, ""); - - /* deliver payload */ - if (skippableContentSize > 0 && dst != NULL) - ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize); - if (magicVariant != NULL) - *magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START; - return skippableContentSize; - } -} - /** ZSTD_findDecompressedSize() : + * compatible with legacy mode * `srcSize` must be the exact length of some number of ZSTD compressed and/or * skippable frames - * note: compatible with legacy mode - * @return : decompressed size of the frames contained */ + * @return : decompressed size of the frames contained */ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) { unsigned long long totalDstSize = 0; @@ -649,7 +451,9 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { size_t const skippableSize = readSkippableFrameSize(src, srcSize); - if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR; + if (ZSTD_isError(skippableSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; @@ -657,17 +461,17 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize) continue; } - { unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize); - if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs; + { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize); + if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret; - if (totalDstSize + fcs < totalDstSize) - return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */ - totalDstSize += fcs; + /* check for overflow */ + if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR; + totalDstSize += ret; } - /* skip to next frame */ { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize); - if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR; - assert(frameSrcSize <= srcSize); + if (ZSTD_isError(frameSrcSize)) { + return ZSTD_CONTENTSIZE_ERROR; + } src = (const BYTE *)src + frameSrcSize; srcSize -= frameSrcSize; @@ -697,19 +501,12 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize) /** ZSTD_decodeFrameHeader() : * `headerSize` must be the size provided by ZSTD_frameHeaderSize(). - * If multiple DDict references are enabled, also will choose the correct DDict to use. * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize) { size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format); if (ZSTD_isError(result)) return result; /* invalid header */ RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small"); - - /* Reference DDict requested by frame if dctx references multiple ddicts */ - if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) { - ZSTD_DCtx_selectFrameDDict(dctx); - } - #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Skip the dictID check in fuzzing mode, because it makes the search * harder. @@ -717,9 +514,7 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID), dictionary_wrong, ""); #endif - dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0; - if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0); - dctx->processedCSize += headerSize; + if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0); return 0; } @@ -731,17 +526,17 @@ static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret) return frameSizeInfo; } -static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize, ZSTD_format_e format) +static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize) { ZSTD_frameSizeInfo frameSizeInfo; - ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); + memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo)); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) - if (format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) + if (ZSTD_isLegacy(src, srcSize)) return ZSTD_findFrameSizeInfoLegacy(src, srcSize); #endif - if (format == ZSTD_f_zstd1 && (srcSize >= ZSTD_SKIPPABLEHEADERSIZE) + if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE) && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize); assert(ZSTD_isError(frameSizeInfo.compressedSize) || @@ -755,7 +550,7 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ZSTD_frameHeader zfh; /* Extract Frame Header */ - { size_t const ret = ZSTD_getFrameHeader_advanced(&zfh, src, srcSize, format); + { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize); if (ZSTD_isError(ret)) return ZSTD_errorFrameSizeInfo(ret); if (ret > 0) @@ -772,11 +567,11 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize if (ZSTD_isError(cBlockSize)) return ZSTD_errorFrameSizeInfo(cBlockSize); - if (ZSTD_blockHeaderSize + cBlockSize > remainingSize) + if (ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize > remainingSize) return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong)); - ip += ZSTD_blockHeaderSize + cBlockSize; - remainingSize -= ZSTD_blockHeaderSize + cBlockSize; + ip += ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize; + remainingSize -= ZSTDInternalConstants::ZSTD_blockHeaderSize + cBlockSize; nbBlocks++; if (blockProperties.lastBlock) break; @@ -789,26 +584,23 @@ static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize ip += 4; } - frameSizeInfo.nbBlocks = nbBlocks; - frameSizeInfo.compressedSize = (size_t)(ip - ipstart); + frameSizeInfo.compressedSize = ip - ipstart; frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) ? zfh.frameContentSize - : (unsigned long long)nbBlocks * zfh.blockSizeMax; + : nbBlocks * zfh.blockSizeMax; return frameSizeInfo; } } -static size_t ZSTD_findFrameCompressedSize_advanced(const void *src, size_t srcSize, ZSTD_format_e format) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, format); - return frameSizeInfo.compressedSize; -} - /** ZSTD_findFrameCompressedSize() : - * See docs in zstd.h - * Note: compatible with legacy mode */ + * compatible with legacy mode + * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame + * `srcSize` must be at least as large as the frame contained + * @return : the compressed size of the frame starting at `src` */ size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize) { - return ZSTD_findFrameCompressedSize_advanced(src, srcSize, ZSTD_f_zstd1); + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); + return frameSizeInfo.compressedSize; } /** ZSTD_decompressBound() : @@ -822,7 +614,7 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) unsigned long long bound = 0; /* Iterate over each frame */ while (srcSize > 0) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1); + ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize); size_t const compressedSize = frameSizeInfo.compressedSize; unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) @@ -835,48 +627,6 @@ unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize) return bound; } -size_t ZSTD_decompressionMargin(void const* src, size_t srcSize) -{ - size_t margin = 0; - unsigned maxBlockSize = 0; - - /* Iterate over each frame */ - while (srcSize > 0) { - ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1); - size_t const compressedSize = frameSizeInfo.compressedSize; - unsigned long long const decompressedBound = frameSizeInfo.decompressedBound; - ZSTD_frameHeader zfh; - - FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), ""); - if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR) - return ERROR(corruption_detected); - - if (zfh.frameType == ZSTD_frame) { - /* Add the frame header to our margin */ - margin += zfh.headerSize; - /* Add the checksum to our margin */ - margin += zfh.checksumFlag ? 4 : 0; - /* Add 3 bytes per block */ - margin += 3 * frameSizeInfo.nbBlocks; - - /* Compute the max block size */ - maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax); - } else { - assert(zfh.frameType == ZSTD_skippableFrame); - /* Add the entire skippable frame size to our margin. */ - margin += compressedSize; - } - - assert(srcSize >= compressedSize); - src = (const BYTE*)src + compressedSize; - srcSize -= compressedSize; - } - - /* Add the max block size back to the margin. */ - margin += maxBlockSize; - - return margin; -} /*-************************************************************* * Frame decoding @@ -887,7 +637,7 @@ size_t ZSTD_decompressionMargin(void const* src, size_t srcSize) size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize) { DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize); - ZSTD_checkContinuity(dctx, blockStart, blockSize); + ZSTD_checkContinuity(dctx, blockStart); dctx->previousDstEnd = (const char*)blockStart + blockSize; return blockSize; } @@ -897,12 +647,12 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_copyRawBlock"); - RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (srcSize == 0) return 0; RETURN_ERROR(dstBuffer_null, ""); } - ZSTD_memmove(dst, src, srcSize); + RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, ""); + memcpy(dst, src, srcSize); return srcSize; } @@ -910,41 +660,15 @@ static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity, BYTE b, size_t regenSize) { - RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); if (dst == NULL) { if (regenSize == 0) return 0; RETURN_ERROR(dstBuffer_null, ""); } - ZSTD_memset(dst, b, regenSize); + RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, ""); + memset(dst, b, regenSize); return regenSize; } -static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming) -{ -#if ZSTD_TRACE - if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { - ZSTD_Trace trace; - ZSTD_memset(&trace, 0, sizeof(trace)); - trace.version = ZSTD_VERSION_NUMBER; - trace.streaming = streaming; - if (dctx->ddict) { - trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); - trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); - trace.dictionaryIsCold = dctx->ddictIsCold; - } - trace.uncompressedSize = (size_t)uncompressedSize; - trace.compressedSize = (size_t)compressedSize; - trace.dctx = dctx; - ZSTD_trace_decompress_end(dctx->traceCtx, &trace); - } -#else - (void)dctx; - (void)uncompressedSize; - (void)compressedSize; - (void)streaming; -#endif -} - /*! ZSTD_decompressFrame() : * @dctx must be properly initialized @@ -954,9 +678,8 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void** srcPtr, size_t *srcSizePtr) { - const BYTE* const istart = (const BYTE*)(*srcPtr); - const BYTE* ip = istart; - BYTE* const ostart = (BYTE*)dst; + const BYTE* ip = (const BYTE*)(*srcPtr); + BYTE* const ostart = (BYTE* const)dst; BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart; BYTE* op = ostart; size_t remainingSrcSize = *srcSizePtr; @@ -965,77 +688,51 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* check */ RETURN_ERROR_IF( - remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize, + remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTDInternalConstants::ZSTD_blockHeaderSize, srcSize_wrong, ""); /* Frame Header */ { size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal( ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; - RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize, + RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTDInternalConstants::ZSTD_blockHeaderSize, srcSize_wrong, ""); FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , ""); ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize; } - /* Shrink the blockSizeMax if enabled */ - if (dctx->maxBlockSizeParam != 0) - dctx->fParams.blockSizeMax = MIN(dctx->fParams.blockSizeMax, (unsigned)dctx->maxBlockSizeParam); - /* Loop on each block */ while (1) { - BYTE* oBlockEnd = oend; size_t decodedSize; blockProperties_t blockProperties; size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; - ip += ZSTD_blockHeaderSize; - remainingSrcSize -= ZSTD_blockHeaderSize; + ip += ZSTDInternalConstants::ZSTD_blockHeaderSize; + remainingSrcSize -= ZSTDInternalConstants::ZSTD_blockHeaderSize; RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, ""); - if (ip >= op && ip < oBlockEnd) { - /* We are decompressing in-place. Limit the output pointer so that we - * don't overwrite the block that we are currently reading. This will - * fail decompression if the input & output pointers aren't spaced - * far enough apart. - * - * This is important to set, even when the pointers are far enough - * apart, because ZSTD_decompressBlock_internal() can decide to store - * literals in the output buffer, after the block it is decompressing. - * Since we don't want anything to overwrite our input, we have to tell - * ZSTD_decompressBlock_internal to never write past ip. - * - * See ZSTD_allocateLiteralsBuffer() for reference. - */ - oBlockEnd = op + (ip - op); - } - switch(blockProperties.blockType) { case bt_compressed: - assert(dctx->isFrameDecompression == 1); - decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, not_streaming); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1); break; case bt_raw : - /* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */ - decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize); + decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); break; case bt_rle : - decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize); + decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize); break; case bt_reserved : default: RETURN_ERROR(corruption_detected, "invalid block type"); } - FORWARD_IF_ERROR(decodedSize, "Block decompression failure"); - DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize); - if (dctx->validateChecksum) { + + if (ZSTD_isError(decodedSize)) return decodedSize; + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize); - } - if (decodedSize) /* support dst = NULL,0 */ { + if (decodedSize != 0) op += decodedSize; - } assert(ip != NULL); ip += cBlockSize; remainingSrcSize -= cBlockSize; @@ -1047,27 +744,22 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, corruption_detected, ""); } if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */ + U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); + U32 checkRead; RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, ""); - if (!dctx->forceIgnoreChecksum) { - U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState); - U32 checkRead; - checkRead = MEM_readLE32(ip); - RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); - } + checkRead = MEM_readLE32(ip); + RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, ""); ip += 4; remainingSrcSize -= 4; } - ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0); + /* Allow caller to get size read */ - DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr); *srcPtr = ip; *srcSizePtr = remainingSrcSize; - return (size_t)(op-ostart); + return op-ostart; } -static -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, +static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, @@ -1087,7 +779,7 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, while (srcSize >= ZSTD_startingInputLength(dctx->format)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) - if (dctx->format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) { + if (ZSTD_isLegacy(src, srcSize)) { size_t decodedSize; size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize); if (ZSTD_isError(frameSize)) return frameSize; @@ -1097,16 +789,7 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize); if (ZSTD_isError(decodedSize)) return decodedSize; - { - unsigned long long const expectedSize = ZSTD_getFrameContentSize(src, srcSize); - RETURN_ERROR_IF(expectedSize == ZSTD_CONTENTSIZE_ERROR, corruption_detected, "Corrupted frame header!"); - if (expectedSize != ZSTD_CONTENTSIZE_UNKNOWN) { - RETURN_ERROR_IF(expectedSize != decodedSize, corruption_detected, - "Frame header size does not match decoded size!"); - } - } - - assert(decodedSize <= dstCapacity); + assert(decodedSize <=- dstCapacity); dst = (BYTE*)dst + decodedSize; dstCapacity -= decodedSize; @@ -1117,18 +800,17 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, } #endif - if (dctx->format == ZSTD_f_zstd1 && srcSize >= 4) { - U32 const magicNumber = MEM_readLE32(src); - DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber); + { U32 const magicNumber = MEM_readLE32(src); + DEBUGLOG(4, "reading magic number %08X (expecting %08X)", + (unsigned)magicNumber, ZSTD_MAGICNUMBER); if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { - /* skippable frame detected : skip it */ size_t const skippableSize = readSkippableFrameSize(src, srcSize); - FORWARD_IF_ERROR(skippableSize, "invalid skippable frame"); + FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed"); assert(skippableSize <= srcSize); src = (const BYTE *)src + skippableSize; srcSize -= skippableSize; - continue; /* check next frame */ + continue; } } if (ddict) { @@ -1139,7 +821,7 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, * use this in all cases but ddict */ FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), ""); } - ZSTD_checkContinuity(dctx, dst, dstCapacity); + ZSTD_checkContinuity(dctx, dst); { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity, &src, &srcSize); @@ -1147,13 +829,15 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown) && (moreThan1Frame==1), srcSize_wrong, - "At least one frame successfully completed, " - "but following bytes are garbage: " - "it's more likely to be a srcSize error, " - "specifying more input bytes than size of frame(s). " - "Note: one could be unlucky, it might be a corruption error instead, " - "happening right at the place where we expect zstd magic bytes. " - "But this is _much_ less likely than a srcSize field error."); + "at least one frame successfully completed, but following " + "bytes are garbage: it's more likely to be a srcSize error, " + "specifying more bytes than compressed size of frame(s). This " + "error message replaces ERROR(prefix_unknown), which would be " + "confusing, as the first header is actually correct. Note that " + "one could be unlucky, it might be a corruption error instead, " + "happening right at the place where we expect zstd magic " + "bytes. But this is _much_ less likely than a srcSize field " + "error."); if (ZSTD_isError(res)) return res; assert(res <= dstCapacity); if (res != 0) @@ -1165,7 +849,7 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx, RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed"); - return (size_t)((BYTE*)dst - (BYTE*)dststart); + return (BYTE*)dst - (BYTE*)dststart; } size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, @@ -1182,7 +866,7 @@ static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx) switch (dctx->dictUses) { default: assert(0 /* Impossible */); - ZSTD_FALLTHROUGH; + /* fall-through */ case ZSTD_dont_use: ZSTD_clearDict(dctx); return NULL; @@ -1204,7 +888,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1) size_t regenSize; - ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem); + ZSTD_DCtx* const dctx = ZSTD_createDCtx(); RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!"); regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); ZSTD_freeDCtx(dctx); @@ -1224,8 +908,8 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } /** - * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we - * allow taking a partial block as the input. Currently only raw uncompressed blocks can + * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed, + * we allow taking a partial block as the input. Currently only raw uncompressed blocks can * be streamed. * * For blocks that can be streamed, this allows us to reduce the latency until we produce @@ -1238,7 +922,7 @@ static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t return dctx->expected; if (dctx->bType != bt_raw) return dctx->expected; - return BOUNDED(1, inputSize, dctx->expected); + return MIN(MAX(inputSize, 1), dctx->expected); } ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { @@ -1246,9 +930,7 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { { default: /* should not happen */ assert(0); - ZSTD_FALLTHROUGH; case ZSTDds_getFrameHeaderSize: - ZSTD_FALLTHROUGH; case ZSTDds_decodeFrameHeader: return ZSTDnit_frameHeader; case ZSTDds_decodeBlockHeader: @@ -1260,7 +942,6 @@ ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) { case ZSTDds_checkChecksum: return ZSTDnit_checksum; case ZSTDds_decodeSkippableHeader: - ZSTD_FALLTHROUGH; case ZSTDds_skipFrame: return ZSTDnit_skippableFrame; } @@ -1277,9 +958,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize); /* Sanity check */ RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed"); - ZSTD_checkContinuity(dctx, dst, dstCapacity); - - dctx->processedCSize += srcSize; + if (dstCapacity) ZSTD_checkContinuity(dctx, dst); switch (dctx->stage) { @@ -1288,29 +967,29 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c if (dctx->format == ZSTD_f_zstd1) { /* allows header */ assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */ if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ - ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */ dctx->stage = ZSTDds_decodeSkippableHeader; return 0; } } dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; - ZSTD_memcpy(dctx->headerBuffer, src, srcSize); + memcpy(dctx->headerBuffer, src, srcSize); dctx->expected = dctx->headerSize - srcSize; dctx->stage = ZSTDds_decodeFrameHeader; return 0; case ZSTDds_decodeFrameHeader: assert(src != NULL); - ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); + memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize); FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), ""); - dctx->expected = ZSTD_blockHeaderSize; + dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; return 0; case ZSTDds_decodeBlockHeader: { blockProperties_t bp; - size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); + size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTDInternalConstants::ZSTD_blockHeaderSize, &bp); if (ZSTD_isError(cBlockSize)) return cBlockSize; RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum"); dctx->expected = cBlockSize; @@ -1330,7 +1009,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->stage = ZSTDds_getFrameHeaderSize; } } else { - dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */ + dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; /* jump to next header */ dctx->stage = ZSTDds_decodeBlockHeader; } return 0; @@ -1344,8 +1023,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c { case bt_compressed: DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed"); - assert(dctx->isFrameDecompression == 1); - rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, is_streaming); + rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1); dctx->expected = 0; /* Streaming not supported */ break; case bt_raw : @@ -1367,7 +1045,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum"); DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize); dctx->decodedSize += rSize; - if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize); + if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize); dctx->previousDstEnd = (char*)dst + rSize; /* Stay on the same stage until we are finished streaming the block. */ @@ -1385,27 +1063,22 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c dctx->expected = 4; dctx->stage = ZSTDds_checkChecksum; } else { - ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); dctx->expected = 0; /* ends here */ dctx->stage = ZSTDds_getFrameHeaderSize; } } else { dctx->stage = ZSTDds_decodeBlockHeader; - dctx->expected = ZSTD_blockHeaderSize; + dctx->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; } return rSize; } case ZSTDds_checkChecksum: assert(srcSize == 4); /* guaranteed by dctx->expected */ - { - if (dctx->validateChecksum) { - U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); - U32 const check32 = MEM_readLE32(src); - DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); - RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); - } - ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1); + { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState); + U32 const check32 = MEM_readLE32(src); + DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32); + RETURN_ERROR_IF(check32 != h32, checksum_wrong, ""); dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; return 0; @@ -1414,8 +1087,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c case ZSTDds_decodeSkippableHeader: assert(src != NULL); assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE); - assert(dctx->format != ZSTD_f_zstd1_magicless); - ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ + memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */ dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */ dctx->stage = ZSTDds_skipFrame; return 0; @@ -1427,7 +1099,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ } } @@ -1468,11 +1140,11 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, /* in minimal huffman, we always use X1 variants */ size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable, dictPtr, dictEnd - dictPtr, - workspace, workspaceSize, /* flags */ 0); + workspace, workspaceSize); #else size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable, - dictPtr, (size_t)(dictEnd - dictPtr), - workspace, workspaceSize, /* flags */ 0); + dictPtr, dictEnd - dictPtr, + workspace, workspaceSize); #endif RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, ""); dictPtr += hSize; @@ -1480,46 +1152,40 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, { short offcodeNCount[MaxOff+1]; unsigned offcodeMaxValue = MaxOff, offcodeLog; - size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr)); + size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, ""); RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->OFTable, offcodeNCount, offcodeMaxValue, - OF_base, OF_bits, - offcodeLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */0); + ZSTDConstants::OF_base, ZSTDConstants::OF_bits, + offcodeLog); dictPtr += offcodeHeaderSize; } { short matchlengthNCount[MaxML+1]; unsigned matchlengthMaxValue = MaxML, matchlengthLog; - size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, ""); RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->MLTable, matchlengthNCount, matchlengthMaxValue, - ML_base, ML_bits, - matchlengthLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */ 0); + ZSTDConstants::ML_base, ZSTDInternalConstants::ML_bits, + matchlengthLog); dictPtr += matchlengthHeaderSize; } { short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog; - size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr)); + size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, ""); RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); ZSTD_buildFSETable( entropy->LLTable, litlengthNCount, litlengthMaxValue, - LL_base, LL_bits, - litlengthLog, - entropy->workspace, sizeof(entropy->workspace), - /* bmi2 */ 0); + ZSTDConstants::LL_base, ZSTDInternalConstants::LL_bits, + litlengthLog); dictPtr += litlengthHeaderSize; } @@ -1533,7 +1199,7 @@ ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, entropy->rep[i] = rep; } } - return (size_t)(dictPtr - (const BYTE*)dict); + return dictPtr - (const BYTE*)dict; } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) @@ -1557,27 +1223,24 @@ static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict return ZSTD_refDictContent(dctx, dict, dictSize); } +static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; + size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { assert(dctx != NULL); -#if ZSTD_TRACE - dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; -#endif dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */ dctx->stage = ZSTDds_getFrameHeaderSize; - dctx->processedCSize = 0; dctx->decodedSize = 0; dctx->previousDstEnd = NULL; dctx->prefixStart = NULL; dctx->virtualStart = NULL; dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ + dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; dctx->bType = bt_reserved; - dctx->isFrameDecompression = 1; ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue)); - ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ + memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */ dctx->LLTptr = dctx->entropy.LLTable; dctx->MLTptr = dctx->entropy.MLTable; dctx->OFTptr = dctx->entropy.OFTable; @@ -1634,7 +1297,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * This could for one of the following reasons : * - The frame does not require a dictionary (most common case). * - The frame was built with dictID intentionally removed. - * Needed dictionary is a hidden piece of information. + * Needed dictionary is a hidden information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, frame header could not be decoded. * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`. @@ -1643,7 +1306,7 @@ unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize) * ZSTD_getFrameHeader(), which will provide a more precise error code. */ unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize) { - ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 }; + ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 }; size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize); if (ZSTD_isError(hError)) return 0; return zfp.dictID; @@ -1672,7 +1335,7 @@ size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, ZSTD_DStream* ZSTD_createDStream(void) { DEBUGLOG(3, "ZSTD_createDStream"); - return ZSTD_createDCtx_internal(ZSTD_defaultCMem); + return ZSTD_createDStream_advanced(ZSTDInternalConstants::ZSTD_defaultCMem); } ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) @@ -1682,7 +1345,7 @@ ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize) ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem) { - return ZSTD_createDCtx_internal(customMem); + return ZSTD_createDCtx_advanced(customMem); } size_t ZSTD_freeDStream(ZSTD_DStream* zds) @@ -1693,7 +1356,7 @@ size_t ZSTD_freeDStream(ZSTD_DStream* zds) /* *** Initialization *** */ -size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; } +size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTDInternalConstants::ZSTD_blockHeaderSize; } size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, @@ -1750,9 +1413,7 @@ size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t di size_t ZSTD_initDStream(ZSTD_DStream* zds) { DEBUGLOG(4, "ZSTD_initDStream"); - FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), ""); - FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), ""); - return ZSTD_startingInputLength(zds->format); + return ZSTD_initDStream_usingDDict(zds, NULL); } /* ZSTD_initDStream_usingDDict() : @@ -1760,7 +1421,6 @@ size_t ZSTD_initDStream(ZSTD_DStream* zds) * this function cannot fail */ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) { - DEBUGLOG(4, "ZSTD_initDStream_usingDDict"); FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , ""); FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , ""); return ZSTD_startingInputLength(dctx->format); @@ -1771,7 +1431,6 @@ size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict) * this function cannot fail */ size_t ZSTD_resetDStream(ZSTD_DStream* dctx) { - DEBUGLOG(4, "ZSTD_resetDStream"); FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), ""); return ZSTD_startingInputLength(dctx->format); } @@ -1784,16 +1443,6 @@ size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) if (ddict) { dctx->ddict = ddict; dctx->dictUses = ZSTD_use_indefinitely; - if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) { - if (dctx->ddictSet == NULL) { - dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem); - if (!dctx->ddictSet) { - RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!"); - } - } - assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */ - FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), ""); - } } return 0; } @@ -1815,7 +1464,7 @@ size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize) size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format) { - return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format); + return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format); } ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) @@ -1832,26 +1481,9 @@ ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam) ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); return bounds; case ZSTD_d_stableOutBuffer: - bounds.lowerBound = (int)ZSTD_bm_buffered; - bounds.upperBound = (int)ZSTD_bm_stable; - return bounds; - case ZSTD_d_forceIgnoreChecksum: - bounds.lowerBound = (int)ZSTD_d_validateChecksum; - bounds.upperBound = (int)ZSTD_d_ignoreChecksum; - return bounds; - case ZSTD_d_refMultipleDDicts: - bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict; - bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts; - return bounds; - case ZSTD_d_disableHuffmanAssembly: - bounds.lowerBound = 0; - bounds.upperBound = 1; - return bounds; - case ZSTD_d_maxBlockSize: - bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; - bounds.upperBound = ZSTD_BLOCKSIZE_MAX; + bounds.lowerBound = (int)ZSTD_obm_buffered; + bounds.upperBound = (int)ZSTD_obm_stable; return bounds; - default:; } bounds.error = ERROR(parameter_unsupported); @@ -1874,35 +1506,6 @@ static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value) RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \ } -size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value) -{ - switch (param) { - case ZSTD_d_windowLogMax: - *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize); - return 0; - case ZSTD_d_format: - *value = (int)dctx->format; - return 0; - case ZSTD_d_stableOutBuffer: - *value = (int)dctx->outBufferMode; - return 0; - case ZSTD_d_forceIgnoreChecksum: - *value = (int)dctx->forceIgnoreChecksum; - return 0; - case ZSTD_d_refMultipleDDicts: - *value = (int)dctx->refMultipleDDicts; - return 0; - case ZSTD_d_disableHuffmanAssembly: - *value = (int)dctx->disableHufAsm; - return 0; - case ZSTD_d_maxBlockSize: - *value = dctx->maxBlockSizeParam; - return 0; - default:; - } - RETURN_ERROR(parameter_unsupported, ""); -} - size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value) { RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); @@ -1918,26 +1521,7 @@ size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value return 0; case ZSTD_d_stableOutBuffer: CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value); - dctx->outBufferMode = (ZSTD_bufferMode_e)value; - return 0; - case ZSTD_d_forceIgnoreChecksum: - CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value); - dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value; - return 0; - case ZSTD_d_refMultipleDDicts: - CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value); - if (dctx->staticSize != 0) { - RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!"); - } - dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value; - return 0; - case ZSTD_d_disableHuffmanAssembly: - CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value); - dctx->disableHufAsm = value != 0; - return 0; - case ZSTD_d_maxBlockSize: - if (value != 0) CHECK_DBOUNDS(ZSTD_d_maxBlockSize, value); - dctx->maxBlockSizeParam = value; + dctx->outBufferMode = (ZSTD_outBufferMode_e)value; return 0; default:; } @@ -1950,13 +1534,13 @@ size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset) || (reset == ZSTD_reset_session_and_parameters) ) { dctx->streamStage = zdss_init; dctx->noForwardProgress = 0; - dctx->isFrameDecompression = 1; } if ( (reset == ZSTD_reset_parameters) || (reset == ZSTD_reset_session_and_parameters) ) { RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, ""); ZSTD_clearDict(dctx); - ZSTD_DCtx_resetParameters(dctx); + dctx->format = ZSTD_f_zstd1; + dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT; } return 0; } @@ -1967,17 +1551,10 @@ size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx) return ZSTD_sizeof_DCtx(dctx); } -static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, unsigned long long frameContentSize, size_t blockSizeMax) +size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) { - size_t const blockSize = MIN((size_t)MIN(windowSize, ZSTD_BLOCKSIZE_MAX), blockSizeMax); - /* We need blockSize + WILDCOPY_OVERLENGTH worth of buffer so that if a block - * ends at windowSize + WILDCOPY_OVERLENGTH + 1 bytes, we can start writing - * the block at the beginning of the output buffer, and maintain a full window. - * - * We need another blockSize worth of buffer so that we can store split - * literals at the end of the block without overwriting the extDict window. - */ - unsigned long long const neededRBSize = windowSize + (blockSize * 2) + (WILDCOPY_OVERLENGTH * 2); + size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX); + unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2); unsigned long long const neededSize = MIN(frameContentSize, neededRBSize); size_t const minRBSize = (size_t) neededSize; RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize, @@ -1985,11 +1562,6 @@ static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, un return minRBSize; } -size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize) -{ - return ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX); -} - size_t ZSTD_estimateDStreamSize(size_t windowSize) { size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX); @@ -2036,7 +1608,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* { ZSTD_outBuffer const expect = zds->expectedOutBuffer; /* No requirement when ZSTD_obm_stable is not enabled. */ - if (zds->outBufferMode != ZSTD_bm_stable) + if (zds->outBufferMode != ZSTD_obm_stable) return 0; /* Any buffer is allowed in zdss_init, this must be the same for every other call until * the context is reset. @@ -2046,7 +1618,7 @@ static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* /* The buffer must match our expectation exactly. */ if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size) return 0; - RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!"); + RETURN_ERROR(dstBuffer_wrong, "ZSTD_obm_stable enabled but output differs!"); } /* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream() @@ -2058,7 +1630,7 @@ static size_t ZSTD_decompressContinueStream( ZSTD_DStream* zds, char** op, char* oend, void const* src, size_t srcSize) { int const isSkipFrame = ZSTD_isSkipFrame(zds); - if (zds->outBufferMode == ZSTD_bm_buffered) { + if (zds->outBufferMode == ZSTD_obm_buffered) { size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart; size_t const decodedSize = ZSTD_decompressContinue(zds, zds->outBuff + zds->outStart, dstSize, src, srcSize); @@ -2071,14 +1643,14 @@ static size_t ZSTD_decompressContinueStream( } } else { /* Write directly into the output buffer */ - size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op); + size_t const dstSize = isSkipFrame ? 0 : oend - *op; size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize); FORWARD_IF_ERROR(decodedSize, ""); *op += decodedSize; /* Flushing is not needed. */ zds->streamStage = zdss_read; assert(*op <= oend); - assert(zds->outBufferMode == ZSTD_bm_stable); + assert(zds->outBufferMode == ZSTD_obm_stable); } return 0; } @@ -2116,12 +1688,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(5, "stage zdss_init => transparent reset "); zds->streamStage = zdss_loadHeader; zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) zds->legacyVersion = 0; -#endif zds->hostageByte = 0; zds->expectedOutBuffer = *output; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_loadHeader : DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip)); @@ -2135,9 +1705,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } #endif { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format); - if (zds->refMultipleDDicts && zds->ddictSet) { - ZSTD_DCtx_selectFrameDDict(zds); - } + DEBUGLOG(5, "header size : %u", (U32)hSize); if (ZSTD_isError(hSize)) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart); @@ -2165,19 +1733,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB assert(iend >= ip); if (toLoad > remainingInput) { /* not enough input to load full header */ if (remainingInput > 0) { - ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); + memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput); zds->lhSize += remainingInput; } input->pos = input->size; - /* check first few bytes */ - FORWARD_IF_ERROR( - ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format), - "First few bytes detected incorrect" ); - /* return hint input size */ - return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ + return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTDInternalConstants::ZSTD_blockHeaderSize; /* remaining header bytes + next block header */ } assert(ip != NULL); - ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; + memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad; break; } } @@ -2185,15 +1748,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && zds->fParams.frameType != ZSTD_skippableFrame && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) { - size_t const cSize = ZSTD_findFrameCompressedSize_advanced(istart, (size_t)(iend-istart), zds->format); + size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart); if (cSize <= (size_t)(iend-istart)) { /* shortcut : using single-pass mode */ - size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds)); + size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds)); if (ZSTD_isError(decompressedSize)) return decompressedSize; - DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()"); - assert(istart != NULL); + DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()") ip = istart + cSize; - op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */ + op += decompressedSize; zds->expected = 0; zds->streamStage = zdss_init; someMoreWork = 0; @@ -2201,7 +1763,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } } /* Check output buffer is large enough for ZSTD_odm_stable. */ - if (zds->outBufferMode == ZSTD_bm_stable + if (zds->outBufferMode == ZSTD_obm_stable && zds->fParams.frameType != ZSTD_skippableFrame && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) { @@ -2212,13 +1774,12 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB DEBUGLOG(4, "Consume header"); FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), ""); - if (zds->format == ZSTD_f_zstd1 - && (MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ + if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */ zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE); zds->stage = ZSTDds_skipFrame; } else { FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), ""); - zds->expected = ZSTD_blockHeaderSize; + zds->expected = ZSTDInternalConstants::ZSTD_blockHeaderSize; zds->stage = ZSTDds_decodeBlockHeader; } @@ -2229,13 +1790,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN); RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize, frameParameter_windowTooLarge, ""); - if (zds->maxBlockSizeParam != 0) - zds->fParams.blockSizeMax = MIN(zds->fParams.blockSizeMax, (unsigned)zds->maxBlockSizeParam); /* Adapt buffer sizes to frame header instructions */ { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */); - size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered - ? ZSTD_decodingBufferSize_internal(zds->fParams.windowSize, zds->fParams.frameContentSize, zds->fParams.blockSizeMax) + size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_obm_buffered + ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize) : 0; ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize); @@ -2256,10 +1815,10 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB bufferSize > zds->staticSize - sizeof(ZSTD_DCtx), memory_allocation, ""); } else { - ZSTD_customFree(zds->inBuff, zds->customMem); + ZSTD_free(zds->inBuff, zds->customMem); zds->inBuffSize = 0; zds->outBuffSize = 0; - zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem); + zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem); RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, ""); } zds->inBuffSize = neededInBuffSize; @@ -2267,11 +1826,11 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB zds->outBuffSize = neededOutBuffSize; } } } zds->streamStage = zdss_read; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_read: DEBUGLOG(5, "stage zdss_read"); - { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)); + { size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip); DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize); if (neededInSize==0) { /* end of frame */ zds->streamStage = zdss_init; @@ -2280,14 +1839,13 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */ FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), ""); - assert(ip != NULL); ip += neededInSize; /* Function modifies the stage so we must break */ break; } } if (ip==iend) { someMoreWork = 0; break; } /* no more input */ zds->streamStage = zdss_load; - ZSTD_FALLTHROUGH; + /* fall-through */ case zdss_load: { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds); @@ -2295,20 +1853,17 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB int const isSkipFrame = ZSTD_isSkipFrame(zds); size_t loadedSize; /* At this point we shouldn't be decompressing a block that we can stream. */ - assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip))); + assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip)); if (isSkipFrame) { loadedSize = MIN(toLoad, (size_t)(iend-ip)); } else { RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos, corruption_detected, "should never happen"); - loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip)); - } - if (loadedSize != 0) { - /* ip may be NULL */ - ip += loadedSize; - zds->inPos += loadedSize; + loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip); } + ip += loadedSize; + zds->inPos += loadedSize; if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */ /* decode loaded input */ @@ -2318,17 +1873,14 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB break; } case zdss_flush: - { - size_t const toFlushSize = zds->outEnd - zds->outStart; - size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize); - - op = op ? op + flushedSize : op; - + { size_t const toFlushSize = zds->outEnd - zds->outStart; + size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize); + op += flushedSize; zds->outStart += flushedSize; if (flushedSize == toFlushSize) { /* flush completed */ zds->streamStage = zdss_read; if ( (zds->outBuffSize < zds->fParams.frameContentSize) - && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { + && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) { DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)", (int)(zds->outBuffSize - zds->outStart), (U32)zds->fParams.blockSizeMax); @@ -2342,7 +1894,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB default: assert(0); /* impossible */ - RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */ + RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */ } } /* result */ @@ -2355,8 +1907,8 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB if ((ip==istart) && (op==ostart)) { /* no forward progress */ zds->noForwardProgress ++; if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) { - RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, ""); - RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, ""); + RETURN_ERROR_IF(op==oend, dstSize_tooSmall, ""); + RETURN_ERROR_IF(ip==iend, srcSize_wrong, ""); assert(0); } } else { @@ -2381,7 +1933,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB } return 1; } /* nextSrcSizeHint==0 */ - nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ + nextSrcSizeHint += ZSTDInternalConstants::ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */ assert(zds->inPos <= nextSrcSizeHint); nextSrcSizeHint -= zds->inPos; /* part already loaded*/ return nextSrcSizeHint; @@ -2393,19 +1945,13 @@ size_t ZSTD_decompressStream_simpleArgs ( void* dst, size_t dstCapacity, size_t* dstPos, const void* src, size_t srcSize, size_t* srcPos) { - ZSTD_outBuffer output; - ZSTD_inBuffer input; - output.dst = dst; - output.size = dstCapacity; - output.pos = *dstPos; - input.src = src; - input.size = srcSize; - input.pos = *srcPos; - { size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); - *dstPos = output.pos; - *srcPos = input.pos; - return cErr; - } + ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; + ZSTD_inBuffer input = { src, srcSize, *srcPos }; + /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ + size_t const cErr = ZSTD_decompressStream(dctx, &output, &input); + *dstPos = output.pos; + *srcPos = input.pos; + return cErr; } -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp b/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp index 75955fdef..e86f19ce8 100644 --- a/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp +++ b/src/duckdb/third_party/zstd/decompress/zstd_decompress_block.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,19 +14,18 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ +#include /* memcpy, memmove, memset */ #include "zstd/common/compiler.h" /* prefetch */ -#include "zstd/common/cpu.h" /* bmi2 */ #include "zstd/common/mem.h" /* low level memory routines */ -#define FSE_STATIC_LINKING_ONLY #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" +#include "zstd/common/huf_static.h" #include "zstd/common/zstd_internal.h" #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_DCtx */ #include "zstd/decompress/zstd_ddict.h" /* ZSTD_DDictDictContent */ #include "zstd/decompress/zstd_decompress_block.h" -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ - +namespace duckdb_zstd { /*_******************************************************* * Macros **********************************************************/ @@ -40,31 +39,23 @@ #error "Cannot force the use of the short and the long ZSTD_decompressSequences variants!" #endif -namespace duckdb_zstd { /*_******************************************************* * Memory operations **********************************************************/ -static void ZSTD_copy4(void* dst, const void* src) { ZSTD_memcpy(dst, src, 4); } +static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } /*-************************************************************* * Block decoding ***************************************************************/ -static size_t ZSTD_blockSizeMax(ZSTD_DCtx const* dctx) -{ - size_t const blockSizeMax = dctx->isFrameDecompression ? dctx->fParams.blockSizeMax : ZSTD_BLOCKSIZE_MAX; - assert(blockSizeMax <= ZSTD_BLOCKSIZE_MAX); - return blockSizeMax; -} - /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { - RETURN_ERROR_IF(srcSize < ZSTD_blockHeaderSize, srcSize_wrong, ""); + RETURN_ERROR_IF(srcSize < ZSTDInternalConstants::ZSTD_blockHeaderSize, srcSize_wrong, ""); { U32 const cBlockHeader = MEM_readLE24(src); U32 const cSize = cBlockHeader >> 3; @@ -77,90 +68,36 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, } } -/* Allocate buffer for literals, either overlapping current dst, or split between dst and litExtraBuffer, or stored entirely within litExtraBuffer */ -static void ZSTD_allocateLiteralsBuffer(ZSTD_DCtx* dctx, void* const dst, const size_t dstCapacity, const size_t litSize, - const streaming_operation streaming, const size_t expectedWriteSize, const unsigned splitImmediately) -{ - size_t const blockSizeMax = ZSTD_blockSizeMax(dctx); - assert(litSize <= blockSizeMax); - assert(dctx->isFrameDecompression || streaming == not_streaming); - assert(expectedWriteSize <= blockSizeMax); - if (streaming == not_streaming && dstCapacity > blockSizeMax + WILDCOPY_OVERLENGTH + litSize + WILDCOPY_OVERLENGTH) { - /* If we aren't streaming, we can just put the literals after the output - * of the current block. We don't need to worry about overwriting the - * extDict of our window, because it doesn't exist. - * So if we have space after the end of the block, just put it there. - */ - dctx->litBuffer = (BYTE*)dst + blockSizeMax + WILDCOPY_OVERLENGTH; - dctx->litBufferEnd = dctx->litBuffer + litSize; - dctx->litBufferLocation = ZSTD_in_dst; - } else if (litSize <= ZSTD_LITBUFFEREXTRASIZE) { - /* Literals fit entirely within the extra buffer, put them there to avoid - * having to split the literals. - */ - dctx->litBuffer = dctx->litExtraBuffer; - dctx->litBufferEnd = dctx->litBuffer + litSize; - dctx->litBufferLocation = ZSTD_not_in_dst; - } else { - assert(blockSizeMax > ZSTD_LITBUFFEREXTRASIZE); - /* Literals must be split between the output block and the extra lit - * buffer. We fill the extra lit buffer with the tail of the literals, - * and put the rest of the literals at the end of the block, with - * WILDCOPY_OVERLENGTH of buffer room to allow for overreads. - * This MUST not write more than our maxBlockSize beyond dst, because in - * streaming mode, that could overwrite part of our extDict window. - */ - if (splitImmediately) { - /* won't fit in litExtraBuffer, so it will be split between end of dst and extra buffer */ - dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; - dctx->litBufferEnd = dctx->litBuffer + litSize - ZSTD_LITBUFFEREXTRASIZE; - } else { - /* initially this will be stored entirely in dst during huffman decoding, it will partially be shifted to litExtraBuffer after */ - dctx->litBuffer = (BYTE*)dst + expectedWriteSize - litSize; - dctx->litBufferEnd = (BYTE*)dst + expectedWriteSize; - } - dctx->litBufferLocation = ZSTD_split; - assert(dctx->litBufferEnd <= (BYTE*)dst + expectedWriteSize); - } -} +/* Hidden declaration for fullbench */ +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize); /*! ZSTD_decodeLiteralsBlock() : - * Where it is possible to do so without being stomped by the output during decompression, the literals block will be stored - * in the dstBuffer. If there is room to do so, it will be stored in full in the excess dst space after where the current - * block will be output. Otherwise it will be stored at the end of the current dst blockspace, with a small portion being - * stored in dctx->litExtraBuffer to help keep it "ahead" of the current output write. - * * @return : nb of bytes read from src (< srcSize ) * note : symbol not declared but exposed for fullbench */ -static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, - const void* src, size_t srcSize, /* note : srcSize < BLOCKSIZE */ - void* dst, size_t dstCapacity, const streaming_operation streaming) +size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, + const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ { DEBUGLOG(5, "ZSTD_decodeLiteralsBlock"); RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); { const BYTE* const istart = (const BYTE*) src; symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); - size_t const blockSizeMax = ZSTD_blockSizeMax(dctx); switch(litEncType) { case set_repeat: DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block"); RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted, ""); - ZSTD_FALLTHROUGH; + /* fall-through */ case set_compressed: - RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need up to 5 for case 3"); + RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); { size_t lhSize, litSize, litCSize; U32 singleStream=0; U32 const lhlCode = (istart[0] >> 2) & 3; U32 const lhc = MEM_readLE32(istart); size_t hufSuccess; - size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); - int const flags = 0 - | (ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0) - | (dctx->disableHufAsm ? HUF_flags_disableAsm : 0); switch(lhlCode) { case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -183,15 +120,8 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); - if (!singleStream) - RETURN_ERROR_IF(litSize < MIN_LITERALS_FOR_4_STREAMS, literals_headerWrong, - "Not enough literals (%zu) for the 4-streams mode (min %u)", - litSize, MIN_LITERALS_FOR_4_STREAMS); + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); - RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 0); /* prefetch huffman table if cold */ if (dctx->ddictIsCold && (litSize > 768 /* heuristic */)) { @@ -200,14 +130,13 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litEncType==set_repeat) { if (singleStream) { - hufSuccess = HUF_decompress1X_usingDTable( + hufSuccess = HUF_decompress1X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, flags); + dctx->HUFptr, dctx->bmi2); } else { - assert(litSize >= MIN_LITERALS_FOR_4_STREAMS); - hufSuccess = HUF_decompress4X_usingDTable( + hufSuccess = HUF_decompress4X_usingDTable_bmi2( dctx->litBuffer, litSize, istart+lhSize, litCSize, - dctx->HUFptr, flags); + dctx->HUFptr, dctx->bmi2); } } else { if (singleStream) { @@ -215,29 +144,20 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, hufSuccess = HUF_decompress1X_DCtx_wksp( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace)); #else - hufSuccess = HUF_decompress1X1_DCtx_wksp( + hufSuccess = HUF_decompress1X1_DCtx_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace), dctx->bmi2); #endif } else { - hufSuccess = HUF_decompress4X_hufOnly_wksp( + hufSuccess = HUF_decompress4X_hufOnly_wksp_bmi2( dctx->entropy.hufTable, dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->workspace, - sizeof(dctx->workspace), flags); + sizeof(dctx->workspace), dctx->bmi2); } } - if (dctx->litBufferLocation == ZSTD_split) - { - assert(litSize > ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memcpy(dctx->litExtraBuffer, dctx->litBufferEnd - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memmove(dctx->litBuffer + ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH, dctx->litBuffer, litSize - ZSTD_LITBUFFEREXTRASIZE); - dctx->litBuffer += ZSTD_LITBUFFEREXTRASIZE - WILDCOPY_OVERLENGTH; - dctx->litBufferEnd -= WILDCOPY_OVERLENGTH; - assert(dctx->litBufferEnd <= (BYTE*)dst + blockSizeMax); - } RETURN_ERROR_IF(HUF_isError(hufSuccess), corruption_detected, ""); @@ -245,13 +165,13 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, dctx->litSize = litSize; dctx->litEntropy = 1; if (litEncType==set_compressed) dctx->HUFptr = dctx->entropy.hufTable; + memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return litCSize + lhSize; } case set_basic: { size_t litSize, lhSize; U32 const lhlCode = ((istart[0]) >> 2) & 3; - size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -264,42 +184,27 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 3: lhSize = 3; - RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize = 3"); litSize = MEM_readLE24(istart) >> 4; break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); - RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ RETURN_ERROR_IF(litSize+lhSize > srcSize, corruption_detected, ""); - if (dctx->litBufferLocation == ZSTD_split) - { - ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize - ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memcpy(dctx->litExtraBuffer, istart + lhSize + litSize - ZSTD_LITBUFFEREXTRASIZE, ZSTD_LITBUFFEREXTRASIZE); - } - else - { - ZSTD_memcpy(dctx->litBuffer, istart + lhSize, litSize); - } + memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; + memset(dctx->litBuffer + dctx->litSize, 0, WILDCOPY_OVERLENGTH); return lhSize+litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart+lhSize; dctx->litSize = litSize; - dctx->litBufferEnd = dctx->litPtr + litSize; - dctx->litBufferLocation = ZSTD_not_in_dst; return lhSize+litSize; } case set_rle: { U32 const lhlCode = ((istart[0]) >> 2) & 3; size_t litSize, lhSize; - size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity); switch(lhlCode) { case 0: case 2: default: /* note : default is impossible, since lhlCode into [0..3] */ @@ -308,28 +213,16 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; case 1: lhSize = 2; - RETURN_ERROR_IF(srcSize<3, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 3"); litSize = MEM_readLE16(istart) >> 4; break; case 3: lhSize = 3; - RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 2; here we need lhSize+1 = 4"); litSize = MEM_readLE24(istart) >> 4; + RETURN_ERROR_IF(srcSize<4, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need lhSize+1 = 4"); break; } - RETURN_ERROR_IF(litSize > 0 && dst == NULL, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(litSize > blockSizeMax, corruption_detected, ""); - RETURN_ERROR_IF(expectedWriteSize < litSize, dstSize_tooSmall, ""); - ZSTD_allocateLiteralsBuffer(dctx, dst, dstCapacity, litSize, streaming, expectedWriteSize, 1); - if (dctx->litBufferLocation == ZSTD_split) - { - ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize - ZSTD_LITBUFFEREXTRASIZE); - ZSTD_memset(dctx->litExtraBuffer, istart[lhSize], ZSTD_LITBUFFEREXTRASIZE); - } - else - { - ZSTD_memset(dctx->litBuffer, istart[lhSize], litSize); - } + RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); + memset(dctx->litBuffer, istart[lhSize], litSize + WILDCOPY_OVERLENGTH); dctx->litPtr = dctx->litBuffer; dctx->litSize = litSize; return lhSize+1; @@ -340,21 +233,9 @@ static size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, } } -/* Hidden declaration for fullbench */ -size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx, - const void* src, size_t srcSize, - void* dst, size_t dstCapacity); -size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx, - const void* src, size_t srcSize, - void* dst, size_t dstCapacity) -{ - dctx->isFrameDecompression = 0; - return ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, not_streaming); -} - /* Default FSE distribution tables. * These are pre-calculated FSE decoding tables using default distributions as defined in specification : - * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#default-distributions + * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#default-distributions * They were generated programmatically with following method : * - start from default distributions, present in /lib/common/zstd_internal.h * - generate tables normally, using ZSTD_buildFSETable() @@ -461,7 +342,7 @@ static const ZSTD_seqSymbol ML_defaultDTable[(1<nbBits = 0; cell->nextState = 0; assert(nbAddBits < 255); - cell->nbAdditionalBits = nbAddBits; + cell->nbAdditionalBits = (BYTE)nbAddBits; cell->baseValue = baseValue; } @@ -482,26 +363,23 @@ static void ZSTD_buildSeqTable_rle(ZSTD_seqSymbol* dt, U32 baseValue, U8 nbAddBi * generate FSE decoding table for one symbol (ll, ml or off) * cannot fail if input is valid => * all inputs are presumed validated at this stage */ -FORCE_INLINE_TEMPLATE -void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, +void +ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U8* nbAdditionalBits, - unsigned tableLog, void* wksp, size_t wkspSize) + const U32* baseValue, const U32* nbAdditionalBits, + unsigned tableLog) { ZSTD_seqSymbol* const tableDecode = dt+1; + U16 symbolNext[MaxSeq+1]; + U32 const maxSV1 = maxSymbolValue + 1; U32 const tableSize = 1 << tableLog; - - U16* symbolNext = (U16*)wksp; - BYTE* spread = (BYTE*)(symbolNext + MaxSeq + 1); - U32 highThreshold = tableSize - 1; - + U32 highThreshold = tableSize-1; /* Sanity Checks */ assert(maxSymbolValue <= MaxSeq); assert(tableLog <= MaxFSELog); - assert(wkspSize >= ZSTD_BUILD_FSE_TABLE_WKSP_SIZE); - (void)wkspSize; + /* Init, lay down lowprob symbols */ { ZSTD_seqSymbol_header DTableH; DTableH.tableLog = tableLog; @@ -517,128 +395,34 @@ void ZSTD_buildFSETable_body(ZSTD_seqSymbol* dt, assert(normalizedCounter[s]>=0); symbolNext[s] = (U16)normalizedCounter[s]; } } } - ZSTD_memcpy(dt, &DTableH, sizeof(DTableH)); + memcpy(dt, &DTableH, sizeof(DTableH)); } /* Spread symbols */ - assert(tableSize <= 512); - /* Specialized symbol spreading for the case when there are - * no low probability (-1 count) symbols. When compressing - * small blocks we avoid low probability symbols to hit this - * case, since header decoding speed matters more. - */ - if (highThreshold == tableSize - 1) { - size_t const tableMask = tableSize-1; - size_t const step = FSE_TABLESTEP(tableSize); - /* First lay down the symbols in order. - * We use a uint64_t to lay down 8 bytes at a time. This reduces branch - * misses since small blocks generally have small table logs, so nearly - * all symbols have counts <= 8. We ensure we have 8 bytes at the end of - * our buffer to handle the over-write. - */ - { - U64 const add = 0x0101010101010101ull; - size_t pos = 0; - U64 sv = 0; - U32 s; - for (s=0; s=0); - pos += (size_t)n; - } - } - /* Now we spread those positions across the table. - * The benefit of doing it in two stages is that we avoid the - * variable size inner loop, which caused lots of branch misses. - * Now we can run through all the positions without any branch misses. - * We unroll the loop twice, since that is what empirically worked best. - */ - { - size_t position = 0; - size_t s; - size_t const unroll = 2; - assert(tableSize % unroll == 0); /* FSE_MIN_TABLELOG is 5 */ - for (s = 0; s < (size_t)tableSize; s += unroll) { - size_t u; - for (u = 0; u < unroll; ++u) { - size_t const uPosition = (position + (u * step)) & tableMask; - tableDecode[uPosition].baseValue = spread[s + u]; - } - position = (position + (unroll * step)) & tableMask; - } - assert(position == 0); - } - } else { - U32 const tableMask = tableSize-1; + { U32 const tableMask = tableSize-1; U32 const step = FSE_TABLESTEP(tableSize); U32 s, position = 0; for (s=0; s highThreshold)) position = (position + step) & tableMask; /* lowprob area */ + while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */ } } assert(position == 0); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ } /* Build Decoding table */ - { - U32 u; + { U32 u; for (u=0; u max, corruption_detected, ""); { U32 const symbol = *(const BYTE*)src; U32 const baseline = baseValue[symbol]; - U8 const nbBits = nbAdditionalBits[symbol]; + U32 const nbBits = nbAdditionalBits[symbol]; ZSTD_buildSeqTable_rle(DTableSpace, baseline, nbBits); } *DTablePtr = DTableSpace; @@ -683,7 +466,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t const headerSize = FSE_readNCount(norm, &max, &tableLog, src, srcSize); RETURN_ERROR_IF(FSE_isError(headerSize), corruption_detected, ""); RETURN_ERROR_IF(tableLog > maxLog, corruption_detected, ""); - ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog, wksp, wkspSize, bmi2); + ZSTD_buildFSETable(DTableSpace, norm, max, baseValue, nbAdditionalBits, tableLog); *DTablePtr = DTableSpace; return headerSize; } @@ -696,7 +479,7 @@ static size_t ZSTD_buildSeqTable(ZSTD_seqSymbol* DTableSpace, const ZSTD_seqSymb size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize) { - const BYTE* const istart = (const BYTE*)src; + const BYTE* const istart = (const BYTE* const)src; const BYTE* const iend = istart + srcSize; const BYTE* ip = istart; int nbSeq; @@ -707,11 +490,15 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, /* SeqHead */ nbSeq = *ip++; + if (!nbSeq) { + *nbSeqPtr=0; + RETURN_ERROR_IF(srcSize != 1, srcSize_wrong, ""); + return 1; + } if (nbSeq > 0x7F) { if (nbSeq == 0xFF) { RETURN_ERROR_IF(ip+2 > iend, srcSize_wrong, ""); - nbSeq = MEM_readLE16(ip) + LONGNBSEQ; - ip+=2; + nbSeq = MEM_readLE16(ip) + LONGNBSEQ, ip+=2; } else { RETURN_ERROR_IF(ip >= iend, srcSize_wrong, ""); nbSeq = ((nbSeq-0x80)<<8) + *ip++; @@ -719,16 +506,8 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, } *nbSeqPtr = nbSeq; - if (nbSeq == 0) { - /* No sequence : section ends immediately */ - RETURN_ERROR_IF(ip != iend, corruption_detected, - "extraneous data present in the Sequences section"); - return (size_t)(ip - istart); - } - /* FSE table descriptors */ RETURN_ERROR_IF(ip+1 > iend, srcSize_wrong, ""); /* minimum possible size: 1 byte for symbol encoding types */ - RETURN_ERROR_IF(*ip & 3, corruption_detected, ""); /* The last field, Reserved, must be all-zeroes. */ { symbolEncodingType_e const LLtype = (symbolEncodingType_e)(*ip >> 6); symbolEncodingType_e const OFtype = (symbolEncodingType_e)((*ip >> 4) & 3); symbolEncodingType_e const MLtype = (symbolEncodingType_e)((*ip >> 2) & 3); @@ -738,11 +517,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const llhSize = ZSTD_buildSeqTable(dctx->entropy.LLTable, &dctx->LLTptr, LLtype, MaxLL, LLFSELog, ip, iend-ip, - LL_base, LL_bits, + ZSTDConstants::LL_base, ZSTDInternalConstants::LL_bits, LL_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); + dctx->ddictIsCold, nbSeq); RETURN_ERROR_IF(ZSTD_isError(llhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += llhSize; } @@ -750,11 +527,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const ofhSize = ZSTD_buildSeqTable(dctx->entropy.OFTable, &dctx->OFTptr, OFtype, MaxOff, OffFSELog, ip, iend-ip, - OF_base, OF_bits, + ZSTDConstants::OF_base, ZSTDConstants::OF_bits, OF_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); + dctx->ddictIsCold, nbSeq); RETURN_ERROR_IF(ZSTD_isError(ofhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += ofhSize; } @@ -762,11 +537,9 @@ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, { size_t const mlhSize = ZSTD_buildSeqTable(dctx->entropy.MLTable, &dctx->MLTptr, MLtype, MaxML, MLFSELog, ip, iend-ip, - ML_base, ML_bits, + ZSTDConstants::ML_base, ZSTDInternalConstants::ML_bits, ML_defaultDTable, dctx->fseEntropy, - dctx->ddictIsCold, nbSeq, - dctx->workspace, sizeof(dctx->workspace), - ZSTD_DCtx_get_bmi2(dctx)); + dctx->ddictIsCold, nbSeq); RETURN_ERROR_IF(ZSTD_isError(mlhSize), corruption_detected, "ZSTD_buildSeqTable failed"); ip += mlhSize; } @@ -780,6 +553,7 @@ typedef struct { size_t litLength; size_t matchLength; size_t offset; + const BYTE* match; } seq_t; typedef struct { @@ -793,6 +567,9 @@ typedef struct { ZSTD_fseState stateOffb; ZSTD_fseState stateML; size_t prevOffset[ZSTD_REP_NUM]; + const BYTE* prefixStart; + const BYTE* dictEnd; + size_t pos; } seqState_t; /*! ZSTD_overlapCopy8() : @@ -835,7 +612,7 @@ HINT_INLINE void ZSTD_overlapCopy8(BYTE** op, BYTE const** ip, size_t offset) { * - ZSTD_overlap_src_before_dst: The src and dst may overlap and may be any distance apart. * The src buffer must be before the dst buffer. */ -static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { +static void ZSTD_safecopy(BYTE* op, BYTE* const oend_w, BYTE const* ip, ptrdiff_t length, ZSTD_overlap_e ovtype) { ptrdiff_t const diff = op - ip; BYTE* const oend = op + length; @@ -851,7 +628,6 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt /* Copy 8 bytes and ensure the offset >= 8 when there can be overlap. */ assert(length >= 8); ZSTD_overlapCopy8(&op, &ip, diff); - length -= 8; assert(op - ip >= 8); assert(op <= oend); } @@ -866,35 +642,12 @@ static void ZSTD_safecopy(BYTE* op, const BYTE* const oend_w, BYTE const* ip, pt assert(oend > oend_w); ZSTD_wildcopy(op, ip, oend_w - op, ovtype); ip += oend_w - op; - op += oend_w - op; + op = oend_w; } /* Handle the leftovers. */ while (op < oend) *op++ = *ip++; } -/* ZSTD_safecopyDstBeforeSrc(): - * This version allows overlap with dst before src, or handles the non-overlap case with dst after src - * Kept separate from more common ZSTD_safecopy case to avoid performance impact to the safecopy common case */ -static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, ptrdiff_t length) { - ptrdiff_t const diff = op - ip; - BYTE* const oend = op + length; - - if (length < 8 || diff > -8) { - /* Handle short lengths, close overlaps, and dst not before src. */ - while (op < oend) *op++ = *ip++; - return; - } - - if (op <= oend - WILDCOPY_OVERLENGTH && diff < -WILDCOPY_VECLEN) { - ZSTD_wildcopy(op, ip, oend - WILDCOPY_OVERLENGTH - op, ZSTD_no_overlap); - ip += oend - WILDCOPY_OVERLENGTH - op; - op += oend - WILDCOPY_OVERLENGTH - op; - } - - /* Handle the leftovers. */ - while (op < oend) *op++ = *ip++; -} - /* ZSTD_execSequenceEnd(): * This version handles cases that are near the end of the output buffer. It requires * more careful checks to make sure there is no overflow. By separating out these hard @@ -904,11 +657,10 @@ static void ZSTD_safecopyDstBeforeSrc(BYTE* op, const BYTE* ip, ptrdiff_t length * to be optimized for many small sequences, since those fall into ZSTD_execSequence(). */ FORCE_NOINLINE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_execSequenceEnd(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; @@ -931,78 +683,27 @@ size_t ZSTD_execSequenceEnd(BYTE* op, if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { /* offset beyond prefix */ RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); - match = dictEnd - (prefixStart - match); + match = dictEnd - (prefixStart-match); if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); + memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } - ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); - return sequenceLength; -} - -/* ZSTD_execSequenceEndSplitLitBuffer(): - * This version is intended to be used during instances where the litBuffer is still split. It is kept separate to avoid performance impact for the good case. - */ -FORCE_NOINLINE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_execSequenceEndSplitLitBuffer(BYTE* op, - BYTE* const oend, const BYTE* const oend_w, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) -{ - BYTE* const oLitEnd = op + sequence.litLength; - size_t const sequenceLength = sequence.litLength + sequence.matchLength; - const BYTE* const iLitEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - - /* bounds checks : careful of address space overflow in 32-bit mode */ - RETURN_ERROR_IF(sequenceLength > (size_t)(oend - op), dstSize_tooSmall, "last match must fit within dstBuffer"); - RETURN_ERROR_IF(sequence.litLength > (size_t)(litLimit - *litPtr), corruption_detected, "try to read beyond literal buffer"); - assert(op < op + sequenceLength); - assert(oLitEnd < op + sequenceLength); - - /* copy literals */ - RETURN_ERROR_IF(op > *litPtr && op < *litPtr + sequence.litLength, dstSize_tooSmall, "output should not catch up to and overwrite literal buffer"); - ZSTD_safecopyDstBeforeSrc(op, *litPtr, sequence.litLength); - op = oLitEnd; - *litPtr = iLitEnd; - - /* copy Match */ - if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { - /* offset beyond prefix */ - RETURN_ERROR_IF(sequence.offset > (size_t)(oLitEnd - virtualStart), corruption_detected, ""); - match = dictEnd - (prefixStart - match); - if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } + memmove(oLitEnd, match, length1); + op = oLitEnd + length1; + sequence.matchLength -= length1; + match = prefixStart; + } } ZSTD_safecopy(op, oend_w, match, sequence.matchLength, ZSTD_overlap_src_before_dst); return sequenceLength; } HINT_INLINE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR size_t ZSTD_execSequence(BYTE* op, - BYTE* const oend, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) + BYTE* const oend, seq_t sequence, + const BYTE** litPtr, const BYTE* const litLimit, + const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) { BYTE* const oLitEnd = op + sequence.litLength; size_t const sequenceLength = sequence.litLength + sequence.matchLength; @@ -1013,104 +714,6 @@ size_t ZSTD_execSequence(BYTE* op, assert(op != NULL /* Precondition */); assert(oend_w < oend /* No underflow */); - -#if defined(__aarch64__) - /* prefetch sequence starting from match that will be used for copy later */ - PREFETCH_L1(match); -#endif - /* Handle edge cases in a slow path: - * - Read beyond end of literals - * - Match end is within WILDCOPY_OVERLIMIT of oend - * - 32-bit mode and the match length overflows - */ - if (UNLIKELY( - iLitEnd > litLimit || - oMatchEnd > oend_w || - (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) - return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); - - /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ - assert(op <= oLitEnd /* No overflow */); - assert(oLitEnd < oMatchEnd /* Non-zero match & no overflow */); - assert(oMatchEnd <= oend /* No underflow */); - assert(iLitEnd <= litLimit /* Literal length is in bounds */); - assert(oLitEnd <= oend_w /* Can wildcopy literals */); - assert(oMatchEnd <= oend_w /* Can wildcopy matches */); - - /* Copy Literals: - * Split out litLength <= 16 since it is nearly always true. +1.6% on gcc-9. - * We likely don't need the full 32-byte wildcopy. - */ - assert(WILDCOPY_OVERLENGTH >= 16); - ZSTD_copy16(op, (*litPtr)); - if (UNLIKELY(sequence.litLength > 16)) { - ZSTD_wildcopy(op + 16, (*litPtr) + 16, sequence.litLength - 16, ZSTD_no_overlap); - } - op = oLitEnd; - *litPtr = iLitEnd; /* update for next sequence */ - - /* Copy Match */ - if (sequence.offset > (size_t)(oLitEnd - prefixStart)) { - /* offset beyond prefix -> go into extDict */ - RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); - match = dictEnd + (match - prefixStart); - if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); - return sequenceLength; - } - /* span extDict & currentPrefixSegment */ - { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); - op = oLitEnd + length1; - sequence.matchLength -= length1; - match = prefixStart; - } - } - /* Match within prefix of 1 or more bytes */ - assert(op <= oMatchEnd); - assert(oMatchEnd <= oend_w); - assert(match >= prefixStart); - assert(sequence.matchLength >= 1); - - /* Nearly all offsets are >= WILDCOPY_VECLEN bytes, which means we can use wildcopy - * without overlap checking. - */ - if (LIKELY(sequence.offset >= WILDCOPY_VECLEN)) { - /* We bet on a full wildcopy for matches, since we expect matches to be - * longer than literals (in general). In silesia, ~10% of matches are longer - * than 16 bytes. - */ - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength, ZSTD_no_overlap); - return sequenceLength; - } - assert(sequence.offset < WILDCOPY_VECLEN); - - /* Copy 8 bytes and spread the offset to be >= 8. */ - ZSTD_overlapCopy8(&op, &match, sequence.offset); - - /* If the match length is > 8 bytes, then continue with the wildcopy. */ - if (sequence.matchLength > 8) { - assert(op < oMatchEnd); - ZSTD_wildcopy(op, match, (ptrdiff_t)sequence.matchLength - 8, ZSTD_overlap_src_before_dst); - } - return sequenceLength; -} - -HINT_INLINE -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, - BYTE* const oend, const BYTE* const oend_w, seq_t sequence, - const BYTE** litPtr, const BYTE* const litLimit, - const BYTE* const prefixStart, const BYTE* const virtualStart, const BYTE* const dictEnd) -{ - BYTE* const oLitEnd = op + sequence.litLength; - size_t const sequenceLength = sequence.litLength + sequence.matchLength; - BYTE* const oMatchEnd = op + sequenceLength; /* risk : address space overflow (32-bits) */ - const BYTE* const iLitEnd = *litPtr + sequence.litLength; - const BYTE* match = oLitEnd - sequence.offset; - - assert(op != NULL /* Precondition */); - assert(oend_w < oend /* No underflow */); /* Handle edge cases in a slow path: * - Read beyond end of literals * - Match end is within WILDCOPY_OVERLIMIT of oend @@ -1120,7 +723,7 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, iLitEnd > litLimit || oMatchEnd > oend_w || (MEM_32bits() && (size_t)(oend - op) < sequenceLength + WILDCOPY_OVERLENGTH))) - return ZSTD_execSequenceEndSplitLitBuffer(op, oend, oend_w, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); + return ZSTD_execSequenceEnd(op, oend, sequence, litPtr, litLimit, prefixStart, virtualStart, dictEnd); /* Assumptions (everything else goes into ZSTD_execSequenceEnd()) */ assert(op <= oLitEnd /* No overflow */); @@ -1148,12 +751,12 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, RETURN_ERROR_IF(UNLIKELY(sequence.offset > (size_t)(oLitEnd - virtualStart)), corruption_detected, ""); match = dictEnd + (match - prefixStart); if (match + sequence.matchLength <= dictEnd) { - ZSTD_memmove(oLitEnd, match, sequence.matchLength); + memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } /* span extDict & currentPrefixSegment */ { size_t const length1 = dictEnd - match; - ZSTD_memmove(oLitEnd, match, length1); + memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; match = prefixStart; @@ -1188,7 +791,6 @@ size_t ZSTD_execSequenceSplitLitBuffer(BYTE* op, return sequenceLength; } - static void ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqSymbol* dt) { @@ -1202,14 +804,24 @@ ZSTD_initFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, const ZSTD_seqS } FORCE_INLINE_TEMPLATE void -ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 nextState, U32 nbBits) +ZSTD_updateFseState(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD) { + ZSTD_seqSymbol const DInfo = DStatePtr->table[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = nextState + lowBits; + DStatePtr->state = DInfo.nextState + lowBits; +} + +FORCE_INLINE_TEMPLATE void +ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, ZSTD_seqSymbol const DInfo) +{ + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.nextState + lowBits; } /* We need to add at most (ZSTD_WINDOWLOG_MAX_32 - 1) bits to read the maximum - * offset bits. But we can only read at most STREAM_ACCUMULATOR_MIN_32 + * offset bits. But we can only read at most (STREAM_ACCUMULATOR_MIN_32 - 1) * bits before reloading. This value is the maximum number of bytes we read * after reloading when we are decoding long offsets. */ @@ -1219,135 +831,122 @@ ZSTD_updateFseStateWithDInfo(ZSTD_fseState* DStatePtr, BIT_DStream_t* bitD, U16 : 0) typedef enum { ZSTD_lo_isRegularOffset, ZSTD_lo_isLongOffset=1 } ZSTD_longOffset_e; +typedef enum { ZSTD_p_noPrefetch=0, ZSTD_p_prefetch=1 } ZSTD_prefetch_e; -/** - * ZSTD_decodeSequence(): - * @p longOffsets : tells the decoder to reload more bit while decoding large offsets - * only used in 32-bit mode - * @return : Sequence (litL + matchL + offset) - */ FORCE_INLINE_TEMPLATE seq_t -ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const int isLastSeq) +ZSTD_decodeSequence(seqState_t* seqState, const ZSTD_longOffset_e longOffsets, const ZSTD_prefetch_e prefetch) { seq_t seq; - /* - * ZSTD_seqSymbol is a 64 bits wide structure. - * It can be loaded in one operation - * and its fields extracted by simply shifting or bit-extracting on aarch64. - * GCC doesn't recognize this and generates more unnecessary ldr/ldrb/ldrh - * operations that cause performance drop. This can be avoided by using this - * ZSTD_memcpy hack. - */ -#if defined(__aarch64__) && (defined(__GNUC__) && !defined(__clang__)) - ZSTD_seqSymbol llDInfoS, mlDInfoS, ofDInfoS; - ZSTD_seqSymbol* const llDInfo = &llDInfoS; - ZSTD_seqSymbol* const mlDInfo = &mlDInfoS; - ZSTD_seqSymbol* const ofDInfo = &ofDInfoS; - ZSTD_memcpy(llDInfo, seqState->stateLL.table + seqState->stateLL.state, sizeof(ZSTD_seqSymbol)); - ZSTD_memcpy(mlDInfo, seqState->stateML.table + seqState->stateML.state, sizeof(ZSTD_seqSymbol)); - ZSTD_memcpy(ofDInfo, seqState->stateOffb.table + seqState->stateOffb.state, sizeof(ZSTD_seqSymbol)); -#else - const ZSTD_seqSymbol* const llDInfo = seqState->stateLL.table + seqState->stateLL.state; - const ZSTD_seqSymbol* const mlDInfo = seqState->stateML.table + seqState->stateML.state; - const ZSTD_seqSymbol* const ofDInfo = seqState->stateOffb.table + seqState->stateOffb.state; -#endif - seq.matchLength = mlDInfo->baseValue; - seq.litLength = llDInfo->baseValue; - { U32 const ofBase = ofDInfo->baseValue; - BYTE const llBits = llDInfo->nbAdditionalBits; - BYTE const mlBits = mlDInfo->nbAdditionalBits; - BYTE const ofBits = ofDInfo->nbAdditionalBits; - BYTE const totalBits = llBits+mlBits+ofBits; - - U16 const llNext = llDInfo->nextState; - U16 const mlNext = mlDInfo->nextState; - U16 const ofNext = ofDInfo->nextState; - U32 const llnbBits = llDInfo->nbBits; - U32 const mlnbBits = mlDInfo->nbBits; - U32 const ofnbBits = ofDInfo->nbBits; - - assert(llBits <= MaxLLBits); - assert(mlBits <= MaxMLBits); - assert(ofBits <= MaxOff); - /* - * As gcc has better branch and block analyzers, sometimes it is only - * valuable to mark likeliness for clang, it gives around 3-4% of - * performance. - */ - - /* sequence */ - { size_t offset; - if (ofBits > 1) { - ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); - ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); - ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 > LONG_OFFSETS_MAX_EXTRA_BITS_32); - ZSTD_STATIC_ASSERT(STREAM_ACCUMULATOR_MIN_32 - LONG_OFFSETS_MAX_EXTRA_BITS_32 >= MaxMLBits); - if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { - /* Always read extra bits, this keeps the logic simple, - * avoids branches, and avoids accidentally reading 0 bits. - */ - U32 const extraBits = LONG_OFFSETS_MAX_EXTRA_BITS_32; - offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); - BIT_reloadDStream(&seqState->DStream); - offset += BIT_readBitsFast(&seqState->DStream, extraBits); - } else { - offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ - if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); - } - seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset; + ZSTD_seqSymbol const llDInfo = seqState->stateLL.table[seqState->stateLL.state]; + ZSTD_seqSymbol const mlDInfo = seqState->stateML.table[seqState->stateML.state]; + ZSTD_seqSymbol const ofDInfo = seqState->stateOffb.table[seqState->stateOffb.state]; + U32 const llBase = llDInfo.baseValue; + U32 const mlBase = mlDInfo.baseValue; + U32 const ofBase = ofDInfo.baseValue; + BYTE const llBits = llDInfo.nbAdditionalBits; + BYTE const mlBits = mlDInfo.nbAdditionalBits; + BYTE const ofBits = ofDInfo.nbAdditionalBits; + BYTE const totalBits = llBits+mlBits+ofBits; + + /* sequence */ + { size_t offset; + if (ofBits > 1) { + ZSTD_STATIC_ASSERT(ZSTD_lo_isLongOffset == 1); + ZSTD_STATIC_ASSERT(LONG_OFFSETS_MAX_EXTRA_BITS_32 == 5); + assert(ofBits <= MaxOff); + if (MEM_32bits() && longOffsets && (ofBits >= STREAM_ACCUMULATOR_MIN_32)) { + U32 const extraBits = ofBits - MIN(ofBits, 32 - seqState->DStream.bitsConsumed); + offset = ofBase + (BIT_readBitsFast(&seqState->DStream, ofBits - extraBits) << extraBits); + BIT_reloadDStream(&seqState->DStream); + if (extraBits) offset += BIT_readBitsFast(&seqState->DStream, extraBits); + assert(extraBits <= LONG_OFFSETS_MAX_EXTRA_BITS_32); /* to avoid another reload */ } else { - U32 const ll0 = (llDInfo->baseValue == 0); - if (LIKELY((ofBits == 0))) { - offset = seqState->prevOffset[ll0]; - seqState->prevOffset[1] = seqState->prevOffset[!ll0]; + offset = ofBase + BIT_readBitsFast(&seqState->DStream, ofBits/*>0*/); /* <= (ZSTD_WINDOWLOG_MAX-1) bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); + } + seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset; + } else { + U32 const ll0 = (llBase == 0); + if (LIKELY((ofBits == 0))) { + if (LIKELY(!ll0)) + offset = seqState->prevOffset[0]; + else { + offset = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; seqState->prevOffset[0] = offset; - } else { - offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); - { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; - temp -= !temp; /* 0 is not valid: input corrupted => force offset to -1 => corruption detected at execSequence */ - if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; - seqState->prevOffset[1] = seqState->prevOffset[0]; - seqState->prevOffset[0] = offset = temp; - } } } - seq.offset = offset; - } + } + } else { + offset = ofBase + ll0 + BIT_readBitsFast(&seqState->DStream, 1); + { size_t temp = (offset==3) ? seqState->prevOffset[0] - 1 : seqState->prevOffset[offset]; + temp += !temp; /* 0 is not valid; input is corrupted; force offset to 1 */ + if (offset != 1) seqState->prevOffset[2] = seqState->prevOffset[1]; + seqState->prevOffset[1] = seqState->prevOffset[0]; + seqState->prevOffset[0] = offset = temp; + } } } + seq.offset = offset; + } - if (mlBits > 0) - seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); + seq.matchLength = mlBase; + if (mlBits > 0) + seq.matchLength += BIT_readBitsFast(&seqState->DStream, mlBits/*>0*/); - if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) - BIT_reloadDStream(&seqState->DStream); - if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) - BIT_reloadDStream(&seqState->DStream); - /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ - ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); + if (MEM_32bits() && (mlBits+llBits >= STREAM_ACCUMULATOR_MIN_32-LONG_OFFSETS_MAX_EXTRA_BITS_32)) + BIT_reloadDStream(&seqState->DStream); + if (MEM_64bits() && UNLIKELY(totalBits >= STREAM_ACCUMULATOR_MIN_64-(LLFSELog+MLFSELog+OffFSELog))) + BIT_reloadDStream(&seqState->DStream); + /* Ensure there are enough bits to read the rest of data in 64-bit mode. */ + ZSTD_STATIC_ASSERT(16+LLFSELog+MLFSELog+OffFSELog < STREAM_ACCUMULATOR_MIN_64); - if (llBits > 0) - seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); + seq.litLength = llBase; + if (llBits > 0) + seq.litLength += BIT_readBitsFast(&seqState->DStream, llBits/*>0*/); - if (MEM_32bits()) - BIT_reloadDStream(&seqState->DStream); + if (MEM_32bits()) + BIT_reloadDStream(&seqState->DStream); - DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + DEBUGLOG(6, "seq: litL=%u, matchL=%u, offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - if (!isLastSeq) { - /* don't update FSE state for last Sequence */ - ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llNext, llnbBits); /* <= 9 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlNext, mlnbBits); /* <= 9 bits */ + if (prefetch == ZSTD_p_prefetch) { + size_t const pos = seqState->pos + seq.litLength; + const BYTE* const matchBase = (seq.offset > pos) ? seqState->dictEnd : seqState->prefixStart; + seq.match = matchBase + pos - seq.offset; /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. + * No consequence though : no memory access will occur, offset is only used for prefetching */ + seqState->pos = pos + seq.matchLength; + } + + /* ANS state update + * gcc-9.0.0 does 2.5% worse with ZSTD_updateFseStateWithDInfo(). + * clang-9.2.0 does 7% worse with ZSTD_updateFseState(). + * Naturally it seems like ZSTD_updateFseStateWithDInfo() should be the + * better option, so it is the default for other compilers. But, if you + * measure that it is worse, please put up a pull request. + */ + { +#if defined(__GNUC__) && !defined(__clang__) + const int kUseUpdateFseState = 1; +#else + const int kUseUpdateFseState = 0; +#endif + if (kUseUpdateFseState) { + ZSTD_updateFseState(&seqState->stateLL, &seqState->DStream); /* <= 9 bits */ + ZSTD_updateFseState(&seqState->stateML, &seqState->DStream); /* <= 9 bits */ if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ - ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofNext, ofnbBits); /* <= 8 bits */ - BIT_reloadDStream(&seqState->DStream); + ZSTD_updateFseState(&seqState->stateOffb, &seqState->DStream); /* <= 8 bits */ + } else { + ZSTD_updateFseStateWithDInfo(&seqState->stateLL, &seqState->DStream, llDInfo); /* <= 9 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateML, &seqState->DStream, mlDInfo); /* <= 9 bits */ + if (MEM_32bits()) BIT_reloadDStream(&seqState->DStream); /* <= 18 bits */ + ZSTD_updateFseStateWithDInfo(&seqState->stateOffb, &seqState->DStream, ofDInfo); /* <= 8 bits */ } } return seq; } -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) -#if DEBUGLEVEL >= 1 +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStart, BYTE const* oLitEnd) { size_t const windowSize = dctx->fParams.windowSize; @@ -1362,65 +961,59 @@ static int ZSTD_dictionaryIsActive(ZSTD_DCtx const* dctx, BYTE const* prefixStar /* Dictionary is active. */ return 1; } -#endif -static void ZSTD_assertValidSequence( +MEM_STATIC void ZSTD_assertValidSequence( ZSTD_DCtx const* dctx, BYTE const* op, BYTE const* oend, seq_t const seq, BYTE const* prefixStart, BYTE const* virtualStart) { -#if DEBUGLEVEL >= 1 - if (dctx->isFrameDecompression) { - size_t const windowSize = dctx->fParams.windowSize; - size_t const sequenceSize = seq.litLength + seq.matchLength; - BYTE const* const oLitEnd = op + seq.litLength; - DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", - (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); - assert(op <= oend); - assert((size_t)(oend - op) >= sequenceSize); - assert(sequenceSize <= ZSTD_blockSizeMax(dctx)); - if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { - size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); - /* Offset must be within the dictionary. */ - assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); - assert(seq.offset <= windowSize + dictSize); - } else { - /* Offset must be within our window. */ - assert(seq.offset <= windowSize); - } + size_t const windowSize = dctx->fParams.windowSize; + size_t const sequenceSize = seq.litLength + seq.matchLength; + BYTE const* const oLitEnd = op + seq.litLength; + DEBUGLOG(6, "Checking sequence: litL=%u matchL=%u offset=%u", + (U32)seq.litLength, (U32)seq.matchLength, (U32)seq.offset); + assert(op <= oend); + assert((size_t)(oend - op) >= sequenceSize); + assert(sequenceSize <= ZSTD_BLOCKSIZE_MAX); + if (ZSTD_dictionaryIsActive(dctx, prefixStart, oLitEnd)) { + size_t const dictSize = (size_t)((char const*)dctx->dictContentEndForFuzzing - (char const*)dctx->dictContentBeginForFuzzing); + /* Offset must be within the dictionary. */ + assert(seq.offset <= (size_t)(oLitEnd - virtualStart)); + assert(seq.offset <= windowSize + dictSize); + } else { + /* Offset must be within our window. */ + assert(seq.offset <= windowSize); } -#else - (void)dctx, (void)op, (void)oend, (void)seq, (void)prefixStart, (void)virtualStart; -#endif } #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG - - FORCE_INLINE_TEMPLATE size_t DONT_VECTORIZE -ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, +ZSTD_decompressSequences_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = ZSTD_maybeNullPtrAdd(ostart, maxDstSize); + BYTE* const ostart = (BYTE* const)dst; + BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const litEnd = litPtr + dctx->litSize; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const vBase = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer (%i seqs)", nbSeq); + DEBUGLOG(5, "ZSTD_decompressSequences_body"); + (void)frame; - /* Literals are split between internal buffer & output buffer */ + /* Regen sequences */ if (nbSeq) { seqState_t seqState; + size_t error = 0; dctx->fseEntropy = 1; { U32 i; for (i=0; ientropy.rep[i]; } RETURN_ERROR_IF( @@ -1436,331 +1029,134 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx, BIT_DStream_endOfBuffer < BIT_DStream_completed && BIT_DStream_completed < BIT_DStream_overflow); - /* decompress without overrunning litPtr begins */ - { seq_t sequence = {0,0,0}; /* some static analyzer believe that @sequence is not initialized (it necessarily is, since for(;;) loop as at least one iteration) */ - /* Align the decompression loop to 32 + 16 bytes. - * - * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression - * speed swings based on the alignment of the decompression loop. This - * performance swing is caused by parts of the decompression loop falling - * out of the DSB. The entire decompression loop should fit in the DSB, - * when it can't we get much worse performance. You can measure if you've - * hit the good case or the bad case with this perf command for some - * compressed file test.zst: - * - * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ - * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst - * - * If you see most cycles served out of the MITE you've hit the bad case. - * If you see most cycles served out of the DSB you've hit the good case. - * If it is pretty even then you may be in an okay case. - * - * This issue has been reproduced on the following CPUs: - * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 - * Use Instruments->Counters to get DSB/MITE cycles. - * I never got performance swings, but I was able to - * go from the good case of mostly DSB to half of the - * cycles served from MITE. - * - Coffeelake: Intel i9-9900k - * - Coffeelake: Intel i7-9700k - * - * I haven't been able to reproduce the instability or DSB misses on any - * of the following CPUS: - * - Haswell - * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH - * - Skylake - * - * Alignment is done for each of the three major decompression loops: - * - ZSTD_decompressSequences_bodySplitLitBuffer - presplit section of the literal buffer - * - ZSTD_decompressSequences_bodySplitLitBuffer - postsplit section of the literal buffer - * - ZSTD_decompressSequences_body - * Alignment choices are made to minimize large swings on bad cases and influence on performance - * from changes external to this code, rather than to overoptimize on the current commit. - * - * If you are seeing performance stability this script can help test. - * It tests on 4 commits in zstd where I saw performance change. - * - * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 - */ -#if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); -# if __GNUC__ >= 7 - /* good for gcc-7, gcc-9, and gcc-11 */ - __asm__("nop"); - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 4"); -# if __GNUC__ == 8 || __GNUC__ == 10 - /* good for gcc-8 and gcc-10 */ - __asm__("nop"); - __asm__(".p2align 3"); -# endif -# endif -#endif - - /* Handle the initial state where litBuffer is currently split between dst and litExtraBuffer */ - for ( ; nbSeq; nbSeq--) { - sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); - if (litPtr + sequence.litLength > dctx->litBufferEnd) break; - { size_t const oneSeqSize = ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence.litLength - WILDCOPY_OVERLENGTH, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - } } - DEBUGLOG(6, "reached: (litPtr + sequence.litLength > dctx->litBufferEnd)"); - - /* If there are more sequences, they will need to read literals from litExtraBuffer; copy over the remainder from dst and update litPtr and litEnd */ - if (nbSeq > 0) { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - DEBUGLOG(6, "There are %i sequences left, and %zu/%zu literals left in buffer", nbSeq, leftoverLit, sequence.litLength); - if (leftoverLit) { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequence.litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - { size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - } - nbSeq--; - } - } - - if (nbSeq > 0) { - /* there is remaining lit from extra buffer */ - #if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); - __asm__("nop"); -# if __GNUC__ != 7 - /* worse for gcc-7 better for gcc-8, gcc-9, and gcc-10 and clang */ - __asm__(".p2align 4"); - __asm__("nop"); - __asm__(".p2align 3"); -# elif __GNUC__ >= 11 - __asm__(".p2align 3"); -# else - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 3"); -# endif -#endif - - for ( ; nbSeq ; nbSeq--) { - seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); - size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litBufferEnd, prefixStart, vBase, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); -#endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; - DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; - } - } - - /* check if reached exact end */ - DEBUGLOG(5, "ZSTD_decompressSequences_bodySplitLitBuffer: after decode loop, remaining nbSeq : %i", nbSeq); - RETURN_ERROR_IF(nbSeq, corruption_detected, ""); - DEBUGLOG(5, "bitStream : start=%p, ptr=%p, bitsConsumed=%u", seqState.DStream.start, seqState.DStream.ptr, seqState.DStream.bitsConsumed); - RETURN_ERROR_IF(!BIT_endOfDStream(&seqState.DStream), corruption_detected, ""); - /* save reps for next block */ - { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } - } - - /* last literal segment */ - if (dctx->litBufferLocation == ZSTD_split) { - /* split hasn't been reached yet, first get dst then copy litExtraBuffer */ - size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); - DEBUGLOG(6, "copy last literals from segment : %u", (U32)lastLLSize); - RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - } - /* copy last literals from internal buffer */ - { size_t const lastLLSize = (size_t)(litBufferEnd - litPtr); - DEBUGLOG(6, "copy last literals from internal buffer : %u", (U32)lastLLSize); - RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } } - - DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart)); - return (size_t)(op - ostart); -} - -FORCE_INLINE_TEMPLATE size_t -DONT_VECTORIZE -ZSTD_decompressSequences_body(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) -{ - const BYTE* ip = (const BYTE*)seqStart; - const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_not_in_dst ? ZSTD_maybeNullPtrAdd(ostart, maxDstSize) : dctx->litBuffer; - BYTE* op = ostart; - const BYTE* litPtr = dctx->litPtr; - const BYTE* const litEnd = litPtr + dctx->litSize; - const BYTE* const prefixStart = (const BYTE*)(dctx->prefixStart); - const BYTE* const vBase = (const BYTE*)(dctx->virtualStart); - const BYTE* const dictEnd = (const BYTE*)(dctx->dictEnd); - DEBUGLOG(5, "ZSTD_decompressSequences_body: nbSeq = %d", nbSeq); - - /* Regen sequences */ - if (nbSeq) { - seqState_t seqState; - dctx->fseEntropy = 1; - { U32 i; for (i = 0; i < ZSTD_REP_NUM; i++) seqState.prevOffset[i] = dctx->entropy.rep[i]; } - RETURN_ERROR_IF( - ERR_isError(BIT_initDStream(&seqState.DStream, ip, iend - ip)), - corruption_detected, ""); - ZSTD_initFseState(&seqState.stateLL, &seqState.DStream, dctx->LLTptr); - ZSTD_initFseState(&seqState.stateOffb, &seqState.DStream, dctx->OFTptr); - ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); - assert(dst != NULL); - -#if defined(__GNUC__) && defined(__x86_64__) - __asm__(".p2align 6"); - __asm__("nop"); -# if __GNUC__ >= 7 - __asm__(".p2align 5"); - __asm__("nop"); - __asm__(".p2align 3"); -# else - __asm__(".p2align 4"); - __asm__("nop"); - __asm__(".p2align 3"); -# endif + /* Align the decompression loop to 32 + 16 bytes. + * + * zstd compiled with gcc-9 on an Intel i9-9900k shows 10% decompression + * speed swings based on the alignment of the decompression loop. This + * performance swing is caused by parts of the decompression loop falling + * out of the DSB. The entire decompression loop should fit in the DSB, + * when it can't we get much worse performance. You can measure if you've + * hit the good case or the bad case with this perf command for some + * compressed file test.zst: + * + * perf stat -e cycles -e instructions -e idq.all_dsb_cycles_any_uops \ + * -e idq.all_mite_cycles_any_uops -- ./zstd -tq test.zst + * + * If you see most cycles served out of the MITE you've hit the bad case. + * If you see most cycles served out of the DSB you've hit the good case. + * If it is pretty even then you may be in an okay case. + * + * I've been able to reproduce this issue on the following CPUs: + * - Kabylake: Macbook Pro (15-inch, 2019) 2.4 GHz Intel Core i9 + * Use Instruments->Counters to get DSB/MITE cycles. + * I never got performance swings, but I was able to + * go from the good case of mostly DSB to half of the + * cycles served from MITE. + * - Coffeelake: Intel i9-9900k + * + * I haven't been able to reproduce the instability or DSB misses on any + * of the following CPUS: + * - Haswell + * - Broadwell: Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GH + * - Skylake + * + * If you are seeing performance stability this script can help test. + * It tests on 4 commits in zstd where I saw performance change. + * + * https://gist.github.com/terrelln/9889fc06a423fd5ca6e99351564473f4 + */ + __asm__(".p2align 5"); + __asm__("nop"); + __asm__(".p2align 4"); #endif - - for ( ; nbSeq ; nbSeq--) { - seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, nbSeq==1); + for ( ; ; ) { + seq_t const sequence = ZSTD_decodeSequence(&seqState, isLongOffset, ZSTD_p_noPrefetch); size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litEnd, prefixStart, vBase, dictEnd); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequence, prefixStart, vBase); #endif - if (UNLIKELY(ZSTD_isError(oneSeqSize))) - return oneSeqSize; DEBUGLOG(6, "regenerated sequence size : %u", (U32)oneSeqSize); - op += oneSeqSize; + BIT_reloadDStream(&(seqState.DStream)); + /* gcc and clang both don't like early returns in this loop. + * gcc doesn't like early breaks either. + * Instead save an error and report it at the end. + * When there is an error, don't increment op, so we don't + * overwrite. + */ + if (UNLIKELY(ZSTD_isError(oneSeqSize))) error = oneSeqSize; + else op += oneSeqSize; + if (UNLIKELY(!--nbSeq)) break; } /* check if reached exact end */ - assert(nbSeq == 0); - RETURN_ERROR_IF(!BIT_endOfDStream(&seqState.DStream), corruption_detected, ""); + DEBUGLOG(5, "ZSTD_decompressSequences_body: after decode loop, remaining nbSeq : %i", nbSeq); + if (ZSTD_isError(error)) return error; + RETURN_ERROR_IF(nbSeq, corruption_detected, ""); + RETURN_ERROR_IF(BIT_reloadDStream(&seqState.DStream) < BIT_DStream_completed, corruption_detected, ""); /* save reps for next block */ { U32 i; for (i=0; ientropy.rep[i] = (U32)(seqState.prevOffset[i]); } } /* last literal segment */ - { size_t const lastLLSize = (size_t)(litEnd - litPtr); - DEBUGLOG(6, "copy last literals : %u", (U32)lastLLSize); + { size_t const lastLLSize = litEnd - litPtr; RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); if (op != NULL) { - ZSTD_memcpy(op, litPtr, lastLLSize); + memcpy(op, litPtr, lastLLSize); op += lastLLSize; - } } + } + } - DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart)); - return (size_t)(op - ostart); + return op-ostart; } static size_t ZSTD_decompressSequences_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); -} - -static size_t -ZSTD_decompressSequencesSplitLitBuffer_default(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) -{ - return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - -FORCE_INLINE_TEMPLATE - -size_t ZSTD_prefetchMatch(size_t prefetchPos, seq_t const sequence, - const BYTE* const prefixStart, const BYTE* const dictEnd) -{ - prefetchPos += sequence.litLength; - { const BYTE* const matchBase = (sequence.offset > prefetchPos) ? dictEnd : prefixStart; - /* note : this operation can overflow when seq.offset is really too large, which can only happen when input is corrupted. - * No consequence though : memory address is only used for prefetching, not for dereferencing */ - const BYTE* const match = ZSTD_wrappedPtrSub(ZSTD_wrappedPtrAdd(matchBase, prefetchPos), sequence.offset); - PREFETCH_L1(match); PREFETCH_L1(match+CACHELINE_SIZE); /* note : it's safe to invoke PREFETCH() on any memory address, including invalid ones */ - } - return prefetchPos + sequence.matchLength; -} - -/* This decoding function employs prefetching - * to reduce latency impact of cache misses. - * It's generally employed when block contains a significant portion of long-distance matches - * or when coupled with a "cold" dictionary */ FORCE_INLINE_TEMPLATE size_t ZSTD_decompressSequencesLong_body( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { const BYTE* ip = (const BYTE*)seqStart; const BYTE* const iend = ip + seqSize; - BYTE* const ostart = (BYTE*)dst; - BYTE* const oend = dctx->litBufferLocation == ZSTD_in_dst ? dctx->litBuffer : ZSTD_maybeNullPtrAdd(ostart, maxDstSize); + BYTE* const ostart = (BYTE* const)dst; + BYTE* const oend = ostart + maxDstSize; BYTE* op = ostart; const BYTE* litPtr = dctx->litPtr; - const BYTE* litBufferEnd = dctx->litBufferEnd; + const BYTE* const litEnd = litPtr + dctx->litSize; const BYTE* const prefixStart = (const BYTE*) (dctx->prefixStart); const BYTE* const dictStart = (const BYTE*) (dctx->virtualStart); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); + (void)frame; /* Regen sequences */ if (nbSeq) { -#define STORED_SEQS 8 +#define STORED_SEQS 4 #define STORED_SEQS_MASK (STORED_SEQS-1) -#define ADVANCED_SEQS STORED_SEQS +#define ADVANCED_SEQS 4 seq_t sequences[STORED_SEQS]; int const seqAdvance = MIN(nbSeq, ADVANCED_SEQS); seqState_t seqState; int seqNb; - size_t prefetchPos = (size_t)(op-prefixStart); /* track position relative to prefixStart */ - dctx->fseEntropy = 1; { int i; for (i=0; ientropy.rep[i]; } + seqState.prefixStart = prefixStart; + seqState.pos = (size_t)(op-prefixStart); + seqState.dictEnd = dictEnd; assert(dst != NULL); assert(iend >= ip); RETURN_ERROR_IF( @@ -1771,95 +1167,37 @@ ZSTD_decompressSequencesLong_body( ZSTD_initFseState(&seqState.stateML, &seqState.DStream, dctx->MLTptr); /* prepare in advance */ - for (seqNb=0; seqNblitBufferLocation == ZSTD_split && litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength > dctx->litBufferEnd) { - /* lit buffer is reaching split point, empty out the first buffer and transition to litExtraBuffer */ - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) - { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - { size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - - prefetchPos = ZSTD_prefetchMatch(prefetchPos, sequence, prefixStart, dictEnd); - sequences[seqNb & STORED_SEQS_MASK] = sequence; - op += oneSeqSize; - } } - else - { - /* lit buffer is either wholly contained in first or second split, or not split at all*/ - size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? - ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK].litLength - WILDCOPY_OVERLENGTH, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : - ZSTD_execSequence(op, oend, sequences[(seqNb - ADVANCED_SEQS) & STORED_SEQS_MASK], &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); + /* decode and decompress */ + for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && (seqNblitBufferLocation == ZSTD_split && litPtr + sequence->litLength > dctx->litBufferEnd) { - const size_t leftoverLit = dctx->litBufferEnd - litPtr; - if (leftoverLit) { - RETURN_ERROR_IF(leftoverLit > (size_t)(oend - op), dstSize_tooSmall, "remaining lit must fit within dstBuffer"); - ZSTD_safecopyDstBeforeSrc(op, litPtr, leftoverLit); - sequence->litLength -= leftoverLit; - op += leftoverLit; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - dctx->litBufferLocation = ZSTD_not_in_dst; - { size_t const oneSeqSize = ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); -#endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } - } - else - { - size_t const oneSeqSize = dctx->litBufferLocation == ZSTD_split ? - ZSTD_execSequenceSplitLitBuffer(op, oend, litPtr + sequence->litLength - WILDCOPY_OVERLENGTH, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd) : - ZSTD_execSequence(op, oend, *sequence, &litPtr, litBufferEnd, prefixStart, dictStart, dictEnd); + size_t const oneSeqSize = ZSTD_execSequence(op, oend, sequences[seqNb&STORED_SEQS_MASK], &litPtr, litEnd, prefixStart, dictStart, dictEnd); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && defined(FUZZING_ASSERT_VALID_SEQUENCE) - assert(!ZSTD_isError(oneSeqSize)); - ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); + assert(!ZSTD_isError(oneSeqSize)); + if (frame) ZSTD_assertValidSequence(dctx, op, oend, sequences[seqNb&STORED_SEQS_MASK], prefixStart, dictStart); #endif - if (ZSTD_isError(oneSeqSize)) return oneSeqSize; - op += oneSeqSize; - } + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; + op += oneSeqSize; } /* save reps for next block */ @@ -1867,34 +1205,25 @@ ZSTD_decompressSequencesLong_body( } /* last literal segment */ - if (dctx->litBufferLocation == ZSTD_split) { /* first deplete literal buffer in dst, then copy litExtraBuffer */ - size_t const lastLLSize = litBufferEnd - litPtr; - RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, ""); - if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); - op += lastLLSize; - } - litPtr = dctx->litExtraBuffer; - litBufferEnd = dctx->litExtraBuffer + ZSTD_LITBUFFEREXTRASIZE; - } - { size_t const lastLLSize = litBufferEnd - litPtr; + { size_t const lastLLSize = litEnd - litPtr; RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, ""); if (op != NULL) { - ZSTD_memmove(op, litPtr, lastLLSize); + memcpy(op, litPtr, lastLLSize); op += lastLLSize; } } - return (size_t)(op - ostart); + return op-ostart; } static size_t ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1903,34 +1232,17 @@ ZSTD_decompressSequencesLong_default(ZSTD_DCtx* dctx, #if DYNAMIC_BMI2 #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG -static BMI2_TARGET_ATTRIBUTE size_t -DONT_VECTORIZE -ZSTD_decompressSequences_bmi2(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) -{ - return ZSTD_decompressSequences_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); -} -static BMI2_TARGET_ATTRIBUTE size_t -DONT_VECTORIZE -ZSTD_decompressSequencesSplitLitBuffer_bmi2(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) -{ - return ZSTD_decompressSequences_bodySplitLitBuffer(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); -} #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -static BMI2_TARGET_ATTRIBUTE size_t +static TARGET_ATTRIBUTE("bmi2") size_t ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { - return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_body(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ @@ -1940,34 +1252,18 @@ typedef size_t (*ZSTD_decompressSequences_t)( ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset); + const ZSTD_longOffset_e isLongOffset, + const int frame); #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG static size_t ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { DEBUGLOG(5, "ZSTD_decompressSequences"); -#if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } -#endif - return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); -} -static size_t -ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) -{ - DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); -#if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } -#endif - return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ @@ -1982,114 +1278,69 @@ static size_t ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* seqStart, size_t seqSize, int nbSeq, - const ZSTD_longOffset_e isLongOffset) + const ZSTD_longOffset_e isLongOffset, + const int frame) { DEBUGLOG(5, "ZSTD_decompressSequencesLong"); #if DYNAMIC_BMI2 - if (ZSTD_DCtx_get_bmi2(dctx)) { - return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + if (dctx->bmi2) { + return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif - return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset, frame); } #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ -/** - * @returns The total size of the history referenceable by zstd, including - * both the prefix and the extDict. At @p op any offset larger than this - * is invalid. - */ -static size_t ZSTD_totalHistorySize(BYTE* op, BYTE const* virtualStart) -{ - return (size_t)(op - virtualStart); -} -typedef struct { - unsigned longOffsetShare; - unsigned maxNbAdditionalBits; -} ZSTD_OffsetInfo; - -/* ZSTD_getOffsetInfo() : +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) +/* ZSTD_getLongOffsetsShare() : * condition : offTable must be valid * @return : "share" of long offsets (arbitrarily defined as > (1<<23)) - * compared to maximum possible of (1< 22) info.longOffsetShare += 1; - } - - assert(tableLog <= OffFSELog); - info.longOffsetShare <<= (OffFSELog - tableLog); /* scale to OffFSELog */ + const void* ptr = offTable; + U32 const tableLog = ((const ZSTD_seqSymbol_header*)ptr)[0].tableLog; + const ZSTD_seqSymbol* table = offTable + 1; + U32 const max = 1 << tableLog; + U32 u, total = 0; + DEBUGLOG(5, "ZSTD_getLongOffsetsShare: (tableLog=%u)", tableLog); + + assert(max <= (1 << OffFSELog)); /* max not too large */ + for (u=0; u 22) total += 1; } - return info; -} + assert(tableLog <= OffFSELog); + total <<= (OffFSELog - tableLog); /* scale to OffFSELog */ -/** - * @returns The maximum offset we can decode in one read of our bitstream, without - * reloading more bits in the middle of the offset bits read. Any offsets larger - * than this must use the long offset decoder. - */ -static size_t ZSTD_maxShortOffset(void) -{ - if (MEM_64bits()) { - /* We can decode any offset without reloading bits. - * This might change if the max window size grows. - */ - ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); - return (size_t)-1; - } else { - /* The maximum offBase is (1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1. - * This offBase would require STREAM_ACCUMULATOR_MIN extra bits. - * Then we have to subtract ZSTD_REP_NUM to get the maximum possible offset. - */ - size_t const maxOffbase = ((size_t)1 << (STREAM_ACCUMULATOR_MIN + 1)) - 1; - size_t const maxOffset = maxOffbase - ZSTD_REP_NUM; - assert(ZSTD_highbit32((U32)maxOffbase) == STREAM_ACCUMULATOR_MIN); - return maxOffset; - } + return total; } +#endif size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const streaming_operation streaming) + const void* src, size_t srcSize, const int frame) { /* blockType == blockCompressed */ const BYTE* ip = (const BYTE*)src; - DEBUGLOG(5, "ZSTD_decompressBlock_internal (cSize : %u)", (unsigned)srcSize); - - /* Note : the wording of the specification - * allows compressed block to be sized exactly ZSTD_blockSizeMax(dctx). - * This generally does not happen, as it makes little sense, - * since an uncompressed block would feature same size and have no decompression cost. - * Also, note that decoder from reference libzstd before < v1.5.4 - * would consider this edge case as an error. - * As a consequence, avoid generating compressed blocks of size ZSTD_blockSizeMax(dctx) - * for broader compatibility with the deployed ecosystem of zstd decoders */ - RETURN_ERROR_IF(srcSize > ZSTD_blockSizeMax(dctx), srcSize_wrong, ""); + /* isLongOffset must be true if there are long offsets. + * Offsets are long if they are larger than 2^STREAM_ACCUMULATOR_MIN. + * We don't expect that to be the case in 64-bit mode. + * In block mode, window size is not known, so we have to be conservative. + * (note: but it could be evaluated from current-lowLimit) + */ + ZSTD_longOffset_e const isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (!frame || (dctx->fParams.windowSize > (1ULL << STREAM_ACCUMULATOR_MIN)))); + DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize); + + RETURN_ERROR_IF(srcSize >= ZSTD_BLOCKSIZE_MAX, srcSize_wrong, ""); /* Decode literals section */ - { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); - DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); + { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; @@ -2097,23 +1348,6 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, /* Build Decoding Tables */ { - /* Compute the maximum block size, which must also work when !frame and fParams are unset. - * Additionally, take the min with dstCapacity to ensure that the totalHistorySize fits in a size_t. - */ - size_t const blockSizeMax = MIN(dstCapacity, ZSTD_blockSizeMax(dctx)); - size_t const totalHistorySize = ZSTD_totalHistorySize(ZSTD_maybeNullPtrAdd((BYTE*)dst, blockSizeMax), (BYTE const*)dctx->virtualStart); - /* isLongOffset must be true if there are long offsets. - * Offsets are long if they are larger than ZSTD_maxShortOffset(). - * We don't expect that to be the case in 64-bit mode. - * - * We check here to see if our history is large enough to allow long offsets. - * If it isn't, then we can't possible have (valid) long offsets. If the offset - * is invalid, then it is okay to read it incorrectly. - * - * If isLongOffsets is true, then we will later check our decoding table to see - * if it is even possible to generate long offsets. - */ - ZSTD_longOffset_e isLongOffset = (ZSTD_longOffset_e)(MEM_32bits() && (totalHistorySize > ZSTD_maxShortOffset())); /* These macros control at build-time which decompressor implementation * we use. If neither is defined, we do some inspection and dispatch at * runtime. @@ -2121,11 +1355,6 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) int usePrefetchDecoder = dctx->ddictIsCold; -#else - /* Set to 1 to avoid computing offset info if we don't need to. - * Otherwise this value is ignored. - */ - int usePrefetchDecoder = 1; #endif int nbSeq; size_t const seqHSize = ZSTD_decodeSeqHeaders(dctx, &nbSeq, ip, srcSize); @@ -2133,58 +1362,40 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, ip += seqHSize; srcSize -= seqHSize; - RETURN_ERROR_IF((dst == NULL || dstCapacity == 0) && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); - RETURN_ERROR_IF(MEM_64bits() && sizeof(size_t) == sizeof(void*) && (size_t)(-1) - (size_t)dst < (size_t)(1 << 20), dstSize_tooSmall, - "invalid dst"); + RETURN_ERROR_IF(dst == NULL && nbSeq > 0, dstSize_tooSmall, "NULL not handled"); - /* If we could potentially have long offsets, or we might want to use the prefetch decoder, - * compute information about the share of long offsets, and the maximum nbAdditionalBits. - * NOTE: could probably use a larger nbSeq limit - */ - if (isLongOffset || (!usePrefetchDecoder && (totalHistorySize > (1u << 24)) && (nbSeq > 8))) { - ZSTD_OffsetInfo const info = ZSTD_getOffsetInfo(dctx->OFTptr, nbSeq); - if (isLongOffset && info.maxNbAdditionalBits <= STREAM_ACCUMULATOR_MIN) { - /* If isLongOffset, but the maximum number of additional bits that we see in our table is small - * enough, then we know it is impossible to have too long an offset in this block, so we can - * use the regular offset decoder. - */ - isLongOffset = ZSTD_lo_isRegularOffset; - } - if (!usePrefetchDecoder) { - U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ - usePrefetchDecoder = (info.longOffsetShare >= minShare); - } +#if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ + !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) + if ( !usePrefetchDecoder + && (!frame || (dctx->fParams.windowSize > (1<<24))) + && (nbSeq>ADVANCED_SEQS) ) { /* could probably use a larger nbSeq limit */ + U32 const shareLongOffsets = ZSTD_getLongOffsetsShare(dctx->OFTptr); + U32 const minShare = MEM_64bits() ? 7 : 20; /* heuristic values, correspond to 2.73% and 7.81% */ + usePrefetchDecoder = (shareLongOffsets >= minShare); } +#endif dctx->ddictIsCold = 0; #if !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT) && \ !defined(ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG) - if (usePrefetchDecoder) { -#else - (void)usePrefetchDecoder; - { + if (usePrefetchDecoder) #endif #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT - return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); + return ZSTD_decompressSequencesLong(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); #endif - } #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG /* else */ - if (dctx->litBufferLocation == ZSTD_split) - return ZSTD_decompressSequencesSplitLitBuffer(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); - else - return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset); + return ZSTD_decompressSequences(dctx, dst, dstCapacity, ip, srcSize, nbSeq, isLongOffset, frame); #endif } } -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) { - if (dst != dctx->previousDstEnd && dstSize > 0) { /* not contiguous */ + if (dst != dctx->previousDstEnd) { /* not contiguous */ dctx->dictEnd = dctx->previousDstEnd; dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart)); dctx->prefixStart = dst; @@ -2193,26 +1404,15 @@ void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize) } -size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) +size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize) { size_t dSize; - dctx->isFrameDecompression = 0; - ZSTD_checkContinuity(dctx, dst, dstCapacity); - dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, not_streaming); - FORWARD_IF_ERROR(dSize, ""); + ZSTD_checkContinuity(dctx, dst); + dSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 0); dctx->previousDstEnd = (char*)dst + dSize; return dSize; } - -/* NOTE: Must just wrap ZSTD_decompressBlock_deprecated() */ -size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize) -{ - return ZSTD_decompressBlock_deprecated(dctx, dst, dstCapacity, src, srcSize); } - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp deleted file mode 100644 index 489498ce4..000000000 --- a/src/duckdb/third_party/zstd/deprecated/zbuff_common.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/*-************************************* -* Dependencies -***************************************/ -#include "zstd/common/error_private.h" -#include "zstd/deprecated/zbuff.h" - -namespace duckdb_zstd { - -/*-**************************************** -* ZBUFF Error Management (deprecated) -******************************************/ - -/*! ZBUFF_isError() : -* tells if a return value is an error code */ -unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); } -/*! ZBUFF_getErrorName() : -* provides error code string from function result (useful for debugging) */ -const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp deleted file mode 100644 index 5c63dac49..000000000 --- a/src/duckdb/third_party/zstd/deprecated/zbuff_compress.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - - -/* ************************************* -* Dependencies -***************************************/ -#define ZBUFF_STATIC_LINKING_ONLY -#include "zstd/deprecated/zbuff.h" -#include "zstd/common/error_private.h" - - -/*-*********************************************************** -* Streaming compression -* -* A ZBUFF_CCtx object is required to track streaming operation. -* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. -* Use ZBUFF_compressInit() to start a new compression operation. -* ZBUFF_CCtx objects can be reused multiple times. -* -* Use ZBUFF_compressContinue() repetitively to consume your input. -* *srcSizePtr and *dstCapacityPtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. -* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. -* The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst . -* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) -* or an error code, which can be tested using ZBUFF_isError(). -* -* ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. -* Note that it will not output more than *dstCapacityPtr. -* Therefore, some content might still be left into its internal buffer if dst buffer is too small. -* @return : nb of bytes still present into internal buffer (0 if it's empty) -* or an error code, which can be tested using ZBUFF_isError(). -* -* ZBUFF_compressEnd() instructs to finish a frame. -* It will perform a flush and write frame epilogue. -* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. -* @return : nb of bytes still present into internal buffer (0 if it's empty) -* or an error code, which can be tested using ZBUFF_isError(). -* -* Hint : recommended buffer sizes (not compulsory) -* input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value. -* output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed. -* ***********************************************************/ - -namespace duckdb_zstd { - -ZBUFF_CCtx* ZBUFF_createCCtx(void) -{ - return ZSTD_createCStream(); -} - -ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem) -{ - return ZSTD_createCStream_advanced(customMem); -} - -size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) -{ - return ZSTD_freeCStream(zbc); -} - - -/* ====== Initialization ====== */ - -size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, - const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize) -{ - if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* preserve "0 == unknown" behavior */ - FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setPledgedSrcSize(zbc, pledgedSrcSize), ""); - - FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_windowLog, params.cParams.windowLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_hashLog, params.cParams.hashLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_chainLog, params.cParams.chainLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_searchLog, params.cParams.searchLog), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_minMatch, params.cParams.minMatch), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_targetLength, params.cParams.targetLength), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_strategy, params.cParams.strategy), ""); - - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_contentSizeFlag, params.fParams.contentSizeFlag), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_checksumFlag, params.fParams.checksumFlag), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_dictIDFlag, params.fParams.noDictIDFlag), ""); - - FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); - return 0; -} - -size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) -{ - FORWARD_IF_ERROR(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(zbc, ZSTD_c_compressionLevel, compressionLevel), ""); - FORWARD_IF_ERROR(ZSTD_CCtx_loadDictionary(zbc, dict, dictSize), ""); - return 0; -} - -size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) -{ - return ZSTD_initCStream(zbc, compressionLevel); -} - -/* ====== Compression ====== */ - - -size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr) -{ - size_t result; - ZSTD_outBuffer outBuff; - ZSTD_inBuffer inBuff; - outBuff.dst = dst; - outBuff.pos = 0; - outBuff.size = *dstCapacityPtr; - inBuff.src = src; - inBuff.pos = 0; - inBuff.size = *srcSizePtr; - result = ZSTD_compressStream(zbc, &outBuff, &inBuff); - *dstCapacityPtr = outBuff.pos; - *srcSizePtr = inBuff.pos; - return result; -} - - - -/* ====== Finalize ====== */ - -size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) -{ - size_t result; - ZSTD_outBuffer outBuff; - outBuff.dst = dst; - outBuff.pos = 0; - outBuff.size = *dstCapacityPtr; - result = ZSTD_flushStream(zbc, &outBuff); - *dstCapacityPtr = outBuff.pos; - return result; -} - - -size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) -{ - size_t result; - ZSTD_outBuffer outBuff; - outBuff.dst = dst; - outBuff.pos = 0; - outBuff.size = *dstCapacityPtr; - result = ZSTD_endStream(zbc, &outBuff); - *dstCapacityPtr = outBuff.pos; - return result; -} - - - -/* ************************************* -* Tool functions -***************************************/ -size_t ZBUFF_recommendedCInSize(void) { return ZSTD_CStreamInSize(); } -size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_CStreamOutSize(); } - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp b/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp deleted file mode 100644 index c55fd5690..000000000 --- a/src/duckdb/third_party/zstd/deprecated/zbuff_decompress.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - - -/* ************************************* -* Dependencies -***************************************/ -#define ZSTD_DISABLE_DEPRECATE_WARNINGS /* suppress warning on ZSTD_initDStream_usingDict */ -#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ -#define ZBUFF_STATIC_LINKING_ONLY -#include "zstd/deprecated/zbuff.h" - -namespace duckdb_zstd { - -ZBUFF_DCtx* ZBUFF_createDCtx(void) -{ - return ZSTD_createDStream(); -} - -ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem) -{ - return ZSTD_createDStream_advanced(customMem); -} - -size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd) -{ - return ZSTD_freeDStream(zbd); -} - - -/* *** Initialization *** */ - -size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize) -{ - return ZSTD_initDStream_usingDict(zbd, dict, dictSize); -} - -size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd) -{ - return ZSTD_initDStream(zbd); -} - - -/* *** Decompression *** */ - -size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr) -{ - ZSTD_outBuffer outBuff; - ZSTD_inBuffer inBuff; - size_t result; - outBuff.dst = dst; - outBuff.pos = 0; - outBuff.size = *dstCapacityPtr; - inBuff.src = src; - inBuff.pos = 0; - inBuff.size = *srcSizePtr; - result = ZSTD_decompressStream(zbd, &outBuff, &inBuff); - *dstCapacityPtr = outBuff.pos; - *srcSizePtr = inBuff.pos; - return result; -} - - -/* ************************************* -* Tool functions -***************************************/ -size_t ZBUFF_recommendedDInSize(void) { return ZSTD_DStreamInSize(); } -size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_DStreamOutSize(); } - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/cover.cpp b/src/duckdb/third_party/zstd/dict/cover.cpp deleted file mode 100644 index 28f4e0909..000000000 --- a/src/duckdb/third_party/zstd/dict/cover.cpp +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* ***************************************************************************** - * Constructs a dictionary using a heuristic based on the following paper: - * - * Liao, Petri, Moffat, Wirth - * Effective Construction of Relative Lempel-Ziv Dictionaries - * Published in WWW 2016. - * - * Adapted from code originally written by @ot (Giuseppe Ottaviano). - ******************************************************************************/ - -/*-************************************* -* Dependencies -***************************************/ -#include /* fprintf */ -#include /* malloc, free, qsort */ -#include /* memset */ -#include /* clock */ - -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - -#include "zstd/common/mem.h" /* read */ -#include "zstd/common/pool.h" /* POOL_ctx */ -#include "zstd/common/threading.h" /* ZSTD_pthread_mutex_t */ -#include "zstd/common/zstd_internal.h" /* includes zstd.h */ -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ -#include "zdict.h" -#include "zstd/dict/cover.h" - -/*-************************************* -* Constants -***************************************/ -/** -* There are 32bit indexes used to ref samples, so limit samples size to 4GB -* on 64bit builds. -* For 32bit builds we choose 1 GB. -* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large -* contiguous buffer, so 1GB is already a high limit. -*/ -#define COVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) -#define COVER_DEFAULT_SPLITPOINT 1.0 - -/*-************************************* -* Console display -***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif -#undef DISPLAY -// CRAN does not allow stderr references -#define DISPLAY(...) \ - { \ - } -#undef LOCALDISPLAYLEVEL -#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ - if (displayLevel >= l) { \ - DISPLAY(__VA_ARGS__); \ - } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL -#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) - -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE -#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ - if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ - g_time = clock(); \ - DISPLAY(__VA_ARGS__); \ - } \ - } -#undef DISPLAYUPDATE -#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) - -namespace duckdb_zstd { - -/*-************************************* -* Hash table -*************************************** -* A small specialized hash map for storing activeDmers. -* The map does not resize, so if it becomes full it will loop forever. -* Thus, the map must be large enough to store every value. -* The map implements linear probing and keeps its load less than 0.5. -*/ - -#define MAP_EMPTY_VALUE ((U32)-1) -typedef struct COVER_map_pair_t_s { - U32 key; - U32 value; -} COVER_map_pair_t; - -typedef struct COVER_map_s { - COVER_map_pair_t *data; - U32 sizeLog; - U32 size; - U32 sizeMask; -} COVER_map_t; - -/** - * Clear the map. - */ -static void COVER_map_clear(COVER_map_t *map) { - memset(map->data, MAP_EMPTY_VALUE, map->size * sizeof(COVER_map_pair_t)); -} - -/** - * Initializes a map of the given size. - * Returns 1 on success and 0 on failure. - * The map must be destroyed with COVER_map_destroy(). - * The map is only guaranteed to be large enough to hold size elements. - */ -static int COVER_map_init(COVER_map_t *map, U32 size) { - map->sizeLog = ZSTD_highbit32(size) + 2; - map->size = (U32)1 << map->sizeLog; - map->sizeMask = map->size - 1; - map->data = (COVER_map_pair_t *)malloc(map->size * sizeof(COVER_map_pair_t)); - if (!map->data) { - map->sizeLog = 0; - map->size = 0; - return 0; - } - COVER_map_clear(map); - return 1; -} - -/** - * Internal hash function - */ -static const U32 COVER_prime4bytes = 2654435761U; -static U32 COVER_map_hash(COVER_map_t *map, U32 key) { - return (key * COVER_prime4bytes) >> (32 - map->sizeLog); -} - -/** - * Helper function that returns the index that a key should be placed into. - */ -static U32 COVER_map_index(COVER_map_t *map, U32 key) { - const U32 hash = COVER_map_hash(map, key); - U32 i; - for (i = hash;; i = (i + 1) & map->sizeMask) { - COVER_map_pair_t *pos = &map->data[i]; - if (pos->value == MAP_EMPTY_VALUE) { - return i; - } - if (pos->key == key) { - return i; - } - } -} - -/** - * Returns the pointer to the value for key. - * If key is not in the map, it is inserted and the value is set to 0. - * The map must not be full. - */ -static U32 *COVER_map_at(COVER_map_t *map, U32 key) { - COVER_map_pair_t *pos = &map->data[COVER_map_index(map, key)]; - if (pos->value == MAP_EMPTY_VALUE) { - pos->key = key; - pos->value = 0; - } - return &pos->value; -} - -/** - * Deletes key from the map if present. - */ -static void COVER_map_remove(COVER_map_t *map, U32 key) { - U32 i = COVER_map_index(map, key); - COVER_map_pair_t *del = &map->data[i]; - U32 shift = 1; - if (del->value == MAP_EMPTY_VALUE) { - return; - } - for (i = (i + 1) & map->sizeMask;; i = (i + 1) & map->sizeMask) { - COVER_map_pair_t *const pos = &map->data[i]; - /* If the position is empty we are done */ - if (pos->value == MAP_EMPTY_VALUE) { - del->value = MAP_EMPTY_VALUE; - return; - } - /* If pos can be moved to del do so */ - if (((i - COVER_map_hash(map, pos->key)) & map->sizeMask) >= shift) { - del->key = pos->key; - del->value = pos->value; - del = pos; - shift = 1; - } else { - ++shift; - } - } -} - -/** - * Destroys a map that is inited with COVER_map_init(). - */ -static void COVER_map_destroy(COVER_map_t *map) { - if (map->data) { - free(map->data); - } - map->data = NULL; - map->size = 0; -} - -/*-************************************* -* Context -***************************************/ - -typedef struct { - const BYTE *samples; - size_t *offsets; - const size_t *samplesSizes; - size_t nbSamples; - size_t nbTrainSamples; - size_t nbTestSamples; - U32 *suffix; - size_t suffixSize; - U32 *freqs; - U32 *dmerAt; - unsigned d; -} COVER_ctx_t; - -/* We need a global context for qsort... */ -static COVER_ctx_t *g_coverCtx = NULL; - -/*-************************************* -* Helper functions -***************************************/ - -/** - * Returns the sum of the sample sizes. - */ -size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) { - size_t sum = 0; - unsigned i; - for (i = 0; i < nbSamples; ++i) { - sum += samplesSizes[i]; - } - return sum; -} - -/** - * Returns -1 if the dmer at lp is less than the dmer at rp. - * Return 0 if the dmers at lp and rp are equal. - * Returns 1 if the dmer at lp is greater than the dmer at rp. - */ -static int COVER_cmp(COVER_ctx_t *ctx, const void *lp, const void *rp) { - U32 const lhs = *(U32 const *)lp; - U32 const rhs = *(U32 const *)rp; - return memcmp(ctx->samples + lhs, ctx->samples + rhs, ctx->d); -} -/** - * Faster version for d <= 8. - */ -static int COVER_cmp8(COVER_ctx_t *ctx, const void *lp, const void *rp) { - U64 const mask = (ctx->d == 8) ? (U64)-1 : (((U64)1 << (8 * ctx->d)) - 1); - U64 const lhs = MEM_readLE64(ctx->samples + *(U32 const *)lp) & mask; - U64 const rhs = MEM_readLE64(ctx->samples + *(U32 const *)rp) & mask; - if (lhs < rhs) { - return -1; - } - return (lhs > rhs); -} - -/** - * Same as COVER_cmp() except ties are broken by pointer value - * NOTE: g_coverCtx must be set to call this function. A global is required because - * qsort doesn't take an opaque pointer. - */ -static int WIN_CDECL COVER_strict_cmp(const void *lp, const void *rp) { - int result = COVER_cmp(g_coverCtx, lp, rp); - if (result == 0) { - result = lp < rp ? -1 : 1; - } - return result; -} -/** - * Faster version for d <= 8. - */ -static int WIN_CDECL COVER_strict_cmp8(const void *lp, const void *rp) { - int result = COVER_cmp8(g_coverCtx, lp, rp); - if (result == 0) { - result = lp < rp ? -1 : 1; - } - return result; -} - -/** - * Returns the first pointer in [first, last) whose element does not compare - * less than value. If no such element exists it returns last. - */ -static const size_t *COVER_lower_bound(const size_t* first, const size_t* last, - size_t value) { - size_t count = (size_t)(last - first); - assert(last >= first); - while (count != 0) { - size_t step = count / 2; - const size_t *ptr = first; - ptr += step; - if (*ptr < value) { - first = ++ptr; - count -= step + 1; - } else { - count = step; - } - } - return first; -} - -/** - * Generic groupBy function. - * Groups an array sorted by cmp into groups with equivalent values. - * Calls grp for each group. - */ -static void -COVER_groupBy(const void *data, size_t count, size_t size, COVER_ctx_t *ctx, - int (*cmp)(COVER_ctx_t *, const void *, const void *), - void (*grp)(COVER_ctx_t *, const void *, const void *)) { - const BYTE *ptr = (const BYTE *)data; - size_t num = 0; - while (num < count) { - const BYTE *grpEnd = ptr + size; - ++num; - while (num < count && cmp(ctx, ptr, grpEnd) == 0) { - grpEnd += size; - ++num; - } - grp(ctx, ptr, grpEnd); - ptr = grpEnd; - } -} - -/*-************************************* -* Cover functions -***************************************/ - -/** - * Called on each group of positions with the same dmer. - * Counts the frequency of each dmer and saves it in the suffix array. - * Fills `ctx->dmerAt`. - */ -static void COVER_group(COVER_ctx_t *ctx, const void *group, - const void *groupEnd) { - /* The group consists of all the positions with the same first d bytes. */ - const U32 *grpPtr = (const U32 *)group; - const U32 *grpEnd = (const U32 *)groupEnd; - /* The dmerId is how we will reference this dmer. - * This allows us to map the whole dmer space to a much smaller space, the - * size of the suffix array. - */ - const U32 dmerId = (U32)(grpPtr - ctx->suffix); - /* Count the number of samples this dmer shows up in */ - U32 freq = 0; - /* Details */ - const size_t *curOffsetPtr = ctx->offsets; - const size_t *offsetsEnd = ctx->offsets + ctx->nbSamples; - /* Once *grpPtr >= curSampleEnd this occurrence of the dmer is in a - * different sample than the last. - */ - size_t curSampleEnd = ctx->offsets[0]; - for (; grpPtr != grpEnd; ++grpPtr) { - /* Save the dmerId for this position so we can get back to it. */ - ctx->dmerAt[*grpPtr] = dmerId; - /* Dictionaries only help for the first reference to the dmer. - * After that zstd can reference the match from the previous reference. - * So only count each dmer once for each sample it is in. - */ - if (*grpPtr < curSampleEnd) { - continue; - } - freq += 1; - /* Binary search to find the end of the sample *grpPtr is in. - * In the common case that grpPtr + 1 == grpEnd we can skip the binary - * search because the loop is over. - */ - if (grpPtr + 1 != grpEnd) { - const size_t *sampleEndPtr = - COVER_lower_bound(curOffsetPtr, offsetsEnd, *grpPtr); - curSampleEnd = *sampleEndPtr; - curOffsetPtr = sampleEndPtr + 1; - } - } - /* At this point we are never going to look at this segment of the suffix - * array again. We take advantage of this fact to save memory. - * We store the frequency of the dmer in the first position of the group, - * which is dmerId. - */ - ctx->suffix[dmerId] = freq; -} - - -/** - * Selects the best segment in an epoch. - * Segments of are scored according to the function: - * - * Let F(d) be the frequency of dmer d. - * Let S_i be the dmer at position i of segment S which has length k. - * - * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1}) - * - * Once the dmer d is in the dictionary we set F(d) = 0. - */ -static COVER_segment_t COVER_selectSegment(const COVER_ctx_t *ctx, U32 *freqs, - COVER_map_t *activeDmers, U32 begin, - U32 end, - ZDICT_cover_params_t parameters) { - /* Constants */ - const U32 k = parameters.k; - const U32 d = parameters.d; - const U32 dmersInK = k - d + 1; - /* Try each segment (activeSegment) and save the best (bestSegment) */ - COVER_segment_t bestSegment = {0, 0, 0}; - COVER_segment_t activeSegment; - /* Reset the activeDmers in the segment */ - COVER_map_clear(activeDmers); - /* The activeSegment starts at the beginning of the epoch. */ - activeSegment.begin = begin; - activeSegment.end = begin; - activeSegment.score = 0; - /* Slide the activeSegment through the whole epoch. - * Save the best segment in bestSegment. - */ - while (activeSegment.end < end) { - /* The dmerId for the dmer at the next position */ - U32 newDmer = ctx->dmerAt[activeSegment.end]; - /* The entry in activeDmers for this dmerId */ - U32 *newDmerOcc = COVER_map_at(activeDmers, newDmer); - /* If the dmer isn't already present in the segment add its score. */ - if (*newDmerOcc == 0) { - /* The paper suggest using the L-0.5 norm, but experiments show that it - * doesn't help. - */ - activeSegment.score += freqs[newDmer]; - } - /* Add the dmer to the segment */ - activeSegment.end += 1; - *newDmerOcc += 1; - - /* If the window is now too large, drop the first position */ - if (activeSegment.end - activeSegment.begin == dmersInK + 1) { - U32 delDmer = ctx->dmerAt[activeSegment.begin]; - U32 *delDmerOcc = COVER_map_at(activeDmers, delDmer); - activeSegment.begin += 1; - *delDmerOcc -= 1; - /* If this is the last occurrence of the dmer, subtract its score */ - if (*delDmerOcc == 0) { - COVER_map_remove(activeDmers, delDmer); - activeSegment.score -= freqs[delDmer]; - } - } - - /* If this segment is the best so far save it */ - if (activeSegment.score > bestSegment.score) { - bestSegment = activeSegment; - } - } - { - /* Trim off the zero frequency head and tail from the segment. */ - U32 newBegin = bestSegment.end; - U32 newEnd = bestSegment.begin; - U32 pos; - for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { - U32 freq = freqs[ctx->dmerAt[pos]]; - if (freq != 0) { - newBegin = MIN(newBegin, pos); - newEnd = pos + 1; - } - } - bestSegment.begin = newBegin; - bestSegment.end = newEnd; - } - { - /* Zero out the frequency of each dmer covered by the chosen segment. */ - U32 pos; - for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { - freqs[ctx->dmerAt[pos]] = 0; - } - } - return bestSegment; -} - -/** - * Check the validity of the parameters. - * Returns non-zero if the parameters are valid and 0 otherwise. - */ -static int COVER_checkParameters(ZDICT_cover_params_t parameters, - size_t maxDictSize) { - /* k and d are required parameters */ - if (parameters.d == 0 || parameters.k == 0) { - return 0; - } - /* k <= maxDictSize */ - if (parameters.k > maxDictSize) { - return 0; - } - /* d <= k */ - if (parameters.d > parameters.k) { - return 0; - } - /* 0 < splitPoint <= 1 */ - if (parameters.splitPoint <= 0 || parameters.splitPoint > 1){ - return 0; - } - return 1; -} - -/** - * Clean up a context initialized with `COVER_ctx_init()`. - */ -static void COVER_ctx_destroy(COVER_ctx_t *ctx) { - if (!ctx) { - return; - } - if (ctx->suffix) { - free(ctx->suffix); - ctx->suffix = NULL; - } - if (ctx->freqs) { - free(ctx->freqs); - ctx->freqs = NULL; - } - if (ctx->dmerAt) { - free(ctx->dmerAt); - ctx->dmerAt = NULL; - } - if (ctx->offsets) { - free(ctx->offsets); - ctx->offsets = NULL; - } -} - -/** - * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can be used multiple - * times. - * Returns 0 on success or error code on error. - * The context must be destroyed with `COVER_ctx_destroy()`. - */ -static size_t COVER_ctx_init(COVER_ctx_t *ctx, const void *samplesBuffer, - const size_t *samplesSizes, unsigned nbSamples, - unsigned d, double splitPoint) -{ - const BYTE *const samples = (const BYTE *)samplesBuffer; - const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); - /* Split samples into testing and training sets */ - const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples; - const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; - const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; - const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; - - (void) testSamplesSize; - - /* Checks */ - if (totalSamplesSize < MAX(d, sizeof(U64)) || - totalSamplesSize >= (size_t)COVER_MAX_SAMPLES_SIZE) { - DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n", - (unsigned)(totalSamplesSize>>20), (COVER_MAX_SAMPLES_SIZE >> 20)); - return ERROR(srcSize_wrong); - } - /* Check if there are at least 5 training samples */ - if (nbTrainSamples < 5) { - DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid.", nbTrainSamples); - return ERROR(srcSize_wrong); - } - /* Check if there's testing sample */ - if (nbTestSamples < 1) { - DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.", nbTestSamples); - return ERROR(srcSize_wrong); - } - /* Zero the context */ - memset(ctx, 0, sizeof(*ctx)); - DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples, - (unsigned)trainingSamplesSize); - DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples, - (unsigned)testSamplesSize); - ctx->samples = samples; - ctx->samplesSizes = samplesSizes; - ctx->nbSamples = nbSamples; - ctx->nbTrainSamples = nbTrainSamples; - ctx->nbTestSamples = nbTestSamples; - /* Partial suffix array */ - ctx->suffixSize = trainingSamplesSize - MAX(d, sizeof(U64)) + 1; - ctx->suffix = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); - /* Maps index to the dmerID */ - ctx->dmerAt = (U32 *)malloc(ctx->suffixSize * sizeof(U32)); - /* The offsets of each file */ - ctx->offsets = (size_t *)malloc((nbSamples + 1) * sizeof(size_t)); - if (!ctx->suffix || !ctx->dmerAt || !ctx->offsets) { - DISPLAYLEVEL(1, "Failed to allocate scratch buffers\n"); - COVER_ctx_destroy(ctx); - return ERROR(memory_allocation); - } - ctx->freqs = NULL; - ctx->d = d; - - /* Fill offsets from the samplesSizes */ - { - U32 i; - ctx->offsets[0] = 0; - for (i = 1; i <= nbSamples; ++i) { - ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1]; - } - } - DISPLAYLEVEL(2, "Constructing partial suffix array\n"); - { - /* suffix is a partial suffix array. - * It only sorts suffixes by their first parameters.d bytes. - * The sort is stable, so each dmer group is sorted by position in input. - */ - U32 i; - for (i = 0; i < ctx->suffixSize; ++i) { - ctx->suffix[i] = i; - } - /* qsort doesn't take an opaque pointer, so pass as a global. - * On OpenBSD qsort() is not guaranteed to be stable, their mergesort() is. - */ - g_coverCtx = ctx; -#if defined(__OpenBSD__) - mergesort(ctx->suffix, ctx->suffixSize, sizeof(U32), - (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); -#else - qsort(ctx->suffix, ctx->suffixSize, sizeof(U32), - (ctx->d <= 8 ? &COVER_strict_cmp8 : &COVER_strict_cmp)); -#endif - } - DISPLAYLEVEL(2, "Computing frequencies\n"); - /* For each dmer group (group of positions with the same first d bytes): - * 1. For each position we set dmerAt[position] = dmerID. The dmerID is - * (groupBeginPtr - suffix). This allows us to go from position to - * dmerID so we can look up values in freq. - * 2. We calculate how many samples the dmer occurs in and save it in - * freqs[dmerId]. - */ - COVER_groupBy(ctx->suffix, ctx->suffixSize, sizeof(U32), ctx, - (ctx->d <= 8 ? &COVER_cmp8 : &COVER_cmp), &COVER_group); - ctx->freqs = ctx->suffix; - ctx->suffix = NULL; - return 0; -} - -void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel) -{ - const double ratio = (double)nbDmers / (double)maxDictSize; - if (ratio >= 10) { - return; - } - LOCALDISPLAYLEVEL(displayLevel, 1, - "WARNING: The maximum dictionary size %u is too large " - "compared to the source size %u! " - "size(source)/size(dictionary) = %f, but it should be >= " - "10! This may lead to a subpar dictionary! We recommend " - "training on sources at least 10x, and preferably 100x " - "the size of the dictionary! \n", (U32)maxDictSize, - (U32)nbDmers, ratio); -} - -COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, - U32 nbDmers, U32 k, U32 passes) -{ - const U32 minEpochSize = k * 10; - COVER_epoch_info_t epochs; - epochs.num = MAX(1, maxDictSize / k / passes); - epochs.size = nbDmers / epochs.num; - if (epochs.size >= minEpochSize) { - assert(epochs.size * epochs.num <= nbDmers); - return epochs; - } - epochs.size = MIN(minEpochSize, nbDmers); - epochs.num = nbDmers / epochs.size; - assert(epochs.size * epochs.num <= nbDmers); - return epochs; -} - -/** - * Given the prepared context build the dictionary. - */ -static size_t COVER_buildDictionary(const COVER_ctx_t *ctx, U32 *freqs, - COVER_map_t *activeDmers, void *dictBuffer, - size_t dictBufferCapacity, - ZDICT_cover_params_t parameters) { - BYTE *const dict = (BYTE *)dictBuffer; - size_t tail = dictBufferCapacity; - /* Divide the data into epochs. We will select one segment from each epoch. */ - const COVER_epoch_info_t epochs = COVER_computeEpochs( - (U32)dictBufferCapacity, (U32)ctx->suffixSize, parameters.k, 4); - const size_t maxZeroScoreRun = MAX(10, MIN(100, epochs.num >> 3)); - size_t zeroScoreRun = 0; - size_t epoch; - DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", - (U32)epochs.num, (U32)epochs.size); - /* Loop through the epochs until there are no more segments or the dictionary - * is full. - */ - for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs.num) { - const U32 epochBegin = (U32)(epoch * epochs.size); - const U32 epochEnd = epochBegin + epochs.size; - size_t segmentSize; - /* Select a segment */ - COVER_segment_t segment = COVER_selectSegment( - ctx, freqs, activeDmers, epochBegin, epochEnd, parameters); - /* If the segment covers no dmers, then we are out of content. - * There may be new content in other epochs, for continue for some time. - */ - if (segment.score == 0) { - if (++zeroScoreRun >= maxZeroScoreRun) { - break; - } - continue; - } - zeroScoreRun = 0; - /* Trim the segment if necessary and if it is too small then we are done */ - segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); - if (segmentSize < parameters.d) { - break; - } - /* We fill the dictionary from the back to allow the best segments to be - * referenced with the smallest offsets. - */ - tail -= segmentSize; - memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); - DISPLAYUPDATE( - 2, "\r%u%% ", - (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); - } - DISPLAYLEVEL(2, "\r%79s\r", ""); - return tail; -} - -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( - void *dictBuffer, size_t dictBufferCapacity, - const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t parameters) -{ - BYTE* const dict = (BYTE*)dictBuffer; - COVER_ctx_t ctx; - COVER_map_t activeDmers; - parameters.splitPoint = 1.0; - /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; - /* Checks */ - if (!COVER_checkParameters(parameters, dictBufferCapacity)) { - DISPLAYLEVEL(1, "Cover parameters incorrect\n"); - return ERROR(parameter_outOfBound); - } - if (nbSamples == 0) { - DISPLAYLEVEL(1, "Cover must have at least one input file\n"); - return ERROR(srcSize_wrong); - } - if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { - DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", - ZDICT_DICTSIZE_MIN); - return ERROR(dstSize_tooSmall); - } - /* Initialize context and activeDmers */ - { - size_t const initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, - parameters.d, parameters.splitPoint); - if (ZSTD_isError(initVal)) { - return initVal; - } - } - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, g_displayLevel); - if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { - DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); - COVER_ctx_destroy(&ctx); - return ERROR(memory_allocation); - } - - DISPLAYLEVEL(2, "Building dictionary\n"); - { - const size_t tail = - COVER_buildDictionary(&ctx, ctx.freqs, &activeDmers, dictBuffer, - dictBufferCapacity, parameters); - const size_t dictionarySize = ZDICT_finalizeDictionary( - dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail, - samplesBuffer, samplesSizes, nbSamples, parameters.zParams); - if (!ZSTD_isError(dictionarySize)) { - DISPLAYLEVEL(2, "Constructed dictionary of size %u\n", - (unsigned)dictionarySize); - } - COVER_ctx_destroy(&ctx); - COVER_map_destroy(&activeDmers); - return dictionarySize; - } -} - - - -size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters, - const size_t *samplesSizes, const BYTE *samples, - size_t *offsets, - size_t nbTrainSamples, size_t nbSamples, - BYTE *const dict, size_t dictBufferCapacity) { - size_t totalCompressedSize = ERROR(GENERIC); - /* Pointers */ - ZSTD_CCtx *cctx; - ZSTD_CDict *cdict; - void *dst; - /* Local variables */ - size_t dstCapacity; - size_t i; - /* Allocate dst with enough space to compress the maximum sized sample */ - { - size_t maxSampleSize = 0; - i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0; - for (; i < nbSamples; ++i) { - maxSampleSize = MAX(samplesSizes[i], maxSampleSize); - } - dstCapacity = ZSTD_compressBound(maxSampleSize); - dst = malloc(dstCapacity); - } - /* Create the cctx and cdict */ - cctx = ZSTD_createCCtx(); - cdict = ZSTD_createCDict(dict, dictBufferCapacity, - parameters.zParams.compressionLevel); - if (!dst || !cctx || !cdict) { - goto _compressCleanup; - } - /* Compress each sample and sum their sizes (or error) */ - totalCompressedSize = dictBufferCapacity; - i = parameters.splitPoint < 1.0 ? nbTrainSamples : 0; - for (; i < nbSamples; ++i) { - const size_t size = ZSTD_compress_usingCDict( - cctx, dst, dstCapacity, samples + offsets[i], - samplesSizes[i], cdict); - if (ZSTD_isError(size)) { - totalCompressedSize = size; - goto _compressCleanup; - } - totalCompressedSize += size; - } -_compressCleanup: - ZSTD_freeCCtx(cctx); - ZSTD_freeCDict(cdict); - if (dst) { - free(dst); - } - return totalCompressedSize; -} - - -/** - * Initialize the `COVER_best_t`. - */ -void COVER_best_init(COVER_best_t *best) { - if (best==NULL) return; /* compatible with init on NULL */ - (void)ZSTD_pthread_mutex_init(&best->mutex, NULL); - (void)ZSTD_pthread_cond_init(&best->cond, NULL); - best->liveJobs = 0; - best->dict = NULL; - best->dictSize = 0; - best->compressedSize = (size_t)-1; - memset(&best->parameters, 0, sizeof(best->parameters)); -} - -/** - * Wait until liveJobs == 0. - */ -void COVER_best_wait(COVER_best_t *best) { - if (!best) { - return; - } - ZSTD_pthread_mutex_lock(&best->mutex); - while (best->liveJobs != 0) { - ZSTD_pthread_cond_wait(&best->cond, &best->mutex); - } - ZSTD_pthread_mutex_unlock(&best->mutex); -} - -/** - * Call COVER_best_wait() and then destroy the COVER_best_t. - */ -void COVER_best_destroy(COVER_best_t *best) { - if (!best) { - return; - } - COVER_best_wait(best); - if (best->dict) { - free(best->dict); - } - ZSTD_pthread_mutex_destroy(&best->mutex); - ZSTD_pthread_cond_destroy(&best->cond); -} - -/** - * Called when a thread is about to be launched. - * Increments liveJobs. - */ -void COVER_best_start(COVER_best_t *best) { - if (!best) { - return; - } - ZSTD_pthread_mutex_lock(&best->mutex); - ++best->liveJobs; - ZSTD_pthread_mutex_unlock(&best->mutex); -} - -/** - * Called when a thread finishes executing, both on error or success. - * Decrements liveJobs and signals any waiting threads if liveJobs == 0. - * If this dictionary is the best so far save it and its parameters. - */ -void COVER_best_finish(COVER_best_t* best, - ZDICT_cover_params_t parameters, - COVER_dictSelection_t selection) -{ - void* dict = selection.dictContent; - size_t compressedSize = selection.totalCompressedSize; - size_t dictSize = selection.dictSize; - if (!best) { - return; - } - { - size_t liveJobs; - ZSTD_pthread_mutex_lock(&best->mutex); - --best->liveJobs; - liveJobs = best->liveJobs; - /* If the new dictionary is better */ - if (compressedSize < best->compressedSize) { - /* Allocate space if necessary */ - if (!best->dict || best->dictSize < dictSize) { - if (best->dict) { - free(best->dict); - } - best->dict = malloc(dictSize); - if (!best->dict) { - best->compressedSize = ERROR(GENERIC); - best->dictSize = 0; - ZSTD_pthread_cond_signal(&best->cond); - ZSTD_pthread_mutex_unlock(&best->mutex); - return; - } - } - /* Save the dictionary, parameters, and size */ - if (dict) { - memcpy(best->dict, dict, dictSize); - best->dictSize = dictSize; - best->parameters = parameters; - best->compressedSize = compressedSize; - } - } - if (liveJobs == 0) { - ZSTD_pthread_cond_broadcast(&best->cond); - } - ZSTD_pthread_mutex_unlock(&best->mutex); - } -} - -static COVER_dictSelection_t setDictSelection(BYTE* buf, size_t s, size_t csz) -{ - COVER_dictSelection_t ds; - ds.dictContent = buf; - ds.dictSize = s; - ds.totalCompressedSize = csz; - return ds; -} - -COVER_dictSelection_t COVER_dictSelectionError(size_t error) { - return setDictSelection(NULL, 0, error); -} - -unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection) { - return (ZSTD_isError(selection.totalCompressedSize) || !selection.dictContent); -} - -void COVER_dictSelectionFree(COVER_dictSelection_t selection){ - free(selection.dictContent); -} - -COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, - size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, - size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize) { - - size_t largestDict = 0; - size_t largestCompressed = 0; - BYTE* customDictContentEnd = customDictContent + dictContentSize; - - BYTE* largestDictbuffer = (BYTE*)malloc(dictBufferCapacity); - BYTE* candidateDictBuffer = (BYTE*)malloc(dictBufferCapacity); - double regressionTolerance = ((double)params.shrinkDictMaxRegression / 100.0) + 1.00; - - if (!largestDictbuffer || !candidateDictBuffer) { - free(largestDictbuffer); - free(candidateDictBuffer); - return COVER_dictSelectionError(dictContentSize); - } - - /* Initial dictionary size and compressed size */ - memcpy(largestDictbuffer, customDictContent, dictContentSize); - dictContentSize = ZDICT_finalizeDictionary( - largestDictbuffer, dictBufferCapacity, customDictContent, dictContentSize, - samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); - - if (ZDICT_isError(dictContentSize)) { - free(largestDictbuffer); - free(candidateDictBuffer); - return COVER_dictSelectionError(dictContentSize); - } - - totalCompressedSize = COVER_checkTotalCompressedSize(params, samplesSizes, - samplesBuffer, offsets, - nbCheckSamples, nbSamples, - largestDictbuffer, dictContentSize); - - if (ZSTD_isError(totalCompressedSize)) { - free(largestDictbuffer); - free(candidateDictBuffer); - return COVER_dictSelectionError(totalCompressedSize); - } - - if (params.shrinkDict == 0) { - free(candidateDictBuffer); - return setDictSelection(largestDictbuffer, dictContentSize, totalCompressedSize); - } - - largestDict = dictContentSize; - largestCompressed = totalCompressedSize; - dictContentSize = ZDICT_DICTSIZE_MIN; - - /* Largest dict is initially at least ZDICT_DICTSIZE_MIN */ - while (dictContentSize < largestDict) { - memcpy(candidateDictBuffer, largestDictbuffer, largestDict); - dictContentSize = ZDICT_finalizeDictionary( - candidateDictBuffer, dictBufferCapacity, customDictContentEnd - dictContentSize, dictContentSize, - samplesBuffer, samplesSizes, nbFinalizeSamples, params.zParams); - - if (ZDICT_isError(dictContentSize)) { - free(largestDictbuffer); - free(candidateDictBuffer); - return COVER_dictSelectionError(dictContentSize); - - } - - totalCompressedSize = COVER_checkTotalCompressedSize(params, samplesSizes, - samplesBuffer, offsets, - nbCheckSamples, nbSamples, - candidateDictBuffer, dictContentSize); - - if (ZSTD_isError(totalCompressedSize)) { - free(largestDictbuffer); - free(candidateDictBuffer); - return COVER_dictSelectionError(totalCompressedSize); - } - - if ((double)totalCompressedSize <= (double)largestCompressed * regressionTolerance) { - free(largestDictbuffer); - return setDictSelection( candidateDictBuffer, dictContentSize, totalCompressedSize ); - } - dictContentSize *= 2; - } - dictContentSize = largestDict; - totalCompressedSize = largestCompressed; - free(candidateDictBuffer); - return setDictSelection( largestDictbuffer, dictContentSize, totalCompressedSize ); -} - -/** - * Parameters for COVER_tryParameters(). - */ -typedef struct COVER_tryParameters_data_s { - const COVER_ctx_t *ctx; - COVER_best_t *best; - size_t dictBufferCapacity; - ZDICT_cover_params_t parameters; -} COVER_tryParameters_data_t; - -/** - * Tries a set of parameters and updates the COVER_best_t with the results. - * This function is thread safe if zstd is compiled with multithreaded support. - * It takes its parameters as an *OWNING* opaque pointer to support threading. - */ -static void COVER_tryParameters(void *opaque) -{ - /* Save parameters as local variables */ - COVER_tryParameters_data_t *const data = (COVER_tryParameters_data_t*)opaque; - const COVER_ctx_t *const ctx = data->ctx; - const ZDICT_cover_params_t parameters = data->parameters; - size_t dictBufferCapacity = data->dictBufferCapacity; - size_t totalCompressedSize = ERROR(GENERIC); - /* Allocate space for hash table, dict, and freqs */ - COVER_map_t activeDmers; - BYTE* const dict = (BYTE*)malloc(dictBufferCapacity); - COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32* const freqs = (U32*)malloc(ctx->suffixSize * sizeof(U32)); - if (!COVER_map_init(&activeDmers, parameters.k - parameters.d + 1)) { - DISPLAYLEVEL(1, "Failed to allocate dmer map: out of memory\n"); - goto _cleanup; - } - if (!dict || !freqs) { - DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); - goto _cleanup; - } - /* Copy the frequencies because we need to modify them */ - memcpy(freqs, ctx->freqs, ctx->suffixSize * sizeof(U32)); - /* Build the dictionary */ - { - const size_t tail = COVER_buildDictionary(ctx, freqs, &activeDmers, dict, - dictBufferCapacity, parameters); - selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, - ctx->samples, ctx->samplesSizes, (unsigned)ctx->nbTrainSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, - totalCompressedSize); - - if (COVER_dictSelectionIsError(selection)) { - DISPLAYLEVEL(1, "Failed to select dictionary\n"); - goto _cleanup; - } - } -_cleanup: - free(dict); - COVER_best_finish(data->best, parameters, selection); - free(data); - COVER_map_destroy(&activeDmers); - COVER_dictSelectionFree(selection); - free(freqs); -} - -ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( - void* dictBuffer, size_t dictBufferCapacity, const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t* parameters) -{ - /* constants */ - const unsigned nbThreads = parameters->nbThreads; - const double splitPoint = - parameters->splitPoint <= 0.0 ? COVER_DEFAULT_SPLITPOINT : parameters->splitPoint; - const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; - const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; - const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; - const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k; - const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps; - const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1); - const unsigned kIterations = - (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); - const unsigned shrinkDict = 0; - /* Local variables */ - const int displayLevel = parameters->zParams.notificationLevel; - unsigned iteration = 1; - unsigned d; - unsigned k; - COVER_best_t best; - POOL_ctx *pool = NULL; - int warned = 0; - - (void) kIterations; - (void) iteration; - - /* Checks */ - if (splitPoint <= 0 || splitPoint > 1) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); - return ERROR(parameter_outOfBound); - } - if (kMinK < kMaxD || kMaxK < kMinK) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect parameters\n"); - return ERROR(parameter_outOfBound); - } - if (nbSamples == 0) { - DISPLAYLEVEL(1, "Cover must have at least one input file\n"); - return ERROR(srcSize_wrong); - } - if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { - DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", - ZDICT_DICTSIZE_MIN); - return ERROR(dstSize_tooSmall); - } - if (nbThreads > 1) { - pool = POOL_create(nbThreads, 1); - if (!pool) { - return ERROR(memory_allocation); - } - } - /* Initialization */ - COVER_best_init(&best); - /* Turn down global display level to clean up display at level 2 and below */ - g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; - /* Loop through d first because each new value needs a new context */ - LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", - kIterations); - for (d = kMinD; d <= kMaxD; d += 2) { - /* Initialize the context for this value of d */ - COVER_ctx_t ctx; - LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); - { - const size_t initVal = COVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint); - if (ZSTD_isError(initVal)) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); - COVER_best_destroy(&best); - POOL_free(pool); - return initVal; - } - } - if (!warned) { - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.suffixSize, displayLevel); - warned = 1; - } - /* Loop through k reusing the same context */ - for (k = kMinK; k <= kMaxK; k += kStepSize) { - /* Prepare the arguments */ - COVER_tryParameters_data_t *data = (COVER_tryParameters_data_t *)malloc( - sizeof(COVER_tryParameters_data_t)); - LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); - if (!data) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); - COVER_best_destroy(&best); - COVER_ctx_destroy(&ctx); - POOL_free(pool); - return ERROR(memory_allocation); - } - data->ctx = &ctx; - data->best = &best; - data->dictBufferCapacity = dictBufferCapacity; - data->parameters = *parameters; - data->parameters.k = k; - data->parameters.d = d; - data->parameters.splitPoint = splitPoint; - data->parameters.steps = kSteps; - data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = g_displayLevel; - /* Check the parameters */ - if (!COVER_checkParameters(data->parameters, dictBufferCapacity)) { - DISPLAYLEVEL(1, "Cover parameters incorrect\n"); - free(data); - continue; - } - /* Call the function and pass ownership of data to it */ - COVER_best_start(&best); - if (pool) { - POOL_add(pool, &COVER_tryParameters, data); - } else { - COVER_tryParameters(data); - } - /* Print status */ - LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", - (unsigned)((iteration * 100) / kIterations)); - ++iteration; - } - COVER_best_wait(&best); - COVER_ctx_destroy(&ctx); - } - LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); - /* Fill the output buffer and parameters with output of the best parameters */ - { - const size_t dictSize = best.dictSize; - if (ZSTD_isError(best.compressedSize)) { - const size_t compressedSize = best.compressedSize; - COVER_best_destroy(&best); - POOL_free(pool); - return compressedSize; - } - *parameters = best.parameters; - memcpy(dictBuffer, best.dict, dictSize); - COVER_best_destroy(&best); - POOL_free(pool); - return dictSize; - } -} - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/divsufsort.cpp b/src/duckdb/third_party/zstd/dict/divsufsort.cpp deleted file mode 100644 index d0d00f8ca..000000000 --- a/src/duckdb/third_party/zstd/dict/divsufsort.cpp +++ /dev/null @@ -1,1916 +0,0 @@ -/* - * divsufsort.c for libdivsufsort-lite - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*- Compiler specifics -*/ -#ifdef __clang__ -// CRAN does not allow pragmas -#endif - -#if defined(_MSC_VER) -# pragma warning(disable : 4244) -# pragma warning(disable : 4127) /* C4127 : Condition expression is constant */ -#endif - - -/*- Dependencies -*/ -#include -#include -#include - -#include "zstd/dict/divsufsort.h" - -/*- Constants -*/ -#if defined(INLINE) -# undef INLINE -#endif -#if !defined(INLINE) -# define INLINE __inline -#endif -#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) -# undef ALPHABET_SIZE -#endif -#if !defined(ALPHABET_SIZE) -# define ALPHABET_SIZE (256) -#endif -#define BUCKET_A_SIZE (ALPHABET_SIZE) -#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) -#if defined(SS_INSERTIONSORT_THRESHOLD) -# if SS_INSERTIONSORT_THRESHOLD < 1 -# undef SS_INSERTIONSORT_THRESHOLD -# define SS_INSERTIONSORT_THRESHOLD (1) -# endif -#else -# define SS_INSERTIONSORT_THRESHOLD (8) -#endif -#if defined(SS_BLOCKSIZE) -# if SS_BLOCKSIZE < 0 -# undef SS_BLOCKSIZE -# define SS_BLOCKSIZE (0) -# elif 32768 <= SS_BLOCKSIZE -# undef SS_BLOCKSIZE -# define SS_BLOCKSIZE (32767) -# endif -#else -# define SS_BLOCKSIZE (1024) -#endif -/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ -#if SS_BLOCKSIZE == 0 -# define SS_MISORT_STACKSIZE (96) -#elif SS_BLOCKSIZE <= 4096 -# define SS_MISORT_STACKSIZE (16) -#else -# define SS_MISORT_STACKSIZE (24) -#endif -#define SS_SMERGE_STACKSIZE (32) -#define TR_INSERTIONSORT_THRESHOLD (8) -#define TR_STACKSIZE (64) - - -/*- Macros -*/ -#ifndef SWAP -# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) -#endif /* SWAP */ -#ifndef MIN -# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) -#endif /* MIN */ -#ifndef MAX -# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#endif /* MAX */ -#define STACK_PUSH(_a, _b, _c, _d)\ - do {\ - assert(ssize < STACK_SIZE);\ - stack[ssize].a = (_a), stack[ssize].b = (_b),\ - stack[ssize].c = (_c), stack[ssize++].d = (_d);\ - } while(0) -#define STACK_PUSH5(_a, _b, _c, _d, _e)\ - do {\ - assert(ssize < STACK_SIZE);\ - stack[ssize].a = (_a), stack[ssize].b = (_b),\ - stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ - } while(0) -#define STACK_POP(_a, _b, _c, _d)\ - do {\ - assert(0 <= ssize);\ - if(ssize == 0) { return; }\ - (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ - (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ - } while(0) -#define STACK_POP5(_a, _b, _c, _d, _e)\ - do {\ - assert(0 <= ssize);\ - if(ssize == 0) { return; }\ - (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ - (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ - } while(0) -#define BUCKET_A(_c0) bucket_A[(_c0)] -#if ALPHABET_SIZE == 256 -#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) -#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) -#else -#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) -#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) -#endif - -namespace duckdb_zstd { - -/*- Private Functions -*/ - -static const int lg_table[256]= { - -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - -#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) - -static INLINE -int -ss_ilg(int n) { -#if SS_BLOCKSIZE == 0 - return (n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]); -#elif SS_BLOCKSIZE < 256 - return lg_table[n]; -#else - return (n & 0xff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]; -#endif -} - -#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ - -#if SS_BLOCKSIZE != 0 - -static const int sqq_table[256] = { - 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, - 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, - 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, -110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, -128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, -143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, -156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, -169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, -181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, -192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, -202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, -212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, -221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, -230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, -239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, -247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 -}; - -static INLINE -int -ss_isqrt(int x) { - int y, e; - - if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } - e = (x & 0xffff0000) ? - ((x & 0xff000000) ? - 24 + lg_table[(x >> 24) & 0xff] : - 16 + lg_table[(x >> 16) & 0xff]) : - ((x & 0x0000ff00) ? - 8 + lg_table[(x >> 8) & 0xff] : - 0 + lg_table[(x >> 0) & 0xff]); - - if(e >= 16) { - y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); - if(e >= 24) { y = (y + 1 + x / y) >> 1; } - y = (y + 1 + x / y) >> 1; - } else if(e >= 8) { - y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; - } else { - return sqq_table[x] >> 4; - } - - return (x < (y * y)) ? y - 1 : y; -} - -#endif /* SS_BLOCKSIZE != 0 */ - - -/*---------------------------------------------------------------------------*/ - -/* Compares two suffixes. */ -static INLINE -int -ss_compare(const unsigned char *T, - const int *p1, const int *p2, - int depth) { - const unsigned char *U1, *U2, *U1n, *U2n; - - for(U1 = T + depth + *p1, - U2 = T + depth + *p2, - U1n = T + *(p1 + 1) + 2, - U2n = T + *(p2 + 1) + 2; - (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); - ++U1, ++U2) { - } - - return U1 < U1n ? - (U2 < U2n ? *U1 - *U2 : 1) : - (U2 < U2n ? -1 : 0); -} - - -/*---------------------------------------------------------------------------*/ - -#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) - -/* Insertionsort for small size groups */ -static -void -ss_insertionsort(const unsigned char *T, const int *PA, - int *first, int *last, int depth) { - int *i, *j; - int t; - int r; - - for(i = last - 2; first <= i; --i) { - for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { - do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); - if(last <= j) { break; } - } - if(r == 0) { *j = ~*j; } - *(j - 1) = t; - } -} - -#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ - - -/*---------------------------------------------------------------------------*/ - -#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) - -static INLINE -void -ss_fixdown(const unsigned char *Td, const int *PA, - int *SA, int i, int size) { - int j, k; - int v; - int c, d, e; - - for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { - d = Td[PA[SA[k = j++]]]; - if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } - if(d <= c) { break; } - } - SA[i] = v; -} - -/* Simple top-down heapsort. */ -static -void -ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) { - int i, m; - int t; - - m = size; - if((size % 2) == 0) { - m--; - if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } - } - - for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } - if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } - for(i = m - 1; 0 < i; --i) { - t = SA[0], SA[0] = SA[i]; - ss_fixdown(Td, PA, SA, 0, i); - SA[i] = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Returns the median of three elements. */ -static INLINE -int * -ss_median3(const unsigned char *Td, const int *PA, - int *v1, int *v2, int *v3) { - int *t; - if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } - if(Td[PA[*v2]] > Td[PA[*v3]]) { - if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } - else { return v3; } - } - return v2; -} - -/* Returns the median of five elements. */ -static INLINE -int * -ss_median5(const unsigned char *Td, const int *PA, - int *v1, int *v2, int *v3, int *v4, int *v5) { - int *t; - if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } - if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } - if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } - if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } - if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } - if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } - return v3; -} - -/* Returns the pivot element. */ -static INLINE -int * -ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { - int *middle; - int t; - - t = last - first; - middle = first + t / 2; - - if(t <= 512) { - if(t <= 32) { - return ss_median3(Td, PA, first, middle, last - 1); - } else { - t >>= 2; - return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); - } - } - t >>= 3; - first = ss_median3(Td, PA, first, first + t, first + (t << 1)); - middle = ss_median3(Td, PA, middle - t, middle, middle + t); - last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); - return ss_median3(Td, PA, first, middle, last); -} - - -/*---------------------------------------------------------------------------*/ - -/* Binary partition for substrings. */ -static INLINE -int * -ss_partition(const int *PA, - int *first, int *last, int depth) { - int *a, *b; - int t; - for(a = first - 1, b = last;;) { - for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } - for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } - if(b <= a) { break; } - t = ~*b; - *b = *a; - *a = t; - } - if(first < a) { *first = ~*first; } - return a; -} - -/* Multikey introsort for medium size groups. */ -static -void -ss_mintrosort(const unsigned char *T, const int *PA, - int *first, int *last, - int depth) { -#define STACK_SIZE SS_MISORT_STACKSIZE - struct { int *a, *b, c; int d; } stack[STACK_SIZE]; - const unsigned char *Td; - int *a, *b, *c, *d, *e, *f; - int s, t; - int ssize; - int limit; - int v, x = 0; - - for(ssize = 0, limit = ss_ilg(last - first);;) { - - if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { -#if 1 < SS_INSERTIONSORT_THRESHOLD - if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } -#endif - STACK_POP(first, last, depth, limit); - continue; - } - - Td = T + depth; - if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } - if(limit < 0) { - for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { - if((x = Td[PA[*a]]) != v) { - if(1 < (a - first)) { break; } - v = x; - first = a; - } - } - if(Td[PA[*first] - 1] < v) { - first = ss_partition(PA, first, a, depth); - } - if((a - first) <= (last - a)) { - if(1 < (a - first)) { - STACK_PUSH(a, last, depth, -1); - last = a, depth += 1, limit = ss_ilg(a - first); - } else { - first = a, limit = -1; - } - } else { - if(1 < (last - a)) { - STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); - first = a, limit = -1; - } else { - last = a, depth += 1, limit = ss_ilg(a - first); - } - } - continue; - } - - /* choose pivot */ - a = ss_pivot(Td, PA, first, last); - v = Td[PA[*a]]; - SWAP(*first, *a); - - /* partition */ - for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } - if(((a = b) < last) && (x < v)) { - for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - } - for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } - if((b < (d = c)) && (x > v)) { - for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - for(; b < c;) { - SWAP(*b, *c); - for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - - if(a <= d) { - c = b - 1; - - if((s = a - first) > (t = b - a)) { s = t; } - for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } - for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - - a = first + (b - a), c = last - (d - c); - b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); - - if((a - first) <= (last - c)) { - if((last - c) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - STACK_PUSH(c, last, depth, limit); - last = a; - } else if((a - first) <= (c - b)) { - STACK_PUSH(c, last, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - last = a; - } else { - STACK_PUSH(c, last, depth, limit); - STACK_PUSH(first, a, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); - } - } else { - if((a - first) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - STACK_PUSH(first, a, depth, limit); - first = c; - } else if((last - c) <= (c - b)) { - STACK_PUSH(first, a, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - first = c; - } else { - STACK_PUSH(first, a, depth, limit); - STACK_PUSH(c, last, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); - } - } - } else { - limit += 1; - if(Td[PA[*first] - 1] < v) { - first = ss_partition(PA, first, last, depth); - limit = ss_ilg(last - first); - } - depth += 1; - } - } -#undef STACK_SIZE -} - -#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ - - -/*---------------------------------------------------------------------------*/ - -#if SS_BLOCKSIZE != 0 - -static INLINE -void -ss_blockswap(int *a, int *b, int n) { - int t; - for(; 0 < n; --n, ++a, ++b) { - t = *a, *a = *b, *b = t; - } -} - -static INLINE -void -ss_rotate(int *first, int *middle, int *last) { - int *a, *b, t; - int l, r; - l = middle - first, r = last - middle; - for(; (0 < l) && (0 < r);) { - if(l == r) { ss_blockswap(first, middle, l); break; } - if(l < r) { - a = last - 1, b = middle - 1; - t = *a; - do { - *a-- = *b, *b-- = *a; - if(b < first) { - *a = t; - last = a; - if((r -= l + 1) <= l) { break; } - a -= 1, b = middle - 1; - t = *a; - } - } while(1); - } else { - a = first, b = middle; - t = *a; - do { - *a++ = *b, *b++ = *a; - if(last <= b) { - *a = t; - first = a + 1; - if((l -= r + 1) <= r) { break; } - a += 1, b = middle; - t = *a; - } - } while(1); - } - } -} - - -/*---------------------------------------------------------------------------*/ - -static -void -ss_inplacemerge(const unsigned char *T, const int *PA, - int *first, int *middle, int *last, - int depth) { - const int *p; - int *a, *b; - int len, half; - int q, r; - int x; - - for(;;) { - if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } - else { x = 0; p = PA + *(last - 1); } - for(a = first, len = middle - first, half = len >> 1, r = -1; - 0 < len; - len = half, half >>= 1) { - b = a + half; - q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); - if(q < 0) { - a = b + 1; - half -= (len & 1) ^ 1; - } else { - r = q; - } - } - if(a < middle) { - if(r == 0) { *a = ~*a; } - ss_rotate(a, middle, last); - last -= middle - a; - middle = a; - if(first == middle) { break; } - } - --last; - if(x != 0) { while(*--last < 0) { } } - if(middle == last) { break; } - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Merge-forward with internal buffer. */ -static -void -ss_mergeforward(const unsigned char *T, const int *PA, - int *first, int *middle, int *last, - int *buf, int depth) { - int *a, *b, *c, *bufend; - int t; - int r; - - bufend = buf + (middle - first) - 1; - ss_blockswap(buf, first, middle - first); - - for(t = *(a = first), b = buf, c = middle;;) { - r = ss_compare(T, PA + *b, PA + *c, depth); - if(r < 0) { - do { - *a++ = *b; - if(bufend <= b) { *bufend = t; return; } - *b++ = *a; - } while(*b < 0); - } else if(r > 0) { - do { - *a++ = *c, *c++ = *a; - if(last <= c) { - while(b < bufend) { *a++ = *b, *b++ = *a; } - *a = *b, *b = t; - return; - } - } while(*c < 0); - } else { - *c = ~*c; - do { - *a++ = *b; - if(bufend <= b) { *bufend = t; return; } - *b++ = *a; - } while(*b < 0); - - do { - *a++ = *c, *c++ = *a; - if(last <= c) { - while(b < bufend) { *a++ = *b, *b++ = *a; } - *a = *b, *b = t; - return; - } - } while(*c < 0); - } - } -} - -/* Merge-backward with internal buffer. */ -static -void -ss_mergebackward(const unsigned char *T, const int *PA, - int *first, int *middle, int *last, - int *buf, int depth) { - const int *p1, *p2; - int *a, *b, *c, *bufend; - int t; - int r; - int x; - - bufend = buf + (last - middle) - 1; - ss_blockswap(buf, middle, last - middle); - - x = 0; - if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } - else { p1 = PA + *bufend; } - if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } - else { p2 = PA + *(middle - 1); } - for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { - r = ss_compare(T, p1, p2, depth); - if(0 < r) { - if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } - *a-- = *b; - if(b <= buf) { *buf = t; break; } - *b-- = *a; - if(*b < 0) { p1 = PA + ~*b; x |= 1; } - else { p1 = PA + *b; } - } else if(r < 0) { - if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } - *a-- = *c, *c-- = *a; - if(c < first) { - while(buf < b) { *a-- = *b, *b-- = *a; } - *a = *b, *b = t; - break; - } - if(*c < 0) { p2 = PA + ~*c; x |= 2; } - else { p2 = PA + *c; } - } else { - if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } - *a-- = ~*b; - if(b <= buf) { *buf = t; break; } - *b-- = *a; - if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } - *a-- = *c, *c-- = *a; - if(c < first) { - while(buf < b) { *a-- = *b, *b-- = *a; } - *a = *b, *b = t; - break; - } - if(*b < 0) { p1 = PA + ~*b; x |= 1; } - else { p1 = PA + *b; } - if(*c < 0) { p2 = PA + ~*c; x |= 2; } - else { p2 = PA + *c; } - } - } -} - -/* D&C based merge. */ -static -void -ss_swapmerge(const unsigned char *T, const int *PA, - int *first, int *middle, int *last, - int *buf, int bufsize, int depth) { -#define STACK_SIZE SS_SMERGE_STACKSIZE -#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) -#define MERGE_CHECK(a, b, c)\ - do {\ - if(((c) & 1) ||\ - (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ - *(a) = ~*(a);\ - }\ - if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ - *(b) = ~*(b);\ - }\ - } while(0) - struct { int *a, *b, *c; int d; } stack[STACK_SIZE]; - int *l, *r, *lm, *rm; - int m, len, half; - int ssize; - int check, next; - - for(check = 0, ssize = 0;;) { - if((last - middle) <= bufsize) { - if((first < middle) && (middle < last)) { - ss_mergebackward(T, PA, first, middle, last, buf, depth); - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - continue; - } - - if((middle - first) <= bufsize) { - if(first < middle) { - ss_mergeforward(T, PA, first, middle, last, buf, depth); - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - continue; - } - - for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; - 0 < len; - len = half, half >>= 1) { - if(ss_compare(T, PA + GETIDX(*(middle + m + half)), - PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { - m += half + 1; - half -= (len & 1) ^ 1; - } - } - - if(0 < m) { - lm = middle - m, rm = middle + m; - ss_blockswap(lm, middle, m); - l = r = middle, next = 0; - if(rm < last) { - if(*rm < 0) { - *rm = ~*rm; - if(first < lm) { for(; *--l < 0;) { } next |= 4; } - next |= 1; - } else if(first < lm) { - for(; *r < 0; ++r) { } - next |= 2; - } - } - - if((l - first) <= (last - r)) { - STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); - middle = lm, last = l, check = (check & 3) | (next & 4); - } else { - if((next & 2) && (r == middle)) { next ^= 6; } - STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); - first = r, middle = rm, check = (next & 3) | (check & 4); - } - } else { - if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { - *middle = ~*middle; - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - } - } -#undef STACK_SIZE -} - -#endif /* SS_BLOCKSIZE != 0 */ - - -/*---------------------------------------------------------------------------*/ - -/* Substring sort */ -static -void -sssort(const unsigned char *T, const int *PA, - int *first, int *last, - int *buf, int bufsize, - int depth, int n, int lastsuffix) { - int *a; -#if SS_BLOCKSIZE != 0 - int *b, *middle, *curbuf; - int j, k, curbufsize, limit; -#endif - int i; - - if(lastsuffix != 0) { ++first; } - -#if SS_BLOCKSIZE == 0 - ss_mintrosort(T, PA, first, last, depth); -#else - if((bufsize < SS_BLOCKSIZE) && - (bufsize < (last - first)) && - (bufsize < (limit = ss_isqrt(last - first)))) { - if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } - buf = middle = last - limit, bufsize = limit; - } else { - middle = last, limit = 0; - } - for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); -#endif - curbufsize = last - (a + SS_BLOCKSIZE); - curbuf = a + SS_BLOCKSIZE; - if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } - for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { - ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); - } - } -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, a, middle, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, a, middle, depth); -#endif - for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { - if(i & 1) { - ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); - a -= k; - } - } - if(limit != 0) { -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, middle, last, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, middle, last, depth); -#endif - ss_inplacemerge(T, PA, first, middle, last, depth); - } -#endif - - if(lastsuffix != 0) { - /* Insert last type B* suffix. */ - int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; - for(a = first, i = *(first - 1); - (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); - ++a) { - *(a - 1) = *a; - } - *(a - 1) = i; - } -} - - -/*---------------------------------------------------------------------------*/ - -static INLINE -int -tr_ilg(int n) { - return (n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]); -} - - -/*---------------------------------------------------------------------------*/ - -/* Simple insertionsort for small size groups. */ -static -void -tr_insertionsort(const int *ISAd, int *first, int *last) { - int *a, *b; - int t, r; - - for(a = first + 1; a < last; ++a) { - for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { - do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); - if(b < first) { break; } - } - if(r == 0) { *b = ~*b; } - *(b + 1) = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -static INLINE -void -tr_fixdown(const int *ISAd, int *SA, int i, int size) { - int j, k; - int v; - int c, d, e; - - for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { - d = ISAd[SA[k = j++]]; - if(d < (e = ISAd[SA[j]])) { k = j; d = e; } - if(d <= c) { break; } - } - SA[i] = v; -} - -/* Simple top-down heapsort. */ -static -void -tr_heapsort(const int *ISAd, int *SA, int size) { - int i, m; - int t; - - m = size; - if((size % 2) == 0) { - m--; - if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } - } - - for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } - if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } - for(i = m - 1; 0 < i; --i) { - t = SA[0], SA[0] = SA[i]; - tr_fixdown(ISAd, SA, 0, i); - SA[i] = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Returns the median of three elements. */ -static INLINE -int * -tr_median3(const int *ISAd, int *v1, int *v2, int *v3) { - int *t; - if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } - if(ISAd[*v2] > ISAd[*v3]) { - if(ISAd[*v1] > ISAd[*v3]) { return v1; } - else { return v3; } - } - return v2; -} - -/* Returns the median of five elements. */ -static INLINE -int * -tr_median5(const int *ISAd, - int *v1, int *v2, int *v3, int *v4, int *v5) { - int *t; - if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } - if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } - if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } - if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } - if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } - if(ISAd[*v3] > ISAd[*v4]) { return v4; } - return v3; -} - -/* Returns the pivot element. */ -static INLINE -int * -tr_pivot(const int *ISAd, int *first, int *last) { - int *middle; - int t; - - t = last - first; - middle = first + t / 2; - - if(t <= 512) { - if(t <= 32) { - return tr_median3(ISAd, first, middle, last - 1); - } else { - t >>= 2; - return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); - } - } - t >>= 3; - first = tr_median3(ISAd, first, first + t, first + (t << 1)); - middle = tr_median3(ISAd, middle - t, middle, middle + t); - last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); - return tr_median3(ISAd, first, middle, last); -} - - -/*---------------------------------------------------------------------------*/ - -typedef struct _trbudget_t trbudget_t; -struct _trbudget_t { - int chance; - int remain; - int incval; - int count; -}; - -static INLINE -void -trbudget_init(trbudget_t *budget, int chance, int incval) { - budget->chance = chance; - budget->remain = budget->incval = incval; -} - -static INLINE -int -trbudget_check(trbudget_t *budget, int size) { - if(size <= budget->remain) { budget->remain -= size; return 1; } - if(budget->chance == 0) { budget->count += size; return 0; } - budget->remain += budget->incval - size; - budget->chance -= 1; - return 1; -} - - -/*---------------------------------------------------------------------------*/ - -static INLINE -void -tr_partition(const int *ISAd, - int *first, int *middle, int *last, - int **pa, int **pb, int v) { - int *a, *b, *c, *d, *e, *f; - int t, s; - int x = 0; - - for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } - if(((a = b) < last) && (x < v)) { - for(; (++b < last) && ((x = ISAd[*b]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - } - for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } - if((b < (d = c)) && (x > v)) { - for(; (b < --c) && ((x = ISAd[*c]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - for(; b < c;) { - SWAP(*b, *c); - for(; (++b < c) && ((x = ISAd[*b]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - for(; (b < --c) && ((x = ISAd[*c]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - - if(a <= d) { - c = b - 1; - if((s = a - first) > (t = b - a)) { s = t; } - for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } - for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - first += (b - a), last -= (d - c); - } - *pa = first, *pb = last; -} - -static -void -tr_copy(int *ISA, const int *SA, - int *first, int *a, int *b, int *last, - int depth) { - /* sort suffixes of middle partition - by using sorted order of suffixes of left and right partition. */ - int *c, *d, *e; - int s, v; - - v = b - SA - 1; - for(c = first, d = a - 1; c <= d; ++c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *++d = s; - ISA[s] = d - SA; - } - } - for(c = last - 1, e = d + 1, d = b; e < d; --c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *--d = s; - ISA[s] = d - SA; - } - } -} - -static -void -tr_partialcopy(int *ISA, const int *SA, - int *first, int *a, int *b, int *last, - int depth) { - int *c, *d, *e; - int s, v; - int rank, lastrank, newrank = -1; - - v = b - SA - 1; - lastrank = -1; - for(c = first, d = a - 1; c <= d; ++c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *++d = s; - rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } - ISA[s] = newrank; - } - } - - lastrank = -1; - for(e = d; first <= e; --e) { - rank = ISA[*e]; - if(lastrank != rank) { lastrank = rank; newrank = e - SA; } - if(newrank != rank) { ISA[*e] = newrank; } - } - - lastrank = -1; - for(c = last - 1, e = d + 1, d = b; e < d; --c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *--d = s; - rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } - ISA[s] = newrank; - } - } -} - -static -void -tr_introsort(int *ISA, const int *ISAd, - int *SA, int *first, int *last, - trbudget_t *budget) { -#define STACK_SIZE TR_STACKSIZE - struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE]; - int *a, *b, *c; - int t; - int v, x = 0; - int incr = ISAd - ISA; - int limit, next; - int ssize, trlink = -1; - - for(ssize = 0, limit = tr_ilg(last - first);;) { - - if(limit < 0) { - if(limit == -1) { - /* tandem repeat partition */ - tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); - - /* update ranks */ - if(a < last) { - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } - } - if(b < last) { - for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } - } - - /* push */ - if(1 < (b - a)) { - STACK_PUSH5(NULL, a, b, 0, 0); - STACK_PUSH5(ISAd - incr, first, last, -2, trlink); - trlink = ssize - 2; - } - if((a - first) <= (last - b)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); - last = a, limit = tr_ilg(a - first); - } else if(1 < (last - b)) { - first = b, limit = tr_ilg(last - b); - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } else { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); - first = b, limit = tr_ilg(last - b); - } else if(1 < (a - first)) { - last = a, limit = tr_ilg(a - first); - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } else if(limit == -2) { - /* tandem repeat copy */ - a = stack[--ssize].b, b = stack[ssize].c; - if(stack[ssize].d == 0) { - tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); - } - STACK_POP5(ISAd, first, last, limit, trlink); - } else { - /* sorted partition */ - if(0 <= *first) { - a = first; - do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); - first = a; - } - if(first < last) { - a = first; do { *a = ~*a; } while(*++a < 0); - next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; - if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } - - /* push */ - if(trbudget_check(budget, a - first)) { - if((a - first) <= (last - a)) { - STACK_PUSH5(ISAd, a, last, -3, trlink); - ISAd += incr, last = a, limit = next; - } else { - if(1 < (last - a)) { - STACK_PUSH5(ISAd + incr, first, a, next, trlink); - first = a, limit = -3; - } else { - ISAd += incr, last = a, limit = next; - } - } - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - if(1 < (last - a)) { - first = a, limit = -3; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - continue; - } - - if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { - tr_insertionsort(ISAd, first, last); - limit = -3; - continue; - } - - if(limit-- == 0) { - tr_heapsort(ISAd, first, last - first); - for(a = last - 1; first < a; a = b) { - for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } - } - limit = -3; - continue; - } - - /* choose pivot */ - a = tr_pivot(ISAd, first, last); - SWAP(*first, *a); - v = ISAd[*first]; - - /* partition */ - tr_partition(ISAd, first, first + 1, last, &a, &b, v); - if((last - first) != (b - a)) { - next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; - - /* update ranks */ - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } - if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } - - /* push */ - if((1 < (b - a)) && (trbudget_check(budget, b - a))) { - if((a - first) <= (last - b)) { - if((last - b) <= (b - a)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - STACK_PUSH5(ISAd, b, last, limit, trlink); - last = a; - } else if(1 < (last - b)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - first = b; - } else { - ISAd += incr, first = a, last = b, limit = next; - } - } else if((a - first) <= (b - a)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, limit, trlink); - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - last = a; - } else { - STACK_PUSH5(ISAd, b, last, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - STACK_PUSH5(ISAd, b, last, limit, trlink); - STACK_PUSH5(ISAd, first, a, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - if((a - first) <= (b - a)) { - if(1 < (last - b)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - STACK_PUSH5(ISAd, first, a, limit, trlink); - first = b; - } else if(1 < (a - first)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - last = a; - } else { - ISAd += incr, first = a, last = b, limit = next; - } - } else if((last - b) <= (b - a)) { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, limit, trlink); - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - first = b; - } else { - STACK_PUSH5(ISAd, first, a, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - STACK_PUSH5(ISAd, first, a, limit, trlink); - STACK_PUSH5(ISAd, b, last, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } - } else { - if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } - if((a - first) <= (last - b)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, limit, trlink); - last = a; - } else if(1 < (last - b)) { - first = b; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } else { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, limit, trlink); - first = b; - } else if(1 < (a - first)) { - last = a; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } - } else { - if(trbudget_check(budget, last - first)) { - limit = tr_ilg(last - first), ISAd += incr; - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } -#undef STACK_SIZE -} - - - -/*---------------------------------------------------------------------------*/ - -/* Tandem repeat sort */ -static -void -trsort(int *ISA, int *SA, int n, int depth) { - int *ISAd; - int *first, *last; - trbudget_t budget; - int t, skip, unsorted; - - trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); -/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ - for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { - first = SA; - skip = 0; - unsorted = 0; - do { - if((t = *first) < 0) { first -= t; skip += t; } - else { - if(skip != 0) { *(first + skip) = skip; skip = 0; } - last = SA + ISA[t] + 1; - if(1 < (last - first)) { - budget.count = 0; - tr_introsort(ISA, ISAd, SA, first, last, &budget); - if(budget.count != 0) { unsorted += budget.count; } - else { skip = first - last; } - } else if((last - first) == 1) { - skip = -1; - } - first = last; - } - } while(first < (SA + n)); - if(skip != 0) { *(first + skip) = skip; } - if(unsorted == 0) { break; } - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Sorts suffixes of type B*. */ -static -int -sort_typeBstar(const unsigned char *T, int *SA, - int *bucket_A, int *bucket_B, - int n, int openMP) { - int *PAb, *ISAb, *buf; -#ifdef LIBBSC_OPENMP - int *curbuf; - int l; -#endif - int i, j, k, t, m, bufsize; - int c0, c1; -#ifdef LIBBSC_OPENMP - int d0, d1; -#endif - (void)openMP; - - /* Initialize bucket arrays. */ - for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } - for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } - - /* Count the number of occurrences of the first one or two characters of each - type A, B and B* suffix. Moreover, store the beginning position of all - type B* suffixes into the array SA. */ - for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { - /* type A suffix. */ - do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); - if(0 <= i) { - /* type B* suffix. */ - ++BUCKET_BSTAR(c0, c1); - SA[--m] = i; - /* type B suffix. */ - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { - ++BUCKET_B(c0, c1); - } - } - } - m = n - m; -/* -note: - A type B* suffix is lexicographically smaller than a type B suffix that - begins with the same first two characters. -*/ - - /* Calculate the index of start/end point of each bucket. */ - for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { - t = i + BUCKET_A(c0); - BUCKET_A(c0) = i + j; /* start point */ - i = t + BUCKET_B(c0, c0); - for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { - j += BUCKET_BSTAR(c0, c1); - BUCKET_BSTAR(c0, c1) = j; /* end point */ - i += BUCKET_B(c0, c1); - } - } - - if(0 < m) { - /* Sort the type B* suffixes by their first two characters. */ - PAb = SA + n - m; ISAb = SA + m; - for(i = m - 2; 0 <= i; --i) { - t = PAb[i], c0 = T[t], c1 = T[t + 1]; - SA[--BUCKET_BSTAR(c0, c1)] = i; - } - t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; - SA[--BUCKET_BSTAR(c0, c1)] = m - 1; - - /* Sort the type B* substrings using sssort. */ -#ifdef LIBBSC_OPENMP - if (openMP) - { - buf = SA + m; - c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m; -#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1) - { - bufsize = (n - (2 * m)) / omp_get_num_threads(); - curbuf = buf + omp_get_thread_num() * bufsize; - k = 0; - for(;;) { - #pragma omp critical(sssort_lock) - { - if(0 < (l = j)) { - d0 = c0, d1 = c1; - do { - k = BUCKET_BSTAR(d0, d1); - if(--d1 <= d0) { - d1 = ALPHABET_SIZE - 1; - if(--d0 < 0) { break; } - } - } while(((l - k) <= 1) && (0 < (l = k))); - c0 = d0, c1 = d1, j = k; - } - } - if(l == 0) { break; } - sssort(T, PAb, SA + k, SA + l, - curbuf, bufsize, 2, n, *(SA + k) == (m - 1)); - } - } - } - else - { - buf = SA + m, bufsize = n - (2 * m); - for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { - for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { - i = BUCKET_BSTAR(c0, c1); - if(1 < (j - i)) { - sssort(T, PAb, SA + i, SA + j, - buf, bufsize, 2, n, *(SA + i) == (m - 1)); - } - } - } - } -#else - buf = SA + m, bufsize = n - (2 * m); - for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { - for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { - i = BUCKET_BSTAR(c0, c1); - if(1 < (j - i)) { - sssort(T, PAb, SA + i, SA + j, - buf, bufsize, 2, n, *(SA + i) == (m - 1)); - } - } - } -#endif - - /* Compute ranks of type B* substrings. */ - for(i = m - 1; 0 <= i; --i) { - if(0 <= SA[i]) { - j = i; - do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); - SA[i + 1] = i - j; - if(i <= 0) { break; } - } - j = i; - do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); - ISAb[SA[i]] = j; - } - - /* Construct the inverse suffix array of type B* suffixes using trsort. */ - trsort(ISAb, SA, m, 1); - - /* Set the sorted order of type B* suffixes. */ - for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } - if(0 <= i) { - t = i; - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } - SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; - } - } - - /* Calculate the index of start/end point of each bucket. */ - BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ - for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { - i = BUCKET_A(c0 + 1) - 1; - for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { - t = i - BUCKET_B(c0, c1); - BUCKET_B(c0, c1) = i; /* end point */ - - /* Move all type B* suffixes to the correct position. */ - for(i = t, j = BUCKET_BSTAR(c0, c1); - j <= k; - --i, --k) { SA[i] = SA[k]; } - } - BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ - BUCKET_B(c0, c0) = i; /* end point */ - } - } - - return m; -} - -/* Constructs the suffix array by using the sorted order of type B* suffixes. */ -static -void -construct_SA(const unsigned char *T, int *SA, - int *bucket_A, int *bucket_B, - int n, int m) { - int *i, *j, *k; - int s; - int c0, c1, c2; - - if(0 < m) { - /* Construct the sorted order of type B suffixes by using - the sorted order of type B* suffixes. */ - for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { - /* Scan the suffix array from right to left. */ - for(i = SA + BUCKET_BSTAR(c1, c1 + 1), - j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; - i <= j; - --j) { - if(0 < (s = *j)) { - assert(T[s] == c1); - assert(((s + 1) < n) && (T[s] <= T[s + 1])); - assert(T[s - 1] <= T[s]); - *j = ~s; - c0 = T[--s]; - if((0 < s) && (T[s - 1] > c0)) { s = ~s; } - if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } - k = SA + BUCKET_B(c2 = c0, c1); - } - assert(k < j); assert(k != NULL); - *k-- = s; - } else { - assert(((s == 0) && (T[s] == c1)) || (s < 0)); - *j = ~s; - } - } - } - } - - /* Construct the suffix array by using - the sorted order of type B suffixes. */ - k = SA + BUCKET_A(c2 = T[n - 1]); - *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); - /* Scan the suffix array from left to right. */ - for(i = SA, j = SA + n; i < j; ++i) { - if(0 < (s = *i)) { - assert(T[s - 1] >= T[s]); - c0 = T[--s]; - if((s == 0) || (T[s - 1] < c0)) { s = ~s; } - if(c0 != c2) { - BUCKET_A(c2) = k - SA; - k = SA + BUCKET_A(c2 = c0); - } - assert(i < k); - *k++ = s; - } else { - assert(s < 0); - *i = ~s; - } - } -} - -/* Constructs the burrows-wheeler transformed string directly - by using the sorted order of type B* suffixes. */ -static -int -construct_BWT(const unsigned char *T, int *SA, - int *bucket_A, int *bucket_B, - int n, int m) { - int *i, *j, *k, *orig; - int s; - int c0, c1, c2; - - if(0 < m) { - /* Construct the sorted order of type B suffixes by using - the sorted order of type B* suffixes. */ - for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { - /* Scan the suffix array from right to left. */ - for(i = SA + BUCKET_BSTAR(c1, c1 + 1), - j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; - i <= j; - --j) { - if(0 < (s = *j)) { - assert(T[s] == c1); - assert(((s + 1) < n) && (T[s] <= T[s + 1])); - assert(T[s - 1] <= T[s]); - c0 = T[--s]; - *j = ~((int)c0); - if((0 < s) && (T[s - 1] > c0)) { s = ~s; } - if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } - k = SA + BUCKET_B(c2 = c0, c1); - } - assert(k < j); assert(k != NULL); - *k-- = s; - } else if(s != 0) { - *j = ~s; -#ifndef NDEBUG - } else { - assert(T[s] == c1); -#endif - } - } - } - } - - /* Construct the BWTed string by using - the sorted order of type B suffixes. */ - k = SA + BUCKET_A(c2 = T[n - 1]); - *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1); - /* Scan the suffix array from left to right. */ - for(i = SA, j = SA + n, orig = SA; i < j; ++i) { - if(0 < (s = *i)) { - assert(T[s - 1] >= T[s]); - c0 = T[--s]; - *i = c0; - if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); } - if(c0 != c2) { - BUCKET_A(c2) = k - SA; - k = SA + BUCKET_A(c2 = c0); - } - assert(i < k); - *k++ = s; - } else if(s != 0) { - *i = ~s; - } else { - orig = i; - } - } - - return orig - SA; -} - -/* Constructs the burrows-wheeler transformed string directly - by using the sorted order of type B* suffixes. */ -static -int -construct_BWT_indexes(const unsigned char *T, int *SA, - int *bucket_A, int *bucket_B, - int n, int m, - unsigned char * num_indexes, int * indexes) { - int *i, *j, *k, *orig; - int s; - int c0, c1, c2; - - int mod = n / 8; - { - mod |= mod >> 1; mod |= mod >> 2; - mod |= mod >> 4; mod |= mod >> 8; - mod |= mod >> 16; mod >>= 1; - - *num_indexes = (unsigned char)((n - 1) / (mod + 1)); - } - - if(0 < m) { - /* Construct the sorted order of type B suffixes by using - the sorted order of type B* suffixes. */ - for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { - /* Scan the suffix array from right to left. */ - for(i = SA + BUCKET_BSTAR(c1, c1 + 1), - j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; - i <= j; - --j) { - if(0 < (s = *j)) { - assert(T[s] == c1); - assert(((s + 1) < n) && (T[s] <= T[s + 1])); - assert(T[s - 1] <= T[s]); - - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA; - - c0 = T[--s]; - *j = ~((int)c0); - if((0 < s) && (T[s - 1] > c0)) { s = ~s; } - if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } - k = SA + BUCKET_B(c2 = c0, c1); - } - assert(k < j); assert(k != NULL); - *k-- = s; - } else if(s != 0) { - *j = ~s; -#ifndef NDEBUG - } else { - assert(T[s] == c1); -#endif - } - } - } - } - - /* Construct the BWTed string by using - the sorted order of type B suffixes. */ - k = SA + BUCKET_A(c2 = T[n - 1]); - if (T[n - 2] < c2) { - if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA; - *k++ = ~((int)T[n - 2]); - } - else { - *k++ = n - 1; - } - - /* Scan the suffix array from left to right. */ - for(i = SA, j = SA + n, orig = SA; i < j; ++i) { - if(0 < (s = *i)) { - assert(T[s - 1] >= T[s]); - - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA; - - c0 = T[--s]; - *i = c0; - if(c0 != c2) { - BUCKET_A(c2) = k - SA; - k = SA + BUCKET_A(c2 = c0); - } - assert(i < k); - if((0 < s) && (T[s - 1] < c0)) { - if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA; - *k++ = ~((int)T[s - 1]); - } else - *k++ = s; - } else if(s != 0) { - *i = ~s; - } else { - orig = i; - } - } - - return orig - SA; -} - - -/*---------------------------------------------------------------------------*/ - -/*- Function -*/ - -int -divsufsort(const unsigned char *T, int *SA, int n, int openMP) { - int *bucket_A, *bucket_B; - int m; - int err = 0; - - /* Check arguments. */ - if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } - else if(n == 0) { return 0; } - else if(n == 1) { SA[0] = 0; return 0; } - else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } - - bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); - bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); - - /* Suffixsort. */ - if((bucket_A != NULL) && (bucket_B != NULL)) { - m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP); - construct_SA(T, SA, bucket_A, bucket_B, n, m); - } else { - err = -2; - } - - free(bucket_B); - free(bucket_A); - - return err; -} - -int -divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) { - int *B; - int *bucket_A, *bucket_B; - int m, pidx, i; - - /* Check arguments. */ - if((T == NULL) || (U == NULL) || (n < 0)) { return -1; } - else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } - - if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); } - bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); - bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); - - /* Burrows-Wheeler Transform. */ - if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) { - m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP); - - if (num_indexes == NULL || indexes == NULL) { - pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m); - } else { - pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes); - } - - /* Copy to output string. */ - U[0] = T[n - 1]; - for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; } - for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; } - pidx += 1; - } else { - pidx = -2; - } - - free(bucket_B); - free(bucket_A); - if(A == NULL) { free(B); } - - return pidx; -} - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/fastcover.cpp b/src/duckdb/third_party/zstd/dict/fastcover.cpp deleted file mode 100644 index 53e8b7c19..000000000 --- a/src/duckdb/third_party/zstd/dict/fastcover.cpp +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/*-************************************* -* Dependencies -***************************************/ -#include /* fprintf */ -#include /* malloc, free, qsort */ -#include /* memset */ -#include /* clock */ - -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - -#include "zstd/common/mem.h" /* read */ -#include "zstd/common/pool.h" -#include "zstd/common/threading.h" -#include "zstd/common/zstd_internal.h" /* includes zstd.h */ -#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_hash*() */ -#include "zdict.h" -#include "zstd/dict/cover.h" - - -/*-************************************* -* Constants -***************************************/ -/** -* There are 32bit indexes used to ref samples, so limit samples size to 4GB -* on 64bit builds. -* For 32bit builds we choose 1 GB. -* Most 32bit platforms have 2GB user-mode addressable space and we allocate a large -* contiguous buffer, so 1GB is already a high limit. -*/ -#define FASTCOVER_MAX_SAMPLES_SIZE (sizeof(size_t) == 8 ? ((unsigned)-1) : ((unsigned)1 GB)) -#define FASTCOVER_MAX_F 31 -#define FASTCOVER_MAX_ACCEL 10 -#define FASTCOVER_DEFAULT_SPLITPOINT 0.75 -#define DEFAULT_F 20 -#define DEFAULT_ACCEL 1 - -namespace duckdb_zstd { - -/*-************************************* -* Console display -***************************************/ -#ifndef LOCALDISPLAYLEVEL -static int g_displayLevel = 0; -#endif -#undef DISPLAY -// CRAN does not allow stderr references -#define DISPLAY(...) \ - { \ - } -#undef LOCALDISPLAYLEVEL -#define LOCALDISPLAYLEVEL(displayLevel, l, ...) \ - if (displayLevel >= l) { \ - DISPLAY(__VA_ARGS__); \ - } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ -#undef DISPLAYLEVEL -#define DISPLAYLEVEL(l, ...) LOCALDISPLAYLEVEL(g_displayLevel, l, __VA_ARGS__) - -#ifndef LOCALDISPLAYUPDATE -static const clock_t g_refreshRate = CLOCKS_PER_SEC * 15 / 100; -static clock_t g_time = 0; -#endif -#undef LOCALDISPLAYUPDATE -#define LOCALDISPLAYUPDATE(displayLevel, l, ...) \ - if (displayLevel >= l) { \ - if ((clock() - g_time > g_refreshRate) || (displayLevel >= 4)) { \ - g_time = clock(); \ - DISPLAY(__VA_ARGS__); \ - } \ - } -#undef DISPLAYUPDATE -#define DISPLAYUPDATE(l, ...) LOCALDISPLAYUPDATE(g_displayLevel, l, __VA_ARGS__) - - -/*-************************************* -* Hash Functions -***************************************/ -/** - * Hash the d-byte value pointed to by p and mod 2^f into the frequency vector - */ -static size_t FASTCOVER_hashPtrToIndex(const void* p, U32 f, unsigned d) { - if (d == 6) { - return ZSTD_hash6Ptr(p, f); - } - return ZSTD_hash8Ptr(p, f); -} - - -/*-************************************* -* Acceleration -***************************************/ -typedef struct { - unsigned finalize; /* Percentage of training samples used for ZDICT_finalizeDictionary */ - unsigned skip; /* Number of dmer skipped between each dmer counted in computeFrequency */ -} FASTCOVER_accel_t; - - -static const FASTCOVER_accel_t FASTCOVER_defaultAccelParameters[FASTCOVER_MAX_ACCEL+1] = { - { 100, 0 }, /* accel = 0, should not happen because accel = 0 defaults to accel = 1 */ - { 100, 0 }, /* accel = 1 */ - { 50, 1 }, /* accel = 2 */ - { 34, 2 }, /* accel = 3 */ - { 25, 3 }, /* accel = 4 */ - { 20, 4 }, /* accel = 5 */ - { 17, 5 }, /* accel = 6 */ - { 14, 6 }, /* accel = 7 */ - { 13, 7 }, /* accel = 8 */ - { 11, 8 }, /* accel = 9 */ - { 10, 9 }, /* accel = 10 */ -}; - - -/*-************************************* -* Context -***************************************/ -typedef struct { - const BYTE *samples; - size_t *offsets; - const size_t *samplesSizes; - size_t nbSamples; - size_t nbTrainSamples; - size_t nbTestSamples; - size_t nbDmers; - U32 *freqs; - unsigned d; - unsigned f; - FASTCOVER_accel_t accelParams; -} FASTCOVER_ctx_t; - - -/*-************************************* -* Helper functions -***************************************/ -/** - * Selects the best segment in an epoch. - * Segments of are scored according to the function: - * - * Let F(d) be the frequency of all dmers with hash value d. - * Let S_i be hash value of the dmer at position i of segment S which has length k. - * - * Score(S) = F(S_1) + F(S_2) + ... + F(S_{k-d+1}) - * - * Once the dmer with hash value d is in the dictionary we set F(d) = 0. - */ -static COVER_segment_t FASTCOVER_selectSegment(const FASTCOVER_ctx_t *ctx, - U32 *freqs, U32 begin, U32 end, - ZDICT_cover_params_t parameters, - U16* segmentFreqs) { - /* Constants */ - const U32 k = parameters.k; - const U32 d = parameters.d; - const U32 f = ctx->f; - const U32 dmersInK = k - d + 1; - - /* Try each segment (activeSegment) and save the best (bestSegment) */ - COVER_segment_t bestSegment = {0, 0, 0}; - COVER_segment_t activeSegment; - - /* Reset the activeDmers in the segment */ - /* The activeSegment starts at the beginning of the epoch. */ - activeSegment.begin = begin; - activeSegment.end = begin; - activeSegment.score = 0; - - /* Slide the activeSegment through the whole epoch. - * Save the best segment in bestSegment. - */ - while (activeSegment.end < end) { - /* Get hash value of current dmer */ - const size_t idx = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.end, f, d); - - /* Add frequency of this index to score if this is the first occurrence of index in active segment */ - if (segmentFreqs[idx] == 0) { - activeSegment.score += freqs[idx]; - } - /* Increment end of segment and segmentFreqs*/ - activeSegment.end += 1; - segmentFreqs[idx] += 1; - /* If the window is now too large, drop the first position */ - if (activeSegment.end - activeSegment.begin == dmersInK + 1) { - /* Get hash value of the dmer to be eliminated from active segment */ - const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d); - segmentFreqs[delIndex] -= 1; - /* Subtract frequency of this index from score if this is the last occurrence of this index in active segment */ - if (segmentFreqs[delIndex] == 0) { - activeSegment.score -= freqs[delIndex]; - } - /* Increment start of segment */ - activeSegment.begin += 1; - } - - /* If this segment is the best so far save it */ - if (activeSegment.score > bestSegment.score) { - bestSegment = activeSegment; - } - } - - /* Zero out rest of segmentFreqs array */ - while (activeSegment.begin < end) { - const size_t delIndex = FASTCOVER_hashPtrToIndex(ctx->samples + activeSegment.begin, f, d); - segmentFreqs[delIndex] -= 1; - activeSegment.begin += 1; - } - - { - /* Zero the frequency of hash value of each dmer covered by the chosen segment. */ - U32 pos; - for (pos = bestSegment.begin; pos != bestSegment.end; ++pos) { - const size_t i = FASTCOVER_hashPtrToIndex(ctx->samples + pos, f, d); - freqs[i] = 0; - } - } - - return bestSegment; -} - - -static int FASTCOVER_checkParameters(ZDICT_cover_params_t parameters, - size_t maxDictSize, unsigned f, - unsigned accel) { - /* k, d, and f are required parameters */ - if (parameters.d == 0 || parameters.k == 0) { - return 0; - } - /* d has to be 6 or 8 */ - if (parameters.d != 6 && parameters.d != 8) { - return 0; - } - /* k <= maxDictSize */ - if (parameters.k > maxDictSize) { - return 0; - } - /* d <= k */ - if (parameters.d > parameters.k) { - return 0; - } - /* 0 < f <= FASTCOVER_MAX_F*/ - if (f > FASTCOVER_MAX_F || f == 0) { - return 0; - } - /* 0 < splitPoint <= 1 */ - if (parameters.splitPoint <= 0 || parameters.splitPoint > 1) { - return 0; - } - /* 0 < accel <= 10 */ - if (accel > 10 || accel == 0) { - return 0; - } - return 1; -} - - -/** - * Clean up a context initialized with `FASTCOVER_ctx_init()`. - */ -static void -FASTCOVER_ctx_destroy(FASTCOVER_ctx_t* ctx) -{ - if (!ctx) return; - - free(ctx->freqs); - ctx->freqs = NULL; - - free(ctx->offsets); - ctx->offsets = NULL; -} - - -/** - * Calculate for frequency of hash value of each dmer in ctx->samples - */ -static void -FASTCOVER_computeFrequency(U32* freqs, const FASTCOVER_ctx_t* ctx) -{ - const unsigned f = ctx->f; - const unsigned d = ctx->d; - const unsigned skip = ctx->accelParams.skip; - const unsigned readLength = MAX(d, 8); - size_t i; - assert(ctx->nbTrainSamples >= 5); - assert(ctx->nbTrainSamples <= ctx->nbSamples); - for (i = 0; i < ctx->nbTrainSamples; i++) { - size_t start = ctx->offsets[i]; /* start of current dmer */ - size_t const currSampleEnd = ctx->offsets[i+1]; - while (start + readLength <= currSampleEnd) { - const size_t dmerIndex = FASTCOVER_hashPtrToIndex(ctx->samples + start, f, d); - freqs[dmerIndex]++; - start = start + skip + 1; - } - } -} - - -/** - * Prepare a context for dictionary building. - * The context is only dependent on the parameter `d` and can be used multiple - * times. - * Returns 0 on success or error code on error. - * The context must be destroyed with `FASTCOVER_ctx_destroy()`. - */ -static size_t -FASTCOVER_ctx_init(FASTCOVER_ctx_t* ctx, - const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - unsigned d, double splitPoint, unsigned f, - FASTCOVER_accel_t accelParams) -{ - const BYTE* const samples = (const BYTE*)samplesBuffer; - const size_t totalSamplesSize = COVER_sum(samplesSizes, nbSamples); - /* Split samples into testing and training sets */ - const unsigned nbTrainSamples = splitPoint < 1.0 ? (unsigned)((double)nbSamples * splitPoint) : nbSamples; - const unsigned nbTestSamples = splitPoint < 1.0 ? nbSamples - nbTrainSamples : nbSamples; - const size_t trainingSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes, nbTrainSamples) : totalSamplesSize; - const size_t testSamplesSize = splitPoint < 1.0 ? COVER_sum(samplesSizes + nbTrainSamples, nbTestSamples) : totalSamplesSize; - - (void) testSamplesSize; - - /* Checks */ - if (totalSamplesSize < MAX(d, sizeof(U64)) || - totalSamplesSize >= (size_t)FASTCOVER_MAX_SAMPLES_SIZE) { - DISPLAYLEVEL(1, "Total samples size is too large (%u MB), maximum size is %u MB\n", - (unsigned)(totalSamplesSize >> 20), (FASTCOVER_MAX_SAMPLES_SIZE >> 20)); - return ERROR(srcSize_wrong); - } - - /* Check if there are at least 5 training samples */ - if (nbTrainSamples < 5) { - DISPLAYLEVEL(1, "Total number of training samples is %u and is invalid\n", nbTrainSamples); - return ERROR(srcSize_wrong); - } - - /* Check if there's testing sample */ - if (nbTestSamples < 1) { - DISPLAYLEVEL(1, "Total number of testing samples is %u and is invalid.\n", nbTestSamples); - return ERROR(srcSize_wrong); - } - - /* Zero the context */ - memset(ctx, 0, sizeof(*ctx)); - DISPLAYLEVEL(2, "Training on %u samples of total size %u\n", nbTrainSamples, - (unsigned)trainingSamplesSize); - DISPLAYLEVEL(2, "Testing on %u samples of total size %u\n", nbTestSamples, - (unsigned)testSamplesSize); - - ctx->samples = samples; - ctx->samplesSizes = samplesSizes; - ctx->nbSamples = nbSamples; - ctx->nbTrainSamples = nbTrainSamples; - ctx->nbTestSamples = nbTestSamples; - ctx->nbDmers = trainingSamplesSize - MAX(d, sizeof(U64)) + 1; - ctx->d = d; - ctx->f = f; - ctx->accelParams = accelParams; - - /* The offsets of each file */ - ctx->offsets = (size_t*)calloc((nbSamples + 1), sizeof(size_t)); - if (ctx->offsets == NULL) { - DISPLAYLEVEL(1, "Failed to allocate scratch buffers \n"); - FASTCOVER_ctx_destroy(ctx); - return ERROR(memory_allocation); - } - - /* Fill offsets from the samplesSizes */ - { U32 i; - ctx->offsets[0] = 0; - assert(nbSamples >= 5); - for (i = 1; i <= nbSamples; ++i) { - ctx->offsets[i] = ctx->offsets[i - 1] + samplesSizes[i - 1]; - } - } - - /* Initialize frequency array of size 2^f */ - ctx->freqs = (U32*)calloc(((U64)1 << f), sizeof(U32)); - if (ctx->freqs == NULL) { - DISPLAYLEVEL(1, "Failed to allocate frequency table \n"); - FASTCOVER_ctx_destroy(ctx); - return ERROR(memory_allocation); - } - - DISPLAYLEVEL(2, "Computing frequencies\n"); - FASTCOVER_computeFrequency(ctx->freqs, ctx); - - return 0; -} - - -/** - * Given the prepared context build the dictionary. - */ -static size_t -FASTCOVER_buildDictionary(const FASTCOVER_ctx_t* ctx, - U32* freqs, - void* dictBuffer, size_t dictBufferCapacity, - ZDICT_cover_params_t parameters, - U16* segmentFreqs) -{ - BYTE *const dict = (BYTE *)dictBuffer; - size_t tail = dictBufferCapacity; - /* Divide the data into epochs. We will select one segment from each epoch. */ - const COVER_epoch_info_t epochs = COVER_computeEpochs( - (U32)dictBufferCapacity, (U32)ctx->nbDmers, parameters.k, 1); - const size_t maxZeroScoreRun = 10; - size_t zeroScoreRun = 0; - size_t epoch; - DISPLAYLEVEL(2, "Breaking content into %u epochs of size %u\n", - (U32)epochs.num, (U32)epochs.size); - /* Loop through the epochs until there are no more segments or the dictionary - * is full. - */ - for (epoch = 0; tail > 0; epoch = (epoch + 1) % epochs.num) { - const U32 epochBegin = (U32)(epoch * epochs.size); - const U32 epochEnd = epochBegin + epochs.size; - size_t segmentSize; - /* Select a segment */ - COVER_segment_t segment = FASTCOVER_selectSegment( - ctx, freqs, epochBegin, epochEnd, parameters, segmentFreqs); - - /* If the segment covers no dmers, then we are out of content. - * There may be new content in other epochs, for continue for some time. - */ - if (segment.score == 0) { - if (++zeroScoreRun >= maxZeroScoreRun) { - break; - } - continue; - } - zeroScoreRun = 0; - - /* Trim the segment if necessary and if it is too small then we are done */ - segmentSize = MIN(segment.end - segment.begin + parameters.d - 1, tail); - if (segmentSize < parameters.d) { - break; - } - - /* We fill the dictionary from the back to allow the best segments to be - * referenced with the smallest offsets. - */ - tail -= segmentSize; - memcpy(dict + tail, ctx->samples + segment.begin, segmentSize); - DISPLAYUPDATE( - 2, "\r%u%% ", - (unsigned)(((dictBufferCapacity - tail) * 100) / dictBufferCapacity)); - } - DISPLAYLEVEL(2, "\r%79s\r", ""); - return tail; -} - -/** - * Parameters for FASTCOVER_tryParameters(). - */ -typedef struct FASTCOVER_tryParameters_data_s { - const FASTCOVER_ctx_t* ctx; - COVER_best_t* best; - size_t dictBufferCapacity; - ZDICT_cover_params_t parameters; -} FASTCOVER_tryParameters_data_t; - - -/** - * Tries a set of parameters and updates the COVER_best_t with the results. - * This function is thread safe if zstd is compiled with multithreaded support. - * It takes its parameters as an *OWNING* opaque pointer to support threading. - */ -static void FASTCOVER_tryParameters(void* opaque) -{ - /* Save parameters as local variables */ - FASTCOVER_tryParameters_data_t *const data = (FASTCOVER_tryParameters_data_t*)opaque; - const FASTCOVER_ctx_t *const ctx = data->ctx; - const ZDICT_cover_params_t parameters = data->parameters; - size_t dictBufferCapacity = data->dictBufferCapacity; - size_t totalCompressedSize = ERROR(GENERIC); - /* Initialize array to keep track of frequency of dmer within activeSegment */ - U16* segmentFreqs = (U16*)calloc(((U64)1 << ctx->f), sizeof(U16)); - /* Allocate space for hash table, dict, and freqs */ - BYTE *const dict = (BYTE*)malloc(dictBufferCapacity); - COVER_dictSelection_t selection = COVER_dictSelectionError(ERROR(GENERIC)); - U32* freqs = (U32*) malloc(((U64)1 << ctx->f) * sizeof(U32)); - if (!segmentFreqs || !dict || !freqs) { - DISPLAYLEVEL(1, "Failed to allocate buffers: out of memory\n"); - goto _cleanup; - } - /* Copy the frequencies because we need to modify them */ - memcpy(freqs, ctx->freqs, ((U64)1 << ctx->f) * sizeof(U32)); - /* Build the dictionary */ - { const size_t tail = FASTCOVER_buildDictionary(ctx, freqs, dict, dictBufferCapacity, - parameters, segmentFreqs); - - const unsigned nbFinalizeSamples = (unsigned)(ctx->nbTrainSamples * ctx->accelParams.finalize / 100); - selection = COVER_selectDict(dict + tail, dictBufferCapacity, dictBufferCapacity - tail, - ctx->samples, ctx->samplesSizes, nbFinalizeSamples, ctx->nbTrainSamples, ctx->nbSamples, parameters, ctx->offsets, - totalCompressedSize); - - if (COVER_dictSelectionIsError(selection)) { - DISPLAYLEVEL(1, "Failed to select dictionary\n"); - goto _cleanup; - } - } -_cleanup: - free(dict); - COVER_best_finish(data->best, parameters, selection); - free(data); - free(segmentFreqs); - COVER_dictSelectionFree(selection); - free(freqs); -} - - -static void -FASTCOVER_convertToCoverParams(ZDICT_fastCover_params_t fastCoverParams, - ZDICT_cover_params_t* coverParams) -{ - coverParams->k = fastCoverParams.k; - coverParams->d = fastCoverParams.d; - coverParams->steps = fastCoverParams.steps; - coverParams->nbThreads = fastCoverParams.nbThreads; - coverParams->splitPoint = fastCoverParams.splitPoint; - coverParams->zParams = fastCoverParams.zParams; - coverParams->shrinkDict = fastCoverParams.shrinkDict; -} - - -static void -FASTCOVER_convertToFastCoverParams(ZDICT_cover_params_t coverParams, - ZDICT_fastCover_params_t* fastCoverParams, - unsigned f, unsigned accel) -{ - fastCoverParams->k = coverParams.k; - fastCoverParams->d = coverParams.d; - fastCoverParams->steps = coverParams.steps; - fastCoverParams->nbThreads = coverParams.nbThreads; - fastCoverParams->splitPoint = coverParams.splitPoint; - fastCoverParams->f = f; - fastCoverParams->accel = accel; - fastCoverParams->zParams = coverParams.zParams; - fastCoverParams->shrinkDict = coverParams.shrinkDict; -} - - -ZDICTLIB_STATIC_API size_t -ZDICT_trainFromBuffer_fastCover(void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - ZDICT_fastCover_params_t parameters) -{ - BYTE* const dict = (BYTE*)dictBuffer; - FASTCOVER_ctx_t ctx; - ZDICT_cover_params_t coverParams; - FASTCOVER_accel_t accelParams; - /* Initialize global data */ - g_displayLevel = (int)parameters.zParams.notificationLevel; - /* Assign splitPoint and f if not provided */ - parameters.splitPoint = 1.0; - parameters.f = parameters.f == 0 ? DEFAULT_F : parameters.f; - parameters.accel = parameters.accel == 0 ? DEFAULT_ACCEL : parameters.accel; - /* Convert to cover parameter */ - memset(&coverParams, 0 , sizeof(coverParams)); - FASTCOVER_convertToCoverParams(parameters, &coverParams); - /* Checks */ - if (!FASTCOVER_checkParameters(coverParams, dictBufferCapacity, parameters.f, - parameters.accel)) { - DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n"); - return ERROR(parameter_outOfBound); - } - if (nbSamples == 0) { - DISPLAYLEVEL(1, "FASTCOVER must have at least one input file\n"); - return ERROR(srcSize_wrong); - } - if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { - DISPLAYLEVEL(1, "dictBufferCapacity must be at least %u\n", - ZDICT_DICTSIZE_MIN); - return ERROR(dstSize_tooSmall); - } - /* Assign corresponding FASTCOVER_accel_t to accelParams*/ - accelParams = FASTCOVER_defaultAccelParameters[parameters.accel]; - /* Initialize context */ - { - size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, - coverParams.d, parameters.splitPoint, parameters.f, - accelParams); - if (ZSTD_isError(initVal)) { - DISPLAYLEVEL(1, "Failed to initialize context\n"); - return initVal; - } - } - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, g_displayLevel); - /* Build the dictionary */ - DISPLAYLEVEL(2, "Building dictionary\n"); - { - /* Initialize array to keep track of frequency of dmer within activeSegment */ - U16* segmentFreqs = (U16 *)calloc(((U64)1 << parameters.f), sizeof(U16)); - const size_t tail = FASTCOVER_buildDictionary(&ctx, ctx.freqs, dictBuffer, - dictBufferCapacity, coverParams, segmentFreqs); - const unsigned nbFinalizeSamples = (unsigned)(ctx.nbTrainSamples * ctx.accelParams.finalize / 100); - const size_t dictionarySize = ZDICT_finalizeDictionary( - dict, dictBufferCapacity, dict + tail, dictBufferCapacity - tail, - samplesBuffer, samplesSizes, nbFinalizeSamples, coverParams.zParams); - if (!ZSTD_isError(dictionarySize)) { - DISPLAYLEVEL(2, "Constructed dictionary of size %u\n", - (unsigned)dictionarySize); - } - FASTCOVER_ctx_destroy(&ctx); - free(segmentFreqs); - return dictionarySize; - } -} - - -ZDICTLIB_STATIC_API size_t -ZDICT_optimizeTrainFromBuffer_fastCover( - void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - ZDICT_fastCover_params_t* parameters) -{ - ZDICT_cover_params_t coverParams; - FASTCOVER_accel_t accelParams; - /* constants */ - const unsigned nbThreads = parameters->nbThreads; - const double splitPoint = - parameters->splitPoint <= 0.0 ? FASTCOVER_DEFAULT_SPLITPOINT : parameters->splitPoint; - const unsigned kMinD = parameters->d == 0 ? 6 : parameters->d; - const unsigned kMaxD = parameters->d == 0 ? 8 : parameters->d; - const unsigned kMinK = parameters->k == 0 ? 50 : parameters->k; - const unsigned kMaxK = parameters->k == 0 ? 2000 : parameters->k; - const unsigned kSteps = parameters->steps == 0 ? 40 : parameters->steps; - const unsigned kStepSize = MAX((kMaxK - kMinK) / kSteps, 1); - const unsigned kIterations = - (1 + (kMaxD - kMinD) / 2) * (1 + (kMaxK - kMinK) / kStepSize); - const unsigned f = parameters->f == 0 ? DEFAULT_F : parameters->f; - const unsigned accel = parameters->accel == 0 ? DEFAULT_ACCEL : parameters->accel; - const unsigned shrinkDict = 0; - /* Local variables */ - const int displayLevel = (int)parameters->zParams.notificationLevel; - unsigned iteration = 1; - unsigned d; - unsigned k; - COVER_best_t best; - POOL_ctx *pool = NULL; - int warned = 0; - - (void) kIterations; - (void) iteration; - - /* Checks */ - if (splitPoint <= 0 || splitPoint > 1) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect splitPoint\n"); - return ERROR(parameter_outOfBound); - } - if (accel == 0 || accel > FASTCOVER_MAX_ACCEL) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect accel\n"); - return ERROR(parameter_outOfBound); - } - if (kMinK < kMaxD || kMaxK < kMinK) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Incorrect k\n"); - return ERROR(parameter_outOfBound); - } - if (nbSamples == 0) { - LOCALDISPLAYLEVEL(displayLevel, 1, "FASTCOVER must have at least one input file\n"); - return ERROR(srcSize_wrong); - } - if (dictBufferCapacity < ZDICT_DICTSIZE_MIN) { - LOCALDISPLAYLEVEL(displayLevel, 1, "dictBufferCapacity must be at least %u\n", - ZDICT_DICTSIZE_MIN); - return ERROR(dstSize_tooSmall); - } - if (nbThreads > 1) { - pool = POOL_create(nbThreads, 1); - if (!pool) { - return ERROR(memory_allocation); - } - } - /* Initialization */ - COVER_best_init(&best); - memset(&coverParams, 0 , sizeof(coverParams)); - FASTCOVER_convertToCoverParams(*parameters, &coverParams); - accelParams = FASTCOVER_defaultAccelParameters[accel]; - /* Turn down global display level to clean up display at level 2 and below */ - g_displayLevel = displayLevel == 0 ? 0 : displayLevel - 1; - /* Loop through d first because each new value needs a new context */ - LOCALDISPLAYLEVEL(displayLevel, 2, "Trying %u different sets of parameters\n", - kIterations); - for (d = kMinD; d <= kMaxD; d += 2) { - /* Initialize the context for this value of d */ - FASTCOVER_ctx_t ctx; - LOCALDISPLAYLEVEL(displayLevel, 3, "d=%u\n", d); - { - size_t const initVal = FASTCOVER_ctx_init(&ctx, samplesBuffer, samplesSizes, nbSamples, d, splitPoint, f, accelParams); - if (ZSTD_isError(initVal)) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to initialize context\n"); - COVER_best_destroy(&best); - POOL_free(pool); - return initVal; - } - } - if (!warned) { - COVER_warnOnSmallCorpus(dictBufferCapacity, ctx.nbDmers, displayLevel); - warned = 1; - } - /* Loop through k reusing the same context */ - for (k = kMinK; k <= kMaxK; k += kStepSize) { - /* Prepare the arguments */ - FASTCOVER_tryParameters_data_t *data = (FASTCOVER_tryParameters_data_t *)malloc( - sizeof(FASTCOVER_tryParameters_data_t)); - LOCALDISPLAYLEVEL(displayLevel, 3, "k=%u\n", k); - if (!data) { - LOCALDISPLAYLEVEL(displayLevel, 1, "Failed to allocate parameters\n"); - COVER_best_destroy(&best); - FASTCOVER_ctx_destroy(&ctx); - POOL_free(pool); - return ERROR(memory_allocation); - } - data->ctx = &ctx; - data->best = &best; - data->dictBufferCapacity = dictBufferCapacity; - data->parameters = coverParams; - data->parameters.k = k; - data->parameters.d = d; - data->parameters.splitPoint = splitPoint; - data->parameters.steps = kSteps; - data->parameters.shrinkDict = shrinkDict; - data->parameters.zParams.notificationLevel = (unsigned)g_displayLevel; - /* Check the parameters */ - if (!FASTCOVER_checkParameters(data->parameters, dictBufferCapacity, - data->ctx->f, accel)) { - DISPLAYLEVEL(1, "FASTCOVER parameters incorrect\n"); - free(data); - continue; - } - /* Call the function and pass ownership of data to it */ - COVER_best_start(&best); - if (pool) { - POOL_add(pool, &FASTCOVER_tryParameters, data); - } else { - FASTCOVER_tryParameters(data); - } - /* Print status */ - LOCALDISPLAYUPDATE(displayLevel, 2, "\r%u%% ", - (unsigned)((iteration * 100) / kIterations)); - ++iteration; - } - COVER_best_wait(&best); - FASTCOVER_ctx_destroy(&ctx); - } - LOCALDISPLAYLEVEL(displayLevel, 2, "\r%79s\r", ""); - /* Fill the output buffer and parameters with output of the best parameters */ - { - const size_t dictSize = best.dictSize; - if (ZSTD_isError(best.compressedSize)) { - const size_t compressedSize = best.compressedSize; - COVER_best_destroy(&best); - POOL_free(pool); - return compressedSize; - } - FASTCOVER_convertToFastCoverParams(best.parameters, parameters, f, accel); - memcpy(dictBuffer, best.dict, dictSize); - COVER_best_destroy(&best); - POOL_free(pool); - return dictSize; - } - -} - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/dict/zdict.cpp b/src/duckdb/third_party/zstd/dict/zdict.cpp deleted file mode 100644 index cfa829578..000000000 --- a/src/duckdb/third_party/zstd/dict/zdict.cpp +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - -/*-************************************** -* Tuning parameters -****************************************/ -#define MINRATIO 4 /* minimum nb of apparition to be selected in dictionary */ -#define ZDICT_MAX_SAMPLES_SIZE (2000U << 20) -#define ZDICT_MIN_SAMPLES_SIZE (ZDICT_CONTENTSIZE_MIN * MINRATIO) - - -/*-************************************** -* Compiler Options -****************************************/ -/* Unix Large Files support (>4GB) */ -#define _FILE_OFFSET_BITS 64 -#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ -# ifndef _LARGEFILE_SOURCE -# define _LARGEFILE_SOURCE -# endif -#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ -# ifndef _LARGEFILE64_SOURCE -# define _LARGEFILE64_SOURCE -# endif -#endif - - -/*-************************************* -* Dependencies -***************************************/ -#include /* malloc, free */ -#include /* memset */ -#include /* fprintf, fopen, ftello64 */ -#include /* clock */ - -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - -#include "zstd/common/mem.h" /* read */ -#include "zstd/common/fse.h" /* FSE_normalizeCount, FSE_writeNCount */ -#include "zstd/common/huf.h" /* HUF_buildCTable, HUF_writeCTable */ -#include "zstd/common/zstd_internal.h" /* includes zstd.h */ -#include "zstd/common/xxhash.hpp" /* XXH64 */ -#include "zstd/compress/zstd_compress_internal.h" /* ZSTD_loadCEntropy() */ -#include "zdict.h" -#include "zstd/dict/divsufsort.h" -#include "zstd/common/bits.h" /* ZSTD_NbCommonBytes */ - -namespace duckdb_zstd { - -/*-************************************* -* Constants -***************************************/ -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) - -#define DICTLISTSIZE_DEFAULT 10000 - -#define NOISELENGTH 32 - -static const U32 g_selectivity_default = 9; - - -/*-************************************* -* Console display -***************************************/ -#undef DISPLAY -// CRAN does not allow stderr references -#define DISPLAY(...) do { } while (0) -#undef DISPLAYLEVEL -#define DISPLAYLEVEL(l, ...) do { if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } } while (0) /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */ - -static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; } - -static void ZDICT_printHex(const void* ptr, size_t length) -{ - const BYTE* const b = (const BYTE*)ptr; - size_t u; - for (u=0; u126) c = '.'; /* non-printable char */ - DISPLAY("%c", c); - } -} - - -/*-******************************************************** -* Helper functions -**********************************************************/ -unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); } - -const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } - -unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize) -{ - if (dictSize < 8) return 0; - if (MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return 0; - return MEM_readLE32((const char*)dictBuffer + 4); -} - -size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize) -{ - size_t headerSize; - if (dictSize <= 8 || MEM_readLE32(dictBuffer) != ZSTD_MAGIC_DICTIONARY) return ERROR(dictionary_corrupted); - - { ZSTD_compressedBlockState_t* bs = (ZSTD_compressedBlockState_t*)malloc(sizeof(ZSTD_compressedBlockState_t)); - U32* wksp = (U32*)malloc(HUF_WORKSPACE_SIZE); - if (!bs || !wksp) { - headerSize = ERROR(memory_allocation); - } else { - ZSTD_reset_compressedBlockState(bs); - headerSize = ZSTD_loadCEntropy(bs, wksp, dictBuffer, dictSize); - } - - free(bs); - free(wksp); - } - - return headerSize; -} - -/*-******************************************************** -* Dictionary training functions -**********************************************************/ -/*! ZDICT_count() : - Count the nb of common bytes between 2 pointers. - Note : this function presumes end of buffer followed by noisy guard band. -*/ -static size_t ZDICT_count(const void* pIn, const void* pMatch) -{ - const char* const pStart = (const char*)pIn; - for (;;) { - size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn); - if (!diff) { - pIn = (const char*)pIn+sizeof(size_t); - pMatch = (const char*)pMatch+sizeof(size_t); - continue; - } - pIn = (const char*)pIn+ZSTD_NbCommonBytes(diff); - return (size_t)((const char*)pIn - pStart); - } -} - - -typedef struct { - U32 pos; - U32 length; - U32 savings; -} dictItem; - -static void ZDICT_initDictItem(dictItem* d) -{ - d->pos = 1; - d->length = 0; - d->savings = (U32)(-1); -} - - -#define LLIMIT 64 /* heuristic determined experimentally */ -#define MINMATCHLENGTH 7 /* heuristic determined experimentally */ -static dictItem ZDICT_analyzePos( - BYTE* doneMarks, - const int* suffix, U32 start, - const void* buffer, U32 minRatio, U32 notificationLevel) -{ - U32 lengthList[LLIMIT] = {0}; - U32 cumulLength[LLIMIT] = {0}; - U32 savings[LLIMIT] = {0}; - const BYTE* b = (const BYTE*)buffer; - size_t maxLength = LLIMIT; - size_t pos = (size_t)suffix[start]; - U32 end = start; - dictItem solution; - - /* init */ - memset(&solution, 0, sizeof(solution)); - doneMarks[pos] = 1; - - /* trivial repetition cases */ - if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2)) - ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3)) - ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) { - /* skip and mark segment */ - U16 const pattern16 = MEM_read16(b+pos+4); - U32 u, patternEnd = 6; - while (MEM_read16(b+pos+patternEnd) == pattern16) patternEnd+=2 ; - if (b[pos+patternEnd] == b[pos+patternEnd-1]) patternEnd++; - for (u=1; u= MINMATCHLENGTH); - } - - /* look backward */ - { size_t length; - do { - length = ZDICT_count(b + pos, b + *(suffix+start-1)); - if (length >=MINMATCHLENGTH) start--; - } while(length >= MINMATCHLENGTH); - } - - /* exit if not found a minimum nb of repetitions */ - if (end-start < minRatio) { - U32 idx; - for(idx=start; idx= %i at pos %7u ", (unsigned)(end-start), MINMATCHLENGTH, (unsigned)pos); - DISPLAYLEVEL(4, "\n"); - - for (mml = MINMATCHLENGTH ; ; mml++) { - BYTE currentChar = 0; - U32 currentCount = 0; - U32 currentID = refinedStart; - U32 id; - U32 selectedCount = 0; - U32 selectedID = currentID; - for (id =refinedStart; id < refinedEnd; id++) { - if (b[suffix[id] + mml] != currentChar) { - if (currentCount > selectedCount) { - selectedCount = currentCount; - selectedID = currentID; - } - currentID = id; - currentChar = b[ suffix[id] + mml]; - currentCount = 0; - } - currentCount ++; - } - if (currentCount > selectedCount) { /* for last */ - selectedCount = currentCount; - selectedID = currentID; - } - - if (selectedCount < minRatio) - break; - refinedStart = selectedID; - refinedEnd = refinedStart + selectedCount; - } - - /* evaluate gain based on new dict */ - start = refinedStart; - pos = suffix[refinedStart]; - end = start; - memset(lengthList, 0, sizeof(lengthList)); - - /* look forward */ - { size_t length; - do { - end++; - length = ZDICT_count(b + pos, b + suffix[end]); - if (length >= LLIMIT) length = LLIMIT-1; - lengthList[length]++; - } while (length >=MINMATCHLENGTH); - } - - /* look backward */ - { size_t length = MINMATCHLENGTH; - while ((length >= MINMATCHLENGTH) & (start > 0)) { - length = ZDICT_count(b + pos, b + suffix[start - 1]); - if (length >= LLIMIT) length = LLIMIT - 1; - lengthList[length]++; - if (length >= MINMATCHLENGTH) start--; - } - } - - /* largest useful length */ - memset(cumulLength, 0, sizeof(cumulLength)); - cumulLength[maxLength-1] = lengthList[maxLength-1]; - for (i=(int)(maxLength-2); i>=0; i--) - cumulLength[i] = cumulLength[i+1] + lengthList[i]; - - for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break; - maxLength = i; - - /* reduce maxLength in case of final into repetitive data */ - { U32 l = (U32)maxLength; - BYTE const c = b[pos + maxLength-1]; - while (b[pos+l-2]==c) l--; - maxLength = l; - } - if (maxLength < MINMATCHLENGTH) return solution; /* skip : no long-enough solution */ - - /* calculate savings */ - savings[5] = 0; - for (i=MINMATCHLENGTH; i<=(int)maxLength; i++) - savings[i] = savings[i-1] + (lengthList[i] * (i-3)); - - DISPLAYLEVEL(4, "Selected dict at position %u, of length %u : saves %u (ratio: %.2f) \n", - (unsigned)pos, (unsigned)maxLength, (unsigned)savings[maxLength], (double)savings[maxLength] / (double)maxLength); - - solution.pos = (U32)pos; - solution.length = (U32)maxLength; - solution.savings = savings[maxLength]; - - /* mark positions done */ - { U32 id; - for (id=start; id solution.length) length = solution.length; - } - pEnd = (U32)(testedPos + length); - for (p=testedPos; ppos; - const U32 eltEnd = elt.pos + elt.length; - const char* const buf = (const char*) buffer; - - /* tail overlap */ - U32 u; for (u=1; u elt.pos) && (table[u].pos <= eltEnd)) { /* overlap, existing > new */ - /* append */ - U32 const addedLength = table[u].pos - elt.pos; - table[u].length += addedLength; - table[u].pos = elt.pos; - table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ - table[u].savings += elt.length / 8; /* rough approx bonus */ - elt = table[u]; - /* sort : improve rank */ - while ((u>1) && (table[u-1].savings < elt.savings)) - table[u] = table[u-1], u--; - table[u] = elt; - return u; - } } - - /* front overlap */ - for (u=1; u= elt.pos) && (table[u].pos < elt.pos)) { /* overlap, existing < new */ - /* append */ - int const addedLength = (int)eltEnd - (int)(table[u].pos + table[u].length); - table[u].savings += elt.length / 8; /* rough approx bonus */ - if (addedLength > 0) { /* otherwise, elt fully included into existing */ - table[u].length += addedLength; - table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ - } - /* sort : improve rank */ - elt = table[u]; - while ((u>1) && (table[u-1].savings < elt.savings)) - table[u] = table[u-1], u--; - table[u] = elt; - return u; - } - - if (MEM_read64(buf + table[u].pos) == MEM_read64(buf + elt.pos + 1)) { - if (isIncluded(buf + table[u].pos, buf + elt.pos + 1, table[u].length)) { - size_t const addedLength = MAX( (int)elt.length - (int)table[u].length , 1 ); - table[u].pos = elt.pos; - table[u].savings += (U32)(elt.savings * addedLength / elt.length); - table[u].length = MIN(elt.length, table[u].length + 1); - return u; - } - } - } - - return 0; -} - - -static void ZDICT_removeDictItem(dictItem* table, U32 id) -{ - /* convention : table[0].pos stores nb of elts */ - U32 const max = table[0].pos; - U32 u; - if (!id) return; /* protection, should never happen */ - for (u=id; upos--; -} - - -static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt, const void* buffer) -{ - /* merge if possible */ - U32 mergeId = ZDICT_tryMerge(table, elt, 0, buffer); - if (mergeId) { - U32 newMerge = 1; - while (newMerge) { - newMerge = ZDICT_tryMerge(table, table[mergeId], mergeId, buffer); - if (newMerge) ZDICT_removeDictItem(table, mergeId); - mergeId = newMerge; - } - return; - } - - /* insert */ - { U32 current; - U32 nextElt = table->pos; - if (nextElt >= maxSize) nextElt = maxSize-1; - current = nextElt-1; - while (table[current].savings < elt.savings) { - table[current+1] = table[current]; - current--; - } - table[current+1] = elt; - table->pos = nextElt+1; - } -} - - -static U32 ZDICT_dictSize(const dictItem* dictList) -{ - U32 u, dictSize = 0; - for (u=1; u ZDICT_MAX_SAMPLES_SIZE) DISPLAYLEVEL(3, "sample set too large : reduced to %u MB ...\n", (unsigned)(ZDICT_MAX_SAMPLES_SIZE>>20)); - while (bufferSize > ZDICT_MAX_SAMPLES_SIZE) bufferSize -= fileSizes[--nbFiles]; - - /* sort */ - DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (unsigned)(bufferSize>>20)); - { int const divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0); - if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; } - } - suffix[bufferSize] = (int)bufferSize; /* leads into noise */ - suffix0[0] = (int)bufferSize; /* leads into noise */ - /* build reverse suffix sort */ - { size_t pos; - for (pos=0; pos < bufferSize; pos++) - reverseSuffix[suffix[pos]] = (U32)pos; - /* note filePos tracks borders between samples. - It's not used at this stage, but planned to become useful in a later update */ - filePos[0] = 0; - for (pos=1; pos> 21); - } -} - - -typedef struct -{ - ZSTD_CDict* dict; /* dictionary */ - ZSTD_CCtx* zc; /* working context */ - void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */ -} EStats_ress_t; - -#define MAXREPOFFSET 1024 - -static void ZDICT_countEStats(EStats_ress_t esr, const ZSTD_parameters* params, - unsigned* countLit, unsigned* offsetcodeCount, unsigned* matchlengthCount, unsigned* litlengthCount, U32* repOffsets, - const void* src, size_t srcSize, - U32 notificationLevel) -{ - size_t const blockSizeMax = MIN (ZSTD_BLOCKSIZE_MAX, 1 << params->cParams.windowLog); - size_t cSize; - - if (srcSize > blockSizeMax) srcSize = blockSizeMax; /* protection vs large samples */ - { size_t const errorCode = ZSTD_compressBegin_usingCDict_deprecated(esr.zc, esr.dict); - if (ZSTD_isError(errorCode)) { DISPLAYLEVEL(1, "warning : ZSTD_compressBegin_usingCDict failed \n"); return; } - - } - cSize = ZSTD_compressBlock_deprecated(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); - if (ZSTD_isError(cSize)) { DISPLAYLEVEL(3, "warning : could not compress sample size %u \n", (unsigned)srcSize); return; } - - if (cSize) { /* if == 0; block is not compressible */ - const seqStore_t* const seqStorePtr = ZSTD_getSeqStore(esr.zc); - - /* literals stats */ - { const BYTE* bytePtr; - for(bytePtr = seqStorePtr->litStart; bytePtr < seqStorePtr->lit; bytePtr++) - countLit[*bytePtr]++; - } - - /* seqStats */ - { U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - ZSTD_seqToCodes(seqStorePtr); - - { const BYTE* codePtr = seqStorePtr->ofCode; - U32 u; - for (u=0; umlCode; - U32 u; - for (u=0; ullCode; - U32 u; - for (u=0; u= 2) { /* rep offsets */ - const seqDef* const seq = seqStorePtr->sequencesStart; - U32 offset1 = seq[0].offBase - ZSTD_REP_NUM; - U32 offset2 = seq[1].offBase - ZSTD_REP_NUM; - if (offset1 >= MAXREPOFFSET) offset1 = 0; - if (offset2 >= MAXREPOFFSET) offset2 = 0; - repOffsets[offset1] += 3; - repOffsets[offset2] += 1; - } } } -} - -static size_t ZDICT_totalSampleSize(const size_t* fileSizes, unsigned nbFiles) -{ - size_t total=0; - unsigned u; - for (u=0; u0; u--) { - offsetCount_t tmp; - if (table[u-1].count >= table[u].count) break; - tmp = table[u-1]; - table[u-1] = table[u]; - table[u] = tmp; - } -} - -/* ZDICT_flatLit() : - * rewrite `countLit` to contain a mostly flat but still compressible distribution of literals. - * necessary to avoid generating a non-compressible distribution that HUF_writeCTable() cannot encode. - */ -static void ZDICT_flatLit(unsigned* countLit) -{ - int u; - for (u=1; u<256; u++) countLit[u] = 2; - countLit[0] = 4; - countLit[253] = 1; - countLit[254] = 1; -} - -#define OFFCODE_MAX 30 /* only applicable to first block */ -static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, - int compressionLevel, - const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, - const void* dictBuffer, size_t dictBufferSize, - unsigned notificationLevel) -{ - unsigned countLit[256]; - HUF_CREATE_STATIC_CTABLE(hufTable, 255); - unsigned offcodeCount[OFFCODE_MAX+1]; - short offcodeNCount[OFFCODE_MAX+1]; - U32 offcodeMax = ZSTD_highbit32((U32)(dictBufferSize + 128 KB)); - unsigned matchLengthCount[MaxML+1]; - short matchLengthNCount[MaxML+1]; - unsigned litLengthCount[MaxLL+1]; - short litLengthNCount[MaxLL+1]; - U32 repOffset[MAXREPOFFSET]; - offsetCount_t bestRepOffset[ZSTD_REP_NUM+1]; - EStats_ress_t esr = { NULL, NULL, NULL }; - ZSTD_parameters params; - U32 u, huffLog = 11, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total; - size_t pos = 0, errorCode; - size_t eSize = 0; - size_t const totalSrcSize = ZDICT_totalSampleSize(fileSizes, nbFiles); - size_t const averageSampleSize = totalSrcSize / (nbFiles + !nbFiles); - BYTE* dstPtr = (BYTE*)dstBuffer; - U32 wksp[HUF_CTABLE_WORKSPACE_SIZE_U32]; - - /* init */ - DEBUGLOG(4, "ZDICT_analyzeEntropy"); - if (offcodeMax>OFFCODE_MAX) { eSize = ERROR(dictionaryCreation_failed); goto _cleanup; } /* too large dictionary */ - for (u=0; u<256; u++) countLit[u] = 1; /* any character must be described */ - for (u=0; u<=offcodeMax; u++) offcodeCount[u] = 1; - for (u=0; u<=MaxML; u++) matchLengthCount[u] = 1; - for (u=0; u<=MaxLL; u++) litLengthCount[u] = 1; - memset(repOffset, 0, sizeof(repOffset)); - repOffset[1] = repOffset[4] = repOffset[8] = 1; - memset(bestRepOffset, 0, sizeof(bestRepOffset)); - if (compressionLevel==0) compressionLevel = ZSTD_CLEVEL_DEFAULT; - params = ZSTD_getParams(compressionLevel, averageSampleSize, dictBufferSize); - - esr.dict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_rawContent, params.cParams, ZSTD_defaultCMem); - esr.zc = ZSTD_createCCtx(); - esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX); - if (!esr.dict || !esr.zc || !esr.workPlace) { - eSize = ERROR(memory_allocation); - DISPLAYLEVEL(1, "Not enough memory \n"); - goto _cleanup; - } - - /* collect stats on all samples */ - for (u=0; u= 4) { - /* writeStats */ - DISPLAYLEVEL(4, "Offset Code Frequencies : \n"); - for (u=0; u<=offcodeMax; u++) { - DISPLAYLEVEL(4, "%2u :%7u \n", u, offcodeCount[u]); - } } - - /* analyze, build stats, starting with literals */ - { size_t maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); - if (HUF_isError(maxNbBits)) { - eSize = maxNbBits; - DISPLAYLEVEL(1, " HUF_buildCTable error \n"); - goto _cleanup; - } - if (maxNbBits==8) { /* not compressible : will fail on HUF_writeCTable() */ - DISPLAYLEVEL(2, "warning : pathological dataset : literals are not compressible : samples are noisy or too regular \n"); - ZDICT_flatLit(countLit); /* replace distribution by a fake "mostly flat but still compressible" distribution, that HUF_writeCTable() can encode */ - maxNbBits = HUF_buildCTable_wksp(hufTable, countLit, 255, huffLog, wksp, sizeof(wksp)); - assert(maxNbBits==9); - } - huffLog = (U32)maxNbBits; - } - - /* looking for most common first offsets */ - { U32 offset; - for (offset=1; offset dictBufferCapacity) { - dictContentSize = dictBufferCapacity - hSize; - } - - /* Pad the dictionary content with zeros if it is too small */ - if (dictContentSize < minContentSize) { - RETURN_ERROR_IF(hSize + minContentSize > dictBufferCapacity, dstSize_tooSmall, - "dictBufferCapacity too small to fit max repcode"); - paddingSize = minContentSize - dictContentSize; - } else { - paddingSize = 0; - } - - { - size_t const dictSize = hSize + paddingSize + dictContentSize; - - /* The dictionary consists of the header, optional padding, and the content. - * The padding comes before the content because the "best" position in the - * dictionary is the last byte. - */ - BYTE* const outDictHeader = (BYTE*)dictBuffer; - BYTE* const outDictPadding = outDictHeader + hSize; - BYTE* const outDictContent = outDictPadding + paddingSize; - - assert(dictSize <= dictBufferCapacity); - assert(outDictContent + dictContentSize == (BYTE*)dictBuffer + dictSize); - - /* First copy the customDictContent into its final location. - * `customDictContent` and `dictBuffer` may overlap, so we must - * do this before any other writes into the output buffer. - * Then copy the header & padding into the output buffer. - */ - memmove(outDictContent, customDictContent, dictContentSize); - memcpy(outDictHeader, header, hSize); - memset(outDictPadding, 0, paddingSize); - - return dictSize; - } -} - - -static size_t ZDICT_addEntropyTablesFromBuffer_advanced( - void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_params_t params) -{ - int const compressionLevel = (params.compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : params.compressionLevel; - U32 const notificationLevel = params.notificationLevel; - size_t hSize = 8; - - /* calculate entropy tables */ - DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ - DISPLAYLEVEL(2, "statistics ... \n"); - { size_t const eSize = ZDICT_analyzeEntropy((char*)dictBuffer+hSize, dictBufferCapacity-hSize, - compressionLevel, - samplesBuffer, samplesSizes, nbSamples, - (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, - notificationLevel); - if (ZDICT_isError(eSize)) return eSize; - hSize += eSize; - } - - /* add dictionary header (after entropy tables) */ - MEM_writeLE32(dictBuffer, ZSTD_MAGIC_DICTIONARY); - { U64 const randomID = XXH64((char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize, 0); - U32 const compliantID = (randomID % ((1U<<31)-32768)) + 32768; - U32 const dictID = params.dictID ? params.dictID : compliantID; - MEM_writeLE32((char*)dictBuffer+4, dictID); - } - - if (hSize + dictContentSize < dictBufferCapacity) - memmove((char*)dictBuffer + hSize, (char*)dictBuffer + dictBufferCapacity - dictContentSize, dictContentSize); - return MIN(dictBufferCapacity, hSize+dictContentSize); -} - -/*! ZDICT_trainFromBuffer_unsafe_legacy() : -* Warning : `samplesBuffer` must be followed by noisy guard band !!! -* @return : size of dictionary, or an error code which can be tested with ZDICT_isError() -*/ -static size_t ZDICT_trainFromBuffer_unsafe_legacy( - void* dictBuffer, size_t maxDictSize, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_legacy_params_t params) -{ - U32 const dictListSize = MAX(MAX(DICTLISTSIZE_DEFAULT, nbSamples), (U32)(maxDictSize/16)); - dictItem* const dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList)); - unsigned const selectivity = params.selectivityLevel == 0 ? g_selectivity_default : params.selectivityLevel; - unsigned const minRep = (selectivity > 30) ? MINRATIO : nbSamples >> selectivity; - size_t const targetDictSize = maxDictSize; - size_t const samplesBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples); - size_t dictSize = 0; - U32 const notificationLevel = params.zParams.notificationLevel; - - /* checks */ - if (!dictList) return ERROR(memory_allocation); - if (maxDictSize < ZDICT_DICTSIZE_MIN) { free(dictList); return ERROR(dstSize_tooSmall); } /* requested dictionary size is too small */ - if (samplesBuffSize < ZDICT_MIN_SAMPLES_SIZE) { free(dictList); return ERROR(dictionaryCreation_failed); } /* not enough source to create dictionary */ - - /* init */ - ZDICT_initDictItem(dictList); - - /* build dictionary */ - ZDICT_trainBuffer_legacy(dictList, dictListSize, - samplesBuffer, samplesBuffSize, - samplesSizes, nbSamples, - minRep, notificationLevel); - - /* display best matches */ - if (params.zParams.notificationLevel>= 3) { - unsigned const nb = MIN(25, dictList[0].pos); - unsigned const dictContentSize = ZDICT_dictSize(dictList); - unsigned u; - - (void) dictContentSize; - - DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", (unsigned)dictList[0].pos-1, dictContentSize); - DISPLAYLEVEL(3, "list %u best segments \n", nb-1); - for (u=1; u samplesBuffSize) || ((pos + length) > samplesBuffSize)) { - free(dictList); - return ERROR(GENERIC); /* should never happen */ - } - DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |", - u, length, pos, (unsigned)dictList[u].savings); - ZDICT_printHex((const char*)samplesBuffer+pos, printedLength); - DISPLAYLEVEL(3, "| \n"); - } } - - - /* create dictionary */ - { unsigned dictContentSize = ZDICT_dictSize(dictList); - if (dictContentSize < ZDICT_CONTENTSIZE_MIN) { free(dictList); return ERROR(dictionaryCreation_failed); } /* dictionary content too small */ - if (dictContentSize < targetDictSize/4) { - DISPLAYLEVEL(2, "! warning : selected content significantly smaller than requested (%u < %u) \n", dictContentSize, (unsigned)maxDictSize); - if (samplesBuffSize < 10 * targetDictSize) - DISPLAYLEVEL(2, "! consider increasing the number of samples (total size : %u MB)\n", (unsigned)(samplesBuffSize>>20)); - if (minRep > MINRATIO) { - DISPLAYLEVEL(2, "! consider increasing selectivity to produce larger dictionary (-s%u) \n", selectivity+1); - DISPLAYLEVEL(2, "! note : larger dictionaries are not necessarily better, test its efficiency on samples \n"); - } - } - - if ((dictContentSize > targetDictSize*3) && (nbSamples > 2*MINRATIO) && (selectivity>1)) { - unsigned proposedSelectivity = selectivity-1; - while ((nbSamples >> proposedSelectivity) <= MINRATIO) { proposedSelectivity--; } - DISPLAYLEVEL(2, "! note : calculated dictionary significantly larger than requested (%u > %u) \n", dictContentSize, (unsigned)maxDictSize); - DISPLAYLEVEL(2, "! consider increasing dictionary size, or produce denser dictionary (-s%u) \n", proposedSelectivity); - DISPLAYLEVEL(2, "! always test dictionary efficiency on real samples \n"); - } - - /* limit dictionary size */ - { U32 const max = dictList->pos; /* convention : nb of useful elts within dictList */ - U32 currentSize = 0; - U32 n; for (n=1; n targetDictSize) { currentSize -= dictList[n].length; break; } - } - dictList->pos = n; - dictContentSize = currentSize; - } - - /* build dict content */ - { U32 u; - BYTE* ptr = (BYTE*)dictBuffer + maxDictSize; - for (u=1; upos; u++) { - U32 l = dictList[u].length; - ptr -= l; - if (ptr<(BYTE*)dictBuffer) { free(dictList); return ERROR(GENERIC); } /* should not happen */ - memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l); - } } - - dictSize = ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, maxDictSize, - samplesBuffer, samplesSizes, nbSamples, - params.zParams); - } - - /* clean up */ - free(dictList); - return dictSize; -} - - -/* ZDICT_trainFromBuffer_legacy() : - * issue : samplesBuffer need to be followed by a noisy guard band. - * work around : duplicate the buffer, and add the noise */ -size_t ZDICT_trainFromBuffer_legacy(void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_legacy_params_t params) -{ - size_t result; - void* newBuff; - size_t const sBuffSize = ZDICT_totalSampleSize(samplesSizes, nbSamples); - if (sBuffSize < ZDICT_MIN_SAMPLES_SIZE) return 0; /* not enough content => no dictionary */ - - newBuff = malloc(sBuffSize + NOISELENGTH); - if (!newBuff) return ERROR(memory_allocation); - - memcpy(newBuff, samplesBuffer, sBuffSize); - ZDICT_fillNoise((char*)newBuff + sBuffSize, NOISELENGTH); /* guard band, for end of buffer condition */ - - result = - ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, dictBufferCapacity, newBuff, - samplesSizes, nbSamples, params); - free(newBuff); - return result; -} - - -size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples) -{ - ZDICT_fastCover_params_t params; - DEBUGLOG(3, "ZDICT_trainFromBuffer"); - memset(¶ms, 0, sizeof(params)); - params.d = 8; - params.steps = 4; - /* Use default level since no compression level information is available */ - params.zParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; -#if defined(DEBUGLEVEL) && (DEBUGLEVEL>=1) - params.zParams.notificationLevel = DEBUGLEVEL; -#endif - return ZDICT_optimizeTrainFromBuffer_fastCover(dictBuffer, dictBufferCapacity, - samplesBuffer, samplesSizes, nbSamples, - ¶ms); -} - -size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples) -{ - ZDICT_params_t params; - memset(¶ms, 0, sizeof(params)); - return ZDICT_addEntropyTablesFromBuffer_advanced(dictBuffer, dictContentSize, dictBufferCapacity, - samplesBuffer, samplesSizes, nbSamples, - params); -} - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zdict.h b/src/duckdb/third_party/zstd/include/zdict.h deleted file mode 100644 index eaf877270..000000000 --- a/src/duckdb/third_party/zstd/include/zdict.h +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - -#ifndef ZSTD_ZDICT_H -#define ZSTD_ZDICT_H - -/*====== Dependencies ======*/ -#include /* size_t */ - -namespace duckdb_zstd { - -/* ===== ZDICTLIB_API : control library symbols visibility ===== */ -#ifndef ZDICTLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZDICTLIB_VISIBILITY -# define ZDICTLIB_VISIBLE ZDICTLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZDICTLIB_VISIBLE __attribute__ ((visibility ("default"))) -# else -# define ZDICTLIB_VISIBLE -# endif -#endif - -#ifndef ZDICTLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZDICTLIB_HIDDEN __attribute__ ((visibility ("hidden"))) -# else -# define ZDICTLIB_HIDDEN -# endif -#endif - -#if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZDICTLIB_API __declspec(dllexport) ZDICTLIB_VISIBLE -#elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZDICTLIB_API __declspec(dllimport) ZDICTLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ -#else -# define ZDICTLIB_API ZDICTLIB_VISIBLE -#endif - -/******************************************************************************* - * Zstd dictionary builder - * - * FAQ - * === - * Why should I use a dictionary? - * ------------------------------ - * - * Zstd can use dictionaries to improve compression ratio of small data. - * Traditionally small files don't compress well because there is very little - * repetition in a single sample, since it is small. But, if you are compressing - * many similar files, like a bunch of JSON records that share the same - * structure, you can train a dictionary on ahead of time on some samples of - * these files. Then, zstd can use the dictionary to find repetitions that are - * present across samples. This can vastly improve compression ratio. - * - * When is a dictionary useful? - * ---------------------------- - * - * Dictionaries are useful when compressing many small files that are similar. - * The larger a file is, the less benefit a dictionary will have. Generally, - * we don't expect dictionary compression to be effective past 100KB. And the - * smaller a file is, the more we would expect the dictionary to help. - * - * How do I use a dictionary? - * -------------------------- - * - * Simply pass the dictionary to the zstd compressor with - * `ZSTD_CCtx_loadDictionary()`. The same dictionary must then be passed to - * the decompressor, using `ZSTD_DCtx_loadDictionary()`. There are other - * more advanced functions that allow selecting some options, see zstd.h for - * complete documentation. - * - * What is a zstd dictionary? - * -------------------------- - * - * A zstd dictionary has two pieces: Its header, and its content. The header - * contains a magic number, the dictionary ID, and entropy tables. These - * entropy tables allow zstd to save on header costs in the compressed file, - * which really matters for small data. The content is just bytes, which are - * repeated content that is common across many samples. - * - * What is a raw content dictionary? - * --------------------------------- - * - * A raw content dictionary is just bytes. It doesn't have a zstd dictionary - * header, a dictionary ID, or entropy tables. Any buffer is a valid raw - * content dictionary. - * - * How do I train a dictionary? - * ---------------------------- - * - * Gather samples from your use case. These samples should be similar to each - * other. If you have several use cases, you could try to train one dictionary - * per use case. - * - * Pass those samples to `ZDICT_trainFromBuffer()` and that will train your - * dictionary. There are a few advanced versions of this function, but this - * is a great starting point. If you want to further tune your dictionary - * you could try `ZDICT_optimizeTrainFromBuffer_cover()`. If that is too slow - * you can try `ZDICT_optimizeTrainFromBuffer_fastCover()`. - * - * If the dictionary training function fails, that is likely because you - * either passed too few samples, or a dictionary would not be effective - * for your data. Look at the messages that the dictionary trainer printed, - * if it doesn't say too few samples, then a dictionary would not be effective. - * - * How large should my dictionary be? - * ---------------------------------- - * - * A reasonable dictionary size, the `dictBufferCapacity`, is about 100KB. - * The zstd CLI defaults to a 110KB dictionary. You likely don't need a - * dictionary larger than that. But, most use cases can get away with a - * smaller dictionary. The advanced dictionary builders can automatically - * shrink the dictionary for you, and select the smallest size that doesn't - * hurt compression ratio too much. See the `shrinkDict` parameter. - * A smaller dictionary can save memory, and potentially speed up - * compression. - * - * How many samples should I provide to the dictionary builder? - * ------------------------------------------------------------ - * - * We generally recommend passing ~100x the size of the dictionary - * in samples. A few thousand should suffice. Having too few samples - * can hurt the dictionaries effectiveness. Having more samples will - * only improve the dictionaries effectiveness. But having too many - * samples can slow down the dictionary builder. - * - * How do I determine if a dictionary will be effective? - * ----------------------------------------------------- - * - * Simply train a dictionary and try it out. You can use zstd's built in - * benchmarking tool to test the dictionary effectiveness. - * - * # Benchmark levels 1-3 without a dictionary - * zstd -b1e3 -r /path/to/my/files - * # Benchmark levels 1-3 with a dictionary - * zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary - * - * When should I retrain a dictionary? - * ----------------------------------- - * - * You should retrain a dictionary when its effectiveness drops. Dictionary - * effectiveness drops as the data you are compressing changes. Generally, we do - * expect dictionaries to "decay" over time, as your data changes, but the rate - * at which they decay depends on your use case. Internally, we regularly - * retrain dictionaries, and if the new dictionary performs significantly - * better than the old dictionary, we will ship the new dictionary. - * - * I have a raw content dictionary, how do I turn it into a zstd dictionary? - * ------------------------------------------------------------------------- - * - * If you have a raw content dictionary, e.g. by manually constructing it, or - * using a third-party dictionary builder, you can turn it into a zstd - * dictionary by using `ZDICT_finalizeDictionary()`. You'll also have to - * provide some samples of the data. It will add the zstd header to the - * raw content, which contains a dictionary ID and entropy tables, which - * will improve compression ratio, and allow zstd to write the dictionary ID - * into the frame, if you so choose. - * - * Do I have to use zstd's dictionary builder? - * ------------------------------------------- - * - * No! You can construct dictionary content however you please, it is just - * bytes. It will always be valid as a raw content dictionary. If you want - * a zstd dictionary, which can improve compression ratio, use - * `ZDICT_finalizeDictionary()`. - * - * What is the attack surface of a zstd dictionary? - * ------------------------------------------------ - * - * Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so - * zstd should never crash, or access out-of-bounds memory no matter what - * the dictionary is. However, if an attacker can control the dictionary - * during decompression, they can cause zstd to generate arbitrary bytes, - * just like if they controlled the compressed data. - * - ******************************************************************************/ - - -/*! ZDICT_trainFromBuffer(): - * Train a dictionary from an array of samples. - * Redirect towards ZDICT_optimizeTrainFromBuffer_fastCover() single-threaded, with d=8, steps=4, - * f=20, and accel=1. - * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. - * The resulting dictionary will be saved into `dictBuffer`. - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * Note: Dictionary training will fail if there are not enough samples to construct a - * dictionary, or if most of the samples are too small (< 8 bytes being the lower limit). - * If dictionary training fails, you should use zstd without a dictionary, as the dictionary - * would've been ineffective anyways. If you believe your samples would benefit from a dictionary - * please open an issue with details, and we can look into it. - * Note: ZDICT_trainFromBuffer()'s memory usage is about 6 MB. - * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. - * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. - * In general, it's recommended to provide a few thousands samples, though this can vary a lot. - * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. - */ -ZDICTLIB_API size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples); - -typedef struct { - int compressionLevel; /**< optimize for a specific zstd compression level; 0 means default */ - unsigned notificationLevel; /**< Write log to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ - unsigned dictID; /**< force dictID value; 0 means auto mode (32-bits random value) - * NOTE: The zstd format reserves some dictionary IDs for future use. - * You may use them in private settings, but be warned that they - * may be used by zstd in a public dictionary registry in the future. - * These dictionary IDs are: - * - low range : <= 32767 - * - high range : >= (2^31) - */ -} ZDICT_params_t; - -/*! ZDICT_finalizeDictionary(): - * Given a custom content as a basis for dictionary, and a set of samples, - * finalize dictionary by adding headers and statistics according to the zstd - * dictionary format. - * - * Samples must be stored concatenated in a flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each - * sample in order. The samples are used to construct the statistics, so they - * should be representative of what you will compress with this dictionary. - * - * The compression level can be set in `parameters`. You should pass the - * compression level you expect to use in production. The statistics for each - * compression level differ, so tuning the dictionary for the compression level - * can help quite a bit. - * - * You can set an explicit dictionary ID in `parameters`, or allow us to pick - * a random dictionary ID for you, but we can't guarantee no collisions. - * - * The dstDictBuffer and the dictContent may overlap, and the content will be - * appended to the end of the header. If the header + the content doesn't fit in - * maxDictSize the beginning of the content is truncated to make room, since it - * is presumed that the most profitable content is at the end of the dictionary, - * since that is the cheapest to reference. - * - * `maxDictSize` must be >= max(dictContentSize, ZSTD_DICTSIZE_MIN). - * - * @return: size of dictionary stored into `dstDictBuffer` (<= `maxDictSize`), - * or an error code, which can be tested by ZDICT_isError(). - * Note: ZDICT_finalizeDictionary() will push notifications into stderr if - * instructed to, using notificationLevel>0. - * NOTE: This function currently may fail in several edge cases including: - * * Not enough samples - * * Samples are uncompressible - * * Samples are all exactly the same - */ -ZDICTLIB_API size_t ZDICT_finalizeDictionary(void* dstDictBuffer, size_t maxDictSize, - const void* dictContent, size_t dictContentSize, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_params_t parameters); - - -/*====== Helper functions ======*/ -ZDICTLIB_API unsigned ZDICT_getDictID(const void* dictBuffer, size_t dictSize); /**< extracts dictID; @return zero if error (not a valid dictionary) */ -ZDICTLIB_API size_t ZDICT_getDictHeaderSize(const void* dictBuffer, size_t dictSize); /* returns dict header size; returns a ZSTD error code on failure */ -ZDICTLIB_API unsigned ZDICT_isError(size_t errorCode); -ZDICTLIB_API const char* ZDICT_getErrorName(size_t errorCode); - -} // namespace duckdb_zstd - -#endif /* ZSTD_ZDICT_H */ - -#if defined(ZDICT_STATIC_LINKING_ONLY) && !defined(ZSTD_ZDICT_H_STATIC) -#define ZSTD_ZDICT_H_STATIC - -namespace duckdb_zstd { - -/* This can be overridden externally to hide static symbols. */ -#ifndef ZDICTLIB_STATIC_API -# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZDICTLIB_STATIC_API __declspec(dllexport) ZDICTLIB_VISIBLE -# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZDICTLIB_STATIC_API __declspec(dllimport) ZDICTLIB_VISIBLE -# else -# define ZDICTLIB_STATIC_API ZDICTLIB_VISIBLE -# endif -#endif - -/* ==================================================================================== - * The definitions in this section are considered experimental. - * They should never be used with a dynamic library, as they may change in the future. - * They are provided for advanced usages. - * Use them only in association with static linking. - * ==================================================================================== */ - -#define ZDICT_DICTSIZE_MIN 256 -/* Deprecated: Remove in v1.6.0 */ -#define ZDICT_CONTENTSIZE_MIN 128 - -/*! ZDICT_cover_params_t: - * k and d are the only required parameters. - * For others, value 0 means default. - */ -typedef struct { - unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ - unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ - unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ - unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ - double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (1.0), 1.0 when all samples are used for both training and testing */ - unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ - unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ - ZDICT_params_t zParams; -} ZDICT_cover_params_t; - -typedef struct { - unsigned k; /* Segment size : constraint: 0 < k : Reasonable range [16, 2048+] */ - unsigned d; /* dmer size : constraint: 0 < d <= k : Reasonable range [6, 16] */ - unsigned f; /* log of size of frequency array : constraint: 0 < f <= 31 : 1 means default(20)*/ - unsigned steps; /* Number of steps : Only used for optimization : 0 means default (40) : Higher means more parameters checked */ - unsigned nbThreads; /* Number of threads : constraint: 0 < nbThreads : 1 means single-threaded : Only used for optimization : Ignored if ZSTD_MULTITHREAD is not defined */ - double splitPoint; /* Percentage of samples used for training: Only used for optimization : the first nbSamples * splitPoint samples will be used to training, the last nbSamples * (1 - splitPoint) samples will be used for testing, 0 means default (0.75), 1.0 when all samples are used for both training and testing */ - unsigned accel; /* Acceleration level: constraint: 0 < accel <= 10, higher means faster and less accurate, 0 means default(1) */ - unsigned shrinkDict; /* Train dictionaries to shrink in size starting from the minimum size and selects the smallest dictionary that is shrinkDictMaxRegression% worse than the largest dictionary. 0 means no shrinking and 1 means shrinking */ - unsigned shrinkDictMaxRegression; /* Sets shrinkDictMaxRegression so that a smaller dictionary can be at worse shrinkDictMaxRegression% worse than the max dict size dictionary. */ - - ZDICT_params_t zParams; -} ZDICT_fastCover_params_t; - -/*! ZDICT_trainFromBuffer_cover(): - * Train a dictionary from an array of samples using the COVER algorithm. - * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. - * The resulting dictionary will be saved into `dictBuffer`. - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * See ZDICT_trainFromBuffer() for details on failure modes. - * Note: ZDICT_trainFromBuffer_cover() requires about 9 bytes of memory for each input byte. - * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. - * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. - * In general, it's recommended to provide a few thousands samples, though this can vary a lot. - * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. - */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_cover( - void *dictBuffer, size_t dictBufferCapacity, - const void *samplesBuffer, const size_t *samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t parameters); - -/*! ZDICT_optimizeTrainFromBuffer_cover(): - * The same requirements as above hold for all the parameters except `parameters`. - * This function tries many parameter combinations and picks the best parameters. - * `*parameters` is filled with the best parameters found, - * dictionary constructed with those parameters is stored in `dictBuffer`. - * - * All of the parameters d, k, steps are optional. - * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. - * if steps is zero it defaults to its default value. - * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. - * - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * On success `*parameters` contains the parameters selected. - * See ZDICT_trainFromBuffer() for details on failure modes. - * Note: ZDICT_optimizeTrainFromBuffer_cover() requires about 8 bytes of memory for each input byte and additionally another 5 bytes of memory for each byte of memory for each thread. - */ -ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_cover( - void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_cover_params_t* parameters); - -/*! ZDICT_trainFromBuffer_fastCover(): - * Train a dictionary from an array of samples using a modified version of COVER algorithm. - * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. - * d and k are required. - * All other parameters are optional, will use default values if not provided - * The resulting dictionary will be saved into `dictBuffer`. - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * See ZDICT_trainFromBuffer() for details on failure modes. - * Note: ZDICT_trainFromBuffer_fastCover() requires 6 * 2^f bytes of memory. - * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. - * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. - * In general, it's recommended to provide a few thousands samples, though this can vary a lot. - * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. - */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_fastCover(void *dictBuffer, - size_t dictBufferCapacity, const void *samplesBuffer, - const size_t *samplesSizes, unsigned nbSamples, - ZDICT_fastCover_params_t parameters); - -/*! ZDICT_optimizeTrainFromBuffer_fastCover(): - * The same requirements as above hold for all the parameters except `parameters`. - * This function tries many parameter combinations (specifically, k and d combinations) - * and picks the best parameters. `*parameters` is filled with the best parameters found, - * dictionary constructed with those parameters is stored in `dictBuffer`. - * All of the parameters d, k, steps, f, and accel are optional. - * If d is non-zero then we don't check multiple values of d, otherwise we check d = {6, 8}. - * if steps is zero it defaults to its default value. - * If k is non-zero then we don't check multiple values of k, otherwise we check steps values in [50, 2000]. - * If f is zero, default value of 20 is used. - * If accel is zero, default value of 1 is used. - * - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * On success `*parameters` contains the parameters selected. - * See ZDICT_trainFromBuffer() for details on failure modes. - * Note: ZDICT_optimizeTrainFromBuffer_fastCover() requires about 6 * 2^f bytes of memory for each thread. - */ -ZDICTLIB_STATIC_API size_t ZDICT_optimizeTrainFromBuffer_fastCover(void* dictBuffer, - size_t dictBufferCapacity, const void* samplesBuffer, - const size_t* samplesSizes, unsigned nbSamples, - ZDICT_fastCover_params_t* parameters); - -typedef struct { - unsigned selectivityLevel; /* 0 means default; larger => select more => larger dictionary */ - ZDICT_params_t zParams; -} ZDICT_legacy_params_t; - -/*! ZDICT_trainFromBuffer_legacy(): - * Train a dictionary from an array of samples. - * Samples must be stored concatenated in a single flat buffer `samplesBuffer`, - * supplied with an array of sizes `samplesSizes`, providing the size of each sample, in order. - * The resulting dictionary will be saved into `dictBuffer`. - * `parameters` is optional and can be provided with values set to 0 to mean "default". - * @return: size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - * or an error code, which can be tested with ZDICT_isError(). - * See ZDICT_trainFromBuffer() for details on failure modes. - * Tips: In general, a reasonable dictionary has a size of ~ 100 KB. - * It's possible to select smaller or larger size, just by specifying `dictBufferCapacity`. - * In general, it's recommended to provide a few thousands samples, though this can vary a lot. - * It's recommended that total size of all samples be about ~x100 times the target size of dictionary. - * Note: ZDICT_trainFromBuffer_legacy() will send notifications into stderr if instructed to, using notificationLevel>0. - */ -ZDICTLIB_STATIC_API size_t ZDICT_trainFromBuffer_legacy( - void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_legacy_params_t parameters); - - -/* Deprecation warnings */ -/* It is generally possible to disable deprecation warnings from compiler, - for example with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual. - Otherwise, it's also possible to manually define ZDICT_DISABLE_DEPRECATE_WARNINGS */ -#ifdef ZDICT_DISABLE_DEPRECATE_WARNINGS -# define ZDICT_DEPRECATED(message) /* disable deprecation warnings */ -#else -# define ZDICT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ -# define ZDICT_DEPRECATED(message) [[deprecated(message)]] -# elif defined(__clang__) || (ZDICT_GCC_VERSION >= 405) -# define ZDICT_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (ZDICT_GCC_VERSION >= 301) -# define ZDICT_DEPRECATED(message) __attribute__((deprecated)) -# elif defined(_MSC_VER) -# define ZDICT_DEPRECATED(message) __declspec(deprecated(message)) -# else -# pragma message("WARNING: You need to implement ZDICT_DEPRECATED for this compiler") -# define ZDICT_DEPRECATED(message) -# endif -#endif /* ZDICT_DISABLE_DEPRECATE_WARNINGS */ - -ZDICT_DEPRECATED("use ZDICT_finalizeDictionary() instead") -ZDICTLIB_STATIC_API -size_t ZDICT_addEntropyTablesFromBuffer(void* dictBuffer, size_t dictContentSize, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); - -} // namespace duckdb_zstd - -#endif /* ZSTD_ZDICT_H_STATIC */ diff --git a/src/duckdb/third_party/zstd/include/zstd.h b/src/duckdb/third_party/zstd/include/zstd.h index 8b40c366e..ade94c2d5 100644 --- a/src/duckdb/third_party/zstd/include/zstd.h +++ b/src/duckdb/third_party/zstd/include/zstd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -7,71 +7,31 @@ * in the COPYING file in the root directory of this source tree). * You may select, at your option, one of the above-listed licenses. */ - #ifndef ZSTD_H_235446 #define ZSTD_H_235446 -// DuckDB: just enable everything for amalgamation -#ifdef DUCKDB_AMALGAMATION -#define ZSTD_STATIC_LINKING_ONLY -#endif - -/* ====== Dependencies ======*/ +/* ====== Dependency ======*/ #include /* INT_MAX */ #include /* size_t */ -namespace duckdb_zstd { /* ===== ZSTDLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZSTDLIB_VISIBILITY -# define ZSTDLIB_VISIBLE ZSTDLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDLIB_VISIBLE __attribute__ ((visibility ("default"))) -# else -# define ZSTDLIB_VISIBLE -# endif -#endif - -#ifndef ZSTDLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +#ifndef ZSTDLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else -# define ZSTDLIB_HIDDEN +# define ZSTDLIB_VISIBILITY # endif #endif - #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBLE +# define ZSTDLIB_API __declspec(dllexport) ZSTDLIB_VISIBILITY #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDLIB_API __declspec(dllimport) ZSTDLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDLIB_API ZSTDLIB_VISIBLE +# define ZSTDLIB_API ZSTDLIB_VISIBILITY #endif -/* Deprecation warnings : - * Should these warnings be a problem, it is generally possible to disable them, - * typically with -Wno-deprecated-declarations for gcc or _CRT_SECURE_NO_WARNINGS in Visual. - * Otherwise, it's also possible to define ZSTD_DISABLE_DEPRECATE_WARNINGS. - */ -#ifdef ZSTD_DISABLE_DEPRECATE_WARNINGS -# define ZSTD_DEPRECATED(message) /* disable deprecation warnings */ -#else -# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ -# define ZSTD_DEPRECATED(message) [[deprecated(message)]] -# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) -# define ZSTD_DEPRECATED(message) __attribute__((deprecated(message))) -# elif defined(__GNUC__) && (__GNUC__ >= 3) -# define ZSTD_DEPRECATED(message) __attribute__((deprecated)) -# elif defined(_MSC_VER) -# define ZSTD_DEPRECATED(message) __declspec(deprecated(message)) -# else -# pragma message("WARNING: You need to implement ZSTD_DEPRECATED for this compiler") -# define ZSTD_DEPRECATED(message) -# endif -#endif /* ZSTD_DISABLE_DEPRECATE_WARNINGS */ - +namespace duckdb_zstd { /******************************************************************************* Introduction @@ -108,22 +68,17 @@ namespace duckdb_zstd { /*------ Version ------*/ #define ZSTD_VERSION_MAJOR 1 -#define ZSTD_VERSION_MINOR 5 -#define ZSTD_VERSION_RELEASE 6 -#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) +#define ZSTD_VERSION_MINOR 4 +#define ZSTD_VERSION_RELEASE 5 -/*! ZSTD_versionNumber() : - * Return runtime library version, the value is (MAJOR*100*100 + MINOR*100 + RELEASE). */ -ZSTDLIB_API unsigned ZSTD_versionNumber(void); +#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) +ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */ #define ZSTD_LIB_VERSION ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE #define ZSTD_QUOTE(str) #str #define ZSTD_EXPAND_AND_QUOTE(str) ZSTD_QUOTE(str) #define ZSTD_VERSION_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_LIB_VERSION) - -/*! ZSTD_versionString() : - * Return runtime library version, like "1.4.5". Requires v1.3.0+. */ -ZSTDLIB_API const char* ZSTD_versionString(void); +ZSTDLIB_API const char* ZSTD_versionString(void); /* requires v1.3.0+ */ /* ************************************* * Default constant @@ -146,13 +101,13 @@ ZSTDLIB_API const char* ZSTD_versionString(void); #define ZSTD_BLOCKSIZE_MAX (1<= ZSTD_compressBound(srcSize)` guarantees that zstd will have - * enough space to successfully compress the data. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ ZSTDLIB_API size_t ZSTD_compress( void* dst, size_t dstCapacity, @@ -201,11 +156,9 @@ ZSTDLIB_API unsigned long long ZSTD_getFrameContentSize(const void *src, size_t * "empty", "unknown" and "error" results to the same return value (0), * while ZSTD_getFrameContentSize() gives them separate return values. * @return : decompressed size of `src` frame content _if known and not empty_, 0 otherwise. */ -ZSTD_DEPRECATED("Replaced by ZSTD_getFrameContentSize") -ZSTDLIB_API -unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); +ZSTDLIB_API unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize); -/*! ZSTD_findFrameCompressedSize() : Requires v1.4.0+ +/*! ZSTD_findFrameCompressedSize() : * `src` should point to the start of a ZSTD frame or skippable frame. * `srcSize` must be >= first frame size * @return : the compressed size of the first frame starting at `src`, @@ -215,35 +168,12 @@ ZSTDLIB_API size_t ZSTD_findFrameCompressedSize(const void* src, size_t srcSize) /*====== Helper functions ======*/ -/* ZSTD_compressBound() : - * maximum compressed size in worst case single-pass scenario. - * When invoking `ZSTD_compress()` or any other one-pass compression function, - * it's recommended to provide @dstCapacity >= ZSTD_compressBound(srcSize) - * as it eliminates one potential failure scenario, - * aka not enough room in dst buffer to write the compressed frame. - * Note : ZSTD_compressBound() itself can fail, if @srcSize > ZSTD_MAX_INPUT_SIZE . - * In which case, ZSTD_compressBound() will return an error code - * which can be tested using ZSTD_isError(). - * - * ZSTD_COMPRESSBOUND() : - * same as ZSTD_compressBound(), but as a macro. - * It can be used to produce constants, which can be useful for static allocation, - * for example to size a static array on stack. - * Will produce constant value 0 if srcSize too large. - */ -#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00ULL : 0xFF00FF00U) -#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ -ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ -/* ZSTD_isError() : - * Most ZSTD_* functions returning a size_t value can be tested for error, - * using ZSTD_isError(). - * @return 1 if error, 0 otherwise - */ +#define ZSTD_COMPRESSBOUND(srcSize) ((srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) /* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */ +ZSTDLIB_API size_t ZSTD_compressBound(size_t srcSize); /*!< maximum compressed size in worst case single-pass scenario */ ZSTDLIB_API unsigned ZSTD_isError(size_t code); /*!< tells if a `size_t` function result is an error code */ ZSTDLIB_API const char* ZSTD_getErrorName(size_t code); /*!< provides readable string from an error code */ -ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed, requires v1.4.0+ */ +ZSTDLIB_API int ZSTD_minCLevel(void); /*!< minimum negative compression level allowed */ ZSTDLIB_API int ZSTD_maxCLevel(void); /*!< maximum compression level available */ -ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compression level, specified by ZSTD_CLEVEL_DEFAULT, requires v1.5.0+ */ /*************************************** @@ -252,7 +182,7 @@ ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compres /*= Compression context * When compressing many times, * it is recommended to allocate a context just once, - * and reuse it for each successive compression operation. + * and re-use it for each successive compression operation. * This will make workload friendlier for system's memory. * Note : re-using context is just a speed / resource optimization. * It doesn't change the compression ratio, which remains identical. @@ -261,13 +191,13 @@ ZSTDLIB_API int ZSTD_defaultCLevel(void); /*!< default compres */ typedef struct ZSTD_CCtx_s ZSTD_CCtx; ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx(void); -ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx); /*! ZSTD_compressCCtx() : * Same as ZSTD_compress(), using an explicit ZSTD_CCtx. - * Important : in order to mirror `ZSTD_compress()` behavior, - * this function compresses at the requested compression level, - * __ignoring any other advanced parameter__ . + * Important : in order to behave similarly to `ZSTD_compress()`, + * this function compresses at requested compression level, + * __ignoring any other parameter__ . * If any advanced parameter was set using the advanced API, * they will all be reset. Only `compressionLevel` remains. */ @@ -279,38 +209,38 @@ ZSTDLIB_API size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, /*= Decompression context * When decompressing many times, * it is recommended to allocate a context only once, - * and reuse it for each successive compression operation. + * and re-use it for each successive compression operation. * This will make workload friendlier for system's memory. * Use one context per thread for parallel execution. */ typedef struct ZSTD_DCtx_s ZSTD_DCtx; ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx(void); -ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); /*! ZSTD_decompressDCtx() : * Same as ZSTD_decompress(), * requires an allocated ZSTD_DCtx. - * Compatible with sticky parameters (see below). + * Compatible with sticky parameters. */ ZSTDLIB_API size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/********************************************* -* Advanced compression API (Requires v1.4.0+) -**********************************************/ +/*************************************** +* Advanced compression API +***************************************/ /* API design : * Parameters are pushed one by one into an existing context, * using ZSTD_CCtx_set*() functions. * Pushed parameters are sticky : they are valid for next compressed frame, and any subsequent frame. * "sticky" parameters are applicable to `ZSTD_compress2()` and `ZSTD_compressStream*()` ! - * __They do not apply to one-shot variants such as ZSTD_compressCCtx()__ . + * __They do not apply to "simple" one-shot variants such as ZSTD_compressCCtx()__ . * * It's possible to reset all parameters to "default" using ZSTD_CCtx_reset(). * - * This API supersedes all other "advanced" API entry points in the experimental section. - * In the future, we expect to remove API entry points from experimental which are redundant with this API. + * This API supercedes all other "advanced" API entry points in the experimental section. + * In the future, we expect to remove from experimental API entry points which are redundant with this API. */ @@ -328,6 +258,7 @@ typedef enum { ZSTD_fast=1, Only the order (from fast to strong) is guaranteed */ } ZSTD_strategy; + typedef enum { /* compression parameters @@ -394,27 +325,13 @@ typedef enum { * resulting in stronger and slower compression. * Special: value 0 means "use default strategy". */ - ZSTD_c_targetCBlockSize=130, /* v1.5.6+ - * Attempts to fit compressed block size into approximatively targetCBlockSize. - * Bound by ZSTD_TARGETCBLOCKSIZE_MIN and ZSTD_TARGETCBLOCKSIZE_MAX. - * Note that it's not a guarantee, just a convergence target (default:0). - * No target when targetCBlockSize == 0. - * This is helpful in low bandwidth streaming environments to improve end-to-end latency, - * when a client can make use of partial documents (a prominent example being Chrome). - * Note: this parameter is stable since v1.5.6. - * It was present as an experimental parameter in earlier versions, - * but it's not recommended using it with earlier library versions - * due to massive performance regressions. - */ /* LDM mode parameters */ ZSTD_c_enableLongDistanceMatching=160, /* Enable long distance matching. * This parameter is designed to improve compression ratio * for large inputs, by finding large matches at long distance. * It increases memory usage and window size. * Note: enabling this parameter increases default ZSTD_c_windowLog to 128 MB - * except when expressly set to a different value. - * Note: will be enabled by default if ZSTD_c_windowLog >= 128 MB and - * compression strategy >= ZSTD_btopt (== compression level 16+) */ + * except when expressly set to a different value. */ ZSTD_c_ldmHashLog=161, /* Size of the table for long distance matching, as a power of 2. * Larger values increase memory usage and compression ratio, * but decrease compression speed. @@ -445,24 +362,20 @@ typedef enum { ZSTD_c_dictIDFlag=202, /* When applicable, dictionary's ID is written into frame header (default:1) */ /* multi-threading parameters */ - /* These parameters are only active if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). - * Otherwise, trying to set any other value than default (0) will be a no-op and return an error. - * In a situation where it's unknown if the linked library supports multi-threading or not, - * setting ZSTD_c_nbWorkers to any value >= 1 and consulting the return value provides a quick way to check this property. - */ + /* These parameters are only useful if multi-threading is enabled (compiled with build macro ZSTD_MULTITHREAD). + * They return an error otherwise. */ ZSTD_c_nbWorkers=400, /* Select how many threads will be spawned to compress in parallel. - * When nbWorkers >= 1, triggers asynchronous mode when invoking ZSTD_compressStream*() : + * When nbWorkers >= 1, triggers asynchronous mode when used with ZSTD_compressStream*() : * ZSTD_compressStream*() consumes input and flush output if possible, but immediately gives back control to caller, - * while compression is performed in parallel, within worker thread(s). + * while compression work is performed in parallel, within worker threads. * (note : a strong exception to this rule is when first invocation of ZSTD_compressStream2() sets ZSTD_e_end : * in which case, ZSTD_compressStream2() delegates to ZSTD_compress2(), which is always a blocking call). * More workers improve speed, but also increase memory usage. - * Default value is `0`, aka "single-threaded mode" : no worker is spawned, - * compression is performed inside Caller's thread, and all invocations are blocking */ + * Default value is `0`, aka "single-threaded mode" : no worker is spawned, compression is performed inside Caller's thread, all invocations are blocking */ ZSTD_c_jobSize=401, /* Size of a compression job. This value is enforced only when nbWorkers >= 1. * Each compression job is completed in parallel, so this value can indirectly impact the nb of active threads. * 0 means default, which is dynamically determined based on compression parameters. - * Job size must be a minimum of overlap size, or ZSTDMT_JOBSIZE_MIN (= 512 KB), whichever is largest. + * Job size must be a minimum of overlap size, or 1 MB, whichever is largest. * The minimum size is automatically and transparently enforced. */ ZSTD_c_overlapLog=402, /* Control the overlap size, as a fraction of window size. * The overlap size is an amount of data reloaded from previous job at the beginning of a new job. @@ -485,17 +398,8 @@ typedef enum { * ZSTD_c_forceMaxWindow * ZSTD_c_forceAttachDict * ZSTD_c_literalCompressionMode + * ZSTD_c_targetCBlockSize * ZSTD_c_srcSizeHint - * ZSTD_c_enableDedicatedDictSearch - * ZSTD_c_stableInBuffer - * ZSTD_c_stableOutBuffer - * ZSTD_c_blockDelimiters - * ZSTD_c_validateSequences - * ZSTD_c_useBlockSplitter - * ZSTD_c_useRowMatchFinder - * ZSTD_c_prefetchCDictTables - * ZSTD_c_enableSeqProducerFallback - * ZSTD_c_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; * also, the enums values themselves are unstable and can still change. @@ -505,20 +409,8 @@ typedef enum { ZSTD_c_experimentalParam3=1000, ZSTD_c_experimentalParam4=1001, ZSTD_c_experimentalParam5=1002, - /* was ZSTD_c_experimentalParam6=1003; is now ZSTD_c_targetCBlockSize */ - ZSTD_c_experimentalParam7=1004, - ZSTD_c_experimentalParam8=1005, - ZSTD_c_experimentalParam9=1006, - ZSTD_c_experimentalParam10=1007, - ZSTD_c_experimentalParam11=1008, - ZSTD_c_experimentalParam12=1009, - ZSTD_c_experimentalParam13=1010, - ZSTD_c_experimentalParam14=1011, - ZSTD_c_experimentalParam15=1012, - ZSTD_c_experimentalParam16=1013, - ZSTD_c_experimentalParam17=1014, - ZSTD_c_experimentalParam18=1015, - ZSTD_c_experimentalParam19=1016 + ZSTD_c_experimentalParam6=1003, + ZSTD_c_experimentalParam7=1004 } ZSTD_cParameter; typedef struct { @@ -581,7 +473,7 @@ typedef enum { * They will be used to compress next frame. * Resetting session never fails. * - The parameters : changes all parameters back to "default". - * This also removes any reference to any dictionary or external sequence producer. + * This removes any reference to any dictionary too. * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) * - Both : similar to resetting the session, followed by resetting parameters. @@ -590,13 +482,11 @@ ZSTDLIB_API size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset); /*! ZSTD_compress2() : * Behave the same as ZSTD_compressCCtx(), but compression parameters are set using the advanced API. - * (note that this entry point doesn't even expose a compression level parameter). * ZSTD_compress2() always starts a new frame. * Should cctx hold data from a previously unfinished frame, everything about it is forgotten. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - The function is always blocking, returns when compression is completed. - * NOTE: Providing `dstCapacity >= ZSTD_compressBound(srcSize)` guarantees that zstd will have - * enough space to successfully compress the data, though it is possible it fails for other reasons. + * Hint : compression runs faster if `dstCapacity` >= `ZSTD_compressBound(srcSize)`. * @return : compressed size written into `dst` (<= `dstCapacity), * or an error code if it fails (which can be tested using ZSTD_isError()). */ @@ -605,9 +495,9 @@ ZSTDLIB_API size_t ZSTD_compress2( ZSTD_CCtx* cctx, const void* src, size_t srcSize); -/*********************************************** -* Advanced decompression API (Requires v1.4.0+) -************************************************/ +/*************************************** +* Advanced decompression API +***************************************/ /* The advanced API pushes parameters one by one into an existing DCtx context. * Parameters are sticky, and remain valid for all following frames @@ -631,19 +521,11 @@ typedef enum { * At the time of this writing, they include : * ZSTD_d_format * ZSTD_d_stableOutBuffer - * ZSTD_d_forceIgnoreChecksum - * ZSTD_d_refMultipleDDicts - * ZSTD_d_disableHuffmanAssembly - * ZSTD_d_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly */ ZSTD_d_experimentalParam1=1000, - ZSTD_d_experimentalParam2=1001, - ZSTD_d_experimentalParam3=1002, - ZSTD_d_experimentalParam4=1003, - ZSTD_d_experimentalParam5=1004, - ZSTD_d_experimentalParam6=1005 + ZSTD_d_experimentalParam2=1001 } ZSTD_dParameter; @@ -698,14 +580,14 @@ typedef struct ZSTD_outBuffer_s { * A ZSTD_CStream object is required to track streaming operation. * Use ZSTD_createCStream() and ZSTD_freeCStream() to create/release resources. * ZSTD_CStream objects can be reused multiple times on consecutive compression operations. -* It is recommended to reuse ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. +* It is recommended to re-use ZSTD_CStream since it will play nicer with system's memory, by re-using already allocated memory. * * For parallel execution, use one separate ZSTD_CStream per thread. * * note : since v1.3.0, ZSTD_CStream and ZSTD_CCtx are the same thing. * * Parameters are sticky : when starting a new compression on the same context, -* it will reuse the same sticky parameters as previous compression session. +* it will re-use the same sticky parameters as previous compression session. * When in doubt, it's recommended to fully initialize the context before usage. * Use ZSTD_CCtx_reset() to reset the context and ZSTD_CCtx_setParameter(), * ZSTD_CCtx_setPledgedSrcSize(), or ZSTD_CCtx_loadDictionary() and friends to @@ -757,7 +639,7 @@ typedef ZSTD_CCtx ZSTD_CStream; /**< CCtx and CStream are now effectively same /* Continue to distinguish them for compatibility with older versions <= v1.2.0 */ /*===== ZSTD_CStream management functions =====*/ ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream(void); -ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeCStream(ZSTD_CStream* zcs); /*===== Streaming compression functions =====*/ typedef enum { @@ -773,15 +655,14 @@ typedef enum { : note : multithreaded compression will block to flush as much output as possible. */ } ZSTD_EndDirective; -/*! ZSTD_compressStream2() : Requires v1.4.0+ +/*! ZSTD_compressStream2() : * Behaves about the same as ZSTD_compressStream, with additional control on end directive. * - Compression parameters are pushed into CCtx before starting compression, using ZSTD_CCtx_set*() * - Compression parameters cannot be changed once compression is started (save a list of exceptions in multi-threading mode) * - output->pos must be <= dstCapacity, input->pos must be <= srcSize * - output->pos and input->pos will be updated. They are guaranteed to remain below their respective limit. - * - endOp must be a valid directive * - When nbWorkers==0 (default), function is blocking : it completes its job before returning to caller. - * - When nbWorkers>=1, function is non-blocking : it copies a portion of input, distributes jobs to internal worker threads, flush to output whatever is available, + * - When nbWorkers>=1, function is non-blocking : it just acquires a copy of input, and distributes jobs to internal worker threads, flush whatever is available, * and then immediately returns, just indicating that there is some data remaining to be flushed. * The function nonetheless guarantees forward progress : it will return only after it reads or write at least 1+ byte. * - Exception : if the first call requests a ZSTD_e_end directive and provides enough dstCapacity, the function delegates to ZSTD_compress2() which is always blocking. @@ -794,11 +675,6 @@ typedef enum { * only ZSTD_e_end or ZSTD_e_flush operations are allowed. * Before starting a new compression job, or changing compression parameters, * it is required to fully flush internal buffers. - * - note: if an operation ends with an error, it may leave @cctx in an undefined state. - * Therefore, it's UB to invoke ZSTD_compressStream2() of ZSTD_compressStream() on such a state. - * In order to be re-employed after an error, a state must be reset, - * which can be done explicitly (ZSTD_CCtx_reset()), - * or is sometimes implied by methods starting a new compression job (ZSTD_initCStream(), ZSTD_compressCCtx()) */ ZSTDLIB_API size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, ZSTD_outBuffer* output, @@ -824,9 +700,11 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output /* ***************************************************************************** - * This following is a legacy streaming API, available since v1.0+ . + * This following is a legacy streaming API. * It can be replaced by ZSTD_CCtx_reset() and ZSTD_compressStream2(). * It is redundant, but remains fully supported. + * Advanced parameters and dictionary compression can only be used through the + * new API. ******************************************************************************/ /*! @@ -835,9 +713,6 @@ ZSTDLIB_API size_t ZSTD_CStreamOutSize(void); /**< recommended size for output * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * - * Note that ZSTD_initCStream() clears any previously set dictionary. Use the new API - * to compress with a dictionary. */ ZSTDLIB_API size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel); /*! @@ -858,7 +733,7 @@ ZSTDLIB_API size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output); * * A ZSTD_DStream object is required to track streaming operations. * Use ZSTD_createDStream() and ZSTD_freeDStream() to create/release resources. -* ZSTD_DStream objects can be reused multiple times. +* ZSTD_DStream objects can be re-used multiple times. * * Use ZSTD_initDStream() to start a new decompression operation. * @return : recommended first input size @@ -884,41 +759,17 @@ typedef ZSTD_DCtx ZSTD_DStream; /**< DCtx and DStream are now effectively same /* For compatibility with versions <= v1.2.0, prefer differentiating them. */ /*===== ZSTD_DStream management functions =====*/ ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream(void); -ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /* accept NULL pointer */ +ZSTDLIB_API size_t ZSTD_freeDStream(ZSTD_DStream* zds); /*===== Streaming decompression functions =====*/ -/*! ZSTD_initDStream() : - * Initialize/reset DStream state for new decompression operation. - * Call before new decompression operation using same DStream. +/* This function is redundant with the advanced API and equivalent to: * - * Note : This function is redundant with the advanced API and equivalent to: * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); * ZSTD_DCtx_refDDict(zds, NULL); */ ZSTDLIB_API size_t ZSTD_initDStream(ZSTD_DStream* zds); -/*! ZSTD_decompressStream() : - * Streaming decompression function. - * Call repetitively to consume full input updating it as necessary. - * Function will update both input and output `pos` fields exposing current state via these fields: - * - `input.pos < input.size`, some input remaining and caller should provide remaining input - * on the next call. - * - `output.pos < output.size`, decoder finished and flushed all remaining buffers. - * - `output.pos == output.size`, potentially uncflushed data present in the internal buffers, - * call ZSTD_decompressStream() again to flush remaining data to output. - * Note : with no additional input, amount of data flushed <= ZSTD_BLOCKSIZE_MAX. - * - * @return : 0 when a frame is completely decoded and fully flushed, - * or an error code, which can be tested using ZSTD_isError(), - * or any other value > 0, which means there is some decoding or flushing to do to complete current frame. - * - * Note: when an operation returns with an error code, the @zds state may be left in undefined state. - * It's UB to invoke `ZSTD_decompressStream()` on such a state. - * In order to re-use such a state, it must be first reset, - * which can be done explicitly (`ZSTD_DCtx_reset()`), - * or is implied for operations starting some new decompression job (`ZSTD_initDStream`, `ZSTD_decompressDCtx()`, `ZSTD_decompress_usingDict()`) - */ ZSTDLIB_API size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input); ZSTDLIB_API size_t ZSTD_DStreamInSize(void); /*!< recommended size for input buffer */ @@ -931,7 +782,7 @@ ZSTDLIB_API size_t ZSTD_DStreamOutSize(void); /*!< recommended size for output /*! ZSTD_compress_usingDict() : * Compression at an explicit compression level using a Dictionary. * A dictionary can be any arbitrary data segment (also called a prefix), - * or a buffer with specified information (see zdict.h). + * or a buffer with specified information (see dict/zdict.h). * Note : This function loads the dictionary, resulting in significant startup delay. * It's intended for a dictionary used only once. * Note 2 : When `dict == NULL || dictSize < 8` no dictionary is used. */ @@ -974,8 +825,7 @@ ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize int compressionLevel); /*! ZSTD_freeCDict() : - * Function frees memory allocated by ZSTD_createCDict(). - * If a NULL pointer is passed, no operation is performed. */ + * Function frees memory allocated by ZSTD_createCDict(). */ ZSTDLIB_API size_t ZSTD_freeCDict(ZSTD_CDict* CDict); /*! ZSTD_compress_usingCDict() : @@ -997,8 +847,7 @@ typedef struct ZSTD_DDict_s ZSTD_DDict; ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize); /*! ZSTD_freeDDict() : - * Function frees memory allocated with ZSTD_createDDict() - * If a NULL pointer is passed, no operation is performed. */ + * Function frees memory allocated with ZSTD_createDDict() */ ZSTDLIB_API size_t ZSTD_freeDDict(ZSTD_DDict* ddict); /*! ZSTD_decompress_usingDDict() : @@ -1014,30 +863,24 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx, * Dictionary helper functions *******************************/ -/*! ZSTD_getDictID_fromDict() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromDict() : * Provides the dictID stored within dictionary. * if @return == 0, the dictionary is not conformant with Zstandard specification. * It can still be loaded, but as a content-only dictionary. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize); -/*! ZSTD_getDictID_fromCDict() : Requires v1.5.0+ - * Provides the dictID of the dictionary loaded into `cdict`. - * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. - * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ -ZSTDLIB_API unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict); - -/*! ZSTD_getDictID_fromDDict() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromDDict() : * Provides the dictID of the dictionary loaded into `ddict`. * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ ZSTDLIB_API unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict); -/*! ZSTD_getDictID_fromFrame() : Requires v1.4.0+ +/*! ZSTD_getDictID_fromFrame() : * Provides the dictID required to decompressed the frame stored within `src`. * If @return == 0, the dictID could not be decoded. * This could for one of the following reasons : * - The frame does not require a dictionary to be decoded (most common case). - * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden piece of information. + * - The frame was built with dictID intentionally removed. Whatever dictionary is necessary is a hidden information. * Note : this use case also happens when using a non-conformant dictionary. * - `srcSize` is too small, and as a result, the frame header could not be decoded (only possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`). * - This is not a Zstandard frame. @@ -1046,26 +889,23 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); /******************************************************************************* - * Advanced dictionary and prefix API (Requires v1.4.0+) + * Advanced dictionary and prefix API * * This API allows dictionaries to be used with ZSTD_compress2(), - * ZSTD_compressStream2(), and ZSTD_decompressDCtx(). - * Dictionaries are sticky, they remain valid when same context is reused, - * they only reset when the context is reset - * with ZSTD_reset_parameters or ZSTD_reset_session_and_parameters. - * In contrast, Prefixes are single-use. + * ZSTD_compressStream2(), and ZSTD_decompress(). Dictionaries are sticky, and + * only reset with the context is reset with ZSTD_reset_parameters or + * ZSTD_reset_session_and_parameters. Prefixes are single-use. ******************************************************************************/ -/*! ZSTD_CCtx_loadDictionary() : Requires v1.4.0+ +/*! ZSTD_CCtx_loadDictionary() : * Create an internal CDict from `dict` buffer. * Decompression will have to use same dictionary. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Loading a NULL (or 0-size) dictionary invalidates previous dictionary, * meaning "return to no-dictionary mode". - * Note 1 : Dictionary is sticky, it will be used for all future compressed frames, - * until parameters are reset, a new dictionary is loaded, or the dictionary - * is explicitly invalidated by loading a NULL dictionary. + * Note 1 : Dictionary is sticky, it will be used for all future compressed frames. + * To return to "no-dictionary" situation, load a NULL dictionary (or reset parameters). * Note 2 : Loading a dictionary involves building tables. * It's also a CPU consuming operation, with non-negligible impact on latency. * Tables are dependent on compression parameters, and for this reason, @@ -1074,18 +914,14 @@ ZSTDLIB_API unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize); * Use experimental ZSTD_CCtx_loadDictionary_byReference() to reference content instead. * In such a case, dictionary buffer must outlive its users. * Note 4 : Use ZSTD_CCtx_loadDictionary_advanced() - * to precisely select how dictionary content must be interpreted. - * Note 5 : This method does not benefit from LDM (long distance mode). - * If you want to employ LDM on some large dictionary content, - * prefer employing ZSTD_CCtx_refPrefix() described below. - */ + * to precisely select how dictionary content must be interpreted. */ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); -/*! ZSTD_CCtx_refCDict() : Requires v1.4.0+ - * Reference a prepared dictionary, to be used for all future compressed frames. +/*! ZSTD_CCtx_refCDict() : + * Reference a prepared dictionary, to be used for all next compressed frames. * Note that compression parameters are enforced from within CDict, * and supersede any compression parameter previously set within CCtx. - * The parameters ignored are labelled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. + * The parameters ignored are labled as "superseded-by-cdict" in the ZSTD_cParameter enum docs. * The ignored parameters will be used again if the CCtx is returned to no-dictionary mode. * The dictionary will remain valid for future compressed frames using same CCtx. * @result : 0, or an error code (which can be tested with ZSTD_isError()). @@ -1095,13 +931,12 @@ ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, s * Note 2 : CDict is just referenced, its lifetime must outlive its usage within CCtx. */ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); -/*! ZSTD_CCtx_refPrefix() : Requires v1.4.0+ +/*! ZSTD_CCtx_refPrefix() : * Reference a prefix (single-usage dictionary) for next compressed frame. * A prefix is **only used once**. Tables are discarded at end of frame (ZSTD_e_end). * Decompression will need same prefix to properly regenerate data. * Compressing with a prefix is similar in outcome as performing a diff and compressing it, * but performs much faster, especially during decompression (compression speed is tunable with compression level). - * This method is compatible with LDM (long distance mode). * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special: Adding any prefix (including NULL) invalidates any previous prefix or dictionary * Note 1 : Prefix buffer is referenced. It **must** outlive compression. @@ -1117,10 +952,10 @@ ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize); -/*! ZSTD_DCtx_loadDictionary() : Requires v1.4.0+ - * Create an internal DDict from dict buffer, to be used to decompress all future frames. - * The dictionary remains valid for all future frames, until explicitly invalidated, or - * a new dictionary is loaded. +/*! ZSTD_DCtx_loadDictionary() : + * Create an internal DDict from dict buffer, + * to be used to decompress next frames. + * The dictionary remains valid for all future frames, until explicitly invalidated. * @result : 0, or an error code (which can be tested with ZSTD_isError()). * Special : Adding a NULL (or 0-size) dictionary invalidates any previous dictionary, * meaning "return to no-dictionary mode". @@ -1134,26 +969,18 @@ ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, */ ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -/*! ZSTD_DCtx_refDDict() : Requires v1.4.0+ +/*! ZSTD_DCtx_refDDict() : * Reference a prepared dictionary, to be used to decompress next frames. * The dictionary remains active for decompression of future frames using same DCtx. - * - * If called with ZSTD_d_refMultipleDDicts enabled, repeated calls of this function - * will store the DDict references in a table, and the DDict used for decompression - * will be determined at decompression time, as per the dict ID in the frame. - * The memory for the table is allocated on the first call to refDDict, and can be - * freed with ZSTD_freeDCtx(). - * - * If called with ZSTD_d_refMultipleDDicts disabled (the default), only one dictionary - * will be managed, and referencing a dictionary effectively "discards" any previous one. - * * @result : 0, or an error code (which can be tested with ZSTD_isError()). + * Note 1 : Currently, only one dictionary can be managed. + * Referencing a new dictionary effectively "discards" any previous one. * Special: referencing a NULL DDict means "return to no-dictionary mode". * Note 2 : DDict is just referenced, its lifetime must outlive its usage from DCtx. */ ZSTDLIB_API size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -/*! ZSTD_DCtx_refPrefix() : Requires v1.4.0+ +/*! ZSTD_DCtx_refPrefix() : * Reference a prefix (single-usage dictionary) to decompress next frame. * This is the reverse operation of ZSTD_CCtx_refPrefix(), * and must use the same prefix as the one used during compression. @@ -1174,7 +1001,7 @@ ZSTDLIB_API size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, /* === Memory management === */ -/*! ZSTD_sizeof_*() : Requires v1.4.0+ +/*! ZSTD_sizeof_*() : * These functions give the _current_ memory usage of selected object. * Note that object memory usage can evolve (increase or decrease) over time. */ ZSTDLIB_API size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx); @@ -1184,1910 +1011,5 @@ ZSTDLIB_API size_t ZSTD_sizeof_DStream(const ZSTD_DStream* zds); ZSTDLIB_API size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict); ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict); -} // namespace duckdb_zstd - +} #endif /* ZSTD_H_235446 */ - -namespace duckdb_zstd { - -/* ************************************************************************************** - * ADVANCED AND EXPERIMENTAL FUNCTIONS - **************************************************************************************** - * The definitions in the following section are considered experimental. - * They are provided for advanced scenarios. - * They should never be used with a dynamic library, as prototypes may change in the future. - * Use them only in association with static linking. - * ***************************************************************************************/ - -#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY) -#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY - -/* This can be overridden externally to hide static symbols. */ -#ifndef ZSTDLIB_STATIC_API -# if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDLIB_STATIC_API __declspec(dllexport) ZSTDLIB_VISIBLE -# elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDLIB_STATIC_API __declspec(dllimport) ZSTDLIB_VISIBLE -# else -# define ZSTDLIB_STATIC_API ZSTDLIB_VISIBLE -# endif -#endif - -/**************************************************************************************** - * experimental API (static linking only) - **************************************************************************************** - * The following symbols and constants - * are not planned to join "stable API" status in the near future. - * They can still change in future versions. - * Some of them are planned to remain in the static_only section indefinitely. - * Some of them might be removed in the future (especially when redundant with existing stable functions) - * ***************************************************************************************/ - -#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ -#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) -#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ -#define ZSTD_SKIPPABLEHEADERSIZE 8 - -/* compression parameter bounds */ -#define ZSTD_WINDOWLOG_MAX_32 30 -#define ZSTD_WINDOWLOG_MAX_64 31 -#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) -#define ZSTD_WINDOWLOG_MIN 10 -#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) -#define ZSTD_HASHLOG_MIN 6 -#define ZSTD_CHAINLOG_MAX_32 29 -#define ZSTD_CHAINLOG_MAX_64 30 -#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) -#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN -#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) -#define ZSTD_SEARCHLOG_MIN 1 -#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ -#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ -#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX -#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ -#define ZSTD_STRATEGY_MIN ZSTD_fast -#define ZSTD_STRATEGY_MAX ZSTD_btultra2 -#define ZSTD_BLOCKSIZE_MAX_MIN (1 << 10) /* The minimum valid max blocksize. Maximum blocksizes smaller than this make compressBound() inaccurate. */ - - -#define ZSTD_OVERLAPLOG_MIN 0 -#define ZSTD_OVERLAPLOG_MAX 9 - -#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame */ - /* requiring larger than (1< 0: - * If litLength != 0: - * rep == 1 --> offset == repeat_offset_1 - * rep == 2 --> offset == repeat_offset_2 - * rep == 3 --> offset == repeat_offset_3 - * If litLength == 0: - * rep == 1 --> offset == repeat_offset_2 - * rep == 2 --> offset == repeat_offset_3 - * rep == 3 --> offset == repeat_offset_1 - 1 - * - * Note: This field is optional. ZSTD_generateSequences() will calculate the value of - * 'rep', but repeat offsets do not necessarily need to be calculated from an external - * sequence provider's perspective. For example, ZSTD_compressSequences() does not - * use this 'rep' field at all (as of now). - */ -} ZSTD_Sequence; - -typedef struct { - unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ - unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ - unsigned hashLog; /**< dispatch table : larger == faster, more memory */ - unsigned searchLog; /**< nb of searches : larger == more compression, slower */ - unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ - unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ - ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ -} ZSTD_compressionParameters; - -typedef struct { - int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ - int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ - int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ -} ZSTD_frameParameters; - -typedef struct { - ZSTD_compressionParameters cParams; - ZSTD_frameParameters fParams; -} ZSTD_parameters; - -typedef enum { - ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ - ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ - ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ -} ZSTD_dictContentType_e; - -typedef enum { - ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ - ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ -} ZSTD_dictLoadMethod_e; - -typedef enum { - ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ - ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. - * Useful to save 4 bytes per generated frame. - * Decoder cannot recognise automatically this format, requiring this instruction. */ -} ZSTD_format_e; - -typedef enum { - /* Note: this enum controls ZSTD_d_forceIgnoreChecksum */ - ZSTD_d_validateChecksum = 0, - ZSTD_d_ignoreChecksum = 1 -} ZSTD_forceIgnoreChecksum_e; - -typedef enum { - /* Note: this enum controls ZSTD_d_refMultipleDDicts */ - ZSTD_rmd_refSingleDDict = 0, - ZSTD_rmd_refMultipleDDicts = 1 -} ZSTD_refMultipleDDicts_e; - -typedef enum { - /* Note: this enum and the behavior it controls are effectively internal - * implementation details of the compressor. They are expected to continue - * to evolve and should be considered only in the context of extremely - * advanced performance tuning. - * - * Zstd currently supports the use of a CDict in three ways: - * - * - The contents of the CDict can be copied into the working context. This - * means that the compression can search both the dictionary and input - * while operating on a single set of internal tables. This makes - * the compression faster per-byte of input. However, the initial copy of - * the CDict's tables incurs a fixed cost at the beginning of the - * compression. For small compressions (< 8 KB), that copy can dominate - * the cost of the compression. - * - * - The CDict's tables can be used in-place. In this model, compression is - * slower per input byte, because the compressor has to search two sets of - * tables. However, this model incurs no start-up cost (as long as the - * working context's tables can be reused). For small inputs, this can be - * faster than copying the CDict's tables. - * - * - The CDict's tables are not used at all, and instead we use the working - * context alone to reload the dictionary and use params based on the source - * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). - * This method is effective when the dictionary sizes are very small relative - * to the input size, and the input size is fairly large to begin with. - * - * Zstd has a simple internal heuristic that selects which strategy to use - * at the beginning of a compression. However, if experimentation shows that - * Zstd is making poor choices, it is possible to override that choice with - * this enum. - */ - ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ - ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ - ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ - ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ -} ZSTD_dictAttachPref_e; - -typedef enum { - ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. - * Negative compression levels will be uncompressed, and positive compression - * levels will be compressed. */ - ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be - * emitted if Huffman compression is not profitable. */ - ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ -} ZSTD_literalCompressionMode_e; - -typedef enum { - /* Note: This enum controls features which are conditionally beneficial. Zstd typically will make a final - * decision on whether or not to enable the feature (ZSTD_ps_auto), but setting the switch to ZSTD_ps_enable - * or ZSTD_ps_disable allow for a force enable/disable the feature. - */ - ZSTD_ps_auto = 0, /* Let the library automatically determine whether the feature shall be enabled */ - ZSTD_ps_enable = 1, /* Force-enable the feature */ - ZSTD_ps_disable = 2 /* Do not use the feature */ -} ZSTD_paramSwitch_e; - -/*************************************** -* Frame header and size functions -***************************************/ - -/*! ZSTD_findDecompressedSize() : - * `src` should point to the start of a series of ZSTD encoded and/or skippable frames - * `srcSize` must be the _exact_ size of this series - * (i.e. there should be a frame boundary at `src + srcSize`) - * @return : - decompressed size of all data in all successive frames - * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN - * - if an error occurred: ZSTD_CONTENTSIZE_ERROR - * - * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. - * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. - * In which case, it's necessary to use streaming mode to decompress data. - * note 2 : decompressed size is always present when compression is done with ZSTD_compress() - * note 3 : decompressed size can be very large (64-bits value), - * potentially larger than what local system can handle as a single memory segment. - * In which case, it's necessary to use streaming mode to decompress data. - * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. - * Always ensure result fits within application's authorized limits. - * Each application can set its own limits. - * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to - * read each contained frame header. This is fast as most of the data is skipped, - * however it does mean that all frame data must be present and valid. */ -ZSTDLIB_STATIC_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); - -/*! ZSTD_decompressBound() : - * `src` should point to the start of a series of ZSTD encoded and/or skippable frames - * `srcSize` must be the _exact_ size of this series - * (i.e. there should be a frame boundary at `src + srcSize`) - * @return : - upper-bound for the decompressed size of all data in all successive frames - * - if an error occurred: ZSTD_CONTENTSIZE_ERROR - * - * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. - * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. - * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. - * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: - * upper-bound = # blocks * min(128 KB, Window_Size) - */ -ZSTDLIB_STATIC_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); - -/*! ZSTD_frameHeaderSize() : - * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. - * @return : size of the Frame Header, - * or an error code (if srcSize is too small) */ -ZSTDLIB_STATIC_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); - -typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; -typedef struct { - unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ - unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ - unsigned blockSizeMax; - ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ - unsigned headerSize; - unsigned dictID; - unsigned checksumFlag; - unsigned _reserved1; - unsigned _reserved2; -} ZSTD_frameHeader; - -/*! ZSTD_getFrameHeader() : - * decode Frame Header, or requires larger `srcSize`. - * @return : 0, `zfhPtr` is correctly filled, - * >0, `srcSize` is too small, value is wanted `srcSize` amount, - * or an error code, which can be tested using ZSTD_isError() */ -ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ -/*! ZSTD_getFrameHeader_advanced() : - * same as ZSTD_getFrameHeader(), - * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ -ZSTDLIB_STATIC_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); - -/*! ZSTD_decompressionMargin() : - * Zstd supports in-place decompression, where the input and output buffers overlap. - * In this case, the output buffer must be at least (Margin + Output_Size) bytes large, - * and the input buffer must be at the end of the output buffer. - * - * _______________________ Output Buffer ________________________ - * | | - * | ____ Input Buffer ____| - * | | | - * v v v - * |---------------------------------------|-----------|----------| - * ^ ^ ^ - * |___________________ Output_Size ___________________|_ Margin _| - * - * NOTE: See also ZSTD_DECOMPRESSION_MARGIN(). - * NOTE: This applies only to single-pass decompression through ZSTD_decompress() or - * ZSTD_decompressDCtx(). - * NOTE: This function supports multi-frame input. - * - * @param src The compressed frame(s) - * @param srcSize The size of the compressed frame(s) - * @returns The decompression margin or an error that can be checked with ZSTD_isError(). - */ -ZSTDLIB_STATIC_API size_t ZSTD_decompressionMargin(const void* src, size_t srcSize); - -/*! ZSTD_DECOMPRESS_MARGIN() : - * Similar to ZSTD_decompressionMargin(), but instead of computing the margin from - * the compressed frame, compute it from the original size and the blockSizeLog. - * See ZSTD_decompressionMargin() for details. - * - * WARNING: This macro does not support multi-frame input, the input must be a single - * zstd frame. If you need that support use the function, or implement it yourself. - * - * @param originalSize The original uncompressed size of the data. - * @param blockSize The block size == MIN(windowSize, ZSTD_BLOCKSIZE_MAX). - * Unless you explicitly set the windowLog smaller than - * ZSTD_BLOCKSIZELOG_MAX you can just use ZSTD_BLOCKSIZE_MAX. - */ -#define ZSTD_DECOMPRESSION_MARGIN(originalSize, blockSize) ((size_t)( \ - ZSTD_FRAMEHEADERSIZE_MAX /* Frame header */ + \ - 4 /* checksum */ + \ - ((originalSize) == 0 ? 0 : 3 * (((originalSize) + (blockSize) - 1) / blockSize)) /* 3 bytes per block */ + \ - (blockSize) /* One block of margin */ \ - )) - -typedef enum { - ZSTD_sf_noBlockDelimiters = 0, /* Representation of ZSTD_Sequence has no block delimiters, sequences only */ - ZSTD_sf_explicitBlockDelimiters = 1 /* Representation of ZSTD_Sequence contains explicit block delimiters */ -} ZSTD_sequenceFormat_e; - -/*! ZSTD_sequenceBound() : - * `srcSize` : size of the input buffer - * @return : upper-bound for the number of sequences that can be generated - * from a buffer of srcSize bytes - * - * note : returns number of sequences - to get bytes, multiply by sizeof(ZSTD_Sequence). - */ -ZSTDLIB_STATIC_API size_t ZSTD_sequenceBound(size_t srcSize); - -/*! ZSTD_generateSequences() : - * WARNING: This function is meant for debugging and informational purposes ONLY! - * Its implementation is flawed, and it will be deleted in a future version. - * It is not guaranteed to succeed, as there are several cases where it will give - * up and fail. You should NOT use this function in production code. - * - * This function is deprecated, and will be removed in a future version. - * - * Generate sequences using ZSTD_compress2(), given a source buffer. - * - * @param zc The compression context to be used for ZSTD_compress2(). Set any - * compression parameters you need on this context. - * @param outSeqs The output sequences buffer of size @p outSeqsSize - * @param outSeqsSize The size of the output sequences buffer. - * ZSTD_sequenceBound(srcSize) is an upper bound on the number - * of sequences that can be generated. - * @param src The source buffer to generate sequences from of size @p srcSize. - * @param srcSize The size of the source buffer. - * - * Each block will end with a dummy sequence - * with offset == 0, matchLength == 0, and litLength == length of last literals. - * litLength may be == 0, and if so, then the sequence of (of: 0 ml: 0 ll: 0) - * simply acts as a block delimiter. - * - * @returns The number of sequences generated, necessarily less than - * ZSTD_sequenceBound(srcSize), or an error code that can be checked - * with ZSTD_isError(). - */ -ZSTD_DEPRECATED("For debugging only, will be replaced by ZSTD_extractSequences()") -ZSTDLIB_STATIC_API size_t -ZSTD_generateSequences(ZSTD_CCtx* zc, - ZSTD_Sequence* outSeqs, size_t outSeqsSize, - const void* src, size_t srcSize); - -/*! ZSTD_mergeBlockDelimiters() : - * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals - * by merging them into the literals of the next sequence. - * - * As such, the final generated result has no explicit representation of block boundaries, - * and the final last literals segment is not represented in the sequences. - * - * The output of this function can be fed into ZSTD_compressSequences() with CCtx - * setting of ZSTD_c_blockDelimiters as ZSTD_sf_noBlockDelimiters - * @return : number of sequences left after merging - */ -ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); - -/*! ZSTD_compressSequences() : - * Compress an array of ZSTD_Sequence, associated with @src buffer, into dst. - * @src contains the entire input (not just the literals). - * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals - * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) - * The entire source is compressed into a single frame. - * - * The compression behavior changes based on cctx params. In particular: - * If ZSTD_c_blockDelimiters == ZSTD_sf_noBlockDelimiters, the array of ZSTD_Sequence is expected to contain - * no block delimiters (defined in ZSTD_Sequence). Block boundaries are roughly determined based on - * the block size derived from the cctx, and sequences may be split. This is the default setting. - * - * If ZSTD_c_blockDelimiters == ZSTD_sf_explicitBlockDelimiters, the array of ZSTD_Sequence is expected to contain - * block delimiters (defined in ZSTD_Sequence). Behavior is undefined if no block delimiters are provided. - * - * If ZSTD_c_validateSequences == 0, this function will blindly accept the sequences provided. Invalid sequences cause undefined - * behavior. If ZSTD_c_validateSequences == 1, then if sequence is invalid (see doc/zstd_compression_format.md for - * specifics regarding offset/matchlength requirements) then the function will bail out and return an error. - * - * In addition to the two adjustable experimental params, there are other important cctx params. - * - ZSTD_c_minMatch MUST be set as less than or equal to the smallest match generated by the match finder. It has a minimum value of ZSTD_MINMATCH_MIN. - * - ZSTD_c_compressionLevel accordingly adjusts the strength of the entropy coder, as it would in typical compression. - * - ZSTD_c_windowLog affects offset validation: this function will return an error at higher debug levels if a provided offset - * is larger than what the spec allows for a given window log and dictionary (if present). See: doc/zstd_compression_format.md - * - * Note: Repcodes are, as of now, always re-calculated within this function, so ZSTD_Sequence::rep is unused. - * Note 2: Once we integrate ability to ingest repcodes, the explicit block delims mode must respect those repcodes exactly, - * and cannot emit an RLE block that disagrees with the repcode history - * @return : final compressed size, or a ZSTD error code. - */ -ZSTDLIB_STATIC_API size_t -ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize, - const ZSTD_Sequence* inSeqs, size_t inSeqsSize, - const void* src, size_t srcSize); - - -/*! ZSTD_writeSkippableFrame() : - * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. - * - * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, - * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. - * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so - * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. - * - * Returns an error if destination buffer is not large enough, if the source size is not representable - * with a 4-byte unsigned int, or if the parameter magicVariant is greater than 15 (and therefore invalid). - * - * @return : number of bytes written or a ZSTD error. - */ -ZSTDLIB_STATIC_API size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, - const void* src, size_t srcSize, unsigned magicVariant); - -/*! ZSTD_readSkippableFrame() : - * Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer. - * - * The parameter magicVariant will receive the magicVariant that was supplied when the frame was written, - * i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested - * in the magicVariant. - * - * Returns an error if destination buffer is not large enough, or if the frame is not skippable. - * - * @return : number of bytes written or a ZSTD error. - */ -ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant, - const void* src, size_t srcSize); - -/*! ZSTD_isSkippableFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame. - */ -ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); - - - -/*************************************** -* Memory management -***************************************/ - -/*! ZSTD_estimate*() : - * These functions make it possible to estimate memory usage - * of a future {D,C}Ctx, before its creation. - * This is useful in combination with ZSTD_initStatic(), - * which makes it possible to employ a static buffer for ZSTD_CCtx* state. - * - * ZSTD_estimateCCtxSize() will provide a memory budget large enough - * to compress data of any size using one-shot compression ZSTD_compressCCtx() or ZSTD_compress2() - * associated with any compression level up to max specified one. - * The estimate will assume the input may be arbitrarily large, - * which is the worst case. - * - * Note that the size estimation is specific for one-shot compression, - * it is not valid for streaming (see ZSTD_estimateCStreamSize*()) - * nor other potential ways of using a ZSTD_CCtx* state. - * - * When srcSize can be bound by a known and rather "small" value, - * this knowledge can be used to provide a tighter budget estimation - * because the ZSTD_CCtx* state will need less memory for small inputs. - * This tighter estimation can be provided by employing more advanced functions - * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), - * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). - * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. - * - * Note : only single-threaded compression is supported. - * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int maxCompressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); - -/*! ZSTD_estimateCStreamSize() : - * ZSTD_estimateCStreamSize() will provide a memory budget large enough for streaming compression - * using any compression level up to the max specified one. - * It will also consider src size to be arbitrarily "large", which is a worst case scenario. - * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. - * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. - * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. - * Note : CStream size estimation is only correct for single-threaded compression. - * ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - * Note 2 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time. - * Size estimates assume that no external sequence producer is registered. - * - * ZSTD_DStream memory budget depends on frame's window Size. - * This information can be passed manually, using ZSTD_estimateDStreamSize, - * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); - * Any frame requesting a window size larger than max specified one will be rejected. - * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), - * an internal ?Dict will be created, which additional size is not estimated here. - * In this case, get total size by adding ZSTD_estimate?DictSize - */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int maxCompressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t maxWindowSize); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); - -/*! ZSTD_estimate?DictSize() : - * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). - * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). - * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. - */ -ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); -ZSTDLIB_STATIC_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); -ZSTDLIB_STATIC_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); - -/*! ZSTD_initStatic*() : - * Initialize an object using a pre-allocated fixed-size buffer. - * workspace: The memory area to emplace the object into. - * Provided pointer *must be 8-bytes aligned*. - * Buffer must outlive object. - * workspaceSize: Use ZSTD_estimate*Size() to determine - * how large workspace must be to support target scenario. - * @return : pointer to object (same address as workspace, just different type), - * or NULL if error (size too small, incorrect alignment, etc.) - * Note : zstd will never resize nor malloc() when using a static buffer. - * If the object requires more memory than available, - * zstd will just error out (typically ZSTD_error_memory_allocation). - * Note 2 : there is no corresponding "free" function. - * Since workspace is allocated externally, it must be freed externally too. - * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level - * into its associated cParams. - * Limitation 1 : currently not compatible with internal dictionary creation, triggered by - * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). - * Limitation 2 : static cctx currently not compatible with multi-threading. - * Limitation 3 : static dctx is incompatible with legacy support. - */ -ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ - -ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); -ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ - -ZSTDLIB_STATIC_API const ZSTD_CDict* ZSTD_initStaticCDict( - void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams); - -ZSTDLIB_STATIC_API const ZSTD_DDict* ZSTD_initStaticDDict( - void* workspace, size_t workspaceSize, - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType); - - -/*! Custom memory allocation : - * These prototypes make it possible to pass your own allocation/free functions. - * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. - * All allocation/free operations will be completed using these custom variants instead of regular ones. - */ -typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); -typedef void (*ZSTD_freeFunction) (void* opaque, void* address); -typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; -static -#ifdef __GNUC__ -__attribute__((__unused__)) -#endif -ZSTD_customMem const ZSTD_defaultCMem = { NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ - -ZSTDLIB_STATIC_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); -ZSTDLIB_STATIC_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); - -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_compressionParameters cParams, - ZSTD_customMem customMem); - -/*! Thread pool : - * These prototypes make it possible to share a thread pool among multiple compression contexts. - * This can limit resources for applications with multiple threads where each one uses - * a threaded compression mode (via ZSTD_c_nbWorkers parameter). - * ZSTD_createThreadPool creates a new thread pool with a given number of threads. - * Note that the lifetime of such pool must exist while being used. - * ZSTD_CCtx_refThreadPool assigns a thread pool to a context (use NULL argument value - * to use an internal thread pool). - * ZSTD_freeThreadPool frees a thread pool, accepts NULL pointer. - */ -typedef struct POOL_ctx_s ZSTD_threadPool; -ZSTDLIB_STATIC_API ZSTD_threadPool* ZSTD_createThreadPool(size_t numThreads); -ZSTDLIB_STATIC_API void ZSTD_freeThreadPool (ZSTD_threadPool* pool); /* accept NULL pointer */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool); - - -/* - * This API is temporary and is expected to change or disappear in the future! - */ -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_advanced2( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - const ZSTD_CCtx_params* cctxParams, - ZSTD_customMem customMem); - -ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_advanced( - const void* dict, size_t dictSize, - ZSTD_dictLoadMethod_e dictLoadMethod, - ZSTD_dictContentType_e dictContentType, - ZSTD_customMem customMem); - - -/*************************************** -* Advanced compression functions -***************************************/ - -/*! ZSTD_createCDict_byReference() : - * Create a digested dictionary for compression - * Dictionary content is just referenced, not duplicated. - * As a consequence, `dictBuffer` **must** outlive CDict, - * and its content must remain unmodified throughout the lifetime of CDict. - * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ -ZSTDLIB_STATIC_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); - -/*! ZSTD_getCParams() : - * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. - * `estimatedSrcSize` value is optional, select 0 if not known */ -ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); - -/*! ZSTD_getParams() : - * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. - * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ -ZSTDLIB_STATIC_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); - -/*! ZSTD_checkCParams() : - * Ensure param values remain within authorized range. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ -ZSTDLIB_STATIC_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); - -/*! ZSTD_adjustCParams() : - * optimize params for a given `srcSize` and `dictSize`. - * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. - * `dictSize` must be `0` when there is no dictionary. - * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. - * This function never fails (wide contract) */ -ZSTDLIB_STATIC_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); - -/*! ZSTD_CCtx_setCParams() : - * Set all parameters provided within @p cparams into the working @p cctx. - * Note : if modifying parameters during compression (MT mode only), - * note that changes to the .windowLog parameter will be ignored. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - * On failure, no parameters are updated. - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams); - -/*! ZSTD_CCtx_setFParams() : - * Set all parameters provided within @p fparams into the working @p cctx. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams); - -/*! ZSTD_CCtx_setParams() : - * Set all parameters provided within @p params into the working @p cctx. - * @return 0 on success, or an error code (can be checked with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params); - -/*! ZSTD_compress_advanced() : - * Note : this function is now DEPRECATED. - * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. - * This prototype will generate compilation warnings. */ -ZSTD_DEPRECATED("use ZSTD_compress2") -ZSTDLIB_STATIC_API -size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const void* dict,size_t dictSize, - ZSTD_parameters params); - -/*! ZSTD_compress_usingCDict_advanced() : - * Note : this function is now DEPRECATED. - * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. - * This prototype will generate compilation warnings. */ -ZSTD_DEPRECATED("use ZSTD_compress2 with ZSTD_CCtx_loadDictionary") -ZSTDLIB_STATIC_API -size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fParams); - - -/*! ZSTD_CCtx_loadDictionary_byReference() : - * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. - * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); - -/*! ZSTD_CCtx_loadDictionary_advanced() : - * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over - * how to load the dictionary (by copy ? by reference ?) - * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_CCtx_refPrefix_advanced() : - * Same as ZSTD_CCtx_refPrefix(), but gives finer control over - * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); - -/* === experimental parameters === */ -/* these parameters can be used with ZSTD_setParameter() - * they are not guaranteed to remain supported in the future */ - - /* Enables rsyncable mode, - * which makes compressed files more rsync friendly - * by adding periodic synchronization points to the compressed data. - * The target average block size is ZSTD_c_jobSize / 2. - * It's possible to modify the job size to increase or decrease - * the granularity of the synchronization point. - * Once the jobSize is smaller than the window size, - * it will result in compression ratio degradation. - * NOTE 1: rsyncable mode only works when multithreading is enabled. - * NOTE 2: rsyncable performs poorly in combination with long range mode, - * since it will decrease the effectiveness of synchronization points, - * though mileage may vary. - * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. - * If the selected compression level is already running significantly slower, - * the overall speed won't be significantly impacted. - */ - #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 - -/* Select a compression format. - * The value must be of type ZSTD_format_e. - * See ZSTD_format_e enum definition for details */ -#define ZSTD_c_format ZSTD_c_experimentalParam2 - -/* Force back-reference distances to remain < windowSize, - * even when referencing into Dictionary content (default:0) */ -#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 - -/* Controls whether the contents of a CDict - * are used in place, or copied into the working context. - * Accepts values from the ZSTD_dictAttachPref_e enum. - * See the comments on that enum for an explanation of the feature. */ -#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 - -/* Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never compress literals. - * Set to ZSTD_ps_enable to always compress literals. (Note: uncompressed literals - * may still be emitted if huffman is not beneficial to use.) - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * literals compression based on the compression parameters - specifically, - * negative compression levels do not use literal compression. - */ -#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 - -/* User's best guess of source size. - * Hint is not valid when srcSizeHint == 0. - * There is no guarantee that hint is close to actual source size, - * but compression ratio may regress significantly if guess considerably underestimates */ -#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 - -/* Controls whether the new and experimental "dedicated dictionary search - * structure" can be used. This feature is still rough around the edges, be - * prepared for surprising behavior! - * - * How to use it: - * - * When using a CDict, whether to use this feature or not is controlled at - * CDict creation, and it must be set in a CCtxParams set passed into that - * construction (via ZSTD_createCDict_advanced2()). A compression will then - * use the feature or not based on how the CDict was constructed; the value of - * this param, set in the CCtx, will have no effect. - * - * However, when a dictionary buffer is passed into a CCtx, such as via - * ZSTD_CCtx_loadDictionary(), this param can be set on the CCtx to control - * whether the CDict that is created internally can use the feature or not. - * - * What it does: - * - * Normally, the internal data structures of the CDict are analogous to what - * would be stored in a CCtx after compressing the contents of a dictionary. - * To an approximation, a compression using a dictionary can then use those - * data structures to simply continue what is effectively a streaming - * compression where the simulated compression of the dictionary left off. - * Which is to say, the search structures in the CDict are normally the same - * format as in the CCtx. - * - * It is possible to do better, since the CDict is not like a CCtx: the search - * structures are written once during CDict creation, and then are only read - * after that, while the search structures in the CCtx are both read and - * written as the compression goes along. This means we can choose a search - * structure for the dictionary that is read-optimized. - * - * This feature enables the use of that different structure. - * - * Note that some of the members of the ZSTD_compressionParameters struct have - * different semantics and constraints in the dedicated search structure. It is - * highly recommended that you simply set a compression level in the CCtxParams - * you pass into the CDict creation call, and avoid messing with the cParams - * directly. - * - * Effects: - * - * This will only have any effect when the selected ZSTD_strategy - * implementation supports this feature. Currently, that's limited to - * ZSTD_greedy, ZSTD_lazy, and ZSTD_lazy2. - * - * Note that this means that the CDict tables can no longer be copied into the - * CCtx, so the dict attachment mode ZSTD_dictForceCopy will no longer be - * usable. The dictionary can only be attached or reloaded. - * - * In general, you should expect compression to be faster--sometimes very much - * so--and CDict creation to be slightly slower. Eventually, we will probably - * make this mode the default. - */ -#define ZSTD_c_enableDedicatedDictSearch ZSTD_c_experimentalParam8 - -/* ZSTD_c_stableInBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells the compressor that input data presented with ZSTD_inBuffer - * will ALWAYS be the same between calls. - * Technically, the @src pointer must never be changed, - * and the @pos field can only be updated by zstd. - * However, it's possible to increase the @size field, - * allowing scenarios where more data can be appended after compressions starts. - * These conditions are checked by the compressor, - * and compression will fail if they are not respected. - * Also, data in the ZSTD_inBuffer within the range [src, src + pos) - * MUST not be modified during compression or it will result in data corruption. - * - * When this flag is enabled zstd won't allocate an input window buffer, - * because the user guarantees it can reference the ZSTD_inBuffer until - * the frame is complete. But, it will still allocate an output buffer - * large enough to fit a block (see ZSTD_c_stableOutBuffer). This will also - * avoid the memcpy() from the input buffer to the input window buffer. - * - * NOTE: So long as the ZSTD_inBuffer always points to valid memory, using - * this flag is ALWAYS memory safe, and will never access out-of-bounds - * memory. However, compression WILL fail if conditions are not respected. - * - * WARNING: The data in the ZSTD_inBuffer in the range [src, src + pos) MUST - * not be modified during compression or it will result in data corruption. - * This is because zstd needs to reference data in the ZSTD_inBuffer to find - * matches. Normally zstd maintains its own window buffer for this purpose, - * but passing this flag tells zstd to rely on user provided buffer instead. - */ -#define ZSTD_c_stableInBuffer ZSTD_c_experimentalParam9 - -/* ZSTD_c_stableOutBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells he compressor that the ZSTD_outBuffer will not be resized between - * calls. Specifically: (out.size - out.pos) will never grow. This gives the - * compressor the freedom to say: If the compressed data doesn't fit in the - * output buffer then return ZSTD_error_dstSizeTooSmall. This allows us to - * always decompress directly into the output buffer, instead of decompressing - * into an internal buffer and copying to the output buffer. - * - * When this flag is enabled zstd won't allocate an output buffer, because - * it can write directly to the ZSTD_outBuffer. It will still allocate the - * input window buffer (see ZSTD_c_stableInBuffer). - * - * Zstd will check that (out.size - out.pos) never grows and return an error - * if it does. While not strictly necessary, this should prevent surprises. - */ -#define ZSTD_c_stableOutBuffer ZSTD_c_experimentalParam10 - -/* ZSTD_c_blockDelimiters - * Default is 0 == ZSTD_sf_noBlockDelimiters. - * - * For use with sequence compression API: ZSTD_compressSequences(). - * - * Designates whether or not the given array of ZSTD_Sequence contains block delimiters - * and last literals, which are defined as sequences with offset == 0 and matchLength == 0. - * See the definition of ZSTD_Sequence for more specifics. - */ -#define ZSTD_c_blockDelimiters ZSTD_c_experimentalParam11 - -/* ZSTD_c_validateSequences - * Default is 0 == disabled. Set to 1 to enable sequence validation. - * - * For use with sequence compression API: ZSTD_compressSequences(). - * Designates whether or not we validate sequences provided to ZSTD_compressSequences() - * during function execution. - * - * Without validation, providing a sequence that does not conform to the zstd spec will cause - * undefined behavior, and may produce a corrupted block. - * - * With validation enabled, if sequence is invalid (see doc/zstd_compression_format.md for - * specifics regarding offset/matchlength requirements) then the function will bail out and - * return an error. - * - */ -#define ZSTD_c_validateSequences ZSTD_c_experimentalParam12 - -/* ZSTD_c_useBlockSplitter - * Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never use block splitter. - * Set to ZSTD_ps_enable to always use block splitter. - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * block splitting based on the compression parameters. - */ -#define ZSTD_c_useBlockSplitter ZSTD_c_experimentalParam13 - -/* ZSTD_c_useRowMatchFinder - * Controlled with ZSTD_paramSwitch_e enum. - * Default is ZSTD_ps_auto. - * Set to ZSTD_ps_disable to never use row-based matchfinder. - * Set to ZSTD_ps_enable to force usage of row-based matchfinder. - * - * By default, in ZSTD_ps_auto, the library will decide at runtime whether to use - * the row-based matchfinder based on support for SIMD instructions and the window log. - * Note that this only pertains to compression strategies: greedy, lazy, and lazy2 - */ -#define ZSTD_c_useRowMatchFinder ZSTD_c_experimentalParam14 - -/* ZSTD_c_deterministicRefPrefix - * Default is 0 == disabled. Set to 1 to enable. - * - * Zstd produces different results for prefix compression when the prefix is - * directly adjacent to the data about to be compressed vs. when it isn't. - * This is because zstd detects that the two buffers are contiguous and it can - * use a more efficient match finding algorithm. However, this produces different - * results than when the two buffers are non-contiguous. This flag forces zstd - * to always load the prefix in non-contiguous mode, even if it happens to be - * adjacent to the data, to guarantee determinism. - * - * If you really care about determinism when using a dictionary or prefix, - * like when doing delta compression, you should select this option. It comes - * at a speed penalty of about ~2.5% if the dictionary and data happened to be - * contiguous, and is free if they weren't contiguous. We don't expect that - * intentionally making the dictionary and data contiguous will be worth the - * cost to memcpy() the data. - */ -#define ZSTD_c_deterministicRefPrefix ZSTD_c_experimentalParam15 - -/* ZSTD_c_prefetchCDictTables - * Controlled with ZSTD_paramSwitch_e enum. Default is ZSTD_ps_auto. - * - * In some situations, zstd uses CDict tables in-place rather than copying them - * into the working context. (See docs on ZSTD_dictAttachPref_e above for details). - * In such situations, compression speed is seriously impacted when CDict tables are - * "cold" (outside CPU cache). This parameter instructs zstd to prefetch CDict tables - * when they are used in-place. - * - * For sufficiently small inputs, the cost of the prefetch will outweigh the benefit. - * For sufficiently large inputs, zstd will by default memcpy() CDict tables - * into the working context, so there is no need to prefetch. This parameter is - * targeted at a middle range of input sizes, where a prefetch is cheap enough to be - * useful but memcpy() is too expensive. The exact range of input sizes where this - * makes sense is best determined by careful experimentation. - * - * Note: for this parameter, ZSTD_ps_auto is currently equivalent to ZSTD_ps_disable, - * but in the future zstd may conditionally enable this feature via an auto-detection - * heuristic for cold CDicts. - * Use ZSTD_ps_disable to opt out of prefetching under any circumstances. - */ -#define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 - -/* ZSTD_c_enableSeqProducerFallback - * Allowed values are 0 (disable) and 1 (enable). The default setting is 0. - * - * Controls whether zstd will fall back to an internal sequence producer if an - * external sequence producer is registered and returns an error code. This fallback - * is block-by-block: the internal sequence producer will only be called for blocks - * where the external sequence producer returns an error code. Fallback parsing will - * follow any other cParam settings, such as compression level, the same as in a - * normal (fully-internal) compression operation. - * - * The user is strongly encouraged to read the full Block-Level Sequence Producer API - * documentation (below) before setting this parameter. */ -#define ZSTD_c_enableSeqProducerFallback ZSTD_c_experimentalParam17 - -/* ZSTD_c_maxBlockSize - * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). - * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. - * - * This parameter can be used to set an upper bound on the blocksize - * that overrides the default ZSTD_BLOCKSIZE_MAX. It cannot be used to set upper - * bounds greater than ZSTD_BLOCKSIZE_MAX or bounds lower than 1KB (will make - * compressBound() inaccurate). Only currently meant to be used for testing. - * - */ -#define ZSTD_c_maxBlockSize ZSTD_c_experimentalParam18 - -/* ZSTD_c_searchForExternalRepcodes - * This parameter affects how zstd parses external sequences, such as sequences - * provided through the compressSequences() API or from an external block-level - * sequence producer. - * - * If set to ZSTD_ps_enable, the library will check for repeated offsets in - * external sequences, even if those repcodes are not explicitly indicated in - * the "rep" field. Note that this is the only way to exploit repcode matches - * while using compressSequences() or an external sequence producer, since zstd - * currently ignores the "rep" field of external sequences. - * - * If set to ZSTD_ps_disable, the library will not exploit repeated offsets in - * external sequences, regardless of whether the "rep" field has been set. This - * reduces sequence compression overhead by about 25% while sacrificing some - * compression ratio. - * - * The default value is ZSTD_ps_auto, for which the library will enable/disable - * based on compression level. - * - * Note: for now, this param only has an effect if ZSTD_c_blockDelimiters is - * set to ZSTD_sf_explicitBlockDelimiters. That may change in the future. - */ -#define ZSTD_c_searchForExternalRepcodes ZSTD_c_experimentalParam19 - -/*! ZSTD_CCtx_getParameter() : - * Get the requested compression parameter value, selected by enum ZSTD_cParameter, - * and store it into int* value. - * @return : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_getParameter(const ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); - - -/*! ZSTD_CCtx_params : - * Quick howto : - * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure - * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into - * an existing ZSTD_CCtx_params structure. - * This is similar to - * ZSTD_CCtx_setParameter(). - * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to - * an existing CCtx. - * These parameters will be applied to - * all subsequent frames. - * - ZSTD_compressStream2() : Do compression using the CCtx. - * - ZSTD_freeCCtxParams() : Free the memory, accept NULL pointer. - * - * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() - * for static allocation of CCtx for single-threaded compression. - */ -ZSTDLIB_STATIC_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); -ZSTDLIB_STATIC_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); /* accept NULL pointer */ - -/*! ZSTD_CCtxParams_reset() : - * Reset params to default values. - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); - -/*! ZSTD_CCtxParams_init() : - * Initializes the compression parameters of cctxParams according to - * compression level. All other parameters are reset to their default values. - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); - -/*! ZSTD_CCtxParams_init_advanced() : - * Initializes the compression and frame parameters of cctxParams according to - * params. All other parameters are reset to their default values. - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); - -/*! ZSTD_CCtxParams_setParameter() : Requires v1.4.0+ - * Similar to ZSTD_CCtx_setParameter. - * Set one compression parameter, selected by enum ZSTD_cParameter. - * Parameters must be applied to a ZSTD_CCtx using - * ZSTD_CCtx_setParametersUsingCCtxParams(). - * @result : a code representing success or failure (which can be tested with - * ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); - -/*! ZSTD_CCtxParams_getParameter() : - * Similar to ZSTD_CCtx_getParameter. - * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. - * @result : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtxParams_getParameter(const ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); - -/*! ZSTD_CCtx_setParametersUsingCCtxParams() : - * Apply a set of ZSTD_CCtx_params to the compression context. - * This can be done even after compression is started, - * if nbWorkers==0, this will have no impact until a new compression is started. - * if nbWorkers>=1, new parameters will be picked up at next job, - * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). - */ -ZSTDLIB_STATIC_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( - ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); - -/*! ZSTD_compressStream2_simpleArgs() : - * Same as ZSTD_compressStream2(), - * but using only integral types as arguments. - * This variant might be helpful for binders from dynamic languages - * which have troubles handling structures containing memory pointers. - */ -ZSTDLIB_STATIC_API size_t ZSTD_compressStream2_simpleArgs ( - ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, size_t* dstPos, - const void* src, size_t srcSize, size_t* srcPos, - ZSTD_EndDirective endOp); - - -/*************************************** -* Advanced decompression functions -***************************************/ - -/*! ZSTD_isFrame() : - * Tells if the content of `buffer` starts with a valid Frame Identifier. - * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. - * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. - * Note 3 : Skippable Frame Identifiers are considered valid. */ -ZSTDLIB_STATIC_API unsigned ZSTD_isFrame(const void* buffer, size_t size); - -/*! ZSTD_createDDict_byReference() : - * Create a digested dictionary, ready to start decompression operation without startup delay. - * Dictionary content is referenced, and therefore stays in dictBuffer. - * It is important that dictBuffer outlives DDict, - * it must remain read accessible throughout the lifetime of DDict */ -ZSTDLIB_STATIC_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); - -/*! ZSTD_DCtx_loadDictionary_byReference() : - * Same as ZSTD_DCtx_loadDictionary(), - * but references `dict` content instead of copying it into `dctx`. - * This saves memory if `dict` remains around., - * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); - -/*! ZSTD_DCtx_loadDictionary_advanced() : - * Same as ZSTD_DCtx_loadDictionary(), - * but gives direct control over - * how to load the dictionary (by copy ? by reference ?) - * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_DCtx_refPrefix_advanced() : - * Same as ZSTD_DCtx_refPrefix(), but gives finer control over - * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); - -/*! ZSTD_DCtx_setMaxWindowSize() : - * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. - * This protects a decoder context from reserving too much memory for itself (potential attack scenario). - * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. - * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) - * @return : 0, or an error code (which can be tested using ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); - -/*! ZSTD_DCtx_getParameter() : - * Get the requested decompression parameter value, selected by enum ZSTD_dParameter, - * and store it into int* value. - * @return : 0, or an error code (which can be tested with ZSTD_isError()). - */ -ZSTDLIB_STATIC_API size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value); - -/* ZSTD_d_format - * experimental parameter, - * allowing selection between ZSTD_format_e input compression formats - */ -#define ZSTD_d_format ZSTD_d_experimentalParam1 -/* ZSTD_d_stableOutBuffer - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable. - * - * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same - * between calls, except for the modifications that zstd makes to pos (the - * caller must not modify pos). This is checked by the decompressor, and - * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer - * MUST be large enough to fit the entire decompressed frame. This will be - * checked when the frame content size is known. The data in the ZSTD_outBuffer - * in the range [dst, dst + pos) MUST not be modified during decompression - * or you will get data corruption. - * - * When this flag is enabled zstd won't allocate an output buffer, because - * it can write directly to the ZSTD_outBuffer, but it will still allocate - * an input buffer large enough to fit any compressed block. This will also - * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. - * If you need to avoid the input buffer allocation use the buffer-less - * streaming API. - * - * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using - * this flag is ALWAYS memory safe, and will never access out-of-bounds - * memory. However, decompression WILL fail if you violate the preconditions. - * - * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST - * not be modified during decompression or you will get data corruption. This - * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate - * matches. Normally zstd maintains its own buffer for this purpose, but passing - * this flag tells zstd to use the user provided buffer. - */ -#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 - -/* ZSTD_d_forceIgnoreChecksum - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable - * - * Tells the decompressor to skip checksum validation during decompression, regardless - * of whether checksumming was specified during compression. This offers some - * slight performance benefits, and may be useful for debugging. - * Param has values of type ZSTD_forceIgnoreChecksum_e - */ -#define ZSTD_d_forceIgnoreChecksum ZSTD_d_experimentalParam3 - -/* ZSTD_d_refMultipleDDicts - * Experimental parameter. - * Default is 0 == disabled. Set to 1 to enable - * - * If enabled and dctx is allocated on the heap, then additional memory will be allocated - * to store references to multiple ZSTD_DDict. That is, multiple calls of ZSTD_refDDict() - * using a given ZSTD_DCtx, rather than overwriting the previous DDict reference, will instead - * store all references. At decompression time, the appropriate dictID is selected - * from the set of DDicts based on the dictID in the frame. - * - * Usage is simply calling ZSTD_refDDict() on multiple dict buffers. - * - * Param has values of byte ZSTD_refMultipleDDicts_e - * - * WARNING: Enabling this parameter and calling ZSTD_DCtx_refDDict(), will trigger memory - * allocation for the hash table. ZSTD_freeDCtx() also frees this memory. - * Memory is allocated as per ZSTD_DCtx::customMem. - * - * Although this function allocates memory for the table, the user is still responsible for - * memory management of the underlying ZSTD_DDict* themselves. - */ -#define ZSTD_d_refMultipleDDicts ZSTD_d_experimentalParam4 - -/* ZSTD_d_disableHuffmanAssembly - * Set to 1 to disable the Huffman assembly implementation. - * The default value is 0, which allows zstd to use the Huffman assembly - * implementation if available. - * - * This parameter can be used to disable Huffman assembly at runtime. - * If you want to disable it at compile time you can define the macro - * ZSTD_DISABLE_ASM. - */ -#define ZSTD_d_disableHuffmanAssembly ZSTD_d_experimentalParam5 - -/* ZSTD_d_maxBlockSize - * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). - * The default is ZSTD_BLOCKSIZE_MAX, and setting to 0 will set to the default. - * - * Forces the decompressor to reject blocks whose content size is - * larger than the configured maxBlockSize. When maxBlockSize is - * larger than the windowSize, the windowSize is used instead. - * This saves memory on the decoder when you know all blocks are small. - * - * This option is typically used in conjunction with ZSTD_c_maxBlockSize. - * - * WARNING: This causes the decoder to reject otherwise valid frames - * that have block sizes larger than the configured maxBlockSize. - */ -#define ZSTD_d_maxBlockSize ZSTD_d_experimentalParam6 - - -/*! ZSTD_DCtx_setFormat() : - * This function is REDUNDANT. Prefer ZSTD_DCtx_setParameter(). - * Instruct the decoder context about what kind of data to decode next. - * This instruction is mandatory to decode data without a fully-formed header, - * such ZSTD_f_zstd1_magicless for example. - * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ -ZSTD_DEPRECATED("use ZSTD_DCtx_setParameter() instead") -ZSTDLIB_STATIC_API -size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); - -/*! ZSTD_decompressStream_simpleArgs() : - * Same as ZSTD_decompressStream(), - * but using only integral types as arguments. - * This can be helpful for binders from dynamic languages - * which have troubles handling structures containing memory pointers. - */ -ZSTDLIB_STATIC_API size_t ZSTD_decompressStream_simpleArgs ( - ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, size_t* dstPos, - const void* src, size_t srcSize, size_t* srcPos); - - -/******************************************************************** -* Advanced streaming functions -* Warning : most of these functions are now redundant with the Advanced API. -* Once Advanced API reaches "stable" status, -* redundant functions will be deprecated, and then at some point removed. -********************************************************************/ - -/*===== Advanced Streaming compression functions =====*/ - -/*! ZSTD_initCStream_srcSize() : - * This function is DEPRECATED, and equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) - * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * - * pledgedSrcSize must be correct. If it is not known at init time, use - * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, - * "0" also disables frame content size field. It may be enabled in the future. - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, - int compressionLevel, - unsigned long long pledgedSrcSize); - -/*! ZSTD_initCStream_usingDict() : - * This function is DEPRECATED, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); - * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); - * - * Creates of an internal CDict (incompatible with static CCtx), except if - * dict == NULL or dictSize < 8, in which case no dict is used. - * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if - * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - int compressionLevel); - -/*! ZSTD_initCStream_advanced() : - * This function is DEPRECATED, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setParams(zcs, params); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); - * - * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. - * pledgedSrcSize must be correct. - * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, - const void* dict, size_t dictSize, - ZSTD_parameters params, - unsigned long long pledgedSrcSize); - -/*! ZSTD_initCStream_usingCDict() : - * This function is DEPRECATED, and equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_refCDict(zcs, cdict); - * - * note : cdict will just be referenced, and must outlive compression session - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); - -/*! ZSTD_initCStream_usingCDict_advanced() : - * This function is DEPRECATED, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setFParams(zcs, fParams); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * ZSTD_CCtx_refCDict(zcs, cdict); - * - * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. - * pledgedSrcSize must be correct. If srcSize is not known at init time, use - * value ZSTD_CONTENTSIZE_UNKNOWN. - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset and ZSTD_CCtx_refCDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, - const ZSTD_CDict* cdict, - ZSTD_frameParameters fParams, - unsigned long long pledgedSrcSize); - -/*! ZSTD_resetCStream() : - * This function is DEPRECATED, and is equivalent to: - * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); - * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); - * Note: ZSTD_resetCStream() interprets pledgedSrcSize == 0 as ZSTD_CONTENTSIZE_UNKNOWN, but - * ZSTD_CCtx_setPledgedSrcSize() does not do the same, so ZSTD_CONTENTSIZE_UNKNOWN must be - * explicitly specified. - * - * start a new frame, using same parameters from previous frame. - * This is typically useful to skip dictionary loading stage, since it will reuse it in-place. - * Note that zcs must be init at least once before using ZSTD_resetCStream(). - * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. - * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. - * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, - * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. - * @return : 0, or an error code (which can be tested using ZSTD_isError()) - * This prototype will generate compilation warnings. - */ -ZSTD_DEPRECATED("use ZSTD_CCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API -size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); - - -typedef struct { - unsigned long long ingested; /* nb input bytes read and buffered */ - unsigned long long consumed; /* nb input bytes actually compressed */ - unsigned long long produced; /* nb of compressed bytes generated and buffered */ - unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ - unsigned currentJobID; /* MT only : latest started job nb */ - unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ -} ZSTD_frameProgression; - -/* ZSTD_getFrameProgression() : - * tells how much data has been ingested (read from input) - * consumed (input actually compressed) and produced (output) for current frame. - * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. - * Aggregates progression inside active worker threads. - */ -ZSTDLIB_STATIC_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); - -/*! ZSTD_toFlushNow() : - * Tell how many bytes are ready to be flushed immediately. - * Useful for multithreading scenarios (nbWorkers >= 1). - * Probe the oldest active job, defined as oldest job not yet entirely flushed, - * and check its output buffer. - * @return : amount of data stored in oldest job and ready to be flushed immediately. - * if @return == 0, it means either : - * + there is no active job (could be checked with ZSTD_frameProgression()), or - * + oldest job is still actively compressing data, - * but everything it has produced has also been flushed so far, - * therefore flush speed is limited by production speed of oldest job - * irrespective of the speed of concurrent (and newer) jobs. - */ -ZSTDLIB_STATIC_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); - - -/*===== Advanced Streaming decompression functions =====*/ - -/*! - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); - * - * note: no dictionary will be used if dict == NULL or dictSize < 8 - */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_loadDictionary, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); - -/*! - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * ZSTD_DCtx_refDDict(zds, ddict); - * - * note : ddict is referenced, it must outlive decompression session - */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset + ZSTD_DCtx_refDDict, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); - -/*! - * This function is deprecated, and is equivalent to: - * - * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); - * - * reuse decompression parameters from previous init; saves dictionary loading - */ -ZSTD_DEPRECATED("use ZSTD_DCtx_reset, see zstd.h for detailed instructions") -ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); - - -/* ********************* BLOCK-LEVEL SEQUENCE PRODUCER API ********************* - * - * *** OVERVIEW *** - * The Block-Level Sequence Producer API allows users to provide their own custom - * sequence producer which libzstd invokes to process each block. The produced list - * of sequences (literals and matches) is then post-processed by libzstd to produce - * valid compressed blocks. - * - * This block-level offload API is a more granular complement of the existing - * frame-level offload API compressSequences() (introduced in v1.5.1). It offers - * an easier migration story for applications already integrated with libzstd: the - * user application continues to invoke the same compression functions - * ZSTD_compress2() or ZSTD_compressStream2() as usual, and transparently benefits - * from the specific advantages of the external sequence producer. For example, - * the sequence producer could be tuned to take advantage of known characteristics - * of the input, to offer better speed / ratio, or could leverage hardware - * acceleration not available within libzstd itself. - * - * See contrib/externalSequenceProducer for an example program employing the - * Block-Level Sequence Producer API. - * - * *** USAGE *** - * The user is responsible for implementing a function of type - * ZSTD_sequenceProducer_F. For each block, zstd will pass the following - * arguments to the user-provided function: - * - * - sequenceProducerState: a pointer to a user-managed state for the sequence - * producer. - * - * - outSeqs, outSeqsCapacity: an output buffer for the sequence producer. - * outSeqsCapacity is guaranteed >= ZSTD_sequenceBound(srcSize). The memory - * backing outSeqs is managed by the CCtx. - * - * - src, srcSize: an input buffer for the sequence producer to parse. - * srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. - * - * - dict, dictSize: a history buffer, which may be empty, which the sequence - * producer may reference as it parses the src buffer. Currently, zstd will - * always pass dictSize == 0 into external sequence producers, but this will - * change in the future. - * - * - compressionLevel: a signed integer representing the zstd compression level - * set by the user for the current operation. The sequence producer may choose - * to use this information to change its compression strategy and speed/ratio - * tradeoff. Note: the compression level does not reflect zstd parameters set - * through the advanced API. - * - * - windowSize: a size_t representing the maximum allowed offset for external - * sequences. Note that sequence offsets are sometimes allowed to exceed the - * windowSize if a dictionary is present, see doc/zstd_compression_format.md - * for details. - * - * The user-provided function shall return a size_t representing the number of - * sequences written to outSeqs. This return value will be treated as an error - * code if it is greater than outSeqsCapacity. The return value must be non-zero - * if srcSize is non-zero. The ZSTD_SEQUENCE_PRODUCER_ERROR macro is provided - * for convenience, but any value greater than outSeqsCapacity will be treated as - * an error code. - * - * If the user-provided function does not return an error code, the sequences - * written to outSeqs must be a valid parse of the src buffer. Data corruption may - * occur if the parse is not valid. A parse is defined to be valid if the - * following conditions hold: - * - The sum of matchLengths and literalLengths must equal srcSize. - * - All sequences in the parse, except for the final sequence, must have - * matchLength >= ZSTD_MINMATCH_MIN. The final sequence must have - * matchLength >= ZSTD_MINMATCH_MIN or matchLength == 0. - * - All offsets must respect the windowSize parameter as specified in - * doc/zstd_compression_format.md. - * - If the final sequence has matchLength == 0, it must also have offset == 0. - * - * zstd will only validate these conditions (and fail compression if they do not - * hold) if the ZSTD_c_validateSequences cParam is enabled. Note that sequence - * validation has a performance cost. - * - * If the user-provided function returns an error, zstd will either fall back - * to an internal sequence producer or fail the compression operation. The user can - * choose between the two behaviors by setting the ZSTD_c_enableSeqProducerFallback - * cParam. Fallback compression will follow any other cParam settings, such as - * compression level, the same as in a normal compression operation. - * - * The user shall instruct zstd to use a particular ZSTD_sequenceProducer_F - * function by calling - * ZSTD_registerSequenceProducer(cctx, - * sequenceProducerState, - * sequenceProducer) - * This setting will persist until the next parameter reset of the CCtx. - * - * The sequenceProducerState must be initialized by the user before calling - * ZSTD_registerSequenceProducer(). The user is responsible for destroying the - * sequenceProducerState. - * - * *** LIMITATIONS *** - * This API is compatible with all zstd compression APIs which respect advanced parameters. - * However, there are three limitations: - * - * First, the ZSTD_c_enableLongDistanceMatching cParam is not currently supported. - * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with a block-level - * external sequence producer. - * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in some - * cases (see its documentation for details). Users must explicitly set - * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an external - * sequence producer is registered. - * - As of this writing, ZSTD_c_enableLongDistanceMatching is disabled by default - * whenever ZSTD_c_windowLog < 128MB, but that's subject to change. Users should - * check the docs on ZSTD_c_enableLongDistanceMatching whenever the Block-Level Sequence - * Producer API is used in conjunction with advanced settings (like ZSTD_c_windowLog). - * - * Second, history buffers are not currently supported. Concretely, zstd will always pass - * dictSize == 0 to the external sequence producer (for now). This has two implications: - * - Dictionaries are not currently supported. Compression will *not* fail if the user - * references a dictionary, but the dictionary won't have any effect. - * - Stream history is not currently supported. All advanced compression APIs, including - * streaming APIs, work with external sequence producers, but each block is treated as - * an independent chunk without history from previous blocks. - * - * Third, multi-threading within a single compression is not currently supported. In other words, - * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external sequence producer is registered. - * Multi-threading across compressions is fine: simply create one CCtx per thread. - * - * Long-term, we plan to overcome all three limitations. There is no technical blocker to - * overcoming them. It is purely a question of engineering effort. - */ - -#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1)) - -typedef size_t (*ZSTD_sequenceProducer_F) ( - void* sequenceProducerState, - ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, - const void* src, size_t srcSize, - const void* dict, size_t dictSize, - int compressionLevel, - size_t windowSize -); - -/*! ZSTD_registerSequenceProducer() : - * Instruct zstd to use a block-level external sequence producer function. - * - * The sequenceProducerState must be initialized by the caller, and the caller is - * responsible for managing its lifetime. This parameter is sticky across - * compressions. It will remain set until the user explicitly resets compression - * parameters. - * - * Sequence producer registration is considered to be an "advanced parameter", - * part of the "advanced API". This means it will only have an effect on compression - * APIs which respect advanced parameters, such as compress2() and compressStream2(). - * Older compression APIs such as compressCCtx(), which predate the introduction of - * "advanced parameters", will ignore any external sequence producer setting. - * - * The sequence producer can be "cleared" by registering a NULL function pointer. This - * removes all limitations described above in the "LIMITATIONS" section of the API docs. - * - * The user is strongly encouraged to read the full API documentation (above) before - * calling this function. */ -ZSTDLIB_STATIC_API void -ZSTD_registerSequenceProducer( - ZSTD_CCtx* cctx, - void* sequenceProducerState, - ZSTD_sequenceProducer_F sequenceProducer -); - -/*! ZSTD_CCtxParams_registerSequenceProducer() : - * Same as ZSTD_registerSequenceProducer(), but operates on ZSTD_CCtx_params. - * This is used for accurate size estimation with ZSTD_estimateCCtxSize_usingCCtxParams(), - * which is needed when creating a ZSTD_CCtx with ZSTD_initStaticCCtx(). - * - * If you are using the external sequence producer API in a scenario where ZSTD_initStaticCCtx() - * is required, then this function is for you. Otherwise, you probably don't need it. - * - * See tests/zstreamtest.c for example usage. */ -ZSTDLIB_STATIC_API void -ZSTD_CCtxParams_registerSequenceProducer( - ZSTD_CCtx_params* params, - void* sequenceProducerState, - ZSTD_sequenceProducer_F sequenceProducer -); - - -/********************************************************************* -* Buffer-less and synchronous inner streaming functions (DEPRECATED) -* -* This API is deprecated, and will be removed in a future version. -* It allows streaming (de)compression with user allocated buffers. -* However, it is hard to use, and not as well tested as the rest of -* our API. -* -* Please use the normal streaming API instead: ZSTD_compressStream2, -* and ZSTD_decompressStream. -* If there is functionality that you need, but it doesn't provide, -* please open an issue on our GitHub. -********************************************************************* */ - -/** - Buffer-less streaming compression (synchronous mode) - - A ZSTD_CCtx object is required to track streaming operations. - Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. - ZSTD_CCtx object can be reused multiple times within successive compression operations. - - Start by initializing a context. - Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression. - - Then, consume your input using ZSTD_compressContinue(). - There are some important considerations to keep in mind when using this advanced function : - - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. - - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. - - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. - Worst case evaluation is provided by ZSTD_compressBound(). - ZSTD_compressContinue() doesn't guarantee recover after a failed compression. - - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). - It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) - - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. - In which case, it will "discard" the relevant memory section from its history. - - Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. - It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. - Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. - - `ZSTD_CCtx` object can be reused (ZSTD_compressBegin()) to compress again. -*/ - -/*===== Buffer-less streaming compression functions =====*/ -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ - -ZSTD_DEPRECATED("This function will likely be removed in a future release. It is misleading and has very limited utility.") -ZSTDLIB_STATIC_API -size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The buffer-less API is deprecated in favor of the normal streaming API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - -/* The ZSTD_compressBegin_advanced() and ZSTD_compressBegin_usingCDict_advanced() are now DEPRECATED and will generate a compiler warning */ -ZSTD_DEPRECATED("use advanced API to access custom parameters") -ZSTDLIB_STATIC_API -size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ -ZSTD_DEPRECATED("use advanced API to access custom parameters") -ZSTDLIB_STATIC_API -size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ -/** - Buffer-less streaming decompression (synchronous mode) - - A ZSTD_DCtx object is required to track streaming operations. - Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. - A ZSTD_DCtx object can be reused multiple times. - - First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). - Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. - Data fragment must be large enough to ensure successful decoding. - `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. - result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. - >0 : `srcSize` is too small, please provide at least result bytes on next attempt. - errorCode, which can be tested using ZSTD_isError(). - - It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, - such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). - Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. - As a consequence, check that values remain within valid application range. - For example, do not allocate memory blindly, check that `windowSize` is within expectation. - Each application can set its own limits, depending on local restrictions. - For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. - - ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. - ZSTD_decompressContinue() is very sensitive to contiguity, - if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, - or that previous contiguous segment is large enough to properly handle maximum back-reference distance. - There are multiple ways to guarantee this condition. - - The most memory efficient way is to use a round buffer of sufficient size. - Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), - which can return an error code if required value is too large for current system (in 32-bits mode). - In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, - up to the moment there is not enough room left in the buffer to guarantee decoding another full block, - which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. - At which point, decoding can resume from the beginning of the buffer. - Note that already decoded data stored in the buffer should be flushed before being overwritten. - - There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. - - Finally, if you control the compression process, you can also ignore all buffer size rules, - as long as the encoder and decoder progress in "lock-step", - aka use exactly the same buffer sizes, break contiguity at the same place, etc. - - Once buffers are setup, start decompression, with ZSTD_decompressBegin(). - If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). - - Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. - ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). - ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. - - result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). - It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. - It can also be an error code, which can be tested with ZSTD_isError(). - - A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. - Context can then be reset to start a new decompression. - - Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). - This information is not required to properly decode a frame. - - == Special case : skippable frames == - - Skippable frames allow integration of user-defined data into a flow of concatenated frames. - Skippable frames will be ignored (skipped) by decompressor. - The format of skippable frames is as follows : - a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F - b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits - c) Frame Content - any content (User Data) of length equal to Frame Size - For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. - For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. -*/ - -/*===== Buffer-less streaming decompression functions =====*/ - -ZSTDLIB_STATIC_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ - -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_STATIC_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); - -ZSTDLIB_STATIC_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); -ZSTDLIB_STATIC_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - -/* misc */ -ZSTD_DEPRECATED("This function will likely be removed in the next minor release. It is misleading and has very limited utility.") -ZSTDLIB_STATIC_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); -typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; -ZSTDLIB_STATIC_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); - - - - -/* ========================================= */ -/** Block level API (DEPRECATED) */ -/* ========================================= */ - -/*! - - This API is deprecated in favor of the regular compression API. - You can get the frame header down to 2 bytes by setting: - - ZSTD_c_format = ZSTD_f_zstd1_magicless - - ZSTD_c_contentSizeFlag = 0 - - ZSTD_c_checksumFlag = 0 - - ZSTD_c_dictIDFlag = 0 - - This API is not as well tested as our normal API, so we recommend not using it. - We will be removing it in a future version. If the normal API doesn't provide - the functionality you need, please open a GitHub issue. - - Block functions produce and decode raw zstd blocks, without frame metadata. - Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). - But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. - - A few rules to respect : - - Compressing and decompressing require a context structure - + Use ZSTD_createCCtx() and ZSTD_createDCtx() - - It is necessary to init context before starting - + compression : any ZSTD_compressBegin*() variant, including with dictionary - + decompression : any ZSTD_decompressBegin*() variant, including with dictionary - - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB - + If input is larger than a block size, it's necessary to split input data into multiple blocks - + For inputs larger than a single block, consider using regular ZSTD_compress() instead. - Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. - - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! - ===> In which case, nothing is produced into `dst` ! - + User __must__ test for such outcome and deal directly with uncompressed data - + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. - Doing so would mess up with statistics history, leading to potential data corruption. - + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! - + In case of multiple successive blocks, should some of them be uncompressed, - decoder must be informed of their existence in order to follow proper history. - Use ZSTD_insertBlock() for such a case. -*/ - -/*===== Raw zstd block functions =====*/ -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -ZSTD_DEPRECATED("The block API is deprecated in favor of the normal compression API. See docs.") -ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ - -#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zstd/common/allocations.h b/src/duckdb/third_party/zstd/include/zstd/common/allocations.h deleted file mode 100644 index 0bb1506b9..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/allocations.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* This file provides custom allocation primitives - */ -#ifndef ZSTD_ALLOCATIONS_H -#define ZSTD_ALLOCATIONS_H - -#define ZSTD_DEPS_NEED_MALLOC -#include "zstd/common/zstd_deps.h" /* ZSTD_malloc, ZSTD_calloc, ZSTD_free, ZSTD_memset */ - -#include "zstd/common/compiler.h" /* MEM_STATIC */ -#define ZSTD_STATIC_LINKING_ONLY -#include "zstd.h" /* ZSTD_customMem */ - -namespace duckdb_zstd { - -/* custom memory allocation functions */ - -MEM_STATIC void* ZSTD_customMalloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) - return customMem.customAlloc(customMem.opaque, size); - return ZSTD_malloc(size); -} - -MEM_STATIC void* ZSTD_customCalloc(size_t size, ZSTD_customMem customMem) -{ - if (customMem.customAlloc) { - /* calloc implemented as malloc+memset; - * not as efficient as calloc, but next best guess for custom malloc */ - void* const ptr = customMem.customAlloc(customMem.opaque, size); - ZSTD_memset(ptr, 0, size); - return ptr; - } - return ZSTD_calloc(1, size); -} - -MEM_STATIC void ZSTD_customFree(void* ptr, ZSTD_customMem customMem) -{ - if (ptr!=NULL) { - if (customMem.customFree) - customMem.customFree(customMem.opaque, ptr); - else - ZSTD_free(ptr); - } -} - -} // namespace duckdb_zstd - -#endif /* ZSTD_ALLOCATIONS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/bits.h b/src/duckdb/third_party/zstd/include/zstd/common/bits.h deleted file mode 100644 index ecdf916dc..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/bits.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_BITS_H -#define ZSTD_BITS_H - -#include "zstd/common/mem.h" - -namespace duckdb_zstd { - -MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) -{ - assert(val != 0); - { - static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, - 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, - 26, 12, 18, 6, 11, 5, 10, 9}; - return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; - } -} - -MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) -{ - assert(val != 0); -# if defined(_MSC_VER) -# if STATIC_BMI2 == 1 - return (unsigned)_tzcnt_u32(val); -# else - if (val != 0) { - unsigned long r; - _BitScanForward(&r, val); - return (unsigned)r; - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)__builtin_ctz(val); -# else - return ZSTD_countTrailingZeros32_fallback(val); -# endif -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { - assert(val != 0); - { - static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31}; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; - } -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) -{ - assert(val != 0); -# if defined(_MSC_VER) -# if STATIC_BMI2 == 1 - return (unsigned)_lzcnt_u32(val); -# else - if (val != 0) { - unsigned long r; - _BitScanReverse(&r, val); - return (unsigned)(31 - r); - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)__builtin_clz(val); -# else - return ZSTD_countLeadingZeros32_fallback(val); -# endif -} - -MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) -{ - assert(val != 0); -# if defined(_MSC_VER) && defined(_WIN64) -# if STATIC_BMI2 == 1 - return (unsigned)_tzcnt_u64(val); -# else - if (val != 0) { - unsigned long r; - _BitScanForward64(&r, val); - return (unsigned)r; - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) - return (unsigned)__builtin_ctzll(val); -# else - { - U32 mostSignificantWord = (U32)(val >> 32); - U32 leastSignificantWord = (U32)val; - if (leastSignificantWord == 0) { - return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); - } else { - return ZSTD_countTrailingZeros32(leastSignificantWord); - } - } -# endif -} - -MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) -{ - assert(val != 0); -# if defined(_MSC_VER) && defined(_WIN64) -# if STATIC_BMI2 == 1 - return (unsigned)_lzcnt_u64(val); -# else - if (val != 0) { - unsigned long r; - _BitScanReverse64(&r, val); - return (unsigned)(63 - r); - } else { - /* Should not reach this code path */ - __assume(0); - } -# endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) - return (unsigned)(__builtin_clzll(val)); -# else - { - U32 mostSignificantWord = (U32)(val >> 32); - U32 leastSignificantWord = (U32)val; - if (mostSignificantWord == 0) { - return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); - } else { - return ZSTD_countLeadingZeros32(mostSignificantWord); - } - } -# endif -} - -MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) -{ - if (MEM_isLittleEndian()) { - if (MEM_64bits()) { - return ZSTD_countTrailingZeros64((U64)val) >> 3; - } else { - return ZSTD_countTrailingZeros32((U32)val) >> 3; - } - } else { /* Big Endian CPU */ - if (MEM_64bits()) { - return ZSTD_countLeadingZeros64((U64)val) >> 3; - } else { - return ZSTD_countLeadingZeros32((U32)val) >> 3; - } - } -} - -MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ -{ - assert(val != 0); - return 31 - ZSTD_countLeadingZeros32(val); -} - -/* ZSTD_rotateRight_*(): - * Rotates a bitfield to the right by "count" bits. - * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts - */ -MEM_STATIC -U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { - assert(count < 64); - count &= 0x3F; /* for fickle pattern recognition */ - return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); -} - -MEM_STATIC -U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { - assert(count < 32); - count &= 0x1F; /* for fickle pattern recognition */ - return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); -} - -MEM_STATIC -U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { - assert(count < 16); - count &= 0x0F; /* for fickle pattern recognition */ - return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); -} - -} // namespace duckdb_zstd - -#endif /* ZSTD_BITS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h b/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h index 2b1624295..653074666 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/bitstream.h @@ -1,7 +1,7 @@ /* ****************************************************************** * bitstream * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -27,17 +27,15 @@ #include "zstd/common/compiler.h" /* UNLIKELY() */ #include "zstd/common/debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ #include "zstd/common/error_private.h" /* error codes and messages */ -#include "zstd/common/bits.h" /* ZSTD_highbit32 */ + /*========================================= * Target specific =========================================*/ -#ifndef ZSTD_NO_INTRINSICS -# if (defined(__BMI__) || defined(__BMI2__)) && defined(__GNUC__) -# include /* support for bextr (experimental)/bzhi */ -# elif defined(__ICCARM__) -# include -# endif +#if defined(__BMI__) && defined(__GNUC__) +# include /* support for bextr (experimental) */ +#elif defined(__ICCARM__) +# include #endif #define STREAM_ACCUMULATOR_MIN_32 25 @@ -87,20 +85,19 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); /*-******************************************** * bitStream decoding API (read backward) **********************************************/ -typedef size_t BitContainerType; typedef struct { - BitContainerType bitContainer; + size_t bitContainer; unsigned bitsConsumed; const char* ptr; const char* start; const char* limitPtr; } BIT_DStream_t; -typedef enum { BIT_DStream_unfinished = 0, /* fully refilled */ - BIT_DStream_endOfBuffer = 1, /* still some bits left in bitstream */ - BIT_DStream_completed = 2, /* bitstream entirely consumed, bit-exact */ - BIT_DStream_overflow = 3 /* user requested more bits than present in bitstream */ - } BIT_DStream_status; /* result of BIT_reloadDStream() */ +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); @@ -110,7 +107,7 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); /* Start by invoking BIT_initDStream(). * A chunk of the bitStream is then stored into a local register. -* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (BitContainerType). +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). * You can then retrieve bitFields stored into the local register, **in reverse order**. * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. @@ -131,6 +128,38 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); /* faster, but works only if nbBits >= 1 */ + + +/*-************************************************************** +* Internal functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (U32 val) +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + return _BitScanReverse ( &r, val ) ? (unsigned)r : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; +# endif + } +} + /*===== Local Constants =====*/ static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, @@ -160,26 +189,16 @@ MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, return 0; } -FORCE_INLINE_TEMPLATE size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) -{ -#if defined(STATIC_BMI2) && STATIC_BMI2 == 1 && !defined(ZSTD_NO_INTRINSICS) - return _bzhi_u64(bitContainer, nbBits); -#else - assert(nbBits < BIT_MASK_SIZE); - return bitContainer & BIT_mask[nbBits]; -#endif -} - /*! BIT_addBits() : * can add up to 31 bits into `bitC`. * Note : does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { - DEBUG_STATIC_ASSERT(BIT_MASK_SIZE == 32); + MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); assert(nbBits < BIT_MASK_SIZE); assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); - bitC->bitContainer |= BIT_getLowerBits(value, nbBits) << bitC->bitPos; + bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; bitC->bitPos += nbBits; } @@ -249,7 +268,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { - if (srcSize < 1) { ZSTD_memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } bitD->start = (const char*)srcBuffer; bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); @@ -258,35 +277,35 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); bitD->bitContainer = MEM_readLEST(bitD->ptr); { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } } else { bitD->ptr = bitD->start; bitD->bitContainer = *(const BYTE*)(bitD->start); switch(srcSize) { - case 7: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); - ZSTD_FALLTHROUGH; + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); + /* fall-through */ - case 6: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); - ZSTD_FALLTHROUGH; + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); + /* fall-through */ - case 5: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); - ZSTD_FALLTHROUGH; + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); + /* fall-through */ - case 4: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[3]) << 24; - ZSTD_FALLTHROUGH; + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; + /* fall-through */ - case 3: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[2]) << 16; - ZSTD_FALLTHROUGH; + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; + /* fall-through */ - case 2: bitD->bitContainer += (BitContainerType)(((const BYTE*)(srcBuffer))[1]) << 8; - ZSTD_FALLTHROUGH; + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; + /* fall-through */ default: break; } { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; - bitD->bitsConsumed = lastByte ? 8 - ZSTD_highbit32(lastByte) : 0; + bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ } bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; @@ -295,26 +314,23 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -FORCE_INLINE_TEMPLATE size_t BIT_getUpperBits(BitContainerType bitContainer, U32 const start) +MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) { return bitContainer >> start; } -FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits(BitContainerType bitContainer, U32 const start, U32 const nbBits) +MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) { U32 const regMask = sizeof(bitContainer)*8 - 1; /* if start > regMask, bitstream is corrupted, and result is undefined */ assert(nbBits < BIT_MASK_SIZE); - /* x86 transform & ((1 << nbBits) - 1) to bzhi instruction, it is better - * than accessing memory. When bmi2 instruction is not present, we consider - * such cpus old (pre-Haswell, 2013) and their performance is not of that - * importance. - */ -#if defined(__x86_64__) || defined(_M_X86) - return (bitContainer >> (start & regMask)) & ((((U64)1) << nbBits) - 1); -#else return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; -#endif +} + +MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) +{ + assert(nbBits < BIT_MASK_SIZE); + return bitContainer & BIT_mask[nbBits]; } /*! BIT_lookBits() : @@ -323,7 +339,7 @@ FORCE_INLINE_TEMPLATE size_t BIT_getMiddleBits(BitContainerType bitContainer, U3 * On 32-bits, maxNbBits==24. * On 64-bits, maxNbBits==56. * @return : value extracted */ -FORCE_INLINE_TEMPLATE size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) { /* arbitrate between double-shift and shift+mask */ #if 1 @@ -346,7 +362,7 @@ MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); } -FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) { bitD->bitsConsumed += nbBits; } @@ -355,7 +371,7 @@ FORCE_INLINE_TEMPLATE void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) * Read (consume) next n bits from local register and update. * Pay attention to not read more than nbBits contained into local register. * @return : extracted value. */ -FORCE_INLINE_TEMPLATE size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBits(bitD, nbBits); BIT_skipBits(bitD, nbBits); @@ -363,7 +379,7 @@ FORCE_INLINE_TEMPLATE size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) } /*! BIT_readBitsFast() : - * unsafe version; only works if nbBits >= 1 */ + * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) { size_t const value = BIT_lookBitsFast(bitD, nbBits); @@ -372,21 +388,6 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) return value; } -/*! BIT_reloadDStream_internal() : - * Simple variant of BIT_reloadDStream(), with two conditions: - * 1. bitstream is valid : bitsConsumed <= sizeof(bitD->bitContainer)*8 - * 2. look window is valid after shifted down : bitD->ptr >= bitD->start - */ -MEM_STATIC BIT_DStream_status BIT_reloadDStream_internal(BIT_DStream_t* bitD) -{ - assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); - bitD->ptr -= bitD->bitsConsumed >> 3; - assert(bitD->ptr >= bitD->start); - bitD->bitsConsumed &= 7; - bitD->bitContainer = MEM_readLEST(bitD->ptr); - return BIT_DStream_unfinished; -} - /*! BIT_reloadDStreamFast() : * Similar to BIT_reloadDStream(), but with two differences: * 1. bitsConsumed <= sizeof(bitD->bitContainer)*8 must hold! @@ -397,35 +398,31 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStreamFast(BIT_DStream_t* bitD) { if (UNLIKELY(bitD->ptr < bitD->limitPtr)) return BIT_DStream_overflow; - return BIT_reloadDStream_internal(bitD); + assert(bitD->bitsConsumed <= sizeof(bitD->bitContainer)*8); + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; } /*! BIT_reloadDStream() : * Refill `bitD` from buffer previously set in BIT_initDStream() . - * This function is safe, it guarantees it will not never beyond src buffer. + * This function is safe, it guarantees it will not read beyond src buffer. * @return : status of `BIT_DStream_t` internal register. * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ -FORCE_INLINE_TEMPLATE BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) { - /* note : once in overflow mode, a bitstream remains in this mode until it's reset */ - if (UNLIKELY(bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8))) { - static const BitContainerType zeroFilled = 0; - bitD->ptr = (const char*)&zeroFilled; /* aliasing is allowed for char */ - /* overflow detected, erroneous scenario or end of stream: no update */ + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ return BIT_DStream_overflow; - } - - assert(bitD->ptr >= bitD->start); if (bitD->ptr >= bitD->limitPtr) { - return BIT_reloadDStream_internal(bitD); + return BIT_reloadDStreamFast(bitD); } if (bitD->ptr == bitD->start) { - /* reached end of bitStream => no update */ if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; return BIT_DStream_completed; } - /* start < ptr < limitPtr => cautious update */ + /* start < ptr < limitPtr */ { U32 nbBytes = bitD->bitsConsumed >> 3; BIT_DStream_status result = BIT_DStream_unfinished; if (bitD->ptr - nbBytes < bitD->start) { @@ -447,6 +444,6 @@ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); } -} // namespace duckdb_zstd +} #endif /* BITSTREAM_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/compiler.h b/src/duckdb/third_party/zstd/include/zstd/common/compiler.h index f880f0b11..b94dbad13 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/compiler.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,10 +11,6 @@ #ifndef ZSTD_COMPILER_H #define ZSTD_COMPILER_H -#include - -#include "zstd/common/portability_macros.h" - /*-******************************************************* * Compiler specifics *********************************************************/ @@ -42,30 +38,12 @@ #endif -/** - On MSVC qsort requires that functions passed into it use the __cdecl calling conversion(CC). - This explicitly marks such functions as __cdecl so that the code will still compile - if a CC other than __cdecl has been made the default. -*/ -#if defined(_MSC_VER) -# define WIN_CDECL __cdecl -#else -# define WIN_CDECL -#endif - -/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ -#if defined(__GNUC__) -# define UNUSED_ATTR __attribute__((unused)) -#else -# define UNUSED_ATTR -#endif - /** * FORCE_INLINE_TEMPLATE is used to define C "templates", which take constant * parameters. They must be inlined for the compiler to eliminate the constant * branches. */ -#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR UNUSED_ATTR +#define FORCE_INLINE_TEMPLATE static INLINE_KEYWORD FORCE_INLINE_ATTR /** * HINT_INLINE is used to help the compiler generate better code. It is *not* * used for "templates", so it can be tweaked based on the compilers @@ -80,28 +58,14 @@ #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 && __GNUC__ < 5 # define HINT_INLINE static INLINE_KEYWORD #else -# define HINT_INLINE FORCE_INLINE_TEMPLATE +# define HINT_INLINE static INLINE_KEYWORD FORCE_INLINE_ATTR #endif -/* "soft" inline : - * The compiler is free to select if it's a good idea to inline or not. - * The main objective is to silence compiler warnings - * when a defined function in included but not used. - * - * Note : this macro is prefixed `MEM_` because it used to be provided by `mem.h` unit. - * Updating the prefix is probably preferable, but requires a fairly large codemod, - * since this name is used everywhere. - */ -#ifndef MEM_STATIC /* already defined in Linux Kernel mem.h */ +/* UNUSED_ATTR tells the compiler it is okay if the function is unused. */ #if defined(__GNUC__) -# define MEM_STATIC static __inline UNUSED_ATTR -#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -# define MEM_STATIC static inline -#elif defined(_MSC_VER) -# define MEM_STATIC static __inline +# define UNUSED_ATTR __attribute__((unused)) #else -# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ -#endif +# define UNUSED_ATTR #endif /* force no inlining */ @@ -115,58 +79,67 @@ # endif #endif - /* target attribute */ +#ifndef __has_attribute + #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif #if defined(__GNUC__) || defined(__ICCARM__) # define TARGET_ATTRIBUTE(target) __attribute__((__target__(target))) #else # define TARGET_ATTRIBUTE(target) #endif -/* Target attribute for BMI2 dynamic dispatch. - * Enable lzcnt, bmi, and bmi2. - * We test for bmi1 & bmi2. lzcnt is included in bmi1. +/* Enable runtime BMI2 dispatch based on the CPU. + * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. */ -#define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") +#ifndef DYNAMIC_BMI2 + #if ((defined(__clang__) && __has_attribute(__target__)) \ + || (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (defined(__x86_64__) || defined(_M_X86)) \ + && !defined(__BMI2__) + # define DYNAMIC_BMI2 1 + #else + # define DYNAMIC_BMI2 0 + #endif +#endif /* prefetch * can be disabled, by declaring NO_PREFETCH build macro */ #if defined(NO_PREFETCH) -# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */ -# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */ +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ #else -# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) /* _mm_prefetch() is not defined outside of x86/x64 */ +# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) +# elif defined(__aarch64__) +# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) +# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) -# elif defined(__aarch64__) -# define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0) -# define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0) # else -# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */ -# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */ +# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */ +# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */ # endif #endif /* NO_PREFETCH */ #define CACHELINE_SIZE 64 -#define PREFETCH_AREA(p, s) \ - do { \ - const char* const _ptr = (const char*)(p); \ - size_t const _size = (size_t)(s); \ - size_t _pos; \ - for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ - PREFETCH_L2(_ptr + _pos); \ - } \ - } while (0) +#define PREFETCH_AREA(p, s) { \ + const char* const _ptr = (const char*)(p); \ + size_t const _size = (size_t)(s); \ + size_t _pos; \ + for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \ + PREFETCH_L2(_ptr + _pos); \ + } \ +} /* vectorization - * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax, - * and some compilers, like Intel ICC and MCST LCC, do not support it at all. */ -#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) && !defined(__LCC__) + * older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax */ +#if !defined(__INTEL_COMPILER) && !defined(__clang__) && defined(__GNUC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || (__GNUC__ >= 5) # define DONT_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) # else @@ -182,188 +155,19 @@ * and clang, please do. */ #if defined(__GNUC__) +#ifndef LIKELY #define LIKELY(x) (__builtin_expect((x), 1)) -#define UNLIKELY(x) (__builtin_expect((x), 0)) -#else -#define LIKELY(x) (x) -#define UNLIKELY(x) (x) -#endif - -#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))) -# define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0) -#else -# define ZSTD_UNREACHABLE do { assert(0); } while (0) -#endif - -/* disable warnings */ -#ifdef _MSC_VER /* Visual Studio */ -# include /* For Visual 2005 */ -# pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4204) /* disable: C4204: non-constant aggregate initializer */ -# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ -# pragma warning(disable : 4324) /* disable: C4324: padded structure */ #endif - -/*Like DYNAMIC_BMI2 but for compile time determination of BMI2 support*/ -#ifndef STATIC_BMI2 -# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) -# ifdef __AVX2__ //MSVC does not have a BMI2 specific flag, but every CPU that supports AVX2 also supports BMI2 -# define STATIC_BMI2 1 -# endif -# elif defined(__BMI2__) && defined(__x86_64__) && defined(__GNUC__) -# define STATIC_BMI2 1 -# endif -#endif - -#ifndef STATIC_BMI2 - #define STATIC_BMI2 0 -#endif - -/* compile time determination of SIMD support */ -#if !defined(ZSTD_NO_INTRINSICS) -# if defined(__SSE2__) || defined(_M_AMD64) || (defined (_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) -# define ZSTD_ARCH_X86_SSE2 -# endif -# if defined(__ARM_NEON) || defined(_M_ARM64) -# define ZSTD_ARCH_ARM_NEON -# endif -# -# if defined(ZSTD_ARCH_X86_SSE2) -# include -# elif defined(ZSTD_ARCH_ARM_NEON) -# include -# endif -#endif - -/* C-language Attributes are added in C23. */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute) -# define ZSTD_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) -#else -# define ZSTD_HAS_C_ATTRIBUTE(x) 0 +#ifndef UNLIKELY +#define UNLIKELY(x) (__builtin_expect((x), 0)) #endif - -/* Only use C++ attributes in C++. Some compilers report support for C++ - * attributes when compiling with C. - */ -#if defined(__cplusplus) && defined(__has_cpp_attribute) -# define ZSTD_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else -# define ZSTD_HAS_CPP_ATTRIBUTE(x) 0 +#ifndef LIKELY +#define LIKELY(x) (x) #endif - -/* Define ZSTD_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute. - * - C23: https://en.cppreference.com/w/c/language/attributes/fallthrough - * - CPP17: https://en.cppreference.com/w/cpp/language/attributes/fallthrough - * - Else: __attribute__((__fallthrough__)) - */ -#ifndef ZSTD_FALLTHROUGH -# define ZSTD_FALLTHROUGH +#ifndef UNLIKELY +#define UNLIKELY(x) (x) #endif - -/*-************************************************************** -* Alignment check -*****************************************************************/ - -/* this test was initially positioned in mem.h, - * but this file is removed (or replaced) for linux kernel - * so it's now hosted in compiler.h, - * which remains valid for both user & kernel spaces. - */ - -#ifndef ZSTD_ALIGNOF -# if defined(__GNUC__) || defined(_MSC_VER) -/* covers gcc, clang & MSVC */ -/* note : this section must come first, before C11, - * due to a limitation in the kernel source generator */ -# define ZSTD_ALIGNOF(T) __alignof(T) - -# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -/* C11 support */ -# include -# define ZSTD_ALIGNOF(T) alignof(T) - -# else -/* No known support for alignof() - imperfect backup */ -# define ZSTD_ALIGNOF(T) (sizeof(void*) < sizeof(T) ? sizeof(void*) : sizeof(T)) - -# endif -#endif /* ZSTD_ALIGNOF */ - -/*-************************************************************** -* Sanitizer -*****************************************************************/ - -/** - * Zstd relies on pointer overflow in its decompressor. - * We add this attribute to functions that rely on pointer overflow. - */ -#ifndef ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -# if __has_attribute(no_sanitize) -# if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 8 - /* gcc < 8 only has signed-integer-overlow which triggers on pointer overflow */ -# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("signed-integer-overflow"))) -# else - /* older versions of clang [3.7, 5.0) will warn that pointer-overflow is ignored. */ -# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR __attribute__((no_sanitize("pointer-overflow"))) -# endif -# else -# define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -# endif #endif -namespace duckdb_zstd { - -/** - * Helper function to perform a wrapped pointer difference without trigging - * UBSAN. - * - * @returns lhs - rhs with wrapping - */ -MEM_STATIC -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -ptrdiff_t ZSTD_wrappedPtrDiff(unsigned char const* lhs, unsigned char const* rhs) -{ - return lhs - rhs; -} - -/** - * Helper function to perform a wrapped pointer add without triggering UBSAN. - * - * @return ptr + add with wrapping - */ -MEM_STATIC -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -unsigned char const* ZSTD_wrappedPtrAdd(unsigned char const* ptr, ptrdiff_t add) -{ - return ptr + add; -} - -/** - * Helper function to perform a wrapped pointer subtraction without triggering - * UBSAN. - * - * @return ptr - sub with wrapping - */ -MEM_STATIC -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -unsigned char const* ZSTD_wrappedPtrSub(unsigned char const* ptr, ptrdiff_t sub) -{ - return ptr - sub; -} - -/** - * Helper function to add to a pointer that works around C's undefined behavior - * of adding 0 to NULL. - * - * @returns `ptr + add` except it defines `NULL + 0 == NULL`. - */ -MEM_STATIC -unsigned char* ZSTD_maybeNullPtrAdd(unsigned char* ptr, ptrdiff_t add) -{ - return add > 0 ? ptr + add : ptr; -} - -} // namespace duckdb_zstd - #endif /* ZSTD_COMPILER_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/cpu.h b/src/duckdb/third_party/zstd/include/zstd/common/cpu.h deleted file mode 100644 index 892f9851d..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/cpu.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_COMMON_CPU_H -#define ZSTD_COMMON_CPU_H - -/** - * Implementation taken from folly/CpuId.h - * https://github.com/facebook/folly/blob/master/folly/CpuId.h - */ - -#include "zstd/common/mem.h" - -#ifdef _MSC_VER -#include -#endif - -namespace duckdb_zstd { - -typedef struct { - U32 f1c; - U32 f1d; - U32 f7b; - U32 f7c; -} ZSTD_cpuid_t; - -MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { - U32 f1c = 0; - U32 f1d = 0; - U32 f7b = 0; - U32 f7c = 0; -#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) -#if !defined(__clang__) - int reg[4]; - __cpuid((int*)reg, 0); - { - int const n = reg[0]; - if (n >= 1) { - __cpuid((int*)reg, 1); - f1c = (U32)reg[2]; - f1d = (U32)reg[3]; - } - if (n >= 7) { - __cpuidex((int*)reg, 7, 0); - f7b = (U32)reg[1]; - f7c = (U32)reg[2]; - } - } -#else - /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in - * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs - * to due to being a reserved register. So in that case, do the `cpuid` - * ourselves. Clang supports inline assembly anyway. - */ - U32 n; - __asm__( - "pushq %%rbx\n\t" - "cpuid\n\t" - "popq %%rbx\n\t" - : "=a"(n) - : "a"(0) - : "rcx", "rdx"); - if (n >= 1) { - U32 f1a; - __asm__( - "pushq %%rbx\n\t" - "cpuid\n\t" - "popq %%rbx\n\t" - : "=a"(f1a), "=c"(f1c), "=d"(f1d) - : "a"(1) - :); - } - if (n >= 7) { - __asm__( - "pushq %%rbx\n\t" - "cpuid\n\t" - "movq %%rbx, %%rax\n\t" - "popq %%rbx" - : "=a"(f7b), "=c"(f7c) - : "a"(7), "c"(0) - : "rdx"); - } -#endif -#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) - /* The following block like the normal cpuid branch below, but gcc - * reserves ebx for use of its pic register so we must specially - * handle the save and restore to avoid clobbering the register - */ - U32 n; - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - : "=a"(n) - : "a"(0) - : "ecx", "edx"); - if (n >= 1) { - U32 f1a; - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - : "=a"(f1a), "=c"(f1c), "=d"(f1d) - : "a"(1)); - } - if (n >= 7) { - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "movl %%ebx, %%eax\n\t" - "popl %%ebx" - : "=a"(f7b), "=c"(f7c) - : "a"(7), "c"(0) - : "edx"); - } -#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) - U32 n; - __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); - if (n >= 1) { - U32 f1a; - __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); - } - if (n >= 7) { - U32 f7a; - __asm__("cpuid" - : "=a"(f7a), "=b"(f7b), "=c"(f7c) - : "a"(7), "c"(0) - : "edx"); - } -#endif - { - ZSTD_cpuid_t cpuid; - cpuid.f1c = f1c; - cpuid.f1d = f1d; - cpuid.f7b = f7b; - cpuid.f7c = f7c; - return cpuid; - } -} - -#define X(name, r, bit) \ - MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ - return ((cpuid.r) & (1U << bit)) != 0; \ - } - -/* cpuid(1): Processor Info and Feature Bits. */ -#define C(name, bit) X(name, f1c, bit) - C(sse3, 0) - C(pclmuldq, 1) - C(dtes64, 2) - C(monitor, 3) - C(dscpl, 4) - C(vmx, 5) - C(smx, 6) - C(eist, 7) - C(tm2, 8) - C(ssse3, 9) - C(cnxtid, 10) - C(fma, 12) - C(cx16, 13) - C(xtpr, 14) - C(pdcm, 15) - C(pcid, 17) - C(dca, 18) - C(sse41, 19) - C(sse42, 20) - C(x2apic, 21) - C(movbe, 22) - C(popcnt, 23) - C(tscdeadline, 24) - C(aes, 25) - C(xsave, 26) - C(osxsave, 27) - C(avx, 28) - C(f16c, 29) - C(rdrand, 30) -#undef C -#define D(name, bit) X(name, f1d, bit) - D(fpu, 0) - D(vme, 1) - D(de, 2) - D(pse, 3) - D(tsc, 4) - D(msr, 5) - D(pae, 6) - D(mce, 7) - D(cx8, 8) - D(apic, 9) - D(sep, 11) - D(mtrr, 12) - D(pge, 13) - D(mca, 14) - D(cmov, 15) - D(pat, 16) - D(pse36, 17) - D(psn, 18) - D(clfsh, 19) - D(ds, 21) - D(acpi, 22) - D(mmx, 23) - D(fxsr, 24) - D(sse, 25) - D(sse2, 26) - D(ss, 27) - D(htt, 28) - D(tm, 29) - D(pbe, 31) -#undef D - -/* cpuid(7): Extended Features. */ -#define B(name, bit) X(name, f7b, bit) - B(bmi1, 3) - B(hle, 4) - B(avx2, 5) - B(smep, 7) - B(bmi2, 8) - B(erms, 9) - B(invpcid, 10) - B(rtm, 11) - B(mpx, 14) - B(avx512f, 16) - B(avx512dq, 17) - B(rdseed, 18) - B(adx, 19) - B(smap, 20) - B(avx512ifma, 21) - B(pcommit, 22) - B(clflushopt, 23) - B(clwb, 24) - B(avx512pf, 26) - B(avx512er, 27) - B(avx512cd, 28) - B(sha, 29) - B(avx512bw, 30) - B(avx512vl, 31) -#undef B -#define C(name, bit) X(name, f7c, bit) - C(prefetchwt1, 0) - C(avx512vbmi, 1) -#undef C - -#undef X - -} // namespace duckdb_zstd - -#endif /* ZSTD_COMMON_CPU_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/debug.h b/src/duckdb/third_party/zstd/include/zstd/common/debug.h index 559897771..ac6224888 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/debug.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/debug.h @@ -1,7 +1,7 @@ /* ****************************************************************** * debug * Part of FSE library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -32,7 +32,10 @@ #ifndef DEBUG_H_12987983217 #define DEBUG_H_12987983217 -#include "zstd/common/zstd_deps.h" // DuckDB: added here +#if defined (__cplusplus) +extern "C" { +#endif + /* static assert is triggered at compile time, leaving no runtime artefact. * static assert only works with compile-time constants. @@ -48,6 +51,15 @@ #endif +/* DEBUGFILE can be defined externally, + * typically through compiler command line. + * note : currently useless. + * Value must be stderr or stdout */ +#ifndef DEBUGFILE +# define DEBUGFILE stderr +#endif + + /* recommended values for DEBUGLEVEL : * 0 : release mode, no debug, all run-time checks disabled * 1 : enables assert() only, no display @@ -64,8 +76,7 @@ */ #if (DEBUGLEVEL>=1) -# define ZSTD_DEPS_NEED_ASSERT -// # include "zstd/common/zstd_deps.h" // DuckDB: comment out otherwise amalgamation won't be happy +# include #else # ifndef assert /* assert may be already defined, due to prior #include */ # define assert(condition) ((void)0) /* disable assert (default) */ @@ -73,11 +84,7 @@ #endif #if (DEBUGLEVEL>=2) -# define ZSTD_DEPS_NEED_IO -// # include "zstd/common/zstd_deps.h" // DuckDB: comment out otherwise amalgamation won't be happy - -namespace duckdb_zstd { - +# include extern int g_debuglevel; /* the variable is only declared, it actually lives in debug.c, and is shared by the whole process. @@ -85,30 +92,23 @@ extern int g_debuglevel; /* the variable is only declared, It's useful when enabling very verbose levels on selective conditions (such as position in src) */ -# define RAWLOG(l, ...) \ - do { \ - if (l<=g_debuglevel) { \ - ZSTD_DEBUG_PRINT(__VA_ARGS__); \ - } \ - } while (0) - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define LINE_AS_STRING TOSTRING(__LINE__) - -# define DEBUGLOG(l, ...) \ - do { \ - if (l<=g_debuglevel) { \ - ZSTD_DEBUG_PRINT(__FILE__ ":" LINE_AS_STRING ": " __VA_ARGS__); \ - ZSTD_DEBUG_PRINT(" \n"); \ - } \ - } while (0) +# define RAWLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + fprintf(stderr, __VA_ARGS__); \ + } } +# define DEBUGLOG(l, ...) { \ + if (l<=g_debuglevel) { \ + fprintf(stderr, __FILE__ ": " __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } +#else +# define RAWLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif -} // namespace duckdb_zstd -#else -# define RAWLOG(l, ...) do { } while (0) /* disabled */ -# define DEBUGLOG(l, ...) do { } while (0) /* disabled */ +#if defined (__cplusplus) +} #endif #endif /* DEBUG_H_12987983217 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/error_private.h b/src/duckdb/third_party/zstd/include/zstd/common/error_private.h index 7fe7701de..b1af95d12 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/error_private.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/error_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,13 +16,10 @@ /* **************************************** * Dependencies ******************************************/ -#include "zstd_errors.h" /* enum list */ -#include "zstd/common/compiler.h" -#include "zstd/common/debug.h" -#include "zstd/common/zstd_deps.h" /* size_t */ +#include /* size_t */ +#include "zstd/common/zstd_errors.h" /* enum list */ namespace duckdb_zstd { - /* **************************************** * Compiler-specific ******************************************/ @@ -36,6 +33,7 @@ namespace duckdb_zstd { # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ #endif + /*-**************************************** * Customization (error_public.h) ******************************************/ @@ -55,13 +53,8 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } /* check and forward error code */ -#define CHECK_V_F(e, f) \ - size_t const e = f; \ - do { \ - if (ERR_isError(e)) \ - return e; \ - } while (0) -#define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0) +#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e +#define CHECK_F(f) { CHECK_V_F(_var_err__, f); } /*-**************************************** @@ -75,87 +68,6 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) return ERR_getErrorString(ERR_getErrorCode(code)); } -/** - * Ignore: this is an internal helper. - * - * This is a helper function to help force C99-correctness during compilation. - * Under strict compilation modes, variadic macro arguments can't be empty. - * However, variadic function arguments can be. Using a function therefore lets - * us statically check that at least one (string) argument was passed, - * independent of the compilation flags. - */ -static INLINE_KEYWORD UNUSED_ATTR -void _force_has_format_string(const char *format, ...) { - (void)format; } -/** - * Ignore: this is an internal helper. - * - * We want to force this function invocation to be syntactically correct, but - * we don't want to force runtime evaluation of its arguments. - */ -#define _FORCE_HAS_FORMAT_STRING(...) \ - do { \ - if (0) { \ - _force_has_format_string(__VA_ARGS__); \ - } \ - } while (0) - -#define ERR_QUOTE(str) #str - -/** - * Return the specified error if the condition evaluates to true. - * - * In debug modes, prints additional information. - * In order to do that (particularly, printing the conditional that failed), - * this can't just wrap RETURN_ERROR(). - */ -#define RETURN_ERROR_IF(cond, err, ...) \ - do { \ - if (cond) { \ - RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ - __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } \ - } while (0) - -/** - * Unconditionally return the specified error. - * - * In debug modes, prints additional information. - */ -#define RETURN_ERROR(err, ...) \ - do { \ - RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ - __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return ERROR(err); \ - } while(0) - -/** - * If the provided expression evaluates to an error code, returns that error code. - * - * In debug modes, prints additional information. - */ -#define FORWARD_IF_ERROR(err, ...) \ - do { \ - size_t const err_code = (err); \ - if (ERR_isError(err_code)) { \ - RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ - __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ - _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ - RAWLOG(3, ": " __VA_ARGS__); \ - RAWLOG(3, "\n"); \ - return err_code; \ - } \ - } while(0) - -} // namespace duckdb_zstd - #endif /* ERROR_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/fse.h b/src/duckdb/third_party/zstd/include/zstd/common/fse.h index 9df59ff14..6600fee54 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/fse.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/fse.h @@ -1,7 +1,7 @@ /* ****************************************************************** * FSE : Finite State Entropy codec * Public Prototypes declaration - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -12,7 +12,6 @@ * You may select, at your option, one of the above-listed licenses. ****************************************************************** */ - #ifndef FSE_H #define FSE_H @@ -20,11 +19,10 @@ /*-***************************************** * Dependencies ******************************************/ +#include /* size_t, ptrdiff_t */ -#include "zstd/common/zstd_deps.h" /* size_t, ptrdiff_t */ namespace duckdb_zstd { - /*-***************************************** * FSE_PUBLIC_API : control library symbols visibility ******************************************/ @@ -52,6 +50,34 @@ namespace duckdb_zstd { FSE_PUBLIC_API unsigned FSE_versionNumber(void); /**< library version number; to be used when checking dll version */ +/*-**************************************** +* FSE simple functions +******************************************/ +/*! FSE_compress() : + Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. + 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize). + @return : size of compressed data (<= dstCapacity). + Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead. + if FSE_isError(return), compression failed (more details using FSE_getErrorName()) +*/ +FSE_PUBLIC_API size_t FSE_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/*! FSE_decompress(): + Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'dstCapacity'. + @return : size of regenerated data (<= maxDstSize), + or an error code, which can be tested using FSE_isError() . + + ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!! + Why ? : making this distinction requires a header. + Header management is intentionally delegated to the user layer, which can better manage special cases. +*/ +FSE_PUBLIC_API size_t FSE_decompress(void* dst, size_t dstCapacity, + const void* cSrc, size_t cSrcSize); + + /*-***************************************** * Tool functions ******************************************/ @@ -62,6 +88,20 @@ FSE_PUBLIC_API unsigned FSE_isError(size_t code); /* tells if a return FSE_PUBLIC_API const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */ +/*-***************************************** +* FSE advanced functions +******************************************/ +/*! FSE_compress2() : + Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog' + Both parameters can be defined as '0' to mean : use default value + @return : size of compressed data + Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!! + if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression. + if FSE_isError(return), it's an error code. +*/ +FSE_PUBLIC_API size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); + + /*-***************************************** * FSE detailed API ******************************************/ @@ -94,16 +134,10 @@ FSE_PUBLIC_API unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize /*! FSE_normalizeCount(): normalize counts so that sum(count[]) == Power_of_2 (2^tableLog) 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1). - useLowProbCount is a boolean parameter which trades off compressed size for - faster header decoding. When it is set to 1, the compressed data will be slightly - smaller. And when it is set to 0, FSE_readNCount() and FSE_buildDTable() will be - faster. If you are compressing a small amount of data (< 2 KB) then useLowProbCount=0 - is a good default, since header deserialization makes a big speed difference. - Otherwise, useLowProbCount=1 is a good default, since the speed difference is small. @return : tableLog, or an errorCode, which can be tested using FSE_isError() */ FSE_PUBLIC_API size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, - const unsigned* count, size_t srcSize, unsigned maxSymbolValue, unsigned useLowProbCount); + const unsigned* count, size_t srcSize, unsigned maxSymbolValue); /*! FSE_NCountWriteBound(): Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'. @@ -121,6 +155,8 @@ FSE_PUBLIC_API size_t FSE_writeNCount (void* buffer, size_t bufferSize, /*! Constructor and Destructor of FSE_CTable. Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */ typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */ +FSE_PUBLIC_API FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog); +FSE_PUBLIC_API void FSE_freeCTable (FSE_CTable* ct); /*! FSE_buildCTable(): Builds `ct`, which must be already allocated, using FSE_createCTable(). @@ -189,14 +225,23 @@ FSE_PUBLIC_API size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); -/*! FSE_readNCount_bmi2(): - * Same as FSE_readNCount() but pass bmi2=1 when your CPU supports BMI2 and 0 otherwise. - */ -FSE_PUBLIC_API size_t FSE_readNCount_bmi2(short* normalizedCounter, - unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, - const void* rBuffer, size_t rBuffSize, int bmi2); - +/*! Constructor and Destructor of FSE_DTable. + Note that its size depends on 'tableLog' */ typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ +FSE_PUBLIC_API FSE_DTable* FSE_createDTable(unsigned tableLog); +FSE_PUBLIC_API void FSE_freeDTable(FSE_DTable* dt); + +/*! FSE_buildDTable(): + Builds 'dt', which must be already allocated, using FSE_createDTable(). + return : 0, or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! FSE_decompress_usingDTable(): + Decompress compressed source `cSrc` of size `cSrcSize` using `dt` + into `dst` which must be already allocated. + @return : size of regenerated data (necessarily <= `dstCapacity`), + or an errorCode, which can be tested using FSE_isError() */ +FSE_PUBLIC_API size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); /*! Tutorial : @@ -226,412 +271,7 @@ FSE_decompress_usingDTable() result will tell how many bytes were regenerated (< If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) */ -} // namespace duckdb_zstd - -#endif /* FSE_H */ - -#if defined(FSE_STATIC_LINKING_ONLY) && !defined(FSE_H_FSE_STATIC_LINKING_ONLY) -#define FSE_H_FSE_STATIC_LINKING_ONLY - -/* *** Dependency *** */ -#include "zstd/common/bitstream.h" - -namespace duckdb_zstd { - -/* ***************************************** -* Static allocation -*******************************************/ -/* FSE buffer bounds */ -#define FSE_NCOUNTBOUND 512 -#define FSE_BLOCKBOUND(size) ((size) + ((size)>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) -#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ -#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<((maxTableLog)-1)) + (((maxSymbolValue)+1)*2)) -#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<(maxTableLog))) - -/* or use the size to malloc() space directly. Pay attention to alignment restrictions though */ -#define FSE_CTABLE_SIZE(maxTableLog, maxSymbolValue) (FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(FSE_CTable)) -#define FSE_DTABLE_SIZE(maxTableLog) (FSE_DTABLE_SIZE_U32(maxTableLog) * sizeof(FSE_DTable)) - - -/* ***************************************** - * FSE advanced API - ***************************************** */ - -unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus); -/**< same as FSE_optimalTableLog(), which used `minus==2` */ - -size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); -/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ - -/* FSE_buildCTable_wksp() : - * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). - * `wkspSize` must be >= `FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)` of `unsigned`. - * See FSE_buildCTable_wksp() for breakdown of workspace usage. - */ -#define FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog) (((maxSymbolValue + 2) + (1ull << (tableLog)))/2 + sizeof(U64)/sizeof(U32) /* additional 8 bytes for potential table overwrite */) -#define FSE_BUILD_CTABLE_WORKSPACE_SIZE(maxSymbolValue, tableLog) (sizeof(unsigned) * FSE_BUILD_CTABLE_WORKSPACE_SIZE_U32(maxSymbolValue, tableLog)) -size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); - -#define FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) (sizeof(short) * (maxSymbolValue + 1) + (1ULL << maxTableLog) + 8) -#define FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ((FSE_BUILD_DTABLE_WKSP_SIZE(maxTableLog, maxSymbolValue) + sizeof(unsigned) - 1) / sizeof(unsigned)) -FSE_PUBLIC_API size_t FSE_buildDTable_wksp(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); -/**< Same as FSE_buildDTable(), using an externally allocated `workspace` produced with `FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxSymbolValue)` */ - -#define FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) (FSE_DTABLE_SIZE_U32(maxTableLog) + 1 + FSE_BUILD_DTABLE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) + (FSE_MAX_SYMBOL_VALUE + 1) / 2 + 1) -#define FSE_DECOMPRESS_WKSP_SIZE(maxTableLog, maxSymbolValue) (FSE_DECOMPRESS_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) * sizeof(unsigned)) -size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2); -/**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DECOMPRESS_WKSP_SIZE_U32(maxLog, maxSymbolValue)`. - * Set bmi2 to 1 if your CPU supports BMI2 or 0 if it doesn't */ - -typedef enum { - FSE_repeat_none, /**< Cannot use the previous table */ - FSE_repeat_check, /**< Can use the previous table but it must be checked */ - FSE_repeat_valid /**< Can use the previous table and it is assumed to be valid */ - } FSE_repeat; - -/* ***************************************** -* FSE symbol compression API -*******************************************/ -/*! - This API consists of small unitary functions, which highly benefit from being inlined. - Hence their body are included in next section. -*/ -typedef struct { - ptrdiff_t value; - const void* stateTable; - const void* symbolTT; - unsigned stateLog; -} FSE_CState_t; - -static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct); - -static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol); - -static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr); - -/**< -These functions are inner components of FSE_compress_usingCTable(). -They allow the creation of custom streams, mixing multiple tables and bit sources. - -A key property to keep in mind is that encoding and decoding are done **in reverse direction**. -So the first symbol you will encode is the last you will decode, like a LIFO stack. - -You will need a few variables to track your CStream. They are : - -FSE_CTable ct; // Provided by FSE_buildCTable() -BIT_CStream_t bitStream; // bitStream tracking structure -FSE_CState_t state; // State tracking structure (can have several) - - -The first thing to do is to init bitStream and state. - size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize); - FSE_initCState(&state, ct); - -Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError(); -You can then encode your input data, byte after byte. -FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time. -Remember decoding will be done in reverse direction. - FSE_encodeByte(&bitStream, &state, symbol); - -At any time, you can also add any bit sequence. -Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders - BIT_addBits(&bitStream, bitField, nbBits); - -The above methods don't commit data to memory, they just store it into local register, for speed. -Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). -Writing data to memory is a manual operation, performed by the flushBits function. - BIT_flushBits(&bitStream); - -Your last FSE encoding operation shall be to flush your last state value(s). - FSE_flushState(&bitStream, &state); - -Finally, you must close the bitStream. -The function returns the size of CStream in bytes. -If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible) -If there is an error, it returns an errorCode (which can be tested using FSE_isError()). - size_t size = BIT_closeCStream(&bitStream); -*/ - - -/* ***************************************** -* FSE symbol decompression API -*******************************************/ -typedef struct { - size_t state; - const void* table; /* precise table may vary, depending on U16 */ -} FSE_DState_t; - - -static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt); - -static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); - -static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr); - -/**< -Let's now decompose FSE_decompress_usingDTable() into its unitary components. -You will decode FSE-encoded symbols from the bitStream, -and also any other bitFields you put in, **in reverse order**. - -You will need a few variables to track your bitStream. They are : - -BIT_DStream_t DStream; // Stream context -FSE_DState_t DState; // State context. Multiple ones are possible -FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable() - -The first thing to do is to init the bitStream. - errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize); - -You should then retrieve your initial state(s) -(in reverse flushing order if you have several ones) : - errorCode = FSE_initDState(&DState, &DStream, DTablePtr); - -You can then decode your data, symbol after symbol. -For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'. -Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out). - unsigned char symbol = FSE_decodeSymbol(&DState, &DStream); - -You can retrieve any bitfield you eventually stored into the bitStream (in reverse order) -Note : maximum allowed nbBits is 25, for 32-bits compatibility - size_t bitField = BIT_readBits(&DStream, nbBits); - -All above operations only read from local register (which size depends on size_t). -Refueling the register from memory is manually performed by the reload method. - endSignal = FSE_reloadDStream(&DStream); - -BIT_reloadDStream() result tells if there is still some more data to read from DStream. -BIT_DStream_unfinished : there is still some data left into the DStream. -BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled. -BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed. -BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted. - -When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop, -to properly detect the exact end of stream. -After each decoded symbol, check if DStream is fully consumed using this simple test : - BIT_reloadDStream(&DStream) >= BIT_DStream_completed - -When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. -Checking if DStream has reached its end is performed by : - BIT_endOfDStream(&DStream); -Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. - FSE_endOfDState(&DState); -*/ - - -/* ***************************************** -* FSE unsafe API -*******************************************/ -static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); -/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ - - -/* ***************************************** -* Implementation of inlined functions -*******************************************/ -typedef struct { - int deltaFindState; - U32 deltaNbBits; -} FSE_symbolCompressionTransform; /* total 8 bytes */ - -MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) -{ - const void* ptr = ct; - const U16* u16ptr = (const U16*) ptr; - const U32 tableLog = MEM_read16(ptr); - statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; - statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); - statePtr->stateLog = tableLog; -} - - -/*! FSE_initCState2() : -* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) -* uses the smallest state value possible, saving the cost of this symbol */ -MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) -{ - FSE_initCState(statePtr, ct); - { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; - const U16* stateTable = (const U16*)(statePtr->stateTable); - U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); - statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; - statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; - } -} - -MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) -{ - FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; - const U16* const stateTable = (const U16*)(statePtr->stateTable); - U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); - BIT_addBits(bitC, (size_t)statePtr->value, nbBitsOut); - statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; } -MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) -{ - BIT_addBits(bitC, (size_t)statePtr->value, statePtr->stateLog); - BIT_flushBits(bitC); -} - - -/* FSE_getMaxNbBits() : - * Approximate maximum cost of a symbol, in bits. - * Fractional get rounded up (i.e. a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) - * note 1 : assume symbolValue is valid (<= maxSymbolValue) - * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ -MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) -{ - const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; - return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; -} - -/* FSE_bitCost() : - * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) - * note 1 : assume symbolValue is valid (<= maxSymbolValue) - * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ -MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) -{ - const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; - U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; - U32 const threshold = (minNbBits+1) << 16; - assert(tableLog < 16); - assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ - { U32 const tableSize = 1 << tableLog; - U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); - U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ - U32 const bitMultiplier = 1 << accuracyLog; - assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); - assert(normalizedDeltaFromThreshold <= bitMultiplier); - return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; - } -} - - -/* ====== Decompression ====== */ - -typedef struct { - U16 tableLog; - U16 fastMode; -} FSE_DTableHeader; /* sizeof U32 */ - -typedef struct -{ - unsigned short newState; - unsigned char symbol; - unsigned char nbBits; -} FSE_decode_t; /* size == U32 */ - -MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) -{ - const void* ptr = dt; - const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; - DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); - BIT_reloadDStream(bitD); - DStatePtr->table = dt + 1; -} - -MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - return DInfo.symbol; -} - -MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - size_t const lowBits = BIT_readBits(bitD, nbBits); - DStatePtr->state = DInfo.newState + lowBits; -} - -MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BIT_readBits(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -/*! FSE_decodeSymbolFast() : - unsafe, only works if no symbol has a probability > 50% */ -MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) -{ - FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; - U32 const nbBits = DInfo.nbBits; - BYTE const symbol = DInfo.symbol; - size_t const lowBits = BIT_readBitsFast(bitD, nbBits); - - DStatePtr->state = DInfo.newState + lowBits; - return symbol; -} - -MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) -{ - return DStatePtr->state == 0; -} - - - -#ifndef FSE_COMMONDEFS_ONLY - -/* ************************************************************** -* Tuning parameters -****************************************************************/ -/*!MEMORY_USAGE : -* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) -* Increasing memory usage improves compression ratio -* Reduced memory usage can improve speed, due to cache effect -* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ -#ifndef FSE_MAX_MEMORY_USAGE -# define FSE_MAX_MEMORY_USAGE 14 -#endif -#ifndef FSE_DEFAULT_MEMORY_USAGE -# define FSE_DEFAULT_MEMORY_USAGE 13 -#endif -#if (FSE_DEFAULT_MEMORY_USAGE > FSE_MAX_MEMORY_USAGE) -# error "FSE_DEFAULT_MEMORY_USAGE must be <= FSE_MAX_MEMORY_USAGE" -#endif - -/*!FSE_MAX_SYMBOL_VALUE : -* Maximum symbol value authorized. -* Required for proper stack allocation */ -#ifndef FSE_MAX_SYMBOL_VALUE -# define FSE_MAX_SYMBOL_VALUE 255 -#endif - -/* ************************************************************** -* template functions type & suffix -****************************************************************/ -#define FSE_FUNCTION_TYPE BYTE -#define FSE_FUNCTION_EXTENSION -#define FSE_DECODE_TYPE FSE_decode_t - - -#endif /* !FSE_COMMONDEFS_ONLY */ - - -/* *************************************************************** -* Constants -*****************************************************************/ -#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) -#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX -# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" -#endif - -#define FSE_TABLESTEP(tableSize) (((tableSize)>>1) + ((tableSize)>>3) + 3) - -} // namespace duckdb_zstd +#endif /* FSE_H */ -#endif /* FSE_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h b/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h new file mode 100644 index 000000000..7d8267e3e --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/fse_static.h @@ -0,0 +1,421 @@ +/* ****************************************************************** + * FSE : Finite State Entropy codec + * Public Prototypes declaration + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. + * + * You can contact the author at : + * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. +****************************************************************** */ + +#ifndef FSE_H_FSE_STATIC_LINKING_ONLY +#define FSE_H_FSE_STATIC_LINKING_ONLY + +/* *** Dependency *** */ +#include "zstd/common/bitstream.h" + +namespace duckdb_zstd { + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) (size + (size>>7) + 4 /* fse states */ + sizeof(size_t) /* bitContainer */) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1< 12) ? (1 << (maxTableLog - 2)) : 1024) ) +size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); + +size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); +/**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */ + +size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue); +/**< build a fake FSE_CTable, designed to compress always the same symbolValue */ + +/* FSE_buildCTable_wksp() : + * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`). + * `wkspSize` must be >= `(1<= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +typedef struct { + int deltaFindState; + U32 deltaNbBits; +} FSE_symbolCompressionTransform; /* total 8 bytes */ + +MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) +{ + const void* ptr = ct; + const U16* u16ptr = (const U16*) ptr; + const U32 tableLog = MEM_read16(ptr); + statePtr->value = (ptrdiff_t)1<stateTable = u16ptr+2; + statePtr->symbolTT = ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1); + statePtr->stateLog = tableLog; +} + + +/*! FSE_initCState2() : +* Same as FSE_initCState(), but the first symbol to include (which will be the last to be read) +* uses the smallest state value possible, saving the cost of this symbol */ +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + } +} + +MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, unsigned symbol) +{ + FSE_symbolCompressionTransform const symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* const stateTable = (const U16*)(statePtr->stateTable); + U32 const nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16); + BIT_addBits(bitC, statePtr->value, nbBitsOut); + statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; +} + +MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr) +{ + BIT_addBits(bitC, statePtr->value, statePtr->stateLog); + BIT_flushBits(bitC); +} + + +/* FSE_getMaxNbBits() : + * Approximate maximum cost of a symbol, in bits. + * Fractional get rounded up (i.e : a symbol with a normalized frequency of 3 gives the same result as a frequency of 2) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_getMaxNbBits(const void* symbolTTPtr, U32 symbolValue) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + return (symbolTT[symbolValue].deltaNbBits + ((1<<16)-1)) >> 16; +} + +/* FSE_bitCost() : + * Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) + * note 1 : assume symbolValue is valid (<= maxSymbolValue) + * note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits */ +MEM_STATIC U32 FSE_bitCost(const void* symbolTTPtr, U32 tableLog, U32 symbolValue, U32 accuracyLog) +{ + const FSE_symbolCompressionTransform* symbolTT = (const FSE_symbolCompressionTransform*) symbolTTPtr; + U32 const minNbBits = symbolTT[symbolValue].deltaNbBits >> 16; + U32 const threshold = (minNbBits+1) << 16; + assert(tableLog < 16); + assert(accuracyLog < 31-tableLog); /* ensure enough room for renormalization double shift */ + { U32 const tableSize = 1 << tableLog; + U32 const deltaFromThreshold = threshold - (symbolTT[symbolValue].deltaNbBits + tableSize); + U32 const normalizedDeltaFromThreshold = (deltaFromThreshold << accuracyLog) >> tableLog; /* linear interpolation (very approximate) */ + U32 const bitMultiplier = 1 << accuracyLog; + assert(symbolTT[symbolValue].deltaNbBits + tableSize <= threshold); + assert(normalizedDeltaFromThreshold <= bitMultiplier); + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold; + } +} + + +/* ====== Decompression ====== */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) +{ + const void* ptr = dt; + const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; + DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + +MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + size_t const lowBits = BIT_readBits(bitD, nbBits); + DStatePtr->state = DInfo.newState + lowBits; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +/*! FSE_decodeSymbolFast() : + unsafe, only works if no symbol has a probability > 50% */ +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + U32 const nbBits = DInfo.nbBits; + BYTE const symbol = DInfo.symbol; + size_t const lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#ifndef FSE_MAX_MEMORY_USAGE +# define FSE_MAX_MEMORY_USAGE 14 +#endif +#ifndef FSE_DEFAULT_MEMORY_USAGE +# define FSE_DEFAULT_MEMORY_USAGE 13 +#endif + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#ifndef FSE_MAX_SYMBOL_VALUE +# define FSE_MAX_SYMBOL_VALUE 255 +#endif + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +# error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + +#define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3) + +} + +#endif /* FSE_H_FSE_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/huf.h b/src/duckdb/third_party/zstd/include/zstd/common/huf.h index a28595ce6..4bba72729 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/huf.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/huf.h @@ -1,7 +1,7 @@ /* ****************************************************************** * huff0 huffman codec, * part of Finite State Entropy library - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - Source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -12,271 +12,86 @@ * You may select, at your option, one of the above-listed licenses. ****************************************************************** */ - #ifndef HUF_H_298734234 #define HUF_H_298734234 /* *** Dependencies *** */ -#include "zstd/common/zstd_deps.h" /* size_t */ -#include "zstd/common/mem.h" /* U32 */ -#define FSE_STATIC_LINKING_ONLY -#include "zstd/common/fse.h" - -namespace duckdb_zstd { - -/* *** Tool functions *** */ -#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ -size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ - -/* Error Management */ -unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ -const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ - - -#define HUF_WORKSPACE_SIZE ((8 << 10) + 512 /* sorting scratch space */) -#define HUF_WORKSPACE_SIZE_U64 (HUF_WORKSPACE_SIZE / sizeof(U64)) - -/* *** Constants *** */ -#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_TABLELOG_ABSOLUTEMAX */ -#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ -#define HUF_SYMBOLVALUE_MAX 255 - -#define HUF_TABLELOG_ABSOLUTEMAX 12 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ -#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) -# error "HUF_TABLELOG_MAX is too large !" +#include /* size_t */ + + +/* *** library symbols visibility *** */ +/* Note : when linking with -fvisibility=hidden on gcc, or by default on Visual, + * HUF symbols remain "private" (internal symbols for library only). + * Set macro FSE_DLL_EXPORT to 1 if you want HUF symbols visible on DLL interface */ +#if defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) && defined(__GNUC__) && (__GNUC__ >= 4) +# define HUF_PUBLIC_API __attribute__ ((visibility ("default"))) +#elif defined(FSE_DLL_EXPORT) && (FSE_DLL_EXPORT==1) /* Visual expected */ +# define HUF_PUBLIC_API __declspec(dllexport) +#elif defined(FSE_DLL_IMPORT) && (FSE_DLL_IMPORT==1) +# define HUF_PUBLIC_API __declspec(dllimport) /* not required, just to generate faster code (saves a function pointer load from IAT and an indirect jump) */ +#else +# define HUF_PUBLIC_API #endif +namespace duckdb_zstd { -/* **************************************** -* Static allocation -******************************************/ -/* HUF buffer bounds */ -#define HUF_CTABLEBOUND 129 -#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ -#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ - -/* static allocation of HUF's Compression Table */ -/* this is a private definition, just exposed for allocation and strict aliasing purpose. never EVER access its members directly */ -typedef size_t HUF_CElt; /* consider it an incomplete type */ -#define HUF_CTABLE_SIZE_ST(maxSymbolValue) ((maxSymbolValue)+2) /* Use tables of size_t, for proper alignment */ -#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_ST(maxSymbolValue) * sizeof(size_t)) -#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ - HUF_CElt name[HUF_CTABLE_SIZE_ST(maxSymbolValue)] /* no final ; */ - -/* static allocation of HUF's DTable */ -typedef U32 HUF_DTable; -#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) -#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ - HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } -#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ - HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } - - -/* **************************************** -* Advanced decompression functions -******************************************/ - -/** - * Huffman flags bitset. - * For all flags, 0 is the default value. - */ -typedef enum { - /** - * If compiled with DYNAMIC_BMI2: Set flag only if the CPU supports BMI2 at runtime. - * Otherwise: Ignored. - */ - HUF_flags_bmi2 = (1 << 0), - /** - * If set: Test possible table depths to find the one that produces the smallest header + encoded size. - * If unset: Use heuristic to find the table depth. - */ - HUF_flags_optimalDepth = (1 << 1), - /** - * If set: If the previous table can encode the input, always reuse the previous table. - * If unset: If the previous table can encode the input, reuse the previous table if it results in a smaller output. - */ - HUF_flags_preferRepeat = (1 << 2), - /** - * If set: Sample the input and check if the sample is uncompressible, if it is then don't attempt to compress. - * If unset: Always histogram the entire input. - */ - HUF_flags_suspectUncompressible = (1 << 3), - /** - * If set: Don't use assembly implementations - * If unset: Allow using assembly implementations - */ - HUF_flags_disableAsm = (1 << 4), - /** - * If set: Don't use the fast decoding loop, always use the fallback decoding loop. - * If unset: Use the fast decoding loop when possible. - */ - HUF_flags_disableFast = (1 << 5) -} HUF_flags_e; - - -/* **************************************** - * HUF detailed API - * ****************************************/ -#define HUF_OPTIMAL_DEPTH_THRESHOLD ZSTD_btultra - -/*! HUF_compress() does the following: - * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "fse.h") - * 2. (optional) refine tableLog using HUF_optimalTableLog() - * 3. build Huffman table from count using HUF_buildCTable() - * 4. save Huffman table to memory buffer using HUF_writeCTable() - * 5. encode the data stream using HUF_compress4X_usingCTable() - * - * The following API allows targeting specific sub-functions for advanced tasks. - * For example, it's possible to compress several blocks using the same 'CTable', - * or to save and regenerate 'CTable' using external methods. - */ -unsigned HUF_minTableLog(unsigned symbolCardinality); -unsigned HUF_cardinality(const unsigned* count, unsigned maxSymbolValue); -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace, - size_t wkspSize, HUF_CElt* table, const unsigned* count, int flags); /* table is used as scratch space for building and testing tables, not a return value */ -size_t HUF_writeCTable_wksp(void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog, void* workspace, size_t workspaceSize); -size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); -size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); -int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); - -typedef enum { - HUF_repeat_none, /**< Cannot use the previous table */ - HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ - HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ - } HUF_repeat; - -/** HUF_compress4X_repeat() : - * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. - * If it uses hufTable it does not modify hufTable or repeat. - * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. - * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ -size_t HUF_compress4X_repeat(void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog, - void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int flags); - -/** HUF_buildCTable_wksp() : - * Same as HUF_buildCTable(), but using externally allocated scratch buffer. - * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. - */ -#define HUF_CTABLE_WORKSPACE_SIZE_U32 ((4 * (HUF_SYMBOLVALUE_MAX + 1)) + 192) -#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) -size_t HUF_buildCTable_wksp (HUF_CElt* tree, - const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, - void* workSpace, size_t wkspSize); - -/*! HUF_readStats() : - * Read compact Huffman tree, saved by HUF_writeCTable(). - * `huffWeight` is destination buffer. - * @return : size read from `src` , or an error Code . - * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ -size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, - U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize); - -/*! HUF_readStats_wksp() : - * Same as HUF_readStats() but takes an external workspace which must be - * 4-byte aligned and its size must be >= HUF_READ_STATS_WORKSPACE_SIZE. - * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. - */ -#define HUF_READ_STATS_WORKSPACE_SIZE_U32 FSE_DECOMPRESS_WKSP_SIZE_U32(6, HUF_TABLELOG_MAX-1) -#define HUF_READ_STATS_WORKSPACE_SIZE (HUF_READ_STATS_WORKSPACE_SIZE_U32 * sizeof(unsigned)) -size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, - U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, - const void* src, size_t srcSize, - void* workspace, size_t wkspSize, - int flags); - -/** HUF_readCTable() : - * Loading a CTable saved with HUF_writeCTable() */ -size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); - -/** HUF_getNbBitsFromCTable() : - * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX - * Note 1 : If symbolValue > HUF_readCTableHeader(symbolTable).maxSymbolValue, returns 0 - * Note 2 : is not inlined, as HUF_CElt definition is private - */ -U32 HUF_getNbBitsFromCTable(const HUF_CElt* symbolTable, U32 symbolValue); - -typedef struct { - BYTE tableLog; - BYTE maxSymbolValue; - BYTE unused[sizeof(size_t) - 2]; -} HUF_CTableHeader; - -/** HUF_readCTableHeader() : - * @returns The header from the CTable specifying the tableLog and the maxSymbolValue. +/* ========================== */ +/* *** simple functions *** */ +/* ========================== */ + +/** HUF_compress() : + * Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'. + * 'dst' buffer must be already allocated. + * Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize). + * `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB. + * @return : size of compressed data (<= `dstCapacity`). + * Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! + * if HUF_isError(return), compression failed (more details using HUF_getErrorName()) */ -HUF_CTableHeader HUF_readCTableHeader(HUF_CElt const* ctable); - -/* - * HUF_decompress() does the following: - * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics - * 2. build Huffman table from save, using HUF_readDTableX?() - * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() +HUF_PUBLIC_API size_t HUF_compress(void* dst, size_t dstCapacity, + const void* src, size_t srcSize); + +/** HUF_decompress() : + * Decompress HUF data from buffer 'cSrc', of size 'cSrcSize', + * into already allocated buffer 'dst', of minimum size 'dstSize'. + * `originalSize` : **must** be the ***exact*** size of original (uncompressed) data. + * Note : in contrast with FSE, HUF_decompress can regenerate + * RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, + * because it knows size to regenerate (originalSize). + * @return : size of regenerated data (== originalSize), + * or an error code, which can be tested using HUF_isError() */ +HUF_PUBLIC_API size_t HUF_decompress(void* dst, size_t originalSize, + const void* cSrc, size_t cSrcSize); -/** HUF_selectDecoder() : - * Tells which decoder is likely to decode faster, - * based on a set of pre-computed metrics. - * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . - * Assumption : 0 < dstSize <= 128 KB */ -U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); -/** - * The minimum workspace size for the `workSpace` used in - * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). - * - * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when - * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. - * Buffer overflow errors may potentially occur if code modifications result in - * a required workspace size greater than that specified in the following - * macro. - */ -#define HUF_DECOMPRESS_WORKSPACE_SIZE ((2 << 10) + (1 << 9)) -#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) - - -/* ====================== */ -/* single stream variants */ -/* ====================== */ - -size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable, int flags); -/** HUF_compress1X_repeat() : - * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. - * If it uses hufTable it does not modify hufTable or repeat. - * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. - * If preferRepeat then the old table will always be used if valid. - * If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ -size_t HUF_compress1X_repeat(void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned tableLog, - void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ - HUF_CElt* hufTable, HUF_repeat* repeat, int flags); - -size_t HUF_decompress1X_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); /**< double-symbols decoder */ -#endif - -/* BMI2 variants. - * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. - */ -size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); -#endif -size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int flags); -size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int flags); -#ifndef HUF_FORCE_DECOMPRESS_X2 -size_t HUF_readDTableX1_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); -#endif -#ifndef HUF_FORCE_DECOMPRESS_X1 -size_t HUF_readDTableX2_wksp(HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize, int flags); -#endif +/* *** Tool functions *** */ +#define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */ +HUF_PUBLIC_API size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */ -} // namespace duckdb_zstd +/* Error Management */ +HUF_PUBLIC_API unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +HUF_PUBLIC_API const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ + + +/* *** Advanced function *** */ + +/** HUF_compress2() : + * Same as HUF_compress(), but offers control over `maxSymbolValue` and `tableLog`. + * `maxSymbolValue` must be <= HUF_SYMBOLVALUE_MAX . + * `tableLog` must be `<= HUF_TABLELOG_MAX` . */ +HUF_PUBLIC_API size_t HUF_compress2 (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog); + +/** HUF_compress4X_wksp() : + * Same as HUF_compress2(), but uses externally allocated `workSpace`. + * `workspace` must have minimum alignment of 4, and be at least as large as HUF_WORKSPACE_SIZE */ +#define HUF_WORKSPACE_SIZE ((6 << 10) + 256) +#define HUF_WORKSPACE_SIZE_U32 (HUF_WORKSPACE_SIZE / sizeof(U32)) +HUF_PUBLIC_API size_t HUF_compress4X_wksp (void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize); #endif /* HUF_H_298734234 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h b/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h new file mode 100644 index 000000000..7701972e6 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd/common/huf_static.h @@ -0,0 +1,238 @@ +/* ****************************************************************** + * WARNING !! + * The following section contains advanced and experimental definitions + * which shall never be used in the context of a dynamic library, + * because they are not guaranteed to remain stable in the future. + * Only consider them in association with static linking. + * **************************************************************** */ +#ifndef HUF_H_HUF_STATIC_LINKING_ONLY +#define HUF_H_HUF_STATIC_LINKING_ONLY + +/* *** Dependencies *** */ +#include "zstd/common/mem.h" /* U32 */ + + +/* *** Constants *** */ +#define HUF_TABLELOG_MAX 12 /* max runtime value of tableLog (due to static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ +#define HUF_TABLELOG_DEFAULT 11 /* default tableLog value when none specified */ +#define HUF_SYMBOLVALUE_MAX 255 + +#define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX) +# error "HUF_TABLELOG_MAX is too large !" +#endif + + +/* **************************************** +* Static allocation +******************************************/ +/* HUF buffer bounds */ +#define HUF_CTABLEBOUND 129 +#define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true when incompressible is pre-filtered with fast heuristic */ +#define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* static allocation of HUF's Compression Table */ +#define HUF_CTABLE_SIZE_U32(maxSymbolValue) ((maxSymbolValue)+1) /* Use tables of U32, for proper alignment */ +#define HUF_CTABLE_SIZE(maxSymbolValue) (HUF_CTABLE_SIZE_U32(maxSymbolValue) * sizeof(U32)) +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + U32 name##hb[HUF_CTABLE_SIZE_U32(maxSymbolValue)]; \ + void* name##hv = &(name##hb); \ + HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */ + +/* static allocation of HUF's DTable */ +typedef U32 HUF_DTable; +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog))) +#define HUF_CREATE_STATIC_DTABLEX1(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) } +#define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \ + HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) } + + +/* **************************************** +* Advanced decompression functions +******************************************/ +size_t HUF_decompress4X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */ +size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X_hufOnly_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< considers RLE and uncompressed as errors */ +size_t HUF_decompress4X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress4X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress4X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + + +/* **************************************** + * HUF detailed API + * ****************************************/ + +/*! HUF_compress() does the following: + * 1. count symbol occurrence from source[] into table count[] using FSE_count() (exposed within "zstd/common/fse.h") + * 2. (optional) refine tableLog using HUF_optimalTableLog() + * 3. build Huffman table from count using HUF_buildCTable() + * 4. save Huffman table to memory buffer using HUF_writeCTable() + * 5. encode the data stream using HUF_compress4X_usingCTable() + * + * The following API allows targeting specific sub-functions for advanced tasks. + * For example, it's possible to compress several blocks using the same 'CTable', + * or to save and regenerate 'CTable' using external methods. + */ +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue); +typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ +size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); /* @return : maxNbBits; CTable and count can overlap. In which case, CTable will overwrite count content */ +size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_estimateCompressedSize(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); +int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue); + +typedef enum { + HUF_repeat_none, /**< Cannot use the previous table */ + HUF_repeat_check, /**< Can use the previous table but it must be checked. Note : The previous table must have been constructed by HUF_compress{1, 4}X_repeat */ + HUF_repeat_valid /**< Can use the previous table and it is assumed to be valid */ + } HUF_repeat; +/** HUF_compress4X_repeat() : + * Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. */ +size_t HUF_compress4X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); + +/** HUF_buildCTable_wksp() : + * Same as HUF_buildCTable(), but using externally allocated scratch buffer. + * `workSpace` must be aligned on 4-bytes boundaries, and its size must be >= HUF_CTABLE_WORKSPACE_SIZE. + */ +#define HUF_CTABLE_WORKSPACE_SIZE_U32 (2*HUF_SYMBOLVALUE_MAX +1 +1) +#define HUF_CTABLE_WORKSPACE_SIZE (HUF_CTABLE_WORKSPACE_SIZE_U32 * sizeof(unsigned)) +size_t HUF_buildCTable_wksp (HUF_CElt* tree, + const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, + void* workSpace, size_t wkspSize); + +/*! HUF_readStats() : + * Read compact Huffman tree, saved by HUF_writeCTable(). + * `huffWeight` is destination buffer. + * @return : size read from `src` , or an error Code . + * Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */ +size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, + U32* rankStats, U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + +/** HUF_readCTable() : + * Loading a CTable saved with HUF_writeCTable() */ +size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned *hasZeroWeights); + +/** HUF_getNbBits() : + * Read nbBits from CTable symbolTable, for symbol `symbolValue` presumed <= HUF_SYMBOLVALUE_MAX + * Note 1 : is not inlined, as HUF_CElt definition is private + * Note 2 : const void* used, so that it can provide a statically allocated table as argument (which uses type U32) */ +U32 HUF_getNbBits(const void* symbolTable, U32 symbolValue); + +/* + * HUF_decompress() does the following: + * 1. select the decompression algorithm (X1, X2) based on pre-computed heuristics + * 2. build Huffman table from save, using HUF_readDTableX?() + * 3. decode 1 or 4 segments in parallel using HUF_decompress?X?_usingDTable() + */ + +/** HUF_selectDecoder() : + * Tells which decoder is likely to decode faster, + * based on a set of pre-computed metrics. + * @return : 0==HUF_decompress4X1, 1==HUF_decompress4X2 . + * Assumption : 0 < dstSize <= 128 KB */ +U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize); + +/** + * The minimum workspace size for the `workSpace` used in + * HUF_readDTableX1_wksp() and HUF_readDTableX2_wksp(). + * + * The space used depends on HUF_TABLELOG_MAX, ranging from ~1500 bytes when + * HUF_TABLE_LOG_MAX=12 to ~1850 bytes when HUF_TABLE_LOG_MAX=15. + * Buffer overflow errors may potentially occur if code modifications result in + * a required workspace size greater than that specified in the following + * macro. + */ +#define HUF_DECOMPRESS_WORKSPACE_SIZE (2 << 10) +#define HUF_DECOMPRESS_WORKSPACE_SIZE_U32 (HUF_DECOMPRESS_WORKSPACE_SIZE / sizeof(U32)) + +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_readDTableX1 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX1_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize); +size_t HUF_readDTableX2_wksp (HUF_DTable* DTable, const void* src, size_t srcSize, void* workSpace, size_t wkspSize); +#endif + +size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress4X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + + +/* ====================== */ +/* single stream variants */ +/* ====================== */ + +size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); +size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least HUF_WORKSPACE_SIZE_U32 unsigned */ +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +/** HUF_compress1X_repeat() : + * Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none. + * If it uses hufTable it does not modify hufTable or repeat. + * If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used. + * If preferRepeat then the old table will always be used if valid. */ +size_t HUF_compress1X_repeat(void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned tableLog, + void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */ + HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2); + +size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ +#endif + +size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); +size_t HUF_decompress1X_DCtx_wksp (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */ +size_t HUF_decompress1X1_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< single-symbol decoder */ +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */ +size_t HUF_decompress1X2_DCtx_wksp(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize); /**< double-symbols decoder */ +#endif + +size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */ +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif +#ifndef HUF_FORCE_DECOMPRESS_X1 +size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); +#endif + +/* BMI2 variants. + * If the CPU has BMI2 support, pass bmi2=1, otherwise pass bmi2=0. + */ +size_t HUF_decompress1X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +#ifndef HUF_FORCE_DECOMPRESS_X2 +size_t HUF_decompress1X1_DCtx_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); +#endif +size_t HUF_decompress4X_usingDTable_bmi2(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable, int bmi2); +size_t HUF_decompress4X_hufOnly_wksp_bmi2(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize, void* workSpace, size_t wkspSize, int bmi2); + +} + +#endif /* HUF_STATIC_LINKING_ONLY */ + diff --git a/src/duckdb/third_party/zstd/include/zstd/common/mem.h b/src/duckdb/third_party/zstd/include/zstd/common/mem.h index 4d36251d4..7c7b1f32d 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/mem.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/mem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,10 +14,8 @@ /*-**************************************** * Dependencies ******************************************/ -#include /* size_t, ptrdiff_t */ -#include "zstd/common/compiler.h" /* __has_builtin */ -#include "zstd/common/debug.h" /* DEBUG_STATIC_ASSERT */ -#include "zstd/common/zstd_deps.h" /* ZSTD_memcpy */ +#include /* size_t, ptrdiff_t */ +#include /* memcpy */ /*-**************************************** @@ -27,19 +25,37 @@ # include /* _byteswap_ulong */ # include /* _byteswap_* */ #endif +#if defined(__GNUC__) +# define MEM_STATIC static __inline __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline +#else +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 /* compat. with non-clang compilers */ +#endif + +/* code only tested on 32 and 64 bits systems */ +#define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; } +MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } + +/* detects whether we are being compiled under msan */ +#if defined (__has_feature) +# if __has_feature(memory_sanitizer) +# define MEMORY_SANITIZER 1 +# endif +#endif /*-************************************************************** * Basic Types *****************************************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) -# if defined(_AIX) -# include -# else -# include /* intptr_t */ -# endif +# include typedef uint8_t BYTE; - typedef uint8_t U8; - typedef int8_t S8; typedef uint16_t U16; typedef int16_t S16; typedef uint32_t U32; @@ -52,8 +68,6 @@ # error "this implementation requires char to be exactly 8-bit type" #endif typedef unsigned char BYTE; - typedef unsigned char U8; - typedef signed char S8; #if USHRT_MAX != 65535 # error "this implementation requires short to be exactly 16-bit type" #endif @@ -73,63 +87,25 @@ namespace duckdb_zstd { /*-************************************************************** -* Memory I/O API +* Memory I/O *****************************************************************/ -/*=== Static platform detection ===*/ -MEM_STATIC unsigned MEM_32bits(void); -MEM_STATIC unsigned MEM_64bits(void); -MEM_STATIC unsigned MEM_isLittleEndian(void); - -/*=== Native unaligned read/write ===*/ -MEM_STATIC U16 MEM_read16(const void* memPtr); -MEM_STATIC U32 MEM_read32(const void* memPtr); -MEM_STATIC U64 MEM_read64(const void* memPtr); -MEM_STATIC size_t MEM_readST(const void* memPtr); - -MEM_STATIC void MEM_write16(void* memPtr, U16 value); -MEM_STATIC void MEM_write32(void* memPtr, U32 value); -MEM_STATIC void MEM_write64(void* memPtr, U64 value); - -/*=== Little endian unaligned read/write ===*/ -MEM_STATIC U16 MEM_readLE16(const void* memPtr); -MEM_STATIC U32 MEM_readLE24(const void* memPtr); -MEM_STATIC U32 MEM_readLE32(const void* memPtr); -MEM_STATIC U64 MEM_readLE64(const void* memPtr); -MEM_STATIC size_t MEM_readLEST(const void* memPtr); - -MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val); -MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val); -MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32); -MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64); -MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val); - -/*=== Big endian unaligned read/write ===*/ -MEM_STATIC U32 MEM_readBE32(const void* memPtr); -MEM_STATIC U64 MEM_readBE64(const void* memPtr); -MEM_STATIC size_t MEM_readBEST(const void* memPtr); - -MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32); -MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64); -MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val); - -/*=== Byteswap ===*/ -MEM_STATIC U32 MEM_swap32(U32 in); -MEM_STATIC U64 MEM_swap64(U64 in); -MEM_STATIC size_t MEM_swapST(size_t in); - - -/*-************************************************************** -* Memory I/O Implementation -*****************************************************************/ -/* MEM_FORCE_MEMORY_ACCESS : For accessing unaligned memory: - * Method 0 : always use `memcpy()`. Safe and portable. - * Method 1 : Use compiler extension to set unaligned access. +/* MEM_FORCE_MEMORY_ACCESS : + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. * Method 2 : direct access. This method is portable but violate C standard. * It can generate buggy code on targets depending on alignment. - * Default : method 1 if supported, else method 0 + * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ -# ifdef __GNUC__ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__) # define MEM_FORCE_MEMORY_ACCESS 1 # endif #endif @@ -139,22 +115,8 @@ MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } MEM_STATIC unsigned MEM_isLittleEndian(void) { -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - return 1; -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - return 0; -#elif defined(__clang__) && __LITTLE_ENDIAN__ - return 1; -#elif defined(__clang__) && __BIG_ENDIAN__ - return 0; -#elif defined(_MSC_VER) && (_M_AMD64 || _M_IX86) - return 1; -#elif defined(__DMC__) && defined(_M_IX86) - return 1; -#else const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; -#endif } #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) @@ -172,19 +134,30 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) -typedef __attribute__((aligned(1))) U16 unalign16; -typedef __attribute__((aligned(1))) U32 unalign32; -typedef __attribute__((aligned(1))) U64 unalign64; -typedef __attribute__((aligned(1))) size_t unalignArch; +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +#if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) + __pragma( pack(push, 1) ) + typedef struct { U16 v; } unalign16; + typedef struct { U32 v; } unalign32; + typedef struct { U64 v; } unalign64; + typedef struct { size_t v; } unalignArch; + __pragma( pack(pop) ) +#else + typedef struct { U16 v; } __attribute__((packed)) unalign16; + typedef struct { U32 v; } __attribute__((packed)) unalign32; + typedef struct { U64 v; } __attribute__((packed)) unalign64; + typedef struct { size_t v; } __attribute__((packed)) unalignArch; +#endif -MEM_STATIC U16 MEM_read16(const void* ptr) { return *(const unalign16*)ptr; } -MEM_STATIC U32 MEM_read32(const void* ptr) { return *(const unalign32*)ptr; } -MEM_STATIC U64 MEM_read64(const void* ptr) { return *(const unalign64*)ptr; } -MEM_STATIC size_t MEM_readST(const void* ptr) { return *(const unalignArch*)ptr; } +MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } +MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } +MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } +MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } -MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(unalign16*)memPtr = value; } -MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(unalign32*)memPtr = value; } -MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = value; } +MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } #else @@ -193,49 +166,41 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(unalign64*)memPtr = val MEM_STATIC U16 MEM_read16(const void* memPtr) { - U16 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U32 MEM_read32(const void* memPtr) { - U32 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC U64 MEM_read64(const void* memPtr) { - U64 val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC size_t MEM_readST(const void* memPtr) { - size_t val; ZSTD_memcpy(&val, memPtr, sizeof(val)); return val; + size_t val; memcpy(&val, memPtr, sizeof(val)); return val; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } MEM_STATIC void MEM_write64(void* memPtr, U64 value) { - ZSTD_memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* MEM_FORCE_MEMORY_ACCESS */ -MEM_STATIC U32 MEM_swap32_fallback(U32 in) -{ - return ((in << 24) & 0xff000000 ) | - ((in << 8) & 0x00ff0000 ) | - ((in >> 8) & 0x0000ff00 ) | - ((in >> 24) & 0x000000ff ); -} - MEM_STATIC U32 MEM_swap32(U32 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -244,22 +209,13 @@ MEM_STATIC U32 MEM_swap32(U32 in) || (defined(__clang__) && __has_builtin(__builtin_bswap32)) return __builtin_bswap32(in); #else - return MEM_swap32_fallback(in); + return ((in << 24) & 0xff000000 ) | + ((in << 8) & 0x00ff0000 ) | + ((in >> 8) & 0x0000ff00 ) | + ((in >> 24) & 0x000000ff ); #endif } -MEM_STATIC U64 MEM_swap64_fallback(U64 in) -{ - return ((in << 56) & 0xff00000000000000ULL) | - ((in << 40) & 0x00ff000000000000ULL) | - ((in << 24) & 0x0000ff0000000000ULL) | - ((in << 8) & 0x000000ff00000000ULL) | - ((in >> 8) & 0x00000000ff000000ULL) | - ((in >> 24) & 0x0000000000ff0000ULL) | - ((in >> 40) & 0x000000000000ff00ULL) | - ((in >> 56) & 0x00000000000000ffULL); -} - MEM_STATIC U64 MEM_swap64(U64 in) { #if defined(_MSC_VER) /* Visual Studio */ @@ -268,7 +224,14 @@ MEM_STATIC U64 MEM_swap64(U64 in) || (defined(__clang__) && __has_builtin(__builtin_bswap64)) return __builtin_bswap64(in); #else - return MEM_swap64_fallback(in); + return ((in << 56) & 0xff00000000000000ULL) | + ((in << 40) & 0x00ff000000000000ULL) | + ((in << 24) & 0x0000ff0000000000ULL) | + ((in << 8) & 0x000000ff00000000ULL) | + ((in >> 8) & 0x00000000ff000000ULL) | + ((in >> 24) & 0x0000000000ff0000ULL) | + ((in >> 40) & 0x000000000000ff00ULL) | + ((in >> 56) & 0x00000000000000ffULL); #endif } @@ -305,7 +268,7 @@ MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) MEM_STATIC U32 MEM_readLE24(const void* memPtr) { - return (U32)MEM_readLE16(memPtr) + ((U32)(((const BYTE*)memPtr)[2]) << 16); + return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); } MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) @@ -412,9 +375,6 @@ MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) MEM_writeBE64(memPtr, (U64)val); } -/* code only tested on 32 and 64 bits systems */ -MEM_STATIC void MEM_check(void) { DEBUG_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } - -} // namespace duckdb_zstd +} #endif /* MEM_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/pool.h b/src/duckdb/third_party/zstd/include/zstd/common/pool.h deleted file mode 100644 index e85948f05..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/pool.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef POOL_H -#define POOL_H - -#include "zstd/common/zstd_deps.h" -#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_customMem */ -#include "zstd.h" - -namespace duckdb_zstd { - -typedef struct POOL_ctx_s POOL_ctx; - -/*! POOL_create() : - * Create a thread pool with at most `numThreads` threads. - * `numThreads` must be at least 1. - * The maximum number of queued jobs before blocking is `queueSize`. - * @return : POOL_ctx pointer on success, else NULL. -*/ -POOL_ctx* POOL_create(size_t numThreads, size_t queueSize); - -POOL_ctx* POOL_create_advanced(size_t numThreads, size_t queueSize, - ZSTD_customMem customMem); - -/*! POOL_free() : - * Free a thread pool returned by POOL_create(). - */ -void POOL_free(POOL_ctx* ctx); - - -/*! POOL_joinJobs() : - * Waits for all queued jobs to finish executing. - */ -void POOL_joinJobs(POOL_ctx* ctx); - -/*! POOL_resize() : - * Expands or shrinks pool's number of threads. - * This is more efficient than releasing + creating a new context, - * since it tries to preserve and reuse existing threads. - * `numThreads` must be at least 1. - * @return : 0 when resize was successful, - * !0 (typically 1) if there is an error. - * note : only numThreads can be resized, queueSize remains unchanged. - */ -int POOL_resize(POOL_ctx* ctx, size_t numThreads); - -/*! POOL_sizeof() : - * @return threadpool memory usage - * note : compatible with NULL (returns 0 in this case) - */ -size_t POOL_sizeof(const POOL_ctx* ctx); - -/*! POOL_function : - * The function type that can be added to a thread pool. - */ -typedef void (*POOL_function)(void*); - -/*! POOL_add() : - * Add the job `function(opaque)` to the thread pool. `ctx` must be valid. - * Possibly blocks until there is room in the queue. - * Note : The function may be executed asynchronously, - * therefore, `opaque` must live until function has been completed. - */ -void POOL_add(POOL_ctx* ctx, POOL_function function, void* opaque); - - -/*! POOL_tryAdd() : - * Add the job `function(opaque)` to thread pool _if_ a queue slot is available. - * Returns immediately even if not (does not block). - * @return : 1 if successful, 0 if not. - */ -int POOL_tryAdd(POOL_ctx* ctx, POOL_function function, void* opaque); - -} // namespace duckdb_zstd - -#endif diff --git a/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h b/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h deleted file mode 100644 index e50314a78..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/portability_macros.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_PORTABILITY_MACROS_H -#define ZSTD_PORTABILITY_MACROS_H - -/** - * This header file contains macro definitions to support portability. - * This header is shared between C and ASM code, so it MUST only - * contain macro definitions. It MUST not contain any C code. - * - * This header ONLY defines macros to detect platforms/feature support. - * - */ - - -/* compat. with non-clang compilers */ -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif - -/* compat. with non-clang compilers */ -#ifndef __has_builtin -# define __has_builtin(x) 0 -#endif - -/* compat. with non-clang compilers */ -#ifndef __has_feature -# define __has_feature(x) 0 -#endif - -/* detects whether we are being compiled under msan */ -#ifndef ZSTD_MEMORY_SANITIZER -# if __has_feature(memory_sanitizer) -# define ZSTD_MEMORY_SANITIZER 1 -# else -# define ZSTD_MEMORY_SANITIZER 0 -# endif -#endif - -/* detects whether we are being compiled under asan */ -#ifndef ZSTD_ADDRESS_SANITIZER -# if __has_feature(address_sanitizer) -# define ZSTD_ADDRESS_SANITIZER 1 -# elif defined(__SANITIZE_ADDRESS__) -# define ZSTD_ADDRESS_SANITIZER 1 -# else -# define ZSTD_ADDRESS_SANITIZER 0 -# endif -#endif - -/* detects whether we are being compiled under dfsan */ -#ifndef ZSTD_DATAFLOW_SANITIZER -# if __has_feature(dataflow_sanitizer) -# define ZSTD_DATAFLOW_SANITIZER 1 -# else -# define ZSTD_DATAFLOW_SANITIZER 0 -# endif -#endif - -/* Mark the internal assembly functions as hidden */ -#ifdef __ELF__ -# define ZSTD_HIDE_ASM_FUNCTION(func) .hidden func -#elif defined(__APPLE__) -# define ZSTD_HIDE_ASM_FUNCTION(func) .private_extern func -#else -# define ZSTD_HIDE_ASM_FUNCTION(func) -#endif - -/* Enable runtime BMI2 dispatch based on the CPU. - * Enabled for clang & gcc >=4.8 on x86 when BMI2 isn't enabled by default. - */ -#ifndef DYNAMIC_BMI2 - #if ((defined(__clang__) && __has_attribute(__target__)) \ - || (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ - && (defined(__x86_64__) || defined(_M_X64)) \ - && !defined(__BMI2__) - # define DYNAMIC_BMI2 1 - #else - # define DYNAMIC_BMI2 0 - #endif -#endif - -/** - * Only enable assembly for GNUC compatible compilers, - * because other platforms may not support GAS assembly syntax. - * - * Only enable assembly for Linux / MacOS, other platforms may - * work, but they haven't been tested. This could likely be - * extended to BSD systems. - * - * Disable assembly when MSAN is enabled, because MSAN requires - * 100% of code to be instrumented to work. - */ -#if defined(__GNUC__) -# if defined(__linux__) || defined(__linux) || defined(__APPLE__) -# if ZSTD_MEMORY_SANITIZER -# define ZSTD_ASM_SUPPORTED 0 -# elif ZSTD_DATAFLOW_SANITIZER -# define ZSTD_ASM_SUPPORTED 0 -# else -# define ZSTD_ASM_SUPPORTED 1 -# endif -# else -# define ZSTD_ASM_SUPPORTED 0 -# endif -#else -# define ZSTD_ASM_SUPPORTED 0 -#endif - -/** - * Determines whether we should enable assembly for x86-64 - * with BMI2. - * - * Enable if all of the following conditions hold: - * - ASM hasn't been explicitly disabled by defining ZSTD_DISABLE_ASM - * - Assembly is supported - * - We are compiling for x86-64 and either: - * - DYNAMIC_BMI2 is enabled - * - BMI2 is supported at compile time - */ -#if !defined(ZSTD_DISABLE_ASM) && \ - ZSTD_ASM_SUPPORTED && \ - defined(__x86_64__) && \ - (DYNAMIC_BMI2 || defined(__BMI2__)) -# define ZSTD_ENABLE_ASM_X86_64_BMI2 1 -#else -# define ZSTD_ENABLE_ASM_X86_64_BMI2 0 -#endif - -/* - * For x86 ELF targets, add .note.gnu.property section for Intel CET in - * assembly sources when CET is enabled. - * - * Additionally, any function that may be called indirectly must begin - * with ZSTD_CET_ENDBRANCH. - */ -#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__)) \ - && defined(__has_include) -# if __has_include() -# include -# define ZSTD_CET_ENDBRANCH _CET_ENDBR -# endif -#endif - -#ifndef ZSTD_CET_ENDBRANCH -# define ZSTD_CET_ENDBRANCH -#endif - -#endif /* ZSTD_PORTABILITY_MACROS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/threading.h b/src/duckdb/third_party/zstd/include/zstd/common/threading.h deleted file mode 100644 index fc13da1bf..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/threading.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (c) 2016 Tino Reichardt - * All rights reserved. - * - * You can contact the author at: - * - zstdmt source repository: https://github.com/mcmilk/zstdmt - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef THREADING_H_938743 -#define THREADING_H_938743 - -#include "zstd/common/debug.h" - -#if defined(ZSTD_MULTITHREAD) && defined(_WIN32) - -/** - * Windows minimalist Pthread Wrapper - */ -#ifdef WINVER -# undef WINVER -#endif -#define WINVER 0x0600 - -#ifdef _WIN32_WINNT -# undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0600 - -#ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ -#include -#undef ERROR -#define ERROR(name) ZSTD_ERROR(name) - -/* mutex */ -#define ZSTD_pthread_mutex_t CRITICAL_SECTION -#define ZSTD_pthread_mutex_init(a, b) ((void)(b), InitializeCriticalSection((a)), 0) -#define ZSTD_pthread_mutex_destroy(a) DeleteCriticalSection((a)) -#define ZSTD_pthread_mutex_lock(a) EnterCriticalSection((a)) -#define ZSTD_pthread_mutex_unlock(a) LeaveCriticalSection((a)) - -/* condition variable */ -#define ZSTD_pthread_cond_t CONDITION_VARIABLE -#define ZSTD_pthread_cond_init(a, b) ((void)(b), InitializeConditionVariable((a)), 0) -#define ZSTD_pthread_cond_destroy(a) ((void)(a)) -#define ZSTD_pthread_cond_wait(a, b) SleepConditionVariableCS((a), (b), INFINITE) -#define ZSTD_pthread_cond_signal(a) WakeConditionVariable((a)) -#define ZSTD_pthread_cond_broadcast(a) WakeAllConditionVariable((a)) - -namespace duckdb_zstd { - -/* ZSTD_pthread_create() and ZSTD_pthread_join() */ -typedef HANDLE ZSTD_pthread_t; - -int ZSTD_pthread_create(ZSTD_pthread_t* thread, const void* unused, - void* (*start_routine) (void*), void* arg); - -int ZSTD_pthread_join(ZSTD_pthread_t thread); - -} // namespace duckdb_zstd - -/** - * add here more wrappers as required - */ - - -#elif defined(ZSTD_MULTITHREAD) /* posix assumed ; need a better detection method */ -/* === POSIX Systems === */ -# include - -# if DEBUGLEVEL < 1 - -#define ZSTD_pthread_mutex_t pthread_mutex_t -#define ZSTD_pthread_mutex_init(a, b) pthread_mutex_init((a), (b)) -#define ZSTD_pthread_mutex_destroy(a) pthread_mutex_destroy((a)) -#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock((a)) -#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock((a)) - -#define ZSTD_pthread_cond_t pthread_cond_t -#define ZSTD_pthread_cond_init(a, b) pthread_cond_init((a), (b)) -#define ZSTD_pthread_cond_destroy(a) pthread_cond_destroy((a)) -#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait((a), (b)) -#define ZSTD_pthread_cond_signal(a) pthread_cond_signal((a)) -#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast((a)) - -#define ZSTD_pthread_t pthread_t -#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) -#define ZSTD_pthread_join(a) pthread_join((a),NULL) - -# else /* DEBUGLEVEL >= 1 */ - -/* Debug implementation of threading. - * In this implementation we use pointers for mutexes and condition variables. - * This way, if we forget to init/destroy them the program will crash or ASAN - * will report leaks. - */ - -namespace duckdb_zstd { - -#define ZSTD_pthread_mutex_t pthread_mutex_t* -int ZSTD_pthread_mutex_init(ZSTD_pthread_mutex_t* mutex, pthread_mutexattr_t const* attr); -int ZSTD_pthread_mutex_destroy(ZSTD_pthread_mutex_t* mutex); -#define ZSTD_pthread_mutex_lock(a) pthread_mutex_lock(*(a)) -#define ZSTD_pthread_mutex_unlock(a) pthread_mutex_unlock(*(a)) - -#define ZSTD_pthread_cond_t pthread_cond_t* -int ZSTD_pthread_cond_init(ZSTD_pthread_cond_t* cond, pthread_condattr_t const* attr); -int ZSTD_pthread_cond_destroy(ZSTD_pthread_cond_t* cond); -#define ZSTD_pthread_cond_wait(a, b) pthread_cond_wait(*(a), *(b)) -#define ZSTD_pthread_cond_signal(a) pthread_cond_signal(*(a)) -#define ZSTD_pthread_cond_broadcast(a) pthread_cond_broadcast(*(a)) - -#define ZSTD_pthread_t pthread_t -#define ZSTD_pthread_create(a, b, c, d) pthread_create((a), (b), (c), (d)) -#define ZSTD_pthread_join(a) pthread_join((a),NULL) - -} // namespace duckdb_zstd - -# endif - -#else /* ZSTD_MULTITHREAD not defined */ -/* No multithreading support */ - -namespace duckdb_zstd { - -typedef int ZSTD_pthread_mutex_t; -#define ZSTD_pthread_mutex_init(a, b) ((void)(a), (void)(b), 0) -#define ZSTD_pthread_mutex_destroy(a) ((void)(a)) -#define ZSTD_pthread_mutex_lock(a) ((void)(a)) -#define ZSTD_pthread_mutex_unlock(a) ((void)(a)) - -typedef int ZSTD_pthread_cond_t; -#define ZSTD_pthread_cond_init(a, b) ((void)(a), (void)(b), 0) -#define ZSTD_pthread_cond_destroy(a) ((void)(a)) -#define ZSTD_pthread_cond_wait(a, b) ((void)(a), (void)(b)) -#define ZSTD_pthread_cond_signal(a) ((void)(a)) -#define ZSTD_pthread_cond_broadcast(a) ((void)(a)) - -/* do not use ZSTD_pthread_t */ - -} // namespace duckdb_zstd - -#endif /* ZSTD_MULTITHREAD */ -#endif /* THREADING_H_938743 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp b/src/duckdb/third_party/zstd/include/zstd/common/xxhash.h similarity index 99% rename from src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp rename to src/duckdb/third_party/zstd/include/zstd/common/xxhash.h index 1ebadc466..a6b7990c8 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/xxhash.hpp +++ b/src/duckdb/third_party/zstd/include/zstd/common/xxhash.h @@ -232,3 +232,4 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src } #endif /* XXHASH_H_5627135585666179 */ + diff --git a/src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.hpp b/src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.h similarity index 100% rename from src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.hpp rename to src/duckdb/third_party/zstd/include/zstd/common/xxhash_static.h diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h deleted file mode 100644 index 0be68bbb1..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/zstd_deps.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* This file provides common libc dependencies that zstd requires. - * The purpose is to allow replacing this file with a custom implementation - * to compile zstd without libc support. - */ - -/* Need: - * NULL - * INT_MAX - * UINT_MAX - * ZSTD_memcpy() - * ZSTD_memset() - * ZSTD_memmove() - */ -#ifndef ZSTD_DEPS_COMMON -#define ZSTD_DEPS_COMMON - -#include -#include -#include - -// DuckDB: just enable everything for amalgamation -#ifdef DUCKDB_AMALGAMATION -#define ZSTD_DEPS_NEED_MALLOC -#define ZSTD_DEPS_NEED_MATH64 -#define ZSTD_DEPS_NEED_ASSERT -#define ZSTD_DEPS_NEED_IO -#define ZSTD_DEPS_NEED_STDINT -#define ZSTD_MULTITHREAD -#define FSE_STATIC_LINKING_ONLY -#endif - -#if defined(__GNUC__) && __GNUC__ >= 4 -# define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) -# define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) -# define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) -#else -# define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) -# define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) -# define ZSTD_memset(p,v,l) memset((p),(v),(l)) -#endif - -#endif /* ZSTD_DEPS_COMMON */ - -/* Need: - * ZSTD_malloc() - * ZSTD_free() - * ZSTD_calloc() - */ -#ifdef ZSTD_DEPS_NEED_MALLOC -#ifndef ZSTD_DEPS_MALLOC -#define ZSTD_DEPS_MALLOC - -#include - -#define ZSTD_malloc(s) malloc(s) -#define ZSTD_calloc(n,s) calloc((n), (s)) -#define ZSTD_free(p) free((p)) - -#endif /* ZSTD_DEPS_MALLOC */ -#endif /* ZSTD_DEPS_NEED_MALLOC */ - -/* - * Provides 64-bit math support. - * Need: - * U64 ZSTD_div64(U64 dividend, U32 divisor) - */ -#ifdef ZSTD_DEPS_NEED_MATH64 -#ifndef ZSTD_DEPS_MATH64 -#define ZSTD_DEPS_MATH64 - -#define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) - -#endif /* ZSTD_DEPS_MATH64 */ -#endif /* ZSTD_DEPS_NEED_MATH64 */ - -/* Need: - * assert() - */ -#ifdef ZSTD_DEPS_NEED_ASSERT -#ifndef ZSTD_DEPS_ASSERT -#define ZSTD_DEPS_ASSERT - -#include - -#endif /* ZSTD_DEPS_ASSERT */ -#endif /* ZSTD_DEPS_NEED_ASSERT */ - -/* Need: - * ZSTD_DEBUG_PRINT() - */ -#ifdef ZSTD_DEPS_NEED_IO -#ifndef ZSTD_DEPS_IO -#define ZSTD_DEPS_IO - -#include -#define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) - -#endif /* ZSTD_DEPS_IO */ -#endif /* ZSTD_DEPS_NEED_IO */ - -/* Only requested when is known to be present. - * Need: - * intptr_t - */ -#ifdef ZSTD_DEPS_NEED_STDINT -#ifndef ZSTD_DEPS_STDINT -#define ZSTD_DEPS_STDINT - -#include - -#endif /* ZSTD_DEPS_STDINT */ -#endif /* ZSTD_DEPS_NEED_STDINT */ diff --git a/src/duckdb/third_party/zstd/include/zstd_errors.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h similarity index 73% rename from src/duckdb/third_party/zstd/include/zstd_errors.h rename to src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h index 401f67004..a719982bc 100644 --- a/src/duckdb/third_party/zstd/include/zstd_errors.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/zstd_errors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,36 +14,23 @@ /*===== dependency =====*/ #include /* size_t */ -namespace duckdb_zstd { /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ -#ifndef ZSTDERRORLIB_VISIBLE - /* Backwards compatibility with old macro name */ -# ifdef ZSTDERRORLIB_VISIBILITY -# define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY -# elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) -# else -# define ZSTDERRORLIB_VISIBLE -# endif -#endif - -#ifndef ZSTDERRORLIB_HIDDEN -# if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) +#ifndef ZSTDERRORLIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define ZSTDERRORLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else -# define ZSTDERRORLIB_HIDDEN +# define ZSTDERRORLIB_VISIBILITY # endif #endif - #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) -# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE +# define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBILITY #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) -# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +# define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else -# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE +# define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBILITY #endif - +namespace duckdb_zstd { /*-********************************************* * Error codes list *-********************************************* @@ -67,17 +54,14 @@ typedef enum { ZSTD_error_frameParameter_windowTooLarge = 16, ZSTD_error_corruption_detected = 20, ZSTD_error_checksum_wrong = 22, - ZSTD_error_literals_headerWrong = 24, ZSTD_error_dictionary_corrupted = 30, ZSTD_error_dictionary_wrong = 32, ZSTD_error_dictionaryCreation_failed = 34, ZSTD_error_parameter_unsupported = 40, - ZSTD_error_parameter_combination_unsupported = 41, ZSTD_error_parameter_outOfBound = 42, ZSTD_error_tableLog_tooLarge = 44, ZSTD_error_maxSymbolValue_tooLarge = 46, ZSTD_error_maxSymbolValue_tooSmall = 48, - ZSTD_error_stabilityCondition_notRespected = 50, ZSTD_error_stage_wrong = 60, ZSTD_error_init_missing = 62, ZSTD_error_memory_allocation = 64, @@ -85,15 +69,10 @@ typedef enum { ZSTD_error_dstSize_tooSmall = 70, ZSTD_error_srcSize_wrong = 72, ZSTD_error_dstBuffer_null = 74, - ZSTD_error_noForwardProgress_destFull = 80, - ZSTD_error_noForwardProgress_inputEmpty = 82, /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ ZSTD_error_frameIndex_tooLarge = 100, ZSTD_error_seekableIO = 102, ZSTD_error_dstBuffer_wrong = 104, - ZSTD_error_srcBuffer_wrong = 105, - ZSTD_error_sequenceProducer_failed = 106, - ZSTD_error_externalSequences_invalid = 107, ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ } ZSTD_ErrorCode; @@ -103,7 +82,6 @@ typedef enum { ZSTDERRORLIB_API ZSTD_ErrorCode ZSTD_getErrorCode(size_t functionResult); ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ - -} // namespace duckdb_zstd +} #endif /* ZSTD_ERRORS_H_398273423 */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h index 3e800e3dc..93cb45856 100644 --- a/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/common/zstd_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -19,34 +19,29 @@ /*-************************************* * Dependencies ***************************************/ +#ifdef __aarch64__ +#include +#endif #include "zstd/common/compiler.h" -#include "zstd/common/cpu.h" #include "zstd/common/mem.h" #include "zstd/common/debug.h" /* assert, DEBUGLOG, RAWLOG, g_debuglevel */ #include "zstd/common/error_private.h" -#define ZSTD_STATIC_LINKING_ONLY #include "zstd.h" -#define FSE_STATIC_LINKING_ONLY +#include "zstd_static.h" #include "zstd/common/fse.h" +#include "zstd/common/fse_static.h" #include "zstd/common/huf.h" -#ifndef XXH_STATIC_LINKING_ONLY -# define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */ -#endif -#include "zstd/common/xxhash.hpp" /* XXH_reset, update, digest */ -#include "zstd/common/xxhash_static.hpp" -#ifndef ZSTD_NO_TRACE -# include "zstd/common/zstd_trace.h" -#else -# define ZSTD_TRACE 0 -#endif +#include "zstd/common/huf_static.h" +#include "zstd/common/xxhash.h" /* XXH_reset, update, digest */ +#include "zstd/common/xxhash_static.h" /* XXH_reset, update, digest */ namespace duckdb_zstd { /* ---- static assert (debug) --- */ #define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) #define ZSTD_isError ERR_isError /* for inlining */ -#define FSE_isError ERR_isError -#define HUF_isError ERR_isError +// #define FSE_isError ERR_isError +// #define HUF_isError ERR_isError /*-************************************* @@ -56,7 +51,81 @@ namespace duckdb_zstd { #undef MAX #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) -#define BOUNDED(min,val,max) (MAX(min,MIN(val,max))) + +/** + * Ignore: this is an internal helper. + * + * This is a helper function to help force C99-correctness during compilation. + * Under strict compilation modes, variadic macro arguments can't be empty. + * However, variadic function arguments can be. Using a function therefore lets + * us statically check that at least one (string) argument was passed, + * independent of the compilation flags. + */ +static INLINE_KEYWORD UNUSED_ATTR +void _force_has_format_string(const char *format, ...) { + (void)format; +} + +/** + * Ignore: this is an internal helper. + * + * We want to force this function invocation to be syntactically correct, but + * we don't want to force runtime evaluation of its arguments. + */ +#define _FORCE_HAS_FORMAT_STRING(...) \ + if (0) { \ + _force_has_format_string(__VA_ARGS__); \ + } + +/** + * Return the specified error if the condition evaluates to true. + * + * In debug modes, prints additional information. + * In order to do that (particularly, printing the conditional that failed), + * this can't just wrap RETURN_ERROR(). + */ +#define RETURN_ERROR_IF(cond, err, ...) \ + if (cond) { \ + RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ + __FILE__, __LINE__, ZSTD_QUOTE(cond), ZSTD_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } + +/** + * Unconditionally return the specified error. + * + * In debug modes, prints additional information. + */ +#define RETURN_ERROR(err, ...) \ + do { \ + RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ + __FILE__, __LINE__, ZSTD_QUOTE(ERROR(err))); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return ERROR(err); \ + } while(0); + +/** + * If the provided expression evaluates to an error code, returns that error code. + * + * In debug modes, prints additional information. + */ +#define FORWARD_IF_ERROR(err, ...) \ + do { \ + size_t const err_code = (err); \ + if (ERR_isError(err_code)) { \ + RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ + __FILE__, __LINE__, ZSTD_QUOTE(err), ERR_getErrorName(err_code)); \ + _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ + RAWLOG(3, ": " __VA_ARGS__); \ + RAWLOG(3, "\n"); \ + return err_code; \ + } \ + } while(0); /*-************************************* @@ -65,7 +134,7 @@ namespace duckdb_zstd { #define ZSTD_OPT_NUM (1<<12) #define ZSTD_REP_NUM 3 /* number of repcodes */ -static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; +#define ZSTD_REP_MOVE (ZSTD_REP_NUM-1) #define KB *(1 <<10) #define MB *(1 <<20) @@ -79,21 +148,19 @@ static UNUSED_ATTR const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 }; #define BIT0 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10 -static UNUSED_ATTR const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 }; -static UNUSED_ATTR const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 }; #define ZSTD_FRAMEIDSIZE 4 /* magic number size */ #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */ -static UNUSED_ATTR const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; + typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; #define ZSTD_FRAMECHECKSUMSIZE 4 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */) /* for a non-null block */ -#define MIN_LITERALS_FOR_4_STREAMS 6 +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ +#define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 @@ -101,7 +168,6 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy #define MINMATCH 3 #define Litbits 8 -#define LitHufLog 11 #define MaxLit ((1<= 8 || (ovtype == ZSTD_no_overlap && diff <= -WILDCOPY_VECLEN)); + if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) { /* Handle short offset copies. */ do { - COPY8(op, ip); + COPY8(op, ip) } while (op < oend); } else { assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN); @@ -236,15 +260,20 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e * one COPY16() in the first call. Then, do two calls per loop since * at that point it is more likely to have a high trip count. */ - ZSTD_copy16(op, ip); - if (16 >= length) return; - op += 16; - ip += 16; +#ifndef __aarch64__ + do { + COPY16(op, ip); + } + while (op < oend); +#else + COPY16(op, ip); + if (op >= oend) return; do { COPY16(op, ip); COPY16(op, ip); } while (op < oend); +#endif } } @@ -252,7 +281,7 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, { size_t const length = MIN(dstCapacity, srcSize); if (length > 0) { - ZSTD_memcpy(dst, src, length); + memcpy(dst, src, length); } return length; } @@ -267,46 +296,28 @@ MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, * In which case, resize it down to free some memory */ #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 -/* Controls whether the input/output buffer is buffered or stable. */ -typedef enum { - ZSTD_bm_buffered = 0, /* Buffer the input/output */ - ZSTD_bm_stable = 1 /* ZSTD_inBuffer/ZSTD_outBuffer is stable */ -} ZSTD_bufferMode_e; - /*-******************************************* * Private declarations *********************************************/ typedef struct seqDef_s { - U32 offBase; /* offBase == Offset + ZSTD_REP_NUM, or repcode 1,2,3 */ + U32 offset; U16 litLength; - U16 mlBase; /* mlBase == matchLength - MINMATCH */ + U16 matchLength; } seqDef; -/* Controls whether seqStore has a single "long" litLength or matchLength. See seqStore_t. */ -typedef enum { - ZSTD_llt_none = 0, /* no longLengthType */ - ZSTD_llt_literalLength = 1, /* represents a long literal */ - ZSTD_llt_matchLength = 2 /* represents a long match */ -} ZSTD_longLengthType_e; - typedef struct { seqDef* sequencesStart; - seqDef* sequences; /* ptr to end of sequences */ - BYTE* litStart; - BYTE* lit; /* ptr to end of literals */ - BYTE* llCode; - BYTE* mlCode; - BYTE* ofCode; + seqDef* sequences; + BYTE* litStart; + BYTE* lit; + BYTE* llCode; + BYTE* mlCode; + BYTE* ofCode; size_t maxNbSeq; size_t maxNbLit; - - /* longLengthPos and longLengthType to allow us to represent either a single litLength or matchLength - * in the seqStore that has a value larger than U16 (if it exists). To do so, we increment - * the existing value of the litLength or matchLength by 0x10000. - */ - ZSTD_longLengthType_e longLengthType; - U32 longLengthPos; /* Index of the sequence to apply long length modification to */ + U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */ + U32 longLengthPos; } seqStore_t; typedef struct { @@ -316,19 +327,19 @@ typedef struct { /** * Returns the ZSTD_sequenceLength for the given sequences. It handles the decoding of long sequences - * indicated by longLengthPos and longLengthType, and adds MINMATCH back to matchLength. + * indicated by longLengthPos and longLengthID, and adds MINMATCH back to matchLength. */ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore, seqDef const* seq) { ZSTD_sequenceLength seqLen; seqLen.litLength = seq->litLength; - seqLen.matchLength = seq->mlBase + MINMATCH; + seqLen.matchLength = seq->matchLength + MINMATCH; if (seqStore->longLengthPos == (U32)(seq - seqStore->sequencesStart)) { - if (seqStore->longLengthType == ZSTD_llt_literalLength) { - seqLen.litLength += 0x10000; + if (seqStore->longLengthID == 1) { + seqLen.litLength += 0xFFFF; } - if (seqStore->longLengthType == ZSTD_llt_matchLength) { - seqLen.matchLength += 0x10000; + if (seqStore->longLengthID == 2) { + seqLen.matchLength += 0xFFFF; } } return seqLen; @@ -341,13 +352,42 @@ MEM_STATIC ZSTD_sequenceLength ZSTD_getSequenceLength(seqStore_t const* seqStore * `decompressedBound != ZSTD_CONTENTSIZE_ERROR` */ typedef struct { - size_t nbBlocks; size_t compressedSize; unsigned long long decompressedBound; } ZSTD_frameSizeInfo; /* decompress & legacy */ const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx); /* compress & dictBuilder */ -int ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ +void ZSTD_seqToCodes(const seqStore_t* seqStorePtr); /* compress, dictBuilder, decodeCorpus (shouldn't get its definition from here) */ + +/* custom memory allocation functions */ +void* ZSTD_malloc(size_t size, ZSTD_customMem customMem); +void* ZSTD_calloc(size_t size, ZSTD_customMem customMem); +void ZSTD_free(void* ptr, ZSTD_customMem customMem); + + +MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ +{ + assert(val != 0); + { +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + return _BitScanReverse(&r, val) ? (unsigned)r : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return __builtin_clz (val) ^ 31; +# elif defined(__ICCARM__) /* IAR Intrinsic */ + return 31 - __CLZ(val); +# else /* Software version */ + static const U32 DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return DeBruijnClz[(v * 0x07C4ACDDU) >> 27]; +# endif + } +} /* ZSTD_invalidateRepCodes() : @@ -365,25 +405,16 @@ typedef struct { /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ -/* Used by: decompress, fullbench */ +/* Used by: decompress, fullbench (does not get its definition from here) */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); /*! ZSTD_decodeSeqHeaders() : * decode sequence header from src */ -/* Used by: zstd_decompress_block, fullbench */ +/* Used by: decompress, fullbench (does not get its definition from here) */ size_t ZSTD_decodeSeqHeaders(ZSTD_DCtx* dctx, int* nbSeqPtr, const void* src, size_t srcSize); -/** - * @returns true iff the CPU supports dynamic BMI2 dispatch. - */ -MEM_STATIC int ZSTD_cpuSupportsBmi2(void) -{ - ZSTD_cpuid_t cpuid = ZSTD_cpuid(); - return ZSTD_cpuid_bmi1(cpuid) && ZSTD_cpuid_bmi2(cpuid); } -} // namespace duckdb_zstd - #endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h b/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h deleted file mode 100644 index 045ce9067..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/common/zstd_trace.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_TRACE_H -#define ZSTD_TRACE_H - -#include - -namespace duckdb_zstd { - -/* weak symbol support - * For now, enable conservatively: - * - Only GNUC - * - Only ELF - * - Only x86-64, i386 and aarch64 - * Also, explicitly disable on platforms known not to work so they aren't - * forgotten in the future. - */ -#if !defined(ZSTD_HAVE_WEAK_SYMBOLS) && \ - defined(__GNUC__) && defined(__ELF__) && \ - (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__aarch64__)) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__MINGW32__) && \ - !defined(__CYGWIN__) && !defined(_AIX) -# define ZSTD_HAVE_WEAK_SYMBOLS 1 -#else -# define ZSTD_HAVE_WEAK_SYMBOLS 0 -#endif -#if ZSTD_HAVE_WEAK_SYMBOLS -# define ZSTD_WEAK_ATTR __attribute__((__weak__)) -#else -# define ZSTD_WEAK_ATTR -#endif - -/* Only enable tracing when weak symbols are available. */ -#ifndef ZSTD_TRACE -# define ZSTD_TRACE ZSTD_HAVE_WEAK_SYMBOLS -#endif - -#if ZSTD_TRACE - -struct ZSTD_CCtx_s; -struct ZSTD_DCtx_s; -struct ZSTD_CCtx_params_s; - -typedef struct { - /** - * ZSTD_VERSION_NUMBER - * - * This is guaranteed to be the first member of ZSTD_trace. - * Otherwise, this struct is not stable between versions. If - * the version number does not match your expectation, you - * should not interpret the rest of the struct. - */ - unsigned version; - /** - * Non-zero if streaming (de)compression is used. - */ - unsigned streaming; - /** - * The dictionary ID. - */ - unsigned dictionaryID; - /** - * Is the dictionary cold? - * Only set on decompression. - */ - unsigned dictionaryIsCold; - /** - * The dictionary size or zero if no dictionary. - */ - size_t dictionarySize; - /** - * The uncompressed size of the data. - */ - size_t uncompressedSize; - /** - * The compressed size of the data. - */ - size_t compressedSize; - /** - * The fully resolved CCtx parameters (NULL on decompression). - */ - struct ZSTD_CCtx_params_s const* params; - /** - * The ZSTD_CCtx pointer (NULL on decompression). - */ - struct ZSTD_CCtx_s const* cctx; - /** - * The ZSTD_DCtx pointer (NULL on compression). - */ - struct ZSTD_DCtx_s const* dctx; -} ZSTD_Trace; - -/** - * A tracing context. It must be 0 when tracing is disabled. - * Otherwise, any non-zero value returned by a tracing begin() - * function is presented to any subsequent calls to end(). - * - * Any non-zero value is treated as tracing is enabled and not - * interpreted by the library. - * - * Two possible uses are: - * * A timestamp for when the begin() function was called. - * * A unique key identifying the (de)compression, like the - * address of the [dc]ctx pointer if you need to track - * more information than just a timestamp. - */ -typedef unsigned long long ZSTD_TraceCtx; - -/** - * Trace the beginning of a compression call. - * @param cctx The dctx pointer for the compression. - * It can be used as a key to map begin() to end(). - * @returns Non-zero if tracing is enabled. The return value is - * passed to ZSTD_trace_compress_end(). - */ -ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_compress_begin( - struct ZSTD_CCtx_s const* cctx); - -/** - * Trace the end of a compression call. - * @param ctx The return value of ZSTD_trace_compress_begin(). - * @param trace The zstd tracing info. - */ -ZSTD_WEAK_ATTR void ZSTD_trace_compress_end( - ZSTD_TraceCtx ctx, - ZSTD_Trace const* trace); - -/** - * Trace the beginning of a decompression call. - * @param dctx The dctx pointer for the decompression. - * It can be used as a key to map begin() to end(). - * @returns Non-zero if tracing is enabled. The return value is - * passed to ZSTD_trace_compress_end(). - */ -ZSTD_WEAK_ATTR ZSTD_TraceCtx ZSTD_trace_decompress_begin( - struct ZSTD_DCtx_s const* dctx); - -/** - * Trace the end of a decompression call. - * @param ctx The return value of ZSTD_trace_decompress_begin(). - * @param trace The zstd tracing info. - */ -ZSTD_WEAK_ATTR void ZSTD_trace_decompress_end( - ZSTD_TraceCtx ctx, - ZSTD_Trace const* trace); - -#endif /* ZSTD_TRACE */ - -} // namespace duckdb_zstd - -#endif /* ZSTD_TRACE_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h b/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h deleted file mode 100644 index be9424b13..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/compress/clevels.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_CLEVELS_H -#define ZSTD_CLEVELS_H - -#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressionParameters */ -#include "zstd.h" - -namespace duckdb_zstd { - -/*-===== Pre-defined compression levels =====-*/ - -#define ZSTD_MAX_CLEVEL 22 - -#ifdef __GNUC__ -__attribute__((__unused__)) -#endif - -static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { -{ /* "default" - for any srcSize > 256 KB */ - /* W, C, H, S, L, TL, strat */ - { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ - { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ - { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ - { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ - { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ - { 21, 18, 19, 3, 5, 2, ZSTD_greedy }, /* level 5 */ - { 21, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6 */ - { 21, 19, 20, 4, 5, 8, ZSTD_lazy }, /* level 7 */ - { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 8 */ - { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ - { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 10 */ - { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 11 */ - { 22, 22, 23, 6, 5, 32, ZSTD_lazy2 }, /* level 12 */ - { 22, 22, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ - { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ - { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ - { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ - { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ - { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ - { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ - { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ - { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ - { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ -}, -{ /* for srcSize <= 256 KB */ - /* W, C, H, S, L, T, strat */ - { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ - { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ - { 18, 16, 17, 3, 5, 2, ZSTD_greedy }, /* level 4.*/ - { 18, 17, 18, 5, 5, 2, ZSTD_greedy }, /* level 5.*/ - { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ - { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ - { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ - { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ - { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ - { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 128 KB */ - /* W, C, H, S, L, T, strat */ - { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ - { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ - { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ - { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ - { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ - { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 17, 16, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 17, 16, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ - { 17, 16, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ - { 17, 16, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ - { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ - { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ - { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ - { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ - { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ - { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ - { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ - { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ - { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -{ /* for srcSize <= 16 KB */ - /* W, C, H, S, L, T, strat */ - { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ - { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ - { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ - { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ - { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ - { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ - { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ - { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ - { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ - { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ - { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ - { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ - { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ - { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ - { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ - { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ - { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ - { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ - { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ - { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ - { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ - { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ -}, -}; - -} // namespace duckdb_zstd - -#endif /* ZSTD_CLEVELS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/hist.h b/src/duckdb/third_party/zstd/include/zstd/compress/hist.h index 083af82c1..41bbbbeab 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/hist.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/hist.h @@ -1,7 +1,7 @@ /* ****************************************************************** * hist : Histogram functions * part of Finite State Entropy project - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2013-2020, Yann Collet, Facebook, Inc. * * You can contact the author at : * - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy @@ -14,10 +14,10 @@ ****************************************************************** */ /* --- dependencies --- */ -#include "zstd/common/zstd_deps.h" /* size_t */ +#include /* size_t */ -namespace duckdb_zstd { +namespace duckdb_zstd { /* --- simple histogram functions --- */ /*! HIST_count(): @@ -75,4 +75,4 @@ size_t HIST_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, unsigned HIST_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); -} // namespace duckdb_zstd +} diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h index 1f55ab1bc..5e8c6e099 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,12 +20,9 @@ ***************************************/ #include "zstd/common/zstd_internal.h" #include "zstd/compress/zstd_cwksp.h" -#ifdef ZSTD_MULTITHREAD -# include "zstd/compress/zstdmt_compress.h" -#endif -#include "zstd/common/bits.h" /* ZSTD_highbit32, ZSTD_NbCommonBytes */ - -namespace duckdb_zstd { +// #ifdef ZSTD_MULTITHREAD +// # include "zstdmt_compress.h" +// #endif /*-************************************* * Constants @@ -37,10 +34,11 @@ namespace duckdb_zstd { It's not a big deal though : candidate will just be sorted again. Additionally, candidate position 1 will be lost. But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss. - The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table reuse with a different strategy. + The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be mishandled after table re-use with a different strategy. This constant is required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */ +namespace duckdb_zstd { /*-************************************* * Context memory management ***************************************/ @@ -62,7 +60,7 @@ typedef struct { } ZSTD_localDict; typedef struct { - HUF_CElt CTable[HUF_CTABLE_SIZE_ST(255)]; + U32 CTable[HUF_CTABLE_SIZE_U32(255)]; HUF_repeat repeatMode; } ZSTD_hufCTables_t; @@ -80,101 +78,29 @@ typedef struct { ZSTD_fseCTables_t fse; } ZSTD_entropyCTables_t; -/*********************************************** -* Entropy buffer statistics structs and funcs * -***********************************************/ -/** ZSTD_hufCTablesMetadata_t : - * Stores Literals Block Type for a super-block in hType, and - * huffman tree description in hufDesBuffer. - * hufDesSize refers to the size of huffman tree description in bytes. - * This metadata is populated in ZSTD_buildBlockEntropyStats_literals() */ -typedef struct { - symbolEncodingType_e hType; - BYTE hufDesBuffer[ZSTD_MAX_HUF_HEADER_SIZE]; - size_t hufDesSize; -} ZSTD_hufCTablesMetadata_t; - -/** ZSTD_fseCTablesMetadata_t : - * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and - * fse tables in fseTablesBuffer. - * fseTablesSize refers to the size of fse tables in bytes. - * This metadata is populated in ZSTD_buildBlockEntropyStats_sequences() */ typedef struct { - symbolEncodingType_e llType; - symbolEncodingType_e ofType; - symbolEncodingType_e mlType; - BYTE fseTablesBuffer[ZSTD_MAX_FSE_HEADERS_SIZE]; - size_t fseTablesSize; - size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ -} ZSTD_fseCTablesMetadata_t; - -typedef struct { - ZSTD_hufCTablesMetadata_t hufMetadata; - ZSTD_fseCTablesMetadata_t fseMetadata; -} ZSTD_entropyCTablesMetadata_t; - -/** ZSTD_buildBlockEntropyStats() : - * Builds entropy for the block. - * @return : 0 on success or error code */ -size_t ZSTD_buildBlockEntropyStats( - const seqStore_t* seqStorePtr, - const ZSTD_entropyCTables_t* prevEntropy, - ZSTD_entropyCTables_t* nextEntropy, - const ZSTD_CCtx_params* cctxParams, - ZSTD_entropyCTablesMetadata_t* entropyMetadata, - void* workspace, size_t wkspSize); - -/********************************* -* Compression internals structs * -*********************************/ - -typedef struct { - U32 off; /* Offset sumtype code for the match, using ZSTD_storeSeq() format */ - U32 len; /* Raw length of match */ + U32 off; + U32 len; } ZSTD_match_t; typedef struct { - U32 offset; /* Offset of sequence */ - U32 litLength; /* Length of literals prior to match */ - U32 matchLength; /* Raw length of match */ -} rawSeq; - -typedef struct { - rawSeq* seq; /* The start of the sequences */ - size_t pos; /* The index in seq where reading stopped. pos <= size. */ - size_t posInSequence; /* The position within the sequence at seq[pos] where reading - stopped. posInSequence <= seq[pos].litLength + seq[pos].matchLength */ - size_t size; /* The number of sequences. <= capacity. */ - size_t capacity; /* The capacity starting from `seq` pointer */ -} rawSeqStore_t; - -typedef struct { - U32 idx; /* Index in array of ZSTD_Sequence */ - U32 posInSequence; /* Position within sequence at idx */ - size_t posInSrc; /* Number of bytes given by sequences provided so far */ -} ZSTD_sequencePosition; - -UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0}; - -typedef struct { - int price; /* price from beginning of segment to this position */ - U32 off; /* offset of previous match */ - U32 mlen; /* length of previous match */ - U32 litlen; /* nb of literals since previous match */ - U32 rep[ZSTD_REP_NUM]; /* offset history after previous match */ + int price; + U32 off; + U32 mlen; + U32 litlen; + U32 rep[ZSTD_REP_NUM]; } ZSTD_optimal_t; typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e; -#define ZSTD_OPT_SIZE (ZSTD_OPT_NUM+3) typedef struct { /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */ unsigned* litFreq; /* table of literals statistics, of size 256 */ unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */ unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */ unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */ - ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_SIZE */ - ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_SIZE */ + ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */ + ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */ U32 litSum; /* nb of literals */ U32 litLengthSum; /* nb of litLength codes */ @@ -186,7 +112,7 @@ typedef struct { U32 offCodeSumBasePrice; /* to compare to log2(offreq) */ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */ - ZSTD_paramSwitch_e literalCompressionMode; + ZSTD_literalCompressionMode_e literalCompressionMode; } optState_t; typedef struct { @@ -195,23 +121,14 @@ typedef struct { } ZSTD_compressedBlockState_t; typedef struct { - BYTE const* nextSrc; /* next block here to continue on current prefix */ - BYTE const* base; /* All regular indexes relative to this position */ - BYTE const* dictBase; /* extDict indexes relative to this position */ - U32 dictLimit; /* below that point, need extDict */ - U32 lowLimit; /* below that point, no more valid data */ - U32 nbOverflowCorrections; /* Number of times overflow correction has run since - * ZSTD_window_init(). Useful for debugging coredumps - * and for ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY. - */ + BYTE const* nextSrc; /* next block here to continue on current prefix */ + BYTE const* base; /* All regular indexes relative to this position */ + BYTE const* dictBase; /* extDict indexes relative to this position */ + U32 dictLimit; /* below that point, need extDict */ + U32 lowLimit; /* below that point, no more valid data */ } ZSTD_window_t; -#define ZSTD_WINDOW_START_INDEX 2 - typedef struct ZSTD_matchState_t ZSTD_matchState_t; - -#define ZSTD_ROW_HASH_CACHE_SIZE 8 /* Size of prefetching hash cache for row-based matchfinder */ - struct ZSTD_matchState_t { ZSTD_window_t window; /* State for window round buffer management */ U32 loadedDictEnd; /* index of end of dictionary, within context's referential. @@ -223,38 +140,12 @@ struct ZSTD_matchState_t { */ U32 nextToUpdate; /* index from which to continue table update */ U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */ - - U32 rowHashLog; /* For row-based matchfinder: Hashlog based on nb of rows in the hashTable.*/ - BYTE* tagTable; /* For row-based matchFinder: A row-based table containing the hashes and head index. */ - U32 hashCache[ZSTD_ROW_HASH_CACHE_SIZE]; /* For row-based matchFinder: a cache of hashes to improve speed */ - U64 hashSalt; /* For row-based matchFinder: salts the hash for reuse of tag table */ - U32 hashSaltEntropy; /* For row-based matchFinder: collects entropy for salt generation */ - U32* hashTable; U32* hashTable3; U32* chainTable; - - U32 forceNonContiguous; /* Non-zero if we should force non-contiguous load for the next window update. */ - - int dedicatedDictSearch; /* Indicates whether this matchState is using the - * dedicated dictionary search structure. - */ optState_t opt; /* optimal parser state */ const ZSTD_matchState_t* dictMatchState; ZSTD_compressionParameters cParams; - const rawSeqStore_t* ldmSeqStore; - - /* Controls prefetching in some dictMatchState matchfinders. - * This behavior is controlled from the cctx ms. - * This parameter has no effect in the cdict ms. */ - int prefetchCDictTables; - - /* When == 0, lazy match finders insert every position. - * When != 0, lazy match finders only insert positions they search. - * This allows them to skip much faster over incompressible data, - * at a small cost to compression ratio. - */ - int lazySkipping; }; typedef struct { @@ -268,26 +159,17 @@ typedef struct { U32 checksum; } ldmEntry_t; -typedef struct { - BYTE const* split; - U32 hash; - U32 checksum; - ldmEntry_t* bucket; -} ldmMatchCandidate_t; - -#define LDM_BATCH_SIZE 64 - typedef struct { ZSTD_window_t window; /* State for the window round buffer management */ ldmEntry_t* hashTable; U32 loadedDictEnd; BYTE* bucketOffsets; /* Next position in bucket to insert entry */ - size_t splitIndices[LDM_BATCH_SIZE]; - ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE]; + U64 hashPower; /* Used to compute the rolling hash. + * Depends on ldmParams.minMatchLength */ } ldmState_t; typedef struct { - ZSTD_paramSwitch_e enableLdm; /* ZSTD_ps_enable to enable LDM. ZSTD_ps_auto by default */ + U32 enableLdm; /* 1 if enable long distance matching */ U32 hashLog; /* Log size of hashTable */ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */ U32 minMatchLength; /* Minimum match length */ @@ -295,6 +177,19 @@ typedef struct { U32 windowLog; /* Window log for the LDM */ } ldmParams_t; +typedef struct { + U32 offset; + U32 litLength; + U32 matchLength; +} rawSeq; + +typedef struct { + rawSeq* seq; /* The start of the sequences */ + size_t pos; /* The position where reading stopped. <= size. */ + size_t size; /* The number of sequences. <= capacity. */ + size_t capacity; /* The capacity starting from `seq` pointer */ +} rawSeqStore_t; + typedef struct { int collectSequences; ZSTD_Sequence* seqStart; @@ -318,7 +213,7 @@ struct ZSTD_CCtx_params_s { * There is no guarantee that hint is close to actual source size */ ZSTD_dictAttachPref_e attachDictPref; - ZSTD_paramSwitch_e literalCompressionMode; + ZSTD_literalCompressionMode_e literalCompressionMode; /* Multithreading: used to pass parameters to mtctx */ int nbWorkers; @@ -329,87 +224,17 @@ struct ZSTD_CCtx_params_s { /* Long distance matching parameters */ ldmParams_t ldmParams; - /* Dedicated dict search algorithm trigger */ - int enableDedicatedDictSearch; - - /* Input/output buffer modes */ - ZSTD_bufferMode_e inBufferMode; - ZSTD_bufferMode_e outBufferMode; - - /* Sequence compression API */ - ZSTD_sequenceFormat_e blockDelimiters; - int validateSequences; - - /* Block splitting */ - ZSTD_paramSwitch_e useBlockSplitter; - - /* Param for deciding whether to use row-based matchfinder */ - ZSTD_paramSwitch_e useRowMatchFinder; - - /* Always load a dictionary in ext-dict mode (not prefix mode)? */ - int deterministicRefPrefix; - /* Internal use, for createCCtxParams() and freeCCtxParams() only */ ZSTD_customMem customMem; - - /* Controls prefetching in some dictMatchState matchfinders */ - ZSTD_paramSwitch_e prefetchCDictTables; - - /* Controls whether zstd will fall back to an internal matchfinder - * if the external matchfinder returns an error code. */ - int enableMatchFinderFallback; - - /* Parameters for the external sequence producer API. - * Users set these parameters through ZSTD_registerSequenceProducer(). - * It is not possible to set these parameters individually through the public API. */ - void* extSeqProdState; - ZSTD_sequenceProducer_F extSeqProdFunc; - - /* Adjust the max block size*/ - size_t maxBlockSize; - - /* Controls repcode search in external sequence parsing */ - ZSTD_paramSwitch_e searchForExternalRepcodes; }; /* typedef'd to ZSTD_CCtx_params within "zstd.h" */ -#define COMPRESS_SEQUENCES_WORKSPACE_SIZE (sizeof(unsigned) * (MaxSeq + 2)) -#define ENTROPY_WORKSPACE_SIZE (HUF_WORKSPACE_SIZE + COMPRESS_SEQUENCES_WORKSPACE_SIZE) - -/** - * Indicates whether this compression proceeds directly from user-provided - * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or - * whether the context needs to buffer the input/output (ZSTDb_buffered). - */ -typedef enum { - ZSTDb_not_buffered, - ZSTDb_buffered -} ZSTD_buffered_policy_e; - -/** - * Struct that contains all elements of block splitter that should be allocated - * in a wksp. - */ -#define ZSTD_MAX_NB_BLOCK_SPLITS 196 -typedef struct { - seqStore_t fullSeqStoreChunk; - seqStore_t firstHalfSeqStore; - seqStore_t secondHalfSeqStore; - seqStore_t currSeqStore; - seqStore_t nextSeqStore; - - U32 partitions[ZSTD_MAX_NB_BLOCK_SPLITS]; - ZSTD_entropyCTablesMetadata_t entropyMetadata; -} ZSTD_blockSplitCtx; - struct ZSTD_CCtx_s { ZSTD_compressionStage_e stage; int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */ int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ ZSTD_CCtx_params requestedParams; ZSTD_CCtx_params appliedParams; - ZSTD_CCtx_params simpleApiParams; /* Param storage used by the simple API - not sticky. Must only be used in top-level simple API functions for storage. */ U32 dictID; - size_t dictContentSize; ZSTD_cwksp workspace; /* manages buffer for dynamic allocations */ size_t blockSize; @@ -418,7 +243,6 @@ struct ZSTD_CCtx_s { unsigned long long producedCSize; XXH64_state_t xxhState; ZSTD_customMem customMem; - ZSTD_threadPool* pool; size_t staticSize; SeqCollector seqCollector; int isFirstBlock; @@ -430,10 +254,7 @@ struct ZSTD_CCtx_s { size_t maxNbLdmSequences; rawSeqStore_t externSeqStore; /* Mutable reference to external sequences */ ZSTD_blockState_t blockState; - U32* entropyWorkspace; /* entropy workspace of ENTROPY_WORKSPACE_SIZE bytes */ - - /* Whether we are streaming or not */ - ZSTD_buffered_policy_e bufferedPolicy; + U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ /* streaming */ char* inBuff; @@ -448,11 +269,6 @@ struct ZSTD_CCtx_s { ZSTD_cStreamStage streamStage; U32 frameEnded; - /* Stable in/out buffer verification */ - ZSTD_inBuffer expectedInBuffer; - size_t stableIn_notConsumed; /* nb bytes within stable input buffer that are said to be consumed but are not */ - size_t expectedOutBufferSize; - /* Dictionary */ ZSTD_localDict localDict; const ZSTD_CDict* cdict; @@ -462,54 +278,17 @@ struct ZSTD_CCtx_s { #ifdef ZSTD_MULTITHREAD ZSTDMT_CCtx* mtctx; #endif - - /* Tracing */ -#if ZSTD_TRACE - ZSTD_TraceCtx traceCtx; -#endif - - /* Workspace for block splitter */ - ZSTD_blockSplitCtx blockSplitCtx; - - /* Buffer for output from external sequence producer */ - ZSTD_Sequence* extSeqBuf; - size_t extSeqBufCapacity; }; typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; -typedef enum { ZSTD_tfp_forCCtx, ZSTD_tfp_forCDict } ZSTD_tableFillPurpose_e; - -typedef enum { - ZSTD_noDict = 0, - ZSTD_extDict = 1, - ZSTD_dictMatchState = 2, - ZSTD_dedicatedDictSearch = 3 -} ZSTD_dictMode_e; - -typedef enum { - ZSTD_cpm_noAttachDict = 0, /* Compression with ZSTD_noDict or ZSTD_extDict. - * In this mode we use both the srcSize and the dictSize - * when selecting and adjusting parameters. - */ - ZSTD_cpm_attachDict = 1, /* Compression with ZSTD_dictMatchState or ZSTD_dedicatedDictSearch. - * In this mode we only take the srcSize into account when selecting - * and adjusting parameters. - */ - ZSTD_cpm_createCDict = 2, /* Creating a CDict. - * In this mode we take both the source size and the dictionary size - * into account when selecting and adjusting the parameters. - */ - ZSTD_cpm_unknown = 3 /* ZSTD_getCParams, ZSTD_getParams, ZSTD_adjustParams. - * We don't know what these parameters are for. We default to the legacy - * behavior of taking both the source size and the dict size into account - * when selecting and adjusting parameters. - */ -} ZSTD_cParamMode_e; + +typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e; + typedef size_t (*ZSTD_blockCompressor) ( ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e rowMatchfinderMode, ZSTD_dictMode_e dictMode); +ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode); MEM_STATIC U32 ZSTD_LLcode(U32 litLength) @@ -543,6 +322,31 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase) return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase]; } +typedef struct repcodes_s { + U32 rep[3]; +} repcodes_t; + +MEM_STATIC repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0) +{ + repcodes_t newReps; + if (offset >= ZSTD_REP_NUM) { /* full offset */ + newReps.rep[2] = rep[1]; + newReps.rep[1] = rep[0]; + newReps.rep[0] = offset - ZSTD_REP_MOVE; + } else { /* repcode */ + U32 const repCode = offset + ll0; + if (repCode > 0) { /* note : if repCode==0, no change */ + U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; + newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2]; + newReps.rep[1] = rep[0]; + newReps.rep[0] = currentOffset; + } else { /* repCode == 0 */ + memcpy(&newReps, rep, sizeof(newReps)); + } + } + return newReps; +} + /* ZSTD_cParam_withinBounds: * @return 1 if value is within cParam bounds, * 0 otherwise */ @@ -558,20 +362,17 @@ MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value) /* ZSTD_noCompressBlock() : * Writes uncompressed block to dst buffer from given src. * Returns the size of the block */ -MEM_STATIC size_t -ZSTD_noCompressBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) +MEM_STATIC size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) { U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); - DEBUGLOG(5, "ZSTD_noCompressBlock (srcSize=%zu, dstCapacity=%zu)", srcSize, dstCapacity); - RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, + RETURN_ERROR_IF(srcSize + ZSTDInternalConstants::ZSTD_blockHeaderSize > dstCapacity, dstSize_tooSmall, "dst buf too small for uncompressed block"); MEM_writeLE24(dst, cBlockHeader24); - ZSTD_memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); - return ZSTD_blockHeaderSize + srcSize; + memcpy((BYTE*)dst + ZSTDInternalConstants::ZSTD_blockHeaderSize, src, srcSize); + return ZSTDInternalConstants::ZSTD_blockHeaderSize + srcSize; } -MEM_STATIC size_t -ZSTD_rleCompressBlock(void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) +MEM_STATIC size_t ZSTD_rleCompressBlock (void* dst, size_t dstCapacity, BYTE src, size_t srcSize, U32 lastBlock) { BYTE* const op = (BYTE*)dst; U32 const cBlockHeader = lastBlock + (((U32)bt_rle)<<1) + (U32)(srcSize << 3); @@ -590,21 +391,21 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) { U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6; ZSTD_STATIC_ASSERT(ZSTD_btultra == 8); - assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, (int)strat)); + assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); return (srcSize >> minlog) + 2; } -MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxParams) +MEM_STATIC int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) { switch (cctxParams->literalCompressionMode) { - case ZSTD_ps_enable: + case ZSTD_lcm_huffman: return 0; - case ZSTD_ps_disable: + case ZSTD_lcm_uncompressed: return 1; default: assert(0 /* impossible: pre-validated */); - ZSTD_FALLTHROUGH; - case ZSTD_ps_auto: + /* fall-through */ + case ZSTD_lcm_auto: return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); } } @@ -614,9 +415,7 @@ MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxPa * Only called when the sequence ends past ilimit_w, so it only needs to be optimized for single * large copies. */ -static void -ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) -{ +static void ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE const* ilimit_w) { assert(iend > ilimit_w); if (ip <= ilimit_w) { ZSTD_wildcopy(op, ip, ilimit_w - ip, ZSTD_no_overlap); @@ -626,28 +425,14 @@ ZSTD_safecopyLiterals(BYTE* op, BYTE const* ip, BYTE const* const iend, BYTE con while (ip < iend) *op++ = *ip++; } - -#define REPCODE1_TO_OFFBASE REPCODE_TO_OFFBASE(1) -#define REPCODE2_TO_OFFBASE REPCODE_TO_OFFBASE(2) -#define REPCODE3_TO_OFFBASE REPCODE_TO_OFFBASE(3) -#define REPCODE_TO_OFFBASE(r) (assert((r)>=1), assert((r)<=ZSTD_REP_NUM), (r)) /* accepts IDs 1,2,3 */ -#define OFFSET_TO_OFFBASE(o) (assert((o)>0), o + ZSTD_REP_NUM) -#define OFFBASE_IS_OFFSET(o) ((o) > ZSTD_REP_NUM) -#define OFFBASE_IS_REPCODE(o) ( 1 <= (o) && (o) <= ZSTD_REP_NUM) -#define OFFBASE_TO_OFFSET(o) (assert(OFFBASE_IS_OFFSET(o)), (o) - ZSTD_REP_NUM) -#define OFFBASE_TO_REPCODE(o) (assert(OFFBASE_IS_REPCODE(o)), (o)) /* returns ID 1,2,3 */ - /*! ZSTD_storeSeq() : - * Store a sequence (litlen, litPtr, offBase and matchLength) into seqStore_t. - * @offBase : Users should employ macros REPCODE_TO_OFFBASE() and OFFSET_TO_OFFBASE(). - * @matchLength : must be >= MINMATCH - * Allowed to over-read literals up to litLimit. + * Store a sequence (litlen, litPtr, offCode and mlBase) into seqStore_t. + * `offCode` : distance to match + ZSTD_REP_MOVE (values <= ZSTD_REP_MOVE are repCodes). + * `mlBase` : matchLength - MINMATCH + * Allowed to overread literals up to litLimit. */ -HINT_INLINE UNUSED_ATTR void -ZSTD_storeSeq(seqStore_t* seqStorePtr, - size_t litLength, const BYTE* literals, const BYTE* litLimit, - U32 offBase, - size_t matchLength) +HINT_INLINE UNUSED_ATTR +void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, const BYTE* litLimit, U32 offCode, size_t mlBase) { BYTE const* const litLimit_w = litLimit - WILDCOPY_OVERLENGTH; BYTE const* const litEnd = literals + litLength; @@ -655,8 +440,8 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, static const BYTE* g_start = NULL; if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */ { U32 const pos = (U32)((const BYTE*)literals - g_start); - DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offBase%7u", - pos, (U32)litLength, (U32)matchLength, (U32)offBase); + DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u", + pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offCode); } #endif assert((size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart) < seqStorePtr->maxNbSeq); @@ -666,9 +451,9 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, assert(literals + litLength <= litLimit); if (litEnd <= litLimit_w) { /* Common case we can use wildcopy. - * First copy 16 bytes, because literals are likely short. - */ - ZSTD_STATIC_ASSERT(WILDCOPY_OVERLENGTH >= 16); + * First copy 16 bytes, because literals are likely short. + */ + assert(WILDCOPY_OVERLENGTH >= 16); ZSTD_copy16(seqStorePtr->lit, literals); if (litLength > 16) { ZSTD_wildcopy(seqStorePtr->lit+16, literals+16, (ptrdiff_t)litLength-16, ZSTD_no_overlap); @@ -680,70 +465,95 @@ ZSTD_storeSeq(seqStore_t* seqStorePtr, /* literal Length */ if (litLength>0xFFFF) { - assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ - seqStorePtr->longLengthType = ZSTD_llt_literalLength; + assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ + seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } seqStorePtr->sequences[0].litLength = (U16)litLength; /* match offset */ - seqStorePtr->sequences[0].offBase = offBase; + seqStorePtr->sequences[0].offset = offCode + 1; /* match Length */ - assert(matchLength >= MINMATCH); - { size_t const mlBase = matchLength - MINMATCH; - if (mlBase>0xFFFF) { - assert(seqStorePtr->longLengthType == ZSTD_llt_none); /* there can only be a single long length */ - seqStorePtr->longLengthType = ZSTD_llt_matchLength; - seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); - } - seqStorePtr->sequences[0].mlBase = (U16)mlBase; + if (mlBase>0xFFFF) { + assert(seqStorePtr->longLengthID == 0); /* there can only be a single long length */ + seqStorePtr->longLengthID = 2; + seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); } + seqStorePtr->sequences[0].matchLength = (U16)mlBase; seqStorePtr->sequences++; } -/* ZSTD_updateRep() : - * updates in-place @rep (array of repeat offsets) - * @offBase : sum-type, using numeric representation of ZSTD_storeSeq() - */ -MEM_STATIC void -ZSTD_updateRep(U32 rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) -{ - if (OFFBASE_IS_OFFSET(offBase)) { /* full offset */ - rep[2] = rep[1]; - rep[1] = rep[0]; - rep[0] = OFFBASE_TO_OFFSET(offBase); - } else { /* repcode */ - U32 const repCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; - if (repCode > 0) { /* note : if repCode==0, no change */ - U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode]; - rep[2] = (repCode >= 2) ? rep[1] : rep[2]; - rep[1] = rep[0]; - rep[0] = currentOffset; - } else { /* repCode == 0 */ - /* nothing to do */ - } - } -} - -typedef struct repcodes_s { - U32 rep[3]; -} repcodes_t; -MEM_STATIC repcodes_t -ZSTD_newRep(U32 const rep[ZSTD_REP_NUM], U32 const offBase, U32 const ll0) +/*-************************************* +* Match length counter +***************************************/ +static unsigned ZSTD_NbCommonBytes (size_t val) { - repcodes_t newReps; - ZSTD_memcpy(&newReps, rep, sizeof(newReps)); - ZSTD_updateRep(newReps.rep, offBase, ll0); - return newReps; + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + return _BitScanForward64( &r, (U64)val ) ? (unsigned)(r >> 3) : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, + 0, 3, 1, 3, 1, 4, 2, 7, + 0, 2, 3, 6, 1, 5, 3, 5, + 1, 3, 4, 4, 2, 5, 6, 7, + 7, 0, 1, 2, 3, 3, 4, 6, + 2, 6, 5, 5, 3, 4, 5, 6, + 7, 1, 2, 4, 6, 4, 4, 5, + 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r=0; + return _BitScanForward( &r, (U32)val ) ? (unsigned)(r >> 3) : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, + 3, 2, 2, 1, 3, 2, 0, 1, + 3, 3, 1, 2, 2, 2, 2, 0, + 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } else { /* Big Endian CPU */ + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + return _BitScanReverse64( &r, val ) ? (unsigned)(r >> 3) : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 4) + return (__builtin_clzll(val) >> 3); +# else + unsigned r; + const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ + if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } else { /* 32 bits */ +# if defined(_MSC_VER) + unsigned long r = 0; + return _BitScanReverse( &r, (unsigned long)val ) ? (unsigned)(r >> 3) : 0; +# elif defined(__GNUC__) && (__GNUC__ >= 3) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } } } -/*-************************************* -* Match length counter -***************************************/ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit) { const BYTE* const pStart = pIn; @@ -789,43 +599,31 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match, * Hashes ***************************************/ static const U32 prime3bytes = 506832829U; -static U32 ZSTD_hash3(U32 u, U32 h, U32 s) { assert(h <= 32); return (((u << (32-24)) * prime3bytes) ^ s) >> (32-h) ; } -MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h, 0); } /* only in zstd_opt.h */ -MEM_STATIC size_t ZSTD_hash3PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash3(MEM_readLE32(ptr), h, s); } +static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; } +MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */ static const U32 prime4bytes = 2654435761U; -static U32 ZSTD_hash4(U32 u, U32 h, U32 s) { assert(h <= 32); return ((u * prime4bytes) ^ s) >> (32-h) ; } -static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_readLE32(ptr), h, 0); } -static size_t ZSTD_hash4PtrS(const void* ptr, U32 h, U32 s) { return ZSTD_hash4(MEM_readLE32(ptr), h, s); } +static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } +static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } static const U64 prime5bytes = 889523592379ULL; -static size_t ZSTD_hash5(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-40)) * prime5bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash5PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash5(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } +static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } static const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-48)) * prime6bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash6PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash6(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } static const U64 prime7bytes = 58295818150454627ULL; -static size_t ZSTD_hash7(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u << (64-56)) * prime7bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash7PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash7(MEM_readLE64(p), h, s); } +static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } +static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL; -static size_t ZSTD_hash8(U64 u, U32 h, U64 s) { assert(h <= 64); return (size_t)((((u) * prime8bytes) ^ s) >> (64-h)) ; } -static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h, 0); } -static size_t ZSTD_hash8PtrS(const void* p, U32 h, U64 s) { return ZSTD_hash8(MEM_readLE64(p), h, s); } - +static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; } +static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); } -MEM_STATIC FORCE_INLINE_ATTR -size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) +MEM_STATIC size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) { - /* Although some of these hashes do support hBits up to 64, some do not. - * To be on the safe side, always avoid hBits > 32. */ - assert(hBits <= 32); - switch(mls) { default: @@ -837,24 +635,6 @@ size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } } -MEM_STATIC FORCE_INLINE_ATTR -size_t ZSTD_hashPtrSalted(const void* p, U32 hBits, U32 mls, const U64 hashSalt) { - /* Although some of these hashes do support hBits up to 64, some do not. - * To be on the safe side, always avoid hBits > 32. */ - assert(hBits <= 32); - - switch(mls) - { - default: - case 4: return ZSTD_hash4PtrS(p, hBits, (U32)hashSalt); - case 5: return ZSTD_hash5PtrS(p, hBits, hashSalt); - case 6: return ZSTD_hash6PtrS(p, hBits, hashSalt); - case 7: return ZSTD_hash7PtrS(p, hBits, hashSalt); - case 8: return ZSTD_hash8PtrS(p, hBits, hashSalt); - } -} - - /** ZSTD_ipow() : * Return base^exponent. */ @@ -939,13 +719,6 @@ MEM_STATIC void ZSTD_window_clear(ZSTD_window_t* window) window->dictLimit = end; } -MEM_STATIC U32 ZSTD_window_isEmpty(ZSTD_window_t const window) -{ - return window.dictLimit == ZSTD_WINDOW_START_INDEX && - window.lowLimit == ZSTD_WINDOW_START_INDEX && - (window.nextSrc - window.base) == ZSTD_WINDOW_START_INDEX; -} - /** * ZSTD_window_hasExtDict(): * Returns non-zero if the window has a non-empty extDict. @@ -965,76 +738,20 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms) return ZSTD_window_hasExtDict(ms->window) ? ZSTD_extDict : ms->dictMatchState != NULL ? - (ms->dictMatchState->dedicatedDictSearch ? ZSTD_dedicatedDictSearch : ZSTD_dictMatchState) : + ZSTD_dictMatchState : ZSTD_noDict; } -/* Defining this macro to non-zero tells zstd to run the overflow correction - * code much more frequently. This is very inefficient, and should only be - * used for tests and fuzzers. - */ -#ifndef ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY -# ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 1 -# else -# define ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY 0 -# endif -#endif - -/** - * ZSTD_window_canOverflowCorrect(): - * Returns non-zero if the indices are large enough for overflow correction - * to work correctly without impacting compression ratio. - */ -MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window, - U32 cycleLog, - U32 maxDist, - U32 loadedDictEnd, - void const* src) -{ - U32 const cycleSize = 1u << cycleLog; - U32 const curr = (U32)((BYTE const*)src - window.base); - U32 const minIndexToOverflowCorrect = cycleSize - + MAX(maxDist, cycleSize) - + ZSTD_WINDOW_START_INDEX; - - /* Adjust the min index to backoff the overflow correction frequency, - * so we don't waste too much CPU in overflow correction. If this - * computation overflows we don't really care, we just need to make - * sure it is at least minIndexToOverflowCorrect. - */ - U32 const adjustment = window.nbOverflowCorrections + 1; - U32 const adjustedIndex = MAX(minIndexToOverflowCorrect * adjustment, - minIndexToOverflowCorrect); - U32 const indexLargeEnough = curr > adjustedIndex; - - /* Only overflow correct early if the dictionary is invalidated already, - * so we don't hurt compression ratio. - */ - U32 const dictionaryInvalidated = curr > maxDist + loadedDictEnd; - - return indexLargeEnough && dictionaryInvalidated; -} - /** * ZSTD_window_needOverflowCorrection(): * Returns non-zero if the indices are getting too large and need overflow * protection. */ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, - U32 cycleLog, - U32 maxDist, - U32 loadedDictEnd, - void const* src, void const* srcEnd) { - U32 const curr = (U32)((BYTE const*)srcEnd - window.base); - if (ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { - if (ZSTD_window_canOverflowCorrect(window, cycleLog, maxDist, loadedDictEnd, src)) { - return 1; - } - } - return curr > ZSTD_CURRENT_MAX; + U32 const current = (U32)((BYTE const*)srcEnd - window.base); + return current > ZSTD_CURRENT_MAX; } /** @@ -1045,10 +762,9 @@ MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, * * The least significant cycleLog bits of the indices must remain the same, * which may be 0. Every index up to maxDist in the past must be valid. + * NOTE: (maxDist & cycleMask) must be zero. */ -MEM_STATIC -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, +MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, U32 maxDist, void const* src) { /* preemptive overflow correction: @@ -1070,52 +786,32 @@ U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * 3. (cctx->lowLimit + 1< 3<<29 + 1<base); - U32 const currentCycle = curr & cycleMask; - /* Ensure newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX. */ - U32 const currentCycleCorrection = currentCycle < ZSTD_WINDOW_START_INDEX - ? MAX(cycleSize, ZSTD_WINDOW_START_INDEX) - : 0; - U32 const newCurrent = currentCycle - + currentCycleCorrection - + MAX(maxDist, cycleSize); - U32 const correction = curr - newCurrent; - /* maxDist must be a power of two so that: - * (newCurrent & cycleMask) == (curr & cycleMask) - * This is required to not corrupt the chains / binary tree. - */ - assert((maxDist & (maxDist - 1)) == 0); - assert((curr & cycleMask) == (newCurrent & cycleMask)); - assert(curr > newCurrent); - if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { - /* Loose bound, should be around 1<<29 (see above) */ - assert(correction > 1<<28); - } + U32 const cycleMask = (1U << cycleLog) - 1; + U32 const current = (U32)((BYTE const*)src - window->base); + U32 const currentCycle0 = current & cycleMask; + /* Exclude zero so that newCurrent - maxDist >= 1. */ + U32 const currentCycle1 = currentCycle0 == 0 ? (1U << cycleLog) : currentCycle0; + U32 const newCurrent = currentCycle1 + maxDist; + U32 const correction = current - newCurrent; + assert((maxDist & cycleMask) == 0); + assert(current > newCurrent); + /* Loose bound, should be around 1<<29 (see above) */ + assert(correction > 1<<28); window->base += correction; window->dictBase += correction; - if (window->lowLimit < correction + ZSTD_WINDOW_START_INDEX) { - window->lowLimit = ZSTD_WINDOW_START_INDEX; - } else { - window->lowLimit -= correction; - } - if (window->dictLimit < correction + ZSTD_WINDOW_START_INDEX) { - window->dictLimit = ZSTD_WINDOW_START_INDEX; - } else { - window->dictLimit -= correction; - } + if (window->lowLimit <= correction) window->lowLimit = 1; + else window->lowLimit -= correction; + if (window->dictLimit <= correction) window->dictLimit = 1; + else window->dictLimit -= correction; /* Ensure we can still reference the full window. */ assert(newCurrent >= maxDist); - assert(newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX); + assert(newCurrent - maxDist >= 1); /* Ensure that lowLimit and dictLimit didn't underflow. */ assert(window->lowLimit <= newCurrent); assert(window->dictLimit <= newCurrent); - ++window->nbOverflowCorrections; - DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, window->lowLimit); return correction; @@ -1204,15 +900,10 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, (unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd); assert(blockEndIdx >= loadedDictEnd); - if (blockEndIdx > loadedDictEnd + maxDist || loadedDictEnd != window->dictLimit) { + if (blockEndIdx > loadedDictEnd + maxDist) { /* On reaching window size, dictionaries are invalidated. * For simplification, if window size is reached anywhere within next block, * the dictionary is invalidated for the full block. - * - * We also have to invalidate the dictionary if ZSTD_window_update() has detected - * non-contiguous segments, which means that loadedDictEnd != window->dictLimit. - * loadedDictEnd may be 0, if forceWindow is true, but in that case we never use - * dictMatchState, so setting it to NULL is not a problem. */ DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)"); *loadedDictEndPtr = 0; @@ -1224,14 +915,12 @@ ZSTD_checkDictValidity(const ZSTD_window_t* window, } MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { - ZSTD_memset(window, 0, sizeof(*window)); - window->base = (BYTE const*)" "; - window->dictBase = (BYTE const*)" "; - ZSTD_STATIC_ASSERT(ZSTD_DUBT_UNSORTED_MARK < ZSTD_WINDOW_START_INDEX); /* Start above ZSTD_DUBT_UNSORTED_MARK */ - window->dictLimit = ZSTD_WINDOW_START_INDEX; /* start from >0, so that 1st position is valid */ - window->lowLimit = ZSTD_WINDOW_START_INDEX; /* it ensures first and later CCtx usages compress the same */ - window->nextSrc = window->base + ZSTD_WINDOW_START_INDEX; /* see issue #1241 */ - window->nbOverflowCorrections = 0; + memset(window, 0, sizeof(*window)); + window->base = (BYTE const*)""; + window->dictBase = (BYTE const*)""; + window->dictLimit = 1; /* start from 1, so that 1st position is valid */ + window->lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ + window->nextSrc = window->base + 1; /* see issue #1241 */ } /** @@ -1241,11 +930,8 @@ MEM_STATIC void ZSTD_window_init(ZSTD_window_t* window) { * forget about the extDict. Handles overlap of the prefix and extDict. * Returns non-zero if the segment is contiguous. */ -MEM_STATIC -ZSTD_ALLOW_POINTER_OVERFLOW_ATTR -U32 ZSTD_window_update(ZSTD_window_t* window, - void const* src, size_t srcSize, - int forceNonContiguous) +MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window, + void const* src, size_t srcSize) { BYTE const* const ip = (BYTE const*)src; U32 contiguous = 1; @@ -1255,7 +941,7 @@ U32 ZSTD_window_update(ZSTD_window_t* window, assert(window->base != NULL); assert(window->dictBase != NULL); /* Check if blocks follow each other */ - if (src != window->nextSrc || forceNonContiguous) { + if (src != window->nextSrc) { /* not contiguous */ size_t const distanceFromBase = (size_t)(window->nextSrc - window->base); DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit); @@ -1283,32 +969,25 @@ U32 ZSTD_window_update(ZSTD_window_t* window, /** * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix. */ -MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) { - U32 const maxDistance = 1U << windowLog; - U32 const lowestValid = ms->window.lowLimit; - U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; - U32 const isDictionary = (ms->loadedDictEnd != 0); - /* When using a dictionary the entire dictionary is valid if a single byte of the dictionary - * is within the window. We invalidate the dictionary (and set loadedDictEnd to 0) when it isn't - * valid for the entire block. So this check is sufficient to find the lowest valid match index. - */ - U32 const matchLowest = isDictionary ? lowestValid : withinWindow; + U32 const maxDistance = 1U << windowLog; + U32 const lowestValid = ms->window.lowLimit; + U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; + U32 const isDictionary = (ms->loadedDictEnd != 0); + U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } /** * Returns the lowest allowed match index in the prefix. */ -MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 curr, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog) { U32 const maxDistance = 1U << windowLog; U32 const lowestValid = ms->window.dictLimit; - U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; + U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); - /* When computing the lowest prefix index we need to take the dictionary into account to handle - * the edge case where the dictionary and the source are contiguous in memory. - */ U32 const matchLowest = isDictionary ? lowestValid : withinWindow; return matchLowest; } @@ -1346,43 +1025,6 @@ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max) #endif -/* Short Cache */ - -/* Normally, zstd matchfinders follow this flow: - * 1. Compute hash at ip - * 2. Load index from hashTable[hash] - * 3. Check if *ip == *(base + index) - * In dictionary compression, loading *(base + index) is often an L2 or even L3 miss. - * - * Short cache is an optimization which allows us to avoid step 3 most of the time - * when the data doesn't actually match. With short cache, the flow becomes: - * 1. Compute (hash, currentTag) at ip. currentTag is an 8-bit independent hash at ip. - * 2. Load (index, matchTag) from hashTable[hash]. See ZSTD_writeTaggedIndex to understand how this works. - * 3. Only if currentTag == matchTag, check *ip == *(base + index). Otherwise, continue. - * - * Currently, short cache is only implemented in CDict hashtables. Thus, its use is limited to - * dictMatchState matchfinders. - */ -#define ZSTD_SHORT_CACHE_TAG_BITS 8 -#define ZSTD_SHORT_CACHE_TAG_MASK ((1u << ZSTD_SHORT_CACHE_TAG_BITS) - 1) - -/* Helper function for ZSTD_fillHashTable and ZSTD_fillDoubleHashTable. - * Unpacks hashAndTag into (hash, tag), then packs (index, tag) into hashTable[hash]. */ -MEM_STATIC void ZSTD_writeTaggedIndex(U32* const hashTable, size_t hashAndTag, U32 index) { - size_t const hash = hashAndTag >> ZSTD_SHORT_CACHE_TAG_BITS; - U32 const tag = (U32)(hashAndTag & ZSTD_SHORT_CACHE_TAG_MASK); - assert(index >> (32 - ZSTD_SHORT_CACHE_TAG_BITS) == 0); - hashTable[hash] = (index << ZSTD_SHORT_CACHE_TAG_BITS) | tag; -} - -/* Helper function for short cache matchfinders. - * Unpacks tag1 and tag2 from lower bits of packedTag1 and packedTag2, then checks if the tags match. */ -MEM_STATIC int ZSTD_comparePackedTags(size_t packedTag1, size_t packedTag2) { - U32 const tag1 = packedTag1 & ZSTD_SHORT_CACHE_TAG_MASK; - U32 const tag2 = packedTag2 & ZSTD_SHORT_CACHE_TAG_MASK; - return tag1 == tag2; -} - /* =============================================================== * Shared internal declarations * These prototypes may be called from sources not in lib/compress @@ -1394,6 +1036,7 @@ MEM_STATIC int ZSTD_comparePackedTags(size_t packedTag1, size_t packedTag2) { * assumptions : magic number supposed already checked * and dictSize >= 8 */ size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, + short* offcodeNCount, unsigned* offcodeMaxValue, const void* const dict, size_t dictSize); void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); @@ -1409,7 +1052,7 @@ void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs); * Note: srcSizeHint == 0 means 0! */ ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); + const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize); /*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. @@ -1460,70 +1103,16 @@ size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity); * This cannot be used when long range matching is enabled. * Zstd will use these sequences, and pass the literals to a secondary block * compressor. + * @return : An error code on failure. * NOTE: seqs are not verified! Invalid sequences can cause out-of-bounds memory * access and data corruption. */ -void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); +size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq); /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat); -/** ZSTD_CCtx_trace() : - * Trace the end of a compression call. - */ -void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize); - -/* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of - * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter. - * Note that the block delimiter must include the last literals of the block. - */ -size_t -ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, - ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); - -/* Returns the number of bytes to move the current read position back by. - * Only non-zero if we ended up splitting a sequence. - * Otherwise, it may return a ZSTD error if something went wrong. - * - * This function will attempt to scan through blockSize bytes - * represented by the sequences in @inSeqs, - * storing any (partial) sequences. - * - * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to - * avoid splitting a match, or to avoid splitting a match such that it would produce a match - * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block. - */ -size_t -ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, - const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, - const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); - -/* Returns 1 if an external sequence producer is registered, otherwise returns 0. */ -MEM_STATIC int ZSTD_hasExtSeqProd(const ZSTD_CCtx_params* params) { - return params->extSeqProdFunc != NULL; } -/* =============================================================== - * Deprecated definitions that are still used internally to avoid - * deprecation warnings. These functions are exactly equivalent to - * their public variants, but avoid the deprecation warnings. - * =============================================================== */ - -size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); - -size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); - -size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); - -} // namespace duckdb_zstd - #endif /* ZSTD_COMPRESS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h index a8fc05ba7..7082db522 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_literals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,26 +17,16 @@ namespace duckdb_zstd { size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* ZSTD_compressRleLiteralsBlock() : - * Conditions : - * - All bytes in @src are identical - * - dstCapacity >= 4 */ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* ZSTD_compressLiterals(): - * @entropyWorkspace: must be aligned on 4-bytes boundaries - * @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE - * @suspectUncompressible: sampling checks, to potentially skip huffman coding - */ -size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const ZSTD_hufCTables_t* prevHuf, +size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, ZSTD_hufCTables_t* nextHuf, ZSTD_strategy strategy, int disableLiteralCompression, - int suspectUncompressible, - int bmi2); + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const int bmi2); -} // namespace duckdb_zstd +} #endif /* ZSTD_COMPRESS_LITERALS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h index 885663f2e..63e27ea63 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_sequences.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -54,6 +54,6 @@ size_t ZSTD_fseBitCost( size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, unsigned const* count, unsigned const max); -} // namespace duckdb_zstd +} #endif /* ZSTD_COMPRESS_SEQUENCES_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h index 34b7a3bf2..df4055036 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_compress_superblock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -18,7 +18,6 @@ #include "zstd.h" /* ZSTD_CCtx */ namespace duckdb_zstd { - /*-************************************* * Target Compressed Block Size ***************************************/ @@ -30,7 +29,7 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, void const* src, size_t srcSize, unsigned lastBlock); +} -} // namespace duckdb_zstd #endif /* ZSTD_COMPRESS_ADVANCED_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h index bb1c62cee..aea4f469c 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_cwksp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -14,11 +14,7 @@ /*-************************************* * Dependencies ***************************************/ -#include "zstd/common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ #include "zstd/common/zstd_internal.h" -#include "zstd/common/portability_macros.h" - -namespace duckdb_zstd { /*-************************************* * Constants @@ -35,30 +31,21 @@ namespace duckdb_zstd { #define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128 #endif +#if defined (MEMORY_SANITIZER) +#include +#endif -/* Set our tables and aligneds to align by 64 bytes */ -#define ZSTD_CWKSP_ALIGNMENT_BYTES 64 +namespace duckdb_zstd { /*-************************************* * Structures ***************************************/ typedef enum { ZSTD_cwksp_alloc_objects, - ZSTD_cwksp_alloc_aligned_init_once, - ZSTD_cwksp_alloc_aligned, - ZSTD_cwksp_alloc_buffers + ZSTD_cwksp_alloc_buffers, + ZSTD_cwksp_alloc_aligned } ZSTD_cwksp_alloc_phase_e; -/** - * Used to describe whether the workspace is statically allocated (and will not - * necessarily ever be freed), or if it's dynamically allocated and we can - * expect a well-formed caller to free this. - */ -typedef enum { - ZSTD_cwksp_dynamic_alloc, - ZSTD_cwksp_static_alloc -} ZSTD_cwksp_static_alloc_e; - /** * Zstd fits all its internal datastructures into a single continuous buffer, * so that it only needs to perform a single OS allocation (or so that a buffer @@ -99,15 +86,15 @@ typedef enum { * * Workspace Layout: * - * [ ... workspace ... ] - * [objects][tables ->] free space [<- buffers][<- aligned][<- init once] + * [ ... workspace ... ] + * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers] * * The various objects that live in the workspace are divided into the * following categories, and are allocated separately: * * - Static objects: this is optionally the enclosing ZSTD_CCtx or ZSTD_CDict, * so that literally everything fits in a single buffer. Note: if present, - * this must be the first object in the workspace, since ZSTD_customFree{CCtx, + * this must be the first object in the workspace, since ZSTD_free{CCtx, * CDict}() rely on a pointer comparison to see whether one or two frees are * required. * @@ -122,20 +109,10 @@ typedef enum { * - Tables: these are any of several different datastructures (hash tables, * chain tables, binary trees) that all respect a common format: they are * uint32_t arrays, all of whose values are between 0 and (nextSrc - base). - * Their sizes depend on the cparams. These tables are 64-byte aligned. - * - * - Init once: these buffers require to be initialized at least once before - * use. They should be used when we want to skip memory initialization - * while not triggering memory checkers (like Valgrind) when reading from - * from this memory without writing to it first. - * These buffers should be used carefully as they might contain data - * from previous compressions. - * Buffers are aligned to 64 bytes. + * Their sizes depend on the cparams. * - * - Aligned: these buffers don't require any initialization before they're - * used. The user of the buffer should make sure they write into a buffer - * location before reading from it. - * Buffers are aligned to 64 bytes. + * - Aligned: these buffers are used for various purposes that require 4 byte + * alignment, but don't require any initialization before they're used. * * - Buffers: these buffers are used for various purposes that don't require * any alignment or initialization before they're used. This means they can @@ -147,9 +124,9 @@ typedef enum { * correctly packed into the workspace buffer. That order is: * * 1. Objects - * 2. Init once / Tables - * 3. Aligned / Tables - * 4. Buffers / Tables + * 2. Buffers + * 3. Aligned + * 4. Tables * * Attempts to reserve objects of different types out of order will fail. */ @@ -161,12 +138,10 @@ typedef struct { void* tableEnd; void* tableValidEnd; void* allocStart; - void* initOnceStart; - BYTE allocFailed; + int allocFailed; int workspaceOversizedDuration; ZSTD_cwksp_alloc_phase_e phase; - ZSTD_cwksp_static_alloc_e isStatic; } ZSTD_cwksp; /*-************************************* @@ -174,7 +149,6 @@ typedef struct { ***************************************/ MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws); -MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws); MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { (void)ws; @@ -184,8 +158,6 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) { assert(ws->tableEnd <= ws->allocStart); assert(ws->tableValidEnd <= ws->allocStart); assert(ws->allocStart <= ws->workspaceEnd); - assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws)); - assert(ws->workspace <= ws->initOnceStart); } /** @@ -206,68 +178,63 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) { * Since tables aren't currently redzoned, you don't need to call through this * to figure out how much space you need for the matchState tables. Everything * else is though. - * - * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size(). */ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) { - if (size == 0) - return 0; +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; +#else return size; +#endif } -/** - * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes. - * Used to determine the number of bytes required for a given "aligned". - */ -MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) { - return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES)); +MEM_STATIC void ZSTD_cwksp_internal_advance_phase( + ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) { + assert(phase >= ws->phase); + if (phase > ws->phase) { + if (ws->phase < ZSTD_cwksp_alloc_buffers && + phase >= ZSTD_cwksp_alloc_buffers) { + ws->tableValidEnd = ws->objectEnd; + } + if (ws->phase < ZSTD_cwksp_alloc_aligned && + phase >= ZSTD_cwksp_alloc_aligned) { + /* If unaligned allocations down from a too-large top have left us + * unaligned, we need to realign our alloc ptr. Technically, this + * can consume space that is unaccounted for in the neededSpace + * calculation. However, I believe this can only happen when the + * workspace is too large, and specifically when it is too large + * by a larger margin than the space that will be consumed. */ + /* TODO: cleaner, compiler warning friendly way to do this??? */ + ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1)); + if (ws->allocStart < ws->tableValidEnd) { + ws->tableValidEnd = ws->allocStart; + } + } + ws->phase = phase; + } } /** - * Returns the amount of additional space the cwksp must allocate - * for internal purposes (currently only alignment). + * Returns whether this object/buffer/etc was allocated in this workspace. */ -MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) { - /* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES - * bytes to align the beginning of tables section and end of buffers; - */ - size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2; - return slackSpace; +MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) { + return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd); } - /** - * Return the number of additional bytes required to align a pointer to the given number of bytes. - * alignBytes must be a power of two. + * Internal function. Do not use directly. */ -MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) { - size_t const alignBytesMask = alignBytes - 1; - size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask; - assert((alignBytes & alignBytesMask) == 0); - assert(bytes < alignBytes); - return bytes; -} +MEM_STATIC void* ZSTD_cwksp_reserve_internal( + ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) { + void* alloc; + void* bottom = ws->tableEnd; + ZSTD_cwksp_internal_advance_phase(ws, phase); + alloc = (BYTE *)ws->allocStart - bytes; -/** - * Returns the initial value for allocStart which is used to determine the position from - * which we can allocate from the end of the workspace. - */ -MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) { - return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1)); -} +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* over-reserve space */ + alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; +#endif -/** - * Internal function. Do not use directly. - * Reserves the given number of bytes within the aligned/buffer segment of the wksp, - * which counts from the end of the wksp (as opposed to the object/table segment). - * - * Returns a pointer to the beginning of that space. - */ -MEM_STATIC void* -ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) -{ - void* const alloc = (BYTE*)ws->allocStart - bytes; - void* const bottom = ws->tableEnd; DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); ZSTD_cwksp_assert_internal_consistency(ws); @@ -277,149 +244,51 @@ ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) ws->allocFailed = 1; return NULL; } - /* the area is reserved from the end of wksp. - * If it overlaps with tableValidEnd, it voids guarantees on values' range */ if (alloc < ws->tableValidEnd) { ws->tableValidEnd = alloc; } ws->allocStart = alloc; - return alloc; -} - -/** - * Moves the cwksp to the next phase, and does any necessary allocations. - * cwksp initialization must necessarily go through each phase in order. - * Returns a 0 on success, or zstd error - */ -MEM_STATIC size_t -ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) -{ - assert(phase >= ws->phase); - if (phase > ws->phase) { - /* Going from allocating objects to allocating initOnce / tables */ - if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once && - phase >= ZSTD_cwksp_alloc_aligned_init_once) { - ws->tableValidEnd = ws->objectEnd; - ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); - - { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */ - void *const alloc = ws->objectEnd; - size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES); - void *const objectEnd = (BYTE *) alloc + bytesToAlign; - DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign); - RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation, - "table phase - alignment initial allocation failed!"); - ws->objectEnd = objectEnd; - ws->tableEnd = objectEnd; /* table area starts being empty */ - if (ws->tableValidEnd < ws->tableEnd) { - ws->tableValidEnd = ws->tableEnd; - } - } - } - ws->phase = phase; - ZSTD_cwksp_assert_internal_consistency(ws); - } - return 0; -} -/** - * Returns whether this object/buffer/etc was allocated in this workspace. - */ -MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) -{ - return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd); -} - -/** - * Internal function. Do not use directly. - */ -MEM_STATIC void* -ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) -{ - void* alloc; - if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) { - return NULL; - } +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on + * either size. */ + alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + __asan_unpoison_memory_region(alloc, bytes); +#endif - alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes); return alloc; } /** * Reserves and returns unaligned memory. */ -MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) -{ +MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) { return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers); } /** - * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). - * This memory has been initialized at least once in the past. - * This doesn't mean it has been initialized this time, and it might contain data from previous - * operations. - * The main usage is for algorithms that might need read access into uninitialized memory. - * The algorithm must maintain safety under these conditions and must make sure it doesn't - * leak any of the past data (directly or in side channels). - */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes) -{ - size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES); - void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once); - assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); - if(ptr && ptr < ws->initOnceStart) { - /* We assume the memory following the current allocation is either: - * 1. Not usable as initOnce memory (end of workspace) - * 2. Another initOnce buffer that has been allocated before (and so was previously memset) - * 3. An ASAN redzone, in which case we don't want to write on it - * For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart. - * Note that we assume here that MSAN and ASAN cannot run in the same time. */ - ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes)); - ws->initOnceStart = ptr; - } -#if ZSTD_MEMORY_SANITIZER - assert(__msan_test_shadow(ptr, bytes) == -1); -#endif - return ptr; -} - -/** - * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes). + * Reserves and returns memory sized on and aligned on sizeof(unsigned). */ -MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) -{ - void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES), - ZSTD_cwksp_alloc_aligned); - assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); - return ptr; +MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) { + assert((bytes & (sizeof(U32)-1)) == 0); + return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned); } /** - * Aligned on 64 bytes. These buffers have the special property that - * their values remain constrained, allowing us to reuse them without + * Aligned on sizeof(unsigned). These buffers have the special property that + * their values remain constrained, allowing us to re-use them without * memset()-ing them. */ -MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) -{ - const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once; - void* alloc; - void* end; - void* top; - - /* We can only start allocating tables after we are done reserving space for objects at the - * start of the workspace */ - if(ws->phase < phase) { - if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) { - return NULL; - } - } - alloc = ws->tableEnd; - end = (BYTE *)alloc + bytes; - top = ws->allocStart; +MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) { + const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned; + void* alloc = ws->tableEnd; + void* end = (BYTE *)alloc + bytes; + void* top = ws->allocStart; DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining", alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes); assert((bytes & (sizeof(U32)-1)) == 0); + ZSTD_cwksp_internal_advance_phase(ws, phase); ZSTD_cwksp_assert_internal_consistency(ws); assert(end <= top); if (end > top) { @@ -429,30 +298,35 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) } ws->tableEnd = end; - assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0); - assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0); +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + __asan_unpoison_memory_region(alloc, bytes); +#endif + return alloc; } /** * Aligned on sizeof(void*). - * Note : should happen only once, at workspace first initialization */ -MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) -{ - size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); +MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) { + size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*)); void* alloc = ws->objectEnd; void* end = (BYTE*)alloc + roundedBytes; - DEBUGLOG(4, +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* over-reserve space */ + end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE; +#endif + + DEBUGLOG(5, "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining", alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes); - assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0); - assert(bytes % ZSTD_ALIGNOF(void*) == 0); + assert(((size_t)alloc & (sizeof(void*)-1)) == 0); + assert((bytes & (sizeof(void*)-1)) == 0); ZSTD_cwksp_assert_internal_consistency(ws); /* we must be in the first phase, no advance is possible */ if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) { - DEBUGLOG(3, "cwksp: object alloc failed!"); + DEBUGLOG(4, "cwksp: object alloc failed!"); ws->allocFailed = 1; return NULL; } @@ -460,13 +334,30 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) ws->tableEnd = end; ws->tableValidEnd = end; +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on + * either size. */ + alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE; + __asan_unpoison_memory_region(alloc, bytes); +#endif + return alloc; } -MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) -{ +MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty"); +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) + /* To validate that the table re-use logic is sound, and that we don't + * access table space that we haven't cleaned, we re-"poison" the table + * space every time we mark it dirty. */ + { + size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; + assert(__msan_test_shadow(ws->objectEnd, size) == -1); + __msan_poison(ws->objectEnd, size); + } +#endif + assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); ws->tableValidEnd = ws->objectEnd; @@ -491,7 +382,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { assert(ws->tableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); if (ws->tableValidEnd < ws->tableEnd) { - ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd)); + memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd); } ZSTD_cwksp_mark_tables_clean(ws); } @@ -503,6 +394,13 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing tables!"); +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + { + size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd; + __asan_poison_memory_region(ws->objectEnd, size); + } +#endif + ws->tableEnd = ws->objectEnd; ZSTD_cwksp_assert_internal_consistency(ws); } @@ -514,66 +412,77 @@ MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) { MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) { DEBUGLOG(4, "cwksp: clearing!"); +#if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) + /* To validate that the context re-use logic is sound, and that we don't + * access stuff that this compression hasn't initialized, we re-"poison" + * the workspace (or at least the non-static, non-table parts of it) + * every time we start a new compression. */ + { + size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd; + __msan_poison(ws->tableValidEnd, size); + } +#endif + +#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE) + { + size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd; + __asan_poison_memory_region(ws->objectEnd, size); + } +#endif + ws->tableEnd = ws->objectEnd; - ws->allocStart = ZSTD_cwksp_initialAllocStart(ws); + ws->allocStart = ws->workspaceEnd; ws->allocFailed = 0; - if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) { - ws->phase = ZSTD_cwksp_alloc_aligned_init_once; + if (ws->phase > ZSTD_cwksp_alloc_buffers) { + ws->phase = ZSTD_cwksp_alloc_buffers; } ZSTD_cwksp_assert_internal_consistency(ws); } -MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { - return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); -} - -MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) { - return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace) - + (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart); -} - /** * The provided workspace takes ownership of the buffer [start, start+size). * Any existing values in the workspace are ignored (the previously managed * buffer, if present, must be separately freed). */ -MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_cwksp_static_alloc_e isStatic) { +MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size) { DEBUGLOG(4, "cwksp: init'ing workspace with %zd bytes", size); assert(((size_t)start & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ ws->workspace = start; ws->workspaceEnd = (BYTE*)start + size; ws->objectEnd = ws->workspace; ws->tableValidEnd = ws->objectEnd; - ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws); ws->phase = ZSTD_cwksp_alloc_objects; - ws->isStatic = isStatic; ZSTD_cwksp_clear(ws); ws->workspaceOversizedDuration = 0; ZSTD_cwksp_assert_internal_consistency(ws); } MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem customMem) { - void* workspace = ZSTD_customMalloc(size, customMem); + void* workspace = ZSTD_malloc(size, customMem); DEBUGLOG(4, "cwksp: creating new workspace with %zd bytes", size); RETURN_ERROR_IF(workspace == NULL, memory_allocation, "NULL pointer!"); - ZSTD_cwksp_init(ws, workspace, size, ZSTD_cwksp_dynamic_alloc); + ZSTD_cwksp_init(ws, workspace, size); return 0; } MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) { void *ptr = ws->workspace; DEBUGLOG(4, "cwksp: freeing workspace"); - ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp)); - ZSTD_customFree(ptr, customMem); + memset(ws, 0, sizeof(ZSTD_cwksp)); + ZSTD_free(ptr, customMem); } /** * Moves the management of a workspace from one cwksp to another. The src cwksp - * is left in an invalid state (src must be re-init()'ed before it's used again). + * is left in an invalid state (src must be re-init()'ed before its used again). */ MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) { *dst = *src; - ZSTD_memset(src, 0, sizeof(ZSTD_cwksp)); + memset(src, 0, sizeof(ZSTD_cwksp)); +} + +MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) { + return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace); } MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { @@ -584,18 +493,6 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) { * Functions Checking Free Space ***************************************/ -/* ZSTD_alignmentSpaceWithinBounds() : - * Returns if the estimated space needed for a wksp is within an acceptable limit of the - * actual amount of space used. - */ -MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) { - /* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice - * the alignment bytes difference between estimation and actual usage */ - return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) && - ZSTD_cwksp_used(ws) <= estimatedSpace; -} - - MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) { return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd); } @@ -623,6 +520,6 @@ MEM_STATIC void ZSTD_cwksp_bump_oversized_duration( } } -} // namespace duckdb_zstd +} #endif /* ZSTD_CWKSP_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h index c91680abc..7991711fa 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_double_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -16,12 +16,8 @@ namespace duckdb_zstd { -#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp); - + void const* end, ZSTD_dictTableLoadMethod_e dtlm); size_t ZSTD_compressBlock_doubleFast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -32,15 +28,6 @@ size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST ZSTD_compressBlock_doubleFast -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE ZSTD_compressBlock_doubleFast_dictMatchState -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT ZSTD_compressBlock_doubleFast_extDict -#else -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST NULL -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT NULL -#endif /* ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR */ - -} // namespace duckdb_zstd +} #endif /* ZSTD_DOUBLE_FAST_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h index 2f7ee5b64..a75839a06 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_fast.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -17,8 +17,7 @@ namespace duckdb_zstd { void ZSTD_fillHashTable(ZSTD_matchState_t* ms, - void const* end, ZSTD_dictTableLoadMethod_e dtlm, - ZSTD_tableFillPurpose_e tfp); + void const* end, ZSTD_dictTableLoadMethod_e dtlm); size_t ZSTD_compressBlock_fast( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -29,6 +28,6 @@ size_t ZSTD_compressBlock_fast_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -} // namespace duckdb_zstd +} #endif /* ZSTD_FAST_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h index d43882c46..555edbf1b 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_lazy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,183 +15,49 @@ namespace duckdb_zstd { -/** - * Dedicated Dictionary Search Structure bucket log. In the - * ZSTD_dedicatedDictSearch mode, the hashTable has - * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just - * one. - */ -#define ZSTD_LAZY_DDSS_BUCKET_LOG 2 - -#define ZSTD_ROW_HASH_TAG_BITS 8 /* nb bits to use for the tag */ - -#if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip); -void ZSTD_row_update(ZSTD_matchState_t* const ms, const BYTE* ip); - -void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip); void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */ -#endif -#ifndef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_greedy( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch( +size_t ZSTD_compressBlock_btlazy2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_dedicatedDictSearch_row( +size_t ZSTD_compressBlock_lazy2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_extDict( +size_t ZSTD_compressBlock_lazy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_greedy_extDict_row( +size_t ZSTD_compressBlock_greedy( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -#define ZSTD_COMPRESSBLOCK_GREEDY ZSTD_compressBlock_greedy -#define ZSTD_COMPRESSBLOCK_GREEDY_ROW ZSTD_compressBlock_greedy_row -#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE ZSTD_compressBlock_greedy_dictMatchState -#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW ZSTD_compressBlock_greedy_dictMatchState_row -#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH ZSTD_compressBlock_greedy_dedicatedDictSearch -#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_greedy_dedicatedDictSearch_row -#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT ZSTD_compressBlock_greedy_extDict -#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW ZSTD_compressBlock_greedy_extDict_row -#else -#define ZSTD_COMPRESSBLOCK_GREEDY NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_ROW NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT NULL -#define ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW NULL -#endif - -#ifndef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_lazy( +size_t ZSTD_compressBlock_btlazy2_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_row( +size_t ZSTD_compressBlock_lazy2_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_lazy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_dedicatedDictSearch_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_extDict( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy_extDict_row( +size_t ZSTD_compressBlock_greedy_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -#define ZSTD_COMPRESSBLOCK_LAZY ZSTD_compressBlock_lazy -#define ZSTD_COMPRESSBLOCK_LAZY_ROW ZSTD_compressBlock_lazy_row -#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE ZSTD_compressBlock_lazy_dictMatchState -#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy_dictMatchState_row -#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy_dedicatedDictSearch -#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy_dedicatedDictSearch_row -#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT ZSTD_compressBlock_lazy_extDict -#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW ZSTD_compressBlock_lazy_extDict_row -#else -#define ZSTD_COMPRESSBLOCK_LAZY NULL -#define ZSTD_COMPRESSBLOCK_LAZY_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH NULL -#define ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT NULL -#define ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW NULL -#endif - -#ifndef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_lazy2( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dictMatchState_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch( +size_t ZSTD_compressBlock_greedy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch_row( +size_t ZSTD_compressBlock_lazy_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_lazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_lazy2_extDict_row( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); - -#define ZSTD_COMPRESSBLOCK_LAZY2 ZSTD_compressBlock_lazy2 -#define ZSTD_COMPRESSBLOCK_LAZY2_ROW ZSTD_compressBlock_lazy2_row -#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE ZSTD_compressBlock_lazy2_dictMatchState -#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW ZSTD_compressBlock_lazy2_dictMatchState_row -#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH ZSTD_compressBlock_lazy2_dedicatedDictSearch -#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW ZSTD_compressBlock_lazy2_dedicatedDictSearch_row -#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT ZSTD_compressBlock_lazy2_extDict -#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW ZSTD_compressBlock_lazy2_extDict_row -#else -#define ZSTD_COMPRESSBLOCK_LAZY2 NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT NULL -#define ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW NULL -#endif - -#ifndef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_btlazy2( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btlazy2_dictMatchState( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); size_t ZSTD_compressBlock_btlazy2_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -#define ZSTD_COMPRESSBLOCK_BTLAZY2 ZSTD_compressBlock_btlazy2 -#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE ZSTD_compressBlock_btlazy2_dictMatchState -#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT ZSTD_compressBlock_btlazy2_extDict -#else -#define ZSTD_COMPRESSBLOCK_BTLAZY2 NULL -#define ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT NULL -#endif - -} // namespace duckdb_zstd +} #endif /* ZSTD_LAZY_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h index a389c64f2..d2640c776 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -11,18 +11,17 @@ #ifndef ZSTD_LDM_H #define ZSTD_LDM_H - #include "zstd/compress/zstd_compress_internal.h" /* ldmParams_t, U32 */ #include "zstd.h" /* ZSTD_CCtx, size_t */ -namespace duckdb_zstd { - /*-************************************* * Long distance matching ***************************************/ #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT +namespace duckdb_zstd { + void ZSTD_ldm_fillHashTable( ldmState_t* state, const BYTE* ip, const BYTE* iend, ldmParams_t const* params); @@ -65,7 +64,6 @@ size_t ZSTD_ldm_generateSequences( */ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - ZSTD_paramSwitch_e useRowMatchFinder, void const* src, size_t srcSize); /** @@ -73,17 +71,11 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore, * * Skip past `srcSize` bytes worth of sequences in `rawSeqStore`. * Avoids emitting matches less than `minMatch` bytes. - * Must be called for data that is not passed to ZSTD_ldm_blockCompress(). + * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). */ void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch); -/* ZSTD_ldm_skipRawSeqStoreBytes(): - * Moves forward in rawSeqStore by nbBytes, updating fields 'pos' and 'posInSequence'. - * Not to be used in conjunction with ZSTD_ldm_skipSequences(). - * Must be called for data with is not passed to ZSTD_ldm_blockCompress(). - */ -void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes); /** ZSTD_ldm_getTableSize() : * Estimate the space needed for long distance matching tables or 0 if LDM is @@ -109,6 +101,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize); void ZSTD_ldm_adjustParameters(ldmParams_t* params, ZSTD_compressionParameters const* cParams); -} // namespace duckdb_zstd +} -#endif /* ZSTD_LDM_H */ +#endif /* ZSTD_FAST_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h deleted file mode 100644 index 3d4b1daa1..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_ldm_geartab.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZSTD_LDM_GEARTAB_H -#define ZSTD_LDM_GEARTAB_H - -#include "zstd/common/compiler.h" /* UNUSED_ATTR */ -#include "zstd/common/mem.h" /* U64 */ - -namespace duckdb_zstd { - -static UNUSED_ATTR const U64 ZSTD_ldm_gearTab[256] = { - 0xf5b8f72c5f77775c, 0x84935f266b7ac412, 0xb647ada9ca730ccc, - 0xb065bb4b114fb1de, 0x34584e7e8c3a9fd0, 0x4e97e17c6ae26b05, - 0x3a03d743bc99a604, 0xcecd042422c4044f, 0x76de76c58524259e, - 0x9c8528f65badeaca, 0x86563706e2097529, 0x2902475fa375d889, - 0xafb32a9739a5ebe6, 0xce2714da3883e639, 0x21eaf821722e69e, - 0x37b628620b628, 0x49a8d455d88caf5, 0x8556d711e6958140, - 0x4f7ae74fc605c1f, 0x829f0c3468bd3a20, 0x4ffdc885c625179e, - 0x8473de048a3daf1b, 0x51008822b05646b2, 0x69d75d12b2d1cc5f, - 0x8c9d4a19159154bc, 0xc3cc10f4abbd4003, 0xd06ddc1cecb97391, - 0xbe48e6e7ed80302e, 0x3481db31cee03547, 0xacc3f67cdaa1d210, - 0x65cb771d8c7f96cc, 0x8eb27177055723dd, 0xc789950d44cd94be, - 0x934feadc3700b12b, 0x5e485f11edbdf182, 0x1e2e2a46fd64767a, - 0x2969ca71d82efa7c, 0x9d46e9935ebbba2e, 0xe056b67e05e6822b, - 0x94d73f55739d03a0, 0xcd7010bdb69b5a03, 0x455ef9fcd79b82f4, - 0x869cb54a8749c161, 0x38d1a4fa6185d225, 0xb475166f94bbe9bb, - 0xa4143548720959f1, 0x7aed4780ba6b26ba, 0xd0ce264439e02312, - 0x84366d746078d508, 0xa8ce973c72ed17be, 0x21c323a29a430b01, - 0x9962d617e3af80ee, 0xab0ce91d9c8cf75b, 0x530e8ee6d19a4dbc, - 0x2ef68c0cf53f5d72, 0xc03a681640a85506, 0x496e4e9f9c310967, - 0x78580472b59b14a0, 0x273824c23b388577, 0x66bf923ad45cb553, - 0x47ae1a5a2492ba86, 0x35e304569e229659, 0x4765182a46870b6f, - 0x6cbab625e9099412, 0xddac9a2e598522c1, 0x7172086e666624f2, - 0xdf5003ca503b7837, 0x88c0c1db78563d09, 0x58d51865acfc289d, - 0x177671aec65224f1, 0xfb79d8a241e967d7, 0x2be1e101cad9a49a, - 0x6625682f6e29186b, 0x399553457ac06e50, 0x35dffb4c23abb74, - 0x429db2591f54aade, 0xc52802a8037d1009, 0x6acb27381f0b25f3, - 0xf45e2551ee4f823b, 0x8b0ea2d99580c2f7, 0x3bed519cbcb4e1e1, - 0xff452823dbb010a, 0x9d42ed614f3dd267, 0x5b9313c06257c57b, - 0xa114b8008b5e1442, 0xc1fe311c11c13d4b, 0x66e8763ea34c5568, - 0x8b982af1c262f05d, 0xee8876faaa75fbb7, 0x8a62a4d0d172bb2a, - 0xc13d94a3b7449a97, 0x6dbbba9dc15d037c, 0xc786101f1d92e0f1, - 0xd78681a907a0b79b, 0xf61aaf2962c9abb9, 0x2cfd16fcd3cb7ad9, - 0x868c5b6744624d21, 0x25e650899c74ddd7, 0xba042af4a7c37463, - 0x4eb1a539465a3eca, 0xbe09dbf03b05d5ca, 0x774e5a362b5472ba, - 0x47a1221229d183cd, 0x504b0ca18ef5a2df, 0xdffbdfbde2456eb9, - 0x46cd2b2fbee34634, 0xf2aef8fe819d98c3, 0x357f5276d4599d61, - 0x24a5483879c453e3, 0x88026889192b4b9, 0x28da96671782dbec, - 0x4ef37c40588e9aaa, 0x8837b90651bc9fb3, 0xc164f741d3f0e5d6, - 0xbc135a0a704b70ba, 0x69cd868f7622ada, 0xbc37ba89e0b9c0ab, - 0x47c14a01323552f6, 0x4f00794bacee98bb, 0x7107de7d637a69d5, - 0x88af793bb6f2255e, 0xf3c6466b8799b598, 0xc288c616aa7f3b59, - 0x81ca63cf42fca3fd, 0x88d85ace36a2674b, 0xd056bd3792389e7, - 0xe55c396c4e9dd32d, 0xbefb504571e6c0a6, 0x96ab32115e91e8cc, - 0xbf8acb18de8f38d1, 0x66dae58801672606, 0x833b6017872317fb, - 0xb87c16f2d1c92864, 0xdb766a74e58b669c, 0x89659f85c61417be, - 0xc8daad856011ea0c, 0x76a4b565b6fe7eae, 0xa469d085f6237312, - 0xaaf0365683a3e96c, 0x4dbb746f8424f7b8, 0x638755af4e4acc1, - 0x3d7807f5bde64486, 0x17be6d8f5bbb7639, 0x903f0cd44dc35dc, - 0x67b672eafdf1196c, 0xa676ff93ed4c82f1, 0x521d1004c5053d9d, - 0x37ba9ad09ccc9202, 0x84e54d297aacfb51, 0xa0b4b776a143445, - 0x820d471e20b348e, 0x1874383cb83d46dc, 0x97edeec7a1efe11c, - 0xb330e50b1bdc42aa, 0x1dd91955ce70e032, 0xa514cdb88f2939d5, - 0x2791233fd90db9d3, 0x7b670a4cc50f7a9b, 0x77c07d2a05c6dfa5, - 0xe3778b6646d0a6fa, 0xb39c8eda47b56749, 0x933ed448addbef28, - 0xaf846af6ab7d0bf4, 0xe5af208eb666e49, 0x5e6622f73534cd6a, - 0x297daeca42ef5b6e, 0x862daef3d35539a6, 0xe68722498f8e1ea9, - 0x981c53093dc0d572, 0xfa09b0bfbf86fbf5, 0x30b1e96166219f15, - 0x70e7d466bdc4fb83, 0x5a66736e35f2a8e9, 0xcddb59d2b7c1baef, - 0xd6c7d247d26d8996, 0xea4e39eac8de1ba3, 0x539c8bb19fa3aff2, - 0x9f90e4c5fd508d8, 0xa34e5956fbaf3385, 0x2e2f8e151d3ef375, - 0x173691e9b83faec1, 0xb85a8d56bf016379, 0x8382381267408ae3, - 0xb90f901bbdc0096d, 0x7c6ad32933bcec65, 0x76bb5e2f2c8ad595, - 0x390f851a6cf46d28, 0xc3e6064da1c2da72, 0xc52a0c101cfa5389, - 0xd78eaf84a3fbc530, 0x3781b9e2288b997e, 0x73c2f6dea83d05c4, - 0x4228e364c5b5ed7, 0x9d7a3edf0da43911, 0x8edcfeda24686756, - 0x5e7667a7b7a9b3a1, 0x4c4f389fa143791d, 0xb08bc1023da7cddc, - 0x7ab4be3ae529b1cc, 0x754e6132dbe74ff9, 0x71635442a839df45, - 0x2f6fb1643fbe52de, 0x961e0a42cf7a8177, 0xf3b45d83d89ef2ea, - 0xee3de4cf4a6e3e9b, 0xcd6848542c3295e7, 0xe4cee1664c78662f, - 0x9947548b474c68c4, 0x25d73777a5ed8b0b, 0xc915b1d636b7fc, - 0x21c2ba75d9b0d2da, 0x5f6b5dcf608a64a1, 0xdcf333255ff9570c, - 0x633b922418ced4ee, 0xc136dde0b004b34a, 0x58cc83b05d4b2f5a, - 0x5eb424dda28e42d2, 0x62df47369739cd98, 0xb4e0b42485e4ce17, - 0x16e1f0c1f9a8d1e7, 0x8ec3916707560ebf, 0x62ba6e2df2cc9db3, - 0xcbf9f4ff77d83a16, 0x78d9d7d07d2bbcc4, 0xef554ce1e02c41f4, - 0x8d7581127eccf94d, 0xa9b53336cb3c8a05, 0x38c42c0bf45c4f91, - 0x640893cdf4488863, 0x80ec34bc575ea568, 0x39f324f5b48eaa40, - 0xe9d9ed1f8eff527f, 0x9224fc058cc5a214, 0xbaba00b04cfe7741, - 0x309a9f120fcf52af, 0xa558f3ec65626212, 0x424bec8b7adabe2f, - 0x41622513a6aea433, 0xb88da2d5324ca798, 0xd287733b245528a4, - 0x9a44697e6d68aec3, 0x7b1093be2f49bb28, 0x50bbec632e3d8aad, - 0x6cd90723e1ea8283, 0x897b9e7431b02bf3, 0x219efdcb338a7047, - 0x3b0311f0a27c0656, 0xdb17bf91c0db96e7, 0x8cd4fd6b4e85a5b2, - 0xfab071054ba6409d, 0x40d6fe831fa9dfd9, 0xaf358debad7d791e, - 0xeb8d0e25a65e3e58, 0xbbcbd3df14e08580, 0xcf751f27ecdab2b, - 0x2b4da14f2613d8f4 -}; - -} // namespace duckdb_zstd - -#endif /* ZSTD_LDM_GEARTAB_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h index e2d45826f..b0d7bc3e2 100644 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h +++ b/src/duckdb/third_party/zstd/include/zstd/compress/zstd_opt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,40 +15,30 @@ namespace duckdb_zstd { -#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ - || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) /* used in ZSTD_loadDictionaryContent() */ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend); -#endif -#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR size_t ZSTD_compressBlock_btopt( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btopt_dictMatchState( +size_t ZSTD_compressBlock_btultra( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -size_t ZSTD_compressBlock_btopt_extDict( +size_t ZSTD_compressBlock_btultra2( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); -#define ZSTD_COMPRESSBLOCK_BTOPT ZSTD_compressBlock_btopt -#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE ZSTD_compressBlock_btopt_dictMatchState -#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT ZSTD_compressBlock_btopt_extDict -#else -#define ZSTD_COMPRESSBLOCK_BTOPT NULL -#define ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT NULL -#endif -#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR -size_t ZSTD_compressBlock_btultra( +size_t ZSTD_compressBlock_btopt_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); size_t ZSTD_compressBlock_btultra_dictMatchState( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); + +size_t ZSTD_compressBlock_btopt_extDict( + ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], + void const* src, size_t srcSize); size_t ZSTD_compressBlock_btultra_extDict( ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize); @@ -56,21 +46,7 @@ size_t ZSTD_compressBlock_btultra_extDict( /* note : no btultra2 variant for extDict nor dictMatchState, * because btultra2 is not meant to work with dictionaries * and is only specific for the first block (no prefix) */ -size_t ZSTD_compressBlock_btultra2( - ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], - void const* src, size_t srcSize); - -#define ZSTD_COMPRESSBLOCK_BTULTRA ZSTD_compressBlock_btultra -#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE ZSTD_compressBlock_btultra_dictMatchState -#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT ZSTD_compressBlock_btultra_extDict -#define ZSTD_COMPRESSBLOCK_BTULTRA2 ZSTD_compressBlock_btultra2 -#else -#define ZSTD_COMPRESSBLOCK_BTULTRA NULL -#define ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE NULL -#define ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT NULL -#define ZSTD_COMPRESSBLOCK_BTULTRA2 NULL -#endif -} // namespace duckdb_zstd +} #endif /* ZSTD_OPT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h b/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h deleted file mode 100644 index 99f7757dd..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/compress/zstdmt_compress.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - - #ifndef ZSTDMT_COMPRESS_H - #define ZSTDMT_COMPRESS_H - -/* Note : This is an internal API. - * These APIs used to be exposed with ZSTDLIB_API, - * because it used to be the only way to invoke MT compression. - * Now, you must use ZSTD_compress2 and ZSTD_compressStream2() instead. - * - * This API requires ZSTD_MULTITHREAD to be defined during compilation, - * otherwise ZSTDMT_createCCtx*() will fail. - */ - -/* === Dependencies === */ -#include "zstd/common/zstd_deps.h" /* size_t */ -#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters */ -#include "zstd.h" /* ZSTD_inBuffer, ZSTD_outBuffer, ZSTDLIB_API */ - -namespace duckdb_zstd { - -/* === Constants === */ -#ifndef ZSTDMT_NBWORKERS_MAX /* a different value can be selected at compile time */ -# define ZSTDMT_NBWORKERS_MAX ((sizeof(void*)==4) /*32-bit*/ ? 64 : 256) -#endif -#ifndef ZSTDMT_JOBSIZE_MIN /* a different value can be selected at compile time */ -# define ZSTDMT_JOBSIZE_MIN (512 KB) -#endif -#define ZSTDMT_JOBLOG_MAX (MEM_32bits() ? 29 : 30) -#define ZSTDMT_JOBSIZE_MAX (MEM_32bits() ? (512 MB) : (1024 MB)) - - -/* ======================================================== - * === Private interface, for use by ZSTD_compress.c === - * === Not exposed in libzstd. Never invoke directly === - * ======================================================== */ - -/* === Memory management === */ -typedef struct ZSTDMT_CCtx_s ZSTDMT_CCtx; -/* Requires ZSTD_MULTITHREAD to be defined during compilation, otherwise it will return NULL. */ -ZSTDMT_CCtx* ZSTDMT_createCCtx_advanced(unsigned nbWorkers, - ZSTD_customMem cMem, - ZSTD_threadPool *pool); -size_t ZSTDMT_freeCCtx(ZSTDMT_CCtx* mtctx); - -size_t ZSTDMT_sizeof_CCtx(ZSTDMT_CCtx* mtctx); - -/* === Streaming functions === */ - -size_t ZSTDMT_nextInputSizeHint(const ZSTDMT_CCtx* mtctx); - -/*! ZSTDMT_initCStream_internal() : - * Private use only. Init streaming operation. - * expects params to be valid. - * must receive dict, or cdict, or none, but not both. - * mtctx can be freshly constructed or reused from a prior compression. - * If mtctx is reused, memory allocations from the prior compression may not be freed, - * even if they are not needed for the current compression. - * @return : 0, or an error code */ -size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* mtctx, - const void* dict, size_t dictSize, ZSTD_dictContentType_e dictContentType, - const ZSTD_CDict* cdict, - ZSTD_CCtx_params params, unsigned long long pledgedSrcSize); - -/*! ZSTDMT_compressStream_generic() : - * Combines ZSTDMT_compressStream() with optional ZSTDMT_flushStream() or ZSTDMT_endStream() - * depending on flush directive. - * @return : minimum amount of data still to be flushed - * 0 if fully flushed - * or an error code - * note : needs to be init using any ZSTD_initCStream*() variant */ -size_t ZSTDMT_compressStream_generic(ZSTDMT_CCtx* mtctx, - ZSTD_outBuffer* output, - ZSTD_inBuffer* input, - ZSTD_EndDirective endOp); - - /*! ZSTDMT_toFlushNow() - * Tell how many bytes are ready to be flushed immediately. - * Probe the oldest active job (not yet entirely flushed) and check its output buffer. - * If return 0, it means there is no active job, - * or, it means oldest job is still active, but everything produced has been flushed so far, - * therefore flushing is limited by speed of oldest job. */ -size_t ZSTDMT_toFlushNow(ZSTDMT_CCtx* mtctx); - -/*! ZSTDMT_updateCParams_whileCompressing() : - * Updates only a selected set of compression parameters, to remain compatible with current frame. - * New parameters will be applied to next compression job. */ -void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams); - -/*! ZSTDMT_getFrameProgression(): - * tells how much data has been consumed (input) and produced (output) for current frame. - * able to count progression inside worker threads. - */ -ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx); - - -} // namespace duckdb_zstd - -#endif /* ZSTDMT_COMPRESS_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h index 7dc647936..a95f384fb 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_ddict.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,11 +15,10 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd/common/zstd_deps.h" /* size_t */ +#include /* size_t */ #include "zstd.h" /* ZSTD_DDict, and several public functions */ namespace duckdb_zstd { - /*-******************************************************* * Interface *********************************************************/ @@ -40,6 +39,6 @@ size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); -} // namespace duckdb_zstd +} #endif /* ZSTD_DDICT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h index 7131a0d95..46d4a2103 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_block.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -15,7 +15,7 @@ /*-******************************************************* * Dependencies *********************************************************/ -#include "zstd/common/zstd_deps.h" /* size_t */ +#include /* size_t */ #include "zstd.h" /* DCtx, and some public functions */ #include "zstd/common/zstd_internal.h" /* blockProperties_t, and some public functions */ #include "zstd/decompress/zstd_decompress_internal.h" /* ZSTD_seqSymbol */ @@ -34,12 +34,6 @@ namespace duckdb_zstd { */ - /* Streaming state is used to inform allocation of the literal buffer */ -typedef enum { - not_streaming = 0, - is_streaming = 1 -} streaming_operation; - /* ZSTD_decompressBlock_internal() : * decompress block, starting at `src`, * into destination buffer `dst`. @@ -48,28 +42,20 @@ typedef enum { */ size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, - const void* src, size_t srcSize, const streaming_operation streaming); + const void* src, size_t srcSize, const int frame); /* ZSTD_buildFSETable() : * generate FSE decoding table for one symbol (ll, ml or off) * this function must be called with valid parameters only * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) * in which case it cannot fail. - * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is - * defined in zstd_decompress_internal.h. * Internal use only. */ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, const short* normalizedCounter, unsigned maxSymbolValue, - const U32* baseValue, const U8* nbAdditionalBits, - unsigned tableLog, void* wksp, size_t wkspSize, - int bmi2); - -/* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ -size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); + const U32* baseValue, const U32* nbAdditionalBits, + unsigned tableLog); -} // namespace duckdb_zstd +} #endif /* ZSTD_DEC_BLOCK_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h index 0f7e198e1..6ff422e2c 100644 --- a/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h +++ b/src/duckdb/third_party/zstd/include/zstd/decompress/zstd_decompress_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. * All rights reserved. * * This source code is licensed under both the BSD-style license (found in the @@ -20,40 +20,19 @@ * Dependencies *********************************************************/ #include "zstd/common/mem.h" /* BYTE, U16, U32 */ -#include "zstd/common/zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ +#include "zstd/common/zstd_internal.h" /* ZSTD_seqSymbol */ namespace duckdb_zstd { /*-******************************************************* * Constants *********************************************************/ -static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 18, 20, 22, 24, 28, 32, 40, - 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, - 0x2000, 0x4000, 0x8000, 0x10000 }; - -static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { - 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, - 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, - 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, - 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; - -static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { - 0, 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 }; - -static UNUSED_ATTR const U32 ML_base[MaxML+1] = { - 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, 37, 39, 41, 43, 47, 51, 59, - 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, - 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; +struct ZSTDConstants { + static const U32 LL_base[MaxLL+1]; + static const U32 OF_base[MaxOff+1]; + static const U32 OF_bits[MaxOff+1]; + static const U32 ML_base[MaxML+1]; +}; /*-******************************************************* @@ -73,17 +52,12 @@ static UNUSED_ATTR const U32 ML_base[MaxML+1] = { #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) -#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) -#define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) -#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 - typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ - HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ U32 rep[ZSTD_REP_NUM]; - U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; } ZSTD_entropyDTables_t; typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, @@ -100,28 +74,10 @@ typedef enum { ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ } ZSTD_dictUses_e; -/* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ -typedef struct { - const ZSTD_DDict** ddictPtrTable; - size_t ddictPtrTableSize; - size_t ddictPtrCount; -} ZSTD_DDictHashSet; - -#ifndef ZSTD_DECODER_INTERNAL_BUFFER -# define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) -#endif - -#define ZSTD_LBMIN 64 -#define ZSTD_LBMAX (128 << 10) - -/* extra buffer, compensates when dst is not large enough to store litBuffer */ -#define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) - typedef enum { - ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ - ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ - ZSTD_split = 2 /* Split between litExtraBuffer and dst */ -} ZSTD_litLocation_e; + ZSTD_obm_buffered = 0, /* Buffer the output */ + ZSTD_obm_stable = 1 /* ZSTD_outBuffer is stable */ +} ZSTD_outBufferMode_e; struct ZSTD_DCtx_s { @@ -137,7 +93,6 @@ struct ZSTD_DCtx_s const void* dictEnd; /* end of previous segment */ size_t expected; ZSTD_frameHeader fParams; - U64 processedCSize; U64 decodedSize; blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ ZSTD_dStage stage; @@ -146,17 +101,12 @@ struct ZSTD_DCtx_s XXH64_state_t xxhState; size_t headerSize; ZSTD_format_e format; - ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ - U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ const BYTE* litPtr; ZSTD_customMem customMem; size_t litSize; size_t rleSize; size_t staticSize; - int isFrameDecompression; -#if DYNAMIC_BMI2 != 0 int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ -#endif /* dictionary */ ZSTD_DDict* ddictLocal; @@ -164,10 +114,6 @@ struct ZSTD_DCtx_s U32 dictID; int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ ZSTD_dictUses_e dictUses; - ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ - ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ - int disableHufAsm; - int maxBlockSizeParam; /* streaming */ ZSTD_dStreamStage streamStage; @@ -180,21 +126,16 @@ struct ZSTD_DCtx_s size_t outStart; size_t outEnd; size_t lhSize; -#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) void* legacyContext; U32 previousLegacyVersion; U32 legacyVersion; -#endif U32 hostageByte; int noForwardProgress; - ZSTD_bufferMode_e outBufferMode; + ZSTD_outBufferMode_e outBufferMode; ZSTD_outBuffer expectedOutBuffer; /* workspace */ - BYTE* litBuffer; - const BYTE* litBufferEnd; - ZSTD_litLocation_e litBufferLocation; - BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ + BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; size_t oversizedDuration; @@ -203,21 +144,8 @@ struct ZSTD_DCtx_s void const* dictContentBeginForFuzzing; void const* dictContentEndForFuzzing; #endif - - /* Tracing */ -#if ZSTD_TRACE - ZSTD_TraceCtx traceCtx; -#endif }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ -MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { -#if DYNAMIC_BMI2 != 0 - return dctx->bmi2; -#else - (void)dctx; - return 0; -#endif -} /*-******************************************************* * Shared internal functions @@ -234,8 +162,8 @@ size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, * If yes, do nothing (continue on current segment). * If not, classify previous segment as "external dictionary", and start a new segment. * This function cannot fail. */ -void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); +void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst); -} // namespace duckdb_zstd +} #endif /* ZSTD_DECOMPRESS_INTERNAL_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h b/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h deleted file mode 100644 index 04c75ef1a..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/deprecated/zbuff.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -/* *************************************************************** -* NOTES/WARNINGS -******************************************************************/ -/* The streaming API defined here is deprecated. - * Consider migrating towards ZSTD_compressStream() API in `zstd.h` - * See 'lib/README.md'. - *****************************************************************/ - -#ifndef ZSTD_BUFFERED_H_23987 -#define ZSTD_BUFFERED_H_23987 - -/* ************************************* -* Dependencies -***************************************/ -// DuckDB: just enable everything -#define ZSTD_STATIC_LINKING_ONLY - -#include /* size_t */ -#include "zstd.h" /* ZSTD_CStream, ZSTD_DStream, ZSTDLIB_API */ - -namespace duckdb_zstd { - -/* *************************************************************** -* Compiler specifics -*****************************************************************/ -/* Deprecation warnings */ -/* Should these warnings be a problem, - * it is generally possible to disable them, - * typically with -Wno-deprecated-declarations for gcc - * or _CRT_SECURE_NO_WARNINGS in Visual. - * Otherwise, it's also possible to define ZBUFF_DISABLE_DEPRECATE_WARNINGS - */ -#ifdef ZBUFF_DISABLE_DEPRECATE_WARNINGS -# define ZBUFF_DEPRECATED(message) ZSTDLIB_API /* disable deprecation warnings */ -#else -# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ -# define ZBUFF_DEPRECATED(message) [[deprecated(message)]] ZSTDLIB_API -# elif (defined(GNUC) && (GNUC > 4 || (GNUC == 4 && GNUC_MINOR >= 5))) || defined(__clang__) -# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated(message))) -# elif defined(__GNUC__) && (__GNUC__ >= 3) -# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __attribute__((deprecated)) -# elif defined(_MSC_VER) -# define ZBUFF_DEPRECATED(message) ZSTDLIB_API __declspec(deprecated(message)) -# else -# pragma message("WARNING: You need to implement ZBUFF_DEPRECATED for this compiler") -# define ZBUFF_DEPRECATED(message) ZSTDLIB_API -# endif -#endif /* ZBUFF_DISABLE_DEPRECATE_WARNINGS */ - - -/* ************************************* -* Streaming functions -***************************************/ -/* This is the easier "buffered" streaming API, -* using an internal buffer to lift all restrictions on user-provided buffers -* which can be any size, any place, for both input and output. -* ZBUFF and ZSTD are 100% interoperable, -* frames created by one can be decoded by the other one */ - -typedef ZSTD_CStream ZBUFF_CCtx; -ZBUFF_DEPRECATED("use ZSTD_createCStream") ZBUFF_CCtx* ZBUFF_createCCtx(void); -ZBUFF_DEPRECATED("use ZSTD_freeCStream") size_t ZBUFF_freeCCtx(ZBUFF_CCtx* cctx); - -ZBUFF_DEPRECATED("use ZSTD_initCStream") size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel); -ZBUFF_DEPRECATED("use ZSTD_initCStream_usingDict") size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); - -ZBUFF_DEPRECATED("use ZSTD_compressStream") size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr); -ZBUFF_DEPRECATED("use ZSTD_flushStream") size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); -ZBUFF_DEPRECATED("use ZSTD_endStream") size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); - -/*-************************************************* -* Streaming compression - howto -* -* A ZBUFF_CCtx object is required to track streaming operation. -* Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. -* ZBUFF_CCtx objects can be reused multiple times. -* -* Start by initializing ZBUF_CCtx. -* Use ZBUFF_compressInit() to start a new compression operation. -* Use ZBUFF_compressInitDictionary() for a compression which requires a dictionary. -* -* Use ZBUFF_compressContinue() repetitively to consume input stream. -* *srcSizePtr and *dstCapacityPtr can be any size. -* The function will report how many bytes were read or written within *srcSizePtr and *dstCapacityPtr. -* Note that it may not consume the entire input, in which case it's up to the caller to present again remaining data. -* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each call, so save its content if it matters or change @dst . -* @return : a hint to preferred nb of bytes to use as input for next function call (it's just a hint, to improve latency) -* or an error code, which can be tested using ZBUFF_isError(). -* -* At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush(). -* The nb of bytes written into `dst` will be reported into *dstCapacityPtr. -* Note that the function cannot output more than *dstCapacityPtr, -* therefore, some content might still be left into internal buffer if *dstCapacityPtr is too small. -* @return : nb of bytes still present into internal buffer (0 if it's empty) -* or an error code, which can be tested using ZBUFF_isError(). -* -* ZBUFF_compressEnd() instructs to finish a frame. -* It will perform a flush and write frame epilogue. -* The epilogue is required for decoders to consider a frame completed. -* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. -* In which case, call again ZBUFF_compressFlush() to complete the flush. -* @return : nb of bytes still present into internal buffer (0 if it's empty) -* or an error code, which can be tested using ZBUFF_isError(). -* -* Hint : _recommended buffer_ sizes (not compulsory) : ZBUFF_recommendedCInSize() / ZBUFF_recommendedCOutSize() -* input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, use this value to reduce intermediate stages (better latency) -* output : ZBUFF_recommendedCOutSize==ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block. Skip some buffering. -* By using both, it ensures that input will be entirely consumed, and output will always contain the result, reducing intermediate buffering. -* **************************************************/ - - -typedef ZSTD_DStream ZBUFF_DCtx; -ZBUFF_DEPRECATED("use ZSTD_createDStream") ZBUFF_DCtx* ZBUFF_createDCtx(void); -ZBUFF_DEPRECATED("use ZSTD_freeDStream") size_t ZBUFF_freeDCtx(ZBUFF_DCtx* dctx); - -ZBUFF_DEPRECATED("use ZSTD_initDStream") size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx); -ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* dctx, const void* dict, size_t dictSize); - -ZBUFF_DEPRECATED("use ZSTD_decompressStream") size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, - void* dst, size_t* dstCapacityPtr, - const void* src, size_t* srcSizePtr); - -/*-*************************************************************************** -* Streaming decompression howto -* -* A ZBUFF_DCtx object is required to track streaming operations. -* Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. -* Use ZBUFF_decompressInit() to start a new decompression operation, -* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. -* Note that ZBUFF_DCtx objects can be re-init multiple times. -* -* Use ZBUFF_decompressContinue() repetitively to consume your input. -* *srcSizePtr and *dstCapacityPtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. -* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. -* The content of `dst` will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change `dst`. -* @return : 0 when a frame is completely decoded and fully flushed, -* 1 when there is still some data left within internal buffer to flush, -* >1 when more data is expected, with value being a suggested next input size (it's just a hint, which helps latency), -* or an error code, which can be tested using ZBUFF_isError(). -* -* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize() -* output : ZBUFF_recommendedDOutSize== 128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. -* input : ZBUFF_recommendedDInSize == 128KB + 3; -* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . -* *******************************************************************************/ - - -/* ************************************* -* Tool functions -***************************************/ -ZBUFF_DEPRECATED("use ZSTD_isError") unsigned ZBUFF_isError(size_t errorCode); -ZBUFF_DEPRECATED("use ZSTD_getErrorName") const char* ZBUFF_getErrorName(size_t errorCode); - -/** Functions below provide recommended buffer sizes for Compression or Decompression operations. -* These sizes are just hints, they tend to offer better latency */ -ZBUFF_DEPRECATED("use ZSTD_CStreamInSize") size_t ZBUFF_recommendedCInSize(void); -ZBUFF_DEPRECATED("use ZSTD_CStreamOutSize") size_t ZBUFF_recommendedCOutSize(void); -ZBUFF_DEPRECATED("use ZSTD_DStreamInSize") size_t ZBUFF_recommendedDInSize(void); -ZBUFF_DEPRECATED("use ZSTD_DStreamOutSize") size_t ZBUFF_recommendedDOutSize(void); - -} // namespace duckdb_zstd - -#endif /* ZSTD_BUFFERED_H_23987 */ - -#ifdef ZBUFF_STATIC_LINKING_ONLY -# ifndef ZBUFF_STATIC_H_30298098432 -# define ZBUFF_STATIC_H_30298098432 - -/* ==================================================================================== - * The definitions in this section are considered experimental. - * They should never be used in association with a dynamic library, as they may change in the future. - * They are provided for advanced usages. - * Use them only in association with static linking. - * ==================================================================================== */ - - -/*--- Dependency ---*/ -// DuckDB: comment out otherwise amalgamation won't be happy -// # define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_customMem */ -// #include "zstd.h" - -namespace duckdb_zstd { - -/*--- Custom memory allocator ---*/ -/*! ZBUFF_createCCtx_advanced() : - * Create a ZBUFF compression context using external alloc and free functions */ -ZBUFF_DEPRECATED("use ZSTD_createCStream_advanced") ZBUFF_CCtx* ZBUFF_createCCtx_advanced(ZSTD_customMem customMem); - -/*! ZBUFF_createDCtx_advanced() : - * Create a ZBUFF decompression context using external alloc and free functions */ -ZBUFF_DEPRECATED("use ZSTD_createDStream_advanced") ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem); - - -/*--- Advanced Streaming Initialization ---*/ -ZBUFF_DEPRECATED("use ZSTD_initDStream_usingDict") size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, - const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize); - -} // namespace duckdb_zstd - -# endif /* ZBUFF_STATIC_H_30298098432 */ -#endif /* ZBUFF_STATIC_LINKING_ONLY */ - diff --git a/src/duckdb/third_party/zstd/include/zstd/dict/cover.h b/src/duckdb/third_party/zstd/include/zstd/dict/cover.h deleted file mode 100644 index dd458ce58..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/dict/cover.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * All rights reserved. - * - * This source code is licensed under both the BSD-style license (found in the - * LICENSE file in the root directory of this source tree) and the GPLv2 (found - * in the COPYING file in the root directory of this source tree). - * You may select, at your option, one of the above-listed licenses. - */ - -#ifndef ZDICT_STATIC_LINKING_ONLY -# define ZDICT_STATIC_LINKING_ONLY -#endif - -#include "zstd/common/threading.h" /* ZSTD_pthread_mutex_t */ -#include "zstd/common/mem.h" /* U32, BYTE */ -#include "zdict.h" - -namespace duckdb_zstd { - -/** - * COVER_best_t is used for two purposes: - * 1. Synchronizing threads. - * 2. Saving the best parameters and dictionary. - * - * All of the methods except COVER_best_init() are thread safe if zstd is - * compiled with multithreaded support. - */ -typedef struct COVER_best_s { - ZSTD_pthread_mutex_t mutex; - ZSTD_pthread_cond_t cond; - size_t liveJobs; - void *dict; - size_t dictSize; - ZDICT_cover_params_t parameters; - size_t compressedSize; -} COVER_best_t; - -/** - * A segment is a range in the source as well as the score of the segment. - */ -typedef struct { - U32 begin; - U32 end; - U32 score; -} COVER_segment_t; - -/** - *Number of epochs and size of each epoch. - */ -typedef struct { - U32 num; - U32 size; -} COVER_epoch_info_t; - -/** - * Struct used for the dictionary selection function. - */ -typedef struct COVER_dictSelection { - BYTE* dictContent; - size_t dictSize; - size_t totalCompressedSize; -} COVER_dictSelection_t; - -/** - * Computes the number of epochs and the size of each epoch. - * We will make sure that each epoch gets at least 10 * k bytes. - * - * The COVER algorithms divide the data up into epochs of equal size and - * select one segment from each epoch. - * - * @param maxDictSize The maximum allowed dictionary size. - * @param nbDmers The number of dmers we are training on. - * @param k The parameter k (segment size). - * @param passes The target number of passes over the dmer corpus. - * More passes means a better dictionary. - */ -COVER_epoch_info_t COVER_computeEpochs(U32 maxDictSize, U32 nbDmers, - U32 k, U32 passes); - -/** - * Warns the user when their corpus is too small. - */ -void COVER_warnOnSmallCorpus(size_t maxDictSize, size_t nbDmers, int displayLevel); - -/** - * Checks total compressed size of a dictionary - */ -size_t COVER_checkTotalCompressedSize(const ZDICT_cover_params_t parameters, - const size_t *samplesSizes, const BYTE *samples, - size_t *offsets, - size_t nbTrainSamples, size_t nbSamples, - BYTE *const dict, size_t dictBufferCapacity); - -/** - * Returns the sum of the sample sizes. - */ -size_t COVER_sum(const size_t *samplesSizes, unsigned nbSamples) ; - -/** - * Initialize the `COVER_best_t`. - */ -void COVER_best_init(COVER_best_t *best); - -/** - * Wait until liveJobs == 0. - */ -void COVER_best_wait(COVER_best_t *best); - -/** - * Call COVER_best_wait() and then destroy the COVER_best_t. - */ -void COVER_best_destroy(COVER_best_t *best); - -/** - * Called when a thread is about to be launched. - * Increments liveJobs. - */ -void COVER_best_start(COVER_best_t *best); - -/** - * Called when a thread finishes executing, both on error or success. - * Decrements liveJobs and signals any waiting threads if liveJobs == 0. - * If this dictionary is the best so far save it and its parameters. - */ -void COVER_best_finish(COVER_best_t *best, ZDICT_cover_params_t parameters, - COVER_dictSelection_t selection); -/** - * Error function for COVER_selectDict function. Checks if the return - * value is an error. - */ -unsigned COVER_dictSelectionIsError(COVER_dictSelection_t selection); - - /** - * Error function for COVER_selectDict function. Returns a struct where - * return.totalCompressedSize is a ZSTD error. - */ -COVER_dictSelection_t COVER_dictSelectionError(size_t error); - -/** - * Always call after selectDict is called to free up used memory from - * newly created dictionary. - */ -void COVER_dictSelectionFree(COVER_dictSelection_t selection); - -/** - * Called to finalize the dictionary and select one based on whether or not - * the shrink-dict flag was enabled. If enabled the dictionary used is the - * smallest dictionary within a specified regression of the compressed size - * from the largest dictionary. - */ - COVER_dictSelection_t COVER_selectDict(BYTE* customDictContent, size_t dictBufferCapacity, - size_t dictContentSize, const BYTE* samplesBuffer, const size_t* samplesSizes, unsigned nbFinalizeSamples, - size_t nbCheckSamples, size_t nbSamples, ZDICT_cover_params_t params, size_t* offsets, size_t totalCompressedSize); - -} // namespace duckdb_zstd diff --git a/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h b/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h deleted file mode 100644 index 4f7cbdee8..000000000 --- a/src/duckdb/third_party/zstd/include/zstd/dict/divsufsort.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * divsufsort.h for libdivsufsort-lite - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _DIVSUFSORT_H -#define _DIVSUFSORT_H 1 - -namespace duckdb_zstd { - -/*- Prototypes -*/ - -/** - * Constructs the suffix array of a given string. - * @param T [0..n-1] The input string. - * @param SA [0..n-1] The output array of suffixes. - * @param n The length of the given string. - * @param openMP enables OpenMP optimization. - * @return 0 if no error occurred, -1 or -2 otherwise. - */ -int -divsufsort(const unsigned char *T, int *SA, int n, int openMP); - -/** - * Constructs the burrows-wheeler transformed string of a given string. - * @param T [0..n-1] The input string. - * @param U [0..n-1] The output string. (can be T) - * @param A [0..n-1] The temporary array. (can be NULL) - * @param n The length of the given string. - * @param num_indexes The length of secondary indexes array. (can be NULL) - * @param indexes The secondary indexes array. (can be NULL) - * @param openMP enables OpenMP optimization. - * @return The primary index if no error occurred, -1 or -2 otherwise. - */ -int -divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP); - - -} // namespace duckdb_zstd - -#endif /* _DIVSUFSORT_H */ diff --git a/src/duckdb/third_party/zstd/include/zstd_static.h b/src/duckdb/third_party/zstd/include/zstd_static.h new file mode 100644 index 000000000..2c31f3d36 --- /dev/null +++ b/src/duckdb/third_party/zstd/include/zstd_static.h @@ -0,0 +1,1070 @@ + +/* ************************************************************************************** + * ADVANCED AND EXPERIMENTAL FUNCTIONS + **************************************************************************************** + * The definitions in the following section are considered experimental. + * They are provided for advanced scenarios. + * They should never be used with a dynamic library, as prototypes may change in the future. + * Use them only in association with static linking. + * ***************************************************************************************/ + +#ifndef ZSTD_H_ZSTD_STATIC_LINKING_ONLY +#define ZSTD_H_ZSTD_STATIC_LINKING_ONLY + +namespace duckdb_zstd { + +/**************************************************************************************** + * experimental API (static linking only) + **************************************************************************************** + * The following symbols and constants + * are not planned to join "stable API" status in the near future. + * They can still change in future versions. + * Some of them are planned to remain in the static_only section indefinitely. + * Some of them might be removed in the future (especially when redundant with existing stable functions) + * ***************************************************************************************/ + +#define ZSTD_FRAMEHEADERSIZE_PREFIX(format) ((format) == ZSTD_f_zstd1 ? 5 : 1) /* minimum input size required to query frame header size */ +#define ZSTD_FRAMEHEADERSIZE_MIN(format) ((format) == ZSTD_f_zstd1 ? 6 : 2) +#define ZSTD_FRAMEHEADERSIZE_MAX 18 /* can be useful for static allocation */ +#define ZSTD_SKIPPABLEHEADERSIZE 8 + +/* compression parameter bounds */ +#define ZSTD_WINDOWLOG_MAX_32 30 +#define ZSTD_WINDOWLOG_MAX_64 31 +#define ZSTD_WINDOWLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_WINDOWLOG_MAX_32 : ZSTD_WINDOWLOG_MAX_64)) +#define ZSTD_WINDOWLOG_MIN 10 +#define ZSTD_HASHLOG_MAX ((ZSTD_WINDOWLOG_MAX < 30) ? ZSTD_WINDOWLOG_MAX : 30) +#define ZSTD_HASHLOG_MIN 6 +#define ZSTD_CHAINLOG_MAX_32 29 +#define ZSTD_CHAINLOG_MAX_64 30 +#define ZSTD_CHAINLOG_MAX ((int)(sizeof(size_t) == 4 ? ZSTD_CHAINLOG_MAX_32 : ZSTD_CHAINLOG_MAX_64)) +#define ZSTD_CHAINLOG_MIN ZSTD_HASHLOG_MIN +#define ZSTD_SEARCHLOG_MAX (ZSTD_WINDOWLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_MINMATCH_MAX 7 /* only for ZSTD_fast, other strategies are limited to 6 */ +#define ZSTD_MINMATCH_MIN 3 /* only for ZSTD_btopt+, faster strategies are limited to 4 */ +#define ZSTD_TARGETLENGTH_MAX ZSTD_BLOCKSIZE_MAX +#define ZSTD_TARGETLENGTH_MIN 0 /* note : comparing this constant to an unsigned results in a tautological test */ +#define ZSTD_STRATEGY_MIN ZSTD_fast +#define ZSTD_STRATEGY_MAX ZSTD_btultra2 + + +#define ZSTD_OVERLAPLOG_MIN 0 +#define ZSTD_OVERLAPLOG_MAX 9 + +#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27 /* by default, the streaming decoder will refuse any frame + * requiring larger than (1< 3, then this is seqDef.offset - 3 + * If seqDef.offset < 3, then this is the corresponding repeat offset + * But if seqDef.offset < 3 and litLength == 0, this is the + * repeat offset before the corresponding repeat offset + * And if seqDef.offset == 3 and litLength == 0, this is the + * most recent repeat offset - 1 + */ + unsigned int offset; + unsigned int litLength; /* Literal length */ + unsigned int matchLength; /* Match length */ + /* 0 when seq not rep and seqDef.offset otherwise + * when litLength == 0 this will be <= 4, otherwise <= 3 like normal + */ + unsigned int rep; +} ZSTD_Sequence; + +typedef struct { + unsigned windowLog; /**< largest match distance : larger == more compression, more memory needed during decompression */ + unsigned chainLog; /**< fully searched segment : larger == more compression, slower, more memory (useless for fast) */ + unsigned hashLog; /**< dispatch table : larger == faster, more memory */ + unsigned searchLog; /**< nb of searches : larger == more compression, slower */ + unsigned minMatch; /**< match length searched : larger == faster decompression, sometimes less compression */ + unsigned targetLength; /**< acceptable match size for optimal parser (only) : larger == more compression, slower */ + ZSTD_strategy strategy; /**< see ZSTD_strategy definition above */ +} ZSTD_compressionParameters; + +typedef struct { + int contentSizeFlag; /**< 1: content size will be in frame header (when known) */ + int checksumFlag; /**< 1: generate a 32-bits checksum using XXH64 algorithm at end of frame, for error detection */ + int noDictIDFlag; /**< 1: no dictID will be saved into frame header (dictID is only useful for dictionary compression) */ +} ZSTD_frameParameters; + +typedef struct { + ZSTD_compressionParameters cParams; + ZSTD_frameParameters fParams; +} ZSTD_parameters; + +typedef enum { + ZSTD_dct_auto = 0, /* dictionary is "full" when starting with ZSTD_MAGIC_DICTIONARY, otherwise it is "rawContent" */ + ZSTD_dct_rawContent = 1, /* ensures dictionary is always loaded as rawContent, even if it starts with ZSTD_MAGIC_DICTIONARY */ + ZSTD_dct_fullDict = 2 /* refuses to load a dictionary if it does not respect Zstandard's specification, starting with ZSTD_MAGIC_DICTIONARY */ +} ZSTD_dictContentType_e; + +typedef enum { + ZSTD_dlm_byCopy = 0, /**< Copy dictionary content internally */ + ZSTD_dlm_byRef = 1 /**< Reference dictionary content -- the dictionary buffer must outlive its users. */ +} ZSTD_dictLoadMethod_e; + +typedef enum { + ZSTD_f_zstd1 = 0, /* zstd frame format, specified in zstd_compression_format.md (default) */ + ZSTD_f_zstd1_magicless = 1 /* Variant of zstd frame format, without initial 4-bytes magic number. + * Useful to save 4 bytes per generated frame. + * Decoder cannot recognise automatically this format, requiring this instruction. */ +} ZSTD_format_e; + +typedef enum { + /* Note: this enum and the behavior it controls are effectively internal + * implementation details of the compressor. They are expected to continue + * to evolve and should be considered only in the context of extremely + * advanced performance tuning. + * + * Zstd currently supports the use of a CDict in three ways: + * + * - The contents of the CDict can be copied into the working context. This + * means that the compression can search both the dictionary and input + * while operating on a single set of internal tables. This makes + * the compression faster per-byte of input. However, the initial copy of + * the CDict's tables incurs a fixed cost at the beginning of the + * compression. For small compressions (< 8 KB), that copy can dominate + * the cost of the compression. + * + * - The CDict's tables can be used in-place. In this model, compression is + * slower per input byte, because the compressor has to search two sets of + * tables. However, this model incurs no start-up cost (as long as the + * working context's tables can be reused). For small inputs, this can be + * faster than copying the CDict's tables. + * + * - The CDict's tables are not used at all, and instead we use the working + * context alone to reload the dictionary and use params based on the source + * size. See ZSTD_compress_insertDictionary() and ZSTD_compress_usingDict(). + * This method is effective when the dictionary sizes are very small relative + * to the input size, and the input size is fairly large to begin with. + * + * Zstd has a simple internal heuristic that selects which strategy to use + * at the beginning of a compression. However, if experimentation shows that + * Zstd is making poor choices, it is possible to override that choice with + * this enum. + */ + ZSTD_dictDefaultAttach = 0, /* Use the default heuristic. */ + ZSTD_dictForceAttach = 1, /* Never copy the dictionary. */ + ZSTD_dictForceCopy = 2, /* Always copy the dictionary. */ + ZSTD_dictForceLoad = 3 /* Always reload the dictionary */ +} ZSTD_dictAttachPref_e; + +typedef enum { + ZSTD_lcm_auto = 0, /**< Automatically determine the compression mode based on the compression level. + * Negative compression levels will be uncompressed, and positive compression + * levels will be compressed. */ + ZSTD_lcm_huffman = 1, /**< Always attempt Huffman compression. Uncompressed literals will still be + * emitted if Huffman compression is not profitable. */ + ZSTD_lcm_uncompressed = 2 /**< Always emit uncompressed literals. */ +} ZSTD_literalCompressionMode_e; + + +/*************************************** +* Frame size functions +***************************************/ + +/*! ZSTD_findDecompressedSize() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - decompressed size of all data in all successive frames + * - if the decompressed size cannot be determined: ZSTD_CONTENTSIZE_UNKNOWN + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : decompressed size is an optional field, that may not be present, especially in streaming mode. + * When `return==ZSTD_CONTENTSIZE_UNKNOWN`, data to decompress could be any size. + * In which case, it's necessary to use streaming mode to decompress data. + * note 2 : decompressed size is always present when compression is done with ZSTD_compress() + * note 3 : decompressed size can be very large (64-bits value), + * potentially larger than what local system can handle as a single memory segment. + * In which case, it's necessary to use streaming mode to decompress data. + * note 4 : If source is untrusted, decompressed size could be wrong or intentionally modified. + * Always ensure result fits within application's authorized limits. + * Each application can set its own limits. + * note 5 : ZSTD_findDecompressedSize handles multiple frames, and so it must traverse the input to + * read each contained frame header. This is fast as most of the data is skipped, + * however it does mean that all frame data must be present and valid. */ +ZSTDLIB_API unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize); + +/*! ZSTD_decompressBound() : + * `src` should point to the start of a series of ZSTD encoded and/or skippable frames + * `srcSize` must be the _exact_ size of this series + * (i.e. there should be a frame boundary at `src + srcSize`) + * @return : - upper-bound for the decompressed size of all data in all successive frames + * - if an error occurred: ZSTD_CONTENTSIZE_ERROR + * + * note 1 : an error can occur if `src` contains an invalid or incorrectly formatted frame. + * note 2 : the upper-bound is exact when the decompressed size field is available in every ZSTD encoded frame of `src`. + * in this case, `ZSTD_findDecompressedSize` and `ZSTD_decompressBound` return the same value. + * note 3 : when the decompressed size field isn't available, the upper-bound for that frame is calculated by: + * upper-bound = # blocks * min(128 KB, Window_Size) + */ +ZSTDLIB_API unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize); + +/*! ZSTD_frameHeaderSize() : + * srcSize must be >= ZSTD_FRAMEHEADERSIZE_PREFIX. + * @return : size of the Frame Header, + * or an error code (if srcSize is too small) */ +ZSTDLIB_API size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize); + +/*! ZSTD_getSequences() : + * Extract sequences from the sequence store + * zc can be used to insert custom compression params. + * This function invokes ZSTD_compress2 + * @return : number of sequences extracted + */ +ZSTDLIB_API size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + size_t outSeqsSize, const void* src, size_t srcSize); + + +/*************************************** +* Memory management +***************************************/ + +/*! ZSTD_estimate*() : + * These functions make it possible to estimate memory usage + * of a future {D,C}Ctx, before its creation. + * + * ZSTD_estimateCCtxSize() will provide a memory budget large enough + * for any compression level up to selected one. + * Note : Unlike ZSTD_estimateCStreamSize*(), this estimate + * does not include space for a window buffer. + * Therefore, the estimation is only guaranteed for single-shot compressions, not streaming. + * The estimate will assume the input may be arbitrarily large, + * which is the worst case. + * + * When srcSize can be bound by a known and rather "small" value, + * this fact can be used to provide a tighter estimation + * because the CCtx compression context will need less memory. + * This tighter estimation can be provided by more advanced functions + * ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(), + * and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter(). + * Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits. + * + * Note 2 : only single-threaded compression is supported. + * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. + */ +ZSTDLIB_API size_t ZSTD_estimateCCtxSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateDCtxSize(void); + +/*! ZSTD_estimateCStreamSize() : + * ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one. + * It will also consider src size to be arbitrarily "large", which is worst case. + * If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation. + * ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel. + * ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1. + * Note : CStream size estimation is only correct for single-threaded compression. + * ZSTD_DStream memory budget depends on window Size. + * This information can be passed manually, using ZSTD_estimateDStreamSize, + * or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame(); + * Note : if streaming is init with function ZSTD_init?Stream_usingDict(), + * an internal ?Dict will be created, which additional size is not estimated here. + * In this case, get total size by adding ZSTD_estimate?DictSize */ +ZSTDLIB_API size_t ZSTD_estimateCStreamSize(int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); +ZSTDLIB_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize(size_t windowSize); +ZSTDLIB_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize); + +/*! ZSTD_estimate?DictSize() : + * ZSTD_estimateCDictSize() will bet that src size is relatively "small", and content is copied, like ZSTD_createCDict(). + * ZSTD_estimateCDictSize_advanced() makes it possible to control compression parameters precisely, like ZSTD_createCDict_advanced(). + * Note : dictionaries created by reference (`ZSTD_dlm_byRef`) are logically smaller. + */ +ZSTDLIB_API size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, ZSTD_dictLoadMethod_e dictLoadMethod); +ZSTDLIB_API size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod); + +/*! ZSTD_initStatic*() : + * Initialize an object using a pre-allocated fixed-size buffer. + * workspace: The memory area to emplace the object into. + * Provided pointer *must be 8-bytes aligned*. + * Buffer must outlive object. + * workspaceSize: Use ZSTD_estimate*Size() to determine + * how large workspace must be to support target scenario. + * @return : pointer to object (same address as workspace, just different type), + * or NULL if error (size too small, incorrect alignment, etc.) + * Note : zstd will never resize nor malloc() when using a static buffer. + * If the object requires more memory than available, + * zstd will just error out (typically ZSTD_error_memory_allocation). + * Note 2 : there is no corresponding "free" function. + * Since workspace is allocated externally, it must be freed externally too. + * Note 3 : cParams : use ZSTD_getCParams() to convert a compression level + * into its associated cParams. + * Limitation 1 : currently not compatible with internal dictionary creation, triggered by + * ZSTD_CCtx_loadDictionary(), ZSTD_initCStream_usingDict() or ZSTD_initDStream_usingDict(). + * Limitation 2 : static cctx currently not compatible with multi-threading. + * Limitation 3 : static dctx is incompatible with legacy support. + */ +ZSTDLIB_API ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_API ZSTD_CStream* ZSTD_initStaticCStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticCCtx() */ + +ZSTDLIB_API ZSTD_DCtx* ZSTD_initStaticDCtx(void* workspace, size_t workspaceSize); +ZSTDLIB_API ZSTD_DStream* ZSTD_initStaticDStream(void* workspace, size_t workspaceSize); /**< same as ZSTD_initStaticDCtx() */ + +ZSTDLIB_API const ZSTD_CDict* ZSTD_initStaticCDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams); + +ZSTDLIB_API const ZSTD_DDict* ZSTD_initStaticDDict( + void* workspace, size_t workspaceSize, + const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType); + + +/*! Custom memory allocation : + * These prototypes make it possible to pass your own allocation/free functions. + * ZSTD_customMem is provided at creation time, using ZSTD_create*_advanced() variants listed below. + * All allocation/free operations will be completed using these custom variants instead of regular ones. + */ +typedef void* (*ZSTD_allocFunction) (void* opaque, size_t size); +typedef void (*ZSTD_freeFunction) (void* opaque, void* address); +typedef struct { ZSTD_allocFunction customAlloc; ZSTD_freeFunction customFree; void* opaque; } ZSTD_customMem; + +ZSTDLIB_API ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem); +ZSTDLIB_API ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem); + +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_compressionParameters cParams, + ZSTD_customMem customMem); + +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, + ZSTD_dictLoadMethod_e dictLoadMethod, + ZSTD_dictContentType_e dictContentType, + ZSTD_customMem customMem); + + + +/*************************************** +* Advanced compression functions +***************************************/ + +/*! ZSTD_createCDict_byReference() : + * Create a digested dictionary for compression + * Dictionary content is just referenced, not duplicated. + * As a consequence, `dictBuffer` **must** outlive CDict, + * and its content must remain unmodified throughout the lifetime of CDict. + * note: equivalent to ZSTD_createCDict_advanced(), with dictLoadMethod==ZSTD_dlm_byRef */ +ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_byReference(const void* dictBuffer, size_t dictSize, int compressionLevel); + +/*! ZSTD_getCParams() : + * @return ZSTD_compressionParameters structure for a selected compression level and estimated srcSize. + * `estimatedSrcSize` value is optional, select 0 if not known */ +ZSTDLIB_API ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_getParams() : + * same as ZSTD_getCParams(), but @return a full `ZSTD_parameters` object instead of sub-component `ZSTD_compressionParameters`. + * All fields of `ZSTD_frameParameters` are set to default : contentSize=1, checksum=0, noDictID=0 */ +ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long estimatedSrcSize, size_t dictSize); + +/*! ZSTD_checkCParams() : + * Ensure param values remain within authorized range. + * @return 0 on success, or an error code (can be checked with ZSTD_isError()) */ +ZSTDLIB_API size_t ZSTD_checkCParams(ZSTD_compressionParameters params); + +/*! ZSTD_adjustCParams() : + * optimize params for a given `srcSize` and `dictSize`. + * `srcSize` can be unknown, in which case use ZSTD_CONTENTSIZE_UNKNOWN. + * `dictSize` must be `0` when there is no dictionary. + * cPar can be invalid : all parameters will be clamped within valid range in the @return struct. + * This function never fails (wide contract) */ +ZSTDLIB_API ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize); + +/*! ZSTD_compress_advanced() : + * Note : this function is now DEPRECATED. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_setParameter() and other parameter setters. + * This prototype will be marked as deprecated and generate compilation warning on reaching v1.5.x */ +ZSTDLIB_API size_t ZSTD_compress_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const void* dict,size_t dictSize, + ZSTD_parameters params); + +/*! ZSTD_compress_usingCDict_advanced() : + * Note : this function is now REDUNDANT. + * It can be replaced by ZSTD_compress2(), in combination with ZSTD_CCtx_loadDictionary() and other parameter setters. + * This prototype will be marked as deprecated and generate compilation warning in some future version */ +ZSTDLIB_API size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams); + + +/*! ZSTD_CCtx_loadDictionary_byReference() : + * Same as ZSTD_CCtx_loadDictionary(), but dictionary content is referenced, instead of being copied into CCtx. + * It saves some memory, but also requires that `dict` outlives its usage within `cctx` */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx* cctx, const void* dict, size_t dictSize); + +/*! ZSTD_CCtx_loadDictionary_advanced() : + * Same as ZSTD_CCtx_loadDictionary(), but gives finer control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?) */ +ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_CCtx_refPrefix_advanced() : + * Same as ZSTD_CCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/* === experimental parameters === */ +/* these parameters can be used with ZSTD_setParameter() + * they are not guaranteed to remain supported in the future */ + + /* Enables rsyncable mode, + * which makes compressed files more rsync friendly + * by adding periodic synchronization points to the compressed data. + * The target average block size is ZSTD_c_jobSize / 2. + * It's possible to modify the job size to increase or decrease + * the granularity of the synchronization point. + * Once the jobSize is smaller than the window size, + * it will result in compression ratio degradation. + * NOTE 1: rsyncable mode only works when multithreading is enabled. + * NOTE 2: rsyncable performs poorly in combination with long range mode, + * since it will decrease the effectiveness of synchronization points, + * though mileage may vary. + * NOTE 3: Rsyncable mode limits maximum compression speed to ~400 MB/s. + * If the selected compression level is already running significantly slower, + * the overall speed won't be significantly impacted. + */ + #define ZSTD_c_rsyncable ZSTD_c_experimentalParam1 + +/* Select a compression format. + * The value must be of type ZSTD_format_e. + * See ZSTD_format_e enum definition for details */ +#define ZSTD_c_format ZSTD_c_experimentalParam2 + +/* Force back-reference distances to remain < windowSize, + * even when referencing into Dictionary content (default:0) */ +#define ZSTD_c_forceMaxWindow ZSTD_c_experimentalParam3 + +/* Controls whether the contents of a CDict + * are used in place, or copied into the working context. + * Accepts values from the ZSTD_dictAttachPref_e enum. + * See the comments on that enum for an explanation of the feature. */ +#define ZSTD_c_forceAttachDict ZSTD_c_experimentalParam4 + +/* Controls how the literals are compressed (default is auto). + * The value must be of type ZSTD_literalCompressionMode_e. + * See ZSTD_literalCompressionMode_t enum definition for details. + */ +#define ZSTD_c_literalCompressionMode ZSTD_c_experimentalParam5 + +/* Tries to fit compressed block size to be around targetCBlockSize. + * No target when targetCBlockSize == 0. + * There is no guarantee on compressed block size (default:0) */ +#define ZSTD_c_targetCBlockSize ZSTD_c_experimentalParam6 + +/* User's best guess of source size. + * Hint is not valid when srcSizeHint == 0. + * There is no guarantee that hint is close to actual source size, + * but compression ratio may regress significantly if guess considerably underestimates */ +#define ZSTD_c_srcSizeHint ZSTD_c_experimentalParam7 + +/*! ZSTD_CCtx_getParameter() : + * Get the requested compression parameter value, selected by enum ZSTD_cParameter, + * and store it into int* value. + * @return : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value); + + +/*! ZSTD_CCtx_params : + * Quick howto : + * - ZSTD_createCCtxParams() : Create a ZSTD_CCtx_params structure + * - ZSTD_CCtxParams_setParameter() : Push parameters one by one into + * an existing ZSTD_CCtx_params structure. + * This is similar to + * ZSTD_CCtx_setParameter(). + * - ZSTD_CCtx_setParametersUsingCCtxParams() : Apply parameters to + * an existing CCtx. + * These parameters will be applied to + * all subsequent frames. + * - ZSTD_compressStream2() : Do compression using the CCtx. + * - ZSTD_freeCCtxParams() : Free the memory. + * + * This can be used with ZSTD_estimateCCtxSize_advanced_usingCCtxParams() + * for static allocation of CCtx for single-threaded compression. + */ +ZSTDLIB_API ZSTD_CCtx_params* ZSTD_createCCtxParams(void); +ZSTDLIB_API size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_reset() : + * Reset params to default values. + */ +ZSTDLIB_API size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params); + +/*! ZSTD_CCtxParams_init() : + * Initializes the compression parameters of cctxParams according to + * compression level. All other parameters are reset to their default values. + */ +ZSTDLIB_API size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel); + +/*! ZSTD_CCtxParams_init_advanced() : + * Initializes the compression and frame parameters of cctxParams according to + * params. All other parameters are reset to their default values. + */ +ZSTDLIB_API size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); + +/*! ZSTD_CCtxParams_setParameter() : + * Similar to ZSTD_CCtx_setParameter. + * Set one compression parameter, selected by enum ZSTD_cParameter. + * Parameters must be applied to a ZSTD_CCtx using ZSTD_CCtx_setParametersUsingCCtxParams(). + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int value); + +/*! ZSTD_CCtxParams_getParameter() : + * Similar to ZSTD_CCtx_getParameter. + * Get the requested value of one compression parameter, selected by enum ZSTD_cParameter. + * @result : 0, or an error code (which can be tested with ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params* params, ZSTD_cParameter param, int* value); + +/*! ZSTD_CCtx_setParametersUsingCCtxParams() : + * Apply a set of ZSTD_CCtx_params to the compression context. + * This can be done even after compression is started, + * if nbWorkers==0, this will have no impact until a new compression is started. + * if nbWorkers>=1, new parameters will be picked up at next job, + * with a few restrictions (windowLog, pledgedSrcSize, nbWorkers, jobSize, and overlapLog are not updated). + */ +ZSTDLIB_API size_t ZSTD_CCtx_setParametersUsingCCtxParams( + ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params); + +/*! ZSTD_compressStream2_simpleArgs() : + * Same as ZSTD_compressStream2(), + * but using only integral types as arguments. + * This variant might be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_API size_t ZSTD_compressStream2_simpleArgs ( + ZSTD_CCtx* cctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos, + ZSTD_EndDirective endOp); + + +/*************************************** +* Advanced decompression functions +***************************************/ + +/*! ZSTD_isFrame() : + * Tells if the content of `buffer` starts with a valid Frame Identifier. + * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0. + * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled. + * Note 3 : Skippable Frame Identifiers are considered valid. */ +ZSTDLIB_API unsigned ZSTD_isFrame(const void* buffer, size_t size); + +/*! ZSTD_createDDict_byReference() : + * Create a digested dictionary, ready to start decompression operation without startup delay. + * Dictionary content is referenced, and therefore stays in dictBuffer. + * It is important that dictBuffer outlives DDict, + * it must remain read accessible throughout the lifetime of DDict */ +ZSTDLIB_API ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_byReference() : + * Same as ZSTD_DCtx_loadDictionary(), + * but references `dict` content instead of copying it into `dctx`. + * This saves memory if `dict` remains around., + * However, it's imperative that `dict` remains accessible (and unmodified) while being used, so it must outlive decompression. */ +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); + +/*! ZSTD_DCtx_loadDictionary_advanced() : + * Same as ZSTD_DCtx_loadDictionary(), + * but gives direct control over + * how to load the dictionary (by copy ? by reference ?) + * and how to interpret it (automatic ? force raw mode ? full mode only ?). */ +ZSTDLIB_API size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx, const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_refPrefix_advanced() : + * Same as ZSTD_DCtx_refPrefix(), but gives finer control over + * how to interpret prefix content (automatic ? force raw mode (default) ? full mode only ?) */ +ZSTDLIB_API size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType); + +/*! ZSTD_DCtx_setMaxWindowSize() : + * Refuses allocating internal buffers for frames requiring a window size larger than provided limit. + * This protects a decoder context from reserving too much memory for itself (potential attack scenario). + * This parameter is only useful in streaming mode, since no internal buffer is allocated in single-pass mode. + * By default, a decompression context accepts all window sizes <= (1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + * @return : 0, or an error code (which can be tested using ZSTD_isError()). + */ +ZSTDLIB_API size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize); + +/* ZSTD_d_format + * experimental parameter, + * allowing selection between ZSTD_format_e input compression formats + */ +#define ZSTD_d_format ZSTD_d_experimentalParam1 +/* ZSTD_d_stableOutBuffer + * Experimental parameter. + * Default is 0 == disabled. Set to 1 to enable. + * + * Tells the decompressor that the ZSTD_outBuffer will ALWAYS be the same + * between calls, except for the modifications that zstd makes to pos (the + * caller must not modify pos). This is checked by the decompressor, and + * decompression will fail if it ever changes. Therefore the ZSTD_outBuffer + * MUST be large enough to fit the entire decompressed frame. This will be + * checked when the frame content size is known. The data in the ZSTD_outBuffer + * in the range [dst, dst + pos) MUST not be modified during decompression + * or you will get data corruption. + * + * When this flags is enabled zstd won't allocate an output buffer, because + * it can write directly to the ZSTD_outBuffer, but it will still allocate + * an input buffer large enough to fit any compressed block. This will also + * avoid the memcpy() from the internal output buffer to the ZSTD_outBuffer. + * If you need to avoid the input buffer allocation use the buffer-less + * streaming API. + * + * NOTE: So long as the ZSTD_outBuffer always points to valid memory, using + * this flag is ALWAYS memory safe, and will never access out-of-bounds + * memory. However, decompression WILL fail if you violate the preconditions. + * + * WARNING: The data in the ZSTD_outBuffer in the range [dst, dst + pos) MUST + * not be modified during decompression or you will get data corruption. This + * is because zstd needs to reference data in the ZSTD_outBuffer to regenerate + * matches. Normally zstd maintains its own buffer for this purpose, but passing + * this flag tells zstd to use the user provided buffer. + */ +#define ZSTD_d_stableOutBuffer ZSTD_d_experimentalParam2 + +/*! ZSTD_DCtx_setFormat() : + * Instruct the decoder context about what kind of data to decode next. + * This instruction is mandatory to decode data without a fully-formed header, + * such ZSTD_f_zstd1_magicless for example. + * @return : 0, or an error code (which can be tested using ZSTD_isError()). */ +ZSTDLIB_API size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format); + +/*! ZSTD_decompressStream_simpleArgs() : + * Same as ZSTD_decompressStream(), + * but using only integral types as arguments. + * This can be helpful for binders from dynamic languages + * which have troubles handling structures containing memory pointers. + */ +ZSTDLIB_API size_t ZSTD_decompressStream_simpleArgs ( + ZSTD_DCtx* dctx, + void* dst, size_t dstCapacity, size_t* dstPos, + const void* src, size_t srcSize, size_t* srcPos); + + +/******************************************************************** +* Advanced streaming functions +* Warning : most of these functions are now redundant with the Advanced API. +* Once Advanced API reaches "stable" status, +* redundant functions will be deprecated, and then at some point removed. +********************************************************************/ + +/*===== Advanced Streaming compression functions =====*/ +/**! ZSTD_initCStream_srcSize() : + * This function is deprecated, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, NULL); // clear the dictionary (if any) + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * pledgedSrcSize must be correct. If it is not known at init time, use + * ZSTD_CONTENTSIZE_UNKNOWN. Note that, for compatibility with older programs, + * "0" also disables frame content size field. It may be enabled in the future. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t +ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, + int compressionLevel, + unsigned long long pledgedSrcSize); + +/**! ZSTD_initCStream_usingDict() : + * This function is deprecated, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * Creates of an internal CDict (incompatible with static CCtx), except if + * dict == NULL or dictSize < 8, in which case no dict is used. + * Note: dict is loaded with ZSTD_dct_auto (treated as a full zstd dictionary if + * it begins with ZSTD_MAGIC_DICTIONARY, else as raw content) and ZSTD_dlm_byCopy. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t +ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + int compressionLevel); + +/**! ZSTD_initCStream_advanced() : + * This function is deprecated, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd parameter and leave the rest as-is. + * for ((param, value) : params) { + * ZSTD_CCtx_setParameter(zcs, param, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_loadDictionary(zcs, dict, dictSize); + * + * dict is loaded with ZSTD_dct_auto and ZSTD_dlm_byCopy. + * pledgedSrcSize must be correct. + * If srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t +ZSTD_initCStream_advanced(ZSTD_CStream* zcs, + const void* dict, size_t dictSize, + ZSTD_parameters params, + unsigned long long pledgedSrcSize); + +/**! ZSTD_initCStream_usingCDict() : + * This function is deprecated, and equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * note : cdict will just be referenced, and must outlive compression session + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict); + +/**! ZSTD_initCStream_usingCDict_advanced() : + * This function is DEPRECATED, and is approximately equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * // Pseudocode: Set each zstd frame parameter and leave the rest as-is. + * for ((fParam, value) : fParams) { + * ZSTD_CCtx_setParameter(zcs, fParam, value); + * } + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * ZSTD_CCtx_refCDict(zcs, cdict); + * + * same as ZSTD_initCStream_usingCDict(), with control over frame parameters. + * pledgedSrcSize must be correct. If srcSize is not known at init time, use + * value ZSTD_CONTENTSIZE_UNKNOWN. + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t +ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, + const ZSTD_CDict* cdict, + ZSTD_frameParameters fParams, + unsigned long long pledgedSrcSize); + +/*! ZSTD_resetCStream() : + * This function is deprecated, and is equivalent to: + * ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); + * ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize); + * + * start a new frame, using same parameters from previous frame. + * This is typically useful to skip dictionary loading stage, since it will re-use it in-place. + * Note that zcs must be init at least once before using ZSTD_resetCStream(). + * If pledgedSrcSize is not known at reset time, use macro ZSTD_CONTENTSIZE_UNKNOWN. + * If pledgedSrcSize > 0, its value must be correct, as it will be written in header, and controlled at the end. + * For the time being, pledgedSrcSize==0 is interpreted as "srcSize unknown" for compatibility with older programs, + * but it will change to mean "empty" in future version, so use macro ZSTD_CONTENTSIZE_UNKNOWN instead. + * @return : 0, or an error code (which can be tested using ZSTD_isError()) + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize); + + +typedef struct { + unsigned long long ingested; /* nb input bytes read and buffered */ + unsigned long long consumed; /* nb input bytes actually compressed */ + unsigned long long produced; /* nb of compressed bytes generated and buffered */ + unsigned long long flushed; /* nb of compressed bytes flushed : not provided; can be tracked from caller side */ + unsigned currentJobID; /* MT only : latest started job nb */ + unsigned nbActiveWorkers; /* MT only : nb of workers actively compressing at probe time */ +} ZSTD_frameProgression; + +/* ZSTD_getFrameProgression() : + * tells how much data has been ingested (read from input) + * consumed (input actually compressed) and produced (output) for current frame. + * Note : (ingested - consumed) is amount of input data buffered internally, not yet compressed. + * Aggregates progression inside active worker threads. + */ +ZSTDLIB_API ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx); + +/*! ZSTD_toFlushNow() : + * Tell how many bytes are ready to be flushed immediately. + * Useful for multithreading scenarios (nbWorkers >= 1). + * Probe the oldest active job, defined as oldest job not yet entirely flushed, + * and check its output buffer. + * @return : amount of data stored in oldest job and ready to be flushed immediately. + * if @return == 0, it means either : + * + there is no active job (could be checked with ZSTD_frameProgression()), or + * + oldest job is still actively compressing data, + * but everything it has produced has also been flushed so far, + * therefore flush speed is limited by production speed of oldest job + * irrespective of the speed of concurrent (and newer) jobs. + */ +ZSTDLIB_API size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx); + + +/*===== Advanced Streaming decompression functions =====*/ +/** + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_loadDictionary(zds, dict, dictSize); + * + * note: no dictionary will be used if dict == NULL or dictSize < 8 + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize); + +/** + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * ZSTD_DCtx_refDDict(zds, ddict); + * + * note : ddict is referenced, it must outlive decompression session + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* zds, const ZSTD_DDict* ddict); + +/** + * This function is deprecated, and is equivalent to: + * + * ZSTD_DCtx_reset(zds, ZSTD_reset_session_only); + * + * re-use decompression parameters from previous init; saves dictionary loading + * Note : this prototype will be marked as deprecated and generate compilation warnings on reaching v1.5.x + */ +ZSTDLIB_API size_t ZSTD_resetDStream(ZSTD_DStream* zds); + + +/********************************************************************* +* Buffer-less and synchronous inner streaming functions +* +* This is an advanced API, giving full control over buffer management, for users which need direct control over memory. +* But it's also a complex one, with several restrictions, documented below. +* Prefer normal streaming API for an easier experience. +********************************************************************* */ + +/** + Buffer-less streaming compression (synchronous mode) + + A ZSTD_CCtx object is required to track streaming operations. + Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage resource. + ZSTD_CCtx object can be re-used multiple times within successive compression operations. + + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression, + or ZSTD_compressBegin_advanced(), for finer parameter control. + It's also possible to duplicate a reference context which has already been initialized, using ZSTD_copyCCtx() + + Then, consume your input using ZSTD_compressContinue(). + There are some important considerations to keep in mind when using this advanced function : + - ZSTD_compressContinue() has no internal buffer. It uses externally provided buffers only. + - Interface is synchronous : input is consumed entirely and produces 1+ compressed blocks. + - Caller must ensure there is enough space in `dst` to store compressed data under worst case scenario. + Worst case evaluation is provided by ZSTD_compressBound(). + ZSTD_compressContinue() doesn't guarantee recover after a failed compression. + - ZSTD_compressContinue() presumes prior input ***is still accessible and unmodified*** (up to maximum distance size, see WindowLog). + It remembers all previous contiguous blocks, plus one separated memory segment (which can itself consists of multiple contiguous blocks) + - ZSTD_compressContinue() detects that prior input has been overwritten when `src` buffer overlaps. + In which case, it will "discard" the relevant memory section from its history. + + Finish a frame with ZSTD_compressEnd(), which will write the last block(s) and optional checksum. + It's possible to use srcSize==0, in which case, it will write a final empty block to end the frame. + Without last block mark, frames are considered unfinished (hence corrupted) by compliant decoders. + + `ZSTD_CCtx` object can be re-used (ZSTD_compressBegin()) to compress again. +*/ + +/*===== Buffer-less streaming compression functions =====*/ +ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params, unsigned long long pledgedSrcSize); /**< pledgedSrcSize : If srcSize is not known at init time, use ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict); /**< note: fails if cdict==NULL */ +ZSTDLIB_API size_t ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize); /* compression parameters are already set within cdict. pledgedSrcSize must be correct. If srcSize is not known, use macro ZSTD_CONTENTSIZE_UNKNOWN */ +ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, unsigned long long pledgedSrcSize); /**< note: if pledgedSrcSize is not known, use ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + + +/*- + Buffer-less streaming decompression (synchronous mode) + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be re-used multiple times. + + First typical operation is to retrieve frame parameters, using ZSTD_getFrameHeader(). + Frame header is extracted from the beginning of compressed frame, so providing only the frame's beginning is enough. + Data fragment must be large enough to ensure successful decoding. + `ZSTD_frameHeaderSize_max` bytes is guaranteed to always be large enough. + @result : 0 : successful decoding, the `ZSTD_frameHeader` structure is correctly filled. + >0 : `srcSize` is too small, please provide at least @result bytes on next attempt. + errorCode, which can be tested using ZSTD_isError(). + + It fills a ZSTD_frameHeader structure with important information to correctly decode the frame, + such as the dictionary ID, content size, or maximum back-reference distance (`windowSize`). + Note that these values could be wrong, either because of data corruption, or because a 3rd party deliberately spoofs false information. + As a consequence, check that values remain within valid application range. + For example, do not allocate memory blindly, check that `windowSize` is within expectation. + Each application can set its own limits, depending on local restrictions. + For extended interoperability, it is recommended to support `windowSize` of at least 8 MB. + + ZSTD_decompressContinue() needs previous data blocks during decompression, up to `windowSize` bytes. + ZSTD_decompressContinue() is very sensitive to contiguity, + if 2 blocks don't follow each other, make sure that either the compressor breaks contiguity at the same place, + or that previous contiguous segment is large enough to properly handle maximum back-reference distance. + There are multiple ways to guarantee this condition. + + The most memory efficient way is to use a round buffer of sufficient size. + Sufficient size is determined by invoking ZSTD_decodingBufferSize_min(), + which can @return an error code if required value is too large for current system (in 32-bits mode). + In a round buffer methodology, ZSTD_decompressContinue() decompresses each block next to previous one, + up to the moment there is not enough room left in the buffer to guarantee decoding another full block, + which maximum size is provided in `ZSTD_frameHeader` structure, field `blockSizeMax`. + At which point, decoding can resume from the beginning of the buffer. + Note that already decoded data stored in the buffer should be flushed before being overwritten. + + There are alternatives possible, for example using two or more buffers of size `windowSize` each, though they consume more memory. + + Finally, if you control the compression process, you can also ignore all buffer size rules, + as long as the encoder and decoder progress in "lock-step", + aka use exactly the same buffer sizes, break contiguity at the same place, etc. + + Once buffers are setup, start decompression, with ZSTD_decompressBegin(). + If decompression requires a dictionary, use ZSTD_decompressBegin_usingDict() or ZSTD_decompressBegin_usingDDict(). + + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how many bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this _exact_ amount of bytes, or it will fail. + + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity). + It can be zero : it just means ZSTD_decompressContinue() has decoded some metadata item. + It can also be an error code, which can be tested with ZSTD_isError(). + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. + + Note : it's possible to know if next input to present is a header or a block, using ZSTD_nextInputType(). + This information is not required to properly decode a frame. + + == Special case : skippable frames == + + Skippable frames allow integration of user-defined data into a flow of concatenated frames. + Skippable frames will be ignored (skipped) by decompressor. + The format of skippable frames is as follows : + a) Skippable frame ID - 4 Bytes, Little endian format, any value from 0x184D2A50 to 0x184D2A5F + b) Frame Size - 4 Bytes, Little endian format, unsigned 32-bits + c) Frame Content - any content (User Data) of length equal to Frame Size + For skippable frames ZSTD_getFrameHeader() returns zfhPtr->frameType==ZSTD_skippableFrame. + For skippable frames ZSTD_decompressContinue() always returns 0 : it only skips the content. +*/ + +/*===== Buffer-less streaming decompression functions =====*/ +typedef enum { ZSTD_frame, ZSTD_skippableFrame } ZSTD_frameType_e; +typedef struct { + unsigned long long frameContentSize; /* if == ZSTD_CONTENTSIZE_UNKNOWN, it means this field is not available. 0 means "empty" */ + unsigned long long windowSize; /* can be very large, up to <= frameContentSize */ + unsigned blockSizeMax; + ZSTD_frameType_e frameType; /* if == ZSTD_skippableFrame, frameContentSize is the size of skippable content */ + unsigned headerSize; + unsigned dictID; + unsigned checksumFlag; +} ZSTD_frameHeader; + +/*! ZSTD_getFrameHeader() : + * decode Frame Header, or requires larger `srcSize`. + * @return : 0, `zfhPtr` is correctly filled, + * >0, `srcSize` is too small, value is wanted `srcSize` amount, + * or an error code, which can be tested using ZSTD_isError() */ +ZSTDLIB_API size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize); /**< doesn't consume input */ +/*! ZSTD_getFrameHeader_advanced() : + * same as ZSTD_getFrameHeader(), + * with added capability to select a format (like ZSTD_f_zstd1_magicless) */ +ZSTDLIB_API size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format); +ZSTDLIB_API size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize); /**< when frame content size is not known, pass in frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN */ + +ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); + +ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); + +/* misc */ +ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); +typedef enum { ZSTDnit_frameHeader, ZSTDnit_blockHeader, ZSTDnit_block, ZSTDnit_lastBlock, ZSTDnit_checksum, ZSTDnit_skippableFrame } ZSTD_nextInputType_e; +ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx); + + + + +/* ============================ */ +/** Block level API */ +/* ============================ */ + +/*! + Block functions produce and decode raw zstd blocks, without frame metadata. + Frame metadata cost is typically ~12 bytes, which can be non-negligible for very small blocks (< 100 bytes). + But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes. + + A few rules to respect : + - Compressing and decompressing require a context structure + + Use ZSTD_createCCtx() and ZSTD_createDCtx() + - It is necessary to init context before starting + + compression : any ZSTD_compressBegin*() variant, including with dictionary + + decompression : any ZSTD_decompressBegin*() variant, including with dictionary + + copyCCtx() and copyDCtx() can be used too + - Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB + + If input is larger than a block size, it's necessary to split input data into multiple blocks + + For inputs larger than a single block, consider using regular ZSTD_compress() instead. + Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block. + - When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) ! + ===> In which case, nothing is produced into `dst` ! + + User __must__ test for such outcome and deal directly with uncompressed data + + A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0. + Doing so would mess up with statistics history, leading to potential data corruption. + + ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !! + + In case of multiple successive blocks, should some of them be uncompressed, + decoder must be informed of their existence in order to follow proper history. + Use ZSTD_insertBlock() for such a case. +*/ + +/*===== Raw zstd block functions =====*/ +ZSTDLIB_API size_t ZSTD_getBlockSize (const ZSTD_CCtx* cctx); +ZSTDLIB_API size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ + +} + +#endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ diff --git a/src/duckdb/ub_extension_core_functions_aggregate_algebraic.cpp b/src/duckdb/ub_extension_core_functions_aggregate_algebraic.cpp deleted file mode 100644 index ac1532ac1..000000000 --- a/src/duckdb/ub_extension_core_functions_aggregate_algebraic.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "extension/core_functions/aggregate/algebraic/corr.cpp" - -#include "extension/core_functions/aggregate/algebraic/stddev.cpp" - -#include "extension/core_functions/aggregate/algebraic/avg.cpp" - -#include "extension/core_functions/aggregate/algebraic/covar.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_aggregate_distributive.cpp b/src/duckdb/ub_extension_core_functions_aggregate_distributive.cpp deleted file mode 100644 index f8c552db1..000000000 --- a/src/duckdb/ub_extension_core_functions_aggregate_distributive.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "extension/core_functions/aggregate/distributive/skew.cpp" - -#include "extension/core_functions/aggregate/distributive/bool.cpp" - -#include "extension/core_functions/aggregate/distributive/bitstring_agg.cpp" - -#include "extension/core_functions/aggregate/distributive/bitagg.cpp" - -#include "extension/core_functions/aggregate/distributive/kurtosis.cpp" - -#include "extension/core_functions/aggregate/distributive/sum.cpp" - -#include "extension/core_functions/aggregate/distributive/arg_min_max.cpp" - -#include "extension/core_functions/aggregate/distributive/product.cpp" - -#include "extension/core_functions/aggregate/distributive/string_agg.cpp" - -#include "extension/core_functions/aggregate/distributive/approx_count.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_aggregate_holistic.cpp b/src/duckdb/ub_extension_core_functions_aggregate_holistic.cpp deleted file mode 100644 index 2e18fa37e..000000000 --- a/src/duckdb/ub_extension_core_functions_aggregate_holistic.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "extension/core_functions/aggregate/holistic/mad.cpp" - -#include "extension/core_functions/aggregate/holistic/quantile.cpp" - -#include "extension/core_functions/aggregate/holistic/reservoir_quantile.cpp" - -#include "extension/core_functions/aggregate/holistic/approximate_quantile.cpp" - -#include "extension/core_functions/aggregate/holistic/approx_top_k.cpp" - -#include "extension/core_functions/aggregate/holistic/mode.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_aggregate_nested.cpp b/src/duckdb/ub_extension_core_functions_aggregate_nested.cpp deleted file mode 100644 index 8f3f5452f..000000000 --- a/src/duckdb/ub_extension_core_functions_aggregate_nested.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "extension/core_functions/aggregate/nested/binned_histogram.cpp" - -#include "extension/core_functions/aggregate/nested/histogram.cpp" - -#include "extension/core_functions/aggregate/nested/list.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_aggregate_regression.cpp b/src/duckdb/ub_extension_core_functions_aggregate_regression.cpp deleted file mode 100644 index 3b2713788..000000000 --- a/src/duckdb/ub_extension_core_functions_aggregate_regression.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "extension/core_functions/aggregate/regression/regr_avg.cpp" - -#include "extension/core_functions/aggregate/regression/regr_intercept.cpp" - -#include "extension/core_functions/aggregate/regression/regr_sxx_syy.cpp" - -#include "extension/core_functions/aggregate/regression/regr_count.cpp" - -#include "extension/core_functions/aggregate/regression/regr_slope.cpp" - -#include "extension/core_functions/aggregate/regression/regr_r2.cpp" - -#include "extension/core_functions/aggregate/regression/regr_sxy.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_array.cpp b/src/duckdb/ub_extension_core_functions_scalar_array.cpp deleted file mode 100644 index 9b9a475b4..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_array.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "extension/core_functions/scalar/array/array_value.cpp" - -#include "extension/core_functions/scalar/array/array_functions.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_bit.cpp b/src/duckdb/ub_extension_core_functions_scalar_bit.cpp deleted file mode 100644 index 0e48db861..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_bit.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/bit/bitstring.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_blob.cpp b/src/duckdb/ub_extension_core_functions_scalar_blob.cpp deleted file mode 100644 index 1eda3bad1..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_blob.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "extension/core_functions/scalar/blob/base64.cpp" - -#include "extension/core_functions/scalar/blob/encode.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_date.cpp b/src/duckdb/ub_extension_core_functions_scalar_date.cpp deleted file mode 100644 index 11b7e8756..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_date.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "extension/core_functions/scalar/date/make_date.cpp" - -#include "extension/core_functions/scalar/date/date_trunc.cpp" - -#include "extension/core_functions/scalar/date/date_part.cpp" - -#include "extension/core_functions/scalar/date/date_diff.cpp" - -#include "extension/core_functions/scalar/date/age.cpp" - -#include "extension/core_functions/scalar/date/time_bucket.cpp" - -#include "extension/core_functions/scalar/date/date_sub.cpp" - -#include "extension/core_functions/scalar/date/current.cpp" - -#include "extension/core_functions/scalar/date/to_interval.cpp" - -#include "extension/core_functions/scalar/date/epoch.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_debug.cpp b/src/duckdb/ub_extension_core_functions_scalar_debug.cpp deleted file mode 100644 index f1c3fa82e..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_debug.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/debug/vector_type.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_enum.cpp b/src/duckdb/ub_extension_core_functions_scalar_enum.cpp deleted file mode 100644 index 74e9bf3f7..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_enum.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/enum/enum_functions.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_generic.cpp b/src/duckdb/ub_extension_core_functions_scalar_generic.cpp deleted file mode 100644 index d24580892..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_generic.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "extension/core_functions/scalar/generic/alias.cpp" - -#include "extension/core_functions/scalar/generic/binning.cpp" - -#include "extension/core_functions/scalar/generic/can_implicitly_cast.cpp" - -#include "extension/core_functions/scalar/generic/current_setting.cpp" - -#include "extension/core_functions/scalar/generic/hash.cpp" - -#include "extension/core_functions/scalar/generic/least.cpp" - -#include "extension/core_functions/scalar/generic/stats.cpp" - -#include "extension/core_functions/scalar/generic/typeof.cpp" - -#include "extension/core_functions/scalar/generic/system_functions.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_list.cpp b/src/duckdb/ub_extension_core_functions_scalar_list.cpp deleted file mode 100644 index 87d225f95..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_list.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "extension/core_functions/scalar/list/flatten.cpp" - -#include "extension/core_functions/scalar/list/list_distance.cpp" - -#include "extension/core_functions/scalar/list/array_slice.cpp" - -#include "extension/core_functions/scalar/list/list_transform.cpp" - -#include "extension/core_functions/scalar/list/list_filter.cpp" - -#include "extension/core_functions/scalar/list/list_reduce.cpp" - -#include "extension/core_functions/scalar/list/list_sort.cpp" - -#include "extension/core_functions/scalar/list/list_aggregates.cpp" - -#include "extension/core_functions/scalar/list/list_has_any_or_all.cpp" - -#include "extension/core_functions/scalar/list/range.cpp" - -#include "extension/core_functions/scalar/list/list_value.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_map.cpp b/src/duckdb/ub_extension_core_functions_scalar_map.cpp deleted file mode 100644 index b191443c0..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_map.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "extension/core_functions/scalar/map/map_keys_values.cpp" - -#include "extension/core_functions/scalar/map/cardinality.cpp" - -#include "extension/core_functions/scalar/map/map_concat.cpp" - -#include "extension/core_functions/scalar/map/map_extract.cpp" - -#include "extension/core_functions/scalar/map/map_from_entries.cpp" - -#include "extension/core_functions/scalar/map/map.cpp" - -#include "extension/core_functions/scalar/map/map_entries.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_math.cpp b/src/duckdb/ub_extension_core_functions_scalar_math.cpp deleted file mode 100644 index 27320ea9f..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_math.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/math/numeric.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_operators.cpp b/src/duckdb/ub_extension_core_functions_scalar_operators.cpp deleted file mode 100644 index 47383d4eb..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_operators.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/operators/bitwise.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_random.cpp b/src/duckdb/ub_extension_core_functions_scalar_random.cpp deleted file mode 100644 index f71b7b4cd..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_random.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "extension/core_functions/scalar/random/random.cpp" - -#include "extension/core_functions/scalar/random/setseed.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_string.cpp b/src/duckdb/ub_extension_core_functions_scalar_string.cpp deleted file mode 100644 index b57063a4b..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_string.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "extension/core_functions/scalar/string/hex.cpp" - -#include "extension/core_functions/scalar/string/unicode.cpp" - -#include "extension/core_functions/scalar/string/translate.cpp" - -#include "extension/core_functions/scalar/string/left_right.cpp" - -#include "extension/core_functions/scalar/string/hamming.cpp" - -#include "extension/core_functions/scalar/string/damerau_levenshtein.cpp" - -#include "extension/core_functions/scalar/string/ascii.cpp" - -#include "extension/core_functions/scalar/string/starts_with.cpp" - -#include "extension/core_functions/scalar/string/repeat.cpp" - -#include "extension/core_functions/scalar/string/chr.cpp" - -#include "extension/core_functions/scalar/string/levenshtein.cpp" - -#include "extension/core_functions/scalar/string/pad.cpp" - -#include "extension/core_functions/scalar/string/bar.cpp" - -#include "extension/core_functions/scalar/string/replace.cpp" - -#include "extension/core_functions/scalar/string/to_base.cpp" - -#include "extension/core_functions/scalar/string/printf.cpp" - -#include "extension/core_functions/scalar/string/format_bytes.cpp" - -#include "extension/core_functions/scalar/string/instr.cpp" - -#include "extension/core_functions/scalar/string/url_encode.cpp" - -#include "extension/core_functions/scalar/string/jaccard.cpp" - -#include "extension/core_functions/scalar/string/reverse.cpp" - -#include "extension/core_functions/scalar/string/trim.cpp" - -#include "extension/core_functions/scalar/string/parse_path.cpp" - -#include "extension/core_functions/scalar/string/jaro_winkler.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_struct.cpp b/src/duckdb/ub_extension_core_functions_scalar_struct.cpp deleted file mode 100644 index 8d52b2f9c..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_struct.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "extension/core_functions/scalar/struct/struct_insert.cpp" - diff --git a/src/duckdb/ub_extension_core_functions_scalar_union.cpp b/src/duckdb/ub_extension_core_functions_scalar_union.cpp deleted file mode 100644 index c23d6ebff..000000000 --- a/src/duckdb/ub_extension_core_functions_scalar_union.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "extension/core_functions/scalar/union/union_value.cpp" - -#include "extension/core_functions/scalar/union/union_extract.cpp" - -#include "extension/core_functions/scalar/union/union_tag.cpp" - diff --git a/src/duckdb/ub_src_common.cpp b/src/duckdb/ub_src_common.cpp index 2632a1276..07cab6cd8 100644 --- a/src/duckdb/ub_src_common.cpp +++ b/src/duckdb/ub_src_common.cpp @@ -46,8 +46,6 @@ #include "src/common/error_data.cpp" -#include "src/common/opener_file_system.cpp" - #include "src/common/printer.cpp" #include "src/common/radix_partitioning.cpp" @@ -56,8 +54,6 @@ #include "src/common/random_engine.cpp" -#include "src/common/stacktrace.cpp" - #include "src/common/string_util.cpp" #include "src/common/enum_util.cpp" diff --git a/src/duckdb/ub_src_core_functions.cpp b/src/duckdb/ub_src_core_functions.cpp new file mode 100644 index 000000000..961929d47 --- /dev/null +++ b/src/duckdb/ub_src_core_functions.cpp @@ -0,0 +1,6 @@ +#include "src/core_functions/core_functions.cpp" + +#include "src/core_functions/function_list.cpp" + +#include "src/core_functions/lambda_functions.cpp" + diff --git a/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp b/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp new file mode 100644 index 000000000..5aee83e92 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_aggregate_algebraic.cpp @@ -0,0 +1,8 @@ +#include "src/core_functions/aggregate/algebraic/avg.cpp" + +#include "src/core_functions/aggregate/algebraic/covar.cpp" + +#include "src/core_functions/aggregate/algebraic/stddev.cpp" + +#include "src/core_functions/aggregate/algebraic/corr.cpp" + diff --git a/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp b/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp new file mode 100644 index 000000000..7deed6d3b --- /dev/null +++ b/src/duckdb/ub_src_core_functions_aggregate_distributive.cpp @@ -0,0 +1,24 @@ +#include "src/core_functions/aggregate/distributive/approx_count.cpp" + +#include "src/core_functions/aggregate/distributive/arg_min_max.cpp" + +#include "src/core_functions/aggregate/distributive/bitagg.cpp" + +#include "src/core_functions/aggregate/distributive/bitstring_agg.cpp" + +#include "src/core_functions/aggregate/distributive/bool.cpp" + +#include "src/core_functions/aggregate/distributive/entropy.cpp" + +#include "src/core_functions/aggregate/distributive/kurtosis.cpp" + +#include "src/core_functions/aggregate/distributive/minmax.cpp" + +#include "src/core_functions/aggregate/distributive/product.cpp" + +#include "src/core_functions/aggregate/distributive/skew.cpp" + +#include "src/core_functions/aggregate/distributive/string_agg.cpp" + +#include "src/core_functions/aggregate/distributive/sum.cpp" + diff --git a/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp b/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp new file mode 100644 index 000000000..67d8f8f08 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_aggregate_holistic.cpp @@ -0,0 +1,12 @@ +#include "src/core_functions/aggregate/holistic/approx_top_k.cpp" + +#include "src/core_functions/aggregate/holistic/quantile.cpp" + +#include "src/core_functions/aggregate/holistic/mad.cpp" + +#include "src/core_functions/aggregate/holistic/mode.cpp" + +#include "src/core_functions/aggregate/holistic/approximate_quantile.cpp" + +#include "src/core_functions/aggregate/holistic/reservoir_quantile.cpp" + diff --git a/src/duckdb/ub_src_core_functions_aggregate_nested.cpp b/src/duckdb/ub_src_core_functions_aggregate_nested.cpp new file mode 100644 index 000000000..ecd5e3be9 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_aggregate_nested.cpp @@ -0,0 +1,6 @@ +#include "src/core_functions/aggregate/nested/binned_histogram.cpp" + +#include "src/core_functions/aggregate/nested/list.cpp" + +#include "src/core_functions/aggregate/nested/histogram.cpp" + diff --git a/src/duckdb/ub_src_core_functions_aggregate_regression.cpp b/src/duckdb/ub_src_core_functions_aggregate_regression.cpp new file mode 100644 index 000000000..19053bcc0 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_aggregate_regression.cpp @@ -0,0 +1,14 @@ +#include "src/core_functions/aggregate/regression/regr_avg.cpp" + +#include "src/core_functions/aggregate/regression/regr_count.cpp" + +#include "src/core_functions/aggregate/regression/regr_slope.cpp" + +#include "src/core_functions/aggregate/regression/regr_r2.cpp" + +#include "src/core_functions/aggregate/regression/regr_sxx_syy.cpp" + +#include "src/core_functions/aggregate/regression/regr_sxy.cpp" + +#include "src/core_functions/aggregate/regression/regr_intercept.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_array.cpp b/src/duckdb/ub_src_core_functions_scalar_array.cpp new file mode 100644 index 000000000..49ed0ec37 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_array.cpp @@ -0,0 +1,4 @@ +#include "src/core_functions/scalar/array/array_value.cpp" + +#include "src/core_functions/scalar/array/array_functions.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_bit.cpp b/src/duckdb/ub_src_core_functions_scalar_bit.cpp new file mode 100644 index 000000000..c0db08283 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_bit.cpp @@ -0,0 +1,2 @@ +#include "src/core_functions/scalar/bit/bitstring.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_blob.cpp b/src/duckdb/ub_src_core_functions_scalar_blob.cpp new file mode 100644 index 000000000..d1ae2334d --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_blob.cpp @@ -0,0 +1,6 @@ +#include "src/core_functions/scalar/blob/base64.cpp" + +#include "src/core_functions/scalar/blob/create_sort_key.cpp" + +#include "src/core_functions/scalar/blob/encode.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_date.cpp b/src/duckdb/ub_src_core_functions_scalar_date.cpp new file mode 100644 index 000000000..49bb85bd7 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_date.cpp @@ -0,0 +1,22 @@ +#include "src/core_functions/scalar/date/age.cpp" + +#include "src/core_functions/scalar/date/current.cpp" + +#include "src/core_functions/scalar/date/epoch.cpp" + +#include "src/core_functions/scalar/date/date_diff.cpp" + +#include "src/core_functions/scalar/date/date_part.cpp" + +#include "src/core_functions/scalar/date/date_sub.cpp" + +#include "src/core_functions/scalar/date/date_trunc.cpp" + +#include "src/core_functions/scalar/date/make_date.cpp" + +#include "src/core_functions/scalar/date/strftime.cpp" + +#include "src/core_functions/scalar/date/time_bucket.cpp" + +#include "src/core_functions/scalar/date/to_interval.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_debug.cpp b/src/duckdb/ub_src_core_functions_scalar_debug.cpp new file mode 100644 index 000000000..7675ec524 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_debug.cpp @@ -0,0 +1,2 @@ +#include "src/core_functions/scalar/debug/vector_type.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_enum.cpp b/src/duckdb/ub_src_core_functions_scalar_enum.cpp new file mode 100644 index 000000000..e84741f5b --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_enum.cpp @@ -0,0 +1,2 @@ +#include "src/core_functions/scalar/enum/enum_functions.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_generic.cpp b/src/duckdb/ub_src_core_functions_scalar_generic.cpp new file mode 100644 index 000000000..7c80d7dbf --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_generic.cpp @@ -0,0 +1,18 @@ +#include "src/core_functions/scalar/generic/alias.cpp" + +#include "src/core_functions/scalar/generic/can_implicitly_cast.cpp" + +#include "src/core_functions/scalar/generic/current_setting.cpp" + +#include "src/core_functions/scalar/generic/error.cpp" + +#include "src/core_functions/scalar/generic/hash.cpp" + +#include "src/core_functions/scalar/generic/least.cpp" + +#include "src/core_functions/scalar/generic/stats.cpp" + +#include "src/core_functions/scalar/generic/typeof.cpp" + +#include "src/core_functions/scalar/generic/system_functions.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_list.cpp b/src/duckdb/ub_src_core_functions_scalar_list.cpp new file mode 100644 index 000000000..53a325891 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_list.cpp @@ -0,0 +1,22 @@ +#include "src/core_functions/scalar/list/array_slice.cpp" + +#include "src/core_functions/scalar/list/flatten.cpp" + +#include "src/core_functions/scalar/list/list_aggregates.cpp" + +#include "src/core_functions/scalar/list/list_filter.cpp" + +#include "src/core_functions/scalar/list/list_has_any_or_all.cpp" + +#include "src/core_functions/scalar/list/list_sort.cpp" + +#include "src/core_functions/scalar/list/list_distance.cpp" + +#include "src/core_functions/scalar/list/list_reduce.cpp" + +#include "src/core_functions/scalar/list/list_transform.cpp" + +#include "src/core_functions/scalar/list/list_value.cpp" + +#include "src/core_functions/scalar/list/range.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_map.cpp b/src/duckdb/ub_src_core_functions_scalar_map.cpp new file mode 100644 index 000000000..e86907159 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_map.cpp @@ -0,0 +1,16 @@ +#include "src/core_functions/scalar/map/map.cpp" + +#include "src/core_functions/scalar/map/map_extract.cpp" + +#include "src/core_functions/scalar/map/map_from_entries.cpp" + +#include "src/core_functions/scalar/map/map_entries.cpp" + +#include "src/core_functions/scalar/map/map_concat.cpp" + +#include "src/core_functions/scalar/map/map_contains.cpp" + +#include "src/core_functions/scalar/map/map_keys_values.cpp" + +#include "src/core_functions/scalar/map/cardinality.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_math.cpp b/src/duckdb/ub_src_core_functions_scalar_math.cpp new file mode 100644 index 000000000..d8fcaa8e0 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_math.cpp @@ -0,0 +1,2 @@ +#include "src/core_functions/scalar/math/numeric.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_operators.cpp b/src/duckdb/ub_src_core_functions_scalar_operators.cpp new file mode 100644 index 000000000..edb917bc3 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_operators.cpp @@ -0,0 +1,2 @@ +#include "src/core_functions/scalar/operators/bitwise.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_random.cpp b/src/duckdb/ub_src_core_functions_scalar_random.cpp new file mode 100644 index 000000000..44b6ee631 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_random.cpp @@ -0,0 +1,4 @@ +#include "src/core_functions/scalar/random/random.cpp" + +#include "src/core_functions/scalar/random/setseed.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_string.cpp b/src/duckdb/ub_src_core_functions_scalar_string.cpp new file mode 100644 index 000000000..507f1e60d --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_string.cpp @@ -0,0 +1,58 @@ +#include "src/core_functions/scalar/string/ascii.cpp" + +#include "src/core_functions/scalar/string/bar.cpp" + +#include "src/core_functions/scalar/string/chr.cpp" + +#include "src/core_functions/scalar/string/damerau_levenshtein.cpp" + +#include "src/core_functions/scalar/string/format_bytes.cpp" + +#include "src/core_functions/scalar/string/hamming.cpp" + +#include "src/core_functions/scalar/string/hex.cpp" + +#include "src/core_functions/scalar/string/instr.cpp" + +#include "src/core_functions/scalar/string/jaccard.cpp" + +#include "src/core_functions/scalar/string/jaro_winkler.cpp" + +#include "src/core_functions/scalar/string/left_right.cpp" + +#include "src/core_functions/scalar/string/levenshtein.cpp" + +#include "src/core_functions/scalar/string/md5.cpp" + +#include "src/core_functions/scalar/string/pad.cpp" + +#include "src/core_functions/scalar/string/parse_path.cpp" + +#include "src/core_functions/scalar/string/printf.cpp" + +#include "src/core_functions/scalar/string/regexp_escape.cpp" + +#include "src/core_functions/scalar/string/repeat.cpp" + +#include "src/core_functions/scalar/string/replace.cpp" + +#include "src/core_functions/scalar/string/reverse.cpp" + +#include "src/core_functions/scalar/string/sha1.cpp" + +#include "src/core_functions/scalar/string/sha256.cpp" + +#include "src/core_functions/scalar/string/starts_with.cpp" + +#include "src/core_functions/scalar/string/string_split.cpp" + +#include "src/core_functions/scalar/string/to_base.cpp" + +#include "src/core_functions/scalar/string/translate.cpp" + +#include "src/core_functions/scalar/string/trim.cpp" + +#include "src/core_functions/scalar/string/unicode.cpp" + +#include "src/core_functions/scalar/string/url_encode.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_struct.cpp b/src/duckdb/ub_src_core_functions_scalar_struct.cpp new file mode 100644 index 000000000..a58c0d382 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_struct.cpp @@ -0,0 +1,4 @@ +#include "src/core_functions/scalar/struct/struct_pack.cpp" + +#include "src/core_functions/scalar/struct/struct_insert.cpp" + diff --git a/src/duckdb/ub_src_core_functions_scalar_union.cpp b/src/duckdb/ub_src_core_functions_scalar_union.cpp new file mode 100644 index 000000000..41adab652 --- /dev/null +++ b/src/duckdb/ub_src_core_functions_scalar_union.cpp @@ -0,0 +1,6 @@ +#include "src/core_functions/scalar/union/union_extract.cpp" + +#include "src/core_functions/scalar/union/union_tag.cpp" + +#include "src/core_functions/scalar/union/union_value.cpp" + diff --git a/src/duckdb/ub_src_execution.cpp b/src/duckdb/ub_src_execution.cpp index 1acd5651c..d845738bc 100644 --- a/src/duckdb/ub_src_execution.cpp +++ b/src/duckdb/ub_src_execution.cpp @@ -20,3 +20,9 @@ #include "src/execution/radix_partitioned_hashtable.cpp" +#include "src/execution/reservoir_sample.cpp" + +#include "src/execution/window_executor.cpp" + +#include "src/execution/window_segment_tree.cpp" + diff --git a/src/duckdb/ub_src_execution_operator_aggregate.cpp b/src/duckdb/ub_src_execution_operator_aggregate.cpp index f8555ee93..d7ee3d50a 100644 --- a/src/duckdb/ub_src_execution_operator_aggregate.cpp +++ b/src/duckdb/ub_src_execution_operator_aggregate.cpp @@ -6,8 +6,6 @@ #include "src/execution/operator/aggregate/grouped_aggregate_data.cpp" -#include "src/execution/operator/aggregate/physical_partitioned_aggregate.cpp" - #include "src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp" #include "src/execution/operator/aggregate/physical_ungrouped_aggregate.cpp" diff --git a/src/duckdb/ub_src_execution_operator_csv_scanner_encode.cpp b/src/duckdb/ub_src_execution_operator_csv_scanner_encode.cpp deleted file mode 100644 index f1db7c41a..000000000 --- a/src/duckdb/ub_src_execution_operator_csv_scanner_encode.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/execution/operator/csv_scanner/encode/csv_encoder.cpp" - diff --git a/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp b/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp index 5fd16fb67..7deec5a78 100644 --- a/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp +++ b/src/duckdb/ub_src_execution_operator_csv_scanner_util.cpp @@ -2,5 +2,3 @@ #include "src/execution/operator/csv_scanner/util/csv_reader_options.cpp" -#include "src/execution/operator/csv_scanner/util/csv_validator.cpp" - diff --git a/src/duckdb/ub_src_execution_sample.cpp b/src/duckdb/ub_src_execution_sample.cpp deleted file mode 100644 index 32d9b85ce..000000000 --- a/src/duckdb/ub_src_execution_sample.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "src/execution/sample/base_reservoir_sample.cpp" - -#include "src/execution/sample/reservoir_sample.cpp" - diff --git a/src/duckdb/ub_src_function.cpp b/src/duckdb/ub_src_function.cpp index 06938e55b..586fb8faa 100644 --- a/src/duckdb/ub_src_function.cpp +++ b/src/duckdb/ub_src_function.cpp @@ -8,22 +8,16 @@ #include "src/function/copy_function.cpp" -#include "src/function/encoding_function.cpp" - #include "src/function/function.cpp" #include "src/function/function_binder.cpp" -#include "src/function/function_list.cpp" - #include "src/function/function_set.cpp" #include "src/function/pragma_function.cpp" #include "src/function/macro_function.cpp" -#include "src/function/register_function_list.cpp" - #include "src/function/scalar_macro_function.cpp" #include "src/function/table_macro_function.cpp" diff --git a/src/duckdb/ub_src_function_aggregate.cpp b/src/duckdb/ub_src_function_aggregate.cpp index 6bfe0ba85..389a81ce9 100644 --- a/src/duckdb/ub_src_function_aggregate.cpp +++ b/src/duckdb/ub_src_function_aggregate.cpp @@ -1,2 +1,4 @@ +#include "src/function/aggregate/distributive_functions.cpp" + #include "src/function/aggregate/sorted_aggregate_function.cpp" diff --git a/src/duckdb/ub_src_function_aggregate_distributive.cpp b/src/duckdb/ub_src_function_aggregate_distributive.cpp index 92bcd6c50..005304196 100644 --- a/src/duckdb/ub_src_function_aggregate_distributive.cpp +++ b/src/duckdb/ub_src_function_aggregate_distributive.cpp @@ -1,6 +1,4 @@ #include "src/function/aggregate/distributive/count.cpp" -#include "src/function/aggregate/distributive/first_last_any.cpp" - -#include "src/function/aggregate/distributive/minmax.cpp" +#include "src/function/aggregate/distributive/first.cpp" diff --git a/src/duckdb/ub_src_function_scalar.cpp b/src/duckdb/ub_src_function_scalar.cpp index a0da28dc6..cb65cab27 100644 --- a/src/duckdb/ub_src_function_scalar.cpp +++ b/src/duckdb/ub_src_function_scalar.cpp @@ -1,10 +1,16 @@ -#include "src/function/scalar/compressed_materialization_utils.cpp" +#include "src/function/scalar/compressed_materialization_functions.cpp" -#include "src/function/scalar/create_sort_key.cpp" +#include "src/function/scalar/generic_functions.cpp" + +#include "src/function/scalar/string_functions.cpp" #include "src/function/scalar/strftime_format.cpp" #include "src/function/scalar/nested_functions.cpp" +#include "src/function/scalar/operators.cpp" + #include "src/function/scalar/pragma_functions.cpp" +#include "src/function/scalar/sequence_functions.cpp" + diff --git a/src/duckdb/ub_src_function_scalar_date.cpp b/src/duckdb/ub_src_function_scalar_date.cpp deleted file mode 100644 index 81e2c26c1..000000000 --- a/src/duckdb/ub_src_function_scalar_date.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/function/scalar/date/strftime.cpp" - diff --git a/src/duckdb/ub_src_function_scalar_generic.cpp b/src/duckdb/ub_src_function_scalar_generic.cpp index 926f394d3..842724aff 100644 --- a/src/duckdb/ub_src_function_scalar_generic.cpp +++ b/src/duckdb/ub_src_function_scalar_generic.cpp @@ -1,6 +1,6 @@ -#include "src/function/scalar/generic/constant_or_null.cpp" +#include "src/function/scalar/generic/binning.cpp" -#include "src/function/scalar/generic/error.cpp" +#include "src/function/scalar/generic/constant_or_null.cpp" #include "src/function/scalar/generic/getvariable.cpp" diff --git a/src/duckdb/ub_src_function_scalar_map.cpp b/src/duckdb/ub_src_function_scalar_map.cpp deleted file mode 100644 index 0978d7e0e..000000000 --- a/src/duckdb/ub_src_function_scalar_map.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "src/function/scalar/map/map_contains.cpp" - diff --git a/src/duckdb/ub_src_function_scalar_operator.cpp b/src/duckdb/ub_src_function_scalar_operator.cpp deleted file mode 100644 index f31f65916..000000000 --- a/src/duckdb/ub_src_function_scalar_operator.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "src/function/scalar/operator/add.cpp" - -#include "src/function/scalar/operator/arithmetic.cpp" - -#include "src/function/scalar/operator/multiply.cpp" - -#include "src/function/scalar/operator/subtract.cpp" - diff --git a/src/duckdb/ub_src_function_scalar_operators.cpp b/src/duckdb/ub_src_function_scalar_operators.cpp new file mode 100644 index 000000000..8bd5e0bf9 --- /dev/null +++ b/src/duckdb/ub_src_function_scalar_operators.cpp @@ -0,0 +1,8 @@ +#include "src/function/scalar/operators/add.cpp" + +#include "src/function/scalar/operators/arithmetic.cpp" + +#include "src/function/scalar/operators/multiply.cpp" + +#include "src/function/scalar/operators/subtract.cpp" + diff --git a/src/duckdb/ub_src_function_scalar_string.cpp b/src/duckdb/ub_src_function_scalar_string.cpp index c39a28ea1..9e62653c9 100644 --- a/src/duckdb/ub_src_function_scalar_string.cpp +++ b/src/duckdb/ub_src_function_scalar_string.cpp @@ -8,8 +8,6 @@ #include "src/function/scalar/string/like.cpp" -#include "src/function/scalar/string/md5.cpp" - #include "src/function/scalar/string/nfc_normalize.cpp" #include "src/function/scalar/string/regexp.cpp" @@ -18,16 +16,8 @@ #include "src/function/scalar/string/prefix.cpp" -#include "src/function/scalar/string/regexp_escape.cpp" - -#include "src/function/scalar/string/sha1.cpp" - -#include "src/function/scalar/string/sha256.cpp" - #include "src/function/scalar/string/strip_accents.cpp" -#include "src/function/scalar/string/string_split.cpp" - #include "src/function/scalar/string/suffix.cpp" #include "src/function/scalar/string/contains.cpp" diff --git a/src/duckdb/ub_src_function_scalar_struct.cpp b/src/duckdb/ub_src_function_scalar_struct.cpp index 67f447661..2d3888e7e 100644 --- a/src/duckdb/ub_src_function_scalar_struct.cpp +++ b/src/duckdb/ub_src_function_scalar_struct.cpp @@ -1,6 +1,2 @@ #include "src/function/scalar/struct/struct_extract.cpp" -#include "src/function/scalar/struct/struct_pack.cpp" - -#include "src/function/scalar/struct/struct_concat.cpp" - diff --git a/src/duckdb/ub_src_function_table_system.cpp b/src/duckdb/ub_src_function_table_system.cpp index 4ab6fdaf7..a534b2bf5 100644 --- a/src/duckdb/ub_src_function_table_system.cpp +++ b/src/duckdb/ub_src_function_table_system.cpp @@ -48,8 +48,6 @@ #include "src/function/table/system/pragma_table_info.cpp" -#include "src/function/table/system/pragma_table_sample.cpp" - #include "src/function/table/system/pragma_user_agent.cpp" #include "src/function/table/system/test_all_types.cpp" diff --git a/src/duckdb/ub_src_function_window.cpp b/src/duckdb/ub_src_function_window.cpp deleted file mode 100644 index fbd3fc960..000000000 --- a/src/duckdb/ub_src_function_window.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "src/function/window/window_aggregate_function.cpp" - -#include "src/function/window/window_aggregate_states.cpp" - -#include "src/function/window/window_aggregator.cpp" - -#include "src/function/window/window_boundaries_state.cpp" - -#include "src/function/window/window_collection.cpp" - -#include "src/function/window/window_constant_aggregator.cpp" - -#include "src/function/window/window_custom_aggregator.cpp" - -#include "src/function/window/window_distinct_aggregator.cpp" - -#include "src/function/window/window_executor.cpp" - -#include "src/function/window/window_index_tree.cpp" - -#include "src/function/window/window_merge_sort_tree.cpp" - -#include "src/function/window/window_naive_aggregator.cpp" - -#include "src/function/window/window_rank_function.cpp" - -#include "src/function/window/window_rownumber_function.cpp" - -#include "src/function/window/window_segment_tree.cpp" - -#include "src/function/window/window_shared_expressions.cpp" - -#include "src/function/window/window_token_tree.cpp" - -#include "src/function/window/window_value_function.cpp" - diff --git a/src/duckdb/ub_src_main_settings.cpp b/src/duckdb/ub_src_main_settings.cpp index 6dbcd419e..77cb91e4c 100644 --- a/src/duckdb/ub_src_main_settings.cpp +++ b/src/duckdb/ub_src_main_settings.cpp @@ -1,4 +1,2 @@ -#include "src/main/settings/custom_settings.cpp" - -#include "src/main/settings/autogenerated_settings.cpp" +#include "src/main/settings/settings.cpp" diff --git a/src/duckdb/ub_src_optimizer.cpp b/src/duckdb/ub_src_optimizer.cpp index 26f4abe53..5ef91f3d9 100644 --- a/src/duckdb/ub_src_optimizer.cpp +++ b/src/duckdb/ub_src_optimizer.cpp @@ -4,8 +4,6 @@ #include "src/optimizer/column_lifetime_analyzer.cpp" -#include "src/optimizer/empty_result_pullup.cpp" - #include "src/optimizer/common_aggregate_optimizer.cpp" #include "src/optimizer/compressed_materialization.cpp" @@ -46,7 +44,3 @@ #include "src/optimizer/unnest_rewriter.cpp" -#include "src/optimizer/sampling_pushdown.cpp" - -#include "src/optimizer/sum_rewriter.cpp" - diff --git a/src/duckdb/ub_src_optimizer_pushdown.cpp b/src/duckdb/ub_src_optimizer_pushdown.cpp index 26f3d9c43..a96fc9d8a 100644 --- a/src/duckdb/ub_src_optimizer_pushdown.cpp +++ b/src/duckdb/ub_src_optimizer_pushdown.cpp @@ -26,5 +26,3 @@ #include "src/optimizer/pushdown/pushdown_window.cpp" -#include "src/optimizer/pushdown/pushdown_unnest.cpp" - diff --git a/src/duckdb/ub_src_optimizer_rule.cpp b/src/duckdb/ub_src_optimizer_rule.cpp index ee39a8864..882887e64 100644 --- a/src/duckdb/ub_src_optimizer_rule.cpp +++ b/src/duckdb/ub_src_optimizer_rule.cpp @@ -10,8 +10,6 @@ #include "src/optimizer/rule/date_part_simplification.cpp" -#include "src/optimizer/rule/distinct_aggregate_optimizer.cpp" - #include "src/optimizer/rule/distributivity.cpp" #include "src/optimizer/rule/empty_needle_removal.cpp" diff --git a/src/duckdb/ub_src_parser.cpp b/src/duckdb/ub_src_parser.cpp index 39c2c8368..efcbb8251 100644 --- a/src/duckdb/ub_src_parser.cpp +++ b/src/duckdb/ub_src_parser.cpp @@ -16,8 +16,6 @@ #include "src/parser/parser.cpp" -#include "src/parser/qualified_name.cpp" - #include "src/parser/query_error_context.cpp" #include "src/parser/query_node.cpp" diff --git a/src/duckdb/ub_src_parser_parsed_data.cpp b/src/duckdb/ub_src_parser_parsed_data.cpp index b5bc65914..bf80fff4b 100644 --- a/src/duckdb/ub_src_parser_parsed_data.cpp +++ b/src/duckdb/ub_src_parser_parsed_data.cpp @@ -14,8 +14,6 @@ #include "src/parser/parsed_data/create_info.cpp" -#include "src/parser/parsed_data/create_function_info.cpp" - #include "src/parser/parsed_data/create_index_info.cpp" #include "src/parser/parsed_data/create_aggregate_function_info.cpp" diff --git a/src/duckdb/ub_src_planner.cpp b/src/duckdb/ub_src_planner.cpp index 450ea623c..a02a37422 100644 --- a/src/duckdb/ub_src_planner.cpp +++ b/src/duckdb/ub_src_planner.cpp @@ -1,5 +1,3 @@ -#include "src/planner/binding_alias.cpp" - #include "src/planner/bound_result_modifier.cpp" #include "src/planner/bound_parameter_map.cpp" diff --git a/src/duckdb/ub_src_planner_filter.cpp b/src/duckdb/ub_src_planner_filter.cpp index a7f44ee8b..057a07714 100644 --- a/src/duckdb/ub_src_planner_filter.cpp +++ b/src/duckdb/ub_src_planner_filter.cpp @@ -2,13 +2,7 @@ #include "src/planner/filter/constant_filter.cpp" -#include "src/planner/filter/dynamic_filter.cpp" - -#include "src/planner/filter/in_filter.cpp" - #include "src/planner/filter/null_filter.cpp" #include "src/planner/filter/struct_filter.cpp" -#include "src/planner/filter/optional_filter.cpp" - diff --git a/src/duckdb/ub_src_storage_compression.cpp b/src/duckdb/ub_src_storage_compression.cpp index 491801cd7..ded26082e 100644 --- a/src/duckdb/ub_src_storage_compression.cpp +++ b/src/duckdb/ub_src_storage_compression.cpp @@ -18,11 +18,7 @@ #include "src/storage/compression/patas.cpp" -#include "src/storage/compression/zstd.cpp" - #include "src/storage/compression/alprd.cpp" #include "src/storage/compression/fsst.cpp" -#include "src/storage/compression/empty_validity.cpp" - diff --git a/src/duckdb/ub_src_storage_compression_dictionary.cpp b/src/duckdb/ub_src_storage_compression_dictionary.cpp deleted file mode 100644 index abfb3b323..000000000 --- a/src/duckdb/ub_src_storage_compression_dictionary.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "src/storage/compression/dictionary/common.cpp" - -#include "src/storage/compression/dictionary/analyze.cpp" - -#include "src/storage/compression/dictionary/compression.cpp" - -#include "src/storage/compression/dictionary/decompression.cpp" - diff --git a/src/duckdb/ub_src_storage_compression_roaring.cpp b/src/duckdb/ub_src_storage_compression_roaring.cpp deleted file mode 100644 index cef83799e..000000000 --- a/src/duckdb/ub_src_storage_compression_roaring.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "src/storage/compression/roaring/common.cpp" - -#include "src/storage/compression/roaring/metadata.cpp" - -#include "src/storage/compression/roaring/analyze.cpp" - -#include "src/storage/compression/roaring/compress.cpp" - -#include "src/storage/compression/roaring/scan.cpp" - diff --git a/src/duckdb/ub_src_transaction.cpp b/src/duckdb/ub_src_transaction.cpp index c2b15db55..f1f433751 100644 --- a/src/duckdb/ub_src_transaction.cpp +++ b/src/duckdb/ub_src_transaction.cpp @@ -4,8 +4,6 @@ #include "src/transaction/meta_transaction.cpp" -#include "src/transaction/undo_buffer_allocator.cpp" - #include "src/transaction/undo_buffer.cpp" #include "src/transaction/transaction_context.cpp" diff --git a/src/include/sources.mk b/src/include/sources.mk index 083c0195e..47a534969 100644 --- a/src/include/sources.mk +++ b/src/include/sources.mk @@ -1 +1 @@ -SOURCES=duckdb/ub_src_catalog.o duckdb/ub_src_catalog_catalog_entry.o duckdb/ub_src_catalog_catalog_entry_dependency.o duckdb/ub_src_catalog_default.o duckdb/ub_src_common_adbc.o duckdb/ub_src_common_adbc_nanoarrow.o duckdb/ub_src_common.o duckdb/ub_src_common_arrow_appender.o duckdb/ub_src_common_arrow.o duckdb/ub_src_common_crypto.o duckdb/ub_src_common_enums.o duckdb/ub_src_common_exception.o duckdb/ub_src_common_operator.o duckdb/ub_src_common_progress_bar.o duckdb/ub_src_common_row_operations.o duckdb/ub_src_common_serializer.o duckdb/ub_src_common_sort.o duckdb/ub_src_common_tree_renderer.o duckdb/ub_src_common_types.o duckdb/ub_src_common_types_column.o duckdb/ub_src_common_types_row.o duckdb/ub_src_common_value_operations.o duckdb/src/common/vector_operations/boolean_operators.o duckdb/src/common/vector_operations/comparison_operators.o duckdb/src/common/vector_operations/generators.o duckdb/src/common/vector_operations/is_distinct_from.o duckdb/src/common/vector_operations/null_operations.o duckdb/src/common/vector_operations/numeric_inplace_operators.o duckdb/src/common/vector_operations/vector_cast.o duckdb/src/common/vector_operations/vector_copy.o duckdb/src/common/vector_operations/vector_hash.o duckdb/src/common/vector_operations/vector_storage.o duckdb/ub_src_execution.o duckdb/ub_src_execution_expression_executor.o duckdb/ub_src_execution_index_art.o duckdb/ub_src_execution_index.o duckdb/ub_src_execution_nested_loop_join.o duckdb/ub_src_execution_operator_aggregate.o duckdb/ub_src_execution_operator_csv_scanner_buffer_manager.o duckdb/ub_src_execution_operator_csv_scanner_encode.o duckdb/ub_src_execution_operator_csv_scanner_scanner.o duckdb/ub_src_execution_operator_csv_scanner_sniffer.o duckdb/ub_src_execution_operator_csv_scanner_state_machine.o duckdb/ub_src_execution_operator_csv_scanner_table_function.o duckdb/ub_src_execution_operator_csv_scanner_util.o duckdb/ub_src_execution_operator_filter.o duckdb/ub_src_execution_operator_helper.o duckdb/ub_src_execution_operator_join.o duckdb/ub_src_execution_operator_order.o duckdb/ub_src_execution_operator_persistent.o duckdb/ub_src_execution_operator_projection.o duckdb/ub_src_execution_operator_scan.o duckdb/ub_src_execution_operator_schema.o duckdb/ub_src_execution_operator_set.o duckdb/ub_src_execution_physical_plan.o duckdb/ub_src_execution_sample.o duckdb/ub_src_function_aggregate_distributive.o duckdb/ub_src_function_aggregate.o duckdb/ub_src_function.o duckdb/ub_src_function_cast.o duckdb/ub_src_function_cast_union.o duckdb/ub_src_function_pragma.o duckdb/ub_src_function_scalar_compressed_materialization.o duckdb/ub_src_function_scalar.o duckdb/ub_src_function_scalar_date.o duckdb/ub_src_function_scalar_generic.o duckdb/ub_src_function_scalar_list.o duckdb/ub_src_function_scalar_map.o duckdb/ub_src_function_scalar_operator.o duckdb/ub_src_function_scalar_sequence.o duckdb/ub_src_function_scalar_string.o duckdb/ub_src_function_scalar_string_regexp.o duckdb/ub_src_function_scalar_struct.o duckdb/ub_src_function_scalar_system.o duckdb/ub_src_function_table_arrow.o duckdb/ub_src_function_table.o duckdb/ub_src_function_table_system.o duckdb/ub_src_function_table_version.o duckdb/ub_src_function_window.o duckdb/ub_src_main.o duckdb/ub_src_main_buffered_data.o duckdb/ub_src_main_capi.o duckdb/ub_src_main_capi_cast.o duckdb/ub_src_main_chunk_scan_state.o duckdb/ub_src_main_extension.o duckdb/ub_src_main_relation.o duckdb/ub_src_main_secret.o duckdb/ub_src_main_settings.o duckdb/ub_src_optimizer.o duckdb/ub_src_optimizer_compressed_materialization.o duckdb/ub_src_optimizer_join_order.o duckdb/ub_src_optimizer_matcher.o duckdb/ub_src_optimizer_pullup.o duckdb/ub_src_optimizer_pushdown.o duckdb/ub_src_optimizer_rule.o duckdb/ub_src_optimizer_statistics_expression.o duckdb/ub_src_optimizer_statistics_operator.o duckdb/ub_src_parallel.o duckdb/ub_src_parser.o duckdb/ub_src_parser_constraints.o duckdb/ub_src_parser_expression.o duckdb/ub_src_parser_parsed_data.o duckdb/ub_src_parser_query_node.o duckdb/ub_src_parser_statement.o duckdb/ub_src_parser_tableref.o duckdb/ub_src_parser_transform_constraint.o duckdb/ub_src_parser_transform_expression.o duckdb/ub_src_parser_transform_helpers.o duckdb/ub_src_parser_transform_statement.o duckdb/ub_src_parser_transform_tableref.o duckdb/ub_src_planner.o duckdb/ub_src_planner_binder_expression.o duckdb/ub_src_planner_binder_query_node.o duckdb/ub_src_planner_binder_statement.o duckdb/ub_src_planner_binder_tableref.o duckdb/ub_src_planner_expression.o duckdb/ub_src_planner_expression_binder.o duckdb/ub_src_planner_filter.o duckdb/ub_src_planner_operator.o duckdb/ub_src_planner_subquery.o duckdb/ub_src_storage.o duckdb/ub_src_storage_buffer.o duckdb/ub_src_storage_checkpoint.o duckdb/ub_src_storage_compression_alp.o duckdb/ub_src_storage_compression.o duckdb/ub_src_storage_compression_chimp.o duckdb/ub_src_storage_compression_dictionary.o duckdb/ub_src_storage_compression_roaring.o duckdb/ub_src_storage_metadata.o duckdb/ub_src_storage_serialization.o duckdb/ub_src_storage_statistics.o duckdb/ub_src_storage_table.o duckdb/ub_src_transaction.o duckdb/src/verification/copied_statement_verifier.o duckdb/src/verification/deserialized_statement_verifier.o duckdb/src/verification/external_statement_verifier.o duckdb/src/verification/fetch_row_verifier.o duckdb/src/verification/no_operator_caching_verifier.o duckdb/src/verification/parsed_statement_verifier.o duckdb/src/verification/prepared_statement_verifier.o duckdb/src/verification/statement_verifier.o duckdb/src/verification/unoptimized_statement_verifier.o duckdb/third_party/fmt/format.o duckdb/third_party/fsst/libfsst.o duckdb/third_party/miniz/miniz.o duckdb/third_party/re2/re2/bitmap256.o duckdb/third_party/re2/re2/bitstate.o duckdb/third_party/re2/re2/compile.o duckdb/third_party/re2/re2/dfa.o duckdb/third_party/re2/re2/filtered_re2.o duckdb/third_party/re2/re2/mimics_pcre.o duckdb/third_party/re2/re2/nfa.o duckdb/third_party/re2/re2/onepass.o duckdb/third_party/re2/re2/parse.o duckdb/third_party/re2/re2/perl_groups.o duckdb/third_party/re2/re2/prefilter.o duckdb/third_party/re2/re2/prefilter_tree.o duckdb/third_party/re2/re2/prog.o duckdb/third_party/re2/re2/re2.o duckdb/third_party/re2/re2/regexp.o duckdb/third_party/re2/re2/set.o duckdb/third_party/re2/re2/simplify.o duckdb/third_party/re2/re2/stringpiece.o duckdb/third_party/re2/re2/tostring.o duckdb/third_party/re2/re2/unicode_casefold.o duckdb/third_party/re2/re2/unicode_groups.o duckdb/third_party/re2/util/rune.o duckdb/third_party/re2/util/strutil.o duckdb/third_party/hyperloglog/hyperloglog.o duckdb/third_party/hyperloglog/sds.o duckdb/third_party/skiplist/SkipList.o duckdb/third_party/fastpforlib/bitpacking.o duckdb/third_party/utf8proc/utf8proc.o duckdb/third_party/utf8proc/utf8proc_wrapper.o duckdb/third_party/libpg_query/pg_functions.o duckdb/third_party/libpg_query/postgres_parser.o duckdb/third_party/libpg_query/src_backend_nodes_list.o duckdb/third_party/libpg_query/src_backend_nodes_makefuncs.o duckdb/third_party/libpg_query/src_backend_nodes_value.o duckdb/third_party/libpg_query/src_backend_parser_gram.o duckdb/third_party/libpg_query/src_backend_parser_parser.o duckdb/third_party/libpg_query/src_backend_parser_scan.o duckdb/third_party/libpg_query/src_backend_parser_scansup.o duckdb/third_party/libpg_query/src_common_keywords.o duckdb/third_party/mbedtls/library/aes.o duckdb/third_party/mbedtls/library/aria.o duckdb/third_party/mbedtls/library/asn1parse.o duckdb/third_party/mbedtls/library/base64.o duckdb/third_party/mbedtls/library/bignum.o duckdb/third_party/mbedtls/library/camellia.o duckdb/third_party/mbedtls/library/cipher.o duckdb/third_party/mbedtls/library/cipher_wrap.o duckdb/third_party/mbedtls/library/constant_time.o duckdb/third_party/mbedtls/library/entropy.o duckdb/third_party/mbedtls/library/entropy_poll.o duckdb/third_party/mbedtls/library/gcm.o duckdb/third_party/mbedtls/library/md.o duckdb/third_party/mbedtls/library/oid.o duckdb/third_party/mbedtls/library/pem.o duckdb/third_party/mbedtls/library/pk.o duckdb/third_party/mbedtls/library/pk_wrap.o duckdb/third_party/mbedtls/library/pkparse.o duckdb/third_party/mbedtls/library/platform_util.o duckdb/third_party/mbedtls/library/rsa.o duckdb/third_party/mbedtls/library/rsa_alt_helpers.o duckdb/third_party/mbedtls/library/sha1.o duckdb/third_party/mbedtls/library/sha256.o duckdb/third_party/mbedtls/library/sha512.o duckdb/third_party/mbedtls/mbedtls_wrapper.o duckdb/third_party/yyjson/yyjson.o duckdb/third_party/zstd/common/debug.o duckdb/third_party/zstd/common/entropy_common.o duckdb/third_party/zstd/common/error_private.o duckdb/third_party/zstd/common/fse_decompress.o duckdb/third_party/zstd/common/pool.o duckdb/third_party/zstd/common/threading.o duckdb/third_party/zstd/common/xxhash.o duckdb/third_party/zstd/common/zstd_common.o duckdb/third_party/zstd/compress/fse_compress.o duckdb/third_party/zstd/compress/hist.o duckdb/third_party/zstd/compress/huf_compress.o duckdb/third_party/zstd/compress/zstd_compress.o duckdb/third_party/zstd/compress/zstd_compress_literals.o duckdb/third_party/zstd/compress/zstd_compress_sequences.o duckdb/third_party/zstd/compress/zstd_compress_superblock.o duckdb/third_party/zstd/compress/zstd_double_fast.o duckdb/third_party/zstd/compress/zstd_fast.o duckdb/third_party/zstd/compress/zstd_lazy.o duckdb/third_party/zstd/compress/zstd_ldm.o duckdb/third_party/zstd/compress/zstd_opt.o duckdb/third_party/zstd/compress/zstdmt_compress.o duckdb/third_party/zstd/decompress/huf_decompress.o duckdb/third_party/zstd/decompress/zstd_ddict.o duckdb/third_party/zstd/decompress/zstd_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress_block.o duckdb/third_party/zstd/deprecated/zbuff_common.o duckdb/third_party/zstd/deprecated/zbuff_compress.o duckdb/third_party/zstd/deprecated/zbuff_decompress.o duckdb/third_party/zstd/dict/cover.o duckdb/third_party/zstd/dict/divsufsort.o duckdb/third_party/zstd/dict/fastcover.o duckdb/third_party/zstd/dict/zdict.o duckdb/extension/parquet/column_reader.o duckdb/extension/parquet/column_writer.o duckdb/extension/parquet/parquet_crypto.o duckdb/extension/parquet/parquet_extension.o duckdb/extension/parquet/parquet_metadata.o duckdb/extension/parquet/parquet_reader.o duckdb/extension/parquet/parquet_statistics.o duckdb/extension/parquet/parquet_timestamp.o duckdb/extension/parquet/parquet_writer.o duckdb/extension/parquet/serialize_parquet.o duckdb/extension/parquet/zstd_file_system.o duckdb/extension/parquet/geo_parquet.o duckdb/third_party/parquet/parquet_types.o duckdb/third_party/thrift/thrift/protocol/TProtocol.o duckdb/third_party/thrift/thrift/transport/TTransportException.o duckdb/third_party/thrift/thrift/transport/TBufferTransports.o duckdb/third_party/snappy/snappy.o duckdb/third_party/snappy/snappy-sinksource.o duckdb/third_party/lz4/lz4.o duckdb/third_party/brotli/common/constants.o duckdb/third_party/brotli/common/context.o duckdb/third_party/brotli/common/dictionary.o duckdb/third_party/brotli/common/platform.o duckdb/third_party/brotli/common/shared_dictionary.o duckdb/third_party/brotli/common/transform.o duckdb/third_party/brotli/dec/bit_reader.o duckdb/third_party/brotli/dec/decode.o duckdb/third_party/brotli/dec/huffman.o duckdb/third_party/brotli/dec/state.o duckdb/third_party/brotli/enc/backward_references.o duckdb/third_party/brotli/enc/backward_references_hq.o duckdb/third_party/brotli/enc/bit_cost.o duckdb/third_party/brotli/enc/block_splitter.o duckdb/third_party/brotli/enc/brotli_bit_stream.o duckdb/third_party/brotli/enc/cluster.o duckdb/third_party/brotli/enc/command.o duckdb/third_party/brotli/enc/compound_dictionary.o duckdb/third_party/brotli/enc/compress_fragment.o duckdb/third_party/brotli/enc/compress_fragment_two_pass.o duckdb/third_party/brotli/enc/dictionary_hash.o duckdb/third_party/brotli/enc/encode.o duckdb/third_party/brotli/enc/encoder_dict.o duckdb/third_party/brotli/enc/entropy_encode.o duckdb/third_party/brotli/enc/fast_log.o duckdb/third_party/brotli/enc/histogram.o duckdb/third_party/brotli/enc/literal_cost.o duckdb/third_party/brotli/enc/memory.o duckdb/third_party/brotli/enc/metablock.o duckdb/third_party/brotli/enc/static_dict.o duckdb/third_party/brotli/enc/utf8_util.o duckdb/extension/core_functions/core_functions_extension.o duckdb/extension/core_functions/lambda_functions.o duckdb/extension/core_functions/function_list.o duckdb/ub_extension_core_functions_aggregate_regression.o duckdb/ub_extension_core_functions_aggregate_algebraic.o duckdb/ub_extension_core_functions_aggregate_nested.o duckdb/ub_extension_core_functions_aggregate_holistic.o duckdb/ub_extension_core_functions_aggregate_distributive.o duckdb/ub_extension_core_functions_scalar_random.o duckdb/ub_extension_core_functions_scalar_string.o duckdb/ub_extension_core_functions_scalar_math.o duckdb/ub_extension_core_functions_scalar_generic.o duckdb/ub_extension_core_functions_scalar_enum.o duckdb/ub_extension_core_functions_scalar_map.o duckdb/ub_extension_core_functions_scalar_operators.o duckdb/ub_extension_core_functions_scalar_date.o duckdb/ub_extension_core_functions_scalar_list.o duckdb/ub_extension_core_functions_scalar_blob.o duckdb/ub_extension_core_functions_scalar_debug.o duckdb/ub_extension_core_functions_scalar_array.o duckdb/ub_extension_core_functions_scalar_union.o duckdb/ub_extension_core_functions_scalar_struct.o duckdb/ub_extension_core_functions_scalar_bit.o +SOURCES=duckdb/ub_src_catalog.o duckdb/ub_src_catalog_catalog_entry.o duckdb/ub_src_catalog_catalog_entry_dependency.o duckdb/ub_src_catalog_default.o duckdb/ub_src_common_adbc.o duckdb/ub_src_common_adbc_nanoarrow.o duckdb/ub_src_common.o duckdb/ub_src_common_arrow_appender.o duckdb/ub_src_common_arrow.o duckdb/ub_src_common_crypto.o duckdb/ub_src_common_enums.o duckdb/ub_src_common_exception.o duckdb/ub_src_common_operator.o duckdb/ub_src_common_progress_bar.o duckdb/ub_src_common_row_operations.o duckdb/ub_src_common_serializer.o duckdb/ub_src_common_sort.o duckdb/ub_src_common_tree_renderer.o duckdb/ub_src_common_types.o duckdb/ub_src_common_types_column.o duckdb/ub_src_common_types_row.o duckdb/ub_src_common_value_operations.o duckdb/src/common/vector_operations/boolean_operators.o duckdb/src/common/vector_operations/comparison_operators.o duckdb/src/common/vector_operations/generators.o duckdb/src/common/vector_operations/is_distinct_from.o duckdb/src/common/vector_operations/null_operations.o duckdb/src/common/vector_operations/numeric_inplace_operators.o duckdb/src/common/vector_operations/vector_cast.o duckdb/src/common/vector_operations/vector_copy.o duckdb/src/common/vector_operations/vector_hash.o duckdb/src/common/vector_operations/vector_storage.o duckdb/ub_src_core_functions_aggregate_algebraic.o duckdb/ub_src_core_functions_aggregate_distributive.o duckdb/ub_src_core_functions_aggregate_holistic.o duckdb/ub_src_core_functions_aggregate_nested.o duckdb/ub_src_core_functions_aggregate_regression.o duckdb/ub_src_core_functions.o duckdb/ub_src_core_functions_scalar_array.o duckdb/ub_src_core_functions_scalar_bit.o duckdb/ub_src_core_functions_scalar_blob.o duckdb/ub_src_core_functions_scalar_date.o duckdb/ub_src_core_functions_scalar_debug.o duckdb/ub_src_core_functions_scalar_enum.o duckdb/ub_src_core_functions_scalar_generic.o duckdb/ub_src_core_functions_scalar_list.o duckdb/ub_src_core_functions_scalar_map.o duckdb/ub_src_core_functions_scalar_math.o duckdb/ub_src_core_functions_scalar_operators.o duckdb/ub_src_core_functions_scalar_random.o duckdb/ub_src_core_functions_scalar_string.o duckdb/ub_src_core_functions_scalar_struct.o duckdb/ub_src_core_functions_scalar_union.o duckdb/ub_src_execution.o duckdb/ub_src_execution_expression_executor.o duckdb/ub_src_execution_index_art.o duckdb/ub_src_execution_index.o duckdb/ub_src_execution_nested_loop_join.o duckdb/ub_src_execution_operator_aggregate.o duckdb/ub_src_execution_operator_csv_scanner_buffer_manager.o duckdb/ub_src_execution_operator_csv_scanner_scanner.o duckdb/ub_src_execution_operator_csv_scanner_sniffer.o duckdb/ub_src_execution_operator_csv_scanner_state_machine.o duckdb/ub_src_execution_operator_csv_scanner_table_function.o duckdb/ub_src_execution_operator_csv_scanner_util.o duckdb/ub_src_execution_operator_filter.o duckdb/ub_src_execution_operator_helper.o duckdb/ub_src_execution_operator_join.o duckdb/ub_src_execution_operator_order.o duckdb/ub_src_execution_operator_persistent.o duckdb/ub_src_execution_operator_projection.o duckdb/ub_src_execution_operator_scan.o duckdb/ub_src_execution_operator_schema.o duckdb/ub_src_execution_operator_set.o duckdb/ub_src_execution_physical_plan.o duckdb/ub_src_function_aggregate_distributive.o duckdb/ub_src_function_aggregate.o duckdb/ub_src_function.o duckdb/ub_src_function_cast.o duckdb/ub_src_function_cast_union.o duckdb/ub_src_function_pragma.o duckdb/ub_src_function_scalar_compressed_materialization.o duckdb/ub_src_function_scalar.o duckdb/ub_src_function_scalar_generic.o duckdb/ub_src_function_scalar_list.o duckdb/ub_src_function_scalar_operators.o duckdb/ub_src_function_scalar_sequence.o duckdb/ub_src_function_scalar_string.o duckdb/ub_src_function_scalar_string_regexp.o duckdb/ub_src_function_scalar_struct.o duckdb/ub_src_function_scalar_system.o duckdb/ub_src_function_table_arrow.o duckdb/ub_src_function_table.o duckdb/ub_src_function_table_system.o duckdb/ub_src_function_table_version.o duckdb/ub_src_main.o duckdb/ub_src_main_buffered_data.o duckdb/ub_src_main_capi.o duckdb/ub_src_main_capi_cast.o duckdb/ub_src_main_chunk_scan_state.o duckdb/ub_src_main_extension.o duckdb/ub_src_main_relation.o duckdb/ub_src_main_secret.o duckdb/ub_src_main_settings.o duckdb/ub_src_optimizer.o duckdb/ub_src_optimizer_compressed_materialization.o duckdb/ub_src_optimizer_join_order.o duckdb/ub_src_optimizer_matcher.o duckdb/ub_src_optimizer_pullup.o duckdb/ub_src_optimizer_pushdown.o duckdb/ub_src_optimizer_rule.o duckdb/ub_src_optimizer_statistics_expression.o duckdb/ub_src_optimizer_statistics_operator.o duckdb/ub_src_parallel.o duckdb/ub_src_parser.o duckdb/ub_src_parser_constraints.o duckdb/ub_src_parser_expression.o duckdb/ub_src_parser_parsed_data.o duckdb/ub_src_parser_query_node.o duckdb/ub_src_parser_statement.o duckdb/ub_src_parser_tableref.o duckdb/ub_src_parser_transform_constraint.o duckdb/ub_src_parser_transform_expression.o duckdb/ub_src_parser_transform_helpers.o duckdb/ub_src_parser_transform_statement.o duckdb/ub_src_parser_transform_tableref.o duckdb/ub_src_planner.o duckdb/ub_src_planner_binder_expression.o duckdb/ub_src_planner_binder_query_node.o duckdb/ub_src_planner_binder_statement.o duckdb/ub_src_planner_binder_tableref.o duckdb/ub_src_planner_expression.o duckdb/ub_src_planner_expression_binder.o duckdb/ub_src_planner_filter.o duckdb/ub_src_planner_operator.o duckdb/ub_src_planner_subquery.o duckdb/ub_src_storage.o duckdb/ub_src_storage_buffer.o duckdb/ub_src_storage_checkpoint.o duckdb/ub_src_storage_compression_alp.o duckdb/ub_src_storage_compression.o duckdb/ub_src_storage_compression_chimp.o duckdb/ub_src_storage_metadata.o duckdb/ub_src_storage_serialization.o duckdb/ub_src_storage_statistics.o duckdb/ub_src_storage_table.o duckdb/ub_src_transaction.o duckdb/src/verification/copied_statement_verifier.o duckdb/src/verification/deserialized_statement_verifier.o duckdb/src/verification/external_statement_verifier.o duckdb/src/verification/fetch_row_verifier.o duckdb/src/verification/no_operator_caching_verifier.o duckdb/src/verification/parsed_statement_verifier.o duckdb/src/verification/prepared_statement_verifier.o duckdb/src/verification/statement_verifier.o duckdb/src/verification/unoptimized_statement_verifier.o duckdb/third_party/fmt/format.o duckdb/third_party/fsst/libfsst.o duckdb/third_party/miniz/miniz.o duckdb/third_party/re2/re2/bitmap256.o duckdb/third_party/re2/re2/bitstate.o duckdb/third_party/re2/re2/compile.o duckdb/third_party/re2/re2/dfa.o duckdb/third_party/re2/re2/filtered_re2.o duckdb/third_party/re2/re2/mimics_pcre.o duckdb/third_party/re2/re2/nfa.o duckdb/third_party/re2/re2/onepass.o duckdb/third_party/re2/re2/parse.o duckdb/third_party/re2/re2/perl_groups.o duckdb/third_party/re2/re2/prefilter.o duckdb/third_party/re2/re2/prefilter_tree.o duckdb/third_party/re2/re2/prog.o duckdb/third_party/re2/re2/re2.o duckdb/third_party/re2/re2/regexp.o duckdb/third_party/re2/re2/set.o duckdb/third_party/re2/re2/simplify.o duckdb/third_party/re2/re2/stringpiece.o duckdb/third_party/re2/re2/tostring.o duckdb/third_party/re2/re2/unicode_casefold.o duckdb/third_party/re2/re2/unicode_groups.o duckdb/third_party/re2/util/rune.o duckdb/third_party/re2/util/strutil.o duckdb/third_party/hyperloglog/hyperloglog.o duckdb/third_party/hyperloglog/sds.o duckdb/third_party/skiplist/SkipList.o duckdb/third_party/fastpforlib/bitpacking.o duckdb/third_party/utf8proc/utf8proc.o duckdb/third_party/utf8proc/utf8proc_wrapper.o duckdb/third_party/libpg_query/pg_functions.o duckdb/third_party/libpg_query/postgres_parser.o duckdb/third_party/libpg_query/src_backend_nodes_list.o duckdb/third_party/libpg_query/src_backend_nodes_makefuncs.o duckdb/third_party/libpg_query/src_backend_nodes_value.o duckdb/third_party/libpg_query/src_backend_parser_gram.o duckdb/third_party/libpg_query/src_backend_parser_parser.o duckdb/third_party/libpg_query/src_backend_parser_scan.o duckdb/third_party/libpg_query/src_backend_parser_scansup.o duckdb/third_party/libpg_query/src_common_keywords.o duckdb/third_party/mbedtls/library/aes.o duckdb/third_party/mbedtls/library/aria.o duckdb/third_party/mbedtls/library/asn1parse.o duckdb/third_party/mbedtls/library/base64.o duckdb/third_party/mbedtls/library/bignum.o duckdb/third_party/mbedtls/library/camellia.o duckdb/third_party/mbedtls/library/cipher.o duckdb/third_party/mbedtls/library/cipher_wrap.o duckdb/third_party/mbedtls/library/constant_time.o duckdb/third_party/mbedtls/library/entropy.o duckdb/third_party/mbedtls/library/entropy_poll.o duckdb/third_party/mbedtls/library/gcm.o duckdb/third_party/mbedtls/library/md.o duckdb/third_party/mbedtls/library/oid.o duckdb/third_party/mbedtls/library/pem.o duckdb/third_party/mbedtls/library/pk.o duckdb/third_party/mbedtls/library/pk_wrap.o duckdb/third_party/mbedtls/library/pkparse.o duckdb/third_party/mbedtls/library/platform_util.o duckdb/third_party/mbedtls/library/rsa.o duckdb/third_party/mbedtls/library/rsa_alt_helpers.o duckdb/third_party/mbedtls/library/sha1.o duckdb/third_party/mbedtls/library/sha256.o duckdb/third_party/mbedtls/library/sha512.o duckdb/third_party/mbedtls/mbedtls_wrapper.o duckdb/third_party/yyjson/yyjson.o duckdb/extension/parquet/column_reader.o duckdb/extension/parquet/column_writer.o duckdb/extension/parquet/parquet_crypto.o duckdb/extension/parquet/parquet_extension.o duckdb/extension/parquet/parquet_metadata.o duckdb/extension/parquet/parquet_reader.o duckdb/extension/parquet/parquet_statistics.o duckdb/extension/parquet/parquet_timestamp.o duckdb/extension/parquet/parquet_writer.o duckdb/extension/parquet/serialize_parquet.o duckdb/extension/parquet/zstd_file_system.o duckdb/extension/parquet/geo_parquet.o duckdb/third_party/parquet/parquet_constants.o duckdb/third_party/parquet/parquet_types.o duckdb/third_party/thrift/thrift/protocol/TProtocol.o duckdb/third_party/thrift/thrift/transport/TTransportException.o duckdb/third_party/thrift/thrift/transport/TBufferTransports.o duckdb/third_party/snappy/snappy.o duckdb/third_party/snappy/snappy-sinksource.o duckdb/third_party/zstd/decompress/zstd_ddict.o duckdb/third_party/zstd/decompress/huf_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress.o duckdb/third_party/zstd/decompress/zstd_decompress_block.o duckdb/third_party/zstd/common/entropy_common.o duckdb/third_party/zstd/common/fse_decompress.o duckdb/third_party/zstd/common/zstd_common.o duckdb/third_party/zstd/common/error_private.o duckdb/third_party/zstd/common/xxhash.o duckdb/third_party/zstd/compress/fse_compress.o duckdb/third_party/zstd/compress/hist.o duckdb/third_party/zstd/compress/huf_compress.o duckdb/third_party/zstd/compress/zstd_compress.o duckdb/third_party/zstd/compress/zstd_compress_literals.o duckdb/third_party/zstd/compress/zstd_compress_sequences.o duckdb/third_party/zstd/compress/zstd_compress_superblock.o duckdb/third_party/zstd/compress/zstd_double_fast.o duckdb/third_party/zstd/compress/zstd_fast.o duckdb/third_party/zstd/compress/zstd_lazy.o duckdb/third_party/zstd/compress/zstd_ldm.o duckdb/third_party/zstd/compress/zstd_opt.o duckdb/third_party/lz4/lz4.o duckdb/third_party/brotli/common/constants.o duckdb/third_party/brotli/common/context.o duckdb/third_party/brotli/common/dictionary.o duckdb/third_party/brotli/common/platform.o duckdb/third_party/brotli/common/shared_dictionary.o duckdb/third_party/brotli/common/transform.o duckdb/third_party/brotli/dec/bit_reader.o duckdb/third_party/brotli/dec/decode.o duckdb/third_party/brotli/dec/huffman.o duckdb/third_party/brotli/dec/state.o duckdb/third_party/brotli/enc/backward_references.o duckdb/third_party/brotli/enc/backward_references_hq.o duckdb/third_party/brotli/enc/bit_cost.o duckdb/third_party/brotli/enc/block_splitter.o duckdb/third_party/brotli/enc/brotli_bit_stream.o duckdb/third_party/brotli/enc/cluster.o duckdb/third_party/brotli/enc/command.o duckdb/third_party/brotli/enc/compound_dictionary.o duckdb/third_party/brotli/enc/compress_fragment.o duckdb/third_party/brotli/enc/compress_fragment_two_pass.o duckdb/third_party/brotli/enc/dictionary_hash.o duckdb/third_party/brotli/enc/encode.o duckdb/third_party/brotli/enc/encoder_dict.o duckdb/third_party/brotli/enc/entropy_encode.o duckdb/third_party/brotli/enc/fast_log.o duckdb/third_party/brotli/enc/histogram.o duckdb/third_party/brotli/enc/literal_cost.o duckdb/third_party/brotli/enc/memory.o duckdb/third_party/brotli/enc/metablock.o duckdb/third_party/brotli/enc/static_dict.o duckdb/third_party/brotli/enc/utf8_util.o diff --git a/src/relational.cpp b/src/relational.cpp index 3642638d7..d91ef0aa2 100644 --- a/src/relational.cpp +++ b/src/relational.cpp @@ -414,7 +414,7 @@ static SEXP result_to_df(duckdb::unique_ptr res) { } [[cpp11::register]] SEXP rapi_rel_to_df(duckdb::rel_extptr_t rel) { - ScopedInterruptHandler signal_handler(rel->rel->context->GetContext()); + ScopedInterruptHandler signal_handler(rel->rel->context.GetContext()); auto res = rel->rel->Execute(); diff --git a/src/reltoaltrep.cpp b/src/reltoaltrep.cpp index 840d04603..a40694e16 100644 --- a/src/reltoaltrep.cpp +++ b/src/reltoaltrep.cpp @@ -128,23 +128,23 @@ struct AltrepRelationWrapper { Rprintf("duckplyr: materializing\n"); } - ScopedInterruptHandler signal_handler(rel->context->GetContext()); + ScopedInterruptHandler signal_handler(rel->context.GetContext()); // We need to temporarily allow a deeper execution stack // https://github.com/duckdb/duckdb-r/issues/101 - auto old_depth = rel->context->GetContext()->config.max_expression_depth; - rel->context->GetContext()->config.max_expression_depth = old_depth * 2; + auto old_depth = rel->context.GetContext()->config.max_expression_depth; + rel->context.GetContext()->config.max_expression_depth = old_depth * 2; duckdb_httplib::detail::scope_exit reset_max_expression_depth( - [&]() { rel->context->GetContext()->config.max_expression_depth = old_depth; }); + [&]() { rel->context.GetContext()->config.max_expression_depth = old_depth; }); res = Materialize(); // FIXME: Use std::experimental::scope_exit - if (rel->context->GetContext()->config.max_expression_depth != old_depth * 2) { + if (rel->context.GetContext()->config.max_expression_depth != old_depth * 2) { Rprintf("Internal error: max_expression_depth was changed from %" PRIu64 " to %" PRIu64 "\n", - old_depth * 2, rel->context->GetContext()->config.max_expression_depth); + old_depth * 2, rel->context.GetContext()->config.max_expression_depth); } - rel->context->GetContext()->config.max_expression_depth = old_depth; + rel->context.GetContext()->config.max_expression_depth = old_depth; reset_max_expression_depth.release(); if (signal_handler.HandleInterrupt()) { diff --git a/src/rfuns.cpp b/src/rfuns.cpp index 240d2e17b..61371f3f3 100644 --- a/src/rfuns.cpp +++ b/src/rfuns.cpp @@ -407,7 +407,7 @@ ScalarFunctionSet base_r_is_na() { #include #include -#include "duckdb/extension/core_functions/include/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" namespace duckdb { namespace rfuns { @@ -1024,8 +1024,8 @@ DUCKDB_EXTENSION_API const char *rfuns_version() { #include #include -#include "duckdb/extension/core_functions/include/core_functions/aggregate/sum_helpers.hpp" -#include "duckdb/extension/core_functions/include/core_functions/aggregate/distributive_functions.hpp" +#include "duckdb/core_functions/aggregate/sum_helpers.hpp" +#include "duckdb/core_functions/aggregate/distributive_functions.hpp" namespace duckdb { namespace rfuns { diff --git a/src/scan.cpp b/src/scan.cpp index b348723b2..63e8d65c4 100644 --- a/src/scan.cpp +++ b/src/scan.cpp @@ -443,10 +443,8 @@ static unique_ptr DataFrameScanCardinality(ClientContext &contex return make_uniq(bind_data.row_count, bind_data.row_count); } -static InsertionOrderPreservingMap DataFrameScanToString(TableFunctionToStringInput &input) { - InsertionOrderPreservingMap result; - result["Text"] = "data.frame"; - return result; +static string DataFrameScanToString(const FunctionData *bind_data_p) { + return "data.frame"; } DataFrameScanFunction::DataFrameScanFunction() diff --git a/src/utils.cpp b/src/utils.cpp index 746386566..b1cfa2b2c 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -234,7 +234,10 @@ Value RApiTypes::SexpToValue(SEXP valsexp, R_len_t idx, bool typed_logical_null) auto value = SexpToValue(ts_val, child_idx); child_values.push_back(value); } - return Value::LIST(RApiTypes::LogicalTypeFromRType(child_rtype, true), std::move(child_values)); + if (child_values.empty()) { + return Value::EMPTYLIST(RApiTypes::LogicalTypeFromRType(child_rtype, true)); + } + return Value::LIST(std::move(child_values)); } case RTypeId::STRUCT: { child_list_t child_values; @@ -284,7 +287,7 @@ SEXP RApiTypes::ValueToSexp(Value &val, string &timezone_config) { return res; } case LogicalTypeId::TIMESTAMP_TZ: { - cpp11::doubles res({(double)Timestamp::GetEpochSeconds(val.GetValue())}); + cpp11::doubles res({(double)Timestamp::GetEpochSeconds(val.GetValue())}); SET_CLASS(res, RStrings::get().POSIXct_POSIXt_str); Rf_setAttrib(res, RStrings::get().tzone_sym, StringsToSexp({timezone_config})); return res; diff --git a/tests/testthat/_snaps/relational.md b/tests/testthat/_snaps/relational.md index f20ecd8c4..b1a2b61ff 100644 --- a/tests/testthat/_snaps/relational.md +++ b/tests/testthat/_snaps/relational.md @@ -118,7 +118,8 @@ ┌───────────────────────────┐ │ R_DATAFRAME_SCAN │ │ ──────────────────── │ - │ Text: data.frame │ + │ data.frame │ + │ │ │ Projections: x │ │ │ │ ~1 Rows │ diff --git a/tests/testthat/test-rel_api.R b/tests/testthat/test-rel_api.R index 7299d9e84..357a09885 100644 --- a/tests/testthat/test-rel_api.R +++ b/tests/testthat/test-rel_api.R @@ -8829,6 +8829,8 @@ test_that("relational mutate(c = 10, d = log10(c)) order-preserving", { }) test_that("relational mutate(c = NA_character_, d = grepl('.', c)) order-preserving", { + skip_if_not(TEST_RE2) + # Autogenerated drv <- duckdb() con <- dbConnect(drv) @@ -12780,6 +12782,8 @@ test_that("relational mutate(c = 10, d = log10(c)) order-enforcing", { }) test_that("relational mutate(c = NA_character_, d = grepl('.', c)) order-enforcing", { + skip_if_not(TEST_RE2) + # Autogenerated drv <- duckdb() con <- dbConnect(drv) diff --git a/vendor-one.sh b/vendor-one.sh index 55fd84687..510af3a83 100755 --- a/vendor-one.sh +++ b/vendor-one.sh @@ -8,22 +8,15 @@ set -o pipefail cd `dirname $0` -project=duckdb -vendor_base_dir=src/duckdb -vendor_dir=${vendor_base_dir} -repo_org=${project} -repo_name=${project} - - if [ -z "$1" ]; then - upstream_basedir=../../${project} + upstream_basedir=../duckdb else upstream_basedir="$1" fi -upstream_dir=.git/${project} +upstream_dir=.git/duckdb -if [ "$upstream_basedir" != "$upstream_dir" ]; then +if [ "$upstream_basedir" != ".git/duckdb" ]; then git clone "$upstream_basedir" "$upstream_dir" fi @@ -36,26 +29,26 @@ if [ -n "$(git -C "$upstream_dir" status --porcelain)" ]; then echo "Warning: working directory $upstream_dir not clean" fi -base=$(git log -n 3 --format="%s" -- ${vendor_dir} | tee /dev/stderr | sed -nr '/^.*'${repo_org}.${repo_name}'@([0-9a-f]+)( .*)?$/{s//\1/;p;}' | head -n 1) +original=$(git -C "$upstream_dir" rev-parse --verify HEAD) -original=$(git -C "$upstream_dir" log --first-parent --reverse --format="%H" ${base}..HEAD) +base=$(git log -n 3 --format="%s" -- src/duckdb | tee /dev/stderr | sed -nr '/^.*duckdb.duckdb@([0-9a-f]+)( .*)?$/{s//\1/;p;}' | head -n 1) message= is_tag= -for commit in $original; do +for commit in $(git -C "$upstream_dir" log --first-parent --reverse --format="%H" ${base}..HEAD); do echo "Importing commit $commit" git -C "$upstream_dir" checkout "$commit" - rm -rf ${vendor_dir} + rm -rf src/duckdb echo "R: configure" DUCKDB_PATH="$upstream_dir" python3 rconfigure.py for f in patch/*.patch; do if patch -i $f -p1 --forward --dry-run; then - patch -i $f -p1 --forward --no-backup-if-mismatch + patch -i $f -p1 --forward else echo "Removing patch $f" rm $f @@ -64,20 +57,20 @@ for commit in $original; do # Always vendor tags if [ $(git -C "$upstream_dir" describe --tags "$commit" | grep -c -- -) -eq 0 ]; then - message="vendor: Update vendored sources (tag $(git -C "$upstream_dir" describe --tags "$commit")) to ${repo_org}/${repo_name}@$commit" + message="chore: Update vendored sources (tag $(git -C "$upstream_dir" describe --tags "$commit")) to duckdb/duckdb@$commit" is_tag=true break fi - if [ $(git status --porcelain -- ${vendor_base_dir} | wc -l) -gt 1 ]; then - message="vendor: Update vendored sources to ${repo_org}/${repo_name}@$commit" + if [ $(git status --porcelain -- src/duckdb | wc -l) -gt 1 ]; then + message="chore: Update vendored sources to duckdb/duckdb@$commit" break fi done if [ "$message" = "" ]; then echo "No changes." - git checkout -- ${vendor_base_dir} + git checkout -- src/duckdb rm -rf "$upstream_dir" exit 0 fi @@ -90,7 +83,7 @@ echo "Upstream tag: $upstream_tag" if [ -z "${is_tag}" -a "${our_tag#$upstream_tag}" == "$our_tag" ]; then echo "Not vendoring because our tag $our_tag does not start with upstream tag $upstream_tag" - git checkout -- ${vendor_base_dir} + git checkout -- src/duckdb rm -rf "$upstream_dir" exit 0 fi @@ -100,7 +93,7 @@ git add . ( echo "$message" echo - git -C "$upstream_dir" log --first-parent --format="%s" ${base}..${commit} | tee /dev/stderr | sed -r 's%(#[0-9]+)%'${repo_org}/${repo_name}'\1%g' + git -C "$upstream_dir" log --first-parent --format="%s" ${base}..${commit} | tee /dev/stderr | sed -r 's%(#[0-9]+)%duckdb/duckdb\1%g' ) | git commit --file /dev/stdin rm -rf "$upstream_dir" diff --git a/vendor.sh b/vendor.sh index 2ba5d0f8a..cbd853202 100755 --- a/vendor.sh +++ b/vendor.sh @@ -1,30 +1,14 @@ -#!/bin/bash -# https://unix.stackexchange.com/a/654932/19205 -# Using bash for -o pipefail +#!/bin/sh set -e set -x -set -o pipefail cd `dirname $0` -project=duckdb -vendor_base_dir=src/duckdb -vendor_dir=${vendor_base_dir} -repo_org=${project} -repo_name=${project} - - if [ -z "$1" ]; then - upstream_basedir=../../${project} + upstream_dir=../duckdb else - upstream_basedir="$1" -fi - -upstream_dir=.git/${project} - -if [ "$upstream_basedir" != "$upstream_dir" ]; then - git clone "$upstream_basedir" "$upstream_dir" + upstream_dir="$1" fi if [ -n "$(git status --porcelain)" ]; then @@ -36,56 +20,48 @@ if [ -n "$(git -C "$upstream_dir" status --porcelain)" ]; then echo "Warning: working directory $upstream_dir not clean" fi -base=$(git log -n 3 --format="%s" -- ${vendor_dir} | tee /dev/stderr | sed -nr '/^.*'${repo_org}.${repo_name}'@([0-9a-f]+)( .*)?$/{s//\1/;p;}' | head -n 1) +commit=$(git -C "$upstream_dir" rev-parse HEAD) -original=$(git -C "$upstream_dir" rev-parse --verify HEAD) +base=$(git log -n 3 --format="%s" -- src/duckdb | tee /dev/stderr | sed -nr '/^.*duckdb.duckdb@([0-9a-f]+)$/{s//\1/;p;}' | head -n 1) message= -is_tag= -for commit in $original; do +for commit in $commit; do echo "Importing commit $commit" - rm -rf ${vendor_dir} + rm -rf src/duckdb echo "R: configure" - DUCKDB_PATH="$upstream_dir" python3 rconfigure.py + python3 rconfigure.py for f in patch/*.patch; do - if patch -i $f -p1 --forward --dry-run; then - patch -i $f -p1 --forward --no-backup-if-mismatch - else - echo "Removing patch $f" - rm $f - fi + # cat $f | patch -p1 --dry-run + cat $f | patch -p1 done # Always vendor tags if [ $(git -C "$upstream_dir" describe --tags "$commit" | grep -c -- -) -eq 0 ]; then - message="vendor: Update vendored sources (tag $(git -C "$upstream_dir" describe --tags "$commit")) to ${repo_org}/${repo_name}@$commit" - is_tag=true + message="chore: Update vendored sources (tag $(git -C "$upstream_dir" describe --tags "$commit")) to duckdb/duckdb@$commit" break fi - if [ $(git status --porcelain -- ${vendor_base_dir} | wc -l) -gt 1 ]; then - message="vendor: Update vendored sources to ${repo_org}/${repo_name}@$commit" + if [ $(git status --porcelain -- src/duckdb | wc -l) -gt 1 ]; then + message="chore: Update vendored sources to duckdb/duckdb@$commit" break fi done if [ "$message" = "" ]; then echo "No changes." - git checkout -- ${vendor_base_dir} - rm -rf "$upstream_dir" + git checkout -- src/duckdb exit 0 fi + git add . ( echo "$message" echo - git -C "$upstream_dir" log --first-parent --format="%s" ${base}..${commit} | tee /dev/stderr | sed -r 's%(#[0-9]+)%'${repo_org}/${repo_name}'\1%g' + git -C "$upstream_dir" log --first-parent --format="%s" ${base}..${commit} | tee /dev/stderr | sed -r 's%(#[0-9]+)%duckdb/duckdb\1%g' ) | git commit --file /dev/stdin - -rm -rf "$upstream_dir"