1use std::ops::Range;
2
3use serde::Deserialize;
4use serde_json::Value;
5use sqlx_core::{
6 decode::Decode,
7 encode::{Encode, IsNull},
8 error::BoxDynError,
9 types::Type,
10};
11
12use crate::{
13 arguments::ExaBuffer,
14 database::Exasol,
15 type_info::{Decimal, ExaDataType, ExaTypeInfo},
16 value::ExaValueRef,
17};
18
19const MIN_I64_NUMERIC: i64 = -999_999_999_999_999_999;
20const MAX_I64_NUMERIC: i64 = 1_000_000_000_000_000_000;
21const MIN_I128_NUMERIC: i128 = -999_999_999_999_999_999;
22const MAX_I128_NUMERIC: i128 = 1_000_000_000_000_000_000;
23
24const NUMERIC_I64_RANGE: Range<i64> = MIN_I64_NUMERIC..MAX_I64_NUMERIC;
27const NUMERIC_I128_RANGE: Range<i128> = MIN_I128_NUMERIC..MAX_I128_NUMERIC;
28
29impl Type<Exasol> for i8 {
30 fn type_info() -> ExaTypeInfo {
31 ExaDataType::Decimal(Decimal::new(Decimal::MAX_8BIT_PRECISION, 0)).into()
32 }
33
34 fn compatible(ty: &ExaTypeInfo) -> bool {
35 <Self as Type<Exasol>>::type_info().compatible(ty)
36 }
37}
38
39impl Encode<'_, Exasol> for i8 {
40 fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
41 buf.append(self)?;
42 Ok(IsNull::No)
43 }
44
45 fn produces(&self) -> Option<ExaTypeInfo> {
46 let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
47 Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
48 }
49
50 fn size_hint(&self) -> usize {
51 1 + Decimal::MAX_8BIT_PRECISION as usize
53 }
54}
55
56impl Decode<'_, Exasol> for i8 {
57 fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
58 <Self as Deserialize>::deserialize(value.value).map_err(From::from)
59 }
60}
61
62impl Type<Exasol> for i16 {
63 fn type_info() -> ExaTypeInfo {
64 ExaDataType::Decimal(Decimal::new(Decimal::MAX_16BIT_PRECISION, 0)).into()
65 }
66
67 fn compatible(ty: &ExaTypeInfo) -> bool {
68 <Self as Type<Exasol>>::type_info().compatible(ty)
69 }
70}
71
72impl Encode<'_, Exasol> for i16 {
73 fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
74 buf.append(self)?;
75 Ok(IsNull::No)
76 }
77
78 fn produces(&self) -> Option<ExaTypeInfo> {
79 let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
80 Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
81 }
82
83 fn size_hint(&self) -> usize {
84 1 + Decimal::MAX_16BIT_PRECISION as usize
86 }
87}
88
89impl Decode<'_, Exasol> for i16 {
90 fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
91 <Self as Deserialize>::deserialize(value.value).map_err(From::from)
92 }
93}
94
95impl Type<Exasol> for i32 {
96 fn type_info() -> ExaTypeInfo {
97 ExaDataType::Decimal(Decimal::new(Decimal::MAX_32BIT_PRECISION, 0)).into()
98 }
99
100 fn compatible(ty: &ExaTypeInfo) -> bool {
101 <Self as Type<Exasol>>::type_info().compatible(ty)
102 }
103}
104
105impl Encode<'_, Exasol> for i32 {
106 fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
107 buf.append(self)?;
108 Ok(IsNull::No)
109 }
110
111 fn produces(&self) -> Option<ExaTypeInfo> {
112 let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
113 Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
114 }
115
116 fn size_hint(&self) -> usize {
117 1 + Decimal::MAX_32BIT_PRECISION as usize
119 }
120}
121
122impl Decode<'_, Exasol> for i32 {
123 fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
124 <Self as Deserialize>::deserialize(value.value).map_err(From::from)
125 }
126}
127
128impl Type<Exasol> for i64 {
129 fn type_info() -> ExaTypeInfo {
130 ExaDataType::Decimal(Decimal::new(Decimal::MAX_64BIT_PRECISION, 0)).into()
131 }
132
133 fn compatible(ty: &ExaTypeInfo) -> bool {
134 <Self as Type<Exasol>>::type_info().compatible(ty)
135 }
136}
137
138impl Encode<'_, Exasol> for i64 {
139 fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
140 if NUMERIC_I64_RANGE.contains(self) {
141 buf.append(self)?;
142 } else {
143 buf.append(format_args!("{self}"))?;
145 };
146
147 Ok(IsNull::No)
148 }
149
150 fn produces(&self) -> Option<ExaTypeInfo> {
151 let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
152 Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
153 }
154
155 fn size_hint(&self) -> usize {
156 1 + Decimal::MAX_64BIT_PRECISION as usize
158 }
159}
160
161impl Decode<'_, Exasol> for i64 {
162 fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
163 match value.value {
164 Value::Number(n) => <Self as Deserialize>::deserialize(n).map_err(From::from),
165 Value::String(s) => serde_json::from_str(s).map_err(From::from),
166 v => Err(format!("invalid i64 value: {v}").into()),
167 }
168 }
169}
170
171impl Type<Exasol> for i128 {
172 fn type_info() -> ExaTypeInfo {
173 ExaDataType::Decimal(Decimal::new(Decimal::MAX_128BIT_PRECISION, 0)).into()
174 }
175
176 fn compatible(ty: &ExaTypeInfo) -> bool {
177 <Self as Type<Exasol>>::type_info().compatible(ty)
178 }
179}
180
181impl Encode<'_, Exasol> for i128 {
182 fn encode_by_ref(&self, buf: &mut ExaBuffer) -> Result<IsNull, BoxDynError> {
183 if NUMERIC_I128_RANGE.contains(self) {
184 buf.append(self)?;
185 } else {
186 buf.append(format_args!("{self}"))?;
188 };
189
190 Ok(IsNull::No)
191 }
192
193 fn produces(&self) -> Option<ExaTypeInfo> {
194 let precision = self.unsigned_abs().checked_ilog10().unwrap_or_default() + 1;
195 Some(ExaDataType::Decimal(Decimal::new(precision, 0)).into())
196 }
197
198 fn size_hint(&self) -> usize {
199 1 + Decimal::MAX_128BIT_PRECISION as usize
201 }
202}
203
204impl Decode<'_, Exasol> for i128 {
205 fn decode(value: ExaValueRef<'_>) -> Result<Self, BoxDynError> {
206 match value.value {
207 Value::Number(n) => <Self as Deserialize>::deserialize(n).map_err(From::from),
208 Value::String(s) => serde_json::from_str(s).map_err(From::from),
209 v => Err(format!("invalid i128 value: {v}").into()),
210 }
211 }
212}