1: <?php
2:
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;
9:
10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: class CUBRID extends AQueryWriter implements QueryWriter
25: {
26: 27: 28:
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;
35:
36: 37: 38:
39: protected $adapter;
40:
41: 42: 43:
44: protected $quoteCharacter = '`';
45:
46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
63: protected function buildFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE )
64: {
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 ";
76: try {
77: $this->adapter->exec( $sql );
78: } catch( SQLException $e ) {
79: return FALSE;
80: }
81: return TRUE;
82: }
83:
84: 85: 86:
87: protected function getKeyMapForType( $type )
88: {
89: $sqlCode = $this->adapter->get("SHOW CREATE TABLE `{$type}`");
90: if (!isset($sqlCode[0])) return array();
91: $matches = 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 );
93: $list = array();
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],
102: 'to' => 'id',
103: 'on_update' => $matches[6][$i],
104: 'on_delete' => $matches[5][$i]
105: );
106: }
107: return $list;
108: }
109:
110: 111: 112: 113: 114:
115: public function __construct( Adapter $adapter )
116: {
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 ',
123: );
124:
125: $this->sqltype_typeno = array();
126:
127: foreach ( $this->typeno_sqltype as $k => $v ) {
128: $this->sqltype_typeno[trim( ( $v ) )] = $k;
129: }
130:
131: $this->sqltype_typeno['STRING(1073741823)'] = self::C_DATATYPE_STRING;
132:
133: $this->adapter = $adapter;
134: }
135:
136: 137: 138: 139: 140: 141:
142: public function getTypeForID()
143: {
144: return self::C_DATATYPE_INTEGER;
145: }
146:
147: 148: 149:
150: public function getTables()
151: {
152: $rows = $this->adapter->getCol( "SELECT class_name FROM db_class WHERE is_system_class = 'NO';" );
153:
154: return $rows;
155: }
156:
157: 158: 159:
160: public function createTable( $table )
161: {
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"))';
167:
168: $this->adapter->exec( $sql );
169: }
170:
171: 172: 173:
174: public function getColumns( $table )
175: {
176: $table = $this->esc( $table );
177:
178: $columnsRaw = $this->adapter->get( "SHOW COLUMNS FROM $table" );
179:
180: $columns = array();
181: foreach ( $columnsRaw as $r ) {
182: $columns[$r['Field']] = $r['Type'];
183: }
184:
185: return $columns;
186: }
187:
188: 189: 190:
191: public function scanType( $value, $flagSpecial = FALSE )
192: {
193: $this->svalue = $value;
194:
195: if ( is_null( $value ) ) {
196: return self::C_DATATYPE_INTEGER;
197: }
198:
199: if ( $flagSpecial ) {
200: if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) {
201: return self::C_DATATYPE_SPECIAL_DATE;
202: }
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;
205: }
206: }
207:
208: $value = strval( $value );
209:
210: if ( !$this->startsWithZeros( $value ) ) {
211: if ( is_numeric( $value ) && ( floor( $value ) == $value ) && $value >= -2147483647 && $value <= 2147483647 ) {
212: return self::C_DATATYPE_INTEGER;
213: }
214: if ( is_numeric( $value ) ) {
215: return self::C_DATATYPE_DOUBLE;
216: }
217: }
218:
219: return self::C_DATATYPE_STRING;
220: }
221:
222: 223: 224:
225: public function code( $typedescription, $includeSpecials = FALSE )
226: {
227: $r = ( ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : self::C_DATATYPE_SPECIFIED );
228:
229: if ( $includeSpecials ) {
230: return $r;
231: }
232:
233: if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) {
234: return self::C_DATATYPE_SPECIFIED;
235: }
236:
237: return $r;
238: }
239:
240: 241: 242:
243: public function addColumn( $type, $column, $field )
244: {
245: $table = $type;
246: $type = $field;
247:
248: $table = $this->esc( $table );
249: $column = $this->esc( $column );
250:
251: $type = array_key_exists( $type, $this->typeno_sqltype ) ? $this->typeno_sqltype[$type] : '';
252:
253: $this->adapter->exec( "ALTER TABLE $table ADD COLUMN $column $type " );
254: }
255:
256: 257: 258:
259: public function addUniqueConstraint( $type, $properties )
260: {
261: $tableNoQ = $this->esc( $type, TRUE );
262: $columns = array();
263: foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
264: $table = $this->esc( $type );
265: sort( $columns );
266: $name = 'UQ_' . sha1( implode( ',', $columns ) );
267: $sql = "ALTER TABLE $table ADD CONSTRAINT UNIQUE $name (" . implode( ',', $columns ) . ")";
268: try {
269: $this->adapter->exec( $sql );
270: } catch( SQLException $e ) {
271: return FALSE;
272: }
273: return TRUE;
274: }
275:
276: 277: 278:
279: public function sqlStateIn( $state, $list )
280: {
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;
286: }
287:
288: 289: 290:
291: public function addIndex( $type, $name, $column )
292: {
293: try {
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) " );
298: return TRUE;
299: } catch ( SQLException $e ) {
300: return FALSE;
301: }
302: }
303:
304: 305: 306:
307: public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE )
308: {
309: return $this->buildFK( $type, $targetType, $property, $targetProperty, $isDependent );
310: }
311:
312: 313: 314:
315: public function wipeAll()
316: {
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']}\"" );
320: }
321: }
322: foreach ( $this->getTables() as $t ) {
323: $this->adapter->exec( "DROP TABLE \"$t\"" );
324: }
325: }
326:
327: 328: 329:
330: public function esc( $dbStructure, $noQuotes = FALSE )
331: {
332: return parent::esc( strtolower( $dbStructure ), $noQuotes );
333: }
334:
335: 336: 337:
338: public function inferFetchType( $type, $property )
339: {
340: $table = $this->esc( $type, TRUE );
341: $field = $this->esc( $property, TRUE ) . '_id';
342: $keys = $this->getKeyMapForType( $table );
343:
344: foreach( $keys as $key ) {
345: if (
346: $key['from'] === $field
347: ) return $key['table'];
348: }
349: return NULL;
350: }
351: }
352: