@@ -221,45 +221,133 @@ protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schem
221221 {
222222 LOGGER .info ("Inside getSchema" );
223223
224- String dataTypeQuery = "SELECT C.NAME AS COLUMN_NAME, TYPE_NAME(C.USER_TYPE_ID) AS DATA_TYPE " +
224+ String dataTypeQuery = "SELECT C.NAME AS COLUMN_NAME, TYPE_NAME(C.USER_TYPE_ID) AS DATA_TYPE, " +
225+ "C.PRECISION, C.SCALE " +
225226 "FROM sys.columns C " +
226227 "JOIN sys.types T " +
227228 "ON C.USER_TYPE_ID=T.USER_TYPE_ID " +
228229 "WHERE C.OBJECT_ID=OBJECT_ID(?)" ;
229230
230231 String dataType ;
231232 String columnName ;
232- HashMap <String , String > hashMap = new HashMap <>();
233- boolean found = false ;
233+ int precision ;
234+ int scale ;
235+ HashMap <String , ColumnInfo > hashMap = new HashMap <>();
234236
235237 SchemaBuilder schemaBuilder = SchemaBuilder .newBuilder ();
236- try (ResultSet resultSet = getColumns (jdbcConnection .getCatalog (), tableName , jdbcConnection .getMetaData ());
237- Connection connection = getJdbcConnectionFactory ().getConnection (getCredentialProvider ());
238+ try (Connection connection = getJdbcConnectionFactory ().getConnection (getCredentialProvider ());
238239 PreparedStatement stmt = connection .prepareStatement (dataTypeQuery )) {
239240 // fetch data types of columns and prepare map with column name and datatype.
240241 stmt .setString (1 , tableName .getSchemaName () + "." + tableName .getTableName ());
241242 try (ResultSet dataTypeResultSet = stmt .executeQuery ()) {
242243 while (dataTypeResultSet .next ()) {
243244 dataType = dataTypeResultSet .getString ("DATA_TYPE" );
244245 columnName = dataTypeResultSet .getString ("COLUMN_NAME" );
245- hashMap .put (columnName .trim (), dataType .trim ());
246+ precision = dataTypeResultSet .getInt ("PRECISION" );
247+ scale = dataTypeResultSet .getInt ("SCALE" );
248+ hashMap .put (columnName .trim (), new ColumnInfo (dataType .trim (), precision , scale ));
246249 }
247250 }
251+ }
252+
253+ String environment = DataLakeGen2Util .checkEnvironment (jdbcConnection .getMetaData ().getURL ());
254+
255+ if (DataLakeGen2Constants .SQL_POOL .equalsIgnoreCase (environment )) {
256+ // getColumns() method from SQL Server driver is causing an exception in case of Azure Serverless environment.
257+ // so doing explicit data type conversion
258+ schemaBuilder = doDataTypeConversion (hashMap );
259+ }
260+ else {
261+ schemaBuilder = doDataTypeConversionForNonCompatible (jdbcConnection , tableName , hashMap );
262+ }
263+ // add partition columns
264+ partitionSchema .getFields ().forEach (schemaBuilder ::addField );
265+ return schemaBuilder .build ();
266+ }
248267
268+ private SchemaBuilder doDataTypeConversion (HashMap <String , ColumnInfo > columnNameAndDataTypeMap )
269+ {
270+ SchemaBuilder schemaBuilder = SchemaBuilder .newBuilder ();
271+
272+ for (Map .Entry <String , ColumnInfo > entry : columnNameAndDataTypeMap .entrySet ()) {
273+ String columnName = entry .getKey ();
274+ ColumnInfo columnInfo = entry .getValue ();
275+ String dataType = columnInfo .getDataType ();
276+ ArrowType columnType = Types .MinorType .VARCHAR .getType ();
277+
278+ if ("char" .equalsIgnoreCase (dataType ) || "varchar" .equalsIgnoreCase (dataType ) ||
279+ "nchar" .equalsIgnoreCase (dataType ) || "nvarchar" .equalsIgnoreCase (dataType )
280+ || "time" .equalsIgnoreCase (dataType ) || "uniqueidentifier" .equalsIgnoreCase (dataType )) {
281+ columnType = Types .MinorType .VARCHAR .getType ();
282+ }
283+
284+ if ("binary" .equalsIgnoreCase (dataType ) || "varbinary" .equalsIgnoreCase (dataType )) {
285+ columnType = Types .MinorType .VARBINARY .getType ();
286+ }
287+
288+ if ("bit" .equalsIgnoreCase (dataType )) {
289+ columnType = Types .MinorType .BIT .getType ();
290+ }
291+
292+ if ("tinyint" .equalsIgnoreCase (dataType )) {
293+ columnType = Types .MinorType .TINYINT .getType ();
294+ }
295+
296+ if ("smallint" .equalsIgnoreCase (dataType )) {
297+ columnType = Types .MinorType .SMALLINT .getType ();
298+ }
299+
300+ if ("int" .equalsIgnoreCase (dataType )) {
301+ columnType = Types .MinorType .INT .getType ();
302+ }
303+
304+ if ("bigint" .equalsIgnoreCase (dataType )) {
305+ columnType = Types .MinorType .BIGINT .getType ();
306+ }
307+
308+ if ("decimal" .equalsIgnoreCase (dataType )) {
309+ columnType = new ArrowType .Decimal (columnInfo .getPrecision (), columnInfo .getScale (), 128 );
310+ }
311+
312+ if ("numeric" .equalsIgnoreCase (dataType ) || "float" .equalsIgnoreCase (dataType ) || "smallmoney" .equalsIgnoreCase (dataType ) || "money" .equalsIgnoreCase (dataType )) {
313+ columnType = Types .MinorType .FLOAT8 .getType ();
314+ }
315+
316+ if ("real" .equalsIgnoreCase (dataType )) {
317+ columnType = Types .MinorType .FLOAT4 .getType ();
318+ }
319+
320+ if ("date" .equalsIgnoreCase (dataType )) {
321+ columnType = Types .MinorType .DATEDAY .getType ();
322+ }
323+
324+ if ("datetime" .equalsIgnoreCase (dataType ) || "datetime2" .equalsIgnoreCase (dataType )
325+ || "smalldatetime" .equalsIgnoreCase (dataType ) || "datetimeoffset" .equalsIgnoreCase (dataType )) {
326+ columnType = Types .MinorType .DATEMILLI .getType ();
327+ }
328+
329+ schemaBuilder .addField (FieldBuilder .newBuilder (columnName , columnType ).build ());
330+ }
331+ return schemaBuilder ;
332+ }
333+
334+ private SchemaBuilder doDataTypeConversionForNonCompatible (Connection jdbcConnection , TableName tableName , HashMap <String , ColumnInfo > columnNameAndDataTypeMap ) throws SQLException
335+ {
336+ SchemaBuilder schemaBuilder = SchemaBuilder .newBuilder ();
337+
338+ try (ResultSet resultSet = getColumns (jdbcConnection .getCatalog (), tableName , jdbcConnection .getMetaData ())) {
339+ boolean found = false ;
249340 while (resultSet .next ()) {
250341 Optional <ArrowType > columnType = JdbcArrowTypeConverter .toArrowType (
251342 resultSet .getInt ("DATA_TYPE" ),
252343 resultSet .getInt ("COLUMN_SIZE" ),
253344 resultSet .getInt ("DECIMAL_DIGITS" ),
254345 configOptions );
255- columnName = resultSet .getString ("COLUMN_NAME" );
346+ String columnName = resultSet .getString ("COLUMN_NAME" );
347+ ColumnInfo columnInfo = columnNameAndDataTypeMap .get (columnName );
256348
257- dataType = hashMap .get (columnName );
258- LOGGER .debug ("columnName: " + columnName );
259- LOGGER .debug ("dataType: " + dataType );
260-
261- if (dataType != null && DataLakeGen2DataType .isSupported (dataType )) {
262- columnType = Optional .of (DataLakeGen2DataType .fromType (dataType ));
349+ if (columnInfo != null && DataLakeGen2DataType .isSupported (columnInfo .getDataType ())) {
350+ columnType = Optional .of (DataLakeGen2DataType .fromType (columnInfo .getDataType ()));
263351 }
264352
265353 /**
@@ -269,31 +357,58 @@ protected Schema getSchema(Connection jdbcConnection, TableName tableName, Schem
269357 columnType = Optional .of (Types .MinorType .VARCHAR .getType ());
270358 }
271359
272- LOGGER .debug ("columnType: " + columnType );
273360 if (columnType .isPresent () && SupportedTypes .isSupported (columnType .get ())) {
274361 schemaBuilder .addField (FieldBuilder .newBuilder (columnName , columnType .get ()).build ());
275362 found = true ;
276363 }
277364 else {
278- LOGGER .error ("getSchema: Unable to map type for column[" + columnName + " ] to a supported type, attempted " + columnType );
365+ LOGGER .error ("getSchema: Unable to map type for column[{} ] to a supported type, attempted {}" , columnName , columnType );
279366 }
280367 }
281368 if (!found ) {
369+ LOGGER .error ("Could not find any supported columns in table: {}.{}" , tableName .getSchemaName (), tableName .getTableName ());
282370 throw new RuntimeException ("Could not find table in " + tableName .getSchemaName ());
283371 }
284-
285- partitionSchema .getFields ().forEach (schemaBuilder ::addField );
286- return schemaBuilder .build ();
287372 }
373+ return schemaBuilder ;
288374 }
289375
290376 @ Override
291377 protected CredentialsProvider getCredentialProvider ()
292378 {
293379 return CredentialsProviderFactory .createCredentialProvider (
294- getDatabaseConnectionConfig ().getSecret (),
295- getCachableSecretsManager (),
296- new DataLakeGen2OAuthCredentialsProvider ()
380+ getDatabaseConnectionConfig ().getSecret (),
381+ getCachableSecretsManager (),
382+ new DataLakeGen2OAuthCredentialsProvider ()
297383 );
298384 }
299385}
386+
387+ class ColumnInfo
388+ {
389+ private final String dataType ;
390+ private final int precision ;
391+ private final int scale ;
392+
393+ public ColumnInfo (String dataType , int precision , int scale )
394+ {
395+ this .dataType = dataType ;
396+ this .precision = precision ;
397+ this .scale = scale ;
398+ }
399+
400+ public String getDataType ()
401+ {
402+ return dataType ;
403+ }
404+
405+ public int getPrecision ()
406+ {
407+ return precision ;
408+ }
409+
410+ public int getScale ()
411+ {
412+ return scale ;
413+ }
414+ }
0 commit comments