1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.com>.
*/
Doctrine::autoload('Doctrine_Connection_Common');
/**
* Doctrine_Connection_Mysql
*
* @package Doctrine
* @subpackage Connection
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @version $Revision$
* @link www.phpdoctrine.com
* @since 1.0
*/
class Doctrine_Connection_Mysql extends Doctrine_Connection_Common
{
/**
* @var string $driverName the name of this connection driver
*/
protected $driverName = 'Mysql';
/**
* the constructor
*
* @param Doctrine_Manager $manager
* @param PDO|Doctrine_Adapter $adapter database handler
*/
public function __construct(Doctrine_Manager $manager, $adapter)
{
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$this->setAttribute(Doctrine::ATTR_DEFAULT_TABLE_TYPE, 'INNODB');
$this->supported = array(
'sequences' => 'emulated',
'indexes' => true,
'affected_rows' => true,
'transactions' => true,
'savepoints' => false,
'summary_functions' => true,
'order_by_text' => true,
'current_id' => 'emulated',
'limit_queries' => true,
'LOBs' => true,
'replace' => true,
'sub_selects' => true,
'auto_increment' => true,
'primary_key' => true,
'result_introspection' => true,
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => true
);
$this->properties['string_quoting'] = array('start' => "'",
'end' => "'",
'escape' => '\\',
'escape_pattern' => '\\');
$this->properties['identifier_quoting'] = array('start' => '`',
'end' => '`',
'escape' => '`');
$this->properties['sql_comments'] = array(
array('start' => '-- ', 'end' => "\n", 'escape' => false),
array('start' => '#', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false),
);
$this->properties['varchar_max_length'] = 255;
parent::__construct($manager, $adapter);
}
/**
* Set the charset on the current connection
*
* @param string charset
*/
public function setCharset($charset)
{
$query = 'SET NAMES ' . $this->quote($charset);
$this->exec($query);
}
/**
* Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT
* query, except that if there is already a row in the table with the same
* key field values, the REPLACE query just updates its values instead of
* inserting a new row.
*
* The REPLACE type of query does not make part of the SQL standards. Since
* practically only MySQL implements it natively, this type of query is
* emulated through this method for other DBMS using standard types of
* queries inside a transaction to assure the atomicity of the operation.
*
* @access public
*
* @param string $table name of the table on which the REPLACE query will
* be executed.
* @param array $fields associative array that describes the fields and the
* values that will be inserted or updated in the specified table. The
* indexes of the array are the names of all the fields of the table. The
* values of the array are also associative arrays that describe the
* values and other properties of the table fields.
*
* Here follows a list of field properties that need to be specified:
*
* value:
* Value to be assigned to the specified field. This value may be
* of specified in database independent type format as this
* function can perform the necessary datatype conversions.
*
* Default:
* this property is required unless the Null property
* is set to 1.
*
* type
* Name of the type of the field. Currently, all types Metabase
* are supported except for clob and blob.
*
* Default: no type conversion
*
* null
* Boolean property that indicates that the value for this field
* should be set to null.
*
* The default value for fields missing in INSERT queries may be
* specified the definition of a table. Often, the default value
* is already null, but since the REPLACE may be emulated using
* an UPDATE query, make sure that all fields of the table are
* listed in this function argument array.
*
* Default: 0
*
* key
* Boolean property that indicates that this field should be
* handled as a primary key or at least as part of the compound
* unique index of the table that will determine the row that will
* updated if it exists or inserted a new row otherwise.
*
* This function will fail if no key field is specified or if the
* value of a key field is set to null because fields that are
* part of unique index they may not be null.
*
* Default: 0
*
* @return integer the number of affected rows
*/
public function replace(Doctrine_Table $table, array $fields, array $keys)
{
$count = count($fields);
$query = $values = '';
$keys = $colnum = 0;
for (reset($fields); $colnum < $count; next($fields), $colnum++) {
$name = key($fields);
if ($colnum > 0) {
$query .= ',';
$values.= ',';
}
$query .= $table->getColumnName($name);
if (isset($fields[$name]['null']) && $fields[$name]['null']) {
$value = 'NULL';
} else {
$type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null;
$value = $this->quote($fields[$name]['value'], $type);
}
$values .= $value;
if (isset($fields[$name]['key']) && $fields[$name]['key']) {
if ($value === 'NULL') {
throw new Doctrine_Connection_Mysql_Exception('key value '.$name.' may not be NULL');
}
$keys++;
}
}
if ($keys == 0) {
throw new Doctrine_Connection_Mysql_Exception('not specified which fields are keys');
}
$query = 'REPLACE INTO ' . $table->getTableName() . ' (' . $query . ') VALUES (' . $values . ')';
return $this->exec($query);
}
}