static int db_sqlite_bind_values(sqlite3_stmt* stmt, const db_val_t* v, const int n) { int i, ret; if (n>0 && v) { for (i=0; i<n; i++) { if (VAL_NULL(v+i)) { ret=sqlite3_bind_null(stmt, i+1); goto check_ret; } switch(VAL_TYPE(v+i)) { /* every param has '+1' index because in sqlite the leftmost * parameter has index '1' */ case DB_INT: ret=sqlite3_bind_int(stmt, i+1, VAL_INT(v+i)); break; case DB_BIGINT: ret=sqlite3_bind_int64(stmt, i+1, VAL_BIGINT(v+i)); break; case DB_DOUBLE: ret=sqlite3_bind_double(stmt, i+1, VAL_DOUBLE(v+i)); break; case DB_STRING: ret=sqlite3_bind_text(stmt, i+1, VAL_STRING(v+i), strlen(VAL_STRING(v+i)), SQLITE_STATIC); break; case DB_STR: ret=sqlite3_bind_text(stmt, i+1, VAL_STR(v+i).s, VAL_STR(v+i).len, SQLITE_STATIC); break; case DB_DATETIME: ret=sqlite3_bind_int64(stmt, i+1, (long int)VAL_TIME(v+i)); break; case DB_BLOB: ret=sqlite3_bind_blob(stmt, i+1, (void*)VAL_BLOB(v+i).s, VAL_BLOB(v+i).len, SQLITE_STATIC); break; case DB_BITMAP: ret=sqlite3_bind_int(stmt, i+1, (int)VAL_BITMAP(v+i)); break; default: LM_BUG("invalid db type\n"); return 1; } check_ret: if (ret != SQLITE_OK) { return ret; } } } return SQLITE_OK; }
inline SV *valdata(db_val_t* val) { SV *data = &PL_sv_undef; const char* stringval; switch(VAL_TYPE(val)) { case DB1_INT: data = newSViv(VAL_INT(val)); break; case DB1_BIGINT: LM_ERR("BIGINT not supported"); data = &PL_sv_undef; break; case DB1_DOUBLE: data = newSVnv(VAL_DOUBLE(val)); break; case DB1_STRING: stringval = VAL_STRING(val); if (strlen(stringval) > 0) data = newSVpv(stringval, strlen(stringval)); else data = &PL_sv_undef; break; case DB1_STR: if (VAL_STR(val).len > 0) data = newSVpv(VAL_STR(val).s, VAL_STR(val).len); else data = &PL_sv_undef; break; case DB1_DATETIME: data = newSViv((unsigned int)VAL_TIME(val)); break; case DB1_BLOB: if (VAL_BLOB(val).len > 0) data = newSVpv(VAL_BLOB(val).s, VAL_BLOB(val).len); else data = &PL_sv_undef; break; case DB1_BITMAP: data = newSViv(VAL_BITMAP(val)); break; } return data; }
/** * Release a result set from memory. * \param _h handle to the database * \param _r result set that should be freed * \return zero on success, negative value on failure */ int db_sqlite_free_result(db_con_t* _h, db_res_t* _r) { int i; int j; db_val_t* v; db_row_t* res_col; if (!_h) { LM_ERR("invalid database handle\n"); return -1; } if (!_r) { LM_DBG("nothing to free!\n"); return 0; } if (RES_ROWS(_r)) { LM_DBG("freeing rows at %p\n", RES_ROWS(_r)); for (i = 0; i < RES_ROW_N(_r); i++) { for (j = 0; j < RES_COL_N(_r); j++) { res_col = &_r->rows[i]; v = &res_col->values[j]; if (VAL_NULL(v)) continue; /* only allocated types; STR and BLOB;*/ if (VAL_TYPE(v) == DB_STR) { pkg_free(VAL_STR(v).s); VAL_STR(v).s = 0; } else if (VAL_TYPE(v) == DB_BLOB) { pkg_free(VAL_BLOB(v).s); VAL_BLOB(v).s = 0; } } } pkg_free(_r->rows[0].values); pkg_free(_r->rows); RES_ROWS(_r) = NULL; } RES_ROW_N(_r) = 0; pkg_free(_r); _r = NULL; return 0; }
int bdb_set_key(bdb_row_p _r, bdb_val_p _v) { /* NULL is not allowed for primary key */ if (VAL_NULL(&(_v->v))) { LOG(L_ERR, "BDB:bdb_set_key: NULL is not allowed for primary key\n"); return -1; } switch (VAL_TYPE(&(_v->v))) { case DB_INT: _r->key.data = &VAL_INT(&(_v->v)); _r->key.size = sizeof(VAL_INT(&(_v->v))); break; case DB_FLOAT: _r->key.data = &VAL_FLOAT(&(_v->v)); _r->key.size = sizeof(VAL_FLOAT(&(_v->v))); break; case DB_DATETIME: _r->key.data = &VAL_TIME(&(_v->v)); _r->key.size = sizeof(VAL_TIME(&(_v->v))); break; case DB_BLOB: _r->key.data = VAL_BLOB(&(_v->v)).s; _r->key.size = VAL_BLOB(&(_v->v)).len; break; case DB_DOUBLE: _r->key.data = &VAL_DOUBLE(&(_v->v)); _r->key.size = sizeof(VAL_DOUBLE(&(_v->v))); break; case DB_STRING: _r->key.data = (void *)VAL_STRING(&(_v->v)); _r->key.size = strlen(VAL_STRING(&(_v->v))) + 1; break; case DB_STR: _r->key.data = VAL_STR(&(_v->v)).s; _r->key.size = VAL_STR(&(_v->v)).len; break; case DB_BITMAP: _r->key.data = &VAL_BITMAP(&(_v->v)); _r->key.size = sizeof(VAL_BITMAP(&(_v->v))); break; default: LOG(L_ERR, "BDB:bdb_set_skey: unknown column type: %0X\n", VAL_TYPE(&(_v->v))); return -1; break; } return 0; };
void bdb_set_skey(bdb_srow_p _r, bdb_sval_p _v) { /* NULL is not allowed for primary key */ if (VAL_NULL(&(_v->v))) return; switch (VAL_TYPE(&(_v->v))) { case DB_INT: _r->key.data = &VAL_INT(&(_v->v)); _r->key.size = sizeof(VAL_INT(&(_v->v))); break; case DB_FLOAT: _r->key.data = &VAL_FLOAT(&(_v->v)); _r->key.size = sizeof(VAL_FLOAT(&(_v->v))); break; case DB_DATETIME: _r->key.data = &VAL_TIME(&(_v->v)); _r->key.size = sizeof(VAL_TIME(&(_v->v))); break; case DB_BLOB: _r->key.data = VAL_BLOB(&(_v->v)).s; _r->key.size = VAL_BLOB(&(_v->v)).len; break; case DB_DOUBLE: _r->key.data = &VAL_DOUBLE(&(_v->v)); _r->key.size = sizeof(VAL_DOUBLE(&(_v->v))); break; case DB_STRING: _r->key.data = (void *)VAL_STRING(&(_v->v)); _r->key.size = strlen(VAL_STRING(&(_v->v))) + 1; break; case DB_STR: _r->key.data = VAL_STR(&(_v->v)).s; _r->key.size = VAL_STR(&(_v->v)).len; break; case DB_BITMAP: _r->key.data = &VAL_BITMAP(&(_v->v)); _r->key.size = sizeof(VAL_BITMAP(&(_v->v))); break; default: LOG(L_ERR, "BDB:bdb_set_skey: unknown column type: %0X\n", VAL_TYPE(&(_v->v))); break; } #ifdef BDB_EXTRA_DEBUG LOG(L_NOTICE, "BDB:bdb_set_skey: use key '%.*s' (%d bytes)\n", _r->key.size, (char *)_r->key.data, _r->key.size); #endif };
/*! * \brief Convert a str to a db value, copy strings * * Convert a str to a db value, copy strings. * The postgresql module uses a custom escape function for BLOBs. * If the _s is linked in the db_val result, it will be returned zero * \param _t destination value type * \param _v destination value * \param _s source string * \param _l string length * \return 0 on success, negative on error */ int db_postgres_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l) { /* use common function for non BLOB, NULL setting and input * parameter checking */ if ( _t != DB1_BLOB || _s == NULL || _v == NULL) { return db_str2val(_t, _v, _s, _l, 1); } else { char * tmp_s = NULL; LM_DBG("converting BLOB [%.*s]\n", _l, _s); /* * The string is stored in new allocated memory, which we could * not free later thus we need to copy it to some new memory here. */ tmp_s = (char*)PQunescapeBytea((unsigned char*)_s, (size_t*)(void*)&(VAL_BLOB(_v).len)); if(tmp_s==NULL) { LM_ERR("PQunescapeBytea failed\n"); return -7; } VAL_BLOB(_v).s = pkg_malloc(VAL_BLOB(_v).len + 1); if (VAL_BLOB(_v).s == NULL) { LM_ERR("no private memory left\n"); PQfreemem(tmp_s); return -8; } LM_DBG("allocate %d+1 bytes memory for BLOB at %p", VAL_BLOB(_v).len, VAL_BLOB(_v).s); memcpy(VAL_BLOB(_v).s, tmp_s, VAL_BLOB(_v).len); PQfreemem(tmp_s); VAL_BLOB(_v).s[VAL_BLOB(_v).len] = '\0'; VAL_TYPE(_v) = DB1_BLOB; VAL_FREE(_v) = 1; LM_DBG("got blob len %d\n", _l); return 0; } }
int bdb_ufield_db2bdb(bdb_uval_p v, db_val_t* _v) { char *s; VAL_NULL(&(v->v)) = VAL_NULL(_v); VAL_TYPE(&(v->v)) = VAL_TYPE(_v); if (!VAL_NULL(&(v->v))) { switch (VAL_TYPE(_v)) { case DB_INT: VAL_INT(&(v->v)) = VAL_INT(_v); break; case DB_FLOAT: VAL_FLOAT(&(v->v)) = VAL_FLOAT(_v); break; case DB_DATETIME: VAL_TIME(&(v->v)) = VAL_TIME(_v); break; case DB_BLOB: s = pkg_malloc(VAL_BLOB(_v).len); memcpy(s, VAL_BLOB(_v).s, VAL_BLOB(_v).len); VAL_BLOB(&(v->v)).s = s; VAL_BLOB(&(v->v)).len = VAL_BLOB(_v).len; break; case DB_DOUBLE: VAL_DOUBLE(&(v->v)) = VAL_DOUBLE(_v); break; case DB_STRING: VAL_STR(&(v->v)).len = strlen(VAL_STRING(_v)) + 1; s = pkg_malloc(VAL_STR(&(v->v)).len); strcpy(s, VAL_STRING(_v)); VAL_STRING(&(v->v)) = s; break; case DB_STR: s = pkg_malloc(VAL_STR(_v).len); memcpy(s, VAL_STR(_v).s, VAL_STR(_v).len); VAL_STR(&(v->v)).s = s; VAL_STR(&(v->v)).len = VAL_STR(_v).len; break; case DB_BITMAP: VAL_BITMAP(&(v->v)) = VAL_BITMAP(_v); break; default: LOG(L_ERR, "BDB:bdb_ufield_db2bdb: unknown column type: %0X\n", VAL_TYPE(_v)); return -1; break; } } return 0; };
/* * Used when converting the query to a result */ int db_unixodbc_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l, const unsigned int _cpy) { /* db_unixodbc uses the NULL string for NULL SQL values */ if (_v && _s && !strcmp(_s, "NULL")) { LM_DBG("converting NULL value"); static str dummy_string = {"", 0}; memset(_v, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(_v) = dummy_string.s; VAL_STR(_v) = dummy_string; VAL_BLOB(_v) = dummy_string; VAL_TYPE(_v) = _t; VAL_NULL(_v) = 1; return 0; } else { return db_str2val(_t, _v, _s, _l, _cpy); } }
/* * Called after val2str to realy binding */ int db_oracle_val2bind(bmap_t* _m, const db_val_t* _v, OCIDate* _o) { if (VAL_NULL(_v)) { _m->addr = NULL; _m->size = 0; _m->type = SQLT_NON; return 0; } switch (VAL_TYPE(_v)) { case DB1_INT: _m->addr = (int*)&VAL_INT(_v); _m->size = sizeof(VAL_INT(_v)); _m->type = SQLT_INT; break; case DB1_BIGINT: LM_ERR("BIGINT not supported"); return -1; case DB1_BITMAP: _m->addr = (unsigned*)&VAL_BITMAP(_v); _m->size = sizeof(VAL_BITMAP(_v)); _m->type = SQLT_UIN; break; case DB1_DOUBLE: _m->addr = (double*)&VAL_DOUBLE(_v); _m->size = sizeof(VAL_DOUBLE(_v)); _m->type = SQLT_FLT; break; case DB1_STRING: _m->addr = (char*)VAL_STRING(_v); _m->size = strlen(VAL_STRING(_v))+1; _m->type = SQLT_STR; break; case DB1_STR: { unsigned len = VAL_STR(_v).len; char *estr, *pstr = VAL_STR(_v).s; estr = (char*)memchr(pstr, 0, len); if (estr) { LM_WARN("truncate STR len from %u to: '%s'\n", len, pstr); len = (unsigned)(estr - pstr) + 1; } _m->size = len; _m->addr = pstr; _m->type = SQLT_CHR; } break; case DB1_DATETIME: { struct tm* tm = localtime(&VAL_TIME(_v)); if (tm->tm_sec == 60) --tm->tm_sec; OCIDateSetDate(_o, (ub2)(tm->tm_year + 1900), (ub1)(tm->tm_mon + 1), (ub1)tm->tm_mday); OCIDateSetTime(_o, (ub1)tm->tm_hour, (ub1)tm->tm_min, (ub1)tm->tm_sec); _m->addr = _o; _m->size = sizeof(*_o); _m->type = SQLT_ODT; } break; case DB1_BLOB: _m->addr = VAL_BLOB(_v).s; _m->size = VAL_BLOB(_v).len; _m->type = SQLT_CLOB; break; default: LM_ERR("unknown data type\n"); return -1; } return 0; }
/*! * \brief Converting a value to a string * * Converting a value to a string, used when converting result from a query * \param _c database connection * \param _v source value * \param _s target string * \param _len target string length * \return 0 on success, negative on error */ int db_mysql_val2str(const db1_con_t* _c, const db_val_t* _v, char* _s, int* _len) { int l, tmp; char* old_s; tmp = db_val2str(_c, _v, _s, _len); if (tmp < 1) return tmp; switch(VAL_TYPE(_v)) { case DB1_STRING: l = strlen(VAL_STRING(_v)); if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -6; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STRING(_v), l); *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB1_STR: if (*_len < (VAL_STR(_v).len * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -7; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STR(_v).s, VAL_STR(_v).len); *_s++ = '\''; *_s = '\0'; *_len = _s - old_s; return 0; } break; case DB1_BLOB: l = VAL_BLOB(_v).len; if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -9; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STR(_v).s, l); *_s++ = '\''; *_s = '\0'; *_len = _s - old_s; return 0; } break; default: LM_DBG("unknown data type\n"); return -10; } }
/* * Convert a str to a db value, does not copy strings * The postgresql module uses a custom escape function for BLOBs, * so the common db_str2val function from db_ut.h could not used. * If the _s is linked in the db_val result, it will be returned zero */ int pg_str2val(db_type_t _t, db_val_t* _v, char* _s, int _l) { static str dummy_string = {"", 0}; #ifdef PARANOID if (!_v) { LM_ERR("db_val_t parameter cannot be NULL\n"); } #endif if (!_s) { memset(_v, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(_v) = dummy_string.s; VAL_STR(_v) = dummy_string; VAL_BLOB(_v) = dummy_string; VAL_TYPE(_v) = _t; VAL_NULL(_v) = 1; return 0; } VAL_NULL(_v) = 0; switch(_t) { case DB_INT: LM_DBG("converting INT [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("failed to convert INT value from string\n"); return -2; } else { VAL_TYPE(_v) = DB_INT; return 0; } break; case DB_BITMAP: LM_DBG("converting BITMAP [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("failed to convert BITMAP value from string\n"); return -3; } else { VAL_TYPE(_v) = DB_BITMAP; return 0; } break; case DB_DOUBLE: LM_DBG("converting DOUBLE [%s]\n", _s); if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { LM_ERR("failed to convert DOUBLE value from string\n"); return -4; } else { VAL_TYPE(_v) = DB_DOUBLE; return 0; } break; case DB_STRING: LM_DBG("converting STRING [%s]\n", _s); VAL_STRING(_v) = _s; VAL_TYPE(_v) = DB_STRING; return 0; case DB_STR: LM_DBG("converting STR [%s]\n", _s); VAL_STR(_v).s = (char*)_s; VAL_STR(_v).len = _l; VAL_TYPE(_v) = DB_STR; _s = 0; return 0; case DB_DATETIME: LM_DBG("converting DATETIME [%s]\n", _s); if (db_str2time(_s, &VAL_TIME(_v)) < 0) { LM_ERR("failed to convert datetime\n"); return -5; } else { VAL_TYPE(_v) = DB_DATETIME; return 0; } break; case DB_BLOB: LM_DBG("converting BLOB [%s]\n", _s); /* PQunescapeBytea: Converts a string representation of binary data * into binary data — the reverse of PQescapeBytea. * This is needed when retrieving bytea data in text format, * but not when retrieving it in binary format. */ VAL_BLOB(_v).s = (char*)PQunescapeBytea((unsigned char*)_s, (size_t*)(void*)&(VAL_BLOB(_v).len) ); VAL_TYPE(_v) = DB_BLOB; LM_DBG("got blob len %d\n", _l); return 0; } return -6; }
/* * Insert a row into specified table * h: structure representing database connection * k: key names * v: values of the keys * n: number of key=value pairs */ int flat_db_insert(const db1_con_t* h, const db_key_t* k, const db_val_t* v, const int n) { FILE* f; int i; int l; char *s, *p; if (km_local_timestamp < *km_flat_rotate) { flat_rotate_logs(); km_local_timestamp = *km_flat_rotate; } f = CON_FILE(h); if (!f) { LM_ERR("uninitialized connection\n"); return -1; } for(i = 0; i < n; i++) { switch(VAL_TYPE(v + i)) { case DB1_INT: fprintf(f, "%d", VAL_INT(v + i)); break; case DB1_BIGINT: LM_ERR("BIGINT not supported"); return -1; case DB1_DOUBLE: fprintf(f, "%f", VAL_DOUBLE(v + i)); break; case DB1_STRING: fprintf(f, "%s", VAL_STRING(v + i)); break; case DB1_STR: fprintf(f, "%.*s", VAL_STR(v + i).len, VAL_STR(v + i).s); break; case DB1_DATETIME: fprintf(f, "%u", (unsigned int)VAL_TIME(v + i)); break; case DB1_BLOB: l = VAL_BLOB(v+i).len; s = p = VAL_BLOB(v+i).s; while (l--) { if ( !(isprint((int)*s) && *s != '\\' && *s != '|')) { fprintf(f,"%.*s\\x%02X",(int)(s-p),p,(*s & 0xff)); p = s+1; } ++s; } if (p!=s) fprintf(f,"%.*s",(int)(s-p),p); break; case DB1_BITMAP: fprintf(f, "%u", VAL_BITMAP(v + i)); break; } if (i < (n - 1)) { fprintf(f, "%c", *km_flat_delimiter); } } fprintf(f, "\n"); if (flat_flush) { fflush(f); } return 0; }
/* * Convert str to db value, does not copy strings */ int db_mysql_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l) { static str dummy_string = {"", 0}; if (!_v) { LM_ERR("invalid parameter value\n"); return -1; } if (!_s) { memset(_v, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(_v) = dummy_string.s; VAL_STR(_v) = dummy_string; VAL_BLOB(_v) = dummy_string; VAL_TYPE(_v) = _t; VAL_NULL(_v) = 1; return 0; } VAL_NULL(_v) = 0; switch(_t) { case DB_INT: LM_DBG("converting INT [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("error while converting integer value from string\n"); return -2; } else { VAL_TYPE(_v) = DB_INT; return 0; } break; case DB_BIGINT: LM_DBG("converting INT BIG[%s]\n", _s); if (db_str2bigint(_s, &VAL_BIGINT(_v)) < 0) { LM_ERR("error while converting big integer value from string\n"); return -2; } else { VAL_TYPE(_v) = DB_BIGINT; return 0; } break; case DB_BITMAP: LM_DBG("converting BITMAP [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("error while converting bitmap value from string\n"); return -3; } else { VAL_TYPE(_v) = DB_BITMAP; return 0; } break; case DB_DOUBLE: LM_DBG("converting DOUBLE [%s]\n", _s); if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { LM_ERR("error while converting double value from string\n"); return -4; } else { VAL_TYPE(_v) = DB_DOUBLE; return 0; } break; case DB_STRING: LM_DBG("converting STRING [%s]\n", _s); VAL_STRING(_v) = _s; VAL_TYPE(_v) = DB_STRING; return 0; case DB_STR: LM_DBG("converting STR [%.*s]\n", _l, _s); VAL_STR(_v).s = (char*)_s; VAL_STR(_v).len = _l; VAL_TYPE(_v) = DB_STR; return 0; case DB_DATETIME: LM_DBG("converting DATETIME [%s]\n", _s); if (db_str2time(_s, &VAL_TIME(_v)) < 0) { LM_ERR("error while converting datetime value from string\n"); return -5; } else { VAL_TYPE(_v) = DB_DATETIME; return 0; } break; case DB_BLOB: LM_DBG("converting BLOB [%.*s]\n", _l, _s); VAL_BLOB(_v).s = (char*)_s; VAL_BLOB(_v).len = _l; VAL_TYPE(_v) = DB_BLOB; return 0; } return -6; }
/* * Used when converting result from a query */ int km_bdb_val2str(db_val_t* _v, char* _s, int* _len) { int l; if (VAL_NULL(_v)) { *_len = snprintf(_s, *_len, "NULL"); return 0; } switch(VAL_TYPE(_v)) { case DB1_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { LM_ERR("Error while converting int to string\n"); return -2; } else { LM_DBG("Converted int to string\n"); return 0; } break; case DB1_BITMAP: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { LM_ERR("Error while converting bitmap to string\n"); return -3; } else { LM_DBG("Converted bitmap to string\n"); return 0; } break; case DB1_DOUBLE: if (db_double2str(VAL_DOUBLE(_v), _s, _len) < 0) { LM_ERR("Error while converting double to string\n"); return -3; } else { LM_DBG("Converted double to string\n"); return 0; } break; case DB1_STRING: l = strlen(VAL_STRING(_v)); if (*_len < l ) { LM_ERR("Destination buffer too short for string\n"); return -4; } else { LM_DBG("Converted string to string\n"); strncpy(_s, VAL_STRING(_v) , l); _s[l] = 0; *_len = l; return 0; } break; case DB1_STR: l = VAL_STR(_v).len; if (*_len < l) { LM_ERR("Destination buffer too short for str\n"); return -5; } else { LM_DBG("Converted str to string\n"); strncpy(_s, VAL_STR(_v).s , VAL_STR(_v).len); *_len = VAL_STR(_v).len; return 0; } break; case DB1_DATETIME: if (km_bdb_time2str(VAL_TIME(_v), _s, _len) < 0) { LM_ERR("Error while converting time_t to string\n"); return -6; } else { LM_DBG("Converted time_t to string\n"); return 0; } break; case DB1_BLOB: l = VAL_BLOB(_v).len; if (*_len < l) { LM_ERR("Destination buffer too short for blob\n"); return -7; } else { LM_DBG("Converting BLOB [%s]\n", _s); _s = VAL_BLOB(_v).s; *_len = 0; return -8; } break; default: LM_DBG("Unknown data type\n"); return -8; } }
/* * Used when converting result from a query */ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v, char* _s, int* _len) { int l, ret; int pgret; char *tmp_s; size_t tmp_len; char* old_s; if ((!_v) || (!_s) || (!_len) || (!*_len)) { LM_ERR("invalid parameter value\n"); return -1; } if (VAL_NULL(_v)) { if ( *_len < (l=(int)sizeof("NULL")-1)) { LM_ERR("buffer too short to print NULL\n"); return -1; } memcpy(_s, "NULL", l); *_len = l; return 0; } switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { LM_ERR("failed to convert string to int\n"); return -2; } else { return 0; } break; case DB_BIGINT: if (db_bigint2str(VAL_BIGINT(_v), _s, _len) < 0) { LM_ERR("failed to convert string to big int\n"); return -2; } else { return 0; } break; case DB_BITMAP: if (db_int2str(VAL_BITMAP(_v), _s, _len) < 0) { LM_ERR("failed to convert string to int\n"); return -3; } else { return 0; } break; case DB_DOUBLE: if (db_double2str(VAL_DOUBLE(_v), _s, _len) < 0) { LM_ERR("failed to convert string to double\n"); return -3; } else { return 0; } break; case DB_STRING: l = strlen(VAL_STRING(_v)); if (*_len < (l * 2 + 3)) { LM_ERR("destination STRING buffer too short (have %d, need %d)\n", *_len, l * 2 + 3); return -4; } else { old_s = _s; *_s++ = '\''; ret = PQescapeStringConn(CON_CONNECTION(_con), _s, VAL_STRING(_v), l, &pgret); if(pgret!=0) { LM_ERR("PQescapeStringConn failed\n"); return -4; } LM_DBG("PQescapeStringConn: in: %d chars," " out: %d chars\n", l, ret); _s += ret; *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB_STR: l = VAL_STR(_v).len; if (*_len < (l * 2 + 3)) { LM_ERR("destination STR buffer too short (have %d, need %d)\n", *_len, l * 2 + 3); return -5; } else { old_s = _s; *_s++ = '\''; ret = PQescapeStringConn(CON_CONNECTION(_con), _s, VAL_STRING(_v), l, &pgret); if(pgret!=0) { LM_ERR("PQescapeStringConn failed \n"); return -5; } LM_DBG("PQescapeStringConn: in: %d chars, out: %d chars\n", l, ret); _s += ret; *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB_DATETIME: if (db_time2str(VAL_TIME(_v), _s, _len) < 0) { LM_ERR("failed to convert string to time_t\n"); return -6; } else { return 0; } break; case DB_BLOB: l = VAL_BLOB(_v).len; /* this estimation is not always correct, thus we need to check later again */ if (*_len < (l * 2 + 3)) { LM_ERR("destination BLOB buffer too short (have %d, need %d)\n", *_len, l * 2 + 3); return -7; } else { *_s++ = '\''; tmp_s = (char*)PQescapeByteaConn(CON_CONNECTION(_con), (unsigned char*)VAL_STRING(_v), (size_t)l, (size_t*)&tmp_len); if(tmp_s==NULL) { LM_ERR("PQescapeBytea failed\n"); return -7; } if (tmp_len > *_len) { LM_ERR("escaped result too long\n"); return -7; } memcpy(_s, tmp_s, tmp_len); PQfreemem(tmp_s); tmp_len = strlen(_s); *(_s + tmp_len) = '\''; *(_s + tmp_len + 1) = '\0'; *_len = tmp_len + 2; return 0; } break; default: LM_DBG("unknown data type\n"); return -7; } }
/* * Release memory used by row */ inline int db_free_row(db_row_t* _r) { int col; db_val_t* _val; if (!_r) { LM_ERR("invalid parameter value\n"); return -1; } /* * Loop thru each columm, then check to determine if the storage pointed to * by db_val_t structure must be freed. This is required for all data types * which use a pointer to a buffer like DB1_STRING, DB1_STR and DB1_BLOB and * the database module copied them during the assignment. * If this is not done, a memory leak will happen. * Don't try to free the static dummy string (as indicated from the NULL value), * as this is not valid. */ for (col = 0; col < ROW_N(_r); col++) { _val = &(ROW_VALUES(_r)[col]); switch (VAL_TYPE(_val)) { case DB1_STRING: if ( (!VAL_NULL(_val)) && VAL_FREE(_val)) { LM_DBG("free VAL_STRING[%d] '%s' at %p\n", col, (char *)VAL_STRING(_val), (char *)VAL_STRING(_val)); pkg_free((char *)VAL_STRING(_val)); VAL_STRING(_val) = NULL; } break; case DB1_STR: if ( (!VAL_NULL(_val)) && VAL_FREE(_val)) { LM_DBG("free VAL_STR[%d] '%.*s' at %p\n", col, VAL_STR(_val).len, VAL_STR(_val).s, VAL_STR(_val).s); pkg_free(VAL_STR(_val).s); VAL_STR(_val).s = NULL; } break; case DB1_BLOB: if ( (!VAL_NULL(_val)) && VAL_FREE(_val)) { LM_DBG("free VAL_BLOB[%d] at %p\n", col, VAL_BLOB(_val).s); pkg_free(VAL_BLOB(_val).s); VAL_BLOB(_val).s = NULL; } break; default: break; } } /* now as we freed all, set number of colums to zero again */ ROW_N(_r) = 0; if (ROW_VALUES(_r)) { LM_DBG("freeing row values at %p\n", ROW_VALUES(_r)); pkg_free(ROW_VALUES(_r)); ROW_VALUES(_r) = NULL; } return 0; }
/* * Used when converting a result from the query */ int db_unixodbc_val2str(const db1_con_t* _c, const db_val_t* _v, char* _s, int* _len) { int l, tmp; char* old_s; /* db_unixodbc uses a custom escape function */ tmp = db_val2str(_c, _v, _s, _len); if (tmp < 1) return tmp; switch(VAL_TYPE(_v)) { case DB1_STRING: l = strlen(VAL_STRING(_v)); if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -6; } else { old_s = _s; *_s++ = '\''; if(use_escape_common) { _s += escape_common(_s, (char*)VAL_STRING(_v), l); } else { memcpy(_s, VAL_STRING(_v), l); _s += l; } *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB1_STR: l = VAL_STR(_v).len; if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -7; } else { old_s = _s; *_s++ = '\''; if(use_escape_common) { _s += escape_common(_s, VAL_STR(_v).s, l); } else { memcpy(_s, VAL_STR(_v).s, l); _s += l; } *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB1_BLOB: l = VAL_BLOB(_v).len; if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -9; } else { old_s = _s; *_s++ = '\''; if(use_escape_common) { _s += escape_common(_s, VAL_BLOB(_v).s, l); } else { memcpy(_s, VAL_BLOB(_v).s, l); _s += l; } *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; default: LM_DBG("unknown data type\n"); return -10; } }
/*! * \brief Convert rows from mongodb to db API representation * \param _h database connection * \param _r database result set * \return 0 on success, negative on failure */ static int db_mongodb_convert_bson(const db1_con_t* _h, db1_res_t* _r, int _row, const bson_t *_rdoc) { static str dummy_string = {"", 0}; int col; db_mongodb_result_t *mgres; const char *colname; bson_type_t coltype; bson_iter_t riter; bson_iter_t citer; bson_iter_t *piter; db_val_t* dval; uint32_t i32tmp; bson_subtype_t subtype; bson_t *cdoc; mgres = (db_mongodb_result_t*)RES_PTR(_r); if(mgres->nrcols==0) { LM_ERR("no fields to convert\n"); return -1; } if(mgres->colsdoc==NULL) { cdoc = (bson_t*)_rdoc; } else { cdoc = (bson_t*)mgres->colsdoc; } if (!bson_iter_init (&citer, cdoc)) { LM_ERR("failed to initialize columns iterator\n"); return -3; } if(mgres->colsdoc) { if (!bson_iter_init (&riter, _rdoc)) { LM_ERR("failed to initialize result iterator\n"); return -3; } } if (db_allocate_row(_r, &(RES_ROWS(_r)[_row])) != 0) { LM_ERR("could not allocate row: %d\n", _row); return -2; } col = 0; while (bson_iter_next (&citer)) { if(col >= RES_COL_N(_r)) { LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r)); return -4; } colname = bson_iter_key (&citer); LM_DBG("looking for field[%d] named: %s\n", col, colname); if(mgres->colsdoc) { if(!bson_iter_find(&riter, colname)) { LM_ERR("field [%s] not found in result iterator\n", colname); return -4; } piter = &riter; } else { piter = &citer; } coltype = bson_iter_type(piter); dval = &(ROW_VALUES(&(RES_ROWS(_r)[_row]))[col]); VAL_TYPE(dval) = RES_TYPES(_r)[col]; switch(coltype) { case BSON_TYPE_BOOL: VAL_INT(dval) = (int)bson_iter_bool (piter); break; case BSON_TYPE_INT32: VAL_INT(dval) = bson_iter_int32 (piter); break; case BSON_TYPE_TIMESTAMP: bson_iter_timestamp (piter, (uint32_t*)&VAL_INT(dval), &i32tmp); break; case BSON_TYPE_INT64: VAL_BIGINT(dval) = bson_iter_int64 (piter); break; case BSON_TYPE_DOUBLE: VAL_DOUBLE(dval) = bson_iter_double (piter); break; case BSON_TYPE_DATE_TIME: VAL_TIME(dval) = (time_t)(bson_iter_date_time (piter)/1000); break; case BSON_TYPE_BINARY: bson_iter_binary (piter, &subtype, (uint32_t*)&VAL_BLOB(dval).len, (const uint8_t**)&VAL_BLOB(dval).s); break; case BSON_TYPE_UTF8: VAL_STRING(dval) = (char*)bson_iter_utf8 (piter, &i32tmp); break; case BSON_TYPE_OID: break; case BSON_TYPE_NULL: memset(dval, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(dval) = dummy_string.s; VAL_STR(dval) = dummy_string; VAL_BLOB(dval) = dummy_string; VAL_TYPE(dval) = RES_TYPES(_r)[col]; VAL_NULL(dval) = 1; break; #if 0 case BSON_TYPE_EOD: case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: case BSON_TYPE_UNDEFINED: case BSON_TYPE_REGEX: case BSON_TYPE_DBPOINTER: case BSON_TYPE_CODE: case BSON_TYPE_SYMBOL: case BSON_TYPE_CODEWSCOPE: case BSON_TYPE_MAXKEY: case BSON_TYPE_MINKEY: #endif default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype); RES_TYPES(_r)[col] = DB1_STRING; break; } LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype); col++; } return 0; }
/* * Add key-op-value to a bson filter document */ int db_mongodb_bson_filter_add(bson_t *doc, const db_key_t* _k, const db_op_t* _op, const db_val_t* _v, int idx) { bson_t mdoc; db_key_t tkey; const db_val_t *tval; int vtype; str ocmp; tkey = _k[idx]; tval = _v + idx; vtype = VAL_TYPE(tval); /* OP_EQ is handled separately */ if(!strcmp(_op[idx], OP_LT)) { ocmp.s = "$lt"; ocmp.len = 3; } else if(!strcmp(_op[idx], OP_LEQ)) { ocmp.s = "$lte"; ocmp.len = 4; } else if(!strcmp(_op[idx], OP_GT)) { ocmp.s = "$gt"; ocmp.len = 3; } else if(!strcmp(_op[idx], OP_GEQ)) { ocmp.s = "$gte"; ocmp.len = 4; } else if(!strcmp(_op[idx], OP_NEQ) || !strcmp(_op[idx], "!=")) { ocmp.s = "$ne"; ocmp.len = 3; } else { LM_ERR("unsuported match operator: %s\n", _op[idx]); goto error; } if(!bson_append_document_begin(doc, tkey->s, tkey->len, &mdoc)) { LM_ERR("failed to append start to bson doc %.*s %s ... [%d]\n", tkey->len, tkey->s, ocmp.s, idx); goto error; } if(VAL_NULL(tval)) { if(!bson_append_null(&mdoc, ocmp.s, ocmp.len)) { LM_ERR("failed to append null to bson doc %.*s %s null [%d]\n", tkey->len, tkey->s, ocmp.s, idx); goto error; } goto done; } switch(vtype) { case DB1_INT: if(!bson_append_int32(&mdoc, ocmp.s, ocmp.len, VAL_INT(tval))) { LM_ERR("failed to append int to bson doc %.*s %s %d [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_INT(tval), idx); goto error; } break; case DB1_BIGINT: if(!bson_append_int64(&mdoc, ocmp.s, ocmp.len, VAL_BIGINT(tval ))) { LM_ERR("failed to append bigint to bson doc %.*s %s %lld [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_BIGINT(tval), idx); goto error; } return -1; case DB1_DOUBLE: if(!bson_append_double(&mdoc, ocmp.s, ocmp.len, VAL_DOUBLE(tval))) { LM_ERR("failed to append double to bson doc %.*s %s %f [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_DOUBLE(tval), idx); goto error; } break; case DB1_STRING: if(!bson_append_utf8(&mdoc, ocmp.s, ocmp.len, VAL_STRING(tval), strlen(VAL_STRING(tval))) ) { LM_ERR("failed to append string to bson doc %.*s %s %s [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_STRING(tval), idx); goto error; } break; case DB1_STR: if(!bson_append_utf8(&mdoc, ocmp.s, ocmp.len, VAL_STR(tval).s, VAL_STR(tval).len) ) { LM_ERR("failed to append str to bson doc %.*s %s %.*s [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_STR(tval).len, VAL_STR(tval).s, idx); goto error; } break; case DB1_DATETIME: if(!bson_append_time_t(&mdoc, ocmp.s, ocmp.len, VAL_TIME(tval))) { LM_ERR("failed to append time to bson doc %.*s %s %ld [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_TIME(tval), idx); goto error; } break; case DB1_BLOB: if(!bson_append_binary(&mdoc, ocmp.s, ocmp.len, BSON_SUBTYPE_BINARY, (const uint8_t *)VAL_BLOB(tval).s, VAL_BLOB(tval).len) ) { LM_ERR("failed to append blob to bson doc %.*s %s [bin] [%d]\n", tkey->len, tkey->s, ocmp.s, idx); goto error; } break; case DB1_BITMAP: if(!bson_append_int32(&mdoc, ocmp.s, ocmp.len, VAL_INT(tval))) { LM_ERR("failed to append bitmap to bson doc %.*s %s %d [%d]\n", tkey->len, tkey->s, ocmp.s, VAL_INT(tval), idx); goto error; } break; default: LM_ERR("val type [%d] not supported\n", vtype); goto error; } done: if(!bson_append_document_end(doc, &mdoc)) { LM_ERR("failed to append end to bson doc %.*s %s ... [%d]\n", tkey->len, tkey->s, ocmp.s, idx); goto error; } return 0; error: return -1; }
/* * Add key-value to a bson document */ int db_mongodb_bson_add(bson_t *doc, const db_key_t _k, const db_val_t *_v, int idx) { int vtype; vtype = VAL_TYPE(_v); if(VAL_NULL(_v)) { if(!bson_append_null(doc, _k->s, _k->len)) { LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n", _k->len, _k->s, VAL_INT(_v), idx); goto error; } goto done; } switch(vtype) { case DB1_INT: if(!bson_append_int32(doc, _k->s, _k->len, VAL_INT(_v))) { LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n", _k->len, _k->s, VAL_INT(_v), idx); goto error; } break; case DB1_BIGINT: if(!bson_append_int64(doc, _k->s, _k->len, VAL_BIGINT(_v ))) { LM_ERR("failed to append bigint to bson doc %.*s = %lld [%d]\n", _k->len, _k->s, VAL_BIGINT(_v), idx); goto error; } return -1; case DB1_DOUBLE: if(!bson_append_double(doc, _k->s, _k->len, VAL_DOUBLE(_v))) { LM_ERR("failed to append double to bson doc %.*s = %f [%d]\n", _k->len, _k->s, VAL_DOUBLE(_v), idx); goto error; } break; case DB1_STRING: if(!bson_append_utf8(doc, _k->s, _k->len, VAL_STRING(_v), strlen(VAL_STRING(_v))) ) { LM_ERR("failed to append string to bson doc %.*s = %s [%d]\n", _k->len, _k->s, VAL_STRING(_v), idx); goto error; } break; case DB1_STR: if(!bson_append_utf8(doc, _k->s, _k->len, VAL_STR(_v).s, VAL_STR(_v).len) ) { LM_ERR("failed to append str to bson doc %.*s = %.*s [%d]\n", _k->len, _k->s, VAL_STR(_v).len, VAL_STR(_v).s, idx); goto error; } break; case DB1_DATETIME: if(!bson_append_time_t(doc, _k->s, _k->len, VAL_TIME(_v))) { LM_ERR("failed to append time to bson doc %.*s = %ld [%d]\n", _k->len, _k->s, VAL_TIME(_v), idx); goto error; } break; case DB1_BLOB: if(!bson_append_binary(doc, _k->s, _k->len, BSON_SUBTYPE_BINARY, (const uint8_t *)VAL_BLOB(_v).s, VAL_BLOB(_v).len) ) { LM_ERR("failed to append blob to bson doc %.*s = [bin] [%d]\n", _k->len, _k->s, idx); goto error; } break; case DB1_BITMAP: if(!bson_append_int32(doc, _k->s, _k->len, VAL_INT(_v))) { LM_ERR("failed to append bitmap to bson doc %.*s = %d [%d]\n", _k->len, _k->s, VAL_INT(_v), idx); goto error; } break; default: LM_ERR("val type [%d] not supported\n", vtype); return -1; } done: return 0; error: return -1; }
/* * Convert data fron db format to internal format */ static int convert_row(db_res_t* _res, db_row_t* _r, dmap_t* _d) { unsigned i, n = RES_COL_N(_res); ROW_N(_r) = n; for (i = 0; i < n; i++) { static const str dummy_string = {"", 0}; db_val_t* v = &ROW_VALUES(_r)[i]; db_type_t t = RES_TYPES(_res)[i]; if (_d->ind[i] == -1) { /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(v) = dummy_string.s; VAL_STR(v) = dummy_string; VAL_BLOB(v) = dummy_string; VAL_TYPE(v) = t; VAL_NULL(v) = 1; continue; } if (_d->ind[i]) LM_WARN("truncated value in DB\n"); VAL_TYPE(v) = t; switch (t) { case DB_INT: VAL_INT(v) = *_d->pv[i].i; break; case DB_BIGINT: VAL_BIGINT(v) = *_d->pv[i].i; break; case DB_BITMAP: VAL_BITMAP(v) = *_d->pv[i].i; break; case DB_DOUBLE: VAL_DOUBLE(v) = *_d->pv[i].f; break; case DB_DATETIME: { struct tm tm; memset(&tm, 0, sizeof(tm)); OCIDateGetTime(_d->pv[i].o, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); OCIDateGetDate(_d->pv[i].o, &tm.tm_year, &tm.tm_mon, &tm.tm_mday); if (tm.tm_mon) --tm.tm_mon; if (tm.tm_year >= 1900) tm.tm_year -= 1900; VAL_TIME(v) = mktime(&tm); } break; case DB_STR: case DB_BLOB: case DB_STRING: { size_t len = _d->len[i]; char *pstr = pkg_malloc(len+1); if (pstr == NULL) return -1; memcpy(pstr, _d->pv[i].c, len); pstr[len] = '\0'; VAL_FREE(v) = 1; if (t == DB_STR) { VAL_STR(v).s = pstr; VAL_STR(v).len = len; } else if (t == DB_BLOB) { VAL_BLOB(v).s = pstr; VAL_BLOB(v).len = len; } else { VAL_STRING(v) = pstr; } } break; default: LM_ERR("unknown type mapping (%u)\n", t); return -2; } } return 0; }
/* * Insert a row into specified table * h: structure representing database connection * k: key names * v: values of the keys * n: number of key=value pairs */ int flat_db_insert(const db_con_t* h, const db_key_t* k, const db_val_t* v, const int n) { FILE* f; int i; int auxl; str aux; char * begin = flat_iov_buf.s; if (local_timestamp < *flat_rotate) { flat_rotate_logs(); local_timestamp = *flat_rotate; } if ( !h || !CON_TAIL(h) || (f=CON_FILE(h))==NULL ) { LM_ERR("uninitialized connection\n"); return -1; } if (flat_prepare_iovec(n) < 0) { LM_ERR("cannot insert row\n"); return -1; } FLAT_LOCK(f); for(i = 0; i < n; i++) { if (VAL_NULL(v + i)) { FLAT_SET_STR(i, ""); FLAT_SET_LEN(i, 0); continue; } FLAT_SET_STR(i, FLAT_BUF); switch(VAL_TYPE(v + i)) { case DB_INT: /* guess this is 20 */ FLAT_ALLOC(20); FLAT_PRINTF("%d", VAL_INT(v+i), i); break; case DB_DOUBLE: /* guess there are max 20 digits */ FLAT_ALLOC(40); FLAT_PRINTF("%f", VAL_DOUBLE(v+i), i); break; case DB_BIGINT: /* guess there are max 20 digits */ FLAT_ALLOC(40); FLAT_PRINTF("%llu", VAL_BIGINT(v+i), i); break; case DB_STRING: auxl = strlen(VAL_STRING(v + i)); FLAT_ALLOC(auxl * 4); FLAT_COPY(i, VAL_STRING(v + i), auxl); break; case DB_STR: FLAT_ALLOC(VAL_STR(v + i).len * 4); FLAT_COPY(i, VAL_STR(v + i).s, VAL_STR(v + i).len); break; case DB_DATETIME: /* guess this is 20 */ FLAT_ALLOC(20); FLAT_PRINTF("%lu", VAL_TIME(v+i), i); break; case DB_BLOB: auxl = VAL_BLOB(v+i).len; /* the maximum size is 4l - if all chars were not printable */ FLAT_ALLOC(4 * auxl); FLAT_COPY(i, VAL_BLOB(v+i).s, auxl); break; case DB_BITMAP: /* guess this is 20 */ FLAT_ALLOC(20); FLAT_PRINTF("%u", VAL_BITMAP(v+i), i); break; } } /* reorder pointers in case they were altered by (re)allocation */ if (flat_iov_buf.s != begin && flat_iov_buf.len) { FLAT_RESET(); for (i = 0; i < n; i++) { if (!VAL_NULL(v + i)) { FLAT_SET_STR(i, FLAT_BUF); FLAT_INC(FLAT_GET_LEN(i)); } } } do { auxl = writev(fileno(f), flat_iov, 2 * n); } while (auxl < 0 && errno == EINTR); if (auxl < 0) { LM_ERR("unable to write to file: %s - %d\n", strerror(errno), errno); return -1; } /* XXX does this make sense any more? */ if (flat_flush && fflush(f) < 0) { LM_ERR("cannot flush buffer: %s - %d\n", strerror(errno), errno); } FLAT_UNLOCK(f); return 0; }
/* safely adds a new row to the insert list * also checks if the queue is full and returns all the rows that need to * be flushed to DB to the caller * * returns the number of rows detached * * Important : it is the caller's job to shm_free the rows * after flushing to DB * */ int ql_row_add(query_list_t *entry,const db_val_t *row,db_val_t ***ins_rows) { int val_size,i,len,no_rows = 0; char *pos; db_val_t *shm_row; val_size = entry->col_no * sizeof(db_val_t); for (i=0;i<entry->col_no;i++) { if (VAL_TYPE(row+i) == DB_STR && VAL_NULL(row+i) == 0) { val_size += VAL_STR(row+i).len; continue; } if (VAL_TYPE(row+i) == DB_STRING && VAL_NULL(row+i) == 0) { val_size += strlen(VAL_STRING(row+i))+1; continue; } if (VAL_TYPE(row+i) == DB_BLOB && VAL_NULL(row+i) == 0) val_size += VAL_BLOB(row+i).len; } shm_row = shm_malloc(val_size); if (shm_row == NULL) { LM_ERR("no more shm\n"); return -1; } LM_DBG("adding row to table [%.*s] & entry %p\n",entry->table.len,entry->table.s,entry); /* save row info to shm */ pos = (char *)(shm_row + entry->col_no); memcpy(shm_row,row,entry->col_no * sizeof(db_val_t)); for (i=0;i<entry->col_no;i++) { if (VAL_TYPE(row+i) == DB_STR && VAL_NULL(row+i) == 0) { len = VAL_STR(row+i).len; VAL_STR(shm_row+i).len = len; VAL_STR(shm_row+i).s = pos; memcpy(VAL_STR(shm_row+i).s,VAL_STR(row+i).s,len); pos += len; continue; } if (VAL_TYPE(row+i) == DB_STRING && VAL_NULL(row+i) == 0) { len = strlen(VAL_STRING(row+i)) + 1; VAL_STRING(shm_row+i) = pos; memcpy((void *)VAL_STRING(shm_row+i),VAL_STRING(row+i),len); pos += len; continue; } if (VAL_TYPE(row+i) == DB_BLOB && VAL_NULL(row+i) == 0) { len = VAL_BLOB(row+i).len; VAL_BLOB(shm_row+i).len = len; VAL_BLOB(shm_row+i).s = pos; memcpy(VAL_BLOB(shm_row+i).s,VAL_BLOB(row+i).s,len); pos += len; } } LM_DBG("before locking query entry\n"); lock_get(entry->lock); /* store oldest query for timer to know */ if (entry->no_rows == 0) entry->oldest_query = time(0); entry->rows[entry->no_rows++] = shm_row; LM_DBG("query for table [%.*s] has %d rows\n",entry->table.len,entry->table.s,entry->no_rows); /* is it time to flush to DB ? */ if (entry->no_rows == query_buffer_size) { if ((no_rows = ql_detach_rows_unsafe(entry,ins_rows)) < 0) { LM_ERR("failed to detach rows for insertion\n"); lock_release(entry->lock); return -1; } } lock_release(entry->lock); return no_rows; }
/* * Used when converting values to be used in a DB query */ int db_sqlite_val2str(const db_con_t* _c, const db_val_t* _v, char* _s, int* _len) { int l; if (!_c || !_v || !_s || !_len || !*_len) { LM_ERR("invalid parameter value\n"); return -1; } if (VAL_NULL(_v)) { if (*_len < sizeof("NULL")) { LM_ERR("buffer too small\n"); return -1; } *_len = snprintf(_s, *_len, "NULL"); return 0; } switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { LM_ERR("error while converting string to int\n"); return -2; } else { return 0; } break; case DB_BIGINT: if (db_bigint2str(VAL_BIGINT(_v), _s, _len) < 0) { LM_ERR("error while converting bigint to string\n"); return -2; } else { return 0; } break; case DB_BITMAP: if (db_int2str(VAL_BITMAP(_v), _s, _len) < 0) { LM_ERR("error while converting string to int\n"); return -3; } else { return 0; } break; case DB_DOUBLE: if (db_double2str(VAL_DOUBLE(_v), _s, _len) < 0) { LM_ERR("error while converting string to double\n"); return -4; } else { return 0; } break; case DB_STRING: /* TODO check escpaing */ l = strlen(VAL_STRING(_v)); if (*_len < l ) { LM_ERR("Destination buffer too short for string\n"); return -4; } else { LM_DBG("Converted string to string\n"); strncpy(_s, VAL_STRING(_v) , l); _s[l] = 0; *_len = l+1; /* count the 0 also */ return 0; } break; case DB_STR: /* TODO check escpaing */ l = VAL_STR(_v).len; if (*_len < l) { LM_ERR("Destination buffer too short for str\n"); return -5; } else { LM_DBG("Converted str to string\n"); strncpy(_s, VAL_STR(_v).s , l); *_len = l; return 0; } break; break; case DB_DATETIME: if (db_time2str(VAL_TIME(_v), _s, _len) < 0) { LM_ERR("error while converting string to time_t\n"); return -7; } else { return 0; } break; case DB_BLOB: /* TODO check escpaing */ l = VAL_BLOB(_v).len; if (*_len < l) { LM_ERR("Destination buffer too short for blob\n"); return -7; } else { strncpy(_s, VAL_BLOB(_v).s , l); LM_DBG("Converting BLOB [%.*s]\n", l,_s); *_len = l; return 0; } break; default: LM_DBG("unknown data type\n"); return -9; } }
/*! * \brief Converting a value to a string * * Converting a value to a string, used when converting result from a query * \param _con database connection * \param _v source value * \param _s target string * \param _len target string length * \return 0 on success, negative on error */ int db_postgres_val2str( const db1_con_t *_con, const db_val_t *_v, char *_s, int *_len) { int l, ret, tmp; int pgret; char *tmp_s; size_t tmp_len; char *old_s; tmp = db_val2str(_con, _v, _s, _len); if(tmp < 1) return tmp; switch(VAL_TYPE(_v)) { case DB1_STRING: l = strlen(VAL_STRING(_v)); if(*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short for string\n"); return -6; } else { old_s = _s; *_s++ = '\''; ret = PQescapeStringConn( CON_CONNECTION(_con), _s, VAL_STRING(_v), l, &pgret); if(pgret != 0) { LM_ERR("PQescapeStringConn failed\n"); return -6; } LM_DBG("PQescapeStringConn: in: %d chars," " out: %d chars\n", l, ret); _s += ret; *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB1_STR: l = VAL_STR(_v).len; if(*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short for str\n"); return -7; } else { old_s = _s; *_s++ = '\''; ret = PQescapeStringConn( CON_CONNECTION(_con), _s, VAL_STRING(_v), l, &pgret); if(pgret != 0) { LM_ERR("PQescapeStringConn failed \n"); return -7; } LM_DBG("PQescapeStringConn: in: %d chars, out: %d chars\n", l, ret); _s += ret; *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB1_BLOB: l = VAL_BLOB(_v).len; /* this estimation is not always correct, thus we need to check later again */ if(*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short for blob\n"); return -9; } else { *_s++ = '\''; tmp_s = (char *)PQescapeByteaConn(CON_CONNECTION(_con), (unsigned char *)VAL_STRING(_v), (size_t)l, (size_t *)&tmp_len); if(tmp_s == NULL) { LM_ERR("PQescapeByteaConn failed\n"); return -9; } if(tmp_len > *_len) { LM_ERR("escaped result too long\n"); return -9; } memcpy(_s, tmp_s, tmp_len); PQfreemem(tmp_s); tmp_len = strlen(_s); *(_s + tmp_len) = '\''; *(_s + tmp_len + 1) = '\0'; *_len = tmp_len + 2; return 0; } break; default: LM_ERR("unknown data type\n"); return -10; } }
/* * Used when converting values to be used in a DB query */ int db_mysql_val2str(const db_con_t* _c, const db_val_t* _v, char* _s, int* _len) { int l; char* old_s; if (!_c || !_v || !_s || !_len || !*_len) { LM_ERR("invalid parameter value\n"); return -1; } if (VAL_NULL(_v)) { if (*_len < sizeof("NULL")) { LM_ERR("buffer too small\n"); return -1; } *_len = snprintf(_s, *_len, "NULL"); return 0; } switch(VAL_TYPE(_v)) { case DB_INT: if (db_int2str(VAL_INT(_v), _s, _len) < 0) { LM_ERR("error while converting string to int\n"); return -2; } else { return 0; } break; case DB_BIGINT: if (db_bigint2str(VAL_BIGINT(_v), _s, _len) < 0) { LM_ERR("error while converting bigint to string\n"); return -2; } else { return 0; } break; case DB_BITMAP: if (db_int2str(VAL_BITMAP(_v), _s, _len) < 0) { LM_ERR("error while converting string to int\n"); return -3; } else { return 0; } break; case DB_DOUBLE: if (db_double2str(VAL_DOUBLE(_v), _s, _len) < 0) { LM_ERR("error while converting string to double\n"); return -4; } else { return 0; } break; case DB_STRING: l = strlen(VAL_STRING(_v)); if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -5; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STRING(_v), l); *_s++ = '\''; *_s = '\0'; /* FIXME */ *_len = _s - old_s; return 0; } break; case DB_STR: if (*_len < (VAL_STR(_v).len * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -6; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STR(_v).s, VAL_STR(_v).len); *_s++ = '\''; *_s = '\0'; *_len = _s - old_s; return 0; } break; case DB_DATETIME: if (db_time2str(VAL_TIME(_v), _s, _len) < 0) { LM_ERR("error while converting string to time_t\n"); return -7; } else { return 0; } break; case DB_BLOB: l = VAL_BLOB(_v).len; if (*_len < (l * 2 + 3)) { LM_ERR("destination buffer too short\n"); return -8; } else { old_s = _s; *_s++ = '\''; _s += mysql_real_escape_string(CON_CONNECTION(_c), _s, VAL_STR(_v).s, l); *_s++ = '\''; *_s = '\0'; *_len = _s - old_s; return 0; } break; default: LM_DBG("unknown data type\n"); return -9; } /*return -8; --not reached*/ }
/** * Does not copy strings */ int bdb_str2val(db_type_t _t, db_val_t* _v, char* _s, int _l) { static str dummy_string = {"", 0}; if(!_s) { memset(_v, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STRING(_v) = dummy_string.s; VAL_STR(_v) = dummy_string; VAL_BLOB(_v) = dummy_string; VAL_TYPE(_v) = _t; VAL_NULL(_v) = 1; return 0; } VAL_NULL(_v) = 0; switch(_t) { case DB1_INT: if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("Error while converting INT value from string\n"); return -2; } else { VAL_TYPE(_v) = DB1_INT; return 0; } break; case DB1_BIGINT: LM_ERR("BIGINT not supported"); return -1; case DB1_BITMAP: if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("Error while converting BITMAP value from string\n"); return -3; } else { VAL_TYPE(_v) = DB1_BITMAP; return 0; } break; case DB1_DOUBLE: if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { LM_ERR("Error while converting DOUBLE value from string\n"); return -4; } else { VAL_TYPE(_v) = DB1_DOUBLE; return 0; } break; case DB1_STRING: VAL_STRING(_v) = _s; VAL_TYPE(_v) = DB1_STRING; VAL_FREE(_v) = 1; if( strlen(_s)==4 && !strncasecmp(_s, "NULL", 4) ) VAL_NULL(_v) = 1; return 0; case DB1_STR: VAL_STR(_v).s = (char*)_s; VAL_STR(_v).len = _l; VAL_TYPE(_v) = DB1_STR; VAL_FREE(_v) = 1; if( strlen(_s)==4 && !strncasecmp(_s, "NULL", 4) ) VAL_NULL(_v) = 1; return 0; case DB1_DATETIME: if (db_str2time(_s, &VAL_TIME(_v)) < 0) { LM_ERR("Error converting datetime\n"); return -5; } else { VAL_TYPE(_v) = DB1_DATETIME; return 0; } break; case DB1_BLOB: VAL_BLOB(_v).s = _s; VAL_TYPE(_v) = DB1_BLOB; LM_DBG("got blob len %d\n", _l); return 0; } return -6; }
int db_mysql_val2bind(const db_val_t* v, MYSQL_BIND *binds, unsigned int i) { struct tm *t; MYSQL_TIME *mt; if (VAL_NULL(v)) { *(binds[i].is_null) = 1; *(binds[i].length) = 0; binds[i].buffer= NULL; switch(VAL_TYPE(v)) { case DB_INT: binds[i].buffer_type= MYSQL_TYPE_LONG; break; case DB_BIGINT: binds[i].buffer_type= MYSQL_TYPE_LONGLONG; break; case DB_BITMAP: binds[i].buffer_type= MYSQL_TYPE_LONG; break; case DB_DOUBLE: binds[i].buffer_type= MYSQL_TYPE_DOUBLE; break; case DB_STRING: binds[i].buffer_type= MYSQL_TYPE_STRING; break; case DB_STR: binds[i].buffer_type= MYSQL_TYPE_STRING; break; case DB_DATETIME: binds[i].buffer_type= MYSQL_TYPE_DATETIME; break; case DB_BLOB: binds[i].buffer_type= MYSQL_TYPE_BLOB; break; default: LM_ERR("unknown NULL data type (%d)\n",VAL_TYPE(v)); return -10; } return 0; } else { *(binds[i].is_null) = 0; } switch(VAL_TYPE(v)) { case DB_INT: binds[i].buffer_type= MYSQL_TYPE_LONG; binds[i].buffer= (char*)&(VAL_INT(v)); *binds[i].length= sizeof(VAL_INT(v)); break; case DB_BIGINT: binds[i].buffer_type= MYSQL_TYPE_LONGLONG; binds[i].buffer= (char*)&(VAL_BIGINT(v)); *binds[i].length= sizeof(VAL_BIGINT(v)); break; case DB_BITMAP: binds[i].buffer_type= MYSQL_TYPE_LONG; binds[i].buffer= (char*)&(VAL_BITMAP(v)); *binds[i].length= sizeof(VAL_BITMAP(v)); break; case DB_DOUBLE: binds[i].buffer_type= MYSQL_TYPE_DOUBLE; binds[i].buffer= (char*)&(VAL_DOUBLE(v)); *binds[i].length= sizeof(VAL_DOUBLE(v)); break; case DB_STRING: binds[i].buffer_type= MYSQL_TYPE_STRING; binds[i].buffer= (char*)VAL_STRING(v); *binds[i].length= strlen(VAL_STRING(v)); break; case DB_STR: binds[i].buffer_type= MYSQL_TYPE_STRING; binds[i].buffer= VAL_STR(v).s; *binds[i].length= VAL_STR(v).len; break; case DB_DATETIME: binds[i].buffer_type= MYSQL_TYPE_DATETIME; t = localtime( &VAL_TIME(v) ); mt = (MYSQL_TIME*)binds[i].buffer; mt->year = 1900 + t->tm_year; mt->month = (t->tm_mon)+1; mt->day = t->tm_mday; mt->hour = t->tm_hour; mt->minute = t->tm_min; mt->second = t->tm_sec; *binds[i].length= sizeof(MYSQL_TIME); break; case DB_BLOB: binds[i].buffer_type= MYSQL_TYPE_BLOB; binds[i].buffer= VAL_BLOB(v).s; *binds[i].length= VAL_BLOB(v).len; break; default: LM_ERR("unknown data type (%d)\n",VAL_TYPE(v)); return -9; } LM_DBG("added val (%d): len=%ld; type=%d; is_null=%d\n", i, *(binds[i].length), binds[i].buffer_type, *(binds[i].is_null)); return 0; }
/* * Convert a str to a db value, does not copy strings * The postgresql module uses a custom escape function for BLOBs. * If the _s is linked in the db_val result, it will be returned zero */ int db_postgres_str2val(const db_type_t _t, db_val_t* _v, const char* _s, const int _l) { static str dummy_string = {"", 0}; char *x; if (!_v) { LM_ERR("invalid parameter value\n"); return -1; } if (!_s) { memset(_v, 0, sizeof(db_val_t)); /* Initialize the string pointers to a dummy empty * string so that we do not crash when the NULL flag * is set but the module does not check it properly */ VAL_STR(_v) = dummy_string; VAL_TYPE(_v) = _t; VAL_NULL(_v) = 1; return 0; } VAL_NULL(_v) = 0; switch(_t) { case DB_INT: LM_DBG("converting INT [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("failed to convert INT value from string\n"); return -2; } else { VAL_TYPE(_v) = DB_INT; return 0; } break; case DB_BIGINT: LM_DBG("converting BIGINT [%s]\n", _s); if (db_str2bigint(_s, &VAL_BIGINT(_v)) < 0) { LM_ERR("failed to convert BIGINT value from string\n"); return -2; } else { VAL_TYPE(_v) = DB_BIGINT; return 0; } break; case DB_BITMAP: LM_DBG("converting BITMAP [%s]\n", _s); if (db_str2int(_s, &VAL_INT(_v)) < 0) { LM_ERR("failed to convert BITMAP value from string\n"); return -3; } else { VAL_TYPE(_v) = DB_BITMAP; return 0; } break; case DB_DOUBLE: LM_DBG("converting DOUBLE [%s]\n", _s); if (db_str2double(_s, &VAL_DOUBLE(_v)) < 0) { LM_ERR("failed to convert DOUBLE value from string\n"); return -4; } else { VAL_TYPE(_v) = DB_DOUBLE; return 0; } break; case DB_STRING: LM_DBG("converting STRING [%s]\n", _s); VAL_STRING(_v) = _s; VAL_TYPE(_v) = DB_STRING; VAL_FREE(_v) = 1; return 0; case DB_STR: LM_DBG("converting STR [%.*s]\n", _l, _s); VAL_STR(_v).s = (char*)_s; VAL_STR(_v).len = _l; VAL_TYPE(_v) = DB_STR; VAL_FREE(_v) = 1; return 0; case DB_DATETIME: LM_DBG("converting DATETIME [%s]\n", _s); if (db_str2time(_s, &VAL_TIME(_v)) < 0) { LM_ERR("failed to convert datetime\n"); return -5; } else { VAL_TYPE(_v) = DB_DATETIME; return 0; } break; case DB_BLOB: LM_DBG("converting BLOB [%.*s]\n", _l, _s); /* PQunescapeBytea: Converts a string representation of binary data * into binary data - the reverse of PQescapeBytea. * This is needed when retrieving bytea data in text format, * but not when retrieving it in binary format. */ x = (char*)PQunescapeBytea((unsigned char*)_s, (size_t*)(void*)&(VAL_BLOB(_v).len) ); VAL_BLOB(_v).s = pkg_malloc( VAL_BLOB(_v).len+1 ); if (VAL_BLOB(_v).s==NULL) { LM_ERR("failed to allocate pkg for BLOB\n"); return -6; } memcpy( VAL_BLOB(_v).s, x, VAL_BLOB(_v).len); VAL_BLOB(_v).s[VAL_BLOB(_v).len]='\0'; free(x); VAL_TYPE(_v) = DB_BLOB; VAL_FREE(_v) = 1; LM_DBG("got blob len %d\n", _l); return 0; } return -6; }
/* * Insert a row into specified table * h: structure representing database connection * k: key names * v: values of the keys * n: number of key=value pairs */ int flat_db_insert(db_con_t* h, db_key_t* k, db_val_t* v, int n) { FILE* f; int i; char delims[4], *s; size_t len; f = CON_FILE(h); if (!f) { LOG(L_CRIT, "BUG: flat_db_insert: Uninitialized connection\n"); return -1; } if (local_timestamp < *flat_rotate) { flat_rotate_logs(); local_timestamp = *flat_rotate; } for(i = 0; i < n; i++) { if (!VAL_NULL(v + i)) { // TODO: how to distinguish NULL from empty switch(VAL_TYPE(v + i)) { case DB_INT: fprintf(f, "%d", VAL_INT(v + i)); break; case DB_FLOAT: fprintf(f, "%f", VAL_FLOAT(v + i)); break; case DB_DOUBLE: fprintf(f, "%f", VAL_DOUBLE(v + i)); break; case DB_STRING: { s = (char*) VAL_STRING(v + i); delims[0] = flat_delimiter[0]; delims[1] = flat_record_delimiter[0]; delims[2] = flat_escape[0]; delims[3] = '\0'; while (*s) { len = strcspn(s, delims); fprintf(f, "%.*s", (int)len, s); s+= len; if (*s) { fprintf(f, "%c%c", flat_escape[0], *s); s++; } } break; } case DB_STR: case DB_BLOB: if (VAL_TYPE(v + i) == DB_STR) { s = VAL_STR(v + i).s; len = VAL_STR(v + i).len; } else { s = VAL_BLOB(v + i).s; len = VAL_BLOB(v + i).len; } while (len > 0) { char *c; for (c = s; len > 0 && *c != flat_delimiter[0] && *c != flat_record_delimiter[0] && *c != flat_escape[0]; c++, len--); fprintf(f, "%.*s", (int)(c-s), s); s = c; if (len > 0) { fprintf(f, "%c%c", flat_escape[0], *s); s++; len--; } } break; case DB_DATETIME: fprintf(f, "%u", (unsigned int)VAL_TIME(v + i)); break; case DB_BITMAP: fprintf(f, "%u", VAL_BITMAP(v + i)); break; } } if (i < (n - 1)) { fprintf(f, "%c", flat_delimiter[0]); } } fprintf(f, "%c", flat_record_delimiter[0]); if (flat_flush) { fflush(f); } return 0; }