mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
427 lines
11 KiB
427 lines
11 KiB
/*
|
|
* $Id$
|
|
*
|
|
* PostgreSQL Database Driver for SER
|
|
*
|
|
* Portions Copyright (C) 2001-2003 FhG FOKUS
|
|
* Copyright (C) 2003 August.Net Services, LLC
|
|
* Portions Copyright (C) 2005-2008 iptelorg GmbH
|
|
*
|
|
* This file is part of SER, a free SIP server.
|
|
*
|
|
* SER is free software; you can redistribute it and/or modify it under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option) any later
|
|
* version
|
|
*
|
|
* For a license to use the ser software under conditions other than those
|
|
* described here, or to purchase support for this software, please contact
|
|
* iptel.org by e-mail at the following addresses: info@iptel.org
|
|
*
|
|
* SER is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/** \addtogroup postgres
|
|
* @{
|
|
*/
|
|
|
|
/** \file
|
|
* Implementation of various functions that assemble SQL query strings for
|
|
* PostgreSQL.
|
|
*/
|
|
|
|
#include "pg_sql.h"
|
|
|
|
#include "../../lib/srdb2/db_cmd.h"
|
|
#include "../../lib/srdb2/db_fld.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../dprint.h"
|
|
#include "../../ut.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
enum {
|
|
STR_DELETE,
|
|
STR_INSERT,
|
|
STR_UPDATE,
|
|
STR_SELECT,
|
|
STR_REPLACE,
|
|
STR_SET,
|
|
STR_WHERE,
|
|
STR_IS,
|
|
STR_AND,
|
|
STR_OR,
|
|
STR_ESC,
|
|
STR_OP_EQ,
|
|
STR_OP_NE,
|
|
STR_OP_LT,
|
|
STR_OP_GT,
|
|
STR_OP_LEQ,
|
|
STR_OP_GEQ,
|
|
STR_VALUES,
|
|
STR_FROM,
|
|
STR_OID,
|
|
STR_TIMESTAMP,
|
|
STR_ZT
|
|
};
|
|
|
|
|
|
static str strings[] = {
|
|
STR_STATIC_INIT("delete from "),
|
|
STR_STATIC_INIT("insert into "),
|
|
STR_STATIC_INIT("update "),
|
|
STR_STATIC_INIT("select "),
|
|
STR_STATIC_INIT("replace "),
|
|
STR_STATIC_INIT(" set "),
|
|
STR_STATIC_INIT(" where "),
|
|
STR_STATIC_INIT(" is "),
|
|
STR_STATIC_INIT(" and "),
|
|
STR_STATIC_INIT(" or "),
|
|
STR_STATIC_INIT("?"),
|
|
STR_STATIC_INIT("="),
|
|
STR_STATIC_INIT("!="),
|
|
STR_STATIC_INIT("<"),
|
|
STR_STATIC_INIT(">"),
|
|
STR_STATIC_INIT("<="),
|
|
STR_STATIC_INIT(">="),
|
|
STR_STATIC_INIT(") values ("),
|
|
STR_STATIC_INIT(" from "),
|
|
STR_STATIC_INIT("select typname,pg_type.oid from pg_type"),
|
|
STR_STATIC_INIT("select timestamp '2000-01-01 00:00:00' + time '00:00:01'"),
|
|
STR_STATIC_INIT("\0")
|
|
};
|
|
|
|
|
|
/**
|
|
* Reallocatable string buffer.
|
|
*/
|
|
struct string_buffer {
|
|
char *s; /**< allocated memory itself */
|
|
int len; /**< used memory */
|
|
int size; /**< total size of allocated memory */
|
|
int increment; /**< increment when realloc is necessary */
|
|
};
|
|
|
|
|
|
/** Appends string to string buffer.
|
|
* This function appends string to dynamically created string buffer,
|
|
* the buffer is automatically extended if there is not enough room
|
|
* in the buffer. The buffer is allocated using pkg_malloc.
|
|
* @param sb string buffer
|
|
* @param nstr string to add
|
|
* @return 0 if OK, -1 if failed
|
|
*/
|
|
static inline int sb_add(struct string_buffer *sb, str *nstr)
|
|
{
|
|
int new_size = 0;
|
|
int rsize = sb->len + nstr->len;
|
|
int asize;
|
|
char *newp;
|
|
|
|
if (rsize > sb->size) {
|
|
asize = rsize - sb->size;
|
|
new_size = sb->size + (asize / sb->increment
|
|
+ (asize % sb->increment > 0)) * sb->increment;
|
|
newp = pkg_malloc(new_size);
|
|
if (!newp) {
|
|
ERR("postgres: No memory left\n");
|
|
return -1;
|
|
}
|
|
if (sb->s) {
|
|
memcpy(newp, sb->s, sb->len);
|
|
pkg_free(sb->s);
|
|
}
|
|
sb->s = newp;
|
|
sb->size = new_size;
|
|
}
|
|
if(sb->s) {
|
|
memcpy(sb->s + sb->len, nstr->s, nstr->len);
|
|
sb->len += nstr->len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/** Creates str string from zero terminated string without copying.
|
|
* This function initializes members of a temporary str structure
|
|
* with the pointer and lenght of the string from s parameter.
|
|
*
|
|
* @param str A pointer to temporary str structure.
|
|
* @param s A zero terminated string.
|
|
* @return Pointer to the str structure.
|
|
*/
|
|
static inline str* set_str(str *str, const char *s)
|
|
{
|
|
str->s = (char *)s;
|
|
str->len = strlen(s);
|
|
return str;
|
|
}
|
|
|
|
|
|
/** Returns a parameter marker for PostgreSQL with number i
|
|
* The function builds a parameter marker for use in
|
|
* PostgreSQL SQL queries, such as $1, $2, etc.
|
|
* @param i Number of the parameter
|
|
* @retval A pointer to static string with the marker
|
|
*/
|
|
static str* get_marker(unsigned int i)
|
|
{
|
|
static char buf[INT2STR_MAX_LEN + 1];
|
|
static str res;
|
|
const char* c;
|
|
|
|
buf[0] = '$';
|
|
res.s = buf;
|
|
|
|
c = int2str(i, &res.len);
|
|
memcpy(res.s + 1, c, res.len);
|
|
res.len++;
|
|
return &res;
|
|
}
|
|
|
|
|
|
int build_update_sql(str* sql_cmd, db_cmd_t* cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
db_fld_t* fld;
|
|
int i, rv = 0;
|
|
str tmpstr;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_UPDATE]); /* "UPDATE " */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
rv |= sb_add(&sql_buf, &cmd->table); /* table name */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
rv |= sb_add(&sql_buf, &strings[STR_SET]); /* " SET " */
|
|
|
|
/* column name-value pairs */
|
|
for(i = 0, fld = cmd->vals; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "="));
|
|
rv |= sb_add(&sql_buf, &strings[STR_ESC]);
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ","));
|
|
}
|
|
if (rv) goto error;
|
|
|
|
if (!DB_FLD_EMPTY(cmd->match)) {
|
|
rv |= sb_add(&sql_buf, &strings[STR_WHERE]);
|
|
|
|
for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
|
|
switch(fld[i].op) {
|
|
case DB_EQ: rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]); break;
|
|
case DB_NE: rv |= sb_add(&sql_buf, &strings[STR_OP_NE]); break;
|
|
case DB_LT: rv |= sb_add(&sql_buf, &strings[STR_OP_LT]); break;
|
|
case DB_GT: rv |= sb_add(&sql_buf, &strings[STR_OP_GT]); break;
|
|
case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break;
|
|
case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break;
|
|
}
|
|
|
|
rv |= sb_add(&sql_buf, get_marker(i + 1));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]);
|
|
}
|
|
}
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int build_insert_sql(str* sql_cmd, db_cmd_t* cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
db_fld_t* fld;
|
|
int i, rv = 0;
|
|
str tmpstr;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_INSERT]); /* "INSERT INTO " */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
rv |= sb_add(&sql_buf, &cmd->table); /* table name */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\" ("));
|
|
|
|
/* column names */
|
|
for(i = 0, fld = cmd->vals; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ","));
|
|
}
|
|
if (rv) goto error;
|
|
|
|
rv |= sb_add(&sql_buf, &strings[STR_VALUES]);
|
|
|
|
for(i = 0, fld = cmd->vals; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, get_marker(i + 1));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ","));
|
|
}
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, ")"));
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int build_delete_sql(str* sql_cmd, db_cmd_t* cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
db_fld_t* fld;
|
|
int i, rv = 0;
|
|
str tmpstr;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_DELETE]); /* "DELETE FROM " */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
rv |= sb_add(&sql_buf, &cmd->table); /* table name */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
|
|
if (!DB_FLD_EMPTY(cmd->match)) {
|
|
rv |= sb_add(&sql_buf, &strings[STR_WHERE]);
|
|
|
|
for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
|
|
switch(fld[i].op) {
|
|
case DB_EQ: rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]); break;
|
|
case DB_NE: rv |= sb_add(&sql_buf, &strings[STR_OP_NE]); break;
|
|
case DB_LT: rv |= sb_add(&sql_buf, &strings[STR_OP_LT]); break;
|
|
case DB_GT: rv |= sb_add(&sql_buf, &strings[STR_OP_GT]); break;
|
|
case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break;
|
|
case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break;
|
|
}
|
|
|
|
rv |= sb_add(&sql_buf, get_marker(i + 1));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]);
|
|
}
|
|
}
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int build_select_sql(str* sql_cmd, db_cmd_t* cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
db_fld_t* fld;
|
|
int i, rv = 0;
|
|
str tmpstr;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_SELECT]); /* "SELECT " */
|
|
|
|
if (DB_FLD_EMPTY(cmd->result)) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "*"));
|
|
} else {
|
|
for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ","));
|
|
}
|
|
}
|
|
|
|
rv |= sb_add(&sql_buf, &strings[STR_FROM]); /* " FROM " */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
rv |= sb_add(&sql_buf, &cmd->table); /* table name */
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, "\""));
|
|
|
|
if (!DB_FLD_EMPTY(cmd->match)) {
|
|
rv |= sb_add(&sql_buf, &strings[STR_WHERE]);
|
|
|
|
for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
|
|
rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
|
|
|
|
switch(fld[i].op) {
|
|
case DB_EQ: rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]); break;
|
|
case DB_NE: rv |= sb_add(&sql_buf, &strings[STR_OP_NE]); break;
|
|
case DB_LT: rv |= sb_add(&sql_buf, &strings[STR_OP_LT]); break;
|
|
case DB_GT: rv |= sb_add(&sql_buf, &strings[STR_OP_GT]); break;
|
|
case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break;
|
|
case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break;
|
|
}
|
|
|
|
rv |= sb_add(&sql_buf, get_marker(i + 1));
|
|
if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]);
|
|
}
|
|
}
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int build_select_oid_sql(str* sql_cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
int rv = 0;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_OID]);
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int build_timestamp_format_sql(str* sql_cmd)
|
|
{
|
|
struct string_buffer sql_buf = {.s = NULL, .len = 0,
|
|
.size = 0, .increment = 128};
|
|
int rv = 0;
|
|
|
|
rv = sb_add(&sql_buf, &strings[STR_TIMESTAMP]);
|
|
rv |= sb_add(&sql_buf, &strings[STR_ZT]);
|
|
if (rv) goto error;
|
|
|
|
sql_cmd->s = sql_buf.s;
|
|
sql_cmd->len = sql_buf.len;
|
|
return 0;
|
|
|
|
error:
|
|
if (sql_buf.s) pkg_free(sql_buf.s);
|
|
return -1;
|
|
}
|
|
|
|
/** @} */
|