16
16
17
17
*/
18
18
use crate :: mapping:: RustSqlMapping ;
19
+ use crate :: pgrx_attribute:: { ArgValue , PgrxArg , PgrxAttribute } ;
19
20
use crate :: pgrx_sql:: PgrxSql ;
20
21
use crate :: to_sql:: entity:: ToSqlConfigEntity ;
21
22
use crate :: to_sql:: ToSql ;
22
23
use crate :: { SqlGraphEntity , SqlGraphIdentifier , TypeMatch } ;
24
+ use eyre:: eyre;
25
+ use proc_macro2:: TokenStream ;
26
+ use quote:: { format_ident, quote, ToTokens , TokenStreamExt } ;
23
27
use std:: collections:: BTreeSet ;
28
+ use syn:: spanned:: Spanned ;
29
+ use syn:: { AttrStyle , Attribute , Lit } ;
30
+
31
+ #[ derive( Debug , Clone , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
32
+ pub enum Alignment {
33
+ On ,
34
+ Off ,
35
+ }
36
+
37
+ const INVALID_ATTR_CONTENT : & str = r#"expected `#[pgrx(alignment = align)]`, where `align` is "on", or "off""# ;
38
+
39
+ impl ToTokens for Alignment {
40
+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
41
+ let value = match self {
42
+ Alignment :: On => format_ident ! ( "On" ) ,
43
+ Alignment :: Off => format_ident ! ( "Off" ) ,
44
+ } ;
45
+ let quoted = quote ! {
46
+ :: pgrx:: pgrx_sql_entity_graph:: Alignment :: #value
47
+ } ;
48
+ tokens. append_all ( quoted) ;
49
+ }
50
+ }
51
+
52
+ impl Alignment {
53
+ pub fn from_attribute ( attr : & Attribute ) -> Result < Option < Self > , syn:: Error > {
54
+ if attr. style != AttrStyle :: Outer {
55
+ return Err ( syn:: Error :: new (
56
+ attr. span ( ) ,
57
+ "#[pgrx(alignment = ..)] is only valid in an outer context" ,
58
+ ) ) ;
59
+ }
60
+
61
+ let attr = attr. parse_args :: < PgrxAttribute > ( ) ?;
62
+ for arg in attr. args . iter ( ) {
63
+ let PgrxArg :: NameValue ( ref nv) = arg;
64
+ if !nv. path . is_ident ( "alignment" ) {
65
+ continue ;
66
+ }
67
+
68
+ return match nv. value {
69
+ ArgValue :: Lit ( Lit :: Str ( ref s) ) => match s. value ( ) . as_ref ( ) {
70
+ "on" => Ok ( Some ( Self :: On ) ) ,
71
+ "off" => Ok ( Some ( Self :: Off ) ) ,
72
+ _ => Err ( syn:: Error :: new ( s. span ( ) , INVALID_ATTR_CONTENT ) ) ,
73
+ } ,
74
+ ArgValue :: Path ( ref p) => Err ( syn:: Error :: new ( p. span ( ) , INVALID_ATTR_CONTENT ) ) ,
75
+ ArgValue :: Lit ( ref l) => Err ( syn:: Error :: new ( l. span ( ) , INVALID_ATTR_CONTENT ) ) ,
76
+ } ;
77
+ }
78
+
79
+ Ok ( None )
80
+ }
81
+
82
+ pub fn from_attributes ( attrs : & [ Attribute ] ) -> Result < Self , syn:: Error > {
83
+ for attr in attrs {
84
+ if attr. path ( ) . is_ident ( "pgrx" ) {
85
+ if let Some ( v) = Self :: from_attribute ( attr) ? {
86
+ return Ok ( v)
87
+ }
88
+ }
89
+ }
90
+ Ok ( Self :: Off )
91
+ }
92
+ }
24
93
25
- use eyre:: eyre;
26
94
/// The output of a [`PostgresType`](crate::postgres_type::PostgresTypeDerive) from `quote::ToTokens::to_tokens`.
27
95
#[ derive( Debug , Clone , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
28
96
pub struct PostgresTypeEntity {
@@ -37,6 +105,7 @@ pub struct PostgresTypeEntity {
37
105
pub out_fn : & ' static str ,
38
106
pub out_fn_module_path : String ,
39
107
pub to_sql_config : ToSqlConfigEntity ,
108
+ pub alignment : Option < usize > ,
40
109
}
41
110
42
111
impl TypeMatch for PostgresTypeEntity {
@@ -82,6 +151,7 @@ impl ToSql for PostgresTypeEntity {
82
151
out_fn,
83
152
out_fn_module_path,
84
153
in_fn,
154
+ alignment,
85
155
..
86
156
} ) = item_node
87
157
else {
@@ -155,6 +225,21 @@ impl ToSql for PostgresTypeEntity {
155
225
schema = context. schema_prefix_for( & self_index) ,
156
226
) ;
157
227
228
+ let alignment = alignment. map ( |alignment| {
229
+ assert ! ( alignment. is_power_of_two( ) ) ;
230
+ let alignment = match alignment {
231
+ 1 => "char" ,
232
+ 2 => "int2" ,
233
+ 4 => "int4" ,
234
+ 8 | _ => "double" ,
235
+ } ;
236
+ format ! (
237
+ ",\n \
238
+ \t ALIGNMENT = {}",
239
+ alignment
240
+ )
241
+ } ) . unwrap_or_default ( ) ;
242
+
158
243
let materialized_type = format ! {
159
244
"\n \
160
245
-- {file}:{line}\n \
@@ -163,7 +248,7 @@ impl ToSql for PostgresTypeEntity {
163
248
\t INTERNALLENGTH = variable,\n \
164
249
\t INPUT = {schema_prefix_in_fn}{in_fn}, /* {in_fn_path} */\n \
165
250
\t OUTPUT = {schema_prefix_out_fn}{out_fn}, /* {out_fn_path} */\n \
166
- \t STORAGE = extended\n \
251
+ \t STORAGE = extended{alignment} \n \
167
252
);\
168
253
",
169
254
schema = context. schema_prefix_for( & self_index) ,
0 commit comments