1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
column.php
См. документацию.
1<?php
2namespace Bitrix\Perfmon\Sql;
3
4use Bitrix\Main\NotSupportedException;
5
6class Column extends BaseObject
7{
9 public $parent = null;
10 public $type = '';
11 public $typeAddition = '';
12 public $unsigned = false;
13 public $length = '';
14 public $precision = 0;
15 public $nullable = true;
16 public $default = null;
17 public $enum = [];
18
19 protected static $types = [
20 'BIGINT' => true,
21 'BINARY' => true,
22 'BLOB' => true,
23 'BOOLEAN' => true,
24 'BYTEA' => true,
25 'CHAR' => true,
26 'DATE' => true,
27 'DATETIME' => true,
28 'DECIMAL' => true,
29 'DOUBLE' => true,
30 'ENUM' => true,
31 'FLOAT' => true,
32 'INT' => true,
33 'INT8' => true,
34 'INTEGER' => true,
35 'LONGBLOB' => true,
36 'LONGTEXT' => true,
37 'MEDIUMBLOB' => true,
38 'MEDIUMINT' => true,
39 'MEDIUMTEXT' => true,
40 'NUMBER' => true,
41 'NUMERIC' => true,
42 'REAL' => true,
43 'SET' => true,
44 'SMALLINT' => true,
45 'TEXT' => true,
46 'TIME' => true,
47 'TIMESTAMP' => true,
48 'TINYBLOB' => true,
49 'TINYINT' => true,
50 'TINYTEXT' => true,
51 'VARBINARY' => true,
52 'VARCHAR' => true,
53 ];
54
92 public static function checkType($type)
93 {
94 return isset(self::$types[$type]);
95 }
96
106 public function getLength($charWidth, $maxLength = null)
107 {
108 $length = $maxLength ?? intval($this->length);
109 static $fixed = [
110 'INT' => 4,
111 'INTEGER' => 4,
112 'TINYINT' => 1,
113 'FLOAT' => 4,
114 'DOUBLE' => 8,
115 'BIGINT' => 8,
116 'SMALLINT' => 2,
117 'MEDIUMINT' => 3,
118 'TIMESTAMP' => 4,
119 'DATETIME' => 8,
120 'YEAR' => 1,
121 'DATE' => 3,
122 'TIME' => 3,
123 'NUMERIC' => 4, //up to
124 'NUMBER' => 4, //up to
125 'DECIMAL' => 4, //up to
126 'ENUM' => 2, //up to
127 'SET' => 8, //up to
128 'BOOLEAN' => 1,
129 ];
130 if (isset($fixed[$this->type]))
131 {
132 return $fixed[$this->type];
133 }
134 if ($this->type === 'BINARY')
135 {
136 return $length;
137 }
138 if ($this->type === 'VARBINARY')
139 {
140 return $length + ($length > 255 ? 2 : 1);
141 }
142 if ($this->type === 'TINYBLOB' || $this->type === 'TINYTEXT')
143 {
144 return ($length ?: pow(2, 8)) + 1;
145 }
146 if ($this->type === 'BLOB' || $this->type === 'TEXT')
147 {
148 return ($length ?: pow(2, 16)) + 2;
149 }
150 if ($this->type === 'MEDIUMBLOB' || $this->type === 'MEDIUMTEXT')
151 {
152 return ($length ?: pow(2, 24)) + 3;
153 }
154 if ($this->type === 'LONGBLOB' || $this->type === 'LONGTEXT')
155 {
156 return ($length ?: pow(2, 32)) + 3;
157 }
158 if ($this->type === 'CHAR')
159 {
160 return $length * $charWidth;
161 }
162 if ($this->type === 'VARCHAR')
163 {
164 return ($length * $charWidth) + ($length > 255 ? 2 : 1);
165 }
166 throw new NotSupportedException('column type [' . $this->type . '].');
167 }
168
180 public static function create(Tokenizer $tokenizer, $parent = null)
181 {
182 $columnName = $tokenizer->getCurrentToken()->text;
183
184 $tokenizer->nextToken();
185 $tokenizer->skipWhiteSpace();
186 $token = $tokenizer->getCurrentToken();
187 if ($token->upper === 'RESTART')
188 {
189 while (!$tokenizer->endOfInput())
190 {
191 $tokenizer->nextToken();
192 }
193 return null;
194 }
195
196 $columnType = $token->upper;
197 if (!self::checkType($columnType))
198 {
199 throw new NotSupportedException('column type expected but [' . $tokenizer->getCurrentToken()->text . '] found. line: ' . $tokenizer->getCurrentToken()->line);
200 }
201
202 $column = new self($columnName);
203 if ($parent)
204 {
205 $column->setParent($parent);
206 }
207 $column->type = $columnType;
208
209 $level = $token->level;
210 $lengthLevel = -1;
211 $columnDefinition = '';
212 do
213 {
214 if ($token->level == $level && $token->text === ',')
215 {
216 break;
217 }
218 if ($token->level < $level && $token->text === ')')
219 {
220 break;
221 }
222
223 $columnDefinition .= $token->text;
224
225 if ($token->upper === 'NOT')
226 {
227 $column->nullable = false;
228 }
229 elseif ($token->upper === 'DEFAULT')
230 {
231 $column->default = false;
232 }
233 elseif ($token->upper === 'UNSIGNED')
234 {
235 $column->unsigned = true;
236 }
237 elseif ($token->upper === 'PRECISION')
238 {
239 $column->typeAddition = $token->upper;
240 }
241 elseif ($token->upper === 'VARYING')
242 {
243 $column->typeAddition = $token->upper;
244 }
245 elseif ($token->upper === 'PRIMARY')
246 {
247 $constraint = new Constraint;
248 $constraint->columns[] = $column->name;
249 $constraint->setBody('PRIMARY KEY (' . $column->name . ')');
250 $constraint->setParent($column->parent);
251 $column->parent->constraints->add($constraint);
252 }
253 elseif ($column->default === false)
254 {
255 if ($token->type !== Token::T_WHITESPACE && $token->type !== Token::T_COMMENT)
256 {
257 $column->default = $token->text;
258 }
259 }
260
261 $token = $tokenizer->nextToken();
262
263 //parentheses after type
264 if ($lengthLevel == -1)
265 {
266 if ($token->text === '(')
267 {
268 if ($column->type === 'ENUM')
269 {
270 $lengthLevel = $token->level;
271 while (!$tokenizer->endOfInput())
272 {
273 $columnDefinition .= $token->text;
274
275 $token = $tokenizer->nextToken();
276
277 if ($token->level === $lengthLevel && $token->text === ')')
278 {
279 break;
280 }
281
282 if ($token->type == Token::T_SINGLE_QUOTE)
283 {
284 $column->enum[] = trim($token->text, "'");
285 }
286 elseif ($token->type == Token::T_DOUBLE_QUOTE)
287 {
288 $column->enum[] = trim($token->text, '"');
289 }
290 }
291 }
292 else
293 {
294 $lengthLevel = $token->level;
295 while (!$tokenizer->endOfInput())
296 {
297 $columnDefinition .= $token->text;
298
299 $token = $tokenizer->nextToken();
300
301 if ($token->level === $lengthLevel && $token->text === ')')
302 {
303 break;
304 }
305
306 if ($token->type == Token::T_STRING)
307 {
308 if (!$column->length)
309 {
310 $column->length = (int)$token->text;
311 }
312 else
313 {
314 $column->precision = (int)$token->text;
315 }
316 }
317 }
318 }
319 }
320 elseif ($token->type !== Token::T_WHITESPACE && $token->type !== Token::T_COMMENT)
321 {
322 $lengthLevel = 0;
323 }
324 }
325 }
326 while (!$tokenizer->endOfInput());
327
328 $column->setBody($columnDefinition);
329
330 return $column;
331 }
332
338 public function getDdlType()
339 {
340 return ($this->unsigned ? 'UNSIGNED ' : '')
341 . $this->type
342 . ($this->typeAddition ? ' ' . $this->typeAddition : '')
343 . ($this->length !== '' ? '(' . $this->length . ($this->precision !== 0 ? ',' . $this->precision : '') . ')' : '');
344 }
345
353 public function getCreateDdl($dbType = '')
354 {
355 switch ($dbType)
356 {
357 case 'MYSQL':
358 case 'MSSQL':
359 return 'ALTER TABLE ' . $this->parent->name . ' ADD ' . $this->name . ' ' . $this->body;
360 case 'PGSQL':
361 return 'ALTER TABLE ' . $this->parent->name . ' ADD COLUMN ' . $this->name . ' ' . $this->body;
362 case 'ORACLE':
363 return 'ALTER TABLE ' . $this->parent->name . ' ADD (' . $this->name . ' ' . $this->body . ')';
364 default:
365 return '// ' . get_class($this) . ':getCreateDdl for database type [' . $dbType . '] not implemented';
366 }
367 }
368
376 public function getDropDdl($dbType = '')
377 {
378 switch ($dbType)
379 {
380 case 'MYSQL':
381 return 'ALTER TABLE ' . $this->parent->name . ' DROP ' . $this->name;
382 case 'MSSQL':
383 case 'PGSQL':
384 return 'ALTER TABLE ' . $this->parent->name . ' DROP COLUMN ' . $this->name;
385 case 'ORACLE':
386 return 'ALTER TABLE ' . $this->parent->name . ' DROP (' . $this->name . ')';
387 default:
388 return '// ' . get_class($this) . ':getDropDdl for database type [' . $dbType . '] not implemented';
389 }
390 }
391
402 public function getModifyDdl(BaseObject $target, $dbType = '')
403 {
405 switch ($dbType)
406 {
407 case 'MYSQL':
408 return 'ALTER TABLE ' . $this->parent->name . ' CHANGE ' . $this->name . ' ' . $target->name . ' ' . $target->body;
409 case 'PGSQL':
410 $defaultDropped = false;
411 $alter = [];
412 $sourceType = $this->getDdlType();
413 $targetType = $target->getDdlType();
414 if ($sourceType !== $targetType)
415 {
416 $alter[] = 'ALTER COLUMN ' . $this->name . ' DROP DEFAULT';
417 $defaultDropped = true;
418 $alter[] = 'ALTER COLUMN ' . $this->name . ' TYPE ' . $targetType;
419 }
420
421 if ($this->default === null)
422 {
423 if ($target->default !== null)
424 {
425 $alter[] = 'ALTER COLUMN ' . $this->name . ' SET DEFAULT ' . $target->default;
426 }
427 }
428 else
429 {
430 if ($target->default === null)
431 {
432 if (!$defaultDropped)
433 {
434 $alter[] = 'ALTER COLUMN ' . $this->name . ' DROP DEFAULT';
435 }
436 }
437 elseif ($this->default != $target->default)
438 {
439 $alter[] = 'ALTER COLUMN ' . $this->name . ' SET DEFAULT ' . $target->default;
440 }
441 }
442
443 if ($this->nullable != $target->nullable)
444 {
445 $alter[] = 'ALTER COLUMN ' . $this->name . ' ' . ($target->nullable ? 'DROP' : 'SET') . ' NOT NULL ';
446 }
447
448 if ($alter)
449 {
450 return 'ALTER TABLE ' . $this->parent->name . ' ' . implode(', ', $alter);
451 }
452 else
453 {
454 return '// ' . get_class($this) . ':getModifyDdl for database type [' . $dbType . '] not implemented. Change requested from [' . $this->body . '] to [' . $target->body . '].';
455 }
456 case 'MSSQL':
457 if ($this->nullable !== $target->nullable)
458 {
459 $nullDdl = ($target->nullable ? ' NULL' : ' NOT NULL');
460 }
461 else
462 {
463 $nullDdl = '';
464 }
465
466 if (
467 $this->type === $target->type
468 && $this->default === $target->default
469 && (
470 intval($this->length) < intval($target->length)
471 || (
472 intval($target->length) < intval($this->length)
473 && mb_strtoupper($this->type) === 'CHAR'
474 )
475 )
476 )
477 {
478 $sql = [];
480 foreach ($this->parent->indexes->getList() as $index)
481 {
482 if (in_array($this->name, $index->columns, true))
483 {
484 $sql[] = $index->getDropDdl($dbType);
485 }
486 }
487 $sql[] = 'ALTER TABLE ' . $this->parent->name . ' ALTER COLUMN ' . $this->name . ' ' . $target->body . $nullDdl;
488 foreach ($this->parent->indexes->getList() as $index)
489 {
490 if (in_array($this->name, $index->columns, true))
491 {
492 $sql[] = $index->getCreateDdl($dbType);
493 }
494 }
495 return $sql;
496 }
497 elseif (
498 $this->type === $target->type
499 && $this->default === $target->default
500 && intval($this->length) === intval($target->length)
501 && $this->nullable !== $target->nullable
502 )
503 {
504 return 'ALTER TABLE ' . $this->parent->name . ' ALTER COLUMN ' . $this->name . ' ' . $target->body;
505 }
506 else
507 {
508 return '// ' . get_class($this) . ':getModifyDdl for database type [' . $dbType . "] not implemented. Change requested from [${this}->body] to [${target}->body].";
509 }
510 case 'ORACLE':
511 if (
512 $this->type === $target->type
513 && $this->default === $target->default
514 && (
515 intval($this->length) < intval($target->length)
516 || (
517 intval($target->length) < intval($this->length)
518 && mb_strtoupper($this->type) === 'CHAR'
519 )
520 )
521 )
522 {
523 return 'ALTER TABLE ' . $this->parent->name . ' MODIFY (' . $this->name . ' ' . $target->type . '(' . $target->length . ')' . ')';
524 }
525 elseif (
526 $this->type === $target->type
527 && $this->default === $target->default
528 && intval($this->length) === intval($target->length)
529 && $this->nullable !== $target->nullable
530 )
531 {
532 return "
533 declare
534 l_nullable varchar2(1);
535 begin
536 select nullable into l_nullable
537 from user_tab_columns
538 where table_name = '" . $this->parent->name . "'
539 and column_name = '" . $this->name . "';
540 if l_nullable = '" . ($target->nullable ? 'N' : 'Y') . "' then
541 execute immediate 'alter table " . $this->parent->name . ' modify (' . $this->name . ' ' . ($target->nullable ? 'NULL' : 'NOT NULL') . ")';
542 end if;
543 end;
544 ";
545 }
546 else
547 {
548 return '// ' . get_class($this) . ':getModifyDdl for database type [' . $dbType . "] not implemented. Change requested from [${this}->body] to [${target}->body].";
549 }
550 default:
551 return '// ' . get_class($this) . ':getModifyDdl for database type [' . $dbType . "] not implemented. Change requested from [${this}->body] to [${target}->body].";
552 }
553 }
554}
setBody($body)
Определения base_object.php:33
getModifyDdl(BaseObject $target, $dbType='')
Определения base_object.php:197
getCreateDdl($dbType='')
Определения column.php:353
getDdlType()
Определения column.php:338
$parent
Определения column.php:9
$nullable
Определения column.php:15
$typeAddition
Определения column.php:11
getLength($charWidth, $maxLength=null)
Определения column.php:106
static $types
Определения column.php:19
$unsigned
Определения column.php:12
static create(Tokenizer $tokenizer, $parent=null)
Определения column.php:180
getDropDdl($dbType='')
Определения column.php:376
$precision
Определения column.php:14
static checkType($type)
Определения column.php:92
const T_COMMENT
Определения tokenizer.php:15
const T_STRING
Определения tokenizer.php:7
const T_DOUBLE_QUOTE
Определения tokenizer.php:11
const T_WHITESPACE
Определения tokenizer.php:6
const T_SINGLE_QUOTE
Определения tokenizer.php:10
$dbType
Определения autoload.php:6
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393