3 namespace RedBeanPHP\QueryWriter;
4 use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
5 use RedBeanPHP\QueryWriter as QueryWriter;
6 use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
7 use RedBeanPHP\Adapter as Adapter;
8 use RedBeanPHP\RedException\SQL as SQLException;
11 * RedBeanPHP CUBRID Writer.
12 * This is a QueryWriter class for RedBeanPHP.
13 * This QueryWriter provides support for the CUBRID database platform.
15 * @file RedBeanPHP/QueryWriter/CUBRID.php
16 * @author Gabor de Mooij and the RedBeanPHP Community
20 * (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
21 * This source file is subject to the BSD/GPLv2 License that is bundled
22 * with this source code in the file license.txt.
24 class CUBRID extends AQueryWriter implements QueryWriter
29 const C_DATATYPE_INTEGER = 0;
30 const C_DATATYPE_DOUBLE = 1;
31 const C_DATATYPE_STRING = 2;
32 const C_DATATYPE_SPECIAL_DATE = 80;
33 const C_DATATYPE_SPECIAL_DATETIME = 81;
34 const C_DATATYPE_SPECIFIED = 99;
44 protected $quoteCharacter = '`';
47 * This method adds a foreign key from type and field to
48 * target type and target field.
49 * The foreign key is created without an action. On delete/update
50 * no action will be triggered. The FK is only used to allow database
51 * tools to generate pretty diagrams and to make it easy to add actions
53 * This methods accepts a type and infers the corresponding table name.
55 * @param string $type type that will have a foreign key field
56 * @param string $targetType points to this type
57 * @param string $property field that contains the foreign key value
58 * @param string $targetProperty field where the fk points to
63 protected function buildFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE )
65 $table = $this->esc( $type );
66 $tableNoQ = $this->esc( $type, TRUE );
67 $targetTable = $this->esc( $targetType );
68 $targetTableNoQ = $this->esc( $targetType, TRUE );
69 $column = $this->esc( $property );
70 $columnNoQ = $this->esc( $property, TRUE );
71 $targetColumn = $this->esc( $targetProperty );
72 if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $columnNoQ ) ) ) return FALSE;
73 $needsToDropFK = FALSE;
74 $casc = ( $isDep ? 'CASCADE' : 'SET NULL' );
75 $sql = "ALTER TABLE $table ADD CONSTRAINT FOREIGN KEY($column) REFERENCES $targetTable($targetColumn) ON DELETE $casc ";
77 $this->adapter->exec( $sql );
78 } catch( SQLException $e ) {
85 * @see AQueryWriter::getKeyMapForType
87 protected function getKeyMapForType( $type )
89 $sqlCode = $this->adapter->get("SHOW CREATE TABLE `{$type}`");
90 if (!isset($sqlCode[0])) return array();
92 preg_match_all( '/CONSTRAINT\s+\[([\w_]+)\]\s+FOREIGN\s+KEY\s+\(\[([\w_]+)\]\)\s+REFERENCES\s+\[([\w_]+)\](\s+ON\s+DELETE\s+(CASCADE|SET\sNULL|RESTRICT|NO\sACTION)\s+ON\s+UPDATE\s+(SET\sNULL|RESTRICT|NO\sACTION))?/', $sqlCode[0]['CREATE TABLE'], $matches );
94 if (!isset($matches[0])) return $list;
95 $max = count($matches[0]);
96 for($i = 0; $i < $max; $i++) {
97 $label = $this->makeFKLabel( $matches[2][$i], $matches[3][$i], 'id' );
98 $list[ $label ] = array(
99 'name' => $matches[1][$i],
100 'from' => $matches[2][$i],
101 'table' => $matches[3][$i],
103 'on_update' => $matches[6][$i],
104 'on_delete' => $matches[5][$i]
113 * @param Adapter $adapter Database Adapter
115 public function __construct( Adapter $adapter )
117 $this->typeno_sqltype = array(
118 CUBRID::C_DATATYPE_INTEGER => ' INTEGER ',
119 CUBRID::C_DATATYPE_DOUBLE => ' DOUBLE ',
120 CUBRID::C_DATATYPE_STRING => ' STRING ',
121 CUBRID::C_DATATYPE_SPECIAL_DATE => ' DATE ',
122 CUBRID::C_DATATYPE_SPECIAL_DATETIME => ' DATETIME ',
125 $this->sqltype_typeno = array();
127 foreach ( $this->typeno_sqltype as $k => $v ) {
128 $this->sqltype_typeno[trim( ( $v ) )] = $k;
131 $this->sqltype_typeno['STRING(1073741823)'] = self::C_DATATYPE_STRING;
133 $this->adapter = $adapter;
137 * This method returns the datatype to be used for primary key IDS and
138 * foreign keys. Returns one if the data type constants.
142 public function getTypeForID()
144 return self::C_DATATYPE_INTEGER;
148 * @see QueryWriter::getTables
150 public function getTables()
152 $rows = $this->adapter->getCol( "SELECT class_name FROM db_class WHERE is_system_class = 'NO';" );
158 * @see QueryWriter::createTable
160 public function createTable( $table )
162 $sql = 'CREATE TABLE '
163 . $this->esc( $table )
164 . ' ("id" integer AUTO_INCREMENT, CONSTRAINT "pk_'
165 . $this->esc( $table, TRUE )
166 . '_id" PRIMARY KEY("id"))';
168 $this->adapter->exec( $sql );
172 * @see QueryWriter::getColumns
174 public function getColumns( $table )
176 $table = $this->esc( $table );
178 $columnsRaw = $this->adapter->get( "SHOW COLUMNS FROM $table" );
181 foreach ( $columnsRaw as $r ) {
182 $columns[$r['Field']] = $r['Type'];
189 * @see QueryWriter::scanType
191 public function scanType( $value, $flagSpecial = FALSE )
193 $this->svalue = $value;
195 if ( is_null( $value ) ) {
196 return self::C_DATATYPE_INTEGER;
199 if ( $flagSpecial ) {
200 if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) {
201 return self::C_DATATYPE_SPECIAL_DATE;
203 if ( preg_match( '/^\d{4}\-\d\d-\d\d\s\d\d:\d\d:\d\d$/', $value ) ) {
204 return self::C_DATATYPE_SPECIAL_DATETIME;
208 $value = strval( $value );
210 if ( !$this->startsWithZeros( $value ) ) {
211 if ( is_numeric( $value ) && ( floor( $value ) == $value ) && $value >= -2147483647 && $value <= 2147483647 ) {
212 return self::C_DATATYPE_INTEGER;
214 if ( is_numeric( $value ) ) {
215 return self::C_DATATYPE_DOUBLE;
219 return self::C_DATATYPE_STRING;
223 * @see QueryWriter::code
225 public function code( $typedescription, $includeSpecials = FALSE )
227 $r = ( ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : self::C_DATATYPE_SPECIFIED );
229 if ( $includeSpecials ) {
233 if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) {
234 return self::C_DATATYPE_SPECIFIED;
241 * @see QueryWriter::addColumn
243 public function addColumn( $type, $column, $field )
248 $table = $this->esc( $table );
249 $column = $this->esc( $column );
251 $type = array_key_exists( $type, $this->typeno_sqltype ) ? $this->typeno_sqltype[$type] : '';
253 $this->adapter->exec( "ALTER TABLE $table ADD COLUMN $column $type " );
257 * @see QueryWriter::addUniqueIndex
259 public function addUniqueConstraint( $type, $properties )
261 $tableNoQ = $this->esc( $type, TRUE );
263 foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
264 $table = $this->esc( $type );
265 sort( $columns ); // else we get multiple indexes due to order-effects
266 $name = 'UQ_' . sha1( implode( ',', $columns ) );
267 $sql = "ALTER TABLE $table ADD CONSTRAINT UNIQUE $name (" . implode( ',', $columns ) . ")";
269 $this->adapter->exec( $sql );
270 } catch( SQLException $e ) {
277 * @see QueryWriter::sqlStateIn
279 public function sqlStateIn( $state, $list )
281 return ( $state == 'HY000' ) ? ( count( array_diff( array(
282 QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION,
283 QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
284 QueryWriter::C_SQLSTATE_NO_SUCH_TABLE
285 ), $list ) ) !== 3 ) : FALSE;
289 * @see QueryWriter::addIndex
291 public function addIndex( $type, $name, $column )
294 $table = $this->esc( $type );
295 $name = preg_replace( '/\W/', '', $name );
296 $column = $this->esc( $column );
297 $this->adapter->exec( "CREATE INDEX $name ON $table ($column) " );
299 } catch ( SQLException $e ) {
305 * @see QueryWriter::addFK
307 public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE )
309 return $this->buildFK( $type, $targetType, $property, $targetProperty, $isDependent );
313 * @see QueryWriter::wipeAll
315 public function wipeAll()
317 foreach ( $this->getTables() as $t ) {
318 foreach ( $this->getKeyMapForType( $t ) as $k ) {
319 $this->adapter->exec( "ALTER TABLE \"$t\" DROP FOREIGN KEY \"{$k['name']}\"" );
322 foreach ( $this->getTables() as $t ) {
323 $this->adapter->exec( "DROP TABLE \"$t\"" );
328 * @see QueryWriter::esc
330 public function esc( $dbStructure, $noQuotes = FALSE )
332 return parent::esc( strtolower( $dbStructure ), $noQuotes );
336 * @see QueryWriter::inferFetchType
338 public function inferFetchType( $type, $property )
340 $table = $this->esc( $type, TRUE );
341 $field = $this->esc( $property, TRUE ) . '_id';
342 $keys = $this->getKeyMapForType( $table );
344 foreach( $keys as $key ) {
346 $key['from'] === $field
347 ) return $key['table'];