int ldb_msg_find_common_values(struct ldb_context *ldb,
			       TALLOC_CTX *mem_ctx,
			       struct ldb_message_element *el,
			       struct ldb_message_element *el2,
			       uint32_t options)
{
	struct ldb_val *values;
	struct ldb_val *values2;
	unsigned int i, j, k, n_values;

	bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;

	if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (strcmp(el->name, el2->name) != 0) {
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}
	if (el->num_values == 0 || el2->num_values == 0) {
		return LDB_SUCCESS;
	}
	/*
	   With few values, it is better to do the brute-force search than the
	   clever search involving tallocs, memcpys, sorts, etc.
	*/
	if (MIN(el->num_values, el2->num_values) == 1 ||
	    MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
		for (i = 0; i < el2->num_values; i++) {
			for (j = 0; j < el->num_values; j++) {
				if (ldb_val_equal_exact(&el->values[j],
							&el2->values[i])) {
					if (! remove_duplicates) {
					    return			\
					      LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					}
					/*
					  With the remove_duplicates flag, we
					  resolve the intersection by removing
					  the offending one from el.
					*/
					el->num_values--;
					for (k = j; k < el->num_values; k++) {
						el->values[k] = \
							el->values[k + 1];
					}
					j--; /* rewind */
				}
			}
		}
		return LDB_SUCCESS;
	}

	values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
	if (values == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	values2 = talloc_array(mem_ctx, struct ldb_val,
				    el2->num_values);
	if (values2 == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	memcpy(values, el->values,
	       el->num_values * sizeof(struct ldb_val));
	memcpy(values2, el2->values,
	       el2->num_values * sizeof(struct ldb_val));
	TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
	TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);

	/*
	   el->n_values may diverge from the number of values in the sorted
	   list when the remove_duplicates flag is used.
	*/
	n_values = el->num_values;
	i = 0;
	j = 0;
	while (i != n_values && j < el2->num_values) {
		int ret = ldb_val_cmp(&values[i], &values2[j]);
		if (ret < 0) {
			i++;
		} else if (ret > 0) {
			j++;
		} else {
			/* we have a collision */
			if (! remove_duplicates) {
				TALLOC_FREE(values);
				TALLOC_FREE(values2);
				return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
			}
			/*
			   With the remove_duplicates flag we need to find
			   this in the original list and remove it, which is
			   inefficient but hopefully rare.
			*/
			for (k = 0; k < el->num_values; k++) {
				if (ldb_val_equal_exact(&el->values[k],
							&values[i])) {
					break;
				}
			}
			el->num_values--;
			for (; k < el->num_values; k++) {
				el->values[k] = el->values[k + 1];
			}
			i++;
		}
	}
	TALLOC_FREE(values);
	TALLOC_FREE(values2);

	return LDB_SUCCESS;
}
int ldb_msg_find_common_values(struct ldb_context *ldb,
			       TALLOC_CTX *mem_ctx,
			       struct ldb_message_element *el,
			       struct ldb_message_element *el2,
			       uint32_t options)
{
	struct ldb_val *values;
	struct ldb_val *values2;
	unsigned int i, j, k, n_values;

	bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;

	if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (strcmp(el->name, el2->name) != 0) {
		return LDB_ERR_INAPPROPRIATE_MATCHING;
	}
	if (el->num_values == 0 || el2->num_values == 0) {
		return LDB_SUCCESS;
	}
	 
	if (MIN(el->num_values, el2->num_values) == 1 ||
	    MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
		for (i = 0; i < el2->num_values; i++) {
			for (j = 0; j < el->num_values; j++) {
				if (ldb_val_equal_exact(&el->values[j],
							&el2->values[i])) {
					if (! remove_duplicates) {
					    return			\
					      LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					}
					 
					el->num_values--;
					for (k = j; k < el->num_values; k++) {
						el->values[k] = \
							el->values[k + 1];
					}
					j--;  
				}
			}
		}
		return LDB_SUCCESS;
	}

	values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
	if (values == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	values2 = talloc_array(mem_ctx, struct ldb_val,
				    el2->num_values);
	if (values2 == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	memcpy(values, el->values,
	       el->num_values * sizeof(struct ldb_val));
	memcpy(values2, el2->values,
	       el2->num_values * sizeof(struct ldb_val));
	TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
	TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);

	 
	n_values = el->num_values;
	i = 0;
	j = 0;
	while (i != n_values && j < el2->num_values) {
		int ret = ldb_val_cmp(&values[i], &values2[j]);
		if (ret < 0) {
			i++;
		} else if (ret > 0) {
			j++;
		} else {
			 
			if (! remove_duplicates) {
				TALLOC_FREE(values);
				TALLOC_FREE(values2);
				return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
			}
			 
			for (k = 0; k < el->num_values; k++) {
				if (ldb_val_equal_exact(&el->values[k],
							&values[i])) {
					break;
				}
			}
			el->num_values--;
			for (; k < el->num_values; k++) {
				el->values[k] = el->values[k + 1];
			}
			i++;
		}
	}
	TALLOC_FREE(values);
	TALLOC_FREE(values2);

	return LDB_SUCCESS;
}