Skip to content

Commit

Permalink
SNOW-852665: Allow ~ in PUT/GET file path (#1481)
Browse files Browse the repository at this point in the history
allow ~ in PUT/GET file path name
  • Loading branch information
sfc-gh-ext-simba-lb authored Jul 21, 2023
1 parent 832de67 commit 15a45ac
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -864,8 +864,8 @@ private void parseCommand() throws SnowflakeSQLException {
localLocation = systemGetProperty("user.home") + localLocation.substring(1);
}

// it should not contain any ~ after the above replacement
if (localLocation.contains("~")) {
// it should not start with any ~ after the above replacement
if (localLocation.startsWith("~")) {
throw new SnowflakeSQLLoggedException(
session,
ErrorCode.PATH_NOT_DIRECTORY.getMessageCode(),
Expand Down Expand Up @@ -1690,7 +1690,9 @@ static Set<String> expandFileNames(String[] filePathList) throws SnowflakeSQLExc

for (String path : filePathList) {
// replace ~ with user home
path = path.replace("~", systemGetProperty("user.home"));
if (path.startsWith("~")) {
path = systemGetProperty("user.home") + path.substring(1);
}

// user may also specify files relative to current directory
// add the current path if that is the case
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ public void testProcessFileNames() throws Exception {
System.setProperty("user.home", folderName);

String[] locations = {
folderName + "/Tes*Fil*A", folderName + "/TestFil?B", "~/TestFileC", "TestFileD"
folderName + "/Tes*Fil*A",
folderName + "/TestFil?B",
"~/TestFileC",
"TestFileD",
folderName + "/TestFileE~"
};

Set<String> files = SnowflakeFileTransferAgent.expandFileNames(locations);
Expand All @@ -38,6 +42,7 @@ public void testProcessFileNames() throws Exception {
assertTrue(files.contains(folderName + "/TestFileB"));
assertTrue(files.contains(folderName + "/TestFileC"));
assertTrue(files.contains(folderName + "/TestFileD"));
assertTrue(files.contains(folderName + "/TestFileE~"));
}

@Test
Expand Down
101 changes: 97 additions & 4 deletions src/test/java/net/snowflake/client/jdbc/FileUploaderLatestIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
*/
package net.snowflake.client.jdbc;

import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;

import com.amazonaws.services.s3.model.ObjectMetadata;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
Expand All @@ -28,6 +27,7 @@
import net.snowflake.client.core.SFStatement;
import net.snowflake.client.jdbc.cloud.storage.*;
import net.snowflake.common.core.RemoteStoreFileEncryptionMaterial;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
Expand Down Expand Up @@ -810,4 +810,97 @@ private void uploadFileToStageUsingStream(Connection connection, boolean overwri

sfAgent.execute();
}

@Test
public void testUploadFileWithTildeInFolderName() throws SQLException, IOException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
Writer writer = null;
Path topDataDir = null;

try {
topDataDir = Files.createTempDirectory("testPutFileTilde");
topDataDir.toFile().deleteOnExit();

// create sub directory where the name includes ~
Path subDir = Files.createDirectories(Paths.get(topDataDir.toString(), "snowflake~"));

// create a test data
File dataFile = new File(subDir.toFile(), "test.txt");
writer =
new BufferedWriter(
new OutputStreamWriter(
Files.newOutputStream(Paths.get(dataFile.getCanonicalPath())),
StandardCharsets.UTF_8));
writer.write("1,test1");
writer.close();

connection = getConnection();
statement = connection.createStatement();
statement.execute("create or replace stage testStage");
String sql = String.format("PUT 'file://%s' @testStage", dataFile.getCanonicalPath());

// Escape backslashes. This must be done by the application.
sql = sql.replaceAll("\\\\", "\\\\\\\\");
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
assertEquals("UPLOADED", resultSet.getString("status"));
}
} finally {
if (connection != null) {
connection.createStatement().execute("drop stage if exists testStage");
}
closeSQLObjects(resultSet, statement, connection);
if (writer != null) {
writer.close();
}
FileUtils.deleteDirectory(topDataDir.toFile());
}
}

@Test
public void testUploadWithTildeInPath() throws SQLException, IOException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
Writer writer = null;
Path subDir = null;

try {

String homeDir = systemGetProperty("user.home");

// create sub directory where the name includes ~
subDir = Files.createDirectories(Paths.get(homeDir, "snowflake"));

// create a test data
File dataFile = new File(subDir.toFile(), "test.txt");
writer =
new BufferedWriter(
new OutputStreamWriter(
Files.newOutputStream(Paths.get(dataFile.getCanonicalPath())),
StandardCharsets.UTF_8));
writer.write("1,test1");
writer.close();

connection = getConnection();
statement = connection.createStatement();
statement.execute("create or replace stage testStage");

resultSet = statement.executeQuery("PUT 'file://~/snowflake/test.txt' @testStage");
while (resultSet.next()) {
assertEquals("UPLOADED", resultSet.getString("status"));
}
} finally {
if (connection != null) {
connection.createStatement().execute("drop stage if exists testStage");
}
closeSQLObjects(resultSet, statement, connection);
if (writer != null) {
writer.close();
}
FileUtils.deleteDirectory(subDir.toFile());
}
}
}

0 comments on commit 15a45ac

Please sign in to comment.