Lesson 19-C Language and Redis Database Operations

Operating Redis databases in C language typically requires using a C client library, with the most commonly used being hiredis. hiredis is a high-performance Redis client library that supports all Redis commands and provides the capability for asynchronous command execution.

Below is a simple example demonstrating how to use C language with hiredis to connect to a Redis server and perform basic operations, such as setting and getting key-value pairs.

Installing hiredis

First, you need to install the hiredis library. If you are using a Linux system, you can install it via the package manager. For example, on Ubuntu, use the following command:

sudo apt-get install libhiredis-dev

Example Code Next, you can start writing a C program to connect to Redis and execute operations.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

#define REDIS_HOST "localhost"
#define REDIS_PORT 6379

void print_error(redisContext *context) {
    if (context->err) {
        printf("Error: %s\n", context->errstr);
        if (context->err == REDIS_ERR_EOF) {
            printf("Connection closed by server\n");
        } else if (context->err == REDIS_ERR_DISCONNECT) {
            printf("Callback in context without connection\n");
        }
    }
}

int main(void) {
    redisContext *c;
    redisReply *reply;

    // Create Redis connection
    c = redisConnect(REDIS_HOST, REDIS_PORT);
    if (c == NULL || c->err) {
        if (c) {
            print_error(c);
            redisFree(c);
        }
        exit(1);
    }

    // Set key-value pair
    reply = (redisReply *)redisCommand(c, "SET key1 value1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (strcmp(reply->str, "OK") != 0) {
        printf("Unexpected reply from SET command: %s\n", reply->str);
        freeReplyObject(reply);
        exit(1);
    }
    freeReplyObject(reply);

    // Get key-value pair
    reply = (redisReply *)redisCommand(c, "GET key1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_STRING) {
        printf("Value of key1: %s\n", reply->str);
    } else if (reply->type == REDIS_REPLY_NIL) {
        printf("Key1 does not exist\n");
    } else {
        printf("Unexpected reply type from GET command: %d\n", reply->type);
    }
    freeReplyObject(reply);

    // Disconnect
    redisFree(c);

    return 0;
}

Explanation

Connecting to Redis:

  • Use redisConnect to create a new Redis connection.
  • If the connection fails, redisConnect returns a context object with error information.

Executing Commands:

  • Use redisCommand to send commands to the Redis server.
  • redisCommand returns a redisReply structure containing the command result.

Parsing Results:

  • For string-type replies, the redisReply structure contains a pointer to the string in str.
  • For other types of replies, such as integers or arrays, check the type member of redisReply.

Disconnecting:

  • Use redisFree to release connection resources.

Error Handling:

  • Check for errors after each redisCommand call.
  • Use the print_error function to print error messages.

Compiling the Program

  • Compiling the above program requires linking the hiredis library. Use the following command:
gcc -o redis_example redis_example.c -lhiredis

This will generate an executable file named redis_example.

Deleting a Key

    // Delete key
    reply = (redisReply *)redisCommand(c, "DEL key1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
        printf("Deleted key1 successfully.\n");
    } else {
        printf("Failed to delete key1.\n");
    }
    freeReplyObject(reply);

Listing All Keys

    // List all keys
    reply = (redisReply *)redisCommand(c, "KEYS *");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_ARRAY) {
        printf("List of keys:\n");
        for (size_t i = 0; i < reply->elements; i++) {
            printf("%s\n", ((redisReply *)reply->element[i])->str);
        }
    } else {
        printf("Unexpected reply type from KEYS command: %d\n", reply->type);
    }
    freeReplyObject(reply);

Using Pipelines to Execute Commands in Batch

    // Use pipeline to execute commands in batch
    redisAppendCommand(c, "SET key2 value2");
    redisAppendCommand(c, "GET key2");
    redisAppendCommand(c, "DEL key2");

    // Execute commands in the pipeline
    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    freeReplyObject(reply);

    // Get result of each command
    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (strcmp(reply->str, "OK") != 0) {
        printf("Unexpected reply from SET command: %s\n", reply->str);
    }
    freeReplyObject(reply);

    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_STRING) {
        printf("Value of key2: %s\n", reply->str);
    } else if (reply->type == REDIS_REPLY_NIL) {
        printf("Key2 does not exist\n");
    } else {
        printf("Unexpected reply type from GET command: %d\n", reply->type);
    }
    freeReplyObject(reply);

    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
        printf("Deleted key2 successfully.\n");
    } else {
        printf("Failed to delete key2.\n");
    }
    freeReplyObject(reply);

Complete Example Code

Below is the complete C language code example for connecting to a Redis server, executing various commands, and handling results:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

#define REDIS_HOST "localhost"
#define REDIS_PORT 6379

void print_error(redisContext *context) {
    if (context->err) {
        printf("Error: %s\n", context->errstr);
        if (context->err == REDIS_ERR_EOF) {
            printf("Connection closed by server\n");
        } else if (context->err == REDIS_ERR_DISCONNECT) {
            printf("Callback in context without connection\n");
        }
    }
}

int main(void) {
    redisContext *c;
    redisReply *reply;

    // Create Redis connection
    c = redisConnect(REDIS_HOST, REDIS_PORT);
    if (c == NULL || c->err) {
        if (c) {
            print_error(c);
            redisFree(c);
        }
        exit(1);
    }

    // Set key-value pair
    reply = (redisReply *)redisCommand(c, "SET key1 value1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (strcmp(reply->str, "OK") != 0) {
        printf("Unexpected reply from SET command: %s\n", reply->str);
        freeReplyObject(reply);
        exit(1);
    }
    freeReplyObject(reply);

    // Get key-value pair
    reply = (redisReply *)redisCommand(c, "GET key1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_STRING) {
        printf("Value of key1: %s\n", reply->str);
    } else if (reply->type == REDIS_REPLY_NIL) {
        printf("Key1 does not exist\n");
    } else {
        printf("Unexpected reply type from GET command: %d\n", reply->type);
    }
    freeReplyObject(reply);

    // Delete key
    reply = (redisReply *)redisCommand(c, "DEL key1");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
        printf("Deleted key1 successfully.\n");
    } else {
        printf("Failed to delete key1.\n");
    }
    freeReplyObject(reply);

    // List all keys
    reply = (redisReply *)redisCommand(c, "KEYS *");
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_ARRAY) {
        printf("List of keys:\n");
        for (size_t i = 0; i < reply->elements; i++) {
            printf("%s\n", ((redisReply *)reply->element[i])->str);
        }
    } else {
        printf("Unexpected reply type from KEYS command: %d\n", reply->type);
    }
    freeReplyObject(reply);

    // Use pipeline to execute commands in batch
    redisAppendCommand(c, "SET key2 value2");
    redisAppendCommand(c, "GET key2");
    redisAppendCommand(c, "DEL key2");

    // Execute commands in the pipeline
    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    freeReplyObject(reply);

    // Get result of each command
    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (strcmp(reply->str, "OK") != 0) {
        printf("Unexpected reply from SET command: %s\n", reply->str);
    }
    freeReplyObject(reply);

    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_STRING) {
        printf("Value of key2: %s\n", reply->str);
    } else if (reply->type == REDIS_REPLY_NIL) {
        printf("Key2 does not exist\n");
    } else {
        printf("Unexpected reply type from GET command: %d\n", reply->type);
    }
    freeReplyObject(reply);

    reply = (redisReply *)redisGetReply(c);
    if (reply == NULL) {
        print_error(c);
        exit(1);
    }
    if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) {
        printf("Deleted key2 successfully.\n");
    } else {
        printf("Failed to delete key2.\n");
    }
    freeReplyObject(reply);

    // Disconnect
    redisFree(c);

    return 0;
}

Compiling the Program

Compiling the above program requires linking the hiredis library. Use the following command:

sh
gcc -o redis_example redis_example.c -lhiredis
Share your love