Merge branch '2014.11-develop' into 2015.11
[tine20] / tine20 / Tinebase / Backend / Sql / Command / Pgsql.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Backend
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @author      Fl├ívio Gomes da Silva Lisboa <flavio.lisboa@serpro.gov.br>
9  * @copyright   Copyright (c) 2011-2015 Metaways Infosystems GmbH (http://www.metaways.de)
10  */
11
12 /**
13  * encapsulates SQL commands of PostgreSQL database
14  *
15  * @package     Tinebase
16  * @subpackage  Backend
17  */
18 class Tinebase_Backend_Sql_Command_Pgsql implements Tinebase_Backend_Sql_Command_Interface
19 {
20     /**
21      * @var Tinebase_Backend_Sql_Adapter_Pdo_Pgsql
22      */
23     protected $_adapter;
24     
25     /**
26      * @param Tinebase_Backend_Sql_Adapter_Pdo_Pgsql $adapter
27      */
28     public function __construct(Tinebase_Backend_Sql_Adapter_Pdo_Pgsql $adapter)
29     {
30         $this->_adapter = $adapter;
31     }
32     
33     /**
34      * @param string $field
35      * @return string
36      */
37     public function getAggregate($field)
38     {
39         $quotedField = $this->_adapter->quoteIdentifier($field);
40         
41         // since 9.0
42         #return new Zend_Db_Expr("string_agg(DISTINCT $quotedField, ',')");
43         
44         // before 9.0
45         return new Zend_Db_Expr("array_to_string(ARRAY(SELECT DISTINCT unnest(array_agg($quotedField))),',')");
46     }
47     
48     /**
49      * returns concatenation expression
50      *
51      * @param array $values
52      */
53     public function getConcat($values)
54     {
55         $str = '';
56         $i   = 1;
57         $vc  = count($values);
58         
59         foreach($values as $value) {
60             $str .= $value;
61             if ($i < $vc) {
62                 $str .= ' || ';
63             }
64             $i++;
65         }
66         
67         return new Zend_Db_Expr($str);
68     }
69     
70     /**
71      * @param string $field
72      * @param mixed $returnIfTrue
73      * @param mixed $returnIfFalse
74      * @return string
75      */
76     public function getIfIsNull($field, $returnIfTrue, $returnIfFalse)
77     {
78         $quotedField = $this->_adapter->quoteIdentifier($field);
79         
80         return new Zend_Db_Expr("(CASE WHEN $quotedField IS NULL THEN $returnIfTrue ELSE $returnIfFalse END)");
81     }
82     
83     /**
84      * @param Zend_Db_Adapter_Abstract $adapter
85      * @param string $condition
86      * @param string $returnIfTrue
87      * @param string $returnIfFalse
88      * @return string
89      */
90     public function getIfElse($condition, $returnIfTrue, $returnIfFalse)
91     {
92         return new Zend_Db_Expr("(CASE WHEN $condition THEN $returnIfTrue ELSE $returnIfFalse END)");
93     }
94     
95     /**
96      * get get switch case expression with multiple cases
97      * 
98      * @param string $field
99      * @param array $cases
100      * 
101      * @return Zend_Db_Expr
102      */
103     public function getSwitch($field, $cases)
104     {
105         $case = 'CASE ' . $this->_adapter->quoteIdentifier($field) . ' ';
106         foreach ($cases as $when => $then) {
107             $case .=  $this->_adapter->quoteInto(' WHEN ' . $when . ' THEN ?', $then);
108         }
109         $case .= ' END';
110         return new Zend_Db_Expr($case);
111     }
112     
113     /**
114      * @param string $date
115      * @return string
116      */
117     public function setDate($date)
118     {
119         return "DATE({$date})";
120     }
121     
122     /**
123      * @param string $value
124      * @return string
125      */
126     public function setDateValue($value)
127     {
128         return $this->_adapter->quote($value);
129     }
130     
131     /**
132      * @return mixed
133      */
134     public function getFalseValue()
135     {
136         return 'FALSE';
137     }
138     
139     /**
140      * @return mixed
141      */
142     public function getTrueValue()
143     {
144         return 'TRUE';
145     }
146     
147     /**
148      * @return string
149      */
150     public function setDatabaseJokerCharacters()
151     {
152         return array('%', '\_');
153     }
154     
155     /**
156      * get like keyword
157      *
158      * @return string
159      */
160     public function getLike()
161     {
162         return 'iLIKE';
163     }
164     
165     /**
166      * prepare value for case insensitive search
167      *
168      * @param string $value
169      * @return string
170      */
171     public function prepareForILike($value)
172     {
173         return $value;
174     }
175     
176     /**
177      * Even if the database backend is PostgreSQL, we have to verify
178      *  if the extension Unaccent is installed and loaded.
179      *  This is done in Tinebase_Core::checkUnaccentExtension.
180      *
181      * @return boolean
182      */
183     protected function _hasUnaccentExtension()
184     {
185         try {
186             $session = Tinebase_Session::getSessionNamespace();
187             
188             if (isset($session->dbcapabilities) && (isset($session->dbcapabilities['unaccent']) || array_key_exists('unaccent', $session->dbcapabilities))) {
189                 $result = $session->dbcapabilities['unaccent'];
190             } else {
191                 $result = $this->_adapter->hasUnaccentExtension();
192                 
193                 $capabilities['unaccent'] = $result;
194                 
195                 $session->dbcapabilities = $capabilities;
196             }
197             
198         } catch (Zend_Session_Exception $zse) {
199             $result = $this->_adapter->hasUnaccentExtension();
200         }
201         
202         return $result;
203     }
204     
205     /**
206      * returns field without accents (diacritic signs) - for Pgsql;
207      *
208      * @param string $field
209      * @return string
210      */
211     public function getUnaccent($field)
212     {
213         if ($this->_hasUnaccentExtension()){
214             return ' unaccent('.$field.') ';
215         } else{
216             return $field;
217         }
218     }
219     
220     /**
221      * escape special char
222      *
223      * @return string
224      */
225      public function escapeSpecialChar($value)
226      {
227          return str_replace('\\', '\\\\', $value);
228      }
229      
230      /**
231       * Initializes database procedures
232       * @param Setup_Backend_Interface $backend
233       */
234      public function initProcedures(Setup_Backend_Interface $backend)
235      {
236
237      }
238
239     /**
240      * returns something similar to "(interval '$staticPart $timeUnit' * $dynamicPart)"
241      *
242      * @see http://www.postgresql.org/docs/9.1/static/functions-datetime.html
243      *
244      * @param string $timeUnit
245      * @param string $staticPart
246      * @param string $dynamicPart
247      * @return string
248      */
249     public function getDynamicInterval($timeUnit, $staticPart, $dynamicPart)
250     {
251         return '(' . $this->getInterval($timeUnit, $staticPart) .  ' * ' . $dynamicPart . ')';
252     }
253
254     /**
255      * returns something similar to "interval '$staticPart $timeUnit'"
256      *
257      * @param string $timeUnit
258      * @param string $staticPart
259      * @return string
260      */
261     public function getInterval($timeUnit, $staticPart)
262     {
263         return "INTERVAL '" . $staticPart . ' ' . $timeUnit . "'";
264     }
265 }