Skip to content

Commit

Permalink
Merge pull request #28019 from owncloud/terms-col-length
Browse files Browse the repository at this point in the history
Migration to fix term column length
  • Loading branch information
Vincent Petry authored Jul 3, 2017
2 parents 8b06e37 + 8eaa630 commit 5f3e6b2
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 2 deletions.
2 changes: 1 addition & 1 deletion core/Migrations/Version20170516100103.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function changeSchema(Schema $schema, array $options) {

$table->addColumn('term', Type::STRING, [
'notnull' => true,
'length' => 256
'length' => 255
]);

$table->setPrimaryKey(['id']);
Expand Down
59 changes: 59 additions & 0 deletions core/Migrations/Version20170526104128.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
namespace OC\Migrations;

use Doctrine\DBAL\Schema\Schema;
use OC\DB\QueryBuilder\Literal;
use OCP\IDBConnection;
use OCP\Migration\ISchemaMigration;

/**
* Update term column length to ensure index creation works on all db setups
*/
class Version20170526104128 implements ISchemaMigration {

public function changeSchema(Schema $schema, array $options) {
// Get the table
$prefix = $options['tablePrefix'];
$table = $schema->getTable("{$prefix}account_terms");

// Check column length
if($table->getColumn('term')->getLength() === 191) {
// we don't need to adjust it
return;
}

// Need to shorten the column by one character
// Check if we have any terms taking up 192 or more chars (unlikely)

/** @var IDBConnection $db */
$db = \OC::$server->getDatabaseConnection();


$qb = $db->getQueryBuilder();
$qb->select(['id', 'term'])
->from('account_terms')
->where($qb->expr()->gte($qb->expr()->length('term'), new Literal(192)));
$results = $qb->execute();

// Now shorten these terms
$db->beginTransaction();
while($longTerm = $results->fetch()) {
$qb->update('account_terms')
->where($qb->expr()->eq('id', $qb->createNamedParameter($longTerm['id'])))
->set('term', $qb->createNamedParameter($this->trimTerm($longTerm['term'])))
->execute();
}
$db->commit();

// Now update the column length
$table->getColumn('term')->setLength(191);
}

/**
* @param $longTerm
* @return string the shortened string ready for the new db column
*/
public function trimTerm($longTerm) {
return (string) substr($longTerm, 0, 191);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use OC\DB\QueryBuilder\Literal;
use OC\DB\QueryBuilder\QueryFunction;
use OC\DB\QueryBuilder\QuoteHelper;
use OC\Diagnostics\Query;
use OCP\DB\QueryBuilder\IExpressionBuilder;
use OCP\IDBConnection;

Expand Down Expand Up @@ -367,4 +368,14 @@ public function castColumn($column, $type) {
$this->helper->quoteColumnName($column)
);
}

/**
* Returns a query function to find the number of characters in a string column
* @param string $column
* @return string
*/
public function length($column) {
$column = $this->helper->quoteColumnName($column);
return new QueryFunction("LENGTH({$column})");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ public function iLike($x, $y, $type = null) {
return $this->expressionBuilder->comparison($x, " COLLATE {$characterSet}_general_ci LIKE", $y);
}

/**
* Use CHAR_LENGTH on MySQL to return number of characters not bytes.
* @inheritdoc
*/
public function length($column) {
$column = $this->helper->quoteColumnName($column);
return new QueryFunction("CHAR_LENGTH({$column})");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,13 @@ public function iLike($x, $y, $type = null) {
$y = $this->helper->quoteColumnName($y);
return new QueryFunction('REGEXP_LIKE('.$x.', \'^\' || REPLACE('.$y.', \'%\', \'.*\') || \'$\', \'i\')');
}

/**
* Use LENGTHC on Oracle to return multi-byte safe number of characters not bytes.
* @inheritdoc
*/
public function length($column) {
$column = $this->helper->quoteColumnName($column);
return new QueryFunction("LENGTHC({$column})");
}
}
4 changes: 4 additions & 0 deletions lib/private/User/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,10 @@ public function getSearchTerms() {
* @since 10.0.1
*/
public function setSearchTerms(array $terms) {
// Check length of terms, cut if too long
$terms = array_map(function($term) {
return substr($term, 0, 191);
}, $terms);
$this->mapper->setTermsForAccount($this->account->getId(), $terms);
}
}
7 changes: 7 additions & 0 deletions lib/public/DB/QueryBuilder/IExpressionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,11 @@ public function literal($input, $type = null);
* @since 9.0.0
*/
public function castColumn($column, $type);

/**
* @param $column
* @return string
* @since 10.0.3
*/
public function length($column);
}
26 changes: 26 additions & 0 deletions tests/lib/User/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,30 @@ public function testGetCloudId() {
->willReturn('http://localhost:8888/owncloud');
$this->assertEquals("foo@localhost:8888/owncloud", $this->user->getCloudId());
}

/**
* @dataProvider setTermsData
* @param array $terms
* @param array $expected
*/
public function testSettingAccountTerms(array $terms, array $expected) {
$account = $this->getMockBuilder(Account::class)->getMock();
$account->expects($this->once())->method('__call')->with('getId')->willReturn('foo');

$this->accountMapper->expects($this->once())
->method('setTermsForAccount')
->with('foo', $expected);

// Call the method
$user = new User($account, $this->accountMapper, null, $this->config);
$user->setSearchTerms($terms);
}

public function setTermsData() {
return [
'normal terms' => [['term1'], ['term1']],
'too long terms' => [['term1', str_repeat(".", 192)], ['term1', str_repeat(".", 191)]]
];
}

}
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
$OC_Version = [10, 0, 2, 1];
$OC_Version = [10, 0, 2, 3];

// The human readable string
$OC_VersionString = '10.0.2';
Expand Down

0 comments on commit 5f3e6b2

Please sign in to comment.