/** * Removes (drops) a secondary index. * * ~~~~~~~~~~{.c} * if ( aerospike_index_remove(&as, &err, NULL, "test", idx_test_demo_bin1") != AEROSPIKE_OK ) { * fprintf(stderr, "error(%d) %s at [%s:%d]", err.code, err.message, err.file, err.line); * } * ~~~~~~~~~~ * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param ns The namespace containing the index to be removed. * @param name The name of the index to be removed. * * @return AEROSPIKE_OK if successful or index does not exist. Otherwise an error. * * @ingroup index_operations */ as_status aerospike_index_remove( aerospike * as, as_error * err, const as_policy_info * policy, const char * ns, const char * name) { as_error_reset(err); char ddl[1024]; sprintf(ddl, "sindex-delete:ns=%s;indexname=%s", ns, name); char* response = NULL; as_status status = aerospike_info_any(as, err, policy, ddl, &response); switch (status) { case AEROSPIKE_OK: cf_free(response); break; case AEROSPIKE_ERR_INDEX_NOT_FOUND: status = AEROSPIKE_OK; as_error_reset(err); break; default: break; } return status; }
/** * @return AEROSPIKE_OK if successful. Otherwise an error occurred. */ as_status aerospike_udf_put( aerospike * as, as_error * err, const as_policy_info * policy, const char * filename, as_udf_type type, as_bytes * content) { if (type != AS_UDF_TYPE_LUA) { return as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf type: %d", type); } as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } char* command = NULL; as_string filename_string; const char* filebase = as_basename(&filename_string, filename); uint32_t encoded_len = cf_b64_encoded_len(content->size); char* content_base64 = malloc(encoded_len + 1); cf_b64_encode(content->value, content->size, content_base64); content_base64[encoded_len] = 0; if (! asprintf(&command, "udf-put:filename=%s;content=%s;content-len=%d;udf-type=%s;", filebase, content_base64, encoded_len, as_udf_type_str[type])) { as_string_destroy(&filename_string); free(content_base64); return as_error_set_message(err, AEROSPIKE_ERR_CLIENT, "Udf put asprintf failed"); } as_string_destroy(&filename_string); char* response = 0; as_status status = aerospike_info_any(as, err, policy, command, &response); free(command); free(content_base64); if (status) { return status; } free(response); return AEROSPIKE_OK; }
/** * @return AEROSPIKE_OK if successful. Otherwise an error occurred. */ as_status aerospike_udf_remove( aerospike * as, as_error * err, const as_policy_info * policy, const char * filename) { as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } char command[512]; snprintf(command, sizeof(command), "udf-remove:filename=%s;", filename); char* response = 0; as_status status = aerospike_info_any(as, err, policy, command, &response); if (status) { return status; } free(response); return AEROSPIKE_OK; }
/** * Create secondary index. * * This asynchronous server call will return before the command is complete. * The user can optionally wait for command completion by using a task instance. * * ~~~~~~~~~~{.c} * as_index_task task; * if ( aerospike_index_create(&as, &err, &task, NULL, "test", "demo", "bin1", "idx_test_demo_bin1") == AEROSPIKE_OK ) { * aerospike_index_create_wait(&err, &task, 0); * } * ~~~~~~~~~~ * * @param as The aerospike instance to use for this operation. * @param err The as_error to be populated if an error occurs. * @param task The optional task data used to poll for completion. * @param policy The policy to use for this operation. If NULL, then the default policy will be used. * @param ns The namespace to be indexed. * @param set The set to be indexed. * @param bin The bin to be indexed. * @param name The name of the index. * * @return AEROSPIKE_OK if successful or index already exists. Otherwise an error. * * @ingroup index_operations */ as_status aerospike_index_create_complex( aerospike * as, as_error * err, as_index_task * task, const as_policy_info * policy, const as_namespace ns, const as_set set, const as_index_position position, const char * name, as_index_type itype, as_index_datatype dtype) { as_error_reset(err); const char* dtype_string; switch (dtype) { case AS_INDEX_NUMERIC: dtype_string = "NUMERIC"; break; case AS_INDEX_GEO2DSPHERE: dtype_string = "GEO2DSPHERE"; break; default: case AS_INDEX_STRING: dtype_string = "STRING"; break; } const char* itype_string; switch (itype) { default: case AS_INDEX_TYPE_DEFAULT: { itype_string = "DEFAULT"; break; } case AS_INDEX_TYPE_LIST: { itype_string = "LIST"; break; } case AS_INDEX_TYPE_MAPKEYS: { itype_string = "MAPKEYS"; break; } case AS_INDEX_TYPE_MAPVALUES: { itype_string = "MAPVALUES"; break; } } char ddl[1024]; if (itype == AS_INDEX_TYPE_DEFAULT) { // Use old format, so command can work with older servers. sprintf(ddl, "sindex-create:ns=%s%s%s;indexname=%s;" "numbins=1;indexdata=%s,%s;priority=normal\n", ns, set ? ";set=" : "", set ? set : "", name, position, dtype_string ); } else { // Use new format. sprintf(ddl, "sindex-create:ns=%s%s%s;indexname=%s;" "numbins=1;indextype=%s;indexdata=%s,%s;priority=normal\n", ns, set ? ";set=" : "", set ? set : "", name, itype_string, position, dtype_string ); } char* response = NULL; as_status status = aerospike_info_any(as, err, policy, ddl, &response); switch (status) { case AEROSPIKE_OK: // Return task that could optionally be polled for completion. if (task) { task->as = as; as_strncpy(task->ns, ns, sizeof(task->ns)); as_strncpy(task->name, name, sizeof(task->name)); task->done = false; } cf_free(response); break; case AEROSPIKE_ERR_INDEX_FOUND: // Index has already been created. Do not need to poll for completion. if (task) { task->done = true; } status = AEROSPIKE_OK; as_error_reset(err); break; default: break; } return status; }
/** * @return AEROSPIKE_OK if successful. Otherwise an error occurred. */ as_status aerospike_udf_list( aerospike * as, as_error * err, const as_policy_info * policy, as_udf_files * files) { as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } char* response = 0; as_status status = aerospike_info_any(as, err, policy, "udf-list", &response); if (status) { return status; } // response := udf-list\tfilename=<name>,hash=<hash>,type=<type>;[filename=<name>...] char* p = strchr(response, '\t'); if (!p) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf-list response: %s", response); free(response); return AEROSPIKE_ERR_PARAM; } p++; uint32_t capacity = (files->capacity <= 0) ? 500 : files->capacity; as_vector ptrs; as_vector_inita(&ptrs, sizeof(as_udf_file_ptr), capacity); as_udf_file_ptr ptr = {0,0,0}; char* token = p; while (*p) { switch (*p) { case '=': *p++ = 0; as_udf_parse_file(token, p, &ptr); break; case ',': *p++ = 0; token = p; break; case ';': *p++ = 0; token = p; as_vector_append(&ptrs, &ptr); ptr.name = 0; ptr.hash = 0; ptr.type = 0; break; default: p++; break; } } if (files->capacity == 0 && files->entries == NULL) { as_udf_files_init(files, ptrs.size); } uint32_t limit = ptrs.size < files->capacity ? ptrs.size : files->capacity; files->size = limit; for (uint32_t i = 0; i < limit; i++) { as_udf_file_ptr* ptr = as_vector_get(&ptrs, i); as_udf_file* file = &files->entries[i]; if (ptr->name) { as_strncpy(file->name, ptr->name, AS_UDF_FILE_NAME_SIZE); } else { file->name[0] = 0; } if (ptr->hash) { // The hash is not null terminated, so normal strncpy is appropriate here. // strncpy will also pad zeroes if hash size is incorrect. strncpy((char*)file->hash, ptr->hash, AS_UDF_FILE_HASH_SIZE); } else { file->hash[0] = 0; } file->type = AS_UDF_TYPE_LUA; file->content._free = false; file->content.size = 0; file->content.capacity = 0; file->content.bytes = NULL; } as_vector_destroy(&ptrs); free(response); return AEROSPIKE_OK; }
/** * @return AEROSPIKE_OK if successful. Otherwise an error occurred. */ as_status aerospike_udf_get( aerospike * as, as_error * err, const as_policy_info * policy, const char * filename, as_udf_type type, as_udf_file * file) { as_error_reset(err); if (! policy) { policy = &as->config.policies.info; } char command[512]; snprintf(command, sizeof(command), "udf-get:filename=%s;", filename); char* response = 0; as_status status = aerospike_info_any(as, err, policy, command, &response); if (status) { return status; } // response := <command>\tgen=<string>;type=<string>;content=<string>; char* p = strchr(response, '\t'); if (!p) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf-get response: %s", response); free(response); return AEROSPIKE_ERR_PARAM; } p++; p = strstr(p, "content="); if (!p) { as_error_update(err, AEROSPIKE_ERR_PARAM, "Invalid udf-get response: %s", response); free(response); return AEROSPIKE_ERR_PARAM; } p += 8; as_strncpy(file->name, filename, AS_UDF_FILE_NAME_SIZE); file->type = AS_UDF_TYPE_LUA; char* content = p; while (*p) { if (*p == ';') { *p = 0; break; } p++; } uint32_t len = (uint32_t)(p - content); uint32_t size; cf_b64_validate_and_decode_in_place((uint8_t*)content, len, &size); // Update file hash unsigned char hash[SHA_DIGEST_LENGTH]; #ifdef __APPLE__ // Openssl is deprecated on mac, but the library is still included. // Save old settings and disable deprecated warnings. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif SHA1((uint8_t*)content, size, hash); #ifdef __APPLE__ // Restore old settings. #pragma GCC diagnostic pop #endif cf_convert_sha1_to_hex(hash, file->hash); file->content._free = true; file->content.size = size; file->content.capacity = size; file->content.bytes = malloc(size); memcpy(file->content.bytes, content, size); free(response); return AEROSPIKE_OK; }