1616
1717*/
1818use crate :: mapping:: RustSqlMapping ;
19+ use crate :: pgrx_attribute:: { ArgValue , PgrxArg , PgrxAttribute } ;
1920use crate :: pgrx_sql:: PgrxSql ;
2021use crate :: to_sql:: entity:: ToSqlConfigEntity ;
2122use crate :: to_sql:: ToSql ;
2223use crate :: { SqlGraphEntity , SqlGraphIdentifier , TypeMatch } ;
24+ use eyre:: eyre;
25+ use proc_macro2:: TokenStream ;
26+ use quote:: { format_ident, quote, ToTokens , TokenStreamExt } ;
2327use 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+ }
2493
25- use eyre:: eyre;
2694/// The output of a [`PostgresType`](crate::postgres_type::PostgresTypeDerive) from `quote::ToTokens::to_tokens`.
2795#[ derive( Debug , Clone , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
2896pub struct PostgresTypeEntity {
@@ -37,6 +105,7 @@ pub struct PostgresTypeEntity {
37105 pub out_fn : & ' static str ,
38106 pub out_fn_module_path : String ,
39107 pub to_sql_config : ToSqlConfigEntity ,
108+ pub alignment : Option < usize > ,
40109}
41110
42111impl TypeMatch for PostgresTypeEntity {
@@ -82,6 +151,7 @@ impl ToSql for PostgresTypeEntity {
82151 out_fn,
83152 out_fn_module_path,
84153 in_fn,
154+ alignment,
85155 ..
86156 } ) = item_node
87157 else {
@@ -155,6 +225,21 @@ impl ToSql for PostgresTypeEntity {
155225 schema = context. schema_prefix_for( & self_index) ,
156226 ) ;
157227
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+
158243 let materialized_type = format ! {
159244 "\n \
160245 -- {file}:{line}\n \
@@ -163,7 +248,7 @@ impl ToSql for PostgresTypeEntity {
163248 \t INTERNALLENGTH = variable,\n \
164249 \t INPUT = {schema_prefix_in_fn}{in_fn}, /* {in_fn_path} */\n \
165250 \t OUTPUT = {schema_prefix_out_fn}{out_fn}, /* {out_fn_path} */\n \
166- \t STORAGE = extended\n \
251+ \t STORAGE = extended{alignment} \n \
167252 );\
168253 ",
169254 schema = context. schema_prefix_for( & self_index) ,
0 commit comments