⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xdb_sql.c

📁 jabber server jabber server jabber server jabber server
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL").  You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/.   * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights *  * Portions created by or assigned to Jabber.com, Inc. are  * Copyright (c) 1999-2002 Jabber.com, Inc.  All Rights Reserved.  Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. *  * Acknowledgements *  * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. *  * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above.  If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL.  If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL.  *  * --------------------------------------------------------------------------*/#include <jabberd.h>/** the namespace of variables in templates in the configuration */#define NS_XDBSQL "http://jabberd.org/ns/xdbsql"#ifdef HAVE_MYSQL#  include <mysql/mysql.h>#  include <mysql/errmsg.h>#endif#ifdef HAVE_POSTGRESQL#  include <postgresql/libpq-fe.h>#endif/** * the maximum number of defined namespaces to handle, can be overridden with * the <maxns/> configuration setting */#define XDBSQL_MAXNS_PRIME 101/** * @file xdb_sql.c * @brief xdb module that handles the requests using a SQL database * * xdb_sql is an implementation of a xdb module for jabberd14, that handles * the xdb requests using an underlying SQL database. Currently only mysql * is supported. *//** * structure that holds the data used by xdb_sql internally */typedef struct xdbsql_struct {    xht		namespace_defs;		/**< definitions of queries for the different namespaces */#ifdef HAVE_MYSQL    int		use_mysql;		/**< if we want to use the mysql driver */    MYSQL	*mysql;			/**< our database handle */    char	*mysql_user;		/**< username for mysql server */    char	*mysql_password;	/**< password for mysql server */    char	*mysql_host;		/**< hostname of the mysql server */    char	*mysql_database;	/**< database on the mysql server */    int		mysql_port;		/**< port of the mysql server */    char	*mysql_socket;		/**< socket of the mysql server */    unsigned long mysql_flag;		/**< flags for the connection to the mysql server */#endif#ifdef HAVE_POSTGRESQL    int		use_postgresql;		/**< if we want to use the postgresql driver */    PGconn	*postgresql;		/**< our postgresql connection handle */    char	*postgresql_conninfo;	/**< settings used to connect to postgresql */#endif} *xdbsql, _xdbsql;/** * structure that holds the information how to handle a namespace */typedef struct xdbsql_ns_def_struct {    char	**get_query;		/**< SQL query to handle get requests */    xmlnode	get_result;		/**< template for results for get requests */    char	**set;			/**< SQL query to handle set requests */    char	**delete;		/**< SQL query to delete old values */} *xdbsql_ns_def, _xdbsql_ns_def;/** * connect to the mysql server * * @param i the instance we are running in * @param xq our internal instance data */void xdb_sql_mysql_connect(instance i, xdbsql xq) {#ifdef HAVE_MYSQL    /* connect to the database */    if (mysql_real_connect(xq->mysql, xq->mysql_host, xq->mysql_user, xq->mysql_password, xq->mysql_database, xq->mysql_port, xq->mysql_socket, xq->mysql_flag) == NULL) {	log_error(i->id, "failed to connect to mysql server: %s", mysql_error(xq->mysql));    }#else    log_debug2(ZONE, LOGT_STRANGE, "xdb_sql_mysql_connect called, but not compiled in.");#endif}/** * add a string to a spool while escaping some characters * * @param destination the result spool * @param new_string what should be added (this gets destroyed!!!) */void xdb_sql_spool_add_escaped(spool destination, char *new_string) {    char *first_to_escape = NULL;    char *ptr = NULL;    char character_to_escape[2] = "\0\0";    /* check for ' */    first_to_escape = strchr(new_string, '\'');    /* is there a " earlier? */    ptr = strchr(new_string, '"');    if (ptr != NULL && (ptr < first_to_escape || first_to_escape == NULL)) {	first_to_escape = ptr;    }    /* is there a \ earlier? */    ptr = strchr(new_string, '\\');    if (ptr != NULL && (ptr < first_to_escape || first_to_escape == NULL)) {	first_to_escape = ptr;    }    /* is there something to escape? */    if (first_to_escape == NULL) {	/* no */	spool_add(destination, new_string);	return;    }    /* add up to the character that is escaped and this character with escapeing ... */    character_to_escape[0] = first_to_escape[0];    first_to_escape[0] = 0;    spooler(destination, new_string, "\\", character_to_escape, destination);        /* and call recursive */    xdb_sql_spool_add_escaped(destination, first_to_escape+1);}/** * use the template for a query to construct a real query * * @param template the template to construct the SQL query * @param xdb_query the xdb query * @return SQL query */char *xdb_sql_construct_query(char **template, xmlnode xdb_query) {    int index = 0;		/* token counter */    spool result_spool = spool_new(xdb_query->p); /* where to store the result */    /* sanity check */    if (template == NULL || xdb_query == NULL) {	return NULL;    }    /* debugging */    log_debug2(ZONE, LOGT_STORAGE, "constructing query using xdb_query %s", xmlnode2str(xdb_query));    /* construct the result */    while (template[index] != NULL) {	if (index % 2 == 0) {	    /* copy token */	    spool_add(result_spool, template[index]);	} else {	    /* substitute token */	    char *subst = NULL;	    /* XXX very hacky way to select attributes on the root element, xpath in xmlnode would be nice */	    if (j_strncmp(template[index], "attribute::", 11) == 0) {		subst = xmlnode_get_attrib(xdb_query, template[index]+11);	    } else {		char *ptr;		/* text node? */		ptr = strstr(template[index], "/text()");		if (ptr == NULL || ptr-template[index] != strlen(template[index])-7) {		    /* attribute value? */		    ptr = strstr(template[index], "/attribute::");		    if (ptr == NULL) {			/* get the element */			xmlnode subst_node = (xmlnode_get_tag(xdb_query, template[index]));			if (subst_node != NULL)			    subst = xmlnode2str(subst_node);		    } else {			/* attribute value */			xmlnode temp_node = NULL;			char *attribute = pstrdup(xdb_query->p, ptr+12);			ptr = pstrdup(xdb_query->p, template[index]);			strstr(ptr, "/attribute::")[0] = 0;			temp_node = xmlnode_get_tag(xdb_query, ptr);			subst = xmlnode_get_attrib(temp_node, attribute);		    }		} else {		    /* get the text content of the element */		    ptr = pstrdup(xdb_query->p, template[index]);		    strstr(ptr, "/text()")[0] = 0;		    subst = xmlnode_get_tag_data(xdb_query, ptr);		}	    }	    xdb_sql_spool_add_escaped(result_spool, pstrdup(result_spool->p, subst!=NULL ? subst : ""));	}	/* next token */	index++;    }    return spool_print(result_spool);}/** * find any node in a xmlnode tree that matches the search * * @todo something like this should become a part of xmlnode * * @param root the root of the tree we search in * @param name which element to search * @return the found element, or NULL if no such element */xmlnode xdb_sql_find_node_recursive(xmlnode root, const char *name) {    xmlnode ptr = NULL;    /* is it already this node? */    if (j_strcmp(xmlnode_get_name(root), name) == 0) {	/* we found it */	return root;    }    /* check the child nodes */    for (ptr = xmlnode_get_firstchild(root); ptr != NULL; ptr = xmlnode_get_nextsibling(ptr)) {	xmlnode result = xdb_sql_find_node_recursive(ptr, name);	if (result != NULL) {	    return result;	}    }    /* found nothing */    return NULL;}/** * execute a sql query using mysql * * @param i the instance we are running in * @param xq instance internal data * @param query the SQL query to execute * @param template template to construct the result * @param result where to add the results * @return 0 on success, non zero on failure */int xdb_sql_execute_mysql(instance i, xdbsql xq, char *query, xmlnode template, xmlnode result) {#ifdef HAVE_MYSQL    int ret = 0;    MYSQL_RES *res = NULL;    MYSQL_ROW row = NULL;        /* try to execute the query */    ret = mysql_query(xq->mysql, query);    /* failed and we need to reconnect? */    if (ret == CR_SERVER_LOST || ret == CR_SERVER_GONE_ERROR) {	xdb_sql_mysql_connect(i, xq);	ret = mysql_query(xq->mysql, query);    }    /* still an error? log and return */    if (ret != 0) {	log_error(i->id, "mysql query (%s) failed: %s", query, mysql_error(xq->mysql));	return 1;    }    /* the mysql query succeded: fetch results */    while (res = mysql_store_result(xq->mysql)) {	/* how many fields are in the rows */	unsigned int num_fields = mysql_num_fields(res);	/* fetch rows of the result */	while (row = mysql_fetch_row(res)) {	    xmlnode variable = NULL;	    xmlnode new_instance = NULL;	    log_debug2(ZONE, LOGT_STORAGE, "we got a result row with %u fields", num_fields);	    	    /* instantiate a copy of the template */	    new_instance = xmlnode_dup_pool(result->p, template);	    /* find variables in the template and replace them with values */	    while (variable = xdb_sql_find_node_recursive(new_instance, "value")) {		xmlnode parent = xmlnode_get_parent(variable);		int value = j_atoi(xmlnode_get_attrib(variable, "value"), 0);		int parsed = j_strcmp(xmlnode_get_attrib(variable, "parsed"), "parsed") == 0;		/* hide the template variable */		xmlnode_hide(variable);		/* insert the value */		if (value > 0 && value <= num_fields) {		    if (parsed) {			xmlnode fieldvalue = xmlnode_str(row[value-1], j_strlen(row[value-1]));			xmlnode fieldcopy = xmlnode_dup_pool(result->p, fieldvalue);			xmlnode_free(fieldvalue);			xmlnode_insert_tag_node(parent, fieldcopy);		    } else {			xmlnode_insert_cdata(parent, row[value-1], -1);		    }		}	    }	    /* insert the result */	    log_debug2(ZONE, LOGT_STORAGE, "the row results in: %s", xmlnode2str(new_instance));	    xmlnode_insert_node(result, xmlnode_get_firstchild(new_instance));	}	/* free the result again */	mysql_free_result(res);    }    return 0;#else    log_debug2(ZONE, LOGT_STRANGE, "xdb_sql_execute_mysql called, but not compiled in.");    return 1;#endif}/** * execute a sql query using postgresql * * @param i the instance we are running in * @param xq instance internal data * @param query the SQL query to execute * @param template template to construct the result * @param result where to add the results * @return 0 on success, non zero on failure */int xdb_sql_execute_postgresql(instance i, xdbsql xq, char *query, xmlnode template, xmlnode result) {#ifdef HAVE_POSTGRESQL    PGresult *res = NULL;    ExecStatusType status = 0;    int row = 0;    int fields = 0;    /* are we still connected? */    if (PQstatus(xq->postgresql) != CONNECTION_OK) {	log_warn(i->id, "resetting connection to the PostgreSQL server");		/* reset the connection */	PQreset(xq->postgresql);	/* are we now connected? */	if (PQstatus(xq->postgresql) != CONNECTION_OK) {	    log_error(i->id, "cannot reset connection: %s", PQerrorMessage(xq->postgresql));	    return 1;	}    }    /* try to execute the query */    res = PQexec(xq->postgresql, query);    if (res == NULL) {	log_error(i->id, "cannot execute PostgreSQL query: %s", PQerrorMessage(xq->postgresql));	return 1;    }    /* get the status of the execution */    status = PQresultStatus(res);    switch (status) {	case PGRES_EMPTY_QUERY:	case PGRES_BAD_RESPONSE:	case PGRES_FATAL_ERROR:	    log_warn(i->id, "%s: %s", PQresStatus(status), PQresultErrorMessage(res));	    PQclear(res);	    return 1;	case PGRES_COMMAND_OK:	case PGRES_COPY_OUT:	case PGRES_COPY_IN:	    PQclear(res);	    return 0;    }    /* the postgresql query succeded: fetch results */    fields = PQnfields(res);    for (row = 0; row < PQntuples(res); row++) {	xmlnode variable = NULL;	xmlnode new_instance = NULL;	/* instantiate a copy of the template */	new_instance = xmlnode_dup_pool(result->p, template);	/* find variables in the template and replace them with values */	while (variable = xdb_sql_find_node_recursive(new_instance, "value")) {	    xmlnode parent = xmlnode_get_parent(variable);	    int value = j_atoi(xmlnode_get_attrib(variable, "value"), 0);	    int parsed = j_strcmp(xmlnode_get_attrib(variable, "parsed"), "parsed") == 0;	    /* hide the template variable */	    xmlnode_hide(variable);	    /* insert the value */	    if (value > 0 && value <= fields) {		if (parsed) {		    xmlnode fieldvalue = xmlnode_str(PQgetvalue(res, row, value-1), PQgetlength(res, row, value-1));		    xmlnode fieldcopy = xmlnode_dup_pool(result->p, fieldvalue);		    xmlnode_free(fieldvalue);		    xmlnode_insert_tag_node(parent, fieldcopy);		} else {		    xmlnode_insert_cdata(parent, PQgetvalue(res, row, value-1), PQgetlength(res, row, value-1));		}	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -