支持多数据库

This commit is contained in:
zyimm 2023-01-11 15:03:46 +08:00
parent c51878d73c
commit f0587e22ac
11 changed files with 220 additions and 122 deletions

View File

@ -1,9 +1,13 @@
{
"name": "topthink/think-migration",
"name": "zyimm/think-migration",
"authors": [
{
"name": "yunwuxin",
"email": "448901948@qq.com"
},
{
"name": "zyimm",
"email": "zyimm@qq.com"
}
],
"license": "Apache-2.0",
@ -17,6 +21,12 @@
]
},
"require": {
"php": ">=7.0",
"topthink/framework": "5.1.*"
},
"config": {
"allow-plugins": {
"topthink/think-installer": true
}
}
}

View File

@ -26,12 +26,15 @@
* @package Phinx
* @subpackage Phinx\Db
*/
namespace Phinx\Db;
use Phinx\Db\Table\Column;
use Phinx\Db\Table\Index;
use Phinx\Db\Table\ForeignKey;
use InvalidArgumentException;
use Phinx\Db\Adapter\AdapterInterface;
use Phinx\Db\Table\Column;
use Phinx\Db\Table\ForeignKey;
use Phinx\Db\Table\Index;
use RuntimeException;
/**
*
@ -47,7 +50,7 @@ class Table
/**
* @var array
*/
protected $options = array();
protected $options = [];
/**
* @var AdapterInterface
@ -57,22 +60,22 @@ class Table
/**
* @var array
*/
protected $columns = array();
protected $columns = [];
/**
* @var array
*/
protected $indexes = array();
protected $indexes = [];
/**
* @var ForeignKey[]
*/
protected $foreignKeys = array();
protected $foreignKeys = [];
/**
* @var array
*/
protected $data = array();
protected $data = [];
/**
* Class Constuctor.
@ -81,7 +84,7 @@ class Table
* @param array $options Options
* @param AdapterInterface $adapter Database Adapter
*/
public function __construct($name, $options = array(), AdapterInterface $adapter = null)
public function __construct(string $name, array $options = [], AdapterInterface $adapter = null)
{
$this->setName($name);
$this->setOptions($options);
@ -95,9 +98,10 @@ class Table
* Sets the table name.
*
* @param string $name Table Name
*
* @return Table
*/
public function setName($name)
public function setName(string $name): Table
{
$this->name = $name;
return $this;
@ -108,7 +112,7 @@ class Table
*
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
@ -117,9 +121,10 @@ class Table
* Sets the table options.
*
* @param array $options
*
* @return Table
*/
public function setOptions($options)
public function setOptions(array $options): Table
{
$this->options = $options;
return $this;
@ -130,7 +135,7 @@ class Table
*
* @return array
*/
public function getOptions()
public function getOptions(): array
{
return $this->options;
}
@ -139,9 +144,10 @@ class Table
* Sets the database adapter.
*
* @param AdapterInterface $adapter Database Adapter
*
* @return Table
*/
public function setAdapter(AdapterInterface $adapter)
public function setAdapter(AdapterInterface $adapter): Table
{
$this->adapter = $adapter;
return $this;
@ -152,7 +158,7 @@ class Table
*
* @return AdapterInterface
*/
public function getAdapter()
public function getAdapter(): AdapterInterface
{
return $this->adapter;
}
@ -162,7 +168,7 @@ class Table
*
* @return boolean
*/
public function exists()
public function exists(): bool
{
return $this->getAdapter()->hasTable($this->getName());
}
@ -181,9 +187,10 @@ class Table
* Renames the database table.
*
* @param string $newTableName New Table Name
*
* @return Table
*/
public function rename($newTableName)
public function rename(string $newTableName): Table
{
$this->getAdapter()->renameTable($this->getName(), $newTableName);
$this->setName($newTableName);
@ -194,13 +201,14 @@ class Table
* Sets an array of columns waiting to be committed.
* Use setPendingColumns
*
* @deprecated
* @param array $columns Columns
*
* @return Table
* @deprecated
*/
public function setColumns($columns)
public function setColumns(array $columns): Table
{
$this->setPendingColumns($columns);
return $this->setPendingColumns($columns);
}
/**
@ -208,7 +216,7 @@ class Table
*
* @return Column[]
*/
public function getColumns()
public function getColumns(): array
{
return $this->getAdapter()->getColumns($this->getName());
}
@ -217,9 +225,10 @@ class Table
* Sets an array of columns waiting to be committed.
*
* @param array $columns Columns
*
* @return Table
*/
public function setPendingColumns($columns)
public function setPendingColumns(array $columns): Table
{
$this->columns = $columns;
return $this;
@ -230,7 +239,7 @@ class Table
*
* @return Column[]
*/
public function getPendingColumns()
public function getPendingColumns(): array
{
return $this->columns;
}
@ -239,9 +248,10 @@ class Table
* Sets an array of columns waiting to be indexed.
*
* @param array $indexes Indexes
*
* @return Table
*/
public function setIndexes($indexes)
public function setIndexes(array $indexes): Table
{
$this->indexes = $indexes;
return $this;
@ -252,7 +262,7 @@ class Table
*
* @return array
*/
public function getIndexes()
public function getIndexes(): array
{
return $this->indexes;
}
@ -261,9 +271,10 @@ class Table
* Sets an array of foreign keys waiting to be commited.
*
* @param ForeignKey[] $foreignKeys foreign keys
*
* @return Table
*/
public function setForeignKeys($foreignKeys)
public function setForeignKeys(array $foreignKeys): Table
{
$this->foreignKeys = $foreignKeys;
return $this;
@ -274,7 +285,7 @@ class Table
*
* @return array|ForeignKey[]
*/
public function getForeignKeys()
public function getForeignKeys(): array
{
return $this->foreignKeys;
}
@ -283,9 +294,10 @@ class Table
* Sets an array of data to be inserted.
*
* @param array $data Data
*
* @return Table
*/
public function setData($data)
public function setData(array $data): Table
{
$this->data = $data;
return $this;
@ -296,22 +308,22 @@ class Table
*
* @return array
*/
public function getData()
public function getData(): array
{
return $this->data;
}
/**
* Resets all of the pending table changes.
* Resets all the pending table changes.
*
* @return void
*/
public function reset()
{
$this->setPendingColumns(array());
$this->setIndexes(array());
$this->setForeignKeys(array());
$this->setData(array());
$this->setPendingColumns([]);
$this->setIndexes([]);
$this->setForeignKeys([]);
$this->setData([]);
}
/**
@ -323,17 +335,18 @@ class Table
* Valid options can be: limit, default, null, precision or scale.
*
* @param string|Column $columnName Column Name
* @param string $type Column Type
* @param string|null $type Column Type
* @param array $options Column Options
* @throws \RuntimeException
* @throws \InvalidArgumentException
*
* @return Table
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function addColumn($columnName, $type = null, $options = array())
public function addColumn($columnName, string $type = null, array $options = []): Table
{
// we need an adapter set to add a column
if (null === $this->getAdapter()) {
throw new \RuntimeException('An adapter must be specified to add a column.');
throw new RuntimeException('An adapter must be specified to add a column.');
}
// create a new column object if only strings were supplied
@ -348,7 +361,7 @@ class Table
// Delegate to Adapters to check column type
if (!$this->getAdapter()->isValidColumnType($column)) {
throw new \InvalidArgumentException(sprintf(
throw new InvalidArgumentException(sprintf(
'An invalid column type "%s" was specified for column "%s".',
$column->getType(),
$column->getName()
@ -363,9 +376,10 @@ class Table
* Remove a table column.
*
* @param string $columnName Column Name
*
* @return Table
*/
public function removeColumn($columnName)
public function removeColumn(string $columnName): Table
{
$this->getAdapter()->dropColumn($this->getName(), $columnName);
return $this;
@ -376,9 +390,10 @@ class Table
*
* @param string $oldName Old Column Name
* @param string $newName New Column Name
*
* @return Table
*/
public function renameColumn($oldName, $newName)
public function renameColumn(string $oldName, string $newName): Table
{
$this->getAdapter()->renameColumn($this->getName(), $oldName, $newName);
return $this;
@ -390,9 +405,10 @@ class Table
* @param string $columnName Column Name
* @param string|Column $newColumnType New Column Type
* @param array $options Options
*
* @return Table
*/
public function changeColumn($columnName, $newColumnType, $options = array())
public function changeColumn(string $columnName, $newColumnType, array $options = []): Table
{
// create a column object if one wasn't supplied
if (!$newColumnType instanceof Column) {
@ -417,9 +433,10 @@ class Table
*
* @param string $columnName Column Name
* @param array $options Options
*
* @return boolean
*/
public function hasColumn($columnName, $options = array())
public function hasColumn(string $columnName, array $options = []): bool
{
return $this->getAdapter()->hasColumn($this->getName(), $columnName, $options);
}
@ -431,15 +448,16 @@ class Table
*
* @param string|array|Index $columns Table Column(s)
* @param array $options Index Options
*
* @return Table
*/
public function addIndex($columns, $options = array())
public function addIndex($columns, array $options = []): Table
{
// create a new index object if strings or an array of strings were supplied
// create a new index object if strings or an array of strings is supplied
if (!$columns instanceof Index) {
$index = new Index();
if (is_string($columns)) {
$columns = array($columns); // str to array
$columns = [$columns]; // str to array
}
$index->setColumns($columns);
$index->setOptions($options);
@ -456,9 +474,10 @@ class Table
*
* @param array $columns Columns
* @param array $options Options
*
* @return Table
*/
public function removeIndex($columns, $options = array())
public function removeIndex(array $columns, array $options = []): Table
{
$this->getAdapter()->dropIndex($this->getName(), $columns, $options);
return $this;
@ -468,9 +487,10 @@ class Table
* Removes the given index identified by its name from a table.
*
* @param string $name Index name
*
* @return Table
*/
public function removeIndexByName($name)
public function removeIndexByName(string $name): Table
{
$this->getAdapter()->dropIndexByName($this->getName(), $name);
return $this;
@ -480,12 +500,12 @@ class Table
* Checks to see if an index exists.
*
* @param string|array $columns Columns
* @param array $options Options
*
* @return boolean
*/
public function hasIndex($columns, $options = array())
public function hasIndex($columns): bool
{
return $this->getAdapter()->hasIndex($this->getName(), $columns, $options);
return $this->getAdapter()->hasIndex($this->getName(), $columns);
}
/**
@ -498,18 +518,19 @@ class Table
* @param string|Table $referencedTable Referenced Table
* @param string|array $referencedColumns Referenced Columns
* @param array $options Options
*
* @return Table
*/
public function addForeignKey($columns, $referencedTable, $referencedColumns = array('id'), $options = array())
public function addForeignKey($columns, $referencedTable, $referencedColumns = ['id'], array $options = []): Table
{
if (is_string($referencedColumns)) {
$referencedColumns = array($referencedColumns); // str to array
$referencedColumns = [$referencedColumns]; // str to array
}
$fk = new ForeignKey();
if ($referencedTable instanceof Table) {
$fk->setReferencedTable($referencedTable);
} else {
$fk->setReferencedTable(new Table($referencedTable, array(), $this->adapter));
$fk->setReferencedTable(new Table($referencedTable, [], $this->adapter));
}
$fk->setColumns($columns)
->setReferencedColumns($referencedColumns)
@ -523,16 +544,17 @@ class Table
* Removes the given foreign key from the table.
*
* @param string|array $columns Column(s)
* @param null|string $constraint Constraint names
* @param string|null $constraint Constraint names
*
* @return Table
*/
public function dropForeignKey($columns, $constraint = null)
public function dropForeignKey($columns, string $constraint = null): Table
{
if (is_string($columns)) {
$columns = array($columns);
$columns = [$columns];
}
if ($constraint) {
$this->getAdapter()->dropForeignKey($this->getName(), array(), $constraint);
$this->getAdapter()->dropForeignKey($this->getName(), [], $constraint);
} else {
$this->getAdapter()->dropForeignKey($this->getName(), $columns);
}
@ -544,10 +566,11 @@ class Table
* Checks to see if a foreign key exists.
*
* @param string|array $columns Column(s)
* @param null|string $constraint Constraint names
* @param string|null $constraint Constraint names
*
* @return boolean
*/
public function hasForeignKey($columns, $constraint = null)
public function hasForeignKey($columns, string $constraint = null): bool
{
return $this->getAdapter()->hasForeignKey($this->getName(), $columns, $constraint);
}
@ -560,18 +583,18 @@ class Table
*
* @return Table
*/
public function addTimestamps($createdAtColumnName = 'created_at', $updatedAtColumnName = 'updated_at')
public function addTimestamps(string $createdAtColumnName = 'created_at', string $updatedAtColumnName = 'updated_at'): Table
{
$createdAtColumnName = is_null($createdAtColumnName) ? 'created_at' : $createdAtColumnName;
$updatedAtColumnName = is_null($updatedAtColumnName) ? 'updated_at' : $updatedAtColumnName;
$this->addColumn($createdAtColumnName, 'timestamp', array(
$this->addColumn($createdAtColumnName, 'timestamp', [
'default' => 'CURRENT_TIMESTAMP',
'update' => ''
))
->addColumn($updatedAtColumnName, 'timestamp', array(
])
->addColumn($updatedAtColumnName, 'timestamp', [
'null' => true,
'default' => null
));
]);
return $this;
}
@ -588,7 +611,7 @@ class Table
*
* @return Table
*/
public function insert($data)
public function insert(array $data): Table
{
// handle array of array situations
if (isset($data[0]) && is_array($data[0])) {
@ -616,13 +639,13 @@ class Table
/**
* Updates a table from the object instance.
*
* @throws \RuntimeException
* @return void
* @throws RuntimeException
*/
public function update()
{
if (!$this->exists()) {
throw new \RuntimeException('Cannot update a table that doesn\'t exist!');
throw new RuntimeException('Cannot update a table that doesn\'t exist!');
}
// update table

View File

@ -45,6 +45,13 @@ use think\console\Output as OutputInterface;
*/
abstract class AbstractMigration implements MigrationInterface
{
/**
* 数据库配置
*
* @var string|array
*/
protected $dbConfig = null;
/**
* @var float
*/
@ -72,7 +79,7 @@ abstract class AbstractMigration implements MigrationInterface
* @param InputInterface|null $input
* @param OutputInterface|null $output
*/
final public function __construct($version, InputInterface $input = null, OutputInterface $output = null)
final public function __construct(int $version, InputInterface $input = null, OutputInterface $output = null)
{
$this->version = $version;
if (!is_null($input)){
@ -120,7 +127,7 @@ abstract class AbstractMigration implements MigrationInterface
/**
* {@inheritdoc}
*/
public function getAdapter()
public function getAdapter(): AdapterInterface
{
return $this->adapter;
}
@ -203,7 +210,7 @@ abstract class AbstractMigration implements MigrationInterface
/**
* {@inheritdoc}
*/
public function fetchRow($sql)
public function fetchRow($sql): array
{
return $this->getAdapter()->fetchRow($sql);
}
@ -211,7 +218,7 @@ abstract class AbstractMigration implements MigrationInterface
/**
* {@inheritdoc}
*/
public function fetchAll($sql)
public function fetchAll($sql): array
{
return $this->getAdapter()->fetchAll($sql);
}
@ -270,4 +277,9 @@ abstract class AbstractMigration implements MigrationInterface
{
$this->table($tableName)->drop();
}
public function getDbConfig()
{
return $this->dbConfig;
}
}

View File

@ -212,4 +212,9 @@ interface MigrationInterface
* @return Table
*/
public function table($tableName, $options);
/**
* @return mixed
*/
public function getDbConfig();
}

View File

@ -12,18 +12,27 @@ namespace think\migration;
use InvalidArgumentException;
use Phinx\Db\Adapter\AdapterFactory;
use Phinx\Db\Adapter\AdapterInterface;
use think\Db;
use think\Exception;
use think\facade\Config;
abstract class Command extends \think\console\Command
{
protected $dbConfig = null;
public function getAdapter()
/**
* @param string|null $db_config
*
* @return AdapterInterface
* @throws Exception
*/
public function getAdapter(string $db_config = null): AdapterInterface
{
if (isset($this->adapter)) {
return $this->adapter;
}
$this->dbConfig = $db_config;
$options = $this->getDbConfig();
$adapter = AdapterFactory::instance()->getAdapter($options['adapter'], $options);
@ -40,10 +49,11 @@ abstract class Command extends \think\console\Command
/**
* 获取数据库配置
* @return array
* @throws Exception
*/
protected function getDbConfig()
protected function getDbConfig(): array
{
$config = Db::connect()->getConfig();
$config = Db::connect($this->dbConfig)->getConfig();
if (0 == $config['deploy']) {
$dbConfig = [

View File

@ -15,12 +15,13 @@ use think\migration\db\Table;
class Migrator extends AbstractMigration
{
/**
* @param string $tableName
* @param array $options
* @return Table
*/
public function table($tableName, $options = [])
public function table($tableName, $options = []): Table
{
return new Table($tableName, $options, $this->getAdapter());
}

View File

@ -11,6 +11,7 @@
namespace think\migration\command;
use InvalidArgumentException;
use Phinx\Db\Adapter\AdapterFactory;
use Phinx\Db\Adapter\ProxyAdapter;
use Phinx\Migration\AbstractMigration;
@ -18,6 +19,7 @@ use Phinx\Migration\MigrationInterface;
use Phinx\Util\Util;
use think\console\Input;
use think\console\Output;
use think\Exception;
use think\facade\Env;
use think\migration\Command;
use think\migration\Migrator;
@ -29,12 +31,19 @@ abstract class Migrate extends Command
*/
protected $migrations;
protected function getPath()
protected function getPath(): string
{
return Env::get('root_path') . 'database' . DIRECTORY_SEPARATOR . 'migrations';
}
protected function executeMigration(MigrationInterface $migration, $direction = MigrationInterface::UP)
/**
* @param MigrationInterface $migration
* @param string $direction
*
* @return void
* @throws Exception
*/
protected function executeMigration(MigrationInterface $migration, string $direction = MigrationInterface::UP)
{
$this->output->writeln('');
$this->output->writeln(' ==' . ' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' . ' <comment>' . (MigrationInterface::UP === $direction ? 'migrating' : 'reverting') . '</comment>');
@ -44,7 +53,7 @@ abstract class Migrate extends Command
$startTime = time();
$direction = (MigrationInterface::UP === $direction) ? MigrationInterface::UP : MigrationInterface::DOWN;
$migration->setAdapter($this->getAdapter());
$migration->setAdapter($this->getAdapter($migration->getDbConfig()));
// begin the transaction if the adapter supports it
if ($this->getAdapter()->hasTransactions()) {
@ -85,17 +94,26 @@ abstract class Migrate extends Command
$this->output->writeln(' ==' . ' <info>' . $migration->getVersion() . ' ' . $migration->getName() . ':</info>' . ' <comment>' . (MigrationInterface::UP === $direction ? 'migrated' : 'reverted') . ' ' . sprintf('%.4fs', $end - $start) . '</comment>');
}
protected function getVersionLog()
/**
* @return array
* @throws Exception
*/
protected function getVersionLog(): array
{
return $this->getAdapter()->getVersionLog();
}
protected function getVersions()
/**
* @return array
* @throws Exception
*/
protected function getVersions(): array
{
return $this->getAdapter()->getVersions();
}
protected function getMigrations()
protected function getMigrations(): array
{
if (null === $this->migrations) {
$phpFiles = glob($this->getPath() . DIRECTORY_SEPARATOR . '*.php', defined('GLOB_BRACE') ? GLOB_BRACE : 0);
@ -110,14 +128,14 @@ abstract class Migrate extends Command
$version = Util::getVersionFromFileName(basename($filePath));
if (isset($versions[$version])) {
throw new \InvalidArgumentException(sprintf('Duplicate migration - "%s" has the same version as "%s"', $filePath, $versions[$version]->getVersion()));
throw new InvalidArgumentException(sprintf('Duplicate migration - "%s" has the same version as "%s"', $filePath, $versions[$version]->getVersion()));
}
// convert the filename to a class name
$class = Util::mapFileNameToClassName(basename($filePath));
if (isset($fileNames[$class])) {
throw new \InvalidArgumentException(sprintf('Migration "%s" has the same name as "%s"', basename($filePath), $fileNames[$class]));
throw new InvalidArgumentException(sprintf('Migration "%s" has the same name as "%s"', basename($filePath), $fileNames[$class]));
}
$fileNames[$class] = basename($filePath);
@ -126,14 +144,14 @@ abstract class Migrate extends Command
/** @noinspection PhpIncludeInspection */
require_once $filePath;
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Could not find class "%s" in file "%s"', $class, $filePath));
throw new InvalidArgumentException(sprintf('Could not find class "%s" in file "%s"', $class, $filePath));
}
// instantiate it
$migration = new $class($version, $this->input, $this->output);
if (!($migration instanceof AbstractMigration)) {
throw new \InvalidArgumentException(sprintf('The class "%s" in file "%s" must extend \Phinx\Migration\AbstractMigration', $class, $filePath));
throw new InvalidArgumentException(sprintf('The class "%s" in file "%s" must extend \Phinx\Migration\AbstractMigration', $class, $filePath));
}
$versions[$version] = $migration;

View File

@ -13,6 +13,7 @@ use Phinx\Migration\MigrationInterface;
use think\console\input\Option as InputOption;
use think\console\Input;
use think\console\Output;
use think\Exception;
use think\migration\command\Migrate;
class Rollback extends Migrate
@ -44,7 +45,9 @@ EOT
*
* @param Input $input
* @param Output $output
*
* @return void
* @throws \Exception
*/
protected function execute(Input $input, Output $output)
{
@ -65,7 +68,15 @@ EOT
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
}
protected function rollback($version = null, $force = false)
/**
* @param $version
* @param bool $force
*
* @return void
* @throws Exception
*/
protected function rollback($version = null, bool $force = false)
{
$migrations = $this->getMigrations();
$versionLog = $this->getVersionLog();

View File

@ -9,6 +9,7 @@
namespace think\migration\command\migrate;
use Exception;
use Phinx\Migration\MigrationInterface;
use think\console\Input;
use think\console\input\Option as InputOption;
@ -43,7 +44,9 @@ EOT
*
* @param Input $input
* @param Output $output
* @return integer integer 0 on success, or an error code.
*
* @return void
* @throws Exception
*/
protected function execute(Input $input, Output $output)
{
@ -79,6 +82,12 @@ EOT
}
}
/**
* @param $version
*
* @return void
* @throws \think\Exception
*/
protected function migrate($version = null)
{
$migrations = $this->getMigrations();

View File

@ -1,13 +1,9 @@
<?php
// +----------------------------------------------------------------------
// | TopThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015 http://www.topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhangyajun <448901948@qq.com>
// +----------------------------------------------------------------------
\think\Console::addDefaultCommands([
use think\Console;
Console::addDefaultCommands([
"think\\migration\\command\\migrate\\Create",
"think\\migration\\command\\migrate\\Run",
"think\\migration\\command\\migrate\\Rollback",

View File

@ -95,20 +95,22 @@ class Table extends \Phinx\Db\Table
/**
* @param string $createdAtColumnName
* @param string $updatedAtColumnName
*
* @return \Phinx\Db\Table|Table
*/
public function addTimestamps($createdAtColumnName = 'create_time', $updatedAtColumnName = 'update_time')
public function addTimestamps(string $createdAtColumnName = 'create_time', string $updatedAtColumnName = 'update_time')
{
return parent::addTimestamps($createdAtColumnName, $updatedAtColumnName);
}
/**
* @param \Phinx\Db\Table\Column|string $columnName
* @param null $type
* @param string|null $type
* @param array $options
*
* @return \Phinx\Db\Table|Table
*/
public function addColumn($columnName, $type = null, $options = [])
public function addColumn($columnName, string $type = null, array $options = [])
{
if ($columnName instanceof Column && $columnName->getUnique()) {
$index = new Index();
@ -123,9 +125,10 @@ class Table extends \Phinx\Db\Table
* @param string $columnName
* @param null $newColumnType
* @param array $options
*
* @return \Phinx\Db\Table|Table
*/
public function changeColumn($columnName, $newColumnType = null, $options = [])
public function changeColumn(string $columnName, $newColumnType, array $options = [])
{
if ($columnName instanceof \Phinx\Db\Table\Column) {
return parent::changeColumn($columnName->getName(), $columnName, $options);