1<?php 2/** 3 * `ALTER` statement. 4 */ 5 6declare(strict_types=1); 7 8namespace PhpMyAdmin\SqlParser\Statements; 9 10use PhpMyAdmin\SqlParser\Components\AlterOperation; 11use PhpMyAdmin\SqlParser\Components\Expression; 12use PhpMyAdmin\SqlParser\Components\OptionsArray; 13use PhpMyAdmin\SqlParser\Parser; 14use PhpMyAdmin\SqlParser\Statement; 15use PhpMyAdmin\SqlParser\Token; 16use PhpMyAdmin\SqlParser\TokensList; 17 18use function implode; 19 20/** 21 * `ALTER` statement. 22 */ 23class AlterStatement extends Statement 24{ 25 /** 26 * Table affected. 27 * 28 * @var Expression 29 */ 30 public $table; 31 32 /** 33 * Column affected by this statement. 34 * 35 * @var AlterOperation[] 36 */ 37 public $altered = []; 38 39 /** 40 * Options of this statement. 41 * 42 * @var array 43 */ 44 public static $OPTIONS = [ 45 'ONLINE' => 1, 46 'OFFLINE' => 1, 47 'IGNORE' => 2, 48 49 'DATABASE' => 3, 50 'EVENT' => 3, 51 'FUNCTION' => 3, 52 'PROCEDURE' => 3, 53 'SERVER' => 3, 54 'TABLE' => 3, 55 'TABLESPACE' => 3, 56 'USER' => 3, 57 'VIEW' => 3, 58 ]; 59 60 /** 61 * @param Parser $parser the instance that requests parsing 62 * @param TokensList $list the list of tokens to be parsed 63 */ 64 public function parse(Parser $parser, TokensList $list) 65 { 66 ++$list->idx; // Skipping `ALTER`. 67 $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS); 68 ++$list->idx; 69 70 // Parsing affected table. 71 $this->table = Expression::parse( 72 $parser, 73 $list, 74 [ 75 'parseField' => 'table', 76 'breakOnAlias' => true, 77 ] 78 ); 79 ++$list->idx; // Skipping field. 80 81 /** 82 * The state of the parser. 83 * 84 * Below are the states of the parser. 85 * 86 * 0 -----------------[ alter operation ]-----------------> 1 87 * 88 * 1 -------------------------[ , ]-----------------------> 0 89 * 90 * @var int 91 */ 92 $state = 0; 93 94 for (; $list->idx < $list->count; ++$list->idx) { 95 /** 96 * Token parsed at this moment. 97 * 98 * @var Token 99 */ 100 $token = $list->tokens[$list->idx]; 101 102 // End of statement. 103 if ($token->type === Token::TYPE_DELIMITER) { 104 break; 105 } 106 107 // Skipping whitespaces and comments. 108 if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) { 109 continue; 110 } 111 112 if ($state === 0) { 113 $options = []; 114 if ($this->options->has('DATABASE')) { 115 $options = AlterOperation::$DB_OPTIONS; 116 } elseif ($this->options->has('TABLE')) { 117 $options = AlterOperation::$TABLE_OPTIONS; 118 } elseif ($this->options->has('VIEW')) { 119 $options = AlterOperation::$VIEW_OPTIONS; 120 } elseif ($this->options->has('USER')) { 121 $options = AlterOperation::$USER_OPTIONS; 122 } 123 124 $this->altered[] = AlterOperation::parse($parser, $list, $options); 125 $state = 1; 126 } elseif ($state === 1) { 127 if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) { 128 $state = 0; 129 } 130 } 131 } 132 } 133 134 /** 135 * @return string 136 */ 137 public function build() 138 { 139 $tmp = []; 140 foreach ($this->altered as $altered) { 141 $tmp[] = $altered::build($altered); 142 } 143 144 return 'ALTER ' . OptionsArray::build($this->options) 145 . ' ' . Expression::build($this->table) 146 . ' ' . implode(', ', $tmp); 147 } 148} 149