package com.savy3.hadoop.hive.serde2.cobol; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class CobolFieldDecl { int levelNo; String fieldName; String picClause; String value; List<String> fieldParts; String fieldType; Map<String, Integer> fieldProperties; private TypeInfo fieldTypeInfo; boolean isIgnoreField, isDepending, isRedefines; boolean isArray; public CobolFieldDecl(String line) throws NumberFormatException { line = line.replaceAll("[\\t\\n\\r]", " "); line = line.replaceAll("( )+", " ").trim(); this.fieldParts = Arrays.asList(line.trim().toLowerCase().split("\\s")); if (fieldParts.size() <= 1) return; this.fieldProperties = new HashMap<String, Integer>(); this.fieldType = ""; setLevelNo(); setFieldName(); setPicClause(); setValue(); if (getRedefines() != null) isRedefines = true; if (getDepending() != null) isDepending = true; if (picClause != "") { setFieldTypeLength(); if (this.picClause != "") setFieldTypeInfo(); } else { isIgnoreField = true; if (getDepending() != null) { isDepending = true; fieldType = "array<struct"; fieldProperties.put("length", 0); } else { if (getRedefines() != null) isRedefines = true; fieldType = "struct"; fieldProperties.put("length", 0); } } } @Override public String toString() { return "CobolFieldDecl [levelNo=" + levelNo + ", fieldName=" + fieldName + ", picClause=" + picClause + ", value=" + value + ", fieldParts=" + fieldParts + ", fieldType=" + fieldType + ", fieldProperties=" + fieldProperties + ", fieldTypeInfo=" + fieldTypeInfo + ", isIgnoreField=" + isIgnoreField + ", isDepending=" + isDepending + ", isRedefines=" + isRedefines + ", isArray=" + isArray + "]"; } private void setFieldTypeInfo() { this.fieldTypeInfo = TypeInfoUtils .getTypeInfoFromTypeString(this.fieldType); } public TypeInfo getFieldTypeInfo() { return fieldTypeInfo; } void setLevelNo() throws NumberFormatException { try { this.levelNo = Integer.parseInt(this.fieldParts.get(0).trim()); } catch (NumberFormatException e) { System.out.println("Exception with line " + fieldParts); throw e; } } void setFieldName() { this.fieldName = this.fieldParts.get(1).trim().replace('-', '_') .replace('.', ' ').trim(); } String getRedefines() { int redefineIndex = this.fieldParts.indexOf("redefines"); if (redefineIndex > -1) return this.fieldParts.get(redefineIndex + 1).trim() .replace('-', '_'); else return null; } String getDepending() { int occurTimesIndex = this.fieldParts.indexOf("times"); if (occurTimesIndex > -1) { fieldProperties.put("times", Integer.parseInt(this.fieldParts.get(occurTimesIndex - 1))); } else return null; int occurToIndex = this.fieldParts.indexOf("to"); if (occurToIndex > -1) { fieldProperties.put( "times", Integer.parseInt(this.fieldParts.get(occurTimesIndex - 1)) - Integer.parseInt(this.fieldParts .get(occurToIndex - 1)) + 1); } int dependIndex = this.fieldParts.indexOf("depending"); if (dependIndex > -1) { if (this.fieldParts.get(dependIndex + 1).equalsIgnoreCase("on")) return this.fieldParts.get(dependIndex + 2).trim() .replace('-', '_'); else return this.fieldParts.get(dependIndex + 1).trim() .replace('-', '_'); } else return "OCCURS"; } void setPicClause() { int picIndex = this.fieldParts.indexOf("pic"); if (picIndex > -1) this.picClause = this.fieldParts.get(picIndex + 1); else this.picClause = ""; // System.out.println("picIndex"+picClause); } void setValue() { int valIndex = this.fieldParts.indexOf("value"); if (valIndex > -1) { this.value = this.fieldParts.get(valIndex + 1); } else { this.value = ""; } } void setFieldTypeLength() throws RuntimeException, NumberFormatException { switch (this.picClause.charAt(0)) { case 'x': case 'a': fieldType = "string"; validateStringFormat(); break; case 'n': case '9': case 'z': case '+': case '-': case '$': case 's': fieldType = "integer"; validateNumberFormat(); break; default: fieldType = ""; // may need to throw exception } if (fieldType == "string") { } } void validateStringFormat() { if (this.picClause.contains("(")) { String[] s = this.picClause.split("\\(|\\)|\\."); if (s.length == 2) { try { fieldProperties.put("length", Integer.parseInt(s[1])); } catch (NumberFormatException e) { throw e; } } else { throw new RuntimeException( "Alphanumeric Picture clause has more brackets"); } } else { if (this.picClause.matches("x+|a+")) fieldProperties.put("length", this.picClause.length()); else { this.fieldType = ""; throw new RuntimeException( "Alphanumeric Picture clause incorrect '" + this.picClause + "' for field" + this.fieldName + " level No:" + this.levelNo); } } if (fieldProperties.get("length") < 65355) { this.fieldType = "varchar(" + fieldProperties.get("length") + ")"; } } void validateNumberFormat() { String[] s = this.picClause.split("\\(|\\)|\\."); int divideFactor = 1; try { if (this.fieldParts.indexOf("comp-3") > -1) { fieldProperties.put("comp", 3); divideFactor = 2; } switch (s.length) { case 1: fieldProperties.put( "length", new Integer((int) Math.ceil((double) s[0].length() / divideFactor))); break; case 2: fieldProperties.put( "length", new Integer((int) Math.ceil(Double.parseDouble(s[1]) / divideFactor))); break; case 3: fieldProperties.put( "length", new Integer((int) Math.ceil((Double.parseDouble(s[1]) + s[2].length() - 1) / divideFactor))); if (this.picClause.charAt(0) == '9' || this.picClause.charAt(0) == 'n') { fieldProperties.put("decimal", Integer.parseInt(s[1])); } else { fieldProperties.put("decimal", Integer.parseInt(s[1]) - 1); } break; case 4: fieldProperties .put("length", new Integer((int) Math.ceil((Double .parseDouble(s[1]) + Integer .parseInt(s[3])) / divideFactor))); if (this.picClause.charAt(0) == '9' || this.picClause.charAt(0) == 'n') { fieldProperties.put("decimal", Integer.parseInt(s[1])); } else { fieldProperties.put("decimal", Integer.parseInt(s[1]) - 1); } break; default: throw new RuntimeException( "Alphanumeric Picture clause has more brackets"); } // System.out.println("CFD: length"+s.length+"-"+Math.ceil(Double.parseDouble(s[1])/(double)divideFactor)+"-"+fieldProperties.get("length")); if (s.length < 3) { if (fieldProperties.get("length") * divideFactor < 3) this.fieldType = "tinyint"; else if (fieldProperties.get("length") * divideFactor < 5) this.fieldType = "smallint"; else if (fieldProperties.get("length") * divideFactor < 10) this.fieldType = "int"; else if (fieldProperties.get("length") * divideFactor < 19) this.fieldType = "bigint"; else this.fieldType = "string"; } else { this.fieldType = "decimal(" + fieldProperties.get("length") * divideFactor + "," + (fieldProperties.get("length") * divideFactor - fieldProperties.get("decimal")) + ")"; } } catch (NumberFormatException e) { throw e; } } public String getFieldType() { return fieldType; } public Map<String, Integer> getFieldProperties() { return fieldProperties; } public List<String> getFieldParts() { return fieldParts; } public int getLevelNo() { return levelNo; } public String getFieldName() { return fieldName; } public String getPicClause() { return picClause; } public String getValue() { return value; } }