public function testVersionString() { $mock = $this->getMockBuilder(\stdClass::class)->setMethods(['fetchColumn'])->disableOriginalConstructor()->getMock(); $mock->expects($this->once())->method('fetchColumn')->will($this->returnValue("3.0.2")); $this->adapter->expects($this->once())->method('query')->with("show variables like 'version'")->will($this->returnValue($mock)); $this->assertEquals("3.0.2", $this->helper->versionString()); }
public function test() { $this->adapter->expects($this->atLeastOnce())->method('hasTable')->will($this->returnValueMap([['users', true], ['users_new', true]])); $this->adapter->expects($this->atLeastOnce())->method('quoteTableName')->will($this->returnCallback(function ($name) { return "`{$name}`"; })); $this->adapter->expects($this->once())->method('query')->with('RENAME TABLE `users` TO `users_archive`, `users_new` TO `users`'); $this->origin->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users')); $this->destination->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users_new')); $this->switcher->run(); }
public function testRun() { /** @var Column[] $originColumns */ $originColumns = [new Column(), new Column(), new Column()]; $originColumns[0]->setName('id'); $originColumns[1]->setName('name'); $originColumns[2]->setName('something'); /** @var Column[] $destinationColumns */ $destinationColumns = [new Column(), new Column(), new Column()]; $destinationColumns[0]->setName('id'); $destinationColumns[1]->setName('name'); $destinationColumns[2]->setName('something_else'); $this->origin->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users')); $this->origin->expects($this->atLeastOnce())->method('getColumns')->will($this->returnValue($originColumns)); $this->destination->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users_new')); $this->destination->expects($this->atLeastOnce())->method('getColumns')->will($this->returnValue($destinationColumns)); $this->destination->expects($this->atLeastOnce())->method('getRenamedColumns')->will($this->returnValue([])); $matcher = $this->atLeastOnce(); $this->adapter->expects($matcher)->method('fetchRow')->will($this->returnCallback(function ($query) use($matcher) { switch ($matcher->getInvocationCount()) { case 1: $this->assertEquals("SELECT MIN(id) FROM 'users'", $query); return [1]; case 2: $this->assertEquals("SELECT MAX(id) FROM 'users'", $query); return [500]; default: return null; break; } })); $matcher = $this->atLeastOnce(); $this->adapter->expects($matcher)->method('query')->will($this->returnCallback(function ($query) use($matcher) { switch ($matcher->getInvocationCount()) { case 1: $this->assertEquals("SELECT `COLUMN_NAME` FROM `information_schema`.`COLUMNS` WHERE (`TABLE_SCHEMA` = '') AND (`TABLE_NAME` = 'users') AND (`COLUMN_KEY` = 'PRI');", $query); return 'id'; case 2: $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 1 AND 200", $query); break; case 3: $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 201 AND 400", $query); break; case 4: $this->assertEquals("INSERT IGNORE INTO 'users_new' (`id`,`name`) SELECT 'users'.`id`,'users'.`name` FROM 'users' WHERE 'users'.`id` BETWEEN 401 AND 500", $query); break; default: $this->fail('Unexpected query: ' . $query); break; } })); $chunker = new Chunker($this->adapter, $this->origin, $this->destination, $this->sqlHelper, ['stride' => 200]); $chunker->run(); }
protected function setUp() { parent::setUp(); $options = ['host' => getenv('LHM_DATABASE_HOST') ?: 'localhost', 'name' => getenv('LHM_DATABASE_NAME') ?: 'lhm_php_test', 'user' => getenv('LHM_DATABASE_USER') ?: 'root', 'pass' => getenv('LHM_DATABASE_PASSWORD') ?: null, 'port' => getenv('LHM_DATABASE_PORT') ?: 3306]; $this->adapter = new MysqlAdapter($options, new NullOutput()); $this->adapter->setOptions($options); // ensure the database is empty for each test $this->adapter->dropDatabase($options['name']); $this->adapter->createDatabase($options['name']); // leave the adapter in a disconnected state for each test $this->adapter->disconnect(); }
public function test() { $this->adapter->expects($this->atLeastOnce())->method('hasTable')->will($this->returnValueMap([['users', true], ['users_new', true]])); $this->adapter->expects($this->atLeastOnce())->method('quoteTableName')->will($this->returnCallback(function ($name) { return "`{$name}`"; })); $expected = ["set @lhm_auto_commit = @@session.autocommit /* large hadron migration (php) */", "set session autocommit = 0 /* large hadron migration (php) */", "LOCK TABLE `users` write, `users_new` write /* large hadron migration (php) */", "ALTER TABLE `users` rename `users_archive` /* large hadron migration (php) */", "ALTER TABLE `users_new` rename `users` /* large hadron migration (php) */", "COMMIT /* large hadron migration (php) */", "UNLOCK TABLES /* large hadron migration (php) */", "set session autocommit = @lhm_auto_commit /* large hadron migration (php) */"]; $matcher = $this->any(); $this->adapter->expects($matcher)->method('query')->will($this->returnCallback(function ($query) use($matcher, $expected) { $this->assertEquals($expected[$matcher->getInvocationCount() - 1], $query); })); $this->origin->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users')); $this->destination->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users_new')); $this->switcher->run(); }
public function testCreateDeleteTrigger() { $this->origin->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users')); $this->destination->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('users_new')); $this->adapter->expects($this->once())->method('query')->will($this->returnValue("id")); $this->assertEquals(implode("\n ", ['CREATE TRIGGER lhmt_delete_users', "AFTER DELETE ON 'users' FOR EACH ROW", "DELETE IGNORE FROM 'users_new' /* large hadron migration (php) */", "WHERE 'users_new'.`id` = OLD.`id`"]), $this->entangler->createDeleteTrigger()); }
/** * Execute the switch */ protected function execute() { $sqlHelper = $this->getSqlHelper(); foreach ($this->statements() as $statement) { $this->adapter->query($sqlHelper->tagged($statement)); } }
/** * @param integer $lowest * @param integer $highest * @return string */ protected function copy($lowest, $highest) { $originName = $this->adapter->quoteTableName($this->origin->getName()); $destinationName = $this->adapter->quoteTableName($this->destination->getName()); $destinationColumns = implode(',', $this->sqlHelper->quoteColumns($this->intersection->destination())); $originColumns = implode(',', $this->sqlHelper->typedColumns($originName, $this->sqlHelper->quoteColumns($this->intersection->origin()))); return implode(" ", ["INSERT IGNORE INTO {$destinationName} ({$destinationColumns})", "SELECT {$originColumns} FROM {$originName}", "WHERE {$originName}.{$this->primaryKey} BETWEEN {$lowest} AND {$highest}"]); }
/** * @param array $columns List of column names * @return array */ public function quoteColumns(array $columns) { $quoted = []; foreach ($columns as $column) { $quoted[] = $this->adapter->quoteColumnName($column); } return $quoted; }
/** * @throws \RuntimeException */ protected function validate() { if (!$this->adapter->hasTable($this->origin->getName())) { throw new \RuntimeException("Table `{$this->origin->getName()}` does not exists."); } if (!$this->adapter->hasTable($this->destination->getName())) { throw new \RuntimeException("Table `{$this->destination->getName()}` does not exists."); } }
public function testInsertData() { $row = array('column1' => 'value3'); $this->mock->expects($this->once())->method('insert')->with($this->callback(function ($table) { return $table->getName() == 'pre_table_suf'; }, $this->equalTo($row))); $table = new Table('table', array(), $this->adapter); $table->insert($row)->save(); }
/** * @return Table * @throws \RuntimeException */ public function temporaryTable() { if ($this->destination) { return $this->destination; } $temporaryTableName = $this->temporaryTableName(); if ($this->adapter->hasTable($temporaryTableName)) { throw new \RuntimeException("The table `{$temporaryTableName}` already exists."); } $this->getLogger()->info("Creating temporary table `{$temporaryTableName}` from `{$this->origin->getName()}`"); $this->adapter->query("CREATE TABLE {$temporaryTableName} LIKE {$this->origin->getName()}"); return new \Lhm\Table($temporaryTableName, [], $this->adapter); }
/** * Execute the atomic rename. */ protected function execute() { $retries = 0; while ($retries < $this->options['max_retries']) { $retries++; try { foreach ($this->statements() as $statement) { $this->getLogger()->debug("Executing statement `{$statement}`"); $this->adapter->query($statement); } return; } catch (\Exception $e) { if ($this->shouldRetryException($e)) { $this->getLogger()->warning($e->getMessage()); sleep($this->options['retry_sleep_time']); //TODO log the retry continue; } throw $e; } } }
public function testAddTableWithForeignKey() { $this->mock->expects($this->any())->method('isValidColumnType')->with($this->callback(function ($column) { return in_array($column->getType(), array('string', 'integer')); }))->will($this->returnValue(true)); $table = new Table('table', array(), $this->adapter); $table->addColumn('bar', 'string')->addColumn('relation', 'integer')->addForeignKey('relation', 'target_table', array('id')); $this->mock->expects($this->once())->method('createTable')->with($this->callback(function ($table) { if ($table->getName() !== 'pre_table_suf') { throw new \Exception(sprintf('Table::getName was not prefixed/suffixed properly: "%s"', $table->getName())); } $fks = $table->getForeignKeys(); if (count($fks) !== 1) { throw new \Exception(sprintf('Table::getForeignKeys count was incorrect: %d', count($fks))); } foreach ($fks as $fk) { if ($fk->getReferencedTable()->getName() !== 'pre_target_table_suf') { throw new \Exception(sprintf('ForeignKey::getReferencedTable was not prefixed/suffixed properly: "%s"', $fk->getReferencedTable->getName())); } } return true; })); $table->create(); }
/** * Drops the specified database. * * @param string $name Database Name * @return void */ public function dropDatabase($name) { $this->adapter->dropDatabase($name); }
/** * {@inheritdoc} */ public function getOutput() { return $this->adapter->getOutput(); }
/** * Closes the database connection. * * @return void */ public function disconnect() { $this->adapter->disconnect(); }