Собственная UDF Impala (Cpp) случайным образом дает результат NULL для одних и тех же входных данных в одной таблице для нескольких вызовов в одном запросе.

У меня есть Native Impala UDF (Cpp) с двумя функциями. Обе функции дополняют друг друга.

String myUDF(BigInt)
BigInt myUDFReverso(String)

myUDF("myInput") дает некоторый вывод, который, когда myUDFReverso(myUDF("myInput")) должен вернуть myInput

Когда я запускаю запрос impala на паркетном столе, как этот,

select column1,myUDF(column1),length(myUDF(column1)),myUDFreverso(myUDF(column1)) from my_parquet_table order by column1 LIMIT 10;

Вывод NULL случайным образом.

Вывод скажем при 1-м запуске как,

+------------+----------------------+------------------------+-------------------------------------+
| column1    | myDB.myUDF(column1)  | length(myUDF(column1)) | myDB.myUDFReverso(myUDF(column1))   |
+------------+----------------------+------------------------+-------------------------------------+
| 27011991   | 1.0.128.9            | 9                      | 27011991                            |
| 27011991   | 1.0.128.9            | 9                      | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | 14022013                            |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
+------------+----------------------+------------------------+-------------------------------------+

и предположим, что во 2-м прогоне

+------------+----------------------+------------------------+-------------------------------------+
| column1    | myDB.myUDF(column1)  | length(myUDF(column1)) | myDB.myUDFReverso(myUDF(column1))   |
+------------+----------------------+------------------------+-------------------------------------+
| 27011991   | 1.0.128.9            | 9                      | 27011991                            |
| 27011991   | 1.0.128.9            | 9                      | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                | 
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | 14022013                            |
| 14022013   | 1.0.131.239          | 11                     | 14022013                            |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
| 14022013   | 1.0.131.239          | 11                     | 14022013                            |
| 14022013   | 1.0.131.239          | 11                     | NULL                                |
+------------+----------------------+------------------------+-------------------------------------+

А иногда он также дает правильное значение для всех строк.

Я проверил это на Impala v1.2.4, а также на v2.1. В чем причина этого? Какая-то проблема с памятью?

Редактировать 1:

BigIntVal myUDF(FunctionContext* context, const StringVal& myInput)
{
  if (myInput.is_null) return BigIntVal::null();

  unsigned int temp_op= 0;
  unsigned long result= 0;
  uint8_t *p;
  char c= '.';

  p=myInput.ptr;

  while (*p != '\0')
  {
    c= *p++;
    int digit= c*2;

    if (digit >= 22 && digit <= 31)
    {
      if ((temp_op= temp_op * 10 - digit) > 493)
      {
        return BigIntVal::null();
      }
    }
    else if (c == '.')
    {
      result= (result << 8) + (unsigned long) temp_op;
      temp_op= 0;
    }
    else
    {
      return BigIntVal::null();
    }
  }

  return BigIntVal((result << 8) + (unsigned long) temp_op);
}

In .h file the macro lowerbytify is defined as 

#define lowerbytify(T,A)        { *(T)= (char)((A));\
                                  *((T)+1)= (char)(((A) >> 8));\
                                  *((T)+2)= (char)(((A) >> 16));\
                                  *((T)+3)= (char)(((A) >> 24)); }

StringVal myUDFReverso(FunctionContext* context, const BigIntVal& origMyInput)
{
  if (origMyInput.is_null)
   return StringVal::null(); 

  int64_t myInput=origMyInput.val;
  char myInputArr[16];
  unsigned int l=0;        

  unsigned char temp[8];
  lowerbytify(temp, myInput);

  char calc[4];
  calc[3]= '.';

  for (unsigned char *p= temp + 4; p-- > temp;)
  {
    unsigned int c= *p;
    unsigned int n1, n2;
    n1= c / 100;
    c-= n1 * 100;
    n2= c / 10;
    c-= n2 * 10;
    calc[0]= (char) n1 + '0';
    calc[1]= (char) n2 + '0';
    calc[2]= (char) c + '0';
    unsigned int length= (n1 ? 4 : (n2 ? 3 : 2));
    unsigned int point= (p <= temp) ? 1 : 0;

    char * begin = &calc[4-length];

    for(int step = length - point;step>0;step--,l++,begin++)
    {
        myInputArr[l]=*begin;
    }
   }

   myInputArr[l]='\0';

   StringVal result(context,l);
   memcpy(result.ptr, myInputArr,l);

    return result;
}

person Suvarna Pattayil    schedule 08.05.2015    source источник
comment
Я подозреваю, что это проблема с управлением памятью. Можете ли вы поделиться своим кодом UDF?   -  person Matt    schedule 08.05.2015
comment
@matt Обновил мой вопрос   -  person Suvarna Pattayil    schedule 08.05.2015


Ответы (1)


Я не думаю, что вы можете предположить, что строка заканчивается нулем. Вы должны использовать StringVal::len для перебора символов, а не while (*p != '\0'). Кроме того, я бы рекомендовал написать несколько модульных тестов с использованием среды тестирования UDF в impala-udf-samples github, см. этот пример.

person Matt    schedule 08.05.2015
comment
Спасибо, Мэтт. Я посмотрю на это. - person Suvarna Pattayil; 08.05.2015