char* oph_gsl_ifft(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
	if (*error)
	{
	        *length=0;
	        *is_null=0;
	        *error=1;
	        return NULL;
	}
	if (*is_null || !args->lengths[2])
	{
	        *length=0;
	        *is_null=1;
	        *error=0;
	        return NULL;
	}

    if (!initid->ptr) {

        initid->ptr=(char *)calloc(1,sizeof(oph_string));
        if(!initid->ptr){
            pmesg(1,  __FILE__, __LINE__, "Error allocating result\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        oph_stringPtr output = (oph_stringPtr) initid->ptr;

        core_set_type(output,args->args[1],&(args->lengths[1]));
        if (output->type!=OPH_COMPLEX_DOUBLE) {
        	pmesg(1,  __FILE__, __LINE__, "Invalid type: oph_complex_double required\n");
        	*length=0;
        	*is_null=1;
        	*error=1;
        	return NULL;
        }

        core_set_type(output,args->args[0],&(args->lengths[0]));
        if (output->type!=OPH_COMPLEX_DOUBLE) {
        	pmesg(1,  __FILE__, __LINE__, "Invalid type: oph_complex_double or oph_double required\n");
        	*length=0;
        	*is_null=1;
        	*error=1;
        	return NULL;
        }

        output->length = (unsigned long *)calloc(1,sizeof(unsigned long));
        if (!output->length) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating length\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        *(output->length) = args->lengths[2];

        if(core_set_elemsize(output)){
            pmesg(1,  __FILE__, __LINE__, "Error on setting element size\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }

        if(core_set_numelem(output)){
            pmesg(1,  __FILE__, __LINE__, "Error on counting result elements\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }

        output->content = (char *)calloc(1,*(output->length));
        if(!output->content){
            pmesg(1,  __FILE__, __LINE__, "Error allocating result string\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        initid->extension = calloc(1,sizeof(oph_gsl_fft_extraspace));
        if (!initid->extension) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating extra space\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        oph_gsl_fft_extraspace *extra = (oph_gsl_fft_extraspace *) initid->extension;

        extra->wt = gsl_fft_complex_wavetable_alloc(output->numelem);
        if (!extra->wt) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating wavetable\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        extra->ws = gsl_fft_complex_workspace_alloc(output->numelem);
        if (!extra->ws) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating workspace\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

    }

    oph_stringPtr output = (oph_stringPtr) initid->ptr;
    oph_gsl_fft_extraspace *extra = (oph_gsl_fft_extraspace *) initid->extension;

    gsl_set_error_handler_off();

    memcpy(output->content,args->args[2],*(output->length));
    if (gsl_fft_complex_inverse((gsl_complex_packed_array) output->content,1,output->numelem,extra->wt,extra->ws)) {
        pmesg(1,  __FILE__, __LINE__, "Error computing ifft\n");
        *length=0;
        *is_null=1;
        *error=1;
        return NULL;
    }

    *length = *(output->length);
    *error=0;
    *is_null=0;

    return output->content;
}
Пример #2
0
char *oph_predicate2(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	oph_string measure;
	char *buffer;
	char **names;
	int count;
	oph_predicate2_param *param;

	int i = 0;

	if (core_set_type(&(measure), args->args[0], &(args->lengths[0]))) {
		pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	measure.content = args->args[2];
	measure.length = &(args->lengths[2]);
	measure.missingvalue = NULL;

	core_set_elemsize(&(measure));

	if (core_set_numelem(&(measure))) {
		pmesg(1, __FILE__, __LINE__, "Error on counting elements\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	if (!initid->ptr) {
		initid->ptr = (char *) malloc(sizeof(oph_predicate2_param));
		if (!initid->ptr) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param = (oph_predicate2_param *) initid->ptr;

		for (i = 0; i < 4; ++i)
			param->f[i] = NULL;
		param->occurrence = 0;	// ALL

		buffer = (char *) malloc(1 + args->lengths[3]);
		strncpy(buffer, args->args[3], args->lengths[3]);
		buffer[args->lengths[3]] = '\0';
		pthread_rwlock_wrlock(&lock);
		param->f[1] = evaluator_create(buffer);
		pthread_rwlock_unlock(&lock);
		free(buffer);
		if (!param->f[1]) {
			pmesg(1, __FILE__, __LINE__, "Error allocating evaluator\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		evaluator_get_variables(param->f[1], &names, &count);
		if (count > 1) {
			pmesg(1, __FILE__, __LINE__, "Too variables in expression\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		// Comparison operator
		if (core_set_comp(&param->op, args->args[4], &(args->lengths[4]))) {
			pmesg(1, __FILE__, __LINE__, "Comparison operator not recognized\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (args->args[5] && args->lengths[5]) {
			buffer = (char *) malloc(1 + args->lengths[5]);
			core_strncpy(buffer, args->args[5], &(args->lengths[5]));
			if (!strcasecmp(buffer, "nan"))
				sprintf(buffer, "0/0");
		} else
			buffer = strdup("0/0");
		pthread_rwlock_wrlock(&lock);
		param->f[2] = evaluator_create(buffer);
		pthread_rwlock_unlock(&lock);
		free(buffer);
		if (!param->f[2]) {
			pmesg(1, __FILE__, __LINE__, "Error allocating evaluator\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		evaluator_get_variables(param->f[2], &names, &count);
		if (count > 1) {
			pmesg(1, __FILE__, __LINE__, "Too variables in expression\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (args->args[6] && args->lengths[6]) {
			buffer = (char *) malloc(1 + args->lengths[6]);
			core_strncpy(buffer, args->args[6], &(args->lengths[6]));
			if (!strcasecmp(buffer, "nan"))
				sprintf(buffer, "0/0");
		} else
			buffer = strdup("0/0");
		pthread_rwlock_wrlock(&lock);
		param->f[3] = evaluator_create(buffer);
		pthread_rwlock_unlock(&lock);
		free(buffer);
		if (!param->f[3]) {
			pmesg(1, __FILE__, __LINE__, "Error allocating evaluator\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		evaluator_get_variables(param->f[3], &names, &count);
		if (count > 1) {
			pmesg(1, __FILE__, __LINE__, "Too variables in expression\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		oph_string output_array;
		core_set_type(&output_array, args->args[1], &(args->lengths[1]));
		if (!output_array.type) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (core_set_elemsize(&output_array)) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->result_type = output_array.type;
		param->result_elemsize = output_array.elemsize;

		param->length = output_array.elemsize * measure.numelem;
		param->f[0] = malloc(param->length);
		if (!param->f[0]) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (args->arg_count > 7) {
			buffer = (char *) malloc(1 + args->lengths[7]);
			core_strncpy(buffer, args->args[7], &(args->lengths[7]));
			if (strcasecmp(buffer, OPH_PREDICATE2_ALL_OCCURRENCE)) {
				if (!strcasecmp(buffer, OPH_PREDICATE2_FIRST_OCCURRENCE) || !strcasecmp(buffer, OPH_PREDICATE2_BEGIN_OCCURRENCE))
					param->occurrence = 1;
				else if (!strcasecmp(buffer, OPH_PREDICATE2_LAST_OCCURRENCE) || !strcasecmp(buffer, OPH_PREDICATE2_END_OCCURRENCE))
					param->occurrence = -1;
				else {
					if (args->arg_type[7] == STRING_RESULT)
						param->occurrence = (long) strtol(buffer, NULL, 10);
					else
						param->occurrence = *((long long *) args->args[7]);
					if (param->occurrence < 1) {
						free(buffer);
						pmesg(1, __FILE__, __LINE__, "Unable to read occurrence\n");
						*length = 0;
						*is_null = 0;
						*error = 1;
						return NULL;
					}
				}
			}
			free(buffer);
		}
	} else
		param = (oph_predicate2_param *) initid->ptr;

	i = core_oph_predicate2(&measure, initid->ptr);
	if (i) {
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	*length = param->length;
	*error = 0;
	*is_null = 0;
	return (char *) param->f[0];

}
char *oph_gsl_complex_to_polar(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null || !args->lengths[2]) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	if (!initid->ptr) {
		initid->ptr = (char *) calloc(1, sizeof(oph_string));
		if (!initid->ptr) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		oph_stringPtr output = (oph_stringPtr) initid->ptr;

		initid->extension = (char *) calloc(1, sizeof(oph_string));
		if (!initid->extension) {
			pmesg(1, __FILE__, __LINE__, "Error allocating measure\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		oph_stringPtr measure = (oph_stringPtr) initid->extension;

		core_set_type(measure, args->args[0], &(args->lengths[0]));
		if (measure->type != OPH_COMPLEX_INT && measure->type != OPH_COMPLEX_LONG && measure->type != OPH_COMPLEX_FLOAT && measure->type == OPH_COMPLEX_DOUBLE) {
			pmesg(1, __FILE__, __LINE__, "Invalid input type: complex required\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		measure->length = &(args->lengths[2]);

		if (core_set_elemsize(measure)) {
			pmesg(1, __FILE__, __LINE__, "Error on setting element size\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (core_set_numelem(measure)) {
			pmesg(1, __FILE__, __LINE__, "Error on counting result elements\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		core_set_type(output, args->args[1], &(args->lengths[1]));
		if (output->type != OPH_COMPLEX_INT && output->type != OPH_COMPLEX_LONG && output->type != OPH_COMPLEX_FLOAT && output->type != OPH_COMPLEX_DOUBLE) {
			pmesg(1, __FILE__, __LINE__, "Invalid output type: complex required\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (core_set_elemsize(output)) {
			pmesg(1, __FILE__, __LINE__, "Error on setting element size\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		output->length = (unsigned long *) calloc(1, sizeof(unsigned long));
		if (!output->length) {
			pmesg(1, __FILE__, __LINE__, "Error allocating length\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		*(output->length) = measure->numelem * output->elemsize;
		output->numelem = measure->numelem;

		output->content = (char *) calloc(1, *(output->length));
		if (!output->content) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	}

	oph_stringPtr output = (oph_stringPtr) initid->ptr;
	oph_stringPtr measure = (oph_stringPtr) initid->extension;
	measure->content = args->args[2];

	int i, j = 0;
	gsl_complex z;
	double val1, val2;
	switch (measure->type) {
		case OPH_COMPLEX_INT:
			switch (output->type) {
				case OPH_COMPLEX_INT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((int *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((int *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_LONG:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((int *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((int *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_FLOAT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((int *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((int *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_DOUBLE:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((int *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((int *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				default:
					pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
					*length = 0;
					*is_null = 0;
					*error = 1;
					return NULL;
			}
			break;
		case OPH_COMPLEX_LONG:
			switch (output->type) {
				case OPH_COMPLEX_INT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((long long *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((long long *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_LONG:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((long long *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((long long *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_FLOAT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((long long *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((long long *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_DOUBLE:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((long long *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((long long *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				default:
					pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
					*length = 0;
					*is_null = 0;
					*error = 1;
					return NULL;
			}
			break;
		case OPH_COMPLEX_FLOAT:
			switch (output->type) {
				case OPH_COMPLEX_INT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((float *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((float *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_LONG:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((float *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((float *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_FLOAT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((float *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((float *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_DOUBLE:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = (double) ((float *) (args->args[2]))[i];	//real part
						z.dat[1] = (double) ((float *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				default:
					pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
					*length = 0;
					*is_null = 0;
					*error = 1;
					return NULL;
			}
			break;
		case OPH_COMPLEX_DOUBLE:
			switch (output->type) {
				case OPH_COMPLEX_INT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = ((double *) (args->args[2]))[i];	//real part
						z.dat[1] = ((double *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(int)), OPH_DOUBLE, OPH_INT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_LONG:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = ((double *) (args->args[2]))[i];	//real part
						z.dat[1] = ((double *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(long long)), OPH_DOUBLE, OPH_LONG, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_FLOAT:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = ((double *) (args->args[2]))[i];	//real part
						z.dat[1] = ((double *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(float)), OPH_DOUBLE, OPH_FLOAT, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				case OPH_COMPLEX_DOUBLE:
					for (i = 0; i < output->numelem * 2; i += 2) {
						z.dat[0] = ((double *) (args->args[2]))[i];	//real part
						z.dat[1] = ((double *) (args->args[2]))[i + 1];	//imag part
						val1 = gsl_complex_abs(z);
						val2 = gsl_complex_arg(z);
						if (core_oph_type_cast(&val1, output->content + (j * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						if (core_oph_type_cast(&val2, output->content + ((j + 1) * sizeof(double)), OPH_DOUBLE, OPH_DOUBLE, NULL)) {
							pmesg(1, __FILE__, __LINE__, "Error casting output\n");
							*length = 0;
							*is_null = 0;
							*error = 1;
							return NULL;
						}
						j += 2;
					}
					break;
				default:
					pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
					*length = 0;
					*is_null = 0;
					*error = 1;
					return NULL;
			}
			break;
		default:
			pmesg(1, __FILE__, __LINE__, "Type not recognized\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
	}

	*length = *(output->length);
	*error = 0;
	*is_null = 0;

	return output->content;
}
void *sum_array_r(void *initid_r)
{

	// Plugin thread function
	int thid;

	// Each thread has a subset of elements 
	unsigned long *th_array_dim = malloc(sizeof(unsigned long));

	for (thid = 0; thid < NTHREAD; thid++) {
		if (pthread_equal(((th_data *) (((UDF_INIT *) (initid_r))->extension))->thread[thid], pthread_self()))
			break;
	}
	for (;;) {
		barrier_wait(&(((th_data *) (((UDF_INIT *) (initid_r))->extension))->barr_start));
		if (((th_data *) (((UDF_INIT *) (initid_r))->extension))->exit_flag == 1)
			break;

		oph_string measurea;
		oph_string measureb;

		int res = 0;

		if (((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->arg_count < 3) {
			core_set_type(&(measurea), NULL, 0);
			core_set_type(&(measureb), NULL, 0);
		} else if (((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->arg_count == 3) {
			core_set_type(&(measurea), ((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->args[2],
				      &(((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->lengths[2]));
			core_set_type(&(measureb), NULL, 0);
		} else {
			core_set_type(&(measurea), ((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->args[2],
				      &(((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->lengths[2]));
			core_set_type(&(measureb), ((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->args[3],
				      &(((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->lengths[3]));
		}



		if (measurea.type != measureb.type) {
			pmesg(1, __FILE__, __LINE__, "Type are different; unable to sum values\n");
		}

		*th_array_dim = (((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->lengths[0]) / NTHREAD;

		measurea.content = ((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->args[0] + ((*th_array_dim) * thid);
		measurea.length = th_array_dim;
		measureb.content = ((UDF_ARGS *) ((th_data *) (((UDF_INIT *) (initid_r))->extension))->curr_args)->args[1] + ((*th_array_dim) * thid);
		measureb.length = th_array_dim;

		core_set_elemsize(&(measurea));

		if (core_set_numelem(&(measurea))) {
			pmesg(1, __FILE__, __LINE__, "Error on counting elements\n");
		}

		core_set_elemsize(&(measureb));

		if (core_set_numelem(&(measureb))) {
			pmesg(1, __FILE__, __LINE__, "Error on counting elements\n");
		}
		//Exit if array series have different number of elements
		if (measurea.numelem != measureb.numelem) {
			pmesg(1, __FILE__, __LINE__, "Number of array elements are different; unable to sum values\n");
		}


		res = core_oph_sum_array(&measurea, &measureb, (((UDF_INIT *) (initid_r))->ptr) + ((*th_array_dim) * thid));
		if (res) {
			pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		}
		barrier_wait(&(((th_data *) (((UDF_INIT *) (initid_r))->extension))->barr_end));
	}			// end for
	free(th_array_dim);
	th_array_dim = NULL;
}
char* oph_ccluster_kcluster(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
    if(!initid->ptr){
        *error=0;
        *is_null=0;

        initid->ptr=(char *)calloc(1,sizeof(oph_string));
        if(!initid->ptr){
            pmesg(1,  __FILE__, __LINE__, "Error allocating result\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }
        initid->extension = calloc(1,sizeof(oph_ccluster_kcluster_extra));
        if(!initid->extension){
            pmesg(1,  __FILE__, __LINE__, "Error allocating extension\n");
            *length=0;
            *is_null=1;
            *error=1;
            return NULL;
        }

        oph_ccluster_kcluster_extra *extra = (oph_ccluster_kcluster_extra *) initid->extension;

        extra->k = (int) *((long long*) args->args[3]); // set cluster number
        extra->method = OPH_CCLUSTER_KCLUSTER_KMEANS; // default method
        extra->level = OPH_CCLUSTER_KCLUSTER_ALL; // default level
        extra->npass = 1; // default npass
        extra->type = OPH_DOUBLE; // default input type

	if (!strncasecmp(args->args[0],"OPH_INT",args->lengths[0])) extra->type = OPH_INT;
	else if (!strncasecmp(args->args[0],"OPH_SHORT",args->lengths[0])) extra->type = OPH_SHORT;
	else if (!strncasecmp(args->args[0],"OPH_BYTE",args->lengths[0])) extra->type = OPH_BYTE;
	else if (!strncasecmp(args->args[0],"OPH_LONG",args->lengths[0])) extra->type = OPH_LONG;
	else if (!strncasecmp(args->args[0],"OPH_FLOAT",args->lengths[0])) extra->type = OPH_FLOAT;
	else if (!strncasecmp(args->args[0],"OPH_DOUBLE",args->lengths[0])) extra->type = OPH_DOUBLE;
	else {
		pmesg(1,  __FILE__, __LINE__, "Invalid input data type!\n");
		*length=0;
		*is_null=0;
		*error=1;
		return NULL;
	}

        int i;
        for (i = 4; i < args->arg_count; i++) {
                if (args->arg_type[i]==INT_RESULT) { // npass
                    extra->npass = (int) *((long long*) args->args[i]);
                    if (extra->npass < 1) {
                        pmesg(1,  __FILE__, __LINE__, "npass must be >= 1!\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                    }
                } else if (args->arg_type[i]==STRING_RESULT) {
                    if (!strncasecmp(args->args[i],"KMEANS",args->lengths[i])) {
                        extra->method = OPH_CCLUSTER_KCLUSTER_KMEANS;
                    } else if (!strncasecmp(args->args[i],"KMEDIANS",args->lengths[i])) {
                        extra->method = OPH_CCLUSTER_KCLUSTER_KMEDIANS;
                    } else if (!strncasecmp(args->args[i],"CENTROIDS",args->lengths[i])) {
                        extra->level = OPH_CCLUSTER_KCLUSTER_CENTROIDS;
                    } else if (!strncasecmp(args->args[i],"LABELS",args->lengths[i])) {
                        extra->level = OPH_CCLUSTER_KCLUSTER_LABELS;
                    } else if (!strncasecmp(args->args[i],"ALL",args->lengths[i])) {
                        extra->level = OPH_CCLUSTER_KCLUSTER_ALL;
                    } else {
                        pmesg(1,  __FILE__, __LINE__, "invalid argument %d!\n",i);
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
                    }
                } else {
                    pmesg(1,  __FILE__, __LINE__, "wrong type for argument %d!\n",i);
                    *length=0;
                    *is_null=0;
                    *error=1;
                    return NULL;
                }
        }

        extra->npoints = args->lengths[2] / core_sizeof(extra->type);

        extra->data = (double **) malloc(sizeof(double *) * extra->npoints);
        if (!extra->data) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }
        for (i = 0; i < extra->npoints; i++) {
            extra->data[i] = (double *) malloc(sizeof(double));
            if (!extra->data[i]) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
        }

        extra->mask = (int **) malloc(sizeof(int *) * extra->npoints);
        if (!extra->mask) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }
        for (i = 0; i < extra->npoints; i++) {
            extra->mask[i] = (int *) malloc(sizeof(int));
            if (!extra->mask[i]) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
        }

        extra->clusterid = (int *) malloc(sizeof(int) * extra->npoints);
        if (!extra->clusterid) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }

        oph_stringPtr output = (oph_stringPtr) initid->ptr;

        if (extra->level==OPH_CCLUSTER_KCLUSTER_CENTROIDS) {
            extra->cdata = (double **) malloc(sizeof(double *) * extra->k);
            if (!extra->cdata) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            for (i = 0; i < extra->k; i++) {
                extra->cdata[i] = (double *) malloc(sizeof(double));
                if (!extra->cdata[i]) {
                    pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                    *length=0;
                    *is_null=0;
                    *error=1;
                    return NULL;
                }
            }

            extra->cmask = (int **) malloc(sizeof(int *) * extra->k);
            if (!extra->cmask) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            for (i = 0; i < extra->k; i++) {
                extra->cmask[i] = (int *) malloc(sizeof(int));
                if (!extra->cmask[i]) {
                    pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                    *length=0;
                    *is_null=0;
                    *error=1;
                    return NULL;
                }
            }

            unsigned long len = (unsigned long ) strlen("OPH_DOUBLE");
            core_set_type(output, "OPH_DOUBLE" ,&len);
            if(core_set_elemsize(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on setting result elements size\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            output->length = (unsigned long *) malloc(sizeof(unsigned long));
            if (!output->length) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating length\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            *(output->length) = (unsigned long) extra->k * output->elemsize;

            output->content = (char *) malloc(*(output->length));
            if (!output->content) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating output\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            if(core_set_numelem(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on counting result elements\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
        } else if (extra->level==OPH_CCLUSTER_KCLUSTER_ALL) {
            extra->cdata = (double **) malloc(sizeof(double *) * extra->k);
            if (!extra->cdata) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            for (i = 0; i < extra->k; i++) {
                extra->cdata[i] = (double *) malloc(sizeof(double));
                if (!extra->cdata[i]) {
                    pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                    *length=0;
                    *is_null=0;
                    *error=1;
                    return NULL;
                }
            }

            extra->cmask = (int **) malloc(sizeof(int *) * extra->k);
            if (!extra->cmask) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            for (i = 0; i < extra->k; i++) {
                extra->cmask[i] = (int *) malloc(sizeof(int));
                if (!extra->cmask[i]) {
                    pmesg(1,  __FILE__, __LINE__, "Error allocating memory\n");
                    *length=0;
                    *is_null=0;
                    *error=1;
                    return NULL;
                }
            }

            unsigned long len = (unsigned long ) strlen("OPH_DOUBLE");
            core_set_type(output, "OPH_DOUBLE" ,&len);
            if(core_set_elemsize(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on setting result elements size\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            output->length = (unsigned long *) malloc(sizeof(unsigned long));
            if (!output->length) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating length\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            *(output->length) = (unsigned long) extra->npoints * output->elemsize;

            output->content = (char *) malloc(*(output->length));
            if (!output->content) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating output\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            if(core_set_numelem(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on counting result elements\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
        } else {
            unsigned long len = (unsigned long ) strlen("OPH_INT");
            core_set_type(output, "OPH_INT" ,&len);
            if(core_set_elemsize(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on setting result elements size\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            output->length = (unsigned long *) malloc(sizeof(unsigned long));
            if (!output->length) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating length\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
            *(output->length) = (unsigned long) extra->npoints * output->elemsize;

            output->content = (char *) malloc(*(output->length));
            if (!output->content) {
                pmesg(1,  __FILE__, __LINE__, "Error allocating output\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }

            if(core_set_numelem(output)){
                pmesg(1,  __FILE__, __LINE__, "Error on counting result elements\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            }
        }
    }

    if (*error)
    {
        *length=0;
        *is_null=0;
        *error=1;
        return NULL;
    }
    if (*is_null)
    {
        *length=0;
        *is_null=1;
        *error=0;
        return NULL;
    }

    oph_stringPtr output = (oph_stringPtr) initid->ptr;
    oph_ccluster_kcluster_extra *extra = (oph_ccluster_kcluster_extra *) initid->extension;

    double weight[1] = {1.0};
    char method = (extra->method==OPH_CCLUSTER_KCLUSTER_KMEANS)?'a':'m';
    double err;
    int ifound;
    int n;

    switch (extra->type) {
        case OPH_INT:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = (double) ((int *)(args->args[2]))[n];
                extra->mask[n][0] = 1;
            }
            break;
        case OPH_SHORT:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = (double) ((short *)(args->args[2]))[n];
                extra->mask[n][0] = 1;
            }
            break;
        case OPH_BYTE:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = (double) ((char *)(args->args[2]))[n];
                extra->mask[n][0] = 1;
            }
            break;
        case OPH_LONG:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = (double) ((long long *)(args->args[2]))[n];
                extra->mask[n][0] = 1;
            }
            break;
        case OPH_FLOAT:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = (double) ((float *)(args->args[2]))[n];
                if (isnan(extra->data[n][0])) {
                    extra->mask[n][0] = 0;
                } else {
                    extra->mask[n][0] = 1;
                }
            }
            break;
        case OPH_DOUBLE:
            for (n = 0; n < extra->npoints; n++) {
                extra->data[n][0] = ((double *)(args->args[2]))[n];
                if (isnan(extra->data[n][0])) {
                    extra->mask[n][0] = 0;
                } else {
                    extra->mask[n][0] = 1;
                }
            }
            break;
        default:
            pmesg(1,  __FILE__, __LINE__, "Invalid input type\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
    }

    kcluster(extra->k,extra->npoints,1,extra->data,extra->mask,weight,0,extra->npass,method,'e',extra->clusterid,&err,&ifound);

    if(ifound==0){
        pmesg(1,  __FILE__, __LINE__, "k > number of points!\n");
        *length=0;
        *is_null=0;
        *error=1;
        return NULL;
    }
    if(ifound==-1){
        pmesg(1,  __FILE__, __LINE__, "Error allocating memory for clustering\n");
        *length=0;
        *is_null=0;
        *error=1;
        return NULL;
    }

    if (extra->level==OPH_CCLUSTER_KCLUSTER_CENTROIDS) {
        if (!getclustercentroids(extra->k,extra->npoints,1,extra->data,extra->mask,extra->clusterid,extra->cdata,extra->cmask,0,method)) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating memory for centroids retrieval\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }
        for (n = 0; n < extra->k; n++) {
            if (extra->cmask[n][0]==0) {
                pmesg(1,  __FILE__, __LINE__, "All cluster members are missing for cluster %d\n",n);
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            } else {
                ((double *)(output->content))[n] = extra->cdata[n][0];
            }
        }
    } else if (extra->level==OPH_CCLUSTER_KCLUSTER_ALL) {
        if (!getclustercentroids(extra->k,extra->npoints,1,extra->data,extra->mask,extra->clusterid,extra->cdata,extra->cmask,0,method)) {
            pmesg(1,  __FILE__, __LINE__, "Error allocating memory for centroids retrieval\n");
            *length=0;
            *is_null=0;
            *error=1;
            return NULL;
        }
        for (n = 0; n < extra->npoints; n++) {
            if (extra->cmask[extra->clusterid[n]][0]==0) {
                pmesg(1,  __FILE__, __LINE__, "All cluster members are missing for cluster %d\n",extra->clusterid[n]);
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
            } else {
                ((double *)(output->content))[n] = extra->cdata[extra->clusterid[n]][0];
            }
        }
    } else {
        memcpy(output->content,extra->clusterid,*(output->length));
    }

    *length=*(output->length);
    return output->content;
}
char* oph_reduce2(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
        oph_request inp_req;

        long long hierarchy_set = 0;
        long long result_length = 0;
	long long block_size = 1, numelement_to_reduce, max_size = 0;
        int i = 0, j;
	unsigned long lll, olll, k;

	int (*core_oph_oper) (oph_stringPtr byte_array, char *res);

	if (args->arg_count > 5)
	{
		block_size = *((long long*)(args->args[5]));
		if(block_size<=0)
		{
		        pmesg(1,  __FILE__, __LINE__, "Wrong arguments to oph_reduce2 function\n");
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
	}

        core_set_type(&(inp_req.measure), args->args[0], &(args->lengths[0]));
	if(!inp_req.measure.type){
                pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        if(args->arg_count < 4){
                core_set_oper(&inp_req, NULL, 0);
        }
        else{
                core_set_oper(&inp_req, args->args[3], &(args->lengths[3]));
        }

	if(!inp_req.oper){
                pmesg(1,  __FILE__, __LINE__, "Operator not recognized\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        core_set_hier(&inp_req, NULL, 0);
	if(!inp_req.hier){
                pmesg(1,  __FILE__, __LINE__, "Hierarchy not recognized\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        inp_req.measure.content = args->args[2];
        inp_req.measure.length = &(args->lengths[2]);

	if(core_set_elemsize(&(inp_req.measure))){
                pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        if(core_set_numelem(&(inp_req.measure))){
        	pmesg(1,  __FILE__, __LINE__, "Error on counting elements\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

	if (args->arg_count < 6)
		numelement_to_reduce = (long long)inp_req.measure.numelem;
	else
	{
		if(((long long)inp_req.measure.numelem) % block_size)
		{
			pmesg(1,  __FILE__, __LINE__, "Error: 'block_size' %lld not applicable on %ld elements\n", block_size, inp_req.measure.numelem);
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		numelement_to_reduce = (long long)inp_req.measure.numelem / block_size;
	}

	if (args->arg_count > 6) max_size = *((long long*)(args->args[6]));
	if (!max_size) max_size = numelement_to_reduce;

        if((args->arg_count < 5) || !args->args[4])
                hierarchy_set = (long long) (inp_req.measure.numelem);
        else
	{
		hierarchy_set = *((long long*)(args->args[4]));
		if (!hierarchy_set || (hierarchy_set>max_size)) hierarchy_set = max_size;
		else if ((hierarchy_set<0) || (max_size%hierarchy_set)) 
		{
			pmesg(1,  __FILE__, __LINE__, "Wrong parameter value 'count' %lld\n",hierarchy_set);
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
        }

        /* Check if I can apply the hierarchy */
        if(numelement_to_reduce%hierarchy_set)
	{
        	pmesg(1,  __FILE__, __LINE__, "Error: hierarchy_set %lld not applicable on %ld elements\n", hierarchy_set, inp_req.measure.numelem);
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }

        result_length = inp_req.measure.numelem/hierarchy_set;

	oph_type result_type = inp_req.measure.type;
	size_t result_size = inp_req.measure.elemsize;
        switch(inp_req.oper)
	{
                case OPH_COUNT:
			core_oph_oper = core_oph_count;
			break;
                case OPH_MAX:
			core_oph_oper = core_oph_max;
			break;
                case OPH_MIN:
			core_oph_oper = core_oph_min;
			break;
                case OPH_SUM:
			core_oph_oper = core_oph_sum;
			break;
		case OPH_AVG:
			core_oph_oper = core_oph_avg;
			break;
		case OPH_STD:
			core_oph_oper = core_oph_std;
			break;
		case OPH_VAR:
			core_oph_oper = core_oph_var;
			break;
		case OPH_CMOMENT:
			core_oph_oper = core_oph_cmoment;
			break;
		case OPH_ACMOMENT:
			core_oph_oper = core_oph_acmoment;
			break;
		case OPH_RMOMENT:
			core_oph_oper = core_oph_rmoment;
			break;
		case OPH_ARMOMENT:
			core_oph_oper = core_oph_armoment;
			break;
		case OPH_QUANTILE:
			core_oph_oper = core_oph_quantile;
			break;
		default:
                        pmesg(1,  __FILE__, __LINE__, "Unable to recognize operator\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
                        return NULL;
        }
	switch(inp_req.oper)
	{
		case OPH_COUNT:
			result_type = OPH_LONG;
			result_size = core_sizeof(OPH_LONG);
			break;
		case OPH_AVG:
		case OPH_STD:
		case OPH_VAR:
		case OPH_CMOMENT:
		case OPH_ACMOMENT:
		case OPH_RMOMENT:
		case OPH_ARMOMENT:
		case OPH_QUANTILE:
			if(inp_req.measure.type == OPH_BYTE || inp_req.measure.type == OPH_SHORT || inp_req.measure.type == OPH_INT)
			{
				result_type = OPH_FLOAT;
				result_size = core_sizeof(OPH_FLOAT);
			}
			else if(inp_req.measure.type == OPH_LONG)
			{
				result_type = OPH_DOUBLE;
				result_size = core_sizeof(OPH_DOUBLE);
			}
			break;
		default:;
	}

	oph_string output_array;
        core_set_type(&output_array, args->args[1], &(args->lengths[1]));
	if(!output_array.type){
                pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }
	if(core_set_elemsize(&output_array)){
                pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
                *length=0;
                *is_null=0;
                *error=1;
                return NULL;
        }
	olll = result_length*output_array.elemsize;

        /* Allocate the right space for the result set */
	oph_reduce2_param* tmp;
        if(!initid->ptr)
	{
                tmp = (oph_reduce2_param*)malloc(sizeof(oph_reduce2_param));
		initid->ptr = (char*)tmp;
		if(!initid->ptr)
		{
			pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
	                *length=0;
		        *is_null=0;
        		*error=1;
                	return NULL;
		}
		tmp->result = (char *)malloc(olll);
		if(!tmp->result)
		{
			pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
	                *length=0;
		        *is_null=0;
        		*error=1;
                	return NULL;
		}
		if (block_size>1)
		{
			tmp->temp = (char *)malloc(hierarchy_set*inp_req.measure.elemsize);
			if(!tmp->temp)
			{
				pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
			        *length=0;
				*is_null=0;
				*error=1;
		        	return NULL;
			}
		}
		else tmp->temp = NULL;
		if (inp_req.oper == OPH_QUANTILE)
		{
			tmp->temp2 = (char *)malloc(*inp_req.measure.length);
			if(!tmp->temp2)
			{
				pmesg(1,  __FILE__, __LINE__, "Error allocating measures string\n");
				*length=0;
				*is_null=0;
				*error=1;
				return NULL;
			}
		}
		else tmp->temp2 = NULL;
        }
	else tmp = (oph_reduce2_param*)initid->ptr;

	oph_string curr_array;
        curr_array.type = inp_req.measure.type;
        curr_array.elemsize = inp_req.measure.elemsize;
        curr_array.numelem = hierarchy_set;
        curr_array.length = &lll;
        *curr_array.length = (unsigned long)(hierarchy_set*curr_array.elemsize);
	if(args->arg_count > 7)
	{
		curr_array.param = *((double*)(args->args[7]));
		if (curr_array.param<0)
		{
			pmesg(1,  __FILE__, __LINE__, "Wrong parameter value 'order' %f\n",curr_array.param);
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
	}
	else curr_array.param = 2.0;
	curr_array.extend = (void*)tmp->temp2;

	char temporary[result_size];
        for(i=0; i < result_length; i++)
	{
		if (block_size==1) curr_array.content = inp_req.measure.content+(i*(*curr_array.length));
		else
		{
			for (j=0, k=0; k<inp_req.measure.numelem; ++k) // Loop on the input array
				if (k%block_size + (k/(block_size*hierarchy_set))*block_size == i)
				{
					memcpy(tmp->temp+j*inp_req.measure.elemsize,inp_req.measure.content+k*inp_req.measure.elemsize,inp_req.measure.elemsize);
					++j;
					if (j>=hierarchy_set) break; // Found all the elements to be reduced
				}
			if (k>=inp_req.measure.numelem)
			{
				pmesg(1,  __FILE__, __LINE__, "Unable to find an element to be aggregated\n");
				*length=0;
				*is_null=0;
				*error=1;
				return NULL;
			}
			curr_array.content = tmp->temp;
		}
                if(core_oph_oper(&curr_array, temporary))
		{
                        pmesg(1,  __FILE__, __LINE__, "Unable to find result\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
			return NULL;
                }
		if(core_oph_type_cast(temporary, tmp->result+i*output_array.elemsize, result_type, output_array.type))
		{
                        pmesg(1,  __FILE__, __LINE__, "Unable to find result\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
			return NULL;
                }
                pmesg(3,  __FILE__, __LINE__, "RES: %f\n", *(double*)(tmp->result));
        }
        *length = (unsigned long) (olll);

	*is_null=0;
	*error=0;

        return tmp->result;
}
void oph_roll_up_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
{
	int res = 0;
	oph_roll_up_param* param;
	oph_string* measure;
	long long size;

	if(!initid->ptr)
	{
		initid->ptr=(char*)malloc(sizeof(oph_roll_up_param));
		if(!initid->ptr)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_roll_up_param\n");
        	        *is_null=0;
                	*error=1;
	                return;
        	}
		param = (oph_roll_up_param*)initid->ptr;
		param->measure = NULL;
		param->result = NULL;
		param->rows = 0;
	}
	else param = (oph_roll_up_param*)initid->ptr;

	if (!param->measure)
	{
		measure = param->measure = (oph_string*)malloc(sizeof(oph_string));
		if(!param->measure)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_string\n");
        	        *is_null=0;
                	*error=1;
	                return;
        	}
		measure->length = &(args->lengths[2]);

		if (core_set_type(measure, args->args[0], &(args->lengths[0])))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting the data type\n");
			*is_null=0;
			*error=1;
			return;
		}

		if (core_set_elemsize(measure))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting data element size\n");
			*is_null=0;
			*error=1;
			return;
		}

		if(core_set_numelem(measure))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on counting elements\n");
		        *is_null=0;
		        *error=1;
		        return;
		}
	}
	else measure = param->measure;

	if (!param->result)
	{
		if (!args->args[2] || !args->lengths[2])
		{
        	        *is_null=1;
                	*error=0;
	                return;
        	}

		size = *((long long*)args->args[3]);
		if (size<=0)
		{
        	        *is_null=1;
                	*error=0;
	                return;
		}

		oph_string output_array;
		core_set_type(&output_array, args->args[1], &(args->lengths[1]));
		if(!output_array.type){
		        pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
			*is_null=0;
		        *error=1;
		        return;
		}
		if(core_set_elemsize(&output_array)){
		        pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
			*is_null=0;
		        *error=1;
		        return;
		}
		param->result_type = output_array.type;
		param->result_elemsize = output_array.elemsize;

		param->length = size * measure->numelem * output_array.elemsize; // bytes
		if (!param->length)
		{
			*is_null=1;
                	*error=0;
	                return;
        	}
		param->result = (char*)malloc(param->length); // Output
		if(!param->result)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating result\n");
        	        *is_null=0;
                	*error=1;
	                return;
        	}

		param->rows = 0;
		param->size = size;
	}

	measure->content = args->args[2]; // Input
	if (!measure->content)
	{
                *is_null=1;
                *error=0;
                return;
        }
	measure->length = &(args->lengths[2]);

        res = core_oph_roll_up(param);
        if(res)
	{
                pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
                *is_null=1;
                *error=1;
                return;
        }
        *error=0;
        *is_null=0;
}
char* oph_extract(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
{
        int res = 0;
	oph_extract_param* param;
	oph_string *measure, *index_list;

	if (*error)
	{
	        *length=0;
	        *is_null=0;
	        *error=1;
	        return NULL;
	}
	if (*is_null || !args->lengths[2] || !args->lengths[3])
	{
	        *length=0;
	        *is_null=1;
	        *error=0;
	        return NULL;
	}

	if(!initid->ptr)
	{
		initid->ptr=(char*)malloc(sizeof(oph_extract_param));
		if(!initid->ptr)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_extract_param\n");
			param->error = 1;
			*length=0;
        	        *is_null=0;
                	*error=1;
	                return NULL;
        	}
		param = (oph_extract_param*)initid->ptr;
		param->measure = NULL;
		param->index_list = NULL;
		param->result = NULL;
		param->error = 0;
	}
	else param = (oph_extract_param*)initid->ptr;

	if (!param->error && !param->measure && !param->index_list)
	{
		// Measure
		param->measure = malloc(sizeof(oph_string));
		if(!param->measure)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_string\n");
			param->error = 1;
			*length=0;
        	        *is_null=0;
                	*error=1;
	                return NULL;
        	}
		measure = (oph_string*)param->measure;
		measure->length = &(args->lengths[2]);
		res = core_set_type(measure, args->args[0], &(args->lengths[0]));
		if (res)
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting the data type\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		if (core_set_elemsize(measure))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting data element size\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		if(core_set_numelem(measure))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on counting elements\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}

		// Index list
		param->index_list = malloc(sizeof(oph_string));
		if(!param->index_list)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_string\n");
			param->error = 1;
			*length=0;
        	        *is_null=0;
                	*error=1;
	                return NULL;
        	}
		index_list = (oph_string*)param->index_list;
		index_list->length = &(args->lengths[3]);
		char long_type[10];
		sprintf(long_type,"oph_long");
		unsigned long len = strlen(long_type); 
		res = core_set_type(index_list, long_type, &len); // Index are always oph_long, i.e. long long
		if (res)
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting the data type\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		if (core_set_elemsize(index_list))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on setting data element size\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		if(core_set_numelem(index_list))
		{
			pmesg(1,  __FILE__, __LINE__, "Error on counting elements\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}

		oph_string output_array;
		core_set_type(&output_array, args->args[1], &(args->lengths[1]));
		if(!output_array.type){
		        pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		if(core_set_elemsize(&output_array)){
		        pmesg(1,  __FILE__, __LINE__, "Unable to recognize measures type\n");
			param->error = 1;
		        *length=0;
		        *is_null=0;
		        *error=1;
		        return NULL;
		}
		param->result_type = output_array.type;
		param->result_elemsize = output_array.elemsize;

		// Output
		param->length = output_array.elemsize * index_list->numelem; // bytes
		if (!param->length)
		{
			*length=0;
        	        *is_null=1;
                	*error=0;
	                return NULL;
        	}
		param->result = (char*)malloc(param->length);
		if(!param->result)
		{
			pmesg(1, __FILE__, __LINE__, "Error allocating result\n");
			param->error = 1;
			*length=0;
        	        *is_null=0;
                	*error=1;
	                return NULL;
        	}
	}
	else
	{
		measure = (oph_string*)param->measure;
		index_list = (oph_string*)param->index_list;
	}

	// Set measure->content
        measure->content = args->args[2]; // Input
	if (!measure->content)
	{
                *length=0;
                *is_null=1;
                *error=0;
                return NULL;
        }
	// Set index_list->content
	index_list->content = args->args[3]; // Input
	if (!index_list->content)
	{
	        *length=0;
	        *is_null=1;
	        *error=0;
	        return NULL;
	}

	long long i, index;
	char temporary[measure->elemsize];
	for (i=0; i<index_list->numelem; ++i)
	{
		index = *((long long*)(index_list->content+i*index_list->elemsize))-1; // Non 'C'-like indexing
		memcpy(temporary, measure->content+index*measure->elemsize, measure->elemsize);
		if(core_oph_type_cast(temporary, param->result+i*param->result_elemsize, measure->type, param->result_type))
		{
                        pmesg(1,  __FILE__, __LINE__, "Unable to find result\n");
                        *length=0;
                        *is_null=0;
                        *error=1;
			return NULL;
                }
	}

	*length=param->length;
	*is_null=0;
        *error=0;
	return (result=param->result);
}
long long oph_convert_l(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
{
        oph_string *measure;

       if (*error)
        {
                *is_null=0;
                *error=1;
                return -1;
        }
        if (*is_null)
        {
                *is_null=1;
                *error=0;
                return -1;
        }


        long long result;

	if(!initid->ptr){
		initid->ptr = (void *)malloc(sizeof(oph_string));
		measure = (oph_string *)initid->ptr;
        	core_set_type(measure, args->args[0], &(args->lengths[0]));

		if(!measure->type || (measure->type != OPH_BYTE && measure->type != OPH_SHORT && measure->type != OPH_INT && measure->type != OPH_LONG)){
			pmesg(1,  __FILE__, __LINE__, "Invalid type\n");
			*is_null=1;
                	*error=1;
                	return -1;
		}

        	if(core_set_elemsize(measure)){
                	pmesg(1,  __FILE__, __LINE__, "Error on setting elements size\n");
			*is_null=1;
                	*error=1;
                	return -1;
		}
	}
	else
		measure = (oph_string *)initid->ptr;
		
        measure->content = args->args[2];
        measure->length = &(args->lengths[2]);
        if(core_set_numelem(measure)){
                pmesg(1,  __FILE__, __LINE__, "Error on counting elements\n");
		*is_null=1;
                *error=1;
                return -1;
	}


        if(measure->numelem > 1){
                pmesg(1,  __FILE__, __LINE__, "Allowed only one numeric value or wrong input type\n");
                *is_null=1;
                *error=1;
                return -1;
        }

	switch(measure->type){
		case OPH_INT:{
			int tmp;
			core_oph_convert(measure, (void*)(&tmp));
			result = (long long) tmp;
			break;
		}
		case OPH_SHORT:{
			short tmp;
			core_oph_convert(measure, (void*)(&tmp));
			result = (long long) tmp;
			break;
		}
		case OPH_BYTE:{
			char tmp;
			core_oph_convert(measure, (void*)(&tmp));
			result = (long long) tmp;
			break;
		}
		case OPH_LONG:{
			long long tmp;
			core_oph_convert(measure, (void*)(&tmp));
			result = (long long) tmp;
			break;
		}
		default:
			pmesg(1,  __FILE__, __LINE__, "Invalid type\n");
			*is_null=1;
                	*error=1;
                	return -1;
	}

        *error=0;
        *is_null=0;
        return result;

}
void oph_aggregate_operator_add(UDF_INIT * initid, UDF_ARGS * args, char *is_null, char *error)
{
	if (*error || !args->args[2])
		return;

	//Assume that:
	//1. Type of each element is the same
	//2. Length of each array is the same
	oph_string measure;
	oph_agg_oper_data *dat = (oph_agg_oper_data *) initid->ptr;
	oph_requestPtr res = (oph_requestPtr) & (dat->result);

	/* Setting of the aggregate result */
	if (!res->measure.content) {
		//It's the first row 
		core_set_type(&(res->measure), args->args[0], &(args->lengths[0]));

		if (args->arg_count < 4) {
			core_set_oper(res, NULL, 0);
		} else {
			core_set_oper(res, args->args[3], &(args->lengths[3]));
		}

		if (!res->oper) {
			pmesg(1, __FILE__, __LINE__, "Operator not recognized\n");
			*is_null = 0;
			*error = 1;
			return;
		}
		core_set_hier(res, NULL, 0);
		res->measure.length = malloc(sizeof(unsigned long));
		if (!res->measure.length) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*is_null = 0;
			*error = 1;
			return;
		}
		*(res->measure.length) = args->lengths[2];

		core_set_elemsize(&(res->measure));

		if (core_set_numelem(&(res->measure))) {
			pmesg(1, __FILE__, __LINE__, "Error on counting elements\n");
			*is_null = 0;
			*error = 1;
			return;
		}

		res->measure.content = (char *) malloc(*(res->measure.length));
		if (!res->measure.content) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*is_null = 0;
			*error = 1;
			return;
		}

		switch (res->oper) {
			case OPH_COUNT:
				dat->core_oph_oper = core_oph_count_array;
				break;
			case OPH_MAX:
				dat->core_oph_oper = core_oph_max_array;
				break;
			case OPH_MIN:
				dat->core_oph_oper = core_oph_min_array;
				break;
			case OPH_SUM:
				dat->core_oph_oper = core_oph_sum_array;
				break;
			case OPH_AVG:
				dat->core_oph_oper = NULL;
				break;
			default:
				pmesg(1, __FILE__, __LINE__, "Unable to recognize operator\n");
				*is_null = 0;
				*error = 1;
				return;
		}

		oph_string output_array;
		core_set_type(&output_array, args->args[1], &(args->lengths[1]));
		if (!output_array.type) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*is_null = 0;
			*error = 1;
			return;
		}
		if (core_set_elemsize(&output_array)) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*is_null = 0;
			*error = 1;
			return;
		}
		dat->result_size = output_array.elemsize;
		dat->result_type = output_array.type;
		dat->result_length = res->measure.numelem * dat->result_size;
		dat->result_data = (char *) malloc(dat->result_length);
		if (!dat->result_data) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*is_null = 0;
			*error = 1;
			return;
		}
	}

	if (!dat->count && (res->oper == OPH_AVG)) {
		dat->count = (int *) malloc(res->measure.numelem * sizeof(int));
		if (!dat->count) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result string\n");
			*is_null = 0;
			*error = 1;
			return;
		}
		size_t i;
		for (i = 0; i < res->measure.numelem; ++i)
			dat->count[i] = 0;
	}

	measure.type = res->measure.type;
	measure.content = args->args[2];
	measure.length = res->measure.length;
	measure.elemsize = res->measure.elemsize;
	measure.numelem = res->measure.numelem;

	double missingvalue;
	if ((args->arg_count > 4) && args->args[4]) {
		missingvalue = *((double *) (args->args[4]));
		measure.missingvalue = &missingvalue;
	} else
		measure.missingvalue = NULL;

	if (res->oper == OPH_AVG) {
		if (core_oph_sum_array2(&measure, dat->first ? NULL : &(res->measure), res->measure.content, dat->count)) {
			pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
			*is_null = 0;
			*error = 1;
			return;
		}
	} else if (dat->first && (res->oper != OPH_COUNT)) {
		//It's the first row or the first row in the group of the GRUOP BY clause
		//Only perform the copy of the tuple
		memcpy(res->measure.content, args->args[2], *(res->measure.length));
	} else if (dat->core_oph_oper(&measure, dat->first ? NULL : &(res->measure), res->measure.content)) {
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*is_null = 0;
		*error = 1;
		return;
	}

	dat->first = 0;
}
void oph_aggregate_stats_partial_add(UDF_INIT * initid, UDF_ARGS * args, char *is_null, char *error)
{
	if (*error != 0)
		return;
	if (args->args[2]) {
		oph_agg_stats_partial_data *dat = (oph_agg_stats_partial_data *) initid->ptr;

		/* Setting of the aggregate result */
		if (!dat->result.content) {
			//It's the first row

			// default values
			unsigned long def_mask_len = MASK_LEN;
			dat->mask.content = (char *) calloc(MASK_LEN + 1, sizeof(char));
			if (!dat->mask.content) {
				pmesg(1, __FILE__, __LINE__, "Error allocating mask content\n");
				*error = 1;
				return;
			}
			core_strncpy(dat->mask.content, DEFAULT_MASK, &def_mask_len);

			dat->mask.length = (unsigned long *) calloc(1, sizeof(unsigned long));
			if (!dat->mask.length) {
				pmesg(1, __FILE__, __LINE__, "Error allocating mask length\n");
				*error = 1;
				return;
			}
			*(dat->mask.length) = def_mask_len;

			core_set_type(&(dat->measure), NULL, 0);
			dat->measure.length = (unsigned long *) calloc(1, sizeof(unsigned long));
			if (!dat->measure.length) {
				pmesg(1, __FILE__, __LINE__, "Error allocating measure length\n");
				*error = 1;
				return;
			}
			*(dat->measure.length) = args->lengths[2];

			core_set_type(&(dat->measure), args->args[0], &(args->lengths[0]));
			if (dat->measure.type != OPH_SHORT && dat->measure.type != OPH_BYTE && dat->measure.type != OPH_INT && dat->measure.type != OPH_LONG && dat->measure.type != OPH_FLOAT
			    && dat->measure.type != OPH_DOUBLE) {
				pmesg(1, __FILE__, __LINE__, "Invalid type\n");
				*error = 1;
				return;
			}
			if (args->arg_count > 3) {
				core_strncpy(dat->mask.content, args->args[3], &(args->lengths[3]));
				*(dat->mask.length) = args->lengths[3];
			}

			if (core_set_elemsize(&(dat->measure))) {
				pmesg(1, __FILE__, __LINE__, "Error on setting measure elements size\n");
				*error = 1;
				return;
			}
			if (core_set_numelem(&(dat->measure))) {
				pmesg(1, __FILE__, __LINE__, "Error on counting measure elements\n");
				*error = 1;
				return;
			}

			core_set_type(&dat->result, args->args[1], &(args->lengths[1]));
			if (!dat->result.type) {
				pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
				*error = 1;
				return;
			}
			if (core_set_elemsize(&dat->result)) {
				pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
				*error = 1;
				return;
			}
			// mask processing
			int i;
			for (i = 0; i < *(dat->mask.length); i++) {
				if (dat->mask.content[i] == '1') {
					(dat->mask.numelem)++;	// count 1s
					switch (i) {
						case 0:	// mean
							dat->sum1 = 1;	// sum{x_i} needed
							break;
						case 1:	// variance
							dat->sum1 = 1;
							dat->sum2 = 1;	// sum{(x_i)^2} needed
							break;
						case 2:	// std dev
							dat->sum1 = 1;
							dat->sum2 = 1;
							break;
						case 3:	// skew
							dat->sum1 = 1;
							dat->sum2 = 1;
							dat->sum3 = 1;	// sum{(x_i)^3} needed
							break;
						case 4:	// kurtosis
							dat->sum1 = 1;
							dat->sum2 = 1;
							dat->sum3 = 1;
							dat->sum4 = 1;	// sum{(x_i)^4} needed
							break;
						case 5:	// max
							dat->max = 1;	// array with max values needed
							break;
						case 6:	// min
							dat->min = 1;	// array with min values needed
					}
				}
			}
			if (dat->mask.numelem == 0) {
				pmesg(1, __FILE__, __LINE__, "Invalid mask\n");
				*error = 1;
				return;
			}

			int size = 1;
			if (dat->sum1)
				size++;
			if (dat->sum2)
				size++;
			if (dat->sum3)
				size++;
			if (dat->sum4)
				size++;
			if (dat->max)
				size++;
			if (dat->min)
				size++;

			// output array allocation
			dat->result.numelem = size * dat->measure.numelem;	// In future use a structed type of 'size' fields
			unsigned long outlen = dat->result.numelem * dat->result.elemsize;
			dat->result.length = (unsigned long *) calloc(1, sizeof(unsigned long));
			if (!dat->result.length) {
				pmesg(1, __FILE__, __LINE__, "Error allocating result length\n");
				*error = 1;
				return;
			}
			*(dat->result.length) = outlen;
			dat->result.content = (char *) calloc(1, *(dat->result.length));
			if (!dat->result.content) {
				pmesg(1, __FILE__, __LINE__, "Error allocating output array\n");
				*error = 1;
				return;
			}
			// partial results array allocation
			dat->partials = (oph_stringPtr) calloc((size - 1), sizeof(oph_string));
			if (!dat->partials) {
				pmesg(1, __FILE__, __LINE__, "Error allocating intermediate arrays\n");
				*error = 1;
				return;
			}
			for (i = 0; i < (size - 1); i++) {
				dat->partials[i].type = dat->measure.type;
				dat->partials[i].elemsize = dat->measure.elemsize;
				dat->partials[i].numelem = dat->measure.numelem;
				dat->partials[i].length = dat->measure.length;
				dat->partials[i].content = (char *) calloc(1, *(dat->partials[i].length));
				if (!dat->partials[i].content) {
					pmesg(1, __FILE__, __LINE__, "Error allocating intermediate array\n");
					*error = 1;
					return;
				}
			}
		}

		if (!dat->count) {
			//It's the first row or the first row in the group of the GROUP BY clause

			int i = 0;
			int j;
			// copy input values
			if (dat->sum1) {
				memcpy((void *) (dat->partials[i].content), (void *) (args->args[2]), *(dat->partials[i].length));
				i++;
			}
			// copy input values squared
			if (dat->sum2) {
				switch (dat->measure.type) {
					case OPH_INT:
						{
							int val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((int *) (args->args[2]))[j];
								((int *) (dat->partials[i].content))[j] = val_i * val_i;
							}
							break;
						}
					case OPH_SHORT:
						{
							int val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((short *) (args->args[2]))[j];
								((short *) (dat->partials[i].content))[j] = val_i * val_i;
							}
							break;
						}
					case OPH_BYTE:
						{
							int val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((char *) (args->args[2]))[j];
								((char *) (dat->partials[i].content))[j] = val_i * val_i;
							}
							break;
						}
					case OPH_LONG:
						{
							long long val_l;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_l = ((long long *) (args->args[2]))[j];
								((long long *) (dat->partials[i].content))[j] = val_l * val_l;
							}
							break;
						}
					case OPH_FLOAT:
						{
							float val_f;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_f = ((float *) (args->args[2]))[j];
								((float *) (dat->partials[i].content))[j] = val_f * val_f;
							}
							break;
						}
					case OPH_DOUBLE:
						{
							double val_d;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_d = ((double *) (args->args[2]))[j];
								((double *) (dat->partials[i].content))[j] = val_d * val_d;
							}
						}
					case OPH_COMPLEX_INT:
					case OPH_COMPLEX_LONG:
					case OPH_COMPLEX_FLOAT:
					case OPH_COMPLEX_DOUBLE:
					case INVALID_TYPE:
						break;
				}
				i++;
			}
			// copy input values raised to 3
			if (dat->sum3) {
				switch (dat->measure.type) {
					case OPH_INT:
						{
							int val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((int *) (args->args[2]))[j];
								((int *) (dat->partials[i].content))[j] = val_i * val_i * val_i;
							}
							break;
						}
					case OPH_SHORT:
						{
							short val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((short *) (args->args[2]))[j];
								((short *) (dat->partials[i].content))[j] = val_i * val_i * val_i;
							}
							break;
						}
					case OPH_BYTE:
						{
							char val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((char *) (args->args[2]))[j];
								((char *) (dat->partials[i].content))[j] = val_i * val_i * val_i;
							}
							break;
						}
					case OPH_LONG:
						{
							long long val_l;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_l = ((long long *) (args->args[2]))[j];
								((long long *) (dat->partials[i].content))[j] = val_l * val_l * val_l;
							}
							break;
						}
					case OPH_FLOAT:
						{
							float val_f;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_f = ((float *) (args->args[2]))[j];
								((float *) (dat->partials[i].content))[j] = val_f * val_f * val_f;
							}
							break;
						}
					case OPH_DOUBLE:
						{
							double val_d;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_d = ((double *) (args->args[2]))[j];
								((double *) (dat->partials[i].content))[j] = val_d * val_d * val_d;
							}
						}
					case OPH_COMPLEX_INT:
					case OPH_COMPLEX_LONG:
					case OPH_COMPLEX_FLOAT:
					case OPH_COMPLEX_DOUBLE:
					case INVALID_TYPE:
						break;
				}
				i++;
			}
			// copy input values raised to 4
			if (dat->sum4) {
				switch (dat->measure.type) {
					case OPH_INT:
						{
							int val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((int *) (args->args[2]))[j];
								((int *) (dat->partials[i].content))[j] = val_i * val_i * val_i * val_i;
							}
							break;
						}
					case OPH_SHORT:
						{
							short val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((short *) (args->args[2]))[j];
								((short *) (dat->partials[i].content))[j] = val_i * val_i * val_i * val_i;
							}
							break;
						}
					case OPH_BYTE:
						{
							char val_i;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_i = ((char *) (args->args[2]))[j];
								((char *) (dat->partials[i].content))[j] = val_i * val_i * val_i * val_i;
							}
							break;
						}
					case OPH_LONG:
						{
							long long val_l;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_l = ((long long *) (args->args[2]))[j];
								((long long *) (dat->partials[i].content))[j] = val_l * val_l * val_l * val_l;
							}
							break;
						}
					case OPH_FLOAT:
						{
							float val_f;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_f = ((float *) (args->args[2]))[j];
								((float *) (dat->partials[i].content))[j] = val_f * val_f * val_f * val_f;
							}
							break;
						}
					case OPH_DOUBLE:
						{
							double val_d;
							for (j = 0; j < dat->measure.numelem; j++) {
								val_d = ((double *) (args->args[2]))[j];
								((double *) (dat->partials[i].content))[j] = val_d * val_d * val_d * val_d;
							}
						}
					case OPH_COMPLEX_INT:
					case OPH_COMPLEX_LONG:
					case OPH_COMPLEX_FLOAT:
					case OPH_COMPLEX_DOUBLE:
					case INVALID_TYPE:
						break;
				}
				i++;
			}
			// copy input values
			if (dat->max) {
				memcpy(dat->partials[i].content, (void *) (args->args[2]), *(dat->partials[i].length));
				i++;
			}
			// copy input values
			if (dat->min) {
				memcpy(dat->partials[i].content, (void *) (args->args[2]), *(dat->partials[i].length));
				i++;
			}
		} else {
			// Not the first row in the group => execute next aggregation step

			dat->measure.content = args->args[2];

			int i = 0;
			if (dat->sum1) {
				if (core_oph_sum_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
			if (dat->sum2) {
				if (core_oph_sum2_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
			if (dat->sum3) {
				if (core_oph_sum3_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
			if (dat->sum4) {
				if (core_oph_sum4_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
			if (dat->max) {
				if (core_oph_max_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
			if (dat->min) {
				if (core_oph_min_array(&(dat->measure), &(dat->partials[i]), dat->partials[i].content)) {
					pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
					*error = 1;
					return;
				}
				i++;
			}
		}
		dat->count++;
	}
}
char *oph_get_subarray2(UDF_INIT * initid, UDF_ARGS * args, char *result, unsigned long *length, char *is_null, char *error)
{
	int res = 0, number = 0, i;
	oph_get_subarray2_param *param;
	oph_string *measure;
	unsigned long total, max;
	unsigned long *sizes = 0;

	if (*error) {
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}
	if (*is_null || !args->lengths[2] || !args->lengths[3]) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	if (!initid->ptr) {
		initid->ptr = (char *) malloc(sizeof(oph_get_subarray2_param));
		if (!initid->ptr) {
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_get_subarray2_param\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param = (oph_get_subarray2_param *) initid->ptr;
		param->measure = NULL;
		param->subset = NULL;
		param->flags = NULL;
		param->result = NULL;
		param->error = 0;
	} else
		param = (oph_get_subarray2_param *) initid->ptr;

	if (!param->error && !param->measure) {
		// Input
		param->measure = malloc(sizeof(oph_string));
		if (!param->measure) {
			pmesg(1, __FILE__, __LINE__, "Error allocating oph_string\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		measure = (oph_string *) param->measure;

		// Set measure->length
		measure->length = &(args->lengths[2]);

		// Set measure->type
		res = core_set_type(measure, args->args[0], &(args->lengths[0]));
		if (res) {
			pmesg(1, __FILE__, __LINE__, "Error on setting the data type\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		// Set measure->elemsize
		if (core_set_elemsize(measure)) {
			pmesg(1, __FILE__, __LINE__, "Error on setting data element size\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		// Set measure->numelem
		if (core_set_numelem(measure)) {
			pmesg(1, __FILE__, __LINE__, "Error on counting elements\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}

		if (args->arg_count > 4) {
			max = *((long long *) args->args[args->arg_count - 1]);
			number = args->arg_count - 4;
			sizes = (unsigned long *) malloc(number * sizeof(unsigned long));
			for (i = 0; i < number; ++i)
				sizes[i] = *((long long *) args->args[i + 4]);
		} else
			max = measure->numelem;

		// Set subsetting structures
		if (oph_subset_init(&(param->subset))) {
			pmesg(1, __FILE__, __LINE__, "Error in oph_subset initialization\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (oph_subset_parse(args->args[3], args->lengths[3], param->subset, max)) {
			pmesg(1, __FILE__, __LINE__, "Error in parsing subset_string\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		// New implementation with flags
		param->flags = malloc(measure->numelem * sizeof(char));
		if (!param->flags) {
			pmesg(1, __FILE__, __LINE__, "Error allocating flag array\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (oph_subset_set_flags(param->subset, param->flags, measure->numelem, &total, sizes, number)) {
			pmesg(1, __FILE__, __LINE__, "Error in setting flag array\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (sizes)
			free(sizes);

		oph_string output_array;
		core_set_type(&output_array, args->args[1], &(args->lengths[1]));
		if (!output_array.type) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		if (core_set_elemsize(&output_array)) {
			pmesg(1, __FILE__, __LINE__, "Unable to recognize measures type\n");
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
		param->result_type = output_array.type;
		param->result_elemsize = output_array.elemsize;

		// Output
		param->length = total * param->result_elemsize;	// bytes
		if (!param->length) {
			*length = 0;
			*is_null = 1;
			*error = 0;
			return NULL;
		}
		param->result = (char *) malloc(param->length);
		if (!param->result) {
			pmesg(1, __FILE__, __LINE__, "Error allocating result\n");
			param->error = 1;
			*length = 0;
			*is_null = 0;
			*error = 1;
			return NULL;
		}
	} else
		measure = (oph_string *) param->measure;

	// Set measure->content
	measure->content = args->args[2];	// Input
	if (!measure->content) {
		*length = 0;
		*is_null = 1;
		*error = 0;
		return NULL;
	}

	res = core_oph_get_subarray2(param);
	if (res) {
		pmesg(1, __FILE__, __LINE__, "Unable to compute result\n");
		*length = 0;
		*is_null = 0;
		*error = 1;
		return NULL;
	}

	*length = param->length;
	*is_null = 0;
	*error = 0;
	return (result = param->result);
}