We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bug(duckdb): duckdb backend should add in CAST for some bind parameters
DuckDB casts bind parameters `?` to strings which leads to binder errors with some queries

If we have a small tpch dataset:

```python
import duckdb
con = duckdb.connect("tpch.ddb")
con.execute("CALL dbgen(sf=0.1)")

import ibis
con = ibis.duckdb.connect("tpch.ddb")

t = con.table('orders')
expr = t.aggregate(high_line_count=(t.o_orderpriority.case().when('1-URGENT', 1).else_(0).end().sum()

expr.execute()
```

raises

```
RuntimeError: Binder Error: No function matches the given name and argument types 'sum(VARCHAR)'. You might need to add explicit type casts.
	Candidate functions:
	sum(DECIMAL) -> DECIMAL
	sum(SMALLINT) -> HUGEINT
	sum(INTEGER) -> HUGEINT
	sum(BIGINT) -> HUGEINT
	sum(HUGEINT) -> HUGEINT
	sum(DOUBLE) -> DOUBLE

LINE 1: SELECT sum(CASE WHEN (t0.o_orderpriority = ?) ...
```

because our generated SQL doesn't have explicit casts:

```
print(expr.compile())
SELECT sum(CASE WHEN (t0.o_orderpriority = ?) THEN ? ELSE ? END) AS high_line_count 
FROM orders AS t0
```

we want to generate

```
SELECT sum(CASE WHEN (t0.o_orderpriority = ?) THEN cast(? as INTEGER) ELSE cast(? as INTEGER) END) AS high_line_count FROM orders as t0
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ibis/backends/duckdb/registry.py`
Content:
```
1 import collections
2 import operator
3 
4 import numpy as np
5 import sqlalchemy as sa
6 
7 import ibis.expr.datatypes as dt
8 import ibis.expr.operations as ops
9 from ibis.backends.base.sql.alchemy import to_sqla_type, unary
10 
11 from ..base.sql.alchemy.registry import _geospatial_functions, _table_column
12 from ..postgres.registry import fixed_arity, operation_registry
13 
14 operation_registry = {
15     op: operation_registry[op]
16     # duckdb does not support geospatial operations, but shares most of the
17     # remaining postgres rules
18     for op in operation_registry.keys() - _geospatial_functions.keys()
19 }
20 
21 
22 def _round(t, expr):
23     arg, digits = expr.op().args
24     sa_arg = t.translate(arg)
25 
26     if digits is None:
27         return sa.func.round(sa_arg)
28 
29     return sa.func.round(sa_arg, t.translate(digits))
30 
31 
32 _LOG_BASE_FUNCS = {
33     2: sa.func.log2,
34     10: sa.func.log,
35 }
36 
37 
38 def _generic_log(arg, base):
39     return sa.func.ln(arg) / sa.func.ln(base)
40 
41 
42 def _log(t, expr):
43     arg, base = expr.op().args
44     sa_arg = t.translate(arg)
45     if base is not None:
46         sa_base = t.translate(base)
47         try:
48             base_value = sa_base.value
49         except AttributeError:
50             return _generic_log(sa_arg, sa_base)
51         else:
52             func = _LOG_BASE_FUNCS.get(base_value, _generic_log)
53             return func(sa_arg)
54     return sa.func.ln(sa_arg)
55 
56 
57 def _timestamp_from_unix(t, expr):
58     op = expr.op()
59     arg, unit = op.args
60     arg = t.translate(arg)
61 
62     if unit in {"us", "ns"}:
63         raise ValueError(f"`{unit}` unit is not supported!")
64 
65     if unit == "ms":
66         return sa.func.epoch_ms(arg)
67     elif unit == "s":
68         return sa.func.to_timestamp(arg)
69 
70 
71 def _literal(_, expr):
72     dtype = expr.type()
73     sqla_type = to_sqla_type(dtype)
74     op = expr.op()
75     value = op.value
76 
77     if isinstance(dtype, dt.Interval):
78         return sa.text(f"INTERVAL '{value} {dtype.resolution}'")
79     elif isinstance(dtype, dt.Set) or (
80         isinstance(value, collections.abc.Sequence)
81         and not isinstance(value, str)
82     ):
83         return sa.cast(sa.func.list_value(*value), sqla_type)
84     elif isinstance(value, np.ndarray):
85         return sa.cast(sa.func.list_value(*value.tolist()), sqla_type)
86     elif isinstance(value, collections.abc.Mapping):
87         if isinstance(dtype, dt.Struct):
88             placeholders = ", ".join(
89                 f"{key!r}: :v{i}" for i, key in enumerate(value.keys())
90             )
91             return sa.text(f"{{{placeholders}}}").bindparams(
92                 *(
93                     sa.bindparam(f"v{i:d}", val)
94                     for i, val in enumerate(value.values())
95                 )
96             )
97         raise NotImplementedError(
98             f"Ibis dtype `{dtype}` with mapping type "
99             f"`{type(value).__name__}` isn't yet supported with the duckdb "
100             "backend"
101         )
102     return sa.literal(value)
103 
104 
105 def _array_column(t, expr):
106     (arg,) = expr.op().args
107     sqla_type = to_sqla_type(expr.type())
108     return sa.cast(sa.func.list_value(*map(t.translate, arg)), sqla_type)
109 
110 
111 def _struct_field(t, expr):
112     op = expr.op()
113     return sa.func.struct_extract(
114         t.translate(op.arg),
115         sa.text(repr(op.field)),
116         type_=to_sqla_type(expr.type()),
117     )
118 
119 
120 def _regex_extract(t, expr):
121     string, pattern, index = map(t.translate, expr.op().args)
122     result = sa.case(
123         [
124             (
125                 sa.func.regexp_matches(string, pattern),
126                 sa.func.regexp_extract(
127                     string,
128                     pattern,
129                     # DuckDB requires the index to be a constant so we compile
130                     # the value and inline it using sa.text
131                     sa.text(
132                         str(
133                             (index + 1).compile(
134                                 compile_kwargs=dict(literal_binds=True)
135                             )
136                         )
137                     ),
138                 ),
139             )
140         ],
141         else_="",
142     )
143     return result
144 
145 
146 operation_registry.update(
147     {
148         ops.ArrayColumn: _array_column,
149         ops.ArrayConcat: fixed_arity('array_concat', 2),
150         ops.ArrayIndex: fixed_arity('list_element', 2),
151         ops.DayOfWeekName: unary(sa.func.dayname),
152         ops.Literal: _literal,
153         ops.Log2: unary(sa.func.log2),
154         ops.Ln: unary(sa.func.ln),
155         ops.Log: _log,
156         # TODO: map operations, but DuckDB's maps are multimaps
157         ops.Modulus: fixed_arity(operator.mod, 2),
158         ops.Round: _round,
159         ops.StructField: _struct_field,
160         ops.TableColumn: _table_column,
161         ops.TimestampDiff: fixed_arity('age', 2),
162         ops.TimestampFromUNIX: _timestamp_from_unix,
163         ops.Translate: fixed_arity('replace', 3),
164         ops.TimestampNow: fixed_arity('now', 0),
165         ops.RegexExtract: _regex_extract,
166         ops.RegexReplace: fixed_arity("regexp_replace", 3),
167     }
168 )
169
```
--- 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()

```

diff --git a/ibis/backends/duckdb/registry.py b/ibis/backends/duckdb/registry.py
--- a/ibis/backends/duckdb/registry.py
+++ b/ibis/backends/duckdb/registry.py
@@ -99,7 +99,7 @@
             f"`{type(value).__name__}` isn't yet supported with the duckdb "
             "backend"
         )
-    return sa.literal(value)
+    return sa.cast(sa.literal(value), sqla_type)
 
 
 def _array_column(t, expr):

{"golden_diff": "diff --git a/ibis/backends/duckdb/registry.py b/ibis/backends/duckdb/registry.py\n--- a/ibis/backends/duckdb/registry.py\n+++ b/ibis/backends/duckdb/registry.py\n@@ -99,7 +99,7 @@\n             f\"`{type(value).__name__}` isn't yet supported with the duckdb \"\n             \"backend\"\n         )\n-    return sa.literal(value)\n+    return sa.cast(sa.literal(value), sqla_type)\n \n \n def _array_column(t, expr):\n", "issue": "bug(duckdb): duckdb backend should add in CAST for some bind parameters\nDuckDB casts bind parameters `?` to strings which leads to binder errors with some queries\r\n\r\nIf we have a small tpch dataset:\r\n\r\n```python\r\nimport duckdb\r\ncon = duckdb.connect(\"tpch.ddb\")\r\ncon.execute(\"CALL dbgen(sf=0.1)\")\r\n\r\nimport ibis\r\ncon = ibis.duckdb.connect(\"tpch.ddb\")\r\n\r\nt = con.table('orders')\r\nexpr = t.aggregate(high_line_count=(t.o_orderpriority.case().when('1-URGENT', 1).else_(0).end().sum()\r\n\r\nexpr.execute()\r\n```\r\n\r\nraises\r\n\r\n```\r\nRuntimeError: Binder Error: No function matches the given name and argument types 'sum(VARCHAR)'. You might need to add explicit type casts.\r\n\tCandidate functions:\r\n\tsum(DECIMAL) -> DECIMAL\r\n\tsum(SMALLINT) -> HUGEINT\r\n\tsum(INTEGER) -> HUGEINT\r\n\tsum(BIGINT) -> HUGEINT\r\n\tsum(HUGEINT) -> HUGEINT\r\n\tsum(DOUBLE) -> DOUBLE\r\n\r\nLINE 1: SELECT sum(CASE WHEN (t0.o_orderpriority = ?) ...\r\n```\r\n\r\nbecause our generated SQL doesn't have explicit casts:\r\n\r\n```\r\nprint(expr.compile())\r\nSELECT sum(CASE WHEN (t0.o_orderpriority = ?) THEN ? ELSE ? END) AS high_line_count \r\nFROM orders AS t0\r\n```\r\n\r\nwe want to generate\r\n\r\n```\r\nSELECT sum(CASE WHEN (t0.o_orderpriority = ?) THEN cast(? as INTEGER) ELSE cast(? as INTEGER) END) AS high_line_count FROM orders as t0\r\n```\n", "before_files": [{"content": "import collections\nimport operator\n\nimport numpy as np\nimport sqlalchemy as sa\n\nimport ibis.expr.datatypes as dt\nimport ibis.expr.operations as ops\nfrom ibis.backends.base.sql.alchemy import to_sqla_type, unary\n\nfrom ..base.sql.alchemy.registry import _geospatial_functions, _table_column\nfrom ..postgres.registry import fixed_arity, operation_registry\n\noperation_registry = {\n    op: operation_registry[op]\n    # duckdb does not support geospatial operations, but shares most of the\n    # remaining postgres rules\n    for op in operation_registry.keys() - _geospatial_functions.keys()\n}\n\n\ndef _round(t, expr):\n    arg, digits = expr.op().args\n    sa_arg = t.translate(arg)\n\n    if digits is None:\n        return sa.func.round(sa_arg)\n\n    return sa.func.round(sa_arg, t.translate(digits))\n\n\n_LOG_BASE_FUNCS = {\n    2: sa.func.log2,\n    10: sa.func.log,\n}\n\n\ndef _generic_log(arg, base):\n    return sa.func.ln(arg) / sa.func.ln(base)\n\n\ndef _log(t, expr):\n    arg, base = expr.op().args\n    sa_arg = t.translate(arg)\n    if base is not None:\n        sa_base = t.translate(base)\n        try:\n            base_value = sa_base.value\n        except AttributeError:\n            return _generic_log(sa_arg, sa_base)\n        else:\n            func = _LOG_BASE_FUNCS.get(base_value, _generic_log)\n            return func(sa_arg)\n    return sa.func.ln(sa_arg)\n\n\ndef _timestamp_from_unix(t, expr):\n    op = expr.op()\n    arg, unit = op.args\n    arg = t.translate(arg)\n\n    if unit in {\"us\", \"ns\"}:\n        raise ValueError(f\"`{unit}` unit is not supported!\")\n\n    if unit == \"ms\":\n        return sa.func.epoch_ms(arg)\n    elif unit == \"s\":\n        return sa.func.to_timestamp(arg)\n\n\ndef _literal(_, expr):\n    dtype = expr.type()\n    sqla_type = to_sqla_type(dtype)\n    op = expr.op()\n    value = op.value\n\n    if isinstance(dtype, dt.Interval):\n        return sa.text(f\"INTERVAL '{value} {dtype.resolution}'\")\n    elif isinstance(dtype, dt.Set) or (\n        isinstance(value, collections.abc.Sequence)\n        and not isinstance(value, str)\n    ):\n        return sa.cast(sa.func.list_value(*value), sqla_type)\n    elif isinstance(value, np.ndarray):\n        return sa.cast(sa.func.list_value(*value.tolist()), sqla_type)\n    elif isinstance(value, collections.abc.Mapping):\n        if isinstance(dtype, dt.Struct):\n            placeholders = \", \".join(\n                f\"{key!r}: :v{i}\" for i, key in enumerate(value.keys())\n            )\n            return sa.text(f\"{{{placeholders}}}\").bindparams(\n                *(\n                    sa.bindparam(f\"v{i:d}\", val)\n                    for i, val in enumerate(value.values())\n                )\n            )\n        raise NotImplementedError(\n            f\"Ibis dtype `{dtype}` with mapping type \"\n            f\"`{type(value).__name__}` isn't yet supported with the duckdb \"\n            \"backend\"\n        )\n    return sa.literal(value)\n\n\ndef _array_column(t, expr):\n    (arg,) = expr.op().args\n    sqla_type = to_sqla_type(expr.type())\n    return sa.cast(sa.func.list_value(*map(t.translate, arg)), sqla_type)\n\n\ndef _struct_field(t, expr):\n    op = expr.op()\n    return sa.func.struct_extract(\n        t.translate(op.arg),\n        sa.text(repr(op.field)),\n        type_=to_sqla_type(expr.type()),\n    )\n\n\ndef _regex_extract(t, expr):\n    string, pattern, index = map(t.translate, expr.op().args)\n    result = sa.case(\n        [\n            (\n                sa.func.regexp_matches(string, pattern),\n                sa.func.regexp_extract(\n                    string,\n                    pattern,\n                    # DuckDB requires the index to be a constant so we compile\n                    # the value and inline it using sa.text\n                    sa.text(\n                        str(\n                            (index + 1).compile(\n                                compile_kwargs=dict(literal_binds=True)\n                            )\n                        )\n                    ),\n                ),\n            )\n        ],\n        else_=\"\",\n    )\n    return result\n\n\noperation_registry.update(\n    {\n        ops.ArrayColumn: _array_column,\n        ops.ArrayConcat: fixed_arity('array_concat', 2),\n        ops.ArrayIndex: fixed_arity('list_element', 2),\n        ops.DayOfWeekName: unary(sa.func.dayname),\n        ops.Literal: _literal,\n        ops.Log2: unary(sa.func.log2),\n        ops.Ln: unary(sa.func.ln),\n        ops.Log: _log,\n        # TODO: map operations, but DuckDB's maps are multimaps\n        ops.Modulus: fixed_arity(operator.mod, 2),\n        ops.Round: _round,\n        ops.StructField: _struct_field,\n        ops.TableColumn: _table_column,\n        ops.TimestampDiff: fixed_arity('age', 2),\n        ops.TimestampFromUNIX: _timestamp_from_unix,\n        ops.Translate: fixed_arity('replace', 3),\n        ops.TimestampNow: fixed_arity('now', 0),\n        ops.RegexExtract: _regex_extract,\n        ops.RegexReplace: fixed_arity(\"regexp_replace\", 3),\n    }\n)\n", "path": "ibis/backends/duckdb/registry.py"}], "after_files": [{"content": "import collections\nimport operator\n\nimport numpy as np\nimport sqlalchemy as sa\n\nimport ibis.expr.datatypes as dt\nimport ibis.expr.operations as ops\nfrom ibis.backends.base.sql.alchemy import to_sqla_type, unary\n\nfrom ..base.sql.alchemy.registry import _geospatial_functions, _table_column\nfrom ..postgres.registry import fixed_arity, operation_registry\n\noperation_registry = {\n    op: operation_registry[op]\n    # duckdb does not support geospatial operations, but shares most of the\n    # remaining postgres rules\n    for op in operation_registry.keys() - _geospatial_functions.keys()\n}\n\n\ndef _round(t, expr):\n    arg, digits = expr.op().args\n    sa_arg = t.translate(arg)\n\n    if digits is None:\n        return sa.func.round(sa_arg)\n\n    return sa.func.round(sa_arg, t.translate(digits))\n\n\n_LOG_BASE_FUNCS = {\n    2: sa.func.log2,\n    10: sa.func.log,\n}\n\n\ndef _generic_log(arg, base):\n    return sa.func.ln(arg) / sa.func.ln(base)\n\n\ndef _log(t, expr):\n    arg, base = expr.op().args\n    sa_arg = t.translate(arg)\n    if base is not None:\n        sa_base = t.translate(base)\n        try:\n            base_value = sa_base.value\n        except AttributeError:\n            return _generic_log(sa_arg, sa_base)\n        else:\n            func = _LOG_BASE_FUNCS.get(base_value, _generic_log)\n            return func(sa_arg)\n    return sa.func.ln(sa_arg)\n\n\ndef _timestamp_from_unix(t, expr):\n    op = expr.op()\n    arg, unit = op.args\n    arg = t.translate(arg)\n\n    if unit in {\"us\", \"ns\"}:\n        raise ValueError(f\"`{unit}` unit is not supported!\")\n\n    if unit == \"ms\":\n        return sa.func.epoch_ms(arg)\n    elif unit == \"s\":\n        return sa.func.to_timestamp(arg)\n\n\ndef _literal(_, expr):\n    dtype = expr.type()\n    sqla_type = to_sqla_type(dtype)\n    op = expr.op()\n    value = op.value\n\n    if isinstance(dtype, dt.Interval):\n        return sa.text(f\"INTERVAL '{value} {dtype.resolution}'\")\n    elif isinstance(dtype, dt.Set) or (\n        isinstance(value, collections.abc.Sequence)\n        and not isinstance(value, str)\n    ):\n        return sa.cast(sa.func.list_value(*value), sqla_type)\n    elif isinstance(value, np.ndarray):\n        return sa.cast(sa.func.list_value(*value.tolist()), sqla_type)\n    elif isinstance(value, collections.abc.Mapping):\n        if isinstance(dtype, dt.Struct):\n            placeholders = \", \".join(\n                f\"{key!r}: :v{i}\" for i, key in enumerate(value.keys())\n            )\n            return sa.text(f\"{{{placeholders}}}\").bindparams(\n                *(\n                    sa.bindparam(f\"v{i:d}\", val)\n                    for i, val in enumerate(value.values())\n                )\n            )\n        raise NotImplementedError(\n            f\"Ibis dtype `{dtype}` with mapping type \"\n            f\"`{type(value).__name__}` isn't yet supported with the duckdb \"\n            \"backend\"\n        )\n    return sa.cast(sa.literal(value), sqla_type)\n\n\ndef _array_column(t, expr):\n    (arg,) = expr.op().args\n    sqla_type = to_sqla_type(expr.type())\n    return sa.cast(sa.func.list_value(*map(t.translate, arg)), sqla_type)\n\n\ndef _struct_field(t, expr):\n    op = expr.op()\n    return sa.func.struct_extract(\n        t.translate(op.arg),\n        sa.text(repr(op.field)),\n        type_=to_sqla_type(expr.type()),\n    )\n\n\ndef _regex_extract(t, expr):\n    string, pattern, index = map(t.translate, expr.op().args)\n    result = sa.case(\n        [\n            (\n                sa.func.regexp_matches(string, pattern),\n                sa.func.regexp_extract(\n                    string,\n                    pattern,\n                    # DuckDB requires the index to be a constant so we compile\n                    # the value and inline it using sa.text\n                    sa.text(\n                        str(\n                            (index + 1).compile(\n                                compile_kwargs=dict(literal_binds=True)\n                            )\n                        )\n                    ),\n                ),\n            )\n        ],\n        else_=\"\",\n    )\n    return result\n\n\noperation_registry.update(\n    {\n        ops.ArrayColumn: _array_column,\n        ops.ArrayConcat: fixed_arity('array_concat', 2),\n        ops.ArrayIndex: fixed_arity('list_element', 2),\n        ops.DayOfWeekName: unary(sa.func.dayname),\n        ops.Literal: _literal,\n        ops.Log2: unary(sa.func.log2),\n        ops.Ln: unary(sa.func.ln),\n        ops.Log: _log,\n        # TODO: map operations, but DuckDB's maps are multimaps\n        ops.Modulus: fixed_arity(operator.mod, 2),\n        ops.Round: _round,\n        ops.StructField: _struct_field,\n        ops.TableColumn: _table_column,\n        ops.TimestampDiff: fixed_arity('age', 2),\n        ops.TimestampFromUNIX: _timestamp_from_unix,\n        ops.Translate: fixed_arity('replace', 3),\n        ops.TimestampNow: fixed_arity('now', 0),\n        ops.RegexExtract: _regex_extract,\n        ops.RegexReplace: fixed_arity(\"regexp_replace\", 3),\n    }\n)\n", "path": "ibis/backends/duckdb/registry.py"}]}