prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  🪲stats for distinct incorrect
  ### Thank you for taking the time to report a problem with Opteryx.
  _To help us to respond to your request we ask that you try to provide the below detail about the bug._
  
  **Describe the bug** _A clear and specific description of what the bug is. What the error, incorrect or unexpected behaviour was._
  
  
  **Expected behaviour** _A clear and concise description of what you expected to happen._
  
  
  **Sample Code/Statement** _If you can, please submit the SQL statement or Python code snippet, or a representative example using the sample datasets._
  
  ~~~sql
  
  ~~~
  
  **Additional context** _Add any other context about the problem here, for example what you have done to try to diagnose or workaround the problem._
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `opteryx/operators/distinct_node.py`
  Content:
  ```
  1 # Licensed under the Apache License, Version 2.0 (the "License");
  2 # you may not use this file except in compliance with the License.
  3 # You may obtain a copy of the License at
  4 #
  5 #     http://www.apache.org/licenses/LICENSE-2.0
  6 #
  7 # Unless required by applicable law or agreed to in writing, software
  8 # distributed under the License is distributed on an "AS IS" BASIS,
  9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10 # See the License for the specific language governing permissions and
  11 # limitations under the License.
  12 
  13 """
  14 Distinct Node
  15 
  16 This is a SQL Query Execution Plan Node.
  17 
  18 This Node eliminates duplicate records.
  19 """
  20 import time
  21 from typing import Generator
  22 
  23 import pyarrow
  24 import pyarrow.compute
  25 
  26 from opteryx.models import QueryProperties
  27 from opteryx.operators import BasePlanNode
  28 
  29 
  30 class DistinctNode(BasePlanNode):
  31     def __init__(self, properties: QueryProperties, **config):
  32         super().__init__(properties=properties)
  33         self._distinct_on = config.get("on")
  34         if self._distinct_on:
  35             self._distinct_on = [col.schema_column.identity for col in self._distinct_on]
  36 
  37     @property
  38     def config(self):  # pragma: no cover
  39         return ""
  40 
  41     @property
  42     def greedy(self):  # pragma: no cover
  43         return True
  44 
  45     @property
  46     def name(self):  # pragma: no cover
  47         return "Distinction"
  48 
  49     def execute(self) -> Generator[pyarrow.Table, None, None]:
  50 
  51         from opteryx.compiled.functions import HashSet
  52         from opteryx.compiled.functions import distinct
  53 
  54         # We create a HashSet outside the distinct call, this allows us to pass
  55         # the hash to each run of the distinct which means we don't need to concat
  56         # all of the tables together to return a result.
  57         # The Cython distinct is about 8x faster on a 10 million row dataset with
  58         # approx 85k distinct entries (4.8sec vs 0.8sec) and faster on a 177 record
  59         # dataset with 7 distinct entries.
  60         # Being able to run morsel-by-morsel means if we have a LIMIT clause, we can
  61         # limit processing
  62         hash_set = HashSet()
  63 
  64         morsels = self._producers[0]  # type:ignore
  65 
  66         start = time.monotonic_ns()
  67         for morsel in morsels.execute():
  68             deduped, hash_set = distinct(
  69                 morsel, columns=self._distinct_on, seen_hashes=hash_set, return_seen_hashes=True
  70             )
  71             if deduped.num_rows > 0:
  72                 self.statistics.time_distincting += time.monotonic_ns() - start
  73                 yield deduped
  74                 start = time.monotonic_ns()
  75
  ```
  
  Path: `opteryx/__version__.py`
  Content:
  ```
  1 __build__ = 296
  2 
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #     http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 """
  16 Store the version here so:
  17 1) we don't load dependencies by storing it in __init__.py
  18 2) we can import it in setup.py for the same reason
  19 """
  20 from enum import Enum  # isort: skip
  21 
  22 
  23 class VersionStatus(Enum):
  24     ALPHA = "alpha"
  25     BETA = "beta"
  26     RELEASE = "release"
  27 
  28 
  29 _major = 0
  30 _minor = 14
  31 _revision = 0
  32 _status = VersionStatus.ALPHA
  33 
  34 __author__ = "@joocer"
  35 __version__ = f"{_major}.{_minor}.{_revision}" + (
  36     f"-{_status.value}.{__build__}" if _status != VersionStatus.RELEASE else ""
  37 )
  38
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/opteryx/__version__.py b/opteryx/__version__.py
  --- a/opteryx/__version__.py
  +++ b/opteryx/__version__.py
  @@ -1,4 +1,4 @@
  -__build__ = 296
  +__build__ = 298
   
   # Licensed under the Apache License, Version 2.0 (the "License");
   # you may not use this file except in compliance with the License.
  diff --git a/opteryx/operators/distinct_node.py b/opteryx/operators/distinct_node.py
  --- a/opteryx/operators/distinct_node.py
  +++ b/opteryx/operators/distinct_node.py
  @@ -29,10 +29,13 @@
   
   class DistinctNode(BasePlanNode):
       def __init__(self, properties: QueryProperties, **config):
  +        from opteryx.compiled.functions import HashSet
  +
           super().__init__(properties=properties)
           self._distinct_on = config.get("on")
           if self._distinct_on:
               self._distinct_on = [col.schema_column.identity for col in self._distinct_on]
  +        self.hash_set = HashSet()
   
       @property
       def config(self):  # pragma: no cover
  @@ -48,7 +51,6 @@
   
       def execute(self) -> Generator[pyarrow.Table, None, None]:
   
  -        from opteryx.compiled.functions import HashSet
           from opteryx.compiled.functions import distinct
   
           # We create a HashSet outside the distinct call, this allows us to pass
  @@ -59,16 +61,17 @@
           # dataset with 7 distinct entries.
           # Being able to run morsel-by-morsel means if we have a LIMIT clause, we can
           # limit processing
  -        hash_set = HashSet()
   
           morsels = self._producers[0]  # type:ignore
   
  -        start = time.monotonic_ns()
           for morsel in morsels.execute():
  -            deduped, hash_set = distinct(
  -                morsel, columns=self._distinct_on, seen_hashes=hash_set, return_seen_hashes=True
  +            start = time.monotonic_ns()
  +            deduped, self.hash_set = distinct(
  +                morsel,
  +                columns=self._distinct_on,
  +                seen_hashes=self.hash_set,
  +                return_seen_hashes=True,
               )
  +            self.statistics.time_distincting += time.monotonic_ns() - start
               if deduped.num_rows > 0:
  -                self.statistics.time_distincting += time.monotonic_ns() - start
                   yield deduped
  -                start = time.monotonic_ns()
  
verification_info: {"golden_diff": "diff --git a/opteryx/__version__.py b/opteryx/__version__.py\n--- a/opteryx/__version__.py\n+++ b/opteryx/__version__.py\n@@ -1,4 +1,4 @@\n-__build__ = 296\n+__build__ = 298\n \n # Licensed under the Apache License, Version 2.0 (the \"License\");\n # you may not use this file except in compliance with the License.\ndiff --git a/opteryx/operators/distinct_node.py b/opteryx/operators/distinct_node.py\n--- a/opteryx/operators/distinct_node.py\n+++ b/opteryx/operators/distinct_node.py\n@@ -29,10 +29,13 @@\n \n class DistinctNode(BasePlanNode):\n     def __init__(self, properties: QueryProperties, **config):\n+        from opteryx.compiled.functions import HashSet\n+\n         super().__init__(properties=properties)\n         self._distinct_on = config.get(\"on\")\n         if self._distinct_on:\n             self._distinct_on = [col.schema_column.identity for col in self._distinct_on]\n+        self.hash_set = HashSet()\n \n     @property\n     def config(self):  # pragma: no cover\n@@ -48,7 +51,6 @@\n \n     def execute(self) -> Generator[pyarrow.Table, None, None]:\n \n-        from opteryx.compiled.functions import HashSet\n         from opteryx.compiled.functions import distinct\n \n         # We create a HashSet outside the distinct call, this allows us to pass\n@@ -59,16 +61,17 @@\n         # dataset with 7 distinct entries.\n         # Being able to run morsel-by-morsel means if we have a LIMIT clause, we can\n         # limit processing\n-        hash_set = HashSet()\n \n         morsels = self._producers[0]  # type:ignore\n \n-        start = time.monotonic_ns()\n         for morsel in morsels.execute():\n-            deduped, hash_set = distinct(\n-                morsel, columns=self._distinct_on, seen_hashes=hash_set, return_seen_hashes=True\n+            start = time.monotonic_ns()\n+            deduped, self.hash_set = distinct(\n+                morsel,\n+                columns=self._distinct_on,\n+                seen_hashes=self.hash_set,\n+                return_seen_hashes=True,\n             )\n+            self.statistics.time_distincting += time.monotonic_ns() - start\n             if deduped.num_rows > 0:\n-                self.statistics.time_distincting += time.monotonic_ns() - start\n                 yield deduped\n-                start = time.monotonic_ns()\n", "issue": "\ud83e\udeb2stats for distinct incorrect\n### Thank you for taking the time to report a problem with Opteryx.\r\n_To help us to respond to your request we ask that you try to provide the below detail about the bug._\r\n\r\n**Describe the bug** _A clear and specific description of what the bug is. What the error, incorrect or unexpected behaviour was._\r\n\r\n\r\n**Expected behaviour** _A clear and concise description of what you expected to happen._\r\n\r\n\r\n**Sample Code/Statement** _If you can, please submit the SQL statement or Python code snippet, or a representative example using the sample datasets._\r\n\r\n~~~sql\r\n\r\n~~~\r\n\r\n**Additional context** _Add any other context about the problem here, for example what you have done to try to diagnose or workaround the problem._\r\n\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nDistinct Node\n\nThis is a SQL Query Execution Plan Node.\n\nThis Node eliminates duplicate records.\n\"\"\"\nimport time\nfrom typing import Generator\n\nimport pyarrow\nimport pyarrow.compute\n\nfrom opteryx.models import QueryProperties\nfrom opteryx.operators import BasePlanNode\n\n\nclass DistinctNode(BasePlanNode):\n    def __init__(self, properties: QueryProperties, **config):\n        super().__init__(properties=properties)\n        self._distinct_on = config.get(\"on\")\n        if self._distinct_on:\n            self._distinct_on = [col.schema_column.identity for col in self._distinct_on]\n\n    @property\n    def config(self):  # pragma: no cover\n        return \"\"\n\n    @property\n    def greedy(self):  # pragma: no cover\n        return True\n\n    @property\n    def name(self):  # pragma: no cover\n        return \"Distinction\"\n\n    def execute(self) -> Generator[pyarrow.Table, None, None]:\n\n        from opteryx.compiled.functions import HashSet\n        from opteryx.compiled.functions import distinct\n\n        # We create a HashSet outside the distinct call, this allows us to pass\n        # the hash to each run of the distinct which means we don't need to concat\n        # all of the tables together to return a result.\n        # The Cython distinct is about 8x faster on a 10 million row dataset with\n        # approx 85k distinct entries (4.8sec vs 0.8sec) and faster on a 177 record\n        # dataset with 7 distinct entries.\n        # Being able to run morsel-by-morsel means if we have a LIMIT clause, we can\n        # limit processing\n        hash_set = HashSet()\n\n        morsels = self._producers[0]  # type:ignore\n\n        start = time.monotonic_ns()\n        for morsel in morsels.execute():\n            deduped, hash_set = distinct(\n                morsel, columns=self._distinct_on, seen_hashes=hash_set, return_seen_hashes=True\n            )\n            if deduped.num_rows > 0:\n                self.statistics.time_distincting += time.monotonic_ns() - start\n                yield deduped\n                start = time.monotonic_ns()\n", "path": "opteryx/operators/distinct_node.py"}, {"content": "__build__ = 296\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nStore the version here so:\n1) we don't load dependencies by storing it in __init__.py\n2) we can import it in setup.py for the same reason\n\"\"\"\nfrom enum import Enum  # isort: skip\n\n\nclass VersionStatus(Enum):\n    ALPHA = \"alpha\"\n    BETA = \"beta\"\n    RELEASE = \"release\"\n\n\n_major = 0\n_minor = 14\n_revision = 0\n_status = VersionStatus.ALPHA\n\n__author__ = \"@joocer\"\n__version__ = f\"{_major}.{_minor}.{_revision}\" + (\n    f\"-{_status.value}.{__build__}\" if _status != VersionStatus.RELEASE else \"\"\n)\n", "path": "opteryx/__version__.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nDistinct Node\n\nThis is a SQL Query Execution Plan Node.\n\nThis Node eliminates duplicate records.\n\"\"\"\nimport time\nfrom typing import Generator\n\nimport pyarrow\nimport pyarrow.compute\n\nfrom opteryx.models import QueryProperties\nfrom opteryx.operators import BasePlanNode\n\n\nclass DistinctNode(BasePlanNode):\n    def __init__(self, properties: QueryProperties, **config):\n        from opteryx.compiled.functions import HashSet\n\n        super().__init__(properties=properties)\n        self._distinct_on = config.get(\"on\")\n        if self._distinct_on:\n            self._distinct_on = [col.schema_column.identity for col in self._distinct_on]\n        self.hash_set = HashSet()\n\n    @property\n    def config(self):  # pragma: no cover\n        return \"\"\n\n    @property\n    def greedy(self):  # pragma: no cover\n        return True\n\n    @property\n    def name(self):  # pragma: no cover\n        return \"Distinction\"\n\n    def execute(self) -> Generator[pyarrow.Table, None, None]:\n\n        from opteryx.compiled.functions import distinct\n\n        # We create a HashSet outside the distinct call, this allows us to pass\n        # the hash to each run of the distinct which means we don't need to concat\n        # all of the tables together to return a result.\n        # The Cython distinct is about 8x faster on a 10 million row dataset with\n        # approx 85k distinct entries (4.8sec vs 0.8sec) and faster on a 177 record\n        # dataset with 7 distinct entries.\n        # Being able to run morsel-by-morsel means if we have a LIMIT clause, we can\n        # limit processing\n\n        morsels = self._producers[0]  # type:ignore\n\n        for morsel in morsels.execute():\n            start = time.monotonic_ns()\n            deduped, self.hash_set = distinct(\n                morsel,\n                columns=self._distinct_on,\n                seen_hashes=self.hash_set,\n                return_seen_hashes=True,\n            )\n            self.statistics.time_distincting += time.monotonic_ns() - start\n            if deduped.num_rows > 0:\n                yield deduped\n", "path": "opteryx/operators/distinct_node.py"}, {"content": "__build__ = 298\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nStore the version here so:\n1) we don't load dependencies by storing it in __init__.py\n2) we can import it in setup.py for the same reason\n\"\"\"\nfrom enum import Enum  # isort: skip\n\n\nclass VersionStatus(Enum):\n    ALPHA = \"alpha\"\n    BETA = \"beta\"\n    RELEASE = \"release\"\n\n\n_major = 0\n_minor = 14\n_revision = 0\n_status = VersionStatus.ALPHA\n\n__author__ = \"@joocer\"\n__version__ = f\"{_major}.{_minor}.{_revision}\" + (\n    f\"-{_status.value}.{__build__}\" if _status != VersionStatus.RELEASE else \"\"\n)\n", "path": "opteryx/__version__.py"}]}