Ryan Persaud created NIFI-3372:
----------------------------------

             Summary: PutSQL cannot insert True for a BIT field when using 
ConvertJSONToSQL
                 Key: NIFI-3372
                 URL: https://issues.apache.org/jira/browse/NIFI-3372
             Project: Apache NiFi
          Issue Type: Bug
          Components: Core Framework
    Affects Versions: 1.0.1
         Environment: SqlServer
            Reporter: Ryan Persaud


As noted in NIFI-1613, using the column width to truncate fields often yields 
incorrect and undesired results for non-string fields in ConvertJSONToSQL.  I 
have encountered a situation where it is impossible to populate a BIT field in 
SqlServer with true (1) using ConvertJSONToSQL and PutSQL.  The notable 
snippets of code are:

org.apache.nifi.processors.standard.ConvertJSONToSQL (449-455):
                if (!fieldNode.isNull()) {
                    String fieldValue = fieldNode.asText();
                    if (colSize != null && fieldValue.length() > colSize) {
                        fieldValue = fieldValue.substring(0, colSize);
                    }
                    attributes.put("sql.args." + fieldCount + ".value", 
fieldValue);
                }

org.apache.nifi.processors.standard.PutSQL (757-761):
            switch (jdbcType) {
                case Types.BIT:
                case Types.BOOLEAN:
                    stmt.setBoolean(parameterIndex, 
Boolean.parseBoolean(parameterValue));
                    break;

java.lang.Boolean (121-123):
    public static boolean parseBoolean(String s) {
        return ((s != null) && s.equalsIgnoreCase("true"));
    }

In PutSQL, the case for BIT has no body or break, so execution proceeds to the 
BOOLEAN case.  Here, parseBoolean() attempts to parse parameterValue into a 
boolean value.  Looking at parseBoolean(), we can see that the parameterValue 
must contain "true" in order for true to be returned.  Since the code in 
ConvertJSONToSQL will truncate the string to its first character, the string 
sent to PutSQL will never be equal to "true", and parseBoolean() will never 
return true.  

One easy fix for this issue (below) while ConvertJSONToSQL gets sorted out is 
to allow 1 and t (case-insensitive) to also represent true in the BIT case in 
PutSQL.  Then, we can pass true/false 1/0 to ConvertJSONTOSQL, and still be 
able to correctly populate BIT columns.  Since we are also ORing a call to 
parseBoolean(), this modification should not break any existing NiFi flows that 
depend on the current BIT handling of PutSQL.

            switch (jdbcType) {
                case Types.BIT:
                    stmt.setBoolean(parameterIndex, "1".equals(parameterValue) 
|| "t".equalsIgnoreCase(parameterValue) || 
Boolean.parseBoolean(parameterValue));
                    break;
                case Types.BOOLEAN:

As a stopgap, I am currently using the following Python ExecuteScript processor 
in between my ConvertJSONToSQL and PutSQL processors in order to properly 
populate BIT fields:

flowFile = session.get()                                  
properties = context.getProperties()
if (flowFile != None):                                     
  attributes = flowFile.getAttributes()
  for key in attributes.keys():
    if attributes[key] == "-7":
      value_key = key.replace(".type", ".value")
      new_value = "true" if attributes[value_key] == "1" or 
attributes[value_key].lower() == "t" or attributes[value_key].lower() == "true" 
else "false"
      flowFile = session.putAttribute(flowFile, value_key, new_value)
  session.transfer(flowFile, REL_SUCCESS)

I modified PutSQL and created some tests in TestPutSQL, and I'll create a PR 
shortly.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to