Skip to content

Commit 3379576

Browse files
beneschjkosh44
andcommitted
Merge remote-tracking branch 'sfackler/master'
Co-authored-by: Joseph Koshakow <koshy44@gmail.com>
2 parents abff35e + 5ebe602 commit 3379576

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1180
-469
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
- run: docker compose up -d
5656
- uses: sfackler/actions/rustup@master
5757
with:
58-
version: 1.56.0
58+
version: 1.62.0
5959
- run: echo "::set-output name=version::$(rustc --version)"
6060
id: rust-version
6161
- uses: actions/cache@v1

codegen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["Steven Fackler <sfackler@gmail.com>"]
55

66
[dependencies]
7-
phf_codegen = "0.10"
7+
phf_codegen = "0.11"
88
regex = "1.0"
99
marksman_escape = "0.1"
1010
linked-hash-map = "0.5"

codegen/src/errcodes.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# errcodes.txt
33
# PostgreSQL error codes
44
#
5-
# Copyright (c) 2003-2020, PostgreSQL Global Development Group
5+
# Copyright (c) 2003-2022, PostgreSQL Global Development Group
66
#
77
# This list serves as the basis for generating source files containing error
88
# codes. It is kept in a common format to make sure all these source files have
@@ -222,6 +222,7 @@ Section: Class 22 - Data Exception
222222
2203D E ERRCODE_TOO_MANY_JSON_ARRAY_ELEMENTS too_many_json_array_elements
223223
2203E E ERRCODE_TOO_MANY_JSON_OBJECT_MEMBERS too_many_json_object_members
224224
2203F E ERRCODE_SQL_JSON_SCALAR_REQUIRED sql_json_scalar_required
225+
2203G E ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE sql_json_item_cannot_be_cast_to_target_type
225226

226227
Section: Class 23 - Integrity Constraint Violation
227228

@@ -428,6 +429,7 @@ Section: Class 57 - Operator Intervention
428429
57P02 E ERRCODE_CRASH_SHUTDOWN crash_shutdown
429430
57P03 E ERRCODE_CANNOT_CONNECT_NOW cannot_connect_now
430431
57P04 E ERRCODE_DATABASE_DROPPED database_dropped
432+
57P05 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout
431433

432434
Section: Class 58 - System Error (errors external to PostgreSQL itself)
433435

codegen/src/pg_range.dat

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# pg_range.dat
44
# Initial contents of the pg_range system catalog.
55
#
6-
# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
6+
# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
77
# Portions Copyright (c) 1994, Regents of the University of California
88
#
99
# src/include/catalog/pg_range.dat
@@ -12,20 +12,23 @@
1212

1313
[
1414

15-
{ rngtypid => 'int4range', rngsubtype => 'int4', rngsubopc => 'btree/int4_ops',
15+
{ rngtypid => 'int4range', rngsubtype => 'int4',
16+
rngmultitypid => 'int4multirange', rngsubopc => 'btree/int4_ops',
1617
rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' },
1718
{ rngtypid => 'numrange', rngsubtype => 'numeric',
18-
rngsubopc => 'btree/numeric_ops', rngcanonical => '-',
19-
rngsubdiff => 'numrange_subdiff' },
19+
rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops',
20+
rngcanonical => '-', rngsubdiff => 'numrange_subdiff' },
2021
{ rngtypid => 'tsrange', rngsubtype => 'timestamp',
21-
rngsubopc => 'btree/timestamp_ops', rngcanonical => '-',
22-
rngsubdiff => 'tsrange_subdiff' },
22+
rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops',
23+
rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' },
2324
{ rngtypid => 'tstzrange', rngsubtype => 'timestamptz',
24-
rngsubopc => 'btree/timestamptz_ops', rngcanonical => '-',
25-
rngsubdiff => 'tstzrange_subdiff' },
26-
{ rngtypid => 'daterange', rngsubtype => 'date', rngsubopc => 'btree/date_ops',
25+
rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops',
26+
rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' },
27+
{ rngtypid => 'daterange', rngsubtype => 'date',
28+
rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops',
2729
rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' },
28-
{ rngtypid => 'int8range', rngsubtype => 'int8', rngsubopc => 'btree/int8_ops',
30+
{ rngtypid => 'int8range', rngsubtype => 'int8',
31+
rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops',
2932
rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff' },
3033

3134
]

codegen/src/pg_type.dat

Lines changed: 111 additions & 49 deletions
Large diffs are not rendered by default.

codegen/src/type_gen.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct Type {
1717
variant: String,
1818
ident: String,
1919
kind: String,
20+
typtype: Option<String>,
2021
element: u32,
2122
doc: String,
2223
}
@@ -185,6 +186,15 @@ fn parse_types() -> BTreeMap<u32, Type> {
185186
)
186187
})
187188
.collect::<HashMap<_, _>>();
189+
let multi_range_elements = raw_ranges
190+
.iter()
191+
.map(|m| {
192+
(
193+
oids_by_name[&*m["rngmultitypid"]],
194+
oids_by_name[&*m["rngsubtype"]],
195+
)
196+
})
197+
.collect::<HashMap<_, _>>();
188198

189199
let range_vector_re = Regex::new("(range|vector)$").unwrap();
190200
let array_re = Regex::new("^_(.*)").unwrap();
@@ -208,8 +218,18 @@ fn parse_types() -> BTreeMap<u32, Type> {
208218
continue;
209219
}
210220

221+
let typtype = raw_type.get("typtype").cloned();
222+
211223
let element = match &*kind {
212-
"R" => range_elements[&oid],
224+
"R" => match typtype
225+
.as_ref()
226+
.expect("range type must have typtype")
227+
.as_str()
228+
{
229+
"r" => range_elements[&oid],
230+
"m" => multi_range_elements[&oid],
231+
typtype => panic!("invalid range typtype {}", typtype),
232+
},
213233
"A" => oids_by_name[&raw_type["typelem"]],
214234
_ => 0,
215235
};
@@ -235,6 +255,7 @@ fn parse_types() -> BTreeMap<u32, Type> {
235255
variant,
236256
ident,
237257
kind: "A".to_string(),
258+
typtype: None,
238259
element: oid,
239260
doc,
240261
};
@@ -246,6 +267,7 @@ fn parse_types() -> BTreeMap<u32, Type> {
246267
variant,
247268
ident,
248269
kind,
270+
typtype,
249271
element,
250272
doc,
251273
};
@@ -349,7 +371,16 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
349371
let kind = match &*type_.kind {
350372
"P" => "Pseudo".to_owned(),
351373
"A" => format!("Array(Type(Inner::{}))", types[&type_.element].variant),
352-
"R" => format!("Range(Type(Inner::{}))", types[&type_.element].variant),
374+
"R" => match type_
375+
.typtype
376+
.as_ref()
377+
.expect("range type must have typtype")
378+
.as_str()
379+
{
380+
"r" => format!("Range(Type(Inner::{}))", types[&type_.element].variant),
381+
"m" => format!("Multirange(Type(Inner::{}))", types[&type_.element].variant),
382+
typtype => panic!("invalid range typtype {}", typtype),
383+
},
353384
_ => "Simple".to_owned(),
354385
};
355386

postgres-derive-test/src/composites.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::test_type;
1+
use crate::{test_type, test_type_asymmetric};
22
use postgres::{Client, NoTls};
33
use postgres_types::{FromSql, ToSql, WrongType};
44
use std::error::Error;
@@ -238,3 +238,68 @@ fn raw_ident_field() {
238238

239239
test_type(&mut conn, "inventory_item", &[(item, "ROW('foo')")]);
240240
}
241+
242+
#[test]
243+
fn generics() {
244+
#[derive(FromSql, Debug, PartialEq)]
245+
struct InventoryItem<T: Clone, U>
246+
where
247+
U: Clone,
248+
{
249+
name: String,
250+
supplier_id: T,
251+
price: Option<U>,
252+
}
253+
254+
// doesn't make sense to implement derived FromSql on a type with borrows
255+
#[derive(ToSql, Debug, PartialEq)]
256+
#[postgres(name = "InventoryItem")]
257+
struct InventoryItemRef<'a, T: 'a + Clone, U>
258+
where
259+
U: 'a + Clone,
260+
{
261+
name: &'a str,
262+
supplier_id: &'a T,
263+
price: Option<&'a U>,
264+
}
265+
266+
const NAME: &str = "foobar";
267+
const SUPPLIER_ID: i32 = 100;
268+
const PRICE: f64 = 15.50;
269+
270+
let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap();
271+
conn.batch_execute(
272+
"CREATE TYPE pg_temp.\"InventoryItem\" AS (
273+
name TEXT,
274+
supplier_id INT,
275+
price DOUBLE PRECISION
276+
);",
277+
)
278+
.unwrap();
279+
280+
let item = InventoryItemRef {
281+
name: NAME,
282+
supplier_id: &SUPPLIER_ID,
283+
price: Some(&PRICE),
284+
};
285+
286+
let item_null = InventoryItemRef {
287+
name: NAME,
288+
supplier_id: &SUPPLIER_ID,
289+
price: None,
290+
};
291+
292+
test_type_asymmetric(
293+
&mut conn,
294+
"\"InventoryItem\"",
295+
&[
296+
(item, "ROW('foobar', 100, 15.50)"),
297+
(item_null, "ROW('foobar', 100, NULL)"),
298+
],
299+
|t: &InventoryItemRef<i32, f64>, f: &InventoryItem<i32, f64>| {
300+
t.name == f.name.as_str()
301+
&& t.supplier_id == &f.supplier_id
302+
&& t.price == f.price.as_ref()
303+
},
304+
);
305+
}

postgres-derive-test/src/lib.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,41 @@ where
1616
{
1717
for &(ref val, ref repr) in checks.iter() {
1818
let stmt = conn
19-
.prepare(&*format!("SELECT {}::{}", *repr, sql_type))
19+
.prepare(&format!("SELECT {}::{}", *repr, sql_type))
2020
.unwrap();
2121
let result = conn.query_one(&stmt, &[]).unwrap().get(0);
2222
assert_eq!(val, &result);
2323

24-
let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap();
24+
let stmt = conn.prepare(&format!("SELECT $1::{}", sql_type)).unwrap();
2525
let result = conn.query_one(&stmt, &[val]).unwrap().get(0);
2626
assert_eq!(val, &result);
2727
}
2828
}
2929

30+
pub fn test_type_asymmetric<T, F, S, C>(
31+
conn: &mut Client,
32+
sql_type: &str,
33+
checks: &[(T, S)],
34+
cmp: C,
35+
) where
36+
T: ToSql + Sync,
37+
F: FromSqlOwned,
38+
S: fmt::Display,
39+
C: Fn(&T, &F) -> bool,
40+
{
41+
for &(ref val, ref repr) in checks.iter() {
42+
let stmt = conn
43+
.prepare(&format!("SELECT {}::{}", *repr, sql_type))
44+
.unwrap();
45+
let result: F = conn.query_one(&stmt, &[]).unwrap().get(0);
46+
assert!(cmp(val, &result));
47+
48+
let stmt = conn.prepare(&format!("SELECT $1::{}", sql_type)).unwrap();
49+
let result: F = conn.query_one(&stmt, &[val]).unwrap().get(0);
50+
assert!(cmp(val, &result));
51+
}
52+
}
53+
3054
#[test]
3155
fn compile_fail() {
3256
trybuild::TestCases::new().compile_fail("src/compile-fail/*.rs");

postgres-derive/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Change Log
22

3+
## v0.4.3 - 2022-09-07
4+
5+
### Added
6+
7+
* Added support for parameterized structs.
8+
39
## v0.4.2 - 2022-04-30
410

511
### Added

postgres-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "postgres-derive"
3-
version = "0.4.2"
3+
version = "0.4.3"
44
authors = ["Steven Fackler <sfackler@palantir.com>"]
55
license = "MIT/Apache-2.0"
66
edition = "2018"

postgres-derive/src/composites.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use syn::{Error, Ident, Type};
1+
use proc_macro2::Span;
2+
use syn::{
3+
punctuated::Punctuated, Error, GenericParam, Generics, Ident, Path, PathSegment, Type,
4+
TypeParamBound,
5+
};
26

37
use crate::overrides::Overrides;
48

@@ -26,3 +30,23 @@ impl Field {
2630
})
2731
}
2832
}
33+
34+
pub(crate) fn append_generic_bound(mut generics: Generics, bound: &TypeParamBound) -> Generics {
35+
for param in &mut generics.params {
36+
if let GenericParam::Type(param) = param {
37+
param.bounds.push(bound.to_owned())
38+
}
39+
}
40+
generics
41+
}
42+
43+
pub(crate) fn new_derive_path(last: PathSegment) -> Path {
44+
let mut path = Path {
45+
leading_colon: None,
46+
segments: Punctuated::new(),
47+
};
48+
path.segments
49+
.push(Ident::new("postgres_types", Span::call_site()).into());
50+
path.segments.push(last);
51+
path
52+
}

0 commit comments

Comments
 (0)