Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ static function ($columnName) {
},
$stagingTableDefinition->getColumnsNames(),
);
break;
}

$dest = sprintf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,159 @@ public function testGetUpdateWithPkCommandNullManipulationWithTimestampFeatures(
], $result);
}


public function nullManipulationWithTimestampFeaturesTableWithoutTypes(): Generator
{
yield 'default' => [
'default',
// phpcs:ignore
'UPDATE "import_export_test_schema"."import_export_test_test" AS "dest" SET "col1" = COALESCE("src"."col1", \'\'), "col2" = COALESCE("src"."col2", \'\'), "_timestamp" = \'2020-01-01 01:01:01\' FROM "import_export_test_schema"."__temp_stagingTable" AS "src" WHERE "dest"."col1" = COALESCE("src"."col1", \'\') AND (COALESCE(TO_VARCHAR("dest"."col1"), \'\') != COALESCE("src"."col1", \'\') OR COALESCE(TO_VARCHAR("dest"."col2"), \'\') != COALESCE("src"."col2", \'\'))',
false,
];
yield 'new-native-types' => [
'new-native-types',
// phpcs:ignore
'UPDATE "import_export_test_schema"."import_export_test_test" AS "dest" SET "col1" = COALESCE("src"."col1", \'\'), "col2" = COALESCE("src"."col2", \'\'), "_timestamp" = \'2020-01-01 01:01:01\' FROM "import_export_test_schema"."__temp_stagingTable" AS "src" WHERE "dest"."col1" = COALESCE("src"."col1", \'\') AND (COALESCE(TO_VARCHAR("dest"."col1"), \'\') != COALESCE("src"."col1", \'\') OR COALESCE(TO_VARCHAR("dest"."col2"), \'\') != COALESCE("src"."col2", \'\'))',
false,
];
yield 'native-types_timestamp-bc' => [
'native-types_timestamp-bc',
// phpcs:ignore
'UPDATE "import_export_test_schema"."import_export_test_test" AS "dest" SET "col1" = COALESCE("src"."col1", \'\'), "col2" = COALESCE("src"."col2", \'\'), "_timestamp" = \'2020-01-01 01:01:01\' FROM "import_export_test_schema"."__temp_stagingTable" AS "src" WHERE "dest"."col1" = COALESCE("src"."col1", \'\') AND (COALESCE(TO_VARCHAR("dest"."col1"), \'\') != COALESCE("src"."col1", \'\') OR COALESCE(TO_VARCHAR("dest"."col2"), \'\') != COALESCE("src"."col2", \'\'))',
false,
];
}

/**
* @dataProvider nullManipulationWithTimestampFeaturesTableWithoutTypes
*/
public function testGetUpdateWithPkCommandNullManipulationWithTimestampFeaturesTableWithoutTypes(
string $feature,
string $expectedSQL,
bool $expectedTimestampChange,
): void {
$timestampInit = new DateTime('2020-01-01 00:00:01');
$timestampSet = new DateTime('2020-01-01 01:01:01');
$this->createTestSchema();
$this->createTestTableWithColumns(true);
$this->createStagingTableWithData(true);
$this->connection->executeStatement(
sprintf(
'INSERT INTO %s.%s("pk1","pk2","col1","col2") VALUES (3,3,\'\',NULL)',
self::TEST_SCHEMA_QUOTED,
self::TEST_STAGING_TABLE_QUOTED,
),
);

// create fake destination and say that there is pk on col1
$fakeDestination = new SnowflakeTableDefinition(
self::TEST_SCHEMA,
self::TEST_TABLE,
true,
new ColumnCollection([
$this->createNullableGenericColumn('col1'),
$this->createNullableGenericColumn('col2'),
]),
['col1'],
);
// create fake stage and say that there is less columns
$fakeStage = new SnowflakeTableDefinition(
self::TEST_SCHEMA,
self::TEST_STAGING_TABLE,
true,
new ColumnCollection([
$this->createNullableGenericColumn('col1'),
$this->createNullableGenericColumn('col2'),
]),
[],
);

$this->connection->executeStatement(
sprintf(
'INSERT INTO %s("id","col1","col2","_timestamp") VALUES (1,\'1\',\'1\',\'%s\')',
self::TEST_TABLE_IN_SCHEMA,
$timestampInit->format(DateTimeHelper::FORMAT),
),
);
$this->connection->executeStatement(
sprintf(
'INSERT INTO %s("id","col1","col2","_timestamp") VALUES (3,\'3\',NULL,\'%s\')',
self::TEST_TABLE_IN_SCHEMA,
$timestampInit->format(DateTimeHelper::FORMAT),
),
);

$result = $this->connection->fetchAllAssociative(sprintf(
'SELECT * FROM %s',
self::TEST_TABLE_IN_SCHEMA,
));

self::assertEqualsCanonicalizing([
[
'id' => '1',
'col1' => '1',
'col2' => '1',
'_timestamp' => $timestampInit->format(DateTimeHelper::FORMAT),
],
[
'id' => '3',
'col1' => '3',
'col2' => null,
'_timestamp' => $timestampInit->format(DateTimeHelper::FORMAT),
],
], $result);

// use timestamp
$options = new SnowflakeImportOptions(
convertEmptyValuesToNull: [],
isIncremental: false,
useTimestamp: true,
numberOfIgnoredLines: 0,
requireSameTables: SnowflakeImportOptions::SAME_TABLES_REQUIRED,
nullManipulation: SnowflakeImportOptions::NULL_MANIPULATION_ENABLED,
ignoreColumns: [ToStageImporterInterface::TIMESTAMP_COLUMN_NAME],
features: [$feature],
);
$sql = $this->getBuilder()->getUpdateWithPkCommand(
$fakeStage,
$fakeDestination,
$options,
$timestampSet->format(DateTimeHelper::FORMAT),
);

self::assertEquals(
$expectedSQL,
$sql,
);
$this->connection->executeStatement($sql);

$result = $this->connection->fetchAllAssociative(sprintf(
'SELECT * FROM %s',
self::TEST_TABLE_IN_SCHEMA,
));

$assertTimestamp = $timestampInit;
if ($expectedTimestampChange) {
$assertTimestamp = $timestampSet;
}

// timestamp was updated to $timestampSet but there is same row as in stage table so no other value is updated
self::assertEqualsCanonicalizing([
[
'id' => '1',
'col1' => '1',
'col2' => '1',
'_timestamp' => $assertTimestamp->format(DateTimeHelper::FORMAT),
], // timestamp is not update when row has same value
[
'id' => '3',
'col1' => '3',
'col2' => '',
'_timestamp' => $timestampInit->format(DateTimeHelper::FORMAT),
], // timestamp is not update when row has same value and there is null
], $result);
}

private function getStagingTableDefinition(): SnowflakeTableDefinition
{
return new SnowflakeTableDefinition(
Expand Down