mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
added back-sql files
This commit is contained in:
parent
8dc136ddd6
commit
d63b3dc2fd
25
servers/slapd/back-sql/Makefile.in
Normal file
25
servers/slapd/back-sql/Makefile.in
Normal file
@ -0,0 +1,25 @@
|
||||
# $OpenLDAP$
|
||||
|
||||
SRCS = init.c config.c search.c bind.c other.c \
|
||||
entry-id.c schema-map.c sql-wrap.c modify.c util.c
|
||||
OBJS = init.lo config.lo search.lo bind.lo other.lo \
|
||||
entry-id.lo schema-map.lo sql-wrap.lo modify.lo util.lo
|
||||
|
||||
LDAP_INCDIR= ../../../include
|
||||
LDAP_LIBDIR= ../../../libraries
|
||||
|
||||
BUILD_OPT = "--enable-sql"
|
||||
BUILD_MOD = @BUILD_SQL@
|
||||
LINKAGE = @BUILD_SQL_DYNAMIC@
|
||||
|
||||
LIBBASE = back_sql
|
||||
|
||||
XINCPATH = -I.. -I$(srcdir)/.. $(SLAPD_SQL_INCLUDES)
|
||||
XDEFS = $(MODULES_CPPFLAGS)
|
||||
XLDFLAGS = $(MODULES_LDFLAGS)
|
||||
|
||||
all-local-lib: ../.backend
|
||||
|
||||
../.backend: lib$(LIBBASE).a
|
||||
@touch $@
|
||||
|
39
servers/slapd/back-sql/back-sql.h
Normal file
39
servers/slapd/back-sql/back-sql.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef __BACKSQL_H__
|
||||
#define __BACKSQL_H__
|
||||
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include "external.h"
|
||||
#include "sql-types.h"
|
||||
#define BACKSQL_MAX_DN_LEN 255
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *dbhost;
|
||||
int dbport;
|
||||
char *dbuser;
|
||||
char *dbpasswd;
|
||||
char *dbname;
|
||||
//SQL condition for subtree searches differs in syntax:
|
||||
//"LIKE CONCAT('%',?)" or "LIKE '%'+?" or smth else
|
||||
char *subtree_cond;
|
||||
char *oc_query,*at_query;
|
||||
char *insentry_query,*delentry_query;
|
||||
Avlnode *db_conns;
|
||||
Avlnode *oc_by_name;
|
||||
Avlnode *oc_by_id;
|
||||
int schema_loaded;
|
||||
ldap_pvt_thread_mutex_t dbconn_mutex;
|
||||
ldap_pvt_thread_mutex_t schema_mutex;
|
||||
SQLHENV db_env;
|
||||
}backsql_info;
|
||||
|
||||
#endif
|
205
servers/slapd/back-sql/backsql.dsp
Normal file
205
servers/slapd/back-sql/backsql.dsp
Normal file
@ -0,0 +1,205 @@
|
||||
# Microsoft Developer Studio Project File - Name="backsql" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 5.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=backsql - Win32 Single Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "backsql.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "backsql.mak" CFG="backsql - Win32 Single Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "backsql - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "backsql - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "backsql - Win32 Single Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "backsql - Win32 Single Release" (based on\
|
||||
"Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
|
||||
!IF "$(CFG)" == "backsql - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\..\..\Release"
|
||||
# PROP Intermediate_Dir "..\..\..\Release\backsql"
|
||||
# PROP Target_Dir ""
|
||||
RSC=rc.exe
|
||||
# ADD BASE RSC /l 0x419
|
||||
# ADD RSC /l 0x419
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "backsql - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "..\..\..\Debug"
|
||||
# PROP Intermediate_Dir "..\..\..\Debug\backsql"
|
||||
# PROP Target_Dir ""
|
||||
RSC=rc.exe
|
||||
# ADD BASE RSC /l 0x419
|
||||
# ADD RSC /l 0x419
|
||||
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "backsql - Win32 Single Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "backsql"
|
||||
# PROP BASE Intermediate_Dir "backsql"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "..\..\..\SDebug"
|
||||
# PROP Intermediate_Dir "..\..\..\SDebug\backsql"
|
||||
# PROP Target_Dir ""
|
||||
RSC=rc.exe
|
||||
# ADD BASE RSC /l 0x419
|
||||
# ADD RSC /l 0x419
|
||||
# ADD BASE CPP /nologo /MTd /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\\" /I "..\..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "backsql - Win32 Single Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "backldb0"
|
||||
# PROP BASE Intermediate_Dir "backldb0"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\..\..\SRelease"
|
||||
# PROP Intermediate_Dir "..\..\..\SRelease\backsql"
|
||||
# PROP Target_Dir ""
|
||||
RSC=rc.exe
|
||||
# ADD BASE RSC /l 0x419
|
||||
# ADD RSC /l 0x419
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "..\\" /I "..\..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "backsql - Win32 Release"
|
||||
# Name "backsql - Win32 Debug"
|
||||
# Name "backsql - Win32 Single Debug"
|
||||
# Name "backsql - Win32 Single Release"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\back-sql.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bind.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\config.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\entry-id.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\entry-id.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\external.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\init.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\modify.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\other.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\schema-map.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\schema-map.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\search.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\sql-types.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\sql-wrap.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\sql-wrap.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.h
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
35
servers/slapd/back-sql/bind.c
Normal file
35
servers/slapd/back-sql/bind.c
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "slap.h"
|
||||
#include "back-sql.h"
|
||||
#include "sql-wrap.h"
|
||||
|
||||
int backsql_bind(Backend *be,Connection *conn,Operation *op,
|
||||
char *dn,char *ndn,int method,char *mech,struct berval *cred,char** edn)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_bind()\n",0,0,0);
|
||||
//for now, just return OK, allowing to test modify operations
|
||||
send_ldap_result(conn,op,LDAP_SUCCESS,NULL,NULL,NULL,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_bind()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_unbind(Backend *be,Connection *conn,Operation *op)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_unbind()\n",0,0,0);
|
||||
backsql_free_db_conn(be,conn);
|
||||
send_ldap_result(conn,op,LDAP_SUCCESS,NULL,NULL,NULL,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_unbind()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
168
servers/slapd/back-sql/config.c
Normal file
168
servers/slapd/back-sql/config.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include "slap.h"
|
||||
#include "back-sql.h"
|
||||
#include "sql-wrap.h"
|
||||
|
||||
int backsql_db_config(BackendDB *be,const char *fname,int lineno,int argc,char **argv)
|
||||
{
|
||||
backsql_info *si=(backsql_info*) be->be_private;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_db_config()\n",0,0,0);
|
||||
if (!si)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_config: be_private is NULL!!!\n",0,0,0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"dbhost"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing hostname in dbhost directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->dbhost=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): hostname=%s\n",si->dbhost,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"dbuser"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing username in dbuser directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->dbuser=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): dbuser=%s\n",argv[1],0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"dbpasswd"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing password in dbpasswd directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->dbpasswd=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): dbpasswd=%s\n",si->dbpasswd,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"dbname"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing database name in dbname directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->dbname=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): dbname=%s\n",si->dbname,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"subtree_cond"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing SQL condition in subtree_cond directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->subtree_cond=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): subtree_cond=%s\n",si->subtree_cond,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"oc_query"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing SQL statement in oc_query directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->oc_query=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): oc_query=%s\n",si->oc_query,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"at_query"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing SQL statement in at_query directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->at_query=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): at_query=%s\n",si->at_query,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"insentry_query"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing SQL statement in insentry_query directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->insentry_query=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): insentry_query=%s\n",si->insentry_query,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0],"delentry_query"))
|
||||
{
|
||||
if (argc<2)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): missing SQL statement in delentry_query directive\n",
|
||||
fname,lineno,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->delentry_query=strdup(argv[1]);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config(): delentry_query=%s\n",si->delentry_query,0,0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_config (%s line %d): unknown directive '%s' (ignored)\n",
|
||||
fname,lineno,argv[0]);
|
||||
return 0;
|
||||
}
|
36
servers/slapd/back-sql/docs/bugs
Normal file
36
servers/slapd/back-sql/docs/bugs
Normal file
@ -0,0 +1,36 @@
|
||||
1) driver name comparison for MS SQL Server workaround is realy kinda dirty
|
||||
hack, but for now i don't know how to code it more carefully
|
||||
2) another dirty hack: length of LONGVARCHAR and LONGVARBINARY fields is
|
||||
currently set to MAX_ATTR_LEN. Maybe such fields must be handled with
|
||||
SQLGetData() instead of SQLBindCol(), but it is said in documentation,
|
||||
that it is guaranteed to work only when such column goes after last bound
|
||||
column. Or should we get ALL columns with SQLGetData (then something like
|
||||
_SQLFetchAsStrings() wrapper would do SQLGetData() for all columns)...
|
||||
4) in some cases (particularly, when using OpenLink Generic ODBC driver with
|
||||
MS SQL Server), it returns "Function sequence error" after all records are
|
||||
fetched. I really don't know what it means, and after all
|
||||
- it works with any other driver I tried
|
||||
5) referral handling. this bug actually addresses all backends, as I can
|
||||
understand. draft-ietf-ldapext-namedref-xx.txt says that referral should be
|
||||
returned for ANY object containing "ref" attribute. And is_entry_referral
|
||||
macro designed for "referral" objectclass only. This limits usability of
|
||||
referrals too much. For instance, I could want to replicate some subtree on
|
||||
another server, storing just "searchable" attributes + referral to full
|
||||
object, and then use this subtree as kind of index for query routing.
|
||||
If search returns referrals only for "referral" entries - I cannot do such
|
||||
thing
|
||||
6) DO NOT EVER USE -O2 option (or any other optimization) under Un*x/gcc!!!
|
||||
I have spent days trying to catch weird bugs, which went gone with optimization off
|
||||
7) The same thing that works on RedHat 6.0 (glibc 2.1.1), dumps core on
|
||||
6.1 (glibc 2.1.2) (the same code behaves differently when built on 6.0 and 6.1)
|
||||
my problem was solved by upgrading iODBC to 3.0 beta - but it is kinda strange
|
||||
that beta works better than release (and release still works fine on 6.0)
|
||||
8) Oracle does case-sensitive comparison of strings by default, so back-sql
|
||||
becomes sensitive too when using Oracle. Later I'll add some option to slapd.conf
|
||||
that would allow to set some function to process values before comparison
|
||||
(something like "before_match UPPER", so that back-sql could generate
|
||||
something like "select ... from ... where ... and UPPER(colname)=UPPER(?) or
|
||||
UPPER(colname) LIKE UPPER(...)")
|
||||
9) ldapsearch sometimes refuses to show some attributes ("NOT PRINTABLE" diags)
|
||||
on Win32 (on linux everything's fine -- at least with mySQL)
|
||||
|
164
servers/slapd/back-sql/docs/concept
Normal file
164
servers/slapd/back-sql/docs/concept
Normal file
@ -0,0 +1,164 @@
|
||||
CONTENT
|
||||
1. Purpose
|
||||
2. Metainformation used
|
||||
3. Typical back-sql operation
|
||||
4. Perspectives on back-sql as effective storage backend (not MAPPER)
|
||||
|
||||
|
||||
1. Purpose
|
||||
Primary purpose of this backend is to PRESENT information stored in some RDBMS
|
||||
as an LDAP subtree. It is being designed to be tunable to virtually any
|
||||
relational schema without having to change source. It is NOT designed as backend
|
||||
that uses RDBMS to store LDAP data (though you can use it for this purpose, it
|
||||
will definitely be not the most effective way).
|
||||
But THIS backend primarily targets the situation when you ALREADY HAVE some
|
||||
data in one or more RDBMSes of one or more different vendors on one or more
|
||||
different hosts and operating systems, having one or more different
|
||||
relational schemas. These could be data used by different software, which you
|
||||
want to integrate, or just local parts of bigger information project. Using
|
||||
LDAP standalone server with back-sql as middleware, you can integrate this
|
||||
heterogeneous information as a single distributed LDAP tree, and even organize
|
||||
data exchange between nodes, not having to worry about unique id's, different
|
||||
schemas etc (****see authordn attribute in samples, and dts_ldap utility).
|
||||
Or, you could simply want to export some information like ISP database to LDAP,
|
||||
to authenticate users, make email lookups or whatever...
|
||||
|
||||
2. Metainformation used
|
||||
***
|
||||
Almost everything mentioned later is illustrated in example, which is located
|
||||
in backsql/RDBMS_DEPENDENT directory, and contains scripts for generating sample
|
||||
database for Oracle,MS SQL Server and mySQL.
|
||||
***
|
||||
First thing that one must arrange for himself is what set of objectclasses
|
||||
can present your RDBMS information. The easiest way is to create objectclass
|
||||
for each entity you had in ER-diagram when designing your relational schema.
|
||||
Or you could choose some other way...
|
||||
Nevertheless, when you think it out, we must define a way to translate LDAP
|
||||
operation requests to (series of) SQL queries. Let us deal with SEARCH
|
||||
operation.
|
||||
|
||||
Example:
|
||||
Lets suppose that we store information about persons working in our
|
||||
organization in two tables:
|
||||
|
||||
PERSONS PHONES
|
||||
---------- -------------
|
||||
id integer id integer
|
||||
first_name varchar pers_id integer references persons(id)
|
||||
last_name varchar phone
|
||||
middle_name varchar
|
||||
...
|
||||
|
||||
(PHONES contains telephone numbers associated with persons). A person can have
|
||||
several numbers, then PHONES contains several records with corresponding
|
||||
pers_id, or no numbers (and no records in PHONES with such pers_id). LDAP
|
||||
objectclass to present such information could look like this:
|
||||
person
|
||||
-------
|
||||
MUST cn
|
||||
MAY telephoneNumber
|
||||
MAY firstName
|
||||
MAY lastName
|
||||
...
|
||||
|
||||
To fetch all values for cn attribute given person ID, we construct the query:
|
||||
SELECT CONCAT(persons.first_name,' ',persons.last_name) as cn FROM persons WHERE persons.id=?
|
||||
|
||||
for telephoneNumber we can use:
|
||||
SELECT phones.phone as telephoneNumber FROM persons,phones WHERE persons.id=phones.pers.id and persons.id=?
|
||||
|
||||
if we wanted to service LDAP request with filter like (telephoneNumber=123*),
|
||||
we would construct something like:
|
||||
SELECT ... FROM persons,phones WHERE persons.id=phones.pers.id and persons.id=? and phones.phone like '123%'
|
||||
|
||||
So, if we had information about what tables contain values for given each
|
||||
attribute, how to join this tables and arrange these values, we could try
|
||||
to automatically generate such statements, and translate search filters
|
||||
to SQL clauses
|
||||
|
||||
To store such information, we add three more tables to our schema, so that
|
||||
and fill it with data (see samples):
|
||||
|
||||
ldap_objclasses
|
||||
---------------
|
||||
id=1
|
||||
name="person"
|
||||
keytbl="persons"
|
||||
keycol="id"
|
||||
create_proc="{call create_person(?)}"
|
||||
delete_proc="{call delete_person(?)}"
|
||||
|
||||
ldap_attrs
|
||||
-----------
|
||||
id=1
|
||||
oc_id=1
|
||||
name="cn"
|
||||
sel_expr="CONCAT(persons.first_name,' ',persons.last_name)"
|
||||
from_tbls="persons"
|
||||
join_where=NULL
|
||||
add_proc=...
|
||||
delete_proc=...
|
||||
************
|
||||
id=<n>
|
||||
oc_id=1
|
||||
name="telephoneNumber"
|
||||
expr="phones.phone"
|
||||
from_tbls="persons,phones"
|
||||
join_where="phones.pers_id=persons.id"
|
||||
add_proc=...
|
||||
delete_proc=...
|
||||
|
||||
|
||||
ldap_entries
|
||||
------------
|
||||
id=1
|
||||
dn=<dn you choose>
|
||||
parent=<parent record id>
|
||||
keyval=<value of primary key>
|
||||
|
||||
First two tables contain structured information about constructing queries like
|
||||
those we made in example. The latter (ldap_entries), contains information about
|
||||
structure of LDAP tree, referencing actual information by key value. Having
|
||||
objectclass id, we can determine table and column which contain primary keys,
|
||||
and load data for the entry attributes using our queries.
|
||||
|
||||
3. Typical back-sql operation
|
||||
Having metainformation loaded, back-sql uses these tables to determine a set
|
||||
of primary keys of candidates (depending on search scope and filter). It tries
|
||||
to do it for each objectclass registered in ldap_objclasses.
|
||||
Exapmle:
|
||||
for our query with filter (telephoneNumber=123*) we would get following
|
||||
query (which loads candidate IDs)
|
||||
SELECT ldap_entries.id,persons.id, 'person' AS objectClass, ldap_entries.dn AS dn FROM ldap_entries,persons,phones WHERE persons.id=ldap_entries.keyval AND ldap_entries.objclass=? AND ldap_entries.parent=? AND phones.pers_id=persons.id AND (phones.phone LIKE '123%')
|
||||
(for ONELEVEL search)
|
||||
or "... AND dn=?" (for BASE search)
|
||||
or "... AND dn LIKE '%?'" (for SUBTREE)
|
||||
|
||||
Then, for each candidate, we load attributes requested using per-attribute queries
|
||||
like
|
||||
|
||||
SELECT phones.phone AS telephoneNumber FROM persons,phones WHERE persons.id=? AND phones.pers_id=persons.id
|
||||
|
||||
Then, we use test_filter() to test entry for full LDAP search filter match (since
|
||||
we cannot effectively make sense of SYNTAX of corresponding LDAP schema attribute,
|
||||
we translate the filter into most relaxed SQL condition to filter candidates),
|
||||
and send it to user.
|
||||
|
||||
ADD,DELETE,MODIFY operations also performed on per-attribute metainformation
|
||||
(add_proc etc.). In those fields one can specify an SQL statement or stored procedure
|
||||
call which can add, or delete given value of given attribute, using given entry
|
||||
keyval (see examples -- mostly ORACLE and MSSQL - since there're no stored procs in mySQL).
|
||||
|
||||
|
||||
4. Perspectives on back-sql as effective storage backend (not MAPPER)
|
||||
Though as I said, back-sql is intended for presenting existing databases to LDAP,
|
||||
and as such is not most effective in presenting LDAP data to RDBMS, I have a couple
|
||||
of ideas on this point, and going to implement this in back-sql using
|
||||
#ifdefs (one that wants to do RDBMS->LDAP, defines one flag, one that wants
|
||||
LDAP->RDBMS, defines another).
|
||||
These tasks have much in common (RDBMS access,connection handling etc), but
|
||||
latter does not need so much additional metainformation.
|
||||
For instance, it may have one table for each attribute type in LDAP schema,
|
||||
and use ldap_entries analog to present tree structure... Later this functionality
|
||||
will be described more closely...
|
||||
|
38
servers/slapd/back-sql/docs/install
Normal file
38
servers/slapd/back-sql/docs/install
Normal file
@ -0,0 +1,38 @@
|
||||
1. Build
|
||||
To build slapd with back-sql under Unix you need to build and install
|
||||
iODBC 2.50.3 (later versions should probably work). Then, run
|
||||
"configure <options you need> --enable-sql [--with-iodbc-includes=<path>] [--with-iodbc-libs=<path>]",
|
||||
this should build back-sql-enabled slapd.
|
||||
|
||||
Under Win32/MSVC++, I modified the workspace so that back-sql is built into
|
||||
slapd automatically, since MS odbc32 is included in standard library pack,
|
||||
and it does no bad even if you don't plan to use it. I also could provide
|
||||
precompiled executables for those who don't have MSVC later (when back-sql
|
||||
comes into some stable state).
|
||||
|
||||
2. Tune datasources and slapd.conf
|
||||
Next, you need to define ODBC datasource with data you want to publish
|
||||
with help of back-sql. Assuming that you have your data in some SQL-compliant
|
||||
RDBMS, and have installed proper ODBC driver for this RDBMS, this is as simple
|
||||
as adding a record into odbc.ini (for iODBC), or using ODBC wizard in
|
||||
Control Panel (for odbc32). Next, you need to add appropriate "database"
|
||||
record to your slapd.conf. See
|
||||
sample provided in "back-sql/RDBMS_DEPENDENT/" subdirectory. The only thing
|
||||
worth noting about this is that "dbname" directive stands for ODBC datasource
|
||||
name, not the name of your database in RDBMS context.
|
||||
|
||||
3. Creating and using back-sql metatables
|
||||
See SQL scripts and slapd.conf files in sample directory .
|
||||
Create db/user whatever for test, execute create.sql, create_testdb.sql,
|
||||
test_data.sql,test_metadata.sql from appropriate directory (use
|
||||
"mysql < xxx.sql" for mySQL, Query Analyzer+Open query file for MS SQL,
|
||||
sqlplus and "@xxx.sql" for Oracle)
|
||||
|
||||
4. Testing
|
||||
To diagnose back-sql, run slapd with debug level TRACE ("slapd -d 5" will go).
|
||||
Then, use some LDAP client to query corresponding subtree (for test database,
|
||||
you could for instance search one level from "o=sql,c=RU"). I personally used
|
||||
saucer, which is included in OpenLDAP package (it builds automatically under
|
||||
Unix/GNU configure and for MSVC I added appropriate project to workspace).
|
||||
And also Java LDAP browser-editor (see link somewhere on OpenLDAP site) to
|
||||
test ADD/DELETE/MODIFY operations on Oracle and MS SQL
|
18
servers/slapd/back-sql/docs/platforms
Normal file
18
servers/slapd/back-sql/docs/platforms
Normal file
@ -0,0 +1,18 @@
|
||||
Platforms and configurations it has been tested on (for now I included only
|
||||
configurations I've tested personally):
|
||||
|
||||
1) slapd on redhat linux 6.0/6.1 (glibc 2.1.1/2.1.2), built with egcs
|
||||
(versions packaged with appropriate red hat):
|
||||
iODBC 2.50.3 (on 6.0), 3.0beta (on 6.1),
|
||||
mySQL (on same linux) 3.22.25,3.22.30 trough myODBC 2.50.23,
|
||||
MSSQL (on WinNT 4/sp3) 7.0 through OpenLink driver suite 3 (broker on NT),
|
||||
Personal Oracle (on WinNT4/sp3) 8.0.3 through OpenLink driver suite 3 (broker on NT),
|
||||
Oracle (on linux 6.0) 8.0.5 through OpenLink driver suite 3 (broker on linux)
|
||||
|
||||
2) slapd on WinNT4/sp3, Win98 second edition, Windows2000pre,
|
||||
built with MSVC++ 5,6:
|
||||
ODBC32.DLL shipped with appropriate system,
|
||||
MSSQL (on WinNT4/sp3,Win98,Win2000) 7.0, through its native driver,
|
||||
Personal Oracle (on WinNT4/sp3,Win98) 8.0.3, through its native driver,
|
||||
Oracle 7 (on Solaris/Sparc 2.6) through its native driver
|
||||
|
178
servers/slapd/back-sql/entry-id.c
Normal file
178
servers/slapd/back-sql/entry-id.c
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "slap.h"
|
||||
#include "back-sql.h"
|
||||
#include "sql-wrap.h"
|
||||
#include "schema-map.h"
|
||||
#include "entry-id.h"
|
||||
#include "util.h"
|
||||
|
||||
backsql_entryID* backsql_free_entryID(backsql_entryID* id)
|
||||
{
|
||||
backsql_entryID* next=id->next;
|
||||
if (id->dn!=NULL)
|
||||
free(id->dn);
|
||||
free(id);
|
||||
return next;
|
||||
}
|
||||
|
||||
backsql_entryID* backsql_dn2id(backsql_entryID *id,SQLHDBC dbh,char *dn)
|
||||
{
|
||||
static char id_query[]="SELECT id,keyval,objclass FROM ldap_entries WHERE dn=?";
|
||||
SQLHSTMT sth;
|
||||
BACKSQL_ROW_NTS row;
|
||||
//SQLINTEGER nrows=0;
|
||||
RETCODE rc;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_dn2id(): dn='%s'\n",dn,0,0);
|
||||
backsql_Prepare(dbh,&sth,id_query,0);
|
||||
if ((rc=backsql_BindParamStr(sth,1,dn,BACKSQL_MAX_DN_LEN)) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_dn2id(): error binding dn parameter:\n",0,0,0);
|
||||
backsql_PrintErrors(SQL_NULL_HENV,dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((rc=SQLExecute(sth)) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_dn2id(): error executing query:\n",0,0,0);
|
||||
backsql_PrintErrors(SQL_NULL_HENV,dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
backsql_BindRowAsStrings(sth,&row);
|
||||
if ((rc=SQLFetch(sth)) == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
|
||||
{
|
||||
if (id==NULL)
|
||||
{
|
||||
id=(backsql_entryID*)ch_calloc(1,sizeof(backsql_entryID));
|
||||
}
|
||||
id->id=atoi(row.cols[0]);
|
||||
id->keyval=atoi(row.cols[1]);
|
||||
id->oc_id=atoi(row.cols[2]);
|
||||
id->dn=strdup(dn);
|
||||
id->next=NULL;
|
||||
}
|
||||
else
|
||||
id=NULL;
|
||||
backsql_FreeRow(&row);
|
||||
|
||||
SQLFreeStmt(sth, SQL_DROP);
|
||||
if (id!=NULL)
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_dn2id(): id=%d\n",(int)id->id,0,0);
|
||||
else
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_dn2id(): no match\n",0,0,0);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
int backsql_get_attr_vals(backsql_at_map_rec *at,backsql_srch_info *bsi)
|
||||
{
|
||||
RETCODE rc;
|
||||
SQLHSTMT sth;
|
||||
BACKSQL_ROW_NTS row;
|
||||
int i;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_get_attr_vals(): oc='%s' attr='%s' keyval=%d\n",
|
||||
bsi->oc->name,at->name,bsi->c_eid->keyval);
|
||||
|
||||
if ((rc=backsql_Prepare(bsi->dbh,&sth,at->query,0)) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error preparing query: %s\n",at->query,0,0);
|
||||
backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (backsql_BindParamID(sth,1,&(bsi->c_eid->keyval)) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error binding key value parameter\n",0,0,0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((rc=SQLExecute(sth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error executing query\n",0,0,0);
|
||||
backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
return 1;
|
||||
}
|
||||
|
||||
backsql_BindRowAsStrings(sth,&row);
|
||||
while ((rc=SQLFetch(sth)) == SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO)
|
||||
{
|
||||
for (i=0;i<row.ncols;i++)
|
||||
{
|
||||
if (row.is_null[i]>0)
|
||||
{
|
||||
backsql_entry_addattr(bsi->e,row.col_names[i],row.cols[i],/*row.col_prec[i]*/
|
||||
strlen(row.cols[i]));
|
||||
// Debug(LDAP_DEBUG_TRACE,"prec=%d\n",(int)row.col_prec[i],0,0);
|
||||
}
|
||||
// else
|
||||
// Debug(LDAP_DEBUG_TRACE,"NULL value in this row for attribute '%s'\n",row.col_names[i],0,0);
|
||||
}
|
||||
}
|
||||
backsql_FreeRow(&row);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_get_attr_vals()\n",0,0,0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Entry* backsql_id2entry(backsql_srch_info *bsi,Entry* e,backsql_entryID* eid)
|
||||
{
|
||||
char **c_at_name;
|
||||
backsql_at_map_rec *at;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_id2entry()\n",0,0,0);
|
||||
|
||||
bsi->oc=backsql_oc_with_id(bsi->bi,eid->oc_id);
|
||||
bsi->e=e;
|
||||
bsi->c_eid=eid;
|
||||
e->e_attrs=NULL;
|
||||
if (bsi->base_dn != NULL)
|
||||
e->e_dn=strdup(bsi->c_eid->dn);
|
||||
|
||||
if (bsi->attrs!=NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_id2entry(): custom attribute list\n",0,0,0);
|
||||
for(c_at_name=bsi->attrs;*c_at_name!=NULL;c_at_name++)
|
||||
{
|
||||
if (!strcasecmp(*c_at_name,"objectclass") || !strcasecmp(*c_at_name,"0.10"))
|
||||
{
|
||||
//backsql_entry_addattr(bsi->e,"objectclass",bsi->oc->name,strlen(bsi->oc->name));
|
||||
continue;
|
||||
}
|
||||
at=backsql_at_with_name(bsi->oc,*c_at_name);
|
||||
if (at!=NULL)
|
||||
backsql_get_attr_vals(at,bsi);
|
||||
else
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_id2entry(): attribute '%s' is not defined for objectlass '%s'\n",
|
||||
*c_at_name,bsi->oc->name,0);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_id2entry(): retrieving all attributes\n",0,0,0);
|
||||
avl_apply(bsi->oc->attrs,(AVL_APPLY)backsql_get_attr_vals,bsi,0,AVL_INORDER);
|
||||
}
|
||||
backsql_entry_addattr(bsi->e,"objectclass",bsi->oc->name,strlen(bsi->oc->name));
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_id2entry()\n",0,0,0);
|
||||
return e;
|
||||
}
|
16
servers/slapd/back-sql/entry-id.h
Normal file
16
servers/slapd/back-sql/entry-id.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __BACKSQL_ENTRYID_H__
|
||||
#define __BACKSQL_ENTRYID_H__
|
||||
|
||||
typedef struct __backsql_entryID
|
||||
{
|
||||
unsigned long id;
|
||||
unsigned long keyval;
|
||||
unsigned long oc_id;
|
||||
char *dn;
|
||||
struct __backsql_entryID *next;
|
||||
}backsql_entryID;
|
||||
|
||||
backsql_entryID* backsql_dn2id(backsql_entryID* id,SQLHDBC dbh,char *dn);
|
||||
backsql_entryID* backsql_free_entryID(backsql_entryID* id);//returns next
|
||||
|
||||
#endif
|
56
servers/slapd/back-sql/external.h
Normal file
56
servers/slapd/back-sql/external.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* $OpenLDAP$ */
|
||||
#ifndef _SQL_EXTERNAL_H
|
||||
#define _SQL_EXTERNAL_H
|
||||
|
||||
LDAP_BEGIN_DECL
|
||||
|
||||
extern int sql_back_initialize LDAP_P(( BackendInfo *bi ));
|
||||
extern int backsql_destroy LDAP_P(( BackendInfo *bi ));
|
||||
|
||||
extern int backsql_db_init LDAP_P(( BackendDB *bd ));
|
||||
extern int backsql_db_open LDAP_P(( BackendDB *bd ));
|
||||
extern int backsql_db_close LDAP_P(( BackendDB *bd ));
|
||||
extern int backsql_db_destroy LDAP_P(( BackendDB *bd ));
|
||||
|
||||
extern int backsql_db_config LDAP_P(( BackendDB *bd,
|
||||
const char *fname, int lineno, int argc, char **argv ));
|
||||
|
||||
extern int backsql_bind LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op,
|
||||
char *dn, char *ndn, int method, char* mech,
|
||||
struct berval *cred, char** edn ));
|
||||
|
||||
extern int backsql_unbind LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op ));
|
||||
|
||||
extern int backsql_search LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op, char *base,
|
||||
char *nbase, int scope, int deref, int sizelimit, int timelimit,
|
||||
Filter *filter, char *filterstr, char **attrs, int attrsonly ));
|
||||
|
||||
extern int backsql_compare LDAP_P((BackendDB *bd,
|
||||
Connection *conn, Operation *op,
|
||||
char *dn, char *ndn, Ava *ava ));
|
||||
|
||||
extern int backsql_modify LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op,
|
||||
char *dn, char *ndn, LDAPModList *ml ));
|
||||
|
||||
extern int backsql_modrdn LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op,
|
||||
char *dn, char *ndn, char*newrdn, int deleteoldrdn,
|
||||
char *newSuperior ));
|
||||
|
||||
extern int backsql_add LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op, Entry *e ));
|
||||
|
||||
extern int backsql_delete LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op, char *dn, char *ndn ));
|
||||
|
||||
extern int backsql_abandon LDAP_P(( BackendDB *bd,
|
||||
Connection *conn, Operation *op, int msgid ));
|
||||
|
||||
LDAP_END_DECL
|
||||
|
||||
#endif /* _SQL_EXTERNAL_H */
|
||||
|
191
servers/slapd/back-sql/init.c
Normal file
191
servers/slapd/back-sql/init.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "slap.h"
|
||||
#include "back-sql.h"
|
||||
#include "sql-wrap.h"
|
||||
#include "schema-map.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef SLAPD_SQL_DYNAMIC
|
||||
|
||||
int backsql_LTX_init_module(int argc, char *argv[]) {
|
||||
BackendInfo bi;
|
||||
|
||||
memset( &bi, 0, sizeof(bi) );
|
||||
bi.bi_type = "sql";
|
||||
bi.bi_init = backbacksql_initialize;
|
||||
|
||||
backend_add(&bi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SLAPD_SHELL_DYNAMIC */
|
||||
|
||||
int sql_back_initialize(
|
||||
BackendInfo *bi
|
||||
)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_initialize()\n",0,0,0);
|
||||
bi->bi_open = 0;
|
||||
bi->bi_config = 0;
|
||||
bi->bi_close = 0;
|
||||
bi->bi_destroy = 0;
|
||||
|
||||
bi->bi_db_init = backsql_db_init;
|
||||
bi->bi_db_config = backsql_db_config;
|
||||
bi->bi_db_open = backsql_db_open;
|
||||
bi->bi_db_close = backsql_db_close;
|
||||
bi->bi_db_destroy = backsql_db_destroy;
|
||||
|
||||
#ifdef BACKSQL_ALL_DONE
|
||||
bi->bi_op_abandon = backsql_abandon;
|
||||
bi->bi_op_compare = backsql_compare;
|
||||
#else
|
||||
bi->bi_op_abandon = 0;
|
||||
bi->bi_op_compare = 0;
|
||||
#endif
|
||||
bi->bi_op_bind = backsql_bind;
|
||||
bi->bi_op_unbind = backsql_unbind;
|
||||
bi->bi_op_search = backsql_search;
|
||||
bi->bi_op_modify = backsql_modify;
|
||||
bi->bi_op_modrdn = backsql_modrdn;
|
||||
bi->bi_op_add = backsql_add;
|
||||
bi->bi_op_delete = backsql_delete;
|
||||
|
||||
bi->bi_acl_group = 0;
|
||||
|
||||
bi->bi_connection_init = 0;
|
||||
bi->bi_connection_destroy = 0;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_initialize()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int backsql_destroy ( BackendInfo *bi )
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_destroy()\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_destroy()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_db_init(BackendDB *bd)
|
||||
{
|
||||
backsql_info *si;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_db_init()\n",0,0,0);
|
||||
si = (backsql_info *) ch_calloc( 1, sizeof(backsql_info) );
|
||||
ldap_pvt_thread_mutex_init(&si->dbconn_mutex);
|
||||
ldap_pvt_thread_mutex_init(&si->schema_mutex);
|
||||
backsql_init_db_env(si);
|
||||
|
||||
bd->be_private=si;
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_init()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_db_destroy(BackendDB *bd)
|
||||
{
|
||||
backsql_info *si=(backsql_info*)bd->be_private;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_db_destroy()\n",0,0,0);
|
||||
ldap_pvt_thread_mutex_lock(&si->dbconn_mutex);
|
||||
backsql_free_db_env(si);
|
||||
ldap_pvt_thread_mutex_unlock(&si->dbconn_mutex);
|
||||
ldap_pvt_thread_mutex_lock(&si->schema_mutex);
|
||||
backsql_destroy_schema_map(si);
|
||||
ldap_pvt_thread_mutex_unlock(&si->schema_mutex);
|
||||
ldap_pvt_thread_mutex_destroy(&si->schema_mutex);
|
||||
ldap_pvt_thread_mutex_destroy(&si->dbconn_mutex);
|
||||
free(si->dbname);
|
||||
free(si->dbuser);
|
||||
if (si->dbpasswd)
|
||||
free(si->dbpasswd);
|
||||
if (si->dbhost)
|
||||
free(si->dbhost);
|
||||
free(si->subtree_cond);
|
||||
free(si->oc_query);
|
||||
free(si->at_query);
|
||||
free(si->insentry_query);
|
||||
free(si->delentry_query);
|
||||
free(si);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_destroy()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_db_open (BackendDB *bd)
|
||||
{
|
||||
backsql_info *si=(backsql_info*)bd->be_private;
|
||||
Connection tmp;
|
||||
SQLHDBC dbh;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_db_open(): testing RDBMS connection\n",0,0,0);
|
||||
if (si->dbname==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): datasource name not specified (use dbname directive in slapd.conf)\n",0,0,0);
|
||||
return 1;
|
||||
}
|
||||
if (si->dbuser==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): user name not specified (use dbuser directive in slapd.conf)\n",0,0,0);
|
||||
return 1;
|
||||
}
|
||||
if (si->subtree_cond==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): subtree search SQL condition not specified (use subtree_cond directive in slapd.conf)\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): setting '%s' as default\n",backsql_def_subtree_cond,0,0);
|
||||
si->subtree_cond=strdup(backsql_def_subtree_cond);
|
||||
}
|
||||
if (si->oc_query==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): objectclass mapping SQL statement not specified (use oc_query directive in slapd.conf)\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): setting '%s' by default\n",backsql_def_oc_query,0,0);
|
||||
si->oc_query=strdup(backsql_def_oc_query);
|
||||
}
|
||||
if (si->at_query==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): attribute mapping SQL statement not specified (use at_query directive in slapd.conf)\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): setting '%s' by default\n",backsql_def_at_query,0,0);
|
||||
si->at_query=strdup(backsql_def_at_query);
|
||||
}
|
||||
if (si->insentry_query==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): entry insertion SQL statement not specified (use insentry_query directive in slapd.conf)\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): setting '%s' by default\n",backsql_def_insentry_query,0,0);
|
||||
si->insentry_query=strdup(backsql_def_insentry_query);
|
||||
}
|
||||
if (si->delentry_query==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): entry deletion SQL statement not specified (use delentry_query directive in slapd.conf)\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): setting '%s' by default\n",backsql_def_delentry_query,0,0);
|
||||
si->delentry_query=strdup(backsql_def_delentry_query);
|
||||
}
|
||||
tmp.c_connid=-1;
|
||||
dbh=backsql_get_db_conn(bd,&tmp);
|
||||
if (!dbh)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_db_open(): connection failed, exiting\n",0,0,0);
|
||||
return 1;
|
||||
}
|
||||
backsql_free_db_conn(bd,&tmp);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_open(): test succeeded, schema map loaded\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_db_close(BackendDB *bd)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_db_close()\n",0,0,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_db_close()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
409
servers/slapd/back-sql/modify.c
Normal file
409
servers/slapd/back-sql/modify.c
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include "portable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "slap.h"
|
||||
#include "back-sql.h"
|
||||
#include "sql-wrap.h"
|
||||
#include "schema-map.h"
|
||||
#include "entry-id.h"
|
||||
#include "util.h"
|
||||
|
||||
int backsql_modify(BackendDB *be,Connection *conn,Operation *op,
|
||||
char *dn,char *ndn,LDAPModList *modlist)
|
||||
{
|
||||
backsql_info *bi=(backsql_info*)be->be_private;
|
||||
SQLHDBC dbh;
|
||||
SQLHSTMT sth;
|
||||
RETCODE rc;
|
||||
backsql_oc_map_rec *oc=NULL;
|
||||
backsql_entryID e_id,*res;
|
||||
LDAPModList *c_mod;
|
||||
backsql_at_map_rec *at=NULL;
|
||||
struct berval *at_val;
|
||||
int i;
|
||||
|
||||
dn=dn_validate(dn);
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_modify(): changing entry '%s'\n",dn,0,0);
|
||||
dbh=backsql_get_db_conn(be,conn);
|
||||
if (!dbh)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): could not get connection handle - exiting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
res=backsql_dn2id(&e_id,dbh,dn);
|
||||
if (res==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): could not lookup entry id\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,"",NULL,NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
oc=backsql_oc_with_id(bi,e_id.oc_id);
|
||||
if (oc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): cannot determine objectclass of entry -- aborting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SQLAllocStmt(dbh, &sth);
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): traversing modifications list\n",0,0,0);
|
||||
for(c_mod=modlist;c_mod!=NULL;c_mod=c_mod->ml_next)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): attribute '%s'\n",c_mod->ml_type,0,0);
|
||||
at=backsql_at_with_name(oc,c_mod->ml_type);
|
||||
if (at==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): attribute provided is not registered in this objectclass ('%s')\n",c_mod->ml_type,0,0);
|
||||
continue;
|
||||
}
|
||||
SQLBindParameter(sth,1,SQL_PARAM_INPUT,SQL_C_ULONG,SQL_INTEGER,0,0,&e_id.keyval,0,0);
|
||||
switch(c_mod->ml_op)
|
||||
{
|
||||
case LDAP_MOD_REPLACE:
|
||||
{
|
||||
char *query;
|
||||
int qlen;
|
||||
SQLHSTMT asth;
|
||||
BACKSQL_ROW_NTS row;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): replacing values for attribute '%s'\n",at->name,0,0);
|
||||
if (at->add_proc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): add procedure is not defined for this attribute ('%s') - unable to perform replacements\n",at->name,0,0);
|
||||
break;
|
||||
}
|
||||
del_all:
|
||||
query=NULL;
|
||||
qlen=0;
|
||||
query=backsql_strcat(query,&qlen,"SELECT ",at->sel_expr," AS ",at->name,
|
||||
" FROM ",at->from_tbls,
|
||||
" WHERE ",oc->keytbl,".",oc->keycol,"=?",NULL);
|
||||
if (at->join_where!=NULL && at->join_where[0]!='\0')
|
||||
query=backsql_strcat(query,&qlen," AND ",at->join_where,NULL);
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify() constructed query to get all existing values: %s\n",query,0,0);
|
||||
if ((rc=backsql_Prepare(dbh,&asth,query,0)) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error preparing query\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,asth,rc);
|
||||
free(query);
|
||||
break;
|
||||
}
|
||||
free(query);
|
||||
|
||||
if (backsql_BindParamID(asth,1,&e_id.keyval) != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error binding key value parameter\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,asth,rc);
|
||||
SQLFreeStmt(asth,SQL_DROP);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((rc=SQLExecute(asth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_get_attr_values(): error executing attribute query\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,asth,rc);
|
||||
SQLFreeStmt(asth,SQL_DROP);
|
||||
break;
|
||||
}
|
||||
|
||||
backsql_BindRowAsStrings(asth,&row);
|
||||
while ((rc=SQLFetch(asth)) == SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO)
|
||||
{
|
||||
for (i=0;i<row.ncols;i++)
|
||||
{
|
||||
SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,0,0,row.cols[i],strlen(row.cols[i]),0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): executing '%s'\n",at->delete_proc,0,0);
|
||||
rc=SQLExecDirect(sth,at->delete_proc,SQL_NTS);
|
||||
if (rc!=SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): delete_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
backsql_FreeRow(&row);
|
||||
SQLFreeStmt(asth,SQL_DROP);
|
||||
}
|
||||
//PASSTHROUGH - to add new attributes -- do NOT add break
|
||||
case LDAP_MOD_ADD:
|
||||
if (at->add_proc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): add procedure is not defined for this attribute ('%s')\n",at->name,0,0);
|
||||
break;
|
||||
}
|
||||
if (c_mod->ml_bvalues==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): no values given to add for attribute '%s'\n",at->name,0,0);
|
||||
break;
|
||||
}
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): adding new values for attribute '%s'\n",at->name,0,0);
|
||||
for(i=0,at_val=c_mod->ml_bvalues[0];at_val!=NULL;i++,at_val=c_mod->ml_bvalues[i])
|
||||
{
|
||||
//check for syntax here - maybe need binary bind?
|
||||
SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,0,0,at_val->bv_val,at_val->bv_len,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): executing '%s'\n",at->add_proc,0,0);
|
||||
rc=SQLExecDirect(sth,at->add_proc,SQL_NTS);
|
||||
if (rc!=SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): add_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LDAP_MOD_DELETE:
|
||||
if (at->delete_proc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): delete procedure is not defined for this attribute ('%s')\n",at->name,0,0);
|
||||
break;
|
||||
}
|
||||
if (c_mod->ml_bvalues==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): no values given to delete for attribute '%s' -- deleting all values\n",at->name,0,0);
|
||||
goto del_all;
|
||||
}
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): deleting values for attribute '%s'\n",at->name,0,0);
|
||||
for(i=0,at_val=c_mod->ml_bvalues[0];at_val!=NULL;i++,at_val=c_mod->ml_bvalues[i])
|
||||
{
|
||||
//check for syntax here - maybe need binary bind?
|
||||
SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,0,0,at_val->bv_val,at_val->bv_len,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): executing '%s'\n",at->delete_proc,0,0);
|
||||
rc=SQLExecDirect(sth,at->delete_proc,SQL_NTS);
|
||||
if (rc!=SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_modify(): delete_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_RESET_PARAMS);
|
||||
}
|
||||
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_SUCCESS,"",NULL,NULL,NULL);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_modify()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_modrdn(BackendDB *be,Connection *conn,Operation *op,
|
||||
char *dn,char *ndn,char *newrdn,int deleteoldrdn,char *newSuperior)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_modrdn()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_add(BackendDB *be,Connection *conn,Operation *op,Entry *e)
|
||||
{
|
||||
backsql_info *bi=(backsql_info*)be->be_private;
|
||||
SQLHDBC dbh;
|
||||
SQLHSTMT sth;
|
||||
unsigned long new_keyval;
|
||||
long i;
|
||||
RETCODE rc;
|
||||
backsql_oc_map_rec *oc=NULL;
|
||||
backsql_at_map_rec *at_rec=NULL;
|
||||
backsql_entryID parent_id,*res;
|
||||
Attribute *at;
|
||||
struct berval *at_val;
|
||||
char *pdn;
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_add(): adding entry '%s'\n",e->e_dn,0,0);
|
||||
if (dn_validate(e->e_dn)==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_add(): invalid dn '%s' -- aborting\n",e->e_dn,0,0);
|
||||
}
|
||||
for(at=e->e_attrs;at!=NULL;at=at->a_next)
|
||||
{
|
||||
//Debug(LDAP_DEBUG_TRACE,"backsql_add(): scanning entry -- %s\n",at->a_type,0,0);
|
||||
if (!strcasecmp(at->a_type,"objectclass"))
|
||||
{
|
||||
oc=backsql_oc_with_name(bi,at->a_vals[0]->bv_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): cannot determine objectclass of entry -- aborting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
if (oc->create_proc == NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): create procedure is not defined for this objectclass - aborting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dbh=backsql_get_db_conn(be,conn);
|
||||
if (!dbh)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): could not get connection handle - exiting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SQLAllocStmt(dbh, &sth);
|
||||
SQLBindParameter(sth,1,SQL_PARAM_OUTPUT,SQL_C_ULONG,SQL_INTEGER,0,0,&new_keyval,0,0);
|
||||
//SQLBindParameter(sth,2,SQL_PARAM_OUTPUT,SQL_C_SLONG,SQL_INTEGER,0,0,&retcode,0,0);
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): executing '%s'\n",oc->create_proc,0,0);
|
||||
rc=SQLExecDirect(sth,oc->create_proc,SQL_NTS);
|
||||
if (rc != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): create_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_RESET_PARAMS);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): create_proc returned keyval=%d\n",new_keyval,0,0);
|
||||
|
||||
for(at=e->e_attrs;at!=NULL;at=at->a_next)
|
||||
{
|
||||
at_rec=backsql_at_with_name(oc,at->a_type);
|
||||
if (at_rec==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): attribute provided is not registered in this objectclass ('%s')\n",at->a_type,0,0);
|
||||
continue;
|
||||
}
|
||||
if (at_rec->add_proc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): add procedure is not defined for this attribute ('%s')\n",at->a_type,0,0);
|
||||
continue;
|
||||
}
|
||||
SQLBindParameter(sth,1,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&new_keyval,0,0);
|
||||
for(i=0,at_val=at->a_vals[0];at_val!=NULL;i++,at_val=at->a_vals[i])
|
||||
{
|
||||
//if (at->a_syntax==SYNTAX_BIN)
|
||||
// SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_BINARY,0,0,at_val->bv_val,0,0);
|
||||
//else
|
||||
SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,0,0,at_val->bv_val,at_val->bv_len,0);
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): executing '%s'\n",at_rec->add_proc,0,0);
|
||||
rc=SQLExecDirect(sth,at_rec->add_proc,SQL_NTS);
|
||||
if (rc!=SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): add_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_RESET_PARAMS);
|
||||
pdn=dn_parent(be,e->e_dn);
|
||||
res=backsql_dn2id(&parent_id,dbh,pdn);
|
||||
if (res==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): could not lookup parent entry for new record ('%s')\n",
|
||||
pdn,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
free(pdn);
|
||||
backsql_BindParamStr(sth,1,e->e_dn,BACKSQL_MAX_DN_LEN);
|
||||
SQLBindParameter(sth,2,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&oc->id,0,0);
|
||||
SQLBindParameter(sth,3,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&parent_id.id,0,0);
|
||||
SQLBindParameter(sth,4,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&new_keyval,0,0);
|
||||
rc=SQLExecDirect(sth,bi->insentry_query,SQL_NTS);
|
||||
if (rc != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_add(): could not insert ldap_entries record\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
//execute delete_proc to delete data added !!!
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_SUCCESS,"",NULL,NULL,NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backsql_delete(BackendDB *be,Connection *conn,Operation *op,
|
||||
char *dn,char *ndn)
|
||||
{
|
||||
backsql_info *bi=(backsql_info*)be->be_private;
|
||||
SQLHDBC dbh;
|
||||
SQLHSTMT sth;
|
||||
RETCODE rc;
|
||||
backsql_oc_map_rec *oc=NULL;
|
||||
backsql_entryID e_id,*res;
|
||||
|
||||
dn=dn_validate(dn);
|
||||
Debug(LDAP_DEBUG_TRACE,"==>backsql_delete(): deleting entry '%s'\n",dn,0,0);
|
||||
dbh=backsql_get_db_conn(be,conn);
|
||||
if (!dbh)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): could not get connection handle - exiting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
res=backsql_dn2id(&e_id,dbh,dn);
|
||||
if (res==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): could not lookup entry id\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,"",NULL,NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
oc=backsql_oc_with_id(bi,e_id.oc_id);
|
||||
if (oc==NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): cannot determine objectclass of entry -- aborting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
if (oc->delete_proc == NULL)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): delete procedure is not defined for this objectclass - aborting\n",0,0,0);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SQLAllocStmt(dbh, &sth);
|
||||
SQLBindParameter(sth,1,SQL_PARAM_INPUT,SQL_C_ULONG,SQL_INTEGER,0,0,&e_id.keyval,0,0);
|
||||
//SQLBindParameter(sth,2,SQL_PARAM_OUTPUT,SQL_C_SLONG,SQL_INTEGER,0,0,&retcode,0,0);
|
||||
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): executing '%s'\n",oc->delete_proc,0,0);
|
||||
rc=SQLExecDirect(sth,oc->delete_proc,SQL_NTS);
|
||||
if (rc != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): delete_proc execution failed\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_RESET_PARAMS);
|
||||
|
||||
SQLBindParameter(sth,1,SQL_PARAM_INPUT,SQL_C_ULONG,SQL_INTEGER,0,0,&e_id.id,0,0);
|
||||
rc=SQLExecDirect(sth,bi->delentry_query,SQL_NTS);
|
||||
if (rc != SQL_SUCCESS)
|
||||
{
|
||||
Debug(LDAP_DEBUG_TRACE,"backsql_delete(): failed to delete record from ldap_entries\n",0,0,0);
|
||||
backsql_PrintErrors(bi->db_env,dbh,sth,rc);
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
|
||||
return 1;
|
||||
}
|
||||
SQLFreeStmt(sth,SQL_DROP);
|
||||
|
||||
send_ldap_result(conn,op,LDAP_SUCCESS,"",NULL,NULL,NULL);
|
||||
Debug(LDAP_DEBUG_TRACE,"<==backsql_delete()\n",0,0,0);
|
||||
return 0;
|
||||
}
|
33
servers/slapd/back-sql/schema-map.h
Normal file
33
servers/slapd/back-sql/schema-map.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __BACKSQL_SCHEMA_MAP_H__
|
||||
#define __BACKSQL_SCHEMA_MAP_H__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *keytbl;
|
||||
char *keycol;
|
||||
char *create_proc;//expected to return keyval of newly created entry
|
||||
char *delete_proc;//supposed to expect keyval as parameter and delete all the attributes as well
|
||||
unsigned long id;
|
||||
Avlnode *attrs;
|
||||
}backsql_oc_map_rec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;//literal name of corresponding LDAP attribute type
|
||||
char *from_tbls;
|
||||
char *join_where;
|
||||
char *sel_expr;
|
||||
char *add_proc; //supposed to expect 2 binded values: entry keyval and attr. value to add, like "add_name(?,?)"
|
||||
char *modify_proc; //supposed to expect two binded values: entry keyval and old and new values of attr
|
||||
char *delete_proc; //supposed to expect 2 binded values: entry keyval and attr. value to delete
|
||||
char *query; //for optimization purposes attribute load query is preconstructed from parts on schemamap load time
|
||||
}backsql_at_map_rec;
|
||||
|
||||
int backsql_load_schema_map(backsql_info *si,SQLHDBC dbh);
|
||||
backsql_oc_map_rec* backsql_oc_with_name(backsql_info *si,char* objclass);
|
||||
backsql_oc_map_rec* backsql_oc_with_id(backsql_info *si,unsigned long id);
|
||||
backsql_at_map_rec* backsql_at_with_name(backsql_oc_map_rec* objclass,char* attr);
|
||||
int backsql_destroy_schema_map(backsql_info *si);
|
||||
|
||||
#endif
|
25
servers/slapd/back-sql/sql-types.h
Normal file
25
servers/slapd/back-sql/sql-types.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __BACKSQL_SQL_TYPES_H__
|
||||
#define __BACKSQL_SQL_TYPES_H__
|
||||
|
||||
/*
|
||||
* Copyright 1999, Dmitry Kovalev (zmit@mail.ru), All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SWORD ncols;
|
||||
char** col_names;
|
||||
UDWORD *col_prec;
|
||||
char** cols;
|
||||
SQLINTEGER* is_null;
|
||||
}BACKSQL_ROW_NTS;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user