📄 xdb_sql.c
字号:
} /* 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)); } PQclear(res); return 0;#else log_debug2(ZONE, LOGT_STRANGE, "xdb_sql_execute_postgresql called, but not compiled in."); return 1;#endif}/** * execute a sql query * * @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(instance i, xdbsql xq, char *query, xmlnode template, xmlnode result) {#ifdef HAVE_MYSQL if (xq->use_mysql) { return xdb_sql_execute_mysql(i, xq, query, template, result); }#endif#ifdef HAVE_POSTGRESQL if (xq->use_postgresql) { return xdb_sql_execute_postgresql(i, xq, query, template, result); }#endif log_error(i->id, "SQL query %s has not been handled by any sql driver", query); return 1;}/** * modify xdb query to be a result, that can be sent back * * @param p the packet that should be modified */void xdb_sql_makeresult(dpacket p) { xmlnode_put_attrib(p->x, "type", "result"); xmlnode_put_attrib(p->x, "to", xmlnode_get_attrib(p->x, "from")); xmlnode_put_attrib(p->x, "from", jid_full(p->id));}/** * callback function that is called by jabberd to handle xdb requests * * @param i the instance we are for jabberd * @param p the packet containing the xdb query * @param arg pointer to our own internal data * @return r_DONE if we could handle the request, r_ERR otherwise */result xdb_sql_phandler(instance i, dpacket p, void *arg) { xdbsql xq = (xdbsql)arg; /* xdb_sql internal data */ char *ns = NULL; /* namespace of the query */ xdbsql_ns_def ns_def = NULL; /* pointer to the namespace definitions */ int is_set_request = 0; /* if this is a set request */ char *action = NULL; /* xdb-set action */ char *match = NULL; /* xdb-set match */ log_debug2(ZONE, LOGT_STORAGE|LOGT_DELIVER, "handling xdb request %s", xmlnode2str(p->x)); /* get the namespace of the request */ ns = xmlnode_get_attrib(p->x, "ns"); if (ns == NULL) { log_debug2(ZONE, LOGT_STORAGE|LOGT_STRANGE, "xdb_sql got a xdb request without namespace"); return r_ERR; } /* check if we know how to handle this namespace */ ns_def = xhash_get(xq->namespace_defs, ns); if (ns_def == NULL) { log_error(i->id, "xdb_sql got a xdb request for an unconfigured namespace %s, use this handler only for selected namespaces.", ns); return r_ERR; } /* check the type of xdb request */ is_set_request = (j_strcmp(xmlnode_get_attrib(p->x, "type"), "set") == 0); if (is_set_request) { /* set request */ action = xmlnode_get_attrib(p->x, "action"); match = xmlnode_get_attrib(p->x, "match"); if (action == NULL) { char *query = NULL; /* just a boring set */ /* start the transaction */ xdb_sql_execute(i, xq, "BEGIN", NULL, NULL); /* delete old values */ query = xdb_sql_construct_query(ns_def->delete, p->x); log_debug2(ZONE, LOGT_STORAGE, "using the following SQL statement for deletion: %s", query); if (xdb_sql_execute(i, xq, query, NULL, NULL)) { /* SQL query failed */ xdb_sql_execute(i, xq, "ROLLBACK", NULL, NULL); return r_ERR; } /* insert new values (if there are any) */ if (xmlnode_get_firstchild(p->x) != NULL) { query = xdb_sql_construct_query(ns_def->set, p->x); log_debug2(ZONE, LOGT_STORAGE, "using the following SQL statement for insertion: %s", query); if (xdb_sql_execute(i, xq, query, NULL, NULL)) { /* SQL query failed */ xdb_sql_execute(i, xq, "ROLLBACK", NULL, NULL); return r_ERR; } } /* commit the transaction */ xdb_sql_execute(i, xq, "COMMIT", NULL, NULL); /* send result back */ xdb_sql_makeresult(p); deliver(dpacket_new(p->x), NULL); return r_DONE; } else if (j_strcmp(action, "insert") == 0) { char *query = NULL; /* start the transaction */ xdb_sql_execute(i, xq, "BEGIN", NULL, NULL); /* insert new values */ query = xdb_sql_construct_query(ns_def->set, p->x); log_debug2(ZONE, LOGT_STORAGE, "using the following SQL statement for insertion: %s", query); if (xdb_sql_execute(i, xq, query, NULL, NULL)) { /* SQL query failed */ xdb_sql_execute(i, xq, "ROLLBACK", NULL, NULL); return r_ERR; } /* commit the transaction */ xdb_sql_execute(i, xq, "COMMIT", NULL, NULL); /* send result back */ xdb_sql_makeresult(p); deliver(dpacket_new(p->x), NULL); return r_DONE; } else { /* not supported action, probably check */ log_warn(i->id, "unable to handle unsupported xdb-set action '%s'", action); return r_ERR; } } else { char *query = NULL; char *group_element = NULL; xmlnode result_element = p->x; /* get request */ /* start the transaction */ xdb_sql_execute(i, xq, "BEGIN", NULL, NULL); /* get the record(s) */ query = xdb_sql_construct_query(ns_def->get_query, p->x); group_element = xmlnode_get_attrib(ns_def->get_result, "group"); if (group_element != NULL) { result_element = xmlnode_insert_tag(result_element, group_element); xmlnode_put_attrib(result_element, "ns", ns); } log_debug2(ZONE, LOGT_STORAGE, "using the following SQL statement for selection: %s", query); if (xdb_sql_execute(i, xq, query, ns_def->get_result, result_element)) { /* SQL query failed */ xdb_sql_execute(i, xq, "ROLLBACK", NULL, NULL); return r_ERR; } /* commit the transaction */ xdb_sql_execute(i, xq, "COMMIT", NULL, NULL); /* construct the result */ xdb_sql_makeresult(p); deliver(dpacket_new(p->x), NULL); return r_DONE; }}/** * init the mysql driver * * @param i the instance we are (jabberd's view) * @param xq our internal instance data * @param config the configuration node of this instance */void xdb_sql_mysql_init(instance i, xdbsql xq, xmlnode config) {#ifdef HAVE_MYSQL /* create a MYSQL handle */ if (xq->mysql == NULL) { xq->mysql = mysql_init(NULL); } /* process our own configuration */ xq->mysql_user = pstrdup(i->p, xmlnode_get_tag_data(config, "mysql/user")); xq->mysql_password = pstrdup(i->p, xmlnode_get_tag_data(config, "mysql/password")); xq->mysql_host = pstrdup(i->p, xmlnode_get_tag_data(config, "mysql/host")); xq->mysql_database = pstrdup(i->p, xmlnode_get_tag_data(config, "mysql/database")); xq->mysql_port = j_atoi(xmlnode_get_tag_data(config, "mysql/port"), 0); xq->mysql_socket = pstrdup(i->p, xmlnode_get_tag_data(config, "mysql/socket")); xq->mysql_flag = j_atoi(xmlnode_get_tag_data(config, "mysql/flag"), 0); /* connect to the database server */ xdb_sql_mysql_connect(i, xq);#else log_debug2(ZONE, LOGT_STRANGE, "xdb_sql_mysql_init called, but not compiled in.");#endif}/** * init the postgresql driver * * @param i the instance we are (jabberd's view) * @param xq our internal instance data * @param config the configuration node of this instance */void xdb_sql_postgresql_init(instance i, xdbsql xq, xmlnode config) {#ifdef HAVE_POSTGRESQL /* process our own configuration */ xq->postgresql_conninfo = pstrdup(i->p, xmlnode_get_tag_data(config, "postgresql/conninfo")); /* connect to the database server */ xq->postgresql = PQconnectdb(xq->postgresql_conninfo); /* did we connect? */ if (PQstatus(xq->postgresql) != CONNECTION_OK) { log_error(i->id, "failed to connect to postgresql server: %s", PQerrorMessage(xq->postgresql)); }#else log_debug2(ZONE, LOGT_STRANGE, "xdb_sql_postgresql_init called, but not compiled in.");#endif}/** * preprocess a SQL query definition * * @param i the instance we are running in * @param query the SQL query definition * @return array of preprocessed query, contains array of strings, odd entries are literals, even entries are variables */char **xdb_sql_query_preprocess(instance i, char *query) { int count = 0; char *pos = NULL; char *next = NULL; char **result = NULL; /* check provieded parameters */ if (i == NULL || query == NULL) { return NULL; } /* make a copy of the query that we can tokenize */ query = pstrdup(i->p, query); /* go to the start of the query */ pos = query; /* estimate the number of variables in the string */ while ( (pos = strstr(pos, "{")) != NULL ) { /* don't find this variable again */ pos++; /* count the number of variables */ count++; } /* allocate memory for the array */ result = pmalloco(i->p, (count+1)*2*sizeof(char*)); /* tokenize the query */ count = 0; pos = query; while (pos != NULL) { /* find start or end of variable * if count is odd we search for end of variable * if count is even we search for the begin of a variable */ next = (count % 2) ? strstr(pos, "}") : strstr(pos, "{"); /* tokenize */ if (next != NULL) { *next = 0; } /* store the pointer to this token */ result[count] = pos; /* skip the token separator { or } */ if (next != NULL) { next++; } /* next search starts where next points to */ pos = next; count++; } return result;}/** * process a handler definition * * @param i the instance we are running as * @param xq our instance internal data * @param handler the handler definition */void xdb_sql_handler_process(instance i, xdbsql xq, xmlnode handler) { char *handled_ns = NULL; /* which namespace this definition is for */ xdbsql_ns_def nsdef = NULL; /* where to store the processed information */ int count = 0; char *temp = NULL; log_debug2(ZONE, LOGT_INIT, "processing handler definition: %s", xmlnode2str(handler)); nsdef = pmalloco(i->p, sizeof(_xdbsql_ns_def)); /* query the relevant tags from this handler */ handled_ns = pstrdup(i->p, xmlnode_get_attrib(handler, "ns")); temp = xmlnode_get_tag_data(handler, "get/query"); nsdef->get_query = xdb_sql_query_preprocess(i, temp); nsdef->get_result = xmlnode_dup_pool(i->p, xmlnode_get_tag(handler, "get/result")); temp = xmlnode_get_tag_data(handler, "set"); nsdef->set = xdb_sql_query_preprocess(i, temp); temp = xmlnode_get_tag_data(handler, "delete"); nsdef->delete = xdb_sql_query_preprocess(i, temp); /* store the read definition */ log_debug2(ZONE, LOGT_INIT|LOGT_STORAGE, "registering namespace handler for %s", handled_ns); xhash_put(xq->namespace_defs, handled_ns, nsdef);}/** * read the handler configuration and generate their internal representation * * @param i the instance we are running as * @param xq our instance internal data * @param config the configuration data for this xdb_sql instance */void xdb_sql_handler_read(instance i, xdbsql xq, xmlnode config) { xmlnode cur = NULL; /* used to iterate through <handler/> elements */ if (i == NULL || xq == NULL || config == NULL) { log_debug2(ZONE, LOGT_STRANGE|LOGT_INIT|LOGT_STORAGE, "called xdb_sql_handler_read with i, xq, or config as NULL"); return; } for (cur = xmlnode_get_firstchild(config); cur != NULL; cur = xmlnode_get_nextsibling(cur)) { /* we only care for <handler/> elements */ char *element_name = xmlnode_get_name(cur); if (j_strcmp(element_name, "handler") != 0) { continue; } /* process this handler definition */ xdb_sql_handler_process(i, xq, cur); }}/** * init the xdb_sql module, called by the jabberd module loader * * @param i jabberd's data about our instance * @param x the <load/> xmlnode that instructed the moduleloader to load us */void xdb_sql(instance i, xmlnode x) { xdbcache xc; /* to fetch our configuration */ xmlnode config = NULL; /* our configuration */ xdbsql xq = NULL; /* pointer to instance internal data */ char *driver = NULL; /* database driver to use */ /* output a first sign of life ... :) */ log_debug2(ZONE, LOGT_INIT, "xdb_sql loading"); /* fetch our own configuration */ xc = xdb_cache(i); if (xc != NULL) { config = xdb_get(xc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:xdb_sql"); } if (config == NULL) { log_error(i->id, "xdb_sql failed to load its configuration"); return; } /* create our internal data */ xq = pmalloco(i->p, sizeof(_xdbsql)); xq->namespace_defs = xhash_new(j_atoi(xmlnode_get_tag_data(config, "maxns"), XDBSQL_MAXNS_PRIME)); /* use which driver? */ driver = xmlnode_get_tag_data(config, "driver"); if (driver == NULL) { log_error(i->id, "you have to configure which driver xdb_sql should use"); xmlnode_free(config); return;#ifdef HAVE_MYSQL } else if (j_strcmp(driver, "mysql") == 0) { xq->use_mysql = 1; /* use mysql for the queries */ xdb_sql_mysql_init(i, xq, config);#endif#ifdef HAVE_POSTGRESQL } else if (j_strcmp(driver, "postgresql") == 0) { xq->use_postgresql = 1; /* use postgresql for the queries */ xdb_sql_postgresql_init(i, xq, config);#endif } else { log_error(i->id, "Your xdb_sql is compiled without support for the selected database driver '%s'.", driver); } /* read the handler defintions */ xdb_sql_handler_read(i, xq, config); /* register our packet handler */ register_phandler(i, o_DELIVER, xdb_sql_phandler, (void *)xq); /* free the configuration we have processed */ xmlnode_free(config);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -