📄 ldb_sqlite3.c
字号:
/* ldb database library Copyright (C) Derrell Lipman 2005 Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see <http://www.gnu.org/licenses/>.*//* * Name: ldb * * Component: ldb sqlite3 backend * * Description: core files for SQLITE3 backend * * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) */#include "ldb_includes.h"#include <sqlite3.h>struct lsqlite3_private { int trans_count; char **options; sqlite3 *sqlite;};struct lsql_context { struct ldb_module *module; /* search stuff */ long long current_eid; const char * const * attrs; struct ldb_reply *ares; /* async stuff */ void *context; int (*callback)(struct ldb_context *, void *, struct ldb_reply *);};static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, struct ldb_request *req){ struct lsql_context *ac; struct ldb_handle *h; h = talloc_zero(lsqlite3, struct ldb_handle); if (h == NULL) { ldb_set_errstring(module->ldb, "Out of Memory"); return NULL; } h->module = module; ac = talloc(h, struct lsql_context); if (ac == NULL) { ldb_set_errstring(module->ldb, "Out of Memory"); talloc_free(h); return NULL; } h->private_data = (void *)ac; h->state = LDB_ASYNC_INIT; h->status = LDB_SUCCESS; ac->module = module; ac->context = req->context; ac->callback = req->callback; return h;}/* * Macros used throughout */#ifndef FALSE# define FALSE (0)# define TRUE (! FALSE)#endif#define RESULT_ATTR_TABLE "temp_result_attrs"//#define TEMPTAB /* for testing, create non-temporary table */#define TEMPTAB "TEMPORARY"/* * Static variables */sqlite3_stmt * stmtGetEID = NULL;static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...){ char *str, *ret; va_list ap; va_start(ap, fmt); str = sqlite3_vmprintf(fmt, ap); va_end(ap); if (str == NULL) return NULL; ret = talloc_strdup(mem_ctx, str); if (ret == NULL) { sqlite3_free(str); return NULL; } sqlite3_free(str); return ret;}static char base160tab[161] = { 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */ 99 ,100,101,102,103,104,105,106,107,108, /* c-l */ 109,110,111,112,113,114,115,116,117,118, /* m-v */ 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */ 166,167,168,169,170,171,172,173,174,175, /* latin1 */ 176,177,178,179,180,181,182,183,184,185, /* latin1 */ 186,187,188,189,190,191,192,193,194,195, /* latin1 */ 196,197,198,199,200,201,202,203,204,205, /* latin1 */ 206,207,208,209,210,211,212,213,214,215, /* latin1 */ 216,217,218,219,220,221,222,223,224,225, /* latin1 */ 226,227,228,229,230,231,232,233,234,235, /* latin1 */ 236,237,238,239,240,241,242,243,244,245, /* latin1 */ 246,247,248,249,250,251,252,253,254,255, /* latin1 */ '\0'};/* * base160() * * Convert an unsigned long integer into a base160 representation of the * number. * * Parameters: * val -- * value to be converted * * result -- * character array, 5 bytes long, into which the base160 representation * will be placed. The result will be a four-digit representation of the * number (with leading zeros prepended as necessary), and null * terminated. * * Returns: * Nothing */static voidbase160_sql(sqlite3_context * hContext, int argc, sqlite3_value ** argv){ int i; long long val; char result[5]; val = sqlite3_value_int64(argv[0]); for (i = 3; i >= 0; i--) { result[i] = base160tab[val % 160]; val /= 160; } result[4] = '\0'; sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT);}/* * base160next_sql() * * This function enhances sqlite by adding a "base160_next()" function which is * accessible via queries. * * Retrieve the next-greater number in the base160 sequence for the terminal * tree node (the last four digits). Only one tree level (four digits) is * operated on. * * Input: * A character string: either an empty string (in which case no operation is * performed), or a string of base160 digits with a length of a multiple of * four digits. * * Output: * Upon return, the trailing four digits (one tree level) will have been * incremented by 1. */static voidbase160next_sql(sqlite3_context * hContext, int argc, sqlite3_value ** argv){ int i; int len; char * pTab; char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0])); char * pStart = pBase160; /* * We need a minimum of four digits, and we will always get a multiple * of four digits. */ if (pBase160 != NULL && (len = strlen(pBase160)) >= 4 && len % 4 == 0) { if (pBase160 == NULL) { sqlite3_result_null(hContext); return; } pBase160 += strlen(pBase160) - 1; /* We only carry through four digits: one level in the tree */ for (i = 0; i < 4; i++) { /* What base160 value does this digit have? */ pTab = strchr(base160tab, *pBase160); /* Is there a carry? */ if (pTab < base160tab + sizeof(base160tab) - 1) { /* * Nope. Just increment this value and we're * done. */ *pBase160 = *++pTab; break; } else { /* * There's a carry. This value gets * base160tab[0], we decrement the buffer * pointer to get the next higher-order digit, * and continue in the loop. */ *pBase160-- = base160tab[0]; } } sqlite3_result_text(hContext, pStart, strlen(pStart), free); } else { sqlite3_result_value(hContext, argv[0]); if (pBase160 != NULL) { free(pBase160); } }}static char *parsetree_to_sql(struct ldb_module *module, void *mem_ctx, const struct ldb_parse_tree *t){ const struct ldb_schema_attribute *a; struct ldb_val value, subval; char *wild_card_string; char *child, *tmp; char *ret = NULL; char *attr; int i; switch(t->operation) { case LDB_OP_AND: tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); if (tmp == NULL) return NULL; for (i = 1; i < t->u.list.num_elements; i++) { child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); if (child == NULL) return NULL; tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child); if (tmp == NULL) return NULL; } ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp); return ret; case LDB_OP_OR: tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); if (tmp == NULL) return NULL; for (i = 1; i < t->u.list.num_elements; i++) { child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); if (child == NULL) return NULL; tmp = talloc_asprintf_append(tmp, " UNION %s ", child); if (tmp == NULL) return NULL; } return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp); case LDB_OP_NOT: child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child); if (child == NULL) return NULL; return talloc_asprintf(mem_ctx, "SELECT eid FROM ldb_entry " "WHERE eid NOT IN ( %s ) ", child); case LDB_OP_EQUALITY: /* * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } if (strcasecmp(t->u.equality.attr, "objectclass") == 0) { /* * For object classes, we want to search for all objectclasses * that are subclasses as well. */ return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values\n" "WHERE norm_attr_name = 'OBJECTCLASS' " "AND norm_attr_value IN\n" " (SELECT class_name FROM ldb_object_classes\n" " WHERE tree_key GLOB\n" " (SELECT tree_key FROM ldb_object_classes\n" " WHERE class_name = '%q'\n" " ) || '*'\n" " )\n", value.data); } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ const char *cdn = ldb_dn_get_casefold( ldb_dn_new(mem_ctx, module->ldb, (const char *)value.data)); return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_entry " "WHERE norm_dn = '%q'", cdn); } else { /* A normal query. */ return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " "AND norm_attr_value = '%q'", attr, value.data); } case LDB_OP_SUBSTRING: wild_card_string = talloc_strdup(mem_ctx, (t->u.substring.start_with_wildcard)?"*":""); if (wild_card_string == NULL) return NULL; for (i = 0; t->u.substring.chunks[i]; i++) { wild_card_string = talloc_asprintf_append(wild_card_string, "%s*", t->u.substring.chunks[i]->data); if (wild_card_string == NULL) return NULL; } if ( ! t->u.substring.end_with_wildcard ) { /* remove last wildcard */ wild_card_string[strlen(wild_card_string) - 1] = '\0'; } attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; a = ldb_schema_attribute_by_name(module->ldb, attr); subval.data = (void *)wild_card_string; subval.length = strlen(wild_card_string) + 1; /* Get a canonicalised copy of the data */ a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); if (value.data == NULL) { return NULL; } return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " "AND norm_attr_value GLOB '%q'", attr, value.data); case LDB_OP_GREATER: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ", attr, value.data, attr); case LDB_OP_LESS: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ", attr, value.data, attr); case LDB_OP_PRESENT: if (strcasecmp(t->u.present.attr, "dn") == 0) { return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } attr = ldb_attr_casefold(mem_ctx, t->u.present.attr); if (attr == NULL) return NULL; return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' ", attr); case LDB_OP_APPROX: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -