2626import org .apache .drill .common .PlanStringBuilder ;
2727import org .apache .drill .common .exceptions .UserException ;
2828import org .apache .drill .common .logical .FormatPluginConfig ;
29+ import org .apache .drill .common .types .TypeProtos ;
2930import org .apache .drill .shaded .guava .com .google .common .collect .ImmutableList ;
3031import org .slf4j .Logger ;
3132import org .slf4j .LoggerFactory ;
3233
3334import java .util .ArrayList ;
35+ import java .util .Arrays ;
3436import java .util .Collections ;
3537import java .util .HashSet ;
3638import java .util .List ;
@@ -43,11 +45,15 @@ public class FixedwidthFormatConfig implements FormatPluginConfig {
4345 private static final Logger logger = LoggerFactory .getLogger (FixedwidthFormatConfig .class );
4446 private final List <String > extensions ;
4547 private final List <FixedwidthFieldConfig > fields ;
48+ private final List <TypeProtos .MinorType > validDataTypes = Arrays .asList (new TypeProtos .MinorType []{TypeProtos .MinorType .INT , TypeProtos .MinorType .VARCHAR ,
49+ TypeProtos .MinorType .DATE , TypeProtos .MinorType .TIME , TypeProtos .MinorType .TIMESTAMP , TypeProtos .MinorType .FLOAT4 ,
50+ TypeProtos .MinorType .FLOAT8 , TypeProtos .MinorType .BIGINT , TypeProtos .MinorType .VARDECIMAL });
4651
4752 @ JsonCreator
4853 public FixedwidthFormatConfig (@ JsonProperty ("extensions" ) List <String > extensions ,
4954 @ JsonProperty ("fields" ) List <FixedwidthFieldConfig > fields ) {
5055 this .extensions = extensions == null ? Collections .singletonList ("fwf" ) : ImmutableList .copyOf (extensions );
56+ Collections .sort (fields );
5157 this .fields = fields ;
5258
5359 validateFieldInput ();
@@ -133,13 +139,56 @@ public List<Integer> getFieldWidths() {
133139 return result ;
134140 }
135141
142+ @ JsonIgnore
143+ public void setFieldWidths (int i , int value ) {
144+ for (FixedwidthFieldConfig field : fields ) {
145+ if (field .getIndex () == i ) {
146+ field .setWidth (value );
147+ }
148+ }
149+ }
150+
151+ @ JsonIgnore
152+ public List <TypeProtos .MinorType > getFieldTypes () {
153+ List <TypeProtos .MinorType > result = new ArrayList <>();
154+ if (! hasFields ()) {
155+ return result ;
156+ }
157+
158+ for (FixedwidthFieldConfig field : fields ) {
159+ result .add (field .getType ());
160+ }
161+ return result ;
162+ }
163+
164+ @ JsonIgnore
165+ public void setFieldTypes (int i ) {
166+ for (FixedwidthFieldConfig field : fields ) {
167+ if (field .getIndex () == i ) {
168+ field .setType ();
169+ }
170+ }
171+ }
172+
136173 @ JsonIgnore
137174 public void validateFieldInput (){
138175 Set <String > uniqueNames = new HashSet <>();
139- for (String name : this .getFieldNames ()){
140- /*if (name.length() == 0){
176+ List <Integer > fieldIndices = this .getFieldIndices ();
177+ List <Integer > fieldWidths = this .getFieldWidths ();
178+ List <String > fieldNames = this .getFieldNames ();
179+ List <TypeProtos .MinorType > fieldTypes = this .getFieldTypes ();
180+ int width = 0 ;
181+ int prevIndexAndWidth = -1 ;
141182
142- }*/
183+ // Ensure no two fields have the same name
184+ for (String name : this .getFieldNames ()){
185+ if (name .length () == 0 ){
186+ throw UserException
187+ .validationError ()
188+ .message ("Blank field name detected." )
189+ .addContext ("Plugin" , FixedwidthFormatPlugin .DEFAULT_NAME )
190+ .build (logger );
191+ }
143192 if (uniqueNames .contains (name )){
144193 throw UserException
145194 .validationError ()
@@ -149,10 +198,6 @@ public void validateFieldInput(){
149198 }
150199 uniqueNames .add (name );
151200 }
152- List <Integer > fieldIndices = this .getFieldIndices ();
153- List <Integer > fieldWidths = this .getFieldWidths ();
154- List <String > fieldNames = this .getFieldNames ();
155- int prevIndexAndWidth = -1 ;
156201
157202 //assuming that fieldIndices is the same size as fieldWidths, width is required
158203 for (int i = 0 ; i <fieldIndices .size (); i ++) {
@@ -163,24 +208,35 @@ public void validateFieldInput(){
163208 .addContext ("Plugin" , FixedwidthFormatPlugin .DEFAULT_NAME )
164209 .build (logger );
165210 }
166- /*
167- else if (fieldWidths.get(i) == null || fieldWidths.get(i) < 1) {
211+ else if (fieldIndices .get (i ) <= prevIndexAndWidth ) {
212+ throw UserException
213+ .validationError ()
214+ .message ("Overlapping fields: " + fieldNames .get (i -1 ) + " and " + fieldNames .get (i ))
215+ .addContext ("Plugin" , FixedwidthFormatPlugin .DEFAULT_NAME )
216+ .build (logger );
217+ }
218+
219+ if (fieldWidths .get (i ) == null || fieldWidths .get (i ) < 1 ) {
220+ // Come back to this - can we calculate this instead of throwing an error?
168221 if (i == fieldIndices .size ()-1 ) {
169- Integer width =
222+ throw UserException
223+ .validationError ()
224+ .message ("Width for field '" + fieldNames .get (i ) + "' is empty." )
225+ .addContext ("Plugin" , FixedwidthFormatPlugin .DEFAULT_NAME )
226+ .build (logger );
170227 }
171- Integer width = fieldIndices.get(i+1) - fieldIndices.get(i);
172- fieldWidths.set(i, width);
228+ width = fieldIndices .get (i +1 ) - fieldIndices .get (i ) - 1 ;
229+ setFieldWidths (fieldIndices .get (i ), width );
230+ }
231+ prevIndexAndWidth = fieldIndices .get (i ) + fieldWidths .get (i );
232+
233+ // Validate Field Type
234+ if (fieldTypes .get (i ) == null || fieldTypes .get (i ).toString ().length () == 0 ) {
235+ setFieldTypes (fieldIndices .get (i ));
236+ }
237+ else if (!validDataTypes .contains (fieldTypes .get (i ))){
238+ setFieldTypes (fieldIndices .get (i )); //Should we throw an error or default to VARCHAR for data types that are not yet available in this plugin
173239 }
174- */
175- else if (fieldIndices .get (i ) <= prevIndexAndWidth ) {
176- throw UserException
177- .validationError ()
178- .message ("Overlapping fields: " + fieldNames .get (i -1 ) + " and " + fieldNames .get (i ))
179- .addContext ("Plugin" , FixedwidthFormatPlugin .DEFAULT_NAME )
180- .build (logger );
181- }
182- prevIndexAndWidth = fieldIndices .get (i ) + fieldWidths .get (i );
183240 }
184241 }
185-
186242}
0 commit comments