@Test public void testBasicExport() throws OdpsException, SQLException, IOException, ParseException { // Make sure test table not exists String odpsTableName = "basic_export_" + System.currentTimeMillis(); assertFalse("Table " + odpsTableName + " already exists", isTableExist(odpsTableName)); // Create the table we're exporting to createTable(); final int numRecords = 10; try { // Create the source ODPS table createOdpsTableWithRecords(odpsTableName, null, numRecords); runExport( getArgv( false, 10, 10, "--odps-table", odpsTableName, "--odps-project", PROJECT, "--odps-accessid", ACCESS_ID, "--odps-accesskey", ACCESS_KEY, "--odps-endpoint", ENDPOINT)); verifyExport(numRecords); } finally { deleteTable(odpsTableName); } }
public class OdpsExportTest extends ExportJobTestCase { static final String PROJECT = System.getProperty("sqoop.test.odps.project"); static final String ACCESS_ID = System.getProperty("sqoop.test.odps.accessid"); static final String ACCESS_KEY = System.getProperty("sqoop.test.odps.accesskey"); static final String ENDPOINT = System.getProperty("sqoop.test.odps.endpoint", "http://service.odps.aliyun.com/api"); private Odps odps; @Override @Before public void setUp() { Account account = new AliyunAccount(ACCESS_ID, ACCESS_KEY); odps = new Odps(account); odps.setDefaultProject(PROJECT); odps.setEndpoint(ENDPOINT); super.setUp(); } protected boolean isTableExist(String tableName) throws OdpsException { return odps.tables().exists(tableName); } protected void deleteTable(String tableName) throws OdpsException { odps.tables().delete(tableName, true); } /** * When generating data for export tests, each column is generated according to a ColumnGenerator. * Methods exist for determining what to put into text strings in the files to export, as well as * what the string representation of the column as returned by the database should look like. */ public interface ColumnGenerator { /** For a row with id rowNum, what should we write into that line of the text file to export? */ String getExportText(int rowNum); /** For a row with id rowNum, what should the database return for the given column's value? */ String getVerifyText(int rowNum); /** Return the column type to put in the CREATE TABLE statement. */ String getType(); /** Return the column type of the ODPS table. */ OdpsType getOdpsType(); String getDateFormat(); } /** * Return the column name for a column index. Each table contains two columns named 'id' and * 'msg', and then an arbitrary number of additional columns defined by ColumnGenerators. These * columns are referenced by idx 0, 1, 2... * * @param idx the index of the ColumnGenerator in the array passed to createTable(). * @return the name of the column */ protected String forIdx(int idx) { return "col" + idx; } protected void createOdpsTable( String tableName, String[] partitionCols, ColumnGenerator... extraCols) throws OdpsException { TableSchema schema = new TableSchema(); schema.addColumn(new Column("id", OdpsType.BIGINT)); schema.addColumn(new Column("msg", OdpsType.STRING)); int colNum = 0; for (ColumnGenerator generator : extraCols) { schema.addColumn(new Column(forIdx(colNum++), generator.getOdpsType())); } if (partitionCols != null) { for (String partition : partitionCols) { schema.addPartitionColumn(new Column(partition, OdpsType.STRING)); } } odps.tables().create(tableName, schema); } private PartitionSpec getSimplePartitionSpec(String[] partitionCols) { if (partitionCols == null || partitionCols.length == 0) { return null; } StringBuilder sb = new StringBuilder(); String sep = ""; for (String partitionCol : partitionCols) { sb.append(sep).append(partitionCol).append("='pt'"); sep = ","; } return new PartitionSpec(sb.toString()); } private Record getOdpsRecord( TableTunnel.UploadSession uploadSession, int idx, ColumnGenerator... extraCols) throws ParseException { Record record = uploadSession.newRecord(); record.setBigint("id", (long) idx); record.setString("msg", getMsgPrefix() + idx); int colNum = 0; for (ColumnGenerator generator : extraCols) { String field = forIdx(colNum++); String fieldValue = generator.getExportText(idx); switch (generator.getOdpsType()) { case STRING: record.setString(field, fieldValue); break; case BIGINT: record.setBigint(field, Long.parseLong(fieldValue)); break; case DATETIME: String dateFormat = generator.getDateFormat(); record.setDatetime(field, new SimpleDateFormat(dateFormat).parse(fieldValue)); break; case DOUBLE: record.setDouble(field, Double.parseDouble(fieldValue)); break; case DECIMAL: record.setDecimal(field, new BigDecimal(fieldValue)); break; default: throw new RuntimeException("Unknown column type: " + generator.getOdpsType()); } } return record; } protected void createOdpsTableWithRecords( String tableName, String[] partitionCols, int numRecords, ColumnGenerator... extraCols) throws OdpsException, IOException, ParseException { createOdpsTable(tableName, partitionCols, extraCols); TableTunnel tunnel = new TableTunnel(odps); PartitionSpec partitionSpec = getSimplePartitionSpec(partitionCols); TableTunnel.UploadSession uploadSession = partitionSpec == null ? tunnel.createUploadSession(PROJECT, tableName) : tunnel.createUploadSession(PROJECT, tableName, partitionSpec); RecordWriter recordWriter = uploadSession.openRecordWriter(0); for (int i = 0; i < numRecords; i++) { Record record = getOdpsRecord(uploadSession, i, extraCols); recordWriter.write(record); } recordWriter.close(); uploadSession.commit(new Long[] {0L}); } /** * Return a SQL statement that drops a table, if it exists. * * @param tableName the table to drop. * @return the SQL statement to drop that table. */ protected String getDropTableStatement(String tableName) { return "DROP TABLE " + tableName + " IF EXISTS"; } /** * Create the table definition to export to, removing any prior table. By specifying * ColumnGenerator arguments, you can add extra columns to the table of arbitrary type. */ public void createTable(ColumnGenerator... extraColumns) throws SQLException { Connection conn = getConnection(); PreparedStatement statement = conn.prepareStatement( getDropTableStatement(getTableName()), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); try { statement.executeUpdate(); conn.commit(); } finally { statement.close(); } StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE "); sb.append(getTableName()); sb.append(" (id INT NOT NULL PRIMARY KEY, msg VARCHAR(64)"); int colNum = 0; for (ColumnGenerator gen : extraColumns) { sb.append(", " + forIdx(colNum++) + " " + gen.getType()); } sb.append(")"); statement = conn.prepareStatement( sb.toString(), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); try { statement.executeUpdate(); conn.commit(); } finally { statement.close(); } } @Test public void testBasicExport() throws OdpsException, SQLException, IOException, ParseException { // Make sure test table not exists String odpsTableName = "basic_export_" + System.currentTimeMillis(); assertFalse("Table " + odpsTableName + " already exists", isTableExist(odpsTableName)); // Create the table we're exporting to createTable(); final int numRecords = 10; try { // Create the source ODPS table createOdpsTableWithRecords(odpsTableName, null, numRecords); runExport( getArgv( false, 10, 10, "--odps-table", odpsTableName, "--odps-project", PROJECT, "--odps-accessid", ACCESS_ID, "--odps-accesskey", ACCESS_KEY, "--odps-endpoint", ENDPOINT)); verifyExport(numRecords); } finally { deleteTable(odpsTableName); } } }