File Coverage

blib/lib/Pg/Priv.pm
Criterion Covered Total %
statement 56 56 100.0
branch 18 20 90.0
condition 6 7 85.7
subroutine 27 27 100.0
pod 22 22 100.0
total 129 132 97.7


line stmt bran cond sub pod time code
1             package Pg::Priv;
2              
3 3     3   82057 use 5.8.0;
  3         11  
  3         154  
4 3     3   19 use strict;
  3         7  
  3         126  
5 3     3   16 use warnings;
  3         21  
  3         3624  
6              
7             our $VERSION = '0.12';
8              
9             my %label_for = (
10             r => 'SELECT',
11             w => 'UPDATE',
12             a => 'INSERT',
13             d => 'DELETE',
14             D => 'TRUNCATE',
15             x => 'REFERENCE',
16             t => 'TRIGGER',
17             X => 'EXECUTE',
18             U => 'USAGE',
19             C => 'CREATE',
20             c => 'CONNECT',
21             T => 'TEMPORARY',
22             );
23              
24             my %priv_for = map { $label_for{$_} => $_ } keys %label_for;
25              
26             # Some aliases.
27             $priv_for{TEMP} = 'T';
28              
29             sub parse_acl {
30 21     21 1 4524 my ($class, $acl, $quote) = @_;
31 21 50       66 return unless $acl;
32              
33 21         27 my @privs;
34             my $prev;
35 21         32 for my $perms (@{ $acl }) {
  21         44  
36             # http://www.postgresql.org/docs/current/static/sql-grant.html#SQL-GRANT-NOTES
37 36         278 my ($role, $privs, $by) = $perms =~ m{^"?(?:(?:group\s+)?([^=]+))?=([^/]+)/(.*)};
38 36 100       92 $prev = $privs eq '*' ? $prev : $privs;
39 36   100     95 $role ||= 'public';
40 36 100       140 push @privs, $class->new(
    100          
41             to => $quote ? _quote_ident($role) : $role,
42             by => $quote ? _quote_ident($by) : $by,
43             privs => $prev,
44             )
45             }
46 21 100       140 return wantarray ? @privs : \@privs;
47             }
48              
49             sub new {
50 37     37 1 56 my $class = shift;
51 37         199 my $self = bless { @_ } => $class;
52 37   50     187 $self->{parsed} = { map { $_ => 1 } split //, $self->{privs} || '' };
  183         427  
53 37         174 return $self;
54             }
55              
56 49     49 1 295 sub to { shift->{to} }
57 49     49 1 290 sub by { shift->{by} }
58 25     25 1 134 sub privs { shift->{privs} }
59             sub labels {
60 6         20 wantarray ? map { $label_for{$_} } keys %{ shift->{parsed} }
  1         5  
  6         20  
61 2 100   2 1 6 : [ map { $label_for{$_} } keys %{ shift->{parsed} } ];
  1         4  
62             }
63             sub can {
64 143 50   143 1 12044 my $can = shift->{parsed} or return;
65 143         220 for my $what (@_) {
66 212 100       820 return unless $can->{ length $what == 1 ? $what : $priv_for{uc $what} };
    100          
67             }
68 35         133 return 1;
69             }
70              
71 1     1 1 3 sub can_select { shift->can('r') }
72 1     1 1 3 sub can_read { shift->can('r') }
73 1     1 1 3 sub can_update { shift->can('w') }
74 1     1 1 4 sub can_write { shift->can('w') }
75 1     1 1 4 sub can_insert { shift->can('a') }
76 1     1 1 6 sub can_append { shift->can('a') }
77 1     1 1 2 sub can_delete { shift->can('d') }
78 1     1 1 4 sub can_reference { shift->can('x') }
79 1     1 1 4 sub can_trigger { shift->can('t') }
80 1     1 1 3 sub can_execute { shift->can('X') }
81 1     1 1 3 sub can_usage { shift->can('U') }
82 1     1 1 5 sub can_create { shift->can('C') }
83 1     1 1 3 sub can_connect { shift->can('c') }
84 1     1 1 4 sub can_temporary { shift->can('T') }
85 1     1 1 4 sub can_temp { shift->can('T') }
86              
87             # ack ' RESERVED_KEYWORD' src/include/parser/kwlist.h | awk -F '"' '{ print " " $2 }'
88             my %reserved = ( map { $_ => undef } qw(
89             all
90             analyse
91             analyze
92             and
93             any
94             array
95             as
96             asc
97             asymmetric
98             both
99             case
100             cast
101             check
102             collate
103             column
104             constraint
105             create
106             current_catalog
107             current_date
108             current_role
109             current_time
110             current_timestamp
111             current_user
112             default
113             deferrable
114             desc
115             distinct
116             do
117             else
118             end
119             except
120             false
121             fetch
122             for
123             foreign
124             from
125             grant
126             group
127             having
128             in
129             initially
130             intersect
131             into
132             leading
133             limit
134             localtime
135             localtimestamp
136             new
137             not
138             null
139             off
140             offset
141             old
142             on
143             only
144             or
145             order
146             placing
147             primary
148             references
149             returning
150             select
151             session_user
152             some
153             symmetric
154             table
155             then
156             to
157             trailing
158             true
159             union
160             unique
161             user
162             using
163             variadic
164             when
165             where
166             window
167             with
168             ));
169              
170             sub _is_reserved($) {
171 211     211   44719 exists $reserved{+shift};
172             }
173              
174             sub _quote_ident($) {
175 139     139   7743 my $role = shift;
176             # Can avoid quoting if ident starts with a lowercase letter or underscore
177             # and contains only lowercase letters, digits, and underscores, *and* is
178             # not any SQL keyword. Otherwise, supply quotes.
179 139 100 100     814 return $role if $role =~ /^[_a-z](?:[_a-z0-9]+)?$/ && !_is_reserved $role;
180 86         173 $role =~ s/"/""/g;
181 86         522 return qq{"$role"};
182             }
183              
184             1;
185             __END__