Navigation


Changeset 285:0daf6fc2b751 in freeDiameter for extensions/app_acct/acct_db.c


Ignore:
Timestamp:
Apr 30, 2010, 5:55:16 PM (14 years ago)
Author:
Sebastien Decugis <sdecugis@nict.go.jp>
Branch:
default
Phase:
public
Message:

Added a test case for the app_acct extension

File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_acct/acct_db.c

    r284 r285  
    5151
    5252static const char * stmt = "acct_db_stmt";
    53 static PGconn *conn = NULL;
    54 
     53#ifndef TEST_DEBUG
     54static
     55#endif /* TEST_DEBUG */
     56PGconn *conn = NULL;
     57
     58/* Initialize the database context: connection to the DB, prepared statement to insert new records */
    5559int acct_db_init(void)
    5660{
     
    6367        int idx = 0;
    6468        PGresult * res;
    65         #define REALLOC_SIZE    1024
     69        #define REALLOC_SIZE    1024    /* We extend the buffer by this amount */
    6670       
    6771        TRACE_ENTRY();
     
    7680                acct_db_free();
    7781                return EINVAL;
    78         } else {
    79                 TRACE_DEBUG(INFO, "Connection to database successfull: user:%s, db:%s, host:%s.", PQuser(conn), PQdb(conn), PQhost(conn));
    80         }
     82        }
     83        if (PQprotocolVersion(conn) < 3) {
     84                fd_log_debug("Database protocol version is too old, version 3 is required for prepared statements.\n");
     85                acct_db_free();
     86                return EINVAL;
     87        }
     88       
     89        TRACE_DEBUG(FULL, "Connection to database successful, server version %d.", PQserverVersion(conn));
    8190       
    8291        /* Now, prepare the request object */
     
    174183        PQclear(res);
    175184       
    176        
    177 
     185        free(sql);
     186        acct_rec_empty(&emptyrecords);
     187       
     188        /* Ok, ready */
    178189        return 0;
    179190}
    180191
     192/* Terminate the connection to the DB */
    181193void acct_db_free(void)
    182 {
    183         if (conn)
     194{       
     195        if (conn) {
     196                /* Note: the prepared statement is automatically freed when the session terminates */
    184197                PQfinish(conn);
    185         conn = NULL;
     198                conn = NULL;
     199        }
    186200}
    187201
     202/* When a new message has been received, insert the content of the parsed mapping into the DB (using prepared statement) */
    188203int acct_db_insert(struct acct_record_list * records)
    189204{
    190         return ENOTSUP;
     205        char    **val;
     206        int      *val_len;
     207        int      *val_isbin;
     208        int       idx = 0;
     209        PGresult *res;
     210        struct fd_list *li;
     211       
     212        TRACE_ENTRY("%p", records);
     213        CHECK_PARAMS( conn && records );
     214       
     215        /* First, check if the connection with the DB has not staled, and eventually try to fix it */
     216        if (PQstatus(conn) != CONNECTION_OK) {
     217                /* Attempt a reset */
     218                PQreset(conn);
     219                if (PQstatus(conn) != CONNECTION_OK) {
     220                        TRACE_DEBUG(INFO, "Lost connection to the database server, and attempt to reestablish it failed");
     221                        TODO("Terminate the freeDiameter instance completly?");
     222                        return ENOTCONN;
     223                }
     224        }
     225       
     226        /* Alloc the arrays of parameters */
     227        CHECK_MALLOC( val       = calloc(records->nball, sizeof(const char *)) );
     228        CHECK_MALLOC( val_len   = calloc(records->nball, sizeof(const int)) );
     229        CHECK_MALLOC( val_isbin = calloc(records->nball, sizeof(const int)) );
     230       
     231        /* Now write all the map'd records in these arrays */
     232        for (li = records->all.next; li != &records->all; li = li->next) {
     233                struct acct_record_item * r = (struct acct_record_item *)(li->o);
     234                if (r->value) {
     235                        val_isbin[idx] = 1; /* We always pass binary parameters */
     236                        switch (r->param->avptype) {
     237                                case AVP_TYPE_OCTETSTRING:
     238                                        val[idx] = (void *)(r->value->os.data);
     239                                        val_len[idx] = r->value->os.len;
     240                                        break;
     241                                       
     242                                case AVP_TYPE_INTEGER32:
     243                                case AVP_TYPE_UNSIGNED32:
     244                                case AVP_TYPE_FLOAT32:
     245                                        r->scalar.v32 = htonl(r->value->u32);
     246                                        val[idx] = &r->scalar.c;
     247                                        val_len[idx] = sizeof(uint32_t);
     248                                        break;
     249                                       
     250                                case AVP_TYPE_INTEGER64:
     251                                case AVP_TYPE_UNSIGNED64:
     252                                case AVP_TYPE_FLOAT64:
     253                                        r->scalar.v64 = htonll(r->value->u64);
     254                                        val[idx] = &r->scalar.c;
     255                                        val_len[idx] = sizeof(uint64_t);
     256                                        break;
     257                               
     258                                default:
     259                                        ASSERT(0); /* detect bugs */
     260                        }
     261                }
     262               
     263                idx++;
     264        }
     265       
     266        /* OK, now execute the SQL statement */
     267        res = PQexecPrepared(conn, stmt, records->nball, (const char * const *)val, val_len, val_isbin, 1 /* We actually don't care here */);
     268       
     269        /* Done with the parameters */
     270        free(val);
     271        free(val_len);
     272        free(val_isbin);
     273       
     274        /* Now check the result code */
     275        if (PQresultStatus(res) != PGRES_COMMAND_OK) {
     276                TRACE_DEBUG(INFO, "An error occurred while INSERTing in the database: %s", PQerrorMessage(conn));
     277                PQclear(res);
     278                return EINVAL; /* It was probably a mistake in configuration file... */
     279        }
     280        PQclear(res);
     281       
     282        /* Ok, we are done */
     283        return 0;
    191284}
    192285
Note: See TracChangeset for help on using the changeset viewer.