Skip to content

Commit 0671b60

Browse files
authored
Merge pull request #91 from keboola/jirka-ter-59-support-pk
TER-59 named constraint when creating table with PK
2 parents a8d3a23 + 2dfc4ac commit 0671b60

3 files changed

Lines changed: 173 additions & 5 deletions

File tree

src/Table/Teradata/TeradataTableQueryBuilder.php

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class TeradataTableQueryBuilder implements TableQueryBuilderInterface
2323
];
2424

2525
private const INVALID_PKS_FOR_TABLE = 'invalidPKs';
26+
private const PK_CONSTRAINT_NAME = 'kbc_pk';
2627

2728
public function getCreateTempTableCommand(string $schemaName, string $tableName, ColumnCollection $columns): string
2829
{
@@ -144,7 +145,8 @@ public function getCreateTableCommand(
144145

145146
if ($primaryKeys !== []) {
146147
$columnsSql .= sprintf(
147-
",\nPRIMARY KEY (%s)",
148+
",\nCONSTRAINT %s PRIMARY KEY (%s)",
149+
self::PK_CONSTRAINT_NAME,
148150
implode(
149151
', ',
150152
array_map(static fn($item) => TeradataQuote::quoteSingleIdentifier($item), $primaryKeys)
@@ -178,4 +180,52 @@ public function getCreateTableCommandFromDefinition(
178180
: []
179181
);
180182
}
183+
184+
/**
185+
* @param string[] $columns
186+
*/
187+
public function getAddPrimaryKeyCommand(string $schemaName, string $tableName, array $columns): string
188+
{
189+
return sprintf(
190+
'ALTER TABLE %s.%s ADD CONSTRAINT %s PRIMARY KEY (%s);',
191+
TeradataQuote::quoteSingleIdentifier($schemaName),
192+
TeradataQuote::quoteSingleIdentifier($tableName),
193+
self::PK_CONSTRAINT_NAME,
194+
implode(',', array_map(fn($item) => TeradataQuote::quoteSingleIdentifier($item), $columns))
195+
);
196+
}
197+
198+
public function getDropPrimaryKeyCommand(string $schemaName, string $tableName): string
199+
{
200+
return sprintf(
201+
'ALTER TABLE %s.%s DROP CONSTRAINT %s;',
202+
TeradataQuote::quoteSingleIdentifier($schemaName),
203+
TeradataQuote::quoteSingleIdentifier($tableName),
204+
self::PK_CONSTRAINT_NAME
205+
);
206+
}
207+
208+
/**
209+
* @param string[] $columns
210+
*/
211+
public function getCommandForDuplicates(string $schemaName, string $tableName, array $columns): string
212+
{
213+
$formattedColumns = implode(
214+
',',
215+
array_map(fn($item) => TeradataQuote::quoteSingleIdentifier($item), $columns)
216+
);
217+
return sprintf(
218+
<<<SQL
219+
SELECT MAX("_row_number_") AS "count" FROM
220+
(
221+
SELECT ROW_NUMBER() OVER (PARTITION BY %s ORDER BY %s) AS "_row_number_" FROM %s.%s
222+
) "data"
223+
SQL
224+
,
225+
$formattedColumns,
226+
$formattedColumns,
227+
TeradataQuote::quoteSingleIdentifier($schemaName),
228+
TeradataQuote::quoteSingleIdentifier($tableName),
229+
);
230+
}
181231
}

tests/Functional/Teradata/Table/TeradataTableQueryBuilderTest.php

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Generator;
99
use Keboola\TableBackendUtils\Column\ColumnCollection;
1010
use Keboola\TableBackendUtils\Column\Teradata\TeradataColumn;
11+
use Keboola\TableBackendUtils\Escaping\Teradata\TeradataQuote;
1112
use Keboola\TableBackendUtils\Table\Teradata\TeradataTableDefinition;
1213
use Keboola\TableBackendUtils\Table\Teradata\TeradataTableQueryBuilder;
1314
use Keboola\TableBackendUtils\Table\Teradata\TeradataTableReflection;
@@ -215,7 +216,7 @@ public function createTableTestSqlProvider(): Generator
215216
CREATE MULTISET TABLE "$testDb"."$tableName", FALLBACK
216217
("col1" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
217218
"col2" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
218-
PRIMARY KEY ("col1"));
219+
CONSTRAINT kbc_pk PRIMARY KEY ("col1"));
219220
EOT
220221
,
221222
];
@@ -231,7 +232,7 @@ public function createTableTestSqlProvider(): Generator
231232
CREATE MULTISET TABLE "$testDb"."$tableName", FALLBACK
232233
("col1" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
233234
"col2" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
234-
PRIMARY KEY ("col1", "col2"));
235+
CONSTRAINT kbc_pk PRIMARY KEY ("col1", "col2"));
235236
EOT
236237
,
237238
];
@@ -288,7 +289,7 @@ public function createTableTestFromDefinitionSqlProvider(): Generator
288289
CREATE MULTISET TABLE "$testDb"."$tableName", FALLBACK
289290
("col1" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
290291
"col2" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
291-
PRIMARY KEY ("col1"));
292+
CONSTRAINT kbc_pk PRIMARY KEY ("col1"));
292293
EOT
293294
,
294295
'createPrimaryKeys' => true,
@@ -310,7 +311,7 @@ public function createTableTestFromDefinitionSqlProvider(): Generator
310311
CREATE MULTISET TABLE "$testDb"."$tableName", FALLBACK
311312
("col1" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
312313
"col2" VARCHAR (32000) NOT NULL DEFAULT '' CHARACTER SET UNICODE,
313-
PRIMARY KEY ("col1", "col2"));
314+
CONSTRAINT kbc_pk PRIMARY KEY ("col1", "col2"));
314315
EOT
315316
,
316317
'createPrimaryKeys' => true,
@@ -366,4 +367,93 @@ public function testGetCreateTableCommandFromDefinition(
366367
self::assertSame([], $tableReflection->getPrimaryKeysNames());
367368
}
368369
}
370+
371+
public function testAddAndDropPK(): void
372+
{
373+
$testDb = $this->getDatabaseName();
374+
$tableName = self::TABLE_GENERIC;
375+
376+
// definition for table
377+
$definition = new TeradataTableDefinition(
378+
$testDb,
379+
$tableName,
380+
false,
381+
new ColumnCollection(
382+
[
383+
TeradataColumn::createGenericColumn('col1'),
384+
TeradataColumn::createGenericColumn('col2'),
385+
]
386+
),
387+
['col1']
388+
);
389+
390+
// create table
391+
$sql = $this->qb->getCreateTableCommandFromDefinition($definition, true);
392+
$this->connection->executeQuery($sql);
393+
394+
// drop PK - test that PK created in CREATE TABLE can be dropped
395+
$sql = $this->qb->getDropPrimaryKeyCommand($testDb, $tableName);
396+
$this->connection->executeQuery($sql);
397+
$ref1 = new TeradataTableReflection($this->connection, $testDb, $tableName);
398+
$this->assertEmpty($ref1->getPrimaryKeysNames());
399+
400+
// add PK
401+
$sql = $this->qb->getAddPrimaryKeyCommand($testDb, $tableName, ['col2']);
402+
$this->connection->executeQuery($sql);
403+
$ref1 = new TeradataTableReflection($this->connection, $testDb, $tableName);
404+
$this->assertEquals(['col2'], $ref1->getPrimaryKeysNames());
405+
406+
// drop again
407+
$sql = $this->qb->getDropPrimaryKeyCommand($testDb, $tableName);
408+
$this->connection->executeQuery($sql);
409+
$ref1 = new TeradataTableReflection($this->connection, $testDb, $tableName);
410+
$this->assertEmpty($ref1->getPrimaryKeysNames());
411+
}
412+
413+
414+
public function testDeduplication(): void
415+
{
416+
$testDb = $this->getDatabaseName();
417+
$tableName = self::TABLE_GENERIC;
418+
419+
// definition for table
420+
$definition = new TeradataTableDefinition(
421+
$testDb,
422+
$tableName,
423+
false,
424+
new ColumnCollection(
425+
[
426+
TeradataColumn::createGenericColumn('col1'),
427+
TeradataColumn::createGenericColumn('col2'),
428+
TeradataColumn::createGenericColumn('col3'),
429+
]
430+
),
431+
[]
432+
);
433+
434+
$sql = $this->qb->getCreateTableCommandFromDefinition($definition, true);
435+
$this->connection->executeQuery($sql);
436+
437+
foreach ([['1', '1', '1'], ['2', '2', '2'], ['3', '3', '3']] as $i) {
438+
$this->connection->executeStatement(sprintf(
439+
'INSERT INTO %s.%s VALUES (%s)',
440+
TeradataQuote::quoteSingleIdentifier($testDb),
441+
TeradataQuote::quoteSingleIdentifier($tableName),
442+
implode(',', $i)
443+
));
444+
}
445+
$duplicatedSql = $this->qb->getCommandForDuplicates($testDb, $tableName, ['col2', 'col3']);
446+
$data = $this->connection->fetchOne($duplicatedSql);
447+
$this->assertEquals('1', $data);
448+
449+
$this->connection->executeStatement(sprintf(
450+
'INSERT INTO %s.%s VALUES (5,3,3)',
451+
TeradataQuote::quoteSingleIdentifier($testDb),
452+
TeradataQuote::quoteSingleIdentifier($tableName)
453+
));
454+
455+
$duplicatedSql = $this->qb->getCommandForDuplicates($testDb, $tableName, ['col2', 'col3']);
456+
$data = $this->connection->fetchOne($duplicatedSql);
457+
$this->assertEquals('2', $data);
458+
}
369459
}

tests/Unit/Table/Teradata/TeradataTableQueryBuilderTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,32 @@ public function createTableInvalidPKsProvider(): Generator
6767
'exceptionString' => 'Trying to set PK on column col1 but this column is nullable',
6868
];
6969
}
70+
71+
72+
public function testGetPKCommand(): void
73+
{
74+
$this->assertEquals(
75+
'ALTER TABLE "myDB"."myTable" ADD CONSTRAINT kbc_pk PRIMARY KEY ("my","rules");',
76+
$this->qb->getAddPrimaryKeyCommand('myDB', 'myTable', ['my', 'rules'])
77+
);
78+
}
79+
80+
public function testGetDropPKCommand(): void
81+
{
82+
$this->assertEquals(
83+
'ALTER TABLE "myDB"."myTable" DROP CONSTRAINT kbc_pk;',
84+
$this->qb->getDropPrimaryKeyCommand('myDB', 'myTable')
85+
);
86+
}
87+
88+
public function testGetDuplicationCommand(): void
89+
{
90+
$this->assertEquals(
91+
'SELECT MAX("_row_number_") AS "count" FROM
92+
(
93+
SELECT ROW_NUMBER() OVER (PARTITION BY "my","rules" ORDER BY "my","rules") AS "_row_number_" FROM "myDB"."myTable"
94+
) "data"',
95+
$this->qb->getCommandForDuplicates('myDB', 'myTable', ['my', 'rules'])
96+
);
97+
}
7098
}

0 commit comments

Comments
 (0)