Beispiel #1
0
int db_do_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v,
	const int _n, int (*val2str) (const db_con_t*, const db_val_t*, char*, int*),
	int (*submit_query)(const db_con_t* _h, const str* _c))
{
	int off, ret,i,no_rows=0;
	db_val_t **buffered_rows = NULL;

	if (!_h || !_k || !_v || !_n || !val2str || !submit_query) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}
	
	/* insert buffering is enabled ? */
	if (CON_HAS_INSLIST(_h) && !CON_HAS_PS(_h))
	{
		LM_DBG("inlist %p\n",CON_HAS_INSLIST(_h));
		if (IS_INSTANT_FLUSH(_h))
		{
			LM_DBG("timer wishing to flush \n");
			/* if caller signals it's flush time ( timer, etc ), 
			 * detach rows in queue 
			 * the caller is holding the lock at this point */
			no_rows = ql_detach_rows_unsafe(_h->ins_list,&buffered_rows);
			CON_FLUSH_RESET(_h,_h->ins_list);

			if (no_rows == -1)
			{
				LM_ERR("failed to detach rows for insertion\n");
				goto error;
			}

			if (no_rows > 0)
				goto build_query;
			else
			{
				/* caller wanted to make sure that everything if flushed
				 * but queue is empty */
				return 0;
			}
		}
		
		/* if connection has prepared statement, leave
		the row insertion to the proper module func,
		as the submit_query func provided is a dummy one*/
		if ( (no_rows = ql_row_add(_h->ins_list,_v,&buffered_rows)) < 0)
		{
			LM_ERR("failed to insert row to buffered list \n");
			goto error;
		}

		LM_DBG("no rows = %d\n",no_rows);

		if (no_rows == 0)
		{
			/* wait for queries to pile up */
			return 0;
		}
	}

build_query:
	ret = snprintf(sql_buf, SQL_BUF_LEN, "insert into %.*s (", CON_TABLE(_h)->len, CON_TABLE(_h)->s);
	if (ret < 0 || ret >= SQL_BUF_LEN) goto error;
	off = ret;

	ret = db_print_columns(sql_buf + off, SQL_BUF_LEN - off, _k, _n);
	if (ret < 0) goto error;
	off += ret;

	if (CON_HAS_INSLIST(_h))
	{
		if (buffered_rows != NULL || CON_HAS_PS(_h))
		{
			/* if we have to insert now, build the query 
			 * 
			 * if a prep stmt is provided,
			 * build a prep stmt with query_buffer_size elements */

			if (CON_HAS_PS(_h))
				no_rows = query_buffer_size;

			ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, ") values");
			if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error;
			off += ret;

			for (i=0;i<no_rows;i++)
			{
				sql_buf[off++]='(';
				ret = db_print_values(_h, sql_buf + off, SQL_BUF_LEN - off,
										CON_HAS_PS(_h)?_v:buffered_rows[i], _n, val2str);
				if (ret < 0) goto error;
				off += ret;
				sql_buf[off++]=')';

				if (i != (no_rows -1))
					sql_buf[off++]=',';

				/* if we have a PS, leave the function handling prep stmts
				   in the module to free the rows once it's done */
				if (!CON_HAS_PS(_h)) {
					shm_free(buffered_rows[i]);
					buffered_rows[i] = NULL;
				}
			}

			if (off + 1 > SQL_BUF_LEN) goto error0;
			sql_buf[off] = '\0';
			sql_str.s = sql_buf;
			sql_str.len = off;

			goto submit;
		}
		else 
		{
			/* wait for queries to pile up */
			return 0;
		}
	}
	else
	{
		ret = snprintf(sql_buf + off, SQL_BUF_LEN - off, ") values (");
		if (ret < 0 || ret >= (SQL_BUF_LEN - off)) goto error0;
		off += ret;

		ret = db_print_values(_h, sql_buf + off, SQL_BUF_LEN - off, _v, _n, val2str);
		if (ret < 0) goto error0;
		off += ret;

		if (off + 2 > SQL_BUF_LEN) goto error0;
	}

	sql_buf[off++] = ')';
	sql_buf[off] = '\0';
	sql_str.s = sql_buf;
	sql_str.len = off;

submit:
	if (submit_query(_h, &sql_str) < 0) {
	        LM_ERR("error while submitting query\n");
		return -2;
	}
	return 0;

error:
	cleanup_rows(buffered_rows);
error0:
	LM_ERR("error while preparing insert operation\n");
	return -1;
}
Beispiel #2
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;
}