File Coverage

blib/lib/Class/ReluctantORM/Driver/PostgreSQL/Parsing.pm
Criterion Covered Total %
statement 12 42 28.5
branch 0 6 0.0
condition n/a
subroutine 4 8 50.0
pod 3 3 100.0
total 19 59 32.2


line stmt bran cond sub pod time code
1             package Class::ReluctantORM::Driver::PostgreSQL;
2             # This is a continuation
3              
4 1     1   5 use strict;
  1         2  
  1         44  
5 1     1   6 use warnings;
  1         2  
  1         26  
6              
7 1     1   6 use Class::ReluctantORM::Exception;
  1         2  
  1         60  
8 1     1   648 use Class::ReluctantORM::SQL::Parser;
  1         5  
  1         484  
9              
10             our $PARSER = Class::ReluctantORM::SQL::Parser->new();
11              
12             =head1 NAME
13              
14             Class::ReluctantORM::Driver::PostgreSQL::Parsing - Parse Support for CRO PG Driver
15              
16             =head1 DESCRIPTION
17              
18             This module provides Class::ReluctantORM::Driver parsing support for PostgreSQL. It can parse some, but by no means all, DML statements.
19              
20              
21             =head1 LIMITATIONS AND LAMENTATIONS
22              
23             Since this module is based on SQL::Parser 1.xx, it has all the strengths and weaknesses of that module. In particular, we can't actually define a BNF grammar, instead we rely on Dialects and Features, which can be troublesome.
24              
25             CRO introduces some limitations as well.
26              
27             =over
28              
29             =item Only supports SELECT, INSERT, UPDATE, DELETE statements. No DDL.
30              
31             =item Can only parse one statement - no enormous scripts.
32              
33             =item No SQL support for transactional statements (BEGIN, COMMIT, ROLLBACK) though the API may support this.
34              
35             =back
36              
37             =cut
38              
39             =head2 $true = $driver->supports_parsing();
40              
41             Returns true. Hubris!
42              
43             =cut
44              
45 0     0 1   sub supports_parsing { return 1; }
46              
47             =head2 $sql_obj = $driver->parse_statement($string, \%options);
48              
49             Tries to parse the given string as a single statement. Returns a Class::ReluctantORM::SQL on success. Throws an exception if a problem occured.
50              
51             No options as yet.
52              
53             =cut
54              
55             sub parse_statement {
56 0     0 1   Class::ReluctantORM::Exception::NotImplemented->croak();
57             }
58              
59             =head2 $sql_where = $driver->parse_where($string, \%options);
60              
61             Tries to parse the given string as a where clause without the where. Returns a Class::ReluctantORM::SQL::Where on success. Throws an exception if a problem occured.
62              
63             No options as yet.
64              
65             =cut
66              
67             sub parse_where {
68 0     0 1   my $driver = shift;
69 0           my $sql_str = shift;
70 0           my $options = shift; # currently ignored, no options
71              
72 0           my $sql = $sql_str;
73              
74             # The approach here is to try to parse it using
75             # SQL::Statement. But since we don't have a table list,
76             # just a where clause, we have to make up a table list.
77             # I know this is basically awful.
78              
79              
80              
81 0           my @fake_tables = qw(fake_table);
82 0           $@ = 1;
83             TABLE_NAME_TRY:
84 0           while ($@) {
85 0           my $str = 'SELECT * FROM ' . __make_fake_join(@fake_tables) . ' WHERE ' . $sql;
86 0           eval {
87 0           $PARSER->parse($str);
88             };
89              
90 0 0         if ($@) {
91 0           my ($new_table) = $@ =~ /Table '(\w+)' referenced but not found/;
92 0 0         if ($new_table) {
93 0           push @fake_tables, $new_table;
94             } else {
95             # Unknown parse error
96 0           last TABLE_NAME_TRY;
97             }
98             }
99             }
100              
101 0 0         if ($@) {
102 0           Class::ReluctantORM::Exception::SQL::ParseError->croak(error => $@, sql => $sql_str);
103             }
104              
105 0           my $horrid_struct = $PARSER->{struct}; # voids warranty
106              
107 0           my $where = Where->new();
108 0           $where->{orig_str} = $sql_str;
109 0           $where->{root} = $PARSER->__build_crit_from_parse_tree($horrid_struct, $where);
110              
111 0           return $where;
112             }
113              
114             sub __make_fake_join {
115 0     0     my @tables = @_;
116              
117 0           return join (' JOIN ', @tables);
118              
119 0           my $str = shift @tables;
120 0           while (@tables) {
121 0           $str .= ' JOIN ' . (shift(@tables)) . ' USING foo ';
122             }
123 0           return $str;
124             }
125              
126             # Inherit parse_order_by
127              
128              
129             1;
130              
131