--- /dev/null
+/*
+ * 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_dummy()
+{
+ return 0;
+}
+
+int backsql_compare(BackendDB *be,Connection *conn,Operation *op,
+ char *dn,char *ndn,Ava *ava)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_compare()\n",0,0,0);
+ return 0;
+}
+
+int backsql_abandon( BackendDB *be,
+ Connection *conn, Operation *op, int msgid )
+{
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_abandon()\n",0,0,0);
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_abandon()\n",0,0,0);
+ return 0;
+}
--- /dev/null
+CREATE TABLE ldap_attrs (
+ id int IDENTITY (1, 1) NOT NULL ,
+ oc_id int NOT NULL ,
+ name varchar (255) NOT NULL ,
+ sel_expr varchar (255) NOT NULL ,
+ from_tbls varchar (255) NOT NULL ,
+ join_where varchar (255) NULL ,
+ add_proc varchar (255) NULL ,
+ modify_proc varchar (255) NULL ,
+ delete_proc varchar (255) NULL
+)
+GO
+
+CREATE TABLE ldap_entries (
+ id int IDENTITY (1, 1) NOT NULL ,
+ dn varchar (255) NOT NULL ,
+ objclass int NOT NULL ,
+ parent int NOT NULL ,
+ keyval int NOT NULL
+)
+GO
+
+CREATE TABLE ldap_objclasses (
+ id int IDENTITY (1, 1) NOT NULL ,
+ name varchar (64) NOT NULL ,
+ keytbl varchar (64) NOT NULL ,
+ keycol varchar (64) NOT NULL ,
+ create_proc varchar (255) NULL ,
+ delete_proc varchar (255) NULL
+)
+GO
+
+
+ALTER TABLE ldap_attrs WITH NOCHECK ADD
+ CONSTRAINT PK_ldap_attrs PRIMARY KEY
+ (
+ id
+ )
+GO
+
+ALTER TABLE ldap_entries WITH NOCHECK ADD
+ CONSTRAINT PK_ldap_entries PRIMARY KEY
+ (
+ id
+ )
+GO
+
+ALTER TABLE ldap_entries WITH NOCHECK ADD
+ CONSTRAINT UNQ1_ldap_entries UNIQUE
+ (
+ objclass,
+ keyval
+ )
+GO
+
+ALTER TABLE ldap_entries WITH NOCHECK ADD
+ CONSTRAINT UNQ2_ldap_entries UNIQUE
+ (
+ dn
+ )
+GO
+
+ALTER TABLE ldap_objclasses WITH NOCHECK ADD
+ CONSTRAINT PK_ldap_objclasses PRIMARY KEY
+ (
+ id
+ )
+GO
+
+
+ALTER TABLE ldap_objclasses WITH NOCHECK ADD
+ CONSTRAINT UNQ_ldap_objclasses UNIQUE
+ (
+ name
+ )
+GO
--- /dev/null
+
+CREATE TABLE authors_docs (
+ pers_id int NOT NULL ,
+ doc_id int NOT NULL
+)
+GO
+
+CREATE TABLE documents (
+ id int IDENTITY (1, 1) NOT NULL ,
+ abstract varchar (255) NULL ,
+ title varchar (255) NULL ,
+ body binary (255) NULL
+)
+GO
+
+CREATE TABLE institutes (
+ id int IDENTITY (1, 1) NOT NULL ,
+ name varchar (255) NOT NULL
+)
+GO
+
+
+CREATE TABLE persons (
+ id int IDENTITY (1, 1) NOT NULL ,
+ name varchar (255) NULL
+)
+GO
+
+CREATE TABLE phones (
+ id int IDENTITY (1, 1) NOT NULL ,
+ phone varchar (255) NOT NULL ,
+ pers_id int NOT NULL
+)
+GO
+
+ALTER TABLE authors_docs WITH NOCHECK ADD
+ CONSTRAINT PK_authors_docs PRIMARY KEY
+ (
+ pers_id,
+ doc_id
+ )
+GO
+
+ALTER TABLE documents WITH NOCHECK ADD
+ CONSTRAINT PK_documents PRIMARY KEY
+ (
+ id
+ )
+GO
+
+ALTER TABLE institutes WITH NOCHECK ADD
+ CONSTRAINT PK_institutes PRIMARY KEY
+ (
+ id
+ )
+GO
+
+
+ALTER TABLE persons WITH NOCHECK ADD
+ CONSTRAINT PK_persons PRIMARY KEY
+ (
+ id
+ )
+GO
+
+ALTER TABLE phones WITH NOCHECK ADD
+ CONSTRAINT PK_phones PRIMARY KEY
+ (
+ id
+ )
+GO
+
+SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON
+GO
+
+CREATE PROCEDURE add_phone @pers_id int, @phone varchar(255) AS
+INSERT INTO ldap.phones (pers_id,phone) VALUES (@pers_id,@phone)
+GO
+
+CREATE PROCEDURE create_person @@keyval int OUTPUT AS
+INSERT INTO ldap.persons (name) VALUES ('');
+set @@keyval=(SELECT MAX(id) FROM ldap.persons)
+GO
+
+CREATE PROCEDURE delete_person @keyval int AS
+DELETE FROM ldap.phones WHERE pers_id=@keyval;
+DELETE FROM ldap.authors_docs WHERE pers_id=@keyval;
+DELETE FROM ldap.persons WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE create_org @@keyval int OUTPUT AS
+INSERT INTO ldap.institutes (name) VALUES ('');
+set @@keyval=(SELECT MAX(id) FROM ldap.institutes)
+GO
+
+CREATE PROCEDURE create_document @@keyval int OUTPUT AS
+INSERT INTO ldap.documents (title) VALUES ('');
+set @@keyval=(SELECT MAX(id) FROM ldap.documents)
+GO
+
+CREATE PROCEDURE delete_org @keyval int AS
+DELETE FROM ldap.institutes WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE delete_document @keyval int AS
+DELETE FROM ldap.authors_docs WHERE doc_id=@keyval;
+DELETE FROM ldap.documents WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE delete_phone @keyval int,@phone varchar(64) AS
+DELETE FROM ldap.phones WHERE pers_id=@keyval AND phone=@phone;
+GO
+
+CREATE PROCEDURE set_person_name @keyval int, @new_name varchar(255) AS
+UPDATE ldap.persons SET name=@new_name WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE set_org_name @keyval int, @new_name varchar(255) AS
+UPDATE ldap.institutes SET name=@new_name WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE set_doc_title @keyval int, @new_title varchar(255) AS
+UPDATE ldap.documents SET title=@new_title WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE set_doc_abstract @keyval int, @new_abstract varchar(255) AS
+UPDATE ldap.documents SET abstract=@new_abstract WHERE id=@keyval;
+GO
+
+CREATE PROCEDURE make_author_link @keyval int, @author_dn varchar(255) AS
+DECLARE @per_id int;
+SET @per_id=(SELECT keyval FROM ldap.ldap_entries
+ WHERE objclass=1 AND dn=@author_dn);
+IF NOT (@per_id IS NULL)
+ INSERT INTO ldap.authors_docs (doc_id,pers_id) VALUES (@keyval,@per_id);
+GO
+
+CREATE PROCEDURE make_doc_link @keyval int, @doc_dn varchar(255) AS
+DECLARE @doc_id int;
+SET @doc_id=(SELECT keyval FROM ldap.ldap_entries
+ WHERE objclass=2 AND dn=@doc_dn);
+IF NOT (@doc_id IS NULL)
+ INSERT INTO ldap.authors_docs (pers_id,doc_id) VALUES (@keyval,@doc_id);
+GO
+
+CREATE PROCEDURE del_doc_link @keyval int, @doc_dn varchar(255) AS
+DECLARE @doc_id int;
+SET @doc_id=(SELECT keyval FROM ldap.ldap_entries
+ WHERE objclass=2 AND dn=@doc_dn);
+IF NOT (@doc_id IS NULL)
+DELETE FROM ldap.authors_docs WHERE pers_id=@keyval AND doc_id=@doc_id;
+GO
+
+CREATE PROCEDURE del_author_link @keyval int, @author_dn varchar(255) AS
+DECLARE @per_id int;
+SET @per_id=(SELECT keyval FROM ldap.ldap_entries
+ WHERE objclass=1 AND dn=@author_dn);
+IF NOT (@per_id IS NULL)
+ DELETE FROM ldap.authors_docs WHERE doc_id=@keyval AND pers_id=@per_id;
+GO
--- /dev/null
+
+if exists (select * from sysobjects where id = object_id(N'ldap_attrs') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table ldap_attrs
+GO
+
+if exists (select * from sysobjects where id = object_id(N'ldap_entries') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table ldap_entries
+GO
+
+if exists (select * from sysobjects where id = object_id(N'ldap_objclasses') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table ldap_objclasses
+GO
+
--- /dev/null
+drop procedure create_person
+drop procedure set_person_name
+drop procedure delete_phone
+drop procedure add_phone
+drop procedure make_doc_link
+drop procedure del_doc_link
+drop procedure delete_person
+
+drop procedure create_org
+drop procedure set_org_name
+drop procedure delete_org
+
+drop procedure create_document
+drop procedure set_doc_title
+drop procedure set_doc_abstract
+drop procedure make_author_link
+drop procedure del_author_link
+drop procedure delete_document
+
+if exists (select * from sysobjects where id = object_id(N'authors_docs') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table authors_docs
+GO
+
+if exists (select * from sysobjects where id = object_id(N'documents') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table documents
+GO
+
+if exists (select * from sysobjects where id = object_id(N'institutes') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table institutes
+GO
+
+if exists (select * from sysobjects where id = object_id(N'persons') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table persons
+GO
+
+if exists (select * from sysobjects where id = object_id(N'phones') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table phones
+GO
+
--- /dev/null
+# $OpenLDAP$
+#
+# See slapd.conf(5) for details on configuration options.
+# This file should NOT be world readable.
+#
+include ./slapd.at.conf
+include ./slapd.oc.conf
+
+# Define global ACLs to disable default read access.
+
+# Do not enable referrals until AFTER you have a working directory
+# service AND an understanding of referrals.
+#referral ldap://root.openldap.org
+
+pidfile ./slapd.pid
+argsfile ./slapd.args
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+#database ldbm
+#suffix "dc=your-domain, dc=com"
+#suffix "o=Your Organization Name, c=US"
+#directory /usr/tmp
+#rootdn "cn=root, dc=your-domain, dc=com"
+#rootdn "cn=root, o=Your Organization Name, c=US"
+#rootpw secret
+# cleartext passwords, especially for the rootdn, should
+# be avoid. See slapd.conf(5) for details.
+
+database sql
+suffix "o=sql,c=RU"
+rootdn "cn=root,o=sql,c=RU"
+rootpw secret
+dbname ldap_mssql
+dbuser ldap
+dbpasswd ldap
+subtree_cond "ldap_entries.dn LIKE '%'+?"
--- /dev/null
+set IDENTITY_INSERT institutes ON
+insert into institutes (id,name) values (1,'sql')
+set IDENTITY_INSERT institutes OFF
+
+set IDENTITY_INSERT persons ON
+insert into persons (id,name) values (1,'Mitya Kovalev')
+insert into persons (id,name) values (2,'Torvlobnor Puzdoy')
+insert into persons (id,name) values (3,'Akakiy Zinberstein')
+set IDENTITY_INSERT persons OFF
+
+set IDENTITY_INSERT phones ON
+insert into phones (id,phone,pers_id) values (1,'332-2334',1)
+insert into phones (id,phone,pers_id) values (2,'222-3234',1)
+insert into phones (id,phone,pers_id) values (3,'545-4563',2)
+set IDENTITY_INSERT phones OFF
+
+set IDENTITY_INSERT documents ON
+insert into documents (id,abstract,title) values (1,'abstract1','book1')
+insert into documents (id,abstract,title) values (2,'abstract2','book2')
+set IDENTITY_INSERT documents OFF
+
+insert into authors_docs (pers_id,doc_id) values (1,1)
+insert into authors_docs (pers_id,doc_id) values (1,2)
+insert into authors_docs (pers_id,doc_id) values (2,1)
+
+SET IDENTITY_INSERT ldap_entries ON
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (1,'o=sql,c=RU',3,0,1)
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (2,'cn=Mitya Kovalev,o=sql,c=RU',1,1,1)
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (3,'cn=Torvlobnor Puzdoy,o=sql,c=RU',1,1,2)
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (4,'cn=Akakiy Zinberstein,o=sql,c=RU',1,1,3)
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (5,'documentTitle=book1,o=sql,c=RU',2,1,1)
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (6,'documentTitle=book2,o=sql,c=RU',2,1,2)
+
+SET IDENTITY_INSERT ldap_entries OFF
--- /dev/null
+
+
+SET IDENTITY_INSERT ldap_objclasses ON
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (1,'person','persons','id','{call create_person(?)}','{call delete_person(?)}')
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (2,'document','documents','id','{call create_document(?)}','{call delete_document(?)}')
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (3,'organization','institutes','id','{call create_org(?)}','{call delete_org(?)}')
+SET IDENTITY_INSERT ldap_objclasses OFF
+
+
+SET IDENTITY_INSERT ldap_attrs ON
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (1,1,'cn','persons.name','persons',NULL,'{call set_person_name(?,?)}',
+ NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (2,1,'telephoneNumber','phones.phone','persons,phones',
+ 'phones.pers_id=persons.id','{call add_phone(?,?)}',
+ NULL,'{call delete_phone(?,?)}')
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (3,1,'sn','persons.name','persons',NULL,'{call set_person_name(?,?)}',
+ NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (4,2,'abstract','documents.abstract','documents',NULL,'{call set_doc_abstract(?,?)}',
+ NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (5,2,'documentTitle','documents.title','documents',NULL,'{call set_doc_title(?,?)}',
+ NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (6,2,'documentAuthor','persons.name','persons,documents,authors_docs',
+ 'persons.id=authors_docs.pers_id AND documents.id=authors_docs.doc_id',
+ NULL,NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (7,3,'o','institutes.name','institutes',NULL,'{call set_org_name(?,?)}',
+ NULL,NULL)
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (8,1,'documentDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=documents.id AND ldap_entries.objclass=2 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ '{call make_doc_link(?,?)}',NULL,'{call del_doc_link(?,?)}')
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (9,2,'authorDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=persons.id AND ldap_entries.objclass=1 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ '{call make_author_link(?,?)}',NULL,'{call del_author_link(?,?)}')
+
+SET IDENTITY_INSERT ldap_attrs OFF
--- /dev/null
+CREATE TABLE ldap_attrs (
+ id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ oc_id int NOT NULL,
+ name varchar(255) NOT NULL,
+ sel_expr varchar(255) NOT NULL,
+ from_tbls varchar(255) NOT NULL,
+ join_where varchar(255),
+ add_proc varchar(255),
+ modify_proc varchar(255),
+ delete_proc varchar(255)
+);
+
+
+CREATE TABLE ldap_entries (
+ id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ dn varchar(255) NOT NULL ,
+ objclass int NOT NULL ,
+ parent int NOT NULL ,
+ keyval int NOT NULL
+);
+
+
+CREATE TABLE ldap_objclasses (
+ id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ name varchar(64) NOT NULL ,
+ keytbl varchar(64) NOT NULL ,
+ keycol varchar(64) NOT NULL ,
+ create_proc varchar(255),
+ delete_proc varchar(255)
+);
+
+ALTER TABLE ldap_entries ADD
+ CONSTRAINT UNQ1_ldap_entries UNIQUE
+ (
+ objclass,
+ keyval
+ );
+
+ALTER TABLE ldap_entries ADD
+ CONSTRAINT UNQ2_ldap_entries UNIQUE
+ (
+ dn
+ );
+
+
+ALTER TABLE ldap_objclasses ADD
+ CONSTRAINT UNQ_ldap_objclasses UNIQUE
+ (
+ name
+ );
--- /dev/null
+CREATE TABLE persons (
+ id int NOT NULL,
+ name varchar(255) NOT NULL
+);
+
+CREATE TABLE institutes (
+ id int NOT NULL,
+ name varchar(255)
+);
+
+CREATE TABLE documents (
+ id int NOT NULL,
+ title varchar(255) NOT NULL,
+ abstract varchar(255)
+);
+
+CREATE TABLE authors_docs (
+ pers_id int NOT NULL,
+ doc_id int NOT NULL
+);
+
+CREATE TABLE phones (
+ id int NOT NULL ,
+ phone varchar(255) NOT NULL ,
+ pers_id int NOT NULL
+);
+
+
+
+ALTER TABLE authors_docs ADD
+ CONSTRAINT PK_authors_docs PRIMARY KEY
+ (
+ pers_id,
+ doc_id
+ );
+
+ALTER TABLE documents ADD
+ CONSTRAINT PK_documents PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE institutes ADD
+ CONSTRAINT PK_institutes PRIMARY KEY
+ (
+ id
+ );
+
+
+ALTER TABLE persons ADD
+ CONSTRAINT PK_persons PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE phones ADD
+ CONSTRAINT PK_phones PRIMARY KEY
+ (
+ id
+ );
+
--- /dev/null
+DROP TABLE IF EXISTS ldap_attrs;
+
+DROP TABLE IF EXISTS ldap_entries;
+
+DROP TABLE IF EXISTS ldap_objclasses;
--- /dev/null
+DROP TABLE IF EXISTS persons;
+DROP TABLE IF EXISTS institutes;
+DROP TABLE IF EXISTS documents;
+DROP TABLE IF EXISTS authors_docs;
+DROP TABLE IF EXISTS phones;
--- /dev/null
+# $OpenLDAP$
+#
+# See slapd.conf(5) for details on configuration options.
+# This file should NOT be world readable.
+#
+include /usr/local/etc/openldap/slapd.at.conf
+include /usr/local/etc/openldap/slapd.oc.conf
+
+# Define global ACLs to disable default read access.
+
+# Do not enable referrals until AFTER you have a working directory
+# service AND an understanding of referrals.
+#referral ldap://root.openldap.org
+
+pidfile /usr/local/var/slapd.pid
+argsfile /usr/local/var/slapd.args
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+database sql
+suffix "o=sql,c=RU"
+rootdn "cn=root,o=sql,c=RU"
+rootpw secret
+dbname ldap_mysql
+dbuser root
+dbpasswd
+subtree_cond "ldap_entries.dn LIKE CONCAT('%',?)"
+insentry_query "INSERT INTO ldap_entries (dn,objclass,parent,keyval) VALUES (?,?,?,?)"
--- /dev/null
+insert into institutes (id,name) values (1,'sql');
+
+insert into persons (id,name) values (1,'Mitya Kovalev');
+insert into persons (id,name) values (2,'Torvlobnor Puzdoy');
+insert into persons (id,name) values (3,'Akakiy Zinberstein');
+
+insert into phones (id,phone,pers_id) values (1,'332-2334',1);
+insert into phones (id,phone,pers_id) values (2,'222-3234',1);
+insert into phones (id,phone,pers_id) values (3,'545-4563',2);
+
+insert into documents (id,abstract,title) values (1,'abstract1','book1');
+insert into documents (id,abstract,title) values (2,'abstract2','book2');
+
+insert into authors_docs (pers_id,doc_id) values (1,1);
+insert into authors_docs (pers_id,doc_id) values (1,2);
+insert into authors_docs (pers_id,doc_id) values (2,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (1,'o=sql,c=RU',3,0,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (2,'cn=Mitya Kovalev,o=sql,c=RU',1,1,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (3,'cn=Torvlobnor Puzdoy,o=sql,c=RU',1,1,2);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (4,'cn=Akakiy Zinberstein,o=sql,c=RU',1,1,3);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (5,'documentTitle=book1,o=sql,c=RU',2,1,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (6,'documentTitle=book2,o=sql,c=RU',2,1,2);
--- /dev/null
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (1,'person','persons','id',NULL,NULL);
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (2,'document','documents','id',NULL,NULL);
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (3,'organization','institutes','id',NULL,NULL);
+
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (1,1,'cn','persons.name','persons',NULL,NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (2,1,'telephoneNumber','phones.phone','persons,phones',
+ 'phones.pers_id=persons.id',NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (3,1,'sn','persons.name','persons',NULL,NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (4,2,'abstract','documents.abstract','documents',NULL,NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (5,2,'documentTitle','documents.title','documents',NULL,NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (6,2,'documentAuthor','persons.name','persons,documents,authors_docs',
+ 'persons.id=authors_docs.pers_id AND documents.id=authors_docs.doc_id',
+ NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (7,3,'o','institutes.name','institutes',NULL,NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (8,1,'documentDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=documents.id AND ldap_entries.objclass=2 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (9,2,'authorDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=persons.id AND ldap_entries.objclass=1 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ NULL,NULL,NULL);
--- /dev/null
+CREATE TABLE ldap_attrs (
+ id NUMBER NOT NULL,
+ oc_id NUMBER NOT NULL,
+ name varchar2(255) NOT NULL,
+ sel_expr varchar2(255) NOT NULL,
+ from_tbls varchar2(255) NOT NULL,
+ join_where varchar2(255),
+ add_proc varchar2(255),
+ modify_proc varchar2(255),
+ delete_proc varchar2(255)
+);
+
+
+CREATE TABLE ldap_entries (
+ id NUMBER NOT NULL ,
+ dn varchar2(255) NOT NULL ,
+ objclass NUMBER NOT NULL ,
+ parent NUMBER NOT NULL ,
+ keyval NUMBER NOT NULL
+);
+
+
+CREATE TABLE ldap_objclasses (
+ id NUMBER NOT NULL ,
+ name varchar2(64) NOT NULL ,
+ keytbl varchar2(64) NOT NULL ,
+ keycol varchar2(64) NOT NULL ,
+ create_proc varchar2(255),
+ delete_proc varchar2(255)
+);
+
+
+ALTER TABLE ldap_attrs ADD
+ CONSTRAINT PK_ldap_attrs PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE ldap_entries ADD
+ CONSTRAINT PK_ldap_entries PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE ldap_objclasses ADD
+ CONSTRAINT PK_ldap_objclasses PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE ldap_entries ADD
+ CONSTRAINT UNQ1_ldap_entries UNIQUE
+ (
+ objclass,
+ keyval
+ );
+
+ALTER TABLE ldap_entries ADD
+ CONSTRAINT UNQ2_ldap_entries UNIQUE
+ (
+ dn
+ );
+
+
+ALTER TABLE ldap_objclasses ADD
+ CONSTRAINT UNQ_ldap_objclasses UNIQUE
+ (
+ name
+ );
+
+
+CREATE SEQUENCE ldap_objclass_ids START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE ldap_attr_ids START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE ldap_entry_ids START WITH 1 INCREMENT BY 1;
--- /dev/null
+CREATE TABLE persons (
+ id NUMBER NOT NULL,
+ name varchar2(255) NOT NULL
+);
+
+CREATE TABLE institutes (
+ id NUMBER NOT NULL,
+ name varchar2(255)
+);
+
+CREATE TABLE documents (
+ id NUMBER NOT NULL,
+ title varchar2(255) NOT NULL,
+ abstract varchar2(255)
+);
+
+CREATE TABLE authors_docs (
+ pers_id NUMBER NOT NULL,
+ doc_id NUMBER NOT NULL
+);
+
+CREATE TABLE phones (
+ id NUMBER NOT NULL ,
+ phone varchar2(255) NOT NULL ,
+ pers_id NUMBER NOT NULL
+);
+
+
+ALTER TABLE authors_docs ADD
+ CONSTRAINT PK_authors_docs PRIMARY KEY
+ (
+ pers_id,
+ doc_id
+ );
+
+ALTER TABLE documents ADD
+ CONSTRAINT PK_documents PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE institutes ADD
+ CONSTRAINT PK_institutes PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE persons ADD
+ CONSTRAINT PK_persons PRIMARY KEY
+ (
+ id
+ );
+
+ALTER TABLE phones ADD
+ CONSTRAINT PK_phones PRIMARY KEY
+ (
+ id
+ );
+
+CREATE SEQUENCE person_ids START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE document_ids START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE institute_ids START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE phone_ids START WITH 1 INCREMENT BY 1;
+
+CREATE OR REPLACE PROCEDURE create_person(keyval OUT NUMBER) AS
+BEGIN
+INSERT INTO persons (id,name) VALUES (person_ids.nextval,' ');
+SELECT person_ids.currval INTO keyval FROM DUAL;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE delete_person(keyval IN NUMBER) AS
+BEGIN
+DELETE FROM phones WHERE pers_id=keyval;
+DELETE FROM authors_docs WHERE pers_id=keyval;
+DELETE FROM persons WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE create_org(keyval OUT NUMBER) AS
+BEGIN
+INSERT INTO institutes (id,name) VALUES (institute_ids.nextval,' ');
+SELECT institute_ids.currval INTO keyval FROM DUAL;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE delete_org(keyval IN NUMBER) AS
+BEGIN
+DELETE FROM institutes WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE create_document(keyval OUT NUMBER) AS
+BEGIN
+INSERT INTO documents (id,title) VALUES (document_ids.nextval,' ');
+SELECT document_ids.currval INTO keyval FROM DUAL;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE delete_document (keyval IN NUMBER) AS
+BEGIN
+DELETE FROM authors_docs WHERE doc_id=keyval;
+DELETE FROM documents WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE add_phone(pers_id IN NUMBER, phone IN varchar2) AS
+BEGIN
+INSERT INTO phones (id,pers_id,phone) VALUES (phone_ids.nextval,pers_id,phone);
+END;
+/
+
+CREATE OR REPLACE PROCEDURE delete_phone(keyval IN NUMBER, phone IN varchar2) AS
+BEGIN
+DELETE FROM phones WHERE pers_id=keyval AND phone=phone;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE set_person_name(keyval IN NUMBER, new_name IN varchar2) AS
+BEGIN
+UPDATE persons SET name=new_name WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE set_org_name(keyval IN NUMBER, new_name IN varchar2) AS
+BEGIN
+UPDATE institutes SET name=new_name WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE set_doc_title (keyval IN NUMBER, new_title IN varchar2) AS
+BEGIN
+UPDATE documents SET title=new_title WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE set_doc_abstract (keyval IN NUMBER, new_abstract IN varchar2) AS
+BEGIN
+UPDATE documents SET abstract=new_abstract WHERE id=keyval;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE make_author_link (keyval IN NUMBER, author_dn IN varchar2) AS
+per_id NUMBER;
+BEGIN
+SELECT keyval INTO per_id FROM ldap_entries
+ WHERE objclass=1 AND dn=author_dn;
+IF NOT (per_id IS NULL) THEN
+ INSERT INTO authors_docs (doc_id,pers_id) VALUES (keyval,per_id);
+END IF;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE make_doc_link (keyval IN NUMBER, doc_dn IN varchar2) AS
+docid NUMBER;
+BEGIN
+SELECT keyval INTO docid FROM ldap_entries
+ WHERE objclass=2 AND dn=doc_dn;
+IF NOT (docid IS NULL) THEN
+ INSERT INTO authors_docs (pers_id,doc_id) VALUES (keyval,docid);
+END IF;
+END;
+/
+
+CREATE OR REPLACE PROCEDURE del_doc_link (keyval IN NUMBER, doc_dn IN varchar2) AS
+docid NUMBER;
+BEGIN
+SELECT keyval INTO docid FROM ldap_entries
+ WHERE objclass=2 AND dn=doc_dn;
+IF NOT (docid IS NULL) THEN
+ DELETE FROM authors_docs WHERE pers_id=keyval AND doc_id=docid;
+END IF;
+END;
+/
+
+CREATE PROCEDURE del_author_link (keyval IN NUMBER, author_dn IN varchar2) AS
+per_id NUMBER;
+BEGIN
+SELECT keyval INTO per_id FROM ldap_entries
+ WHERE objclass=1 AND dn=author_dn;
+
+IF NOT (per_id IS NULL) THEN
+ DELETE FROM authors_docs WHERE doc_id=keyval AND pers_id=per_id;
+END IF;
+END;
+/
+
--- /dev/null
+DROP TABLE ldap_attrs;
+DROP TABLE ldap_entries;
+DROP TABLE ldap_objclasses;
+DROP SEQUENCE ldap_entry_ids;
+DROP SEQUENCE ldap_attr_ids;
+DROP SEQUENCE ldap_objclass_ids;
+
--- /dev/null
+DROP TABLE persons;
+DROP TABLE institutes;
+DROP TABLE documents;
+DROP TABLE authors_docs;
+DROP TABLE phones;
+DROP SEQUENCE person_ids;
+DROP SEQUENCE institute_ids;
+DROP SEQUENCE document_ids;
+DROP SEQUENCE phone_ids;
+DROP PROCEDURE create_person;
+DROP PROCEDURE delete_person;
+DROP PROCEDURE add_phone;
+DROP PROCEDURE delete_phone;
+DROP PROCEDURE set_person_name;
+DROP PROCEDURE set_org_name;
+DROP PROCEDURE set_doc_title;
+DROP PROCEDURE set_doc_abstract;
+DROP PROCEDURE create_document;
+DROP PROCEDURE create_org;
+DROP PROCEDURE delete_document;
+DROP PROCEDURE delete_org;
+DROP PROCEDURE make_doc_link;
+DROP PROCEDURE del_doc_link;
+DROP PROCEDURE make_author_link;
+DROP PROCEDURE del_author_link;
--- /dev/null
+# $OpenLDAP$
+#
+# See slapd.conf(5) for details on configuration options.
+# This file should NOT be world readable.
+#
+include ./slapd.at.conf
+include ./slapd.oc.conf
+
+# Define global ACLs to disable default read access.
+
+# Do not enable referrals until AFTER you have a working directory
+# service AND an understanding of referrals.
+#referral ldap://root.openldap.org
+
+pidfile ./slapd.pid
+argsfile ./slapd.args
+
+#######################################################################
+# ldbm database definitions
+#######################################################################
+
+#database ldbm
+#suffix "dc=your-domain, dc=com"
+#suffix "o=Your Organization Name, c=US"
+#directory /usr/tmp
+#rootdn "cn=root, dc=your-domain, dc=com"
+#rootdn "cn=root, o=Your Organization Name, c=US"
+#rootpw secret
+# cleartext passwords, especially for the rootdn, should
+# be avoid. See slapd.conf(5) for details.
+
+database sql
+suffix "o=sql,c=RU"
+rootdn "cn=root,o=sql,c=RU"
+rootpw secret
+#dbname ldap_ora8_ms
+dbname ldap_ora8
+dbuser ldap
+dbpasswd ldap
+subtree_cond "ldap_entries.dn LIKE CONCAT('%',?)"
+insentry_query "INSERT INTO ldap_entries (id,dn,objclass,parent,keyval) VALUES (ldap_entry_ids.nextval,?,?,?,?)"
--- /dev/null
+insert into institutes (id,name) values (institute_ids.nextval,'sql');
+
+insert into persons (id,name) values (person_ids.nextval,'Mitya Kovalev');
+
+insert into persons (id,name) values (person_ids.nextval,'Torvlobnor Puzdoy');
+
+insert into persons (id,name) values (person_ids.nextval,'Akakiy Zinberstein');
+
+
+insert into phones (id,phone,pers_id) values (phone_ids.nextval,'332-2334',1);
+
+insert into phones (id,phone,pers_id) values (phone_ids.nextval,'222-3234',1);
+
+insert into phones (id,phone,pers_id) values (phone_ids.nextval,'545-4563',2);
+
+
+insert into documents (id,abstract,title) values (document_ids.nextval,'abstract1','book1');
+
+insert into documents (id,abstract,title) values (document_ids.nextval,'abstract2','book2');
+
+
+insert into authors_docs (pers_id,doc_id) values (1,1);
+
+insert into authors_docs (pers_id,doc_id) values (1,2);
+
+insert into authors_docs (pers_id,doc_id) values (2,1);
+
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'o=sql,c=RU',3,0,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'cn=Mitya Kovalev,o=sql,c=RU',1,1,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'cn=Torvlobnor Puzdoy,o=sql,c=RU',1,1,2);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'cn=Akakiy Zinberstein,o=sql,c=RU',1,1,3);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'documentTitle=book1,o=sql,c=RU',2,1,1);
+
+insert into ldap_entries (id,dn,objclass,parent,keyval)
+values (ldap_entry_ids.nextval,'documentTitle=book2,o=sql,c=RU',2,1,2);
--- /dev/null
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (1,'person','persons','id','{call create_person(?)}','{call delete_person(?)}');
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (2,'document','documents','id','{call create_document(?)}','{call delete_document(?)}');
+
+insert into ldap_objclasses (id,name,keytbl,keycol,create_proc,delete_proc)
+values (3,'organization','institutes','id','{call create_org(?)}','{call delete_org(?)}');
+
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (1,1,'cn','persons.name','persons',NULL,'{call set_person_name(?,?)}',
+ NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (2,1,'telephoneNumber','phones.phone','persons,phones',
+ 'phones.pers_id=persons.id','{call add_phone(?,?)}',
+ NULL,'{call delete_phone(?,?)}');
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (3,1,'sn','persons.name','persons',NULL,'{call set_person_name(?,?)}',
+ NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (4,2,'abstract','documents.abstract','documents',NULL,'{call set_doc_abstract(?,?)}',
+ NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (5,2,'documentTitle','documents.title','documents',NULL,'{call set_doc_title(?,?)}',
+ NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (6,2,'documentAuthor','persons.name','persons,documents,authors_docs',
+ 'persons.id=authors_docs.pers_id AND documents.id=authors_docs.doc_id',
+ NULL,NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (7,3,'o','institutes.name','institutes',NULL,'{call set_org_name(?,?)}',
+ NULL,NULL);
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (8,1,'documentDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=documents.id AND ldap_entries.objclass=2 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ '{call make_doc_link(?,?)}',NULL,'{call del_doc_link(?,?)}');
+
+insert into ldap_attrs (id,oc_id,name,sel_expr,from_tbls,join_where,add_proc,modify_proc,delete_proc)
+values (9,2,'authorDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons',
+ 'ldap_entries.keyval=persons.id AND ldap_entries.objclass=1 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',
+ '{call make_author_link(?,?)}',NULL,'{call del_author_link(?,?)}');
--- /dev/null
+/*
+ * 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 "util.h"
+
+int backsql_dummy(void *,void *);
+
+int backsql_cmp_oc_name(backsql_oc_map_rec *m1,backsql_oc_map_rec *m2)
+{
+ return strcasecmp(m1->name,m2->name);
+}
+
+int backsql_cmp_oc_id(backsql_oc_map_rec *m1,backsql_oc_map_rec *m2)
+{
+ if (m1->id < m2->id)
+ return -1;
+ if (m1->id > m2->id)
+ return 1;
+ return 0;
+}
+
+int backsql_cmp_attr(backsql_at_map_rec *m1,backsql_at_map_rec *m2)
+{
+ return strcasecmp(m1->name,m2->name);
+}
+
+int backsql_load_schema_map(backsql_info *si,SQLHDBC dbh)
+{
+ SQLHSTMT oc_sth,at_sth;
+ RETCODE rc;
+ BACKSQL_ROW_NTS oc_row,at_row;
+ unsigned long oc_id;
+ backsql_oc_map_rec *oc_map;
+ backsql_at_map_rec *at_map;
+ char *tmps;
+ int tmpslen;
+
+ Debug(LDAP_DEBUG_TRACE,"==>load_schema_map()\n",0,0,0);
+ rc=backsql_Prepare(dbh,&oc_sth,si->oc_query,0);
+ if (rc != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): error preparing oc_query: '%s'\n",si->oc_query,0,0);
+ backsql_PrintErrors(si->db_env,dbh,oc_sth,rc);
+ return -1;
+ }
+ rc=backsql_Prepare(dbh,&at_sth,si->at_query,0);
+ if (rc != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): error preparing at_query: '%s'\n",si->at_query,0,0);
+ backsql_PrintErrors(si->db_env,dbh,at_sth,rc);
+ return -1;
+ }
+ if ((rc=backsql_BindParamID(at_sth,1,&oc_id)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): error binding param for at_query: \n",0,0,0);
+ backsql_PrintErrors(si->db_env,dbh,at_sth,rc);
+ return -1;
+ }
+ if ((rc=SQLExecute(oc_sth)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): error executing oc_query: \n",0,0,0);
+ backsql_PrintErrors(si->db_env,dbh,oc_sth,rc);
+ return -1;
+ }
+ backsql_BindRowAsStrings(oc_sth,&oc_row);
+ while ((rc=SQLFetch(oc_sth)) == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
+ {
+ oc_map=(backsql_oc_map_rec*)ch_calloc(1,sizeof(backsql_oc_map_rec));
+ oc_map->id=atoi(oc_row.cols[0]);
+ oc_map->name=strdup(oc_row.cols[1]);
+ oc_map->keytbl=strdup(oc_row.cols[2]);
+ oc_map->keycol=strdup(oc_row.cols[3]);
+ oc_map->create_proc=(oc_row.is_null[4]<0)?NULL:strdup(oc_row.cols[4]);
+ oc_map->delete_proc=(oc_row.is_null[5]<0)?NULL:strdup(oc_row.cols[5]);
+ oc_map->attrs=NULL;
+ avl_insert(&si->oc_by_name,oc_map,(AVL_CMP)backsql_cmp_oc_name,backsql_dummy);
+ avl_insert(&si->oc_by_id,oc_map,(AVL_CMP)backsql_cmp_oc_id,backsql_dummy);
+ oc_id=oc_map->id;
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): objectclass '%s': keytbl='%s' keycol='%s' ",
+ oc_row.cols[1],oc_row.cols[2],oc_row.cols[3]);
+ Debug(LDAP_DEBUG_TRACE,"create_proc='%s' delete_proc='%s' ; attributes:\n",oc_row.cols[4],
+ oc_row.cols[5],0);
+ if ((rc=SQLExecute(at_sth)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): error executing at_query: \n",0,0,0);
+ backsql_PrintErrors(SQL_NULL_HENV,dbh,at_sth,rc);
+ return -1;
+ }
+ backsql_BindRowAsStrings(at_sth,&at_row);
+ while ((rc=SQLFetch(at_sth)) == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
+ {
+ Debug(LDAP_DEBUG_TRACE,"********'%s'\n",at_row.cols[0],0,0);
+ Debug(LDAP_DEBUG_TRACE,"name='%s',sel_expr='%s' from='%s' ",at_row.cols[0],
+ at_row.cols[1],at_row.cols[2]);
+ Debug(LDAP_DEBUG_TRACE,"join_where='%s',add_proc='%s' modify_proc='%s' ",at_row.cols[3],
+ at_row.cols[4],at_row.cols[5]);
+ Debug(LDAP_DEBUG_TRACE,"delete_proc='%s'\n",at_row.cols[6],0,0);
+ at_map=(backsql_at_map_rec*)ch_calloc(1,sizeof(backsql_at_map_rec));
+ at_map->name=strdup(at_row.cols[0]);
+ at_map->sel_expr=strdup(at_row.cols[1]);
+ tmps=NULL;tmpslen=0;
+ backsql_merge_from_clause(&tmps,&tmpslen,at_row.cols[2]);
+ at_map->from_tbls=strdup(tmps);
+ ch_free(tmps);
+ at_map->join_where=strdup((at_row.is_null[3]<0)?"":at_row.cols[3]);
+ at_map->add_proc=(at_row.is_null[4]<0)?NULL:strdup(at_row.cols[4]);
+ at_map->modify_proc=(at_row.is_null[5]<0)?NULL:strdup(at_row.cols[5]);
+ at_map->delete_proc=(at_row.is_null[6]<0)?NULL:strdup(at_row.cols[6]);
+ tmps=NULL;tmpslen=0;
+ tmps=backsql_strcat(tmps,&tmpslen,"SELECT ",at_map->sel_expr," AS ",at_map->name,
+ " FROM ",at_map->from_tbls,
+ " WHERE ",oc_map->keytbl,".",oc_map->keycol,"=?",NULL);
+ if (at_map->join_where!=NULL && at_map->join_where[0]!='\0')
+ tmps=backsql_strcat(tmps,&tmpslen," AND ",at_map->join_where,NULL);
+ at_map->query=strdup(tmps);
+ ch_free(tmps);
+ Debug(LDAP_DEBUG_TRACE,"load_schema_map(): preconstructed query '%s'\n",at_map->query,0,0);
+ avl_insert(&oc_map->attrs,at_map,(AVL_CMP)backsql_cmp_attr,backsql_dummy);
+ }
+ backsql_FreeRow(&at_row);
+ SQLFreeStmt(at_sth,SQL_CLOSE);
+ }
+ backsql_FreeRow(&oc_row);
+ SQLFreeStmt(at_sth,SQL_DROP);
+ SQLFreeStmt(oc_sth,SQL_DROP);
+ si->schema_loaded=1;
+ Debug(LDAP_DEBUG_TRACE,"<==load_schema_map()\n",0,0,0);
+ return 1;
+}
+
+backsql_oc_map_rec* backsql_oc_with_name(backsql_info *si,char* objclass)
+{
+ backsql_oc_map_rec tmp,*res;
+
+// Debug(LDAP_DEBUG_TRACE,"==>oc_with_name(): searching for objectclass with name='%s'\n",objclass,0,0);
+ tmp.name=objclass;
+ res=(backsql_oc_map_rec*)avl_find(si->oc_by_name,&tmp,(AVL_CMP)backsql_cmp_oc_name);
+// if (res!=NULL)
+// Debug(LDAP_DEBUG_TRACE,"<==oc_with_name(): found name='%s', id=%d\n",res->name,res->id,0);
+// else
+// Debug(LDAP_DEBUG_TRACE,"<==oc_with_name(): not found\n",0,0,0);
+ return res;
+}
+
+backsql_oc_map_rec* backsql_oc_with_id(backsql_info *si,unsigned long id)
+{
+ backsql_oc_map_rec tmp,*res;
+
+// Debug(LDAP_DEBUG_TRACE,"==>oc_with_id(): searching for objectclass with id='%d'\n",id,0,0);
+ tmp.id=id;
+ res=(backsql_oc_map_rec*)avl_find(si->oc_by_id,&tmp,(AVL_CMP)backsql_cmp_oc_id);
+// if (res!=NULL)
+// Debug(LDAP_DEBUG_TRACE,"<==oc_with_name(): found name='%s', id=%d\n",res->name,res->id,0);
+// else
+// Debug(LDAP_DEBUG_TRACE,"<==oc_with_name(): not found\n",0,0,0);
+ return res;
+}
+
+backsql_at_map_rec* backsql_at_with_name(backsql_oc_map_rec* objclass,char* attr)
+{
+ backsql_at_map_rec tmp,*res;
+
+ //Debug(LDAP_DEBUG_TRACE,"==>at_with_name(): searching for attribute with name='%s' (for objectclass '%s')\n",
+ // attr,objclass->name,0);
+ tmp.name=attr;
+ res=(backsql_at_map_rec*)avl_find(objclass->attrs,&tmp,(AVL_CMP)backsql_cmp_attr);
+ //if (res!=NULL)
+ //Debug(LDAP_DEBUG_TRACE,"<==at_with_name(): found name='%s', sel_expr='%s'\n",
+ // res->name,res->sel_expr,0);
+ //else
+ // Debug(LDAP_DEBUG_TRACE,"<==at_with_name(): not found\n",0,0,0);
+ return res;
+}
+
+int backsql_free_attr(backsql_at_map_rec *at)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>free_attr(): '%s'\n",at->name,0,0);
+ ch_free(at->name);
+ ch_free(at->sel_expr);
+ if (at->from_tbls!=NULL)
+ ch_free(at->from_tbls);
+ if (at->join_where!=NULL)
+ ch_free(at->join_where);
+ if (at->add_proc!=NULL)
+ ch_free(at->add_proc);
+ if (at->modify_proc!=NULL)
+ ch_free(at->modify_proc);
+ if (at->delete_proc!=NULL)
+ ch_free(at->delete_proc);
+ if (at->query)
+ ch_free(at->query);
+ ch_free(at);
+ Debug(LDAP_DEBUG_TRACE,"<==free_attr()\n",0,0,0);
+ return 1;
+}
+
+int backsql_free_oc(backsql_oc_map_rec *oc)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>free_oc(): '%s'\n",oc->name,0,0);
+ avl_free(oc->attrs,(AVL_FREE)backsql_free_attr);
+ ch_free(oc->name);
+ ch_free(oc->keytbl);
+ ch_free(oc->keycol);
+ if (oc->create_proc!=NULL)
+ ch_free(oc->create_proc);
+ if (oc->delete_proc!=NULL)
+ ch_free(oc->delete_proc);
+ ch_free(oc);
+ Debug(LDAP_DEBUG_TRACE,"<==free_oc()\n",0,0,0);
+ return 1;
+}
+
+int backsql_destroy_schema_map(backsql_info *si)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>destroy_schema_map()\n",0,0,0);
+ avl_free(si->oc_by_id,(AVL_FREE)backsql_free_oc);
+ avl_free(si->oc_by_name,(AVL_FREE)backsql_dummy);
+ Debug(LDAP_DEBUG_TRACE,"<==destroy_schema_map()\n",0,0,0);
+ return 0;
+}
--- /dev/null
+/*
+ * 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_attrlist_add(backsql_srch_info *bsi,char *at_name)
+{
+ char **p=bsi->attrs;
+ int n_attrs=0;
+
+ if (bsi->attrs==NULL)
+ return 1;
+
+ while(*p)
+ {
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): attribute '%s' is in list\n",*p,0,0);
+ if (!strcasecmp(*p,at_name))
+ return 1;
+ n_attrs++;
+ p++;
+ }
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_attrlist_add(): adding '%s' to list\n",at_name,0,0);
+ bsi->attrs=(char**)ch_realloc(bsi->attrs,(n_attrs+2)*sizeof(char*));
+ bsi->attrs[n_attrs]=strdup(at_name);
+ bsi->attrs[n_attrs+1]=NULL;
+ return 1;
+}
+
+void backsql_init_search(backsql_srch_info *bsi,backsql_info *bi,char *nbase,int scope,
+ int slimit,int tlimit,time_t stoptime,Filter *filter,
+ SQLHDBC dbh,Backend *be,Connection *conn,Operation *op,char **attrs)
+{
+ char **p;
+ bsi->base_dn=nbase;
+ bsi->scope=scope;
+ bsi->slimit=slimit;
+ bsi->tlimit=tlimit;
+ bsi->filter=filter;
+ bsi->dbh=dbh;
+ bsi->be=be;
+ bsi->conn=conn;
+ bsi->op=op;
+ if (attrs!=NULL)
+ {
+ bsi->attrs=(char**)ch_calloc(1,sizeof(char*));
+ bsi->attrs[0]=NULL;
+ for(p=attrs;*p!=NULL;p++)
+ backsql_attrlist_add(bsi,*p);
+ }
+ else
+ bsi->attrs=attrs;
+ bsi->abandon=0;
+ bsi->id_list=NULL;
+ bsi->stoptime=stoptime;
+ bsi->bi=bi;
+ bsi->sel=NULL; bsi->from=NULL; bsi->join_where=NULL; bsi->flt_where=NULL;
+ bsi->sel_len=0; bsi->from_len=0; bsi->jwhere_len=0; bsi->fwhere_len=0;
+}
+
+int backsql_process_filter_list(backsql_srch_info *bsi,Filter *f,int op)
+{
+ char *sub_clause=NULL;
+ int len=0,res;
+
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",NULL);
+ while(1)
+ {
+ res=backsql_process_filter(bsi,f);
+
+ if (res==-1)
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," 1=0 ",NULL);
+
+ f=f->f_next;
+ if (f==NULL)
+ break;
+
+ switch (op)
+ {
+ case LDAP_FILTER_AND:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," AND ",NULL);
+ break;
+ case LDAP_FILTER_OR:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len," OR ",NULL);
+ break;
+ }
+ }
+
+
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
+ return 1;
+}
+
+int backsql_process_sub_filter(backsql_srch_info *bsi,Filter *f)
+{
+ int i;
+
+ backsql_at_map_rec *at=backsql_at_with_name(bsi->oc,f->f_sub_type);
+
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,
+ " LIKE '",NULL);
+ if (f->f_sub_initial!=NULL)
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_initial,NULL);
+
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"%",NULL);
+
+ if (f->f_sub_any!=NULL)
+ for(i=0;f->f_sub_any[i]!=NULL;i++)
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_any[i],"%",NULL);
+
+ if (f->f_sub_final!=NULL)
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,f->f_sub_final,NULL);
+
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"')",NULL);
+
+ return 1;
+}
+
+int backsql_process_filter(backsql_srch_info *bsi,Filter *f)
+{
+ backsql_at_map_rec *at;
+ backsql_at_map_rec oc_attr={"objectClass","","",NULL,NULL,NULL,NULL};
+ char *at_name=NULL;
+ int done=0,len=0;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_process_filter()\n",0,0,0);
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_OR:
+ backsql_process_filter_list(bsi,f->f_or,LDAP_FILTER_OR);
+ done=1;
+ break;
+ case LDAP_FILTER_AND:
+ backsql_process_filter_list(bsi,f->f_and,LDAP_FILTER_AND);
+ done=1;
+ break;
+ case LDAP_FILTER_NOT:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",NULL);
+ backsql_process_filter(bsi,f->f_not);
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,")",NULL);
+ done=1;
+ break;
+ case LDAP_FILTER_PRESENT:
+ at_name=f->f_type;
+ break;
+ default:
+ at_name=f->f_avtype;
+ break;
+ }
+
+ if (done)
+ goto done;
+
+ if (strcasecmp(at_name,"objectclass"))
+ at=backsql_at_with_name(bsi->oc,at_name);
+ else
+ {
+ at=&oc_attr;
+ at->sel_expr=backsql_strcat(at->sel_expr,&len,"'",bsi->oc->name,"'",NULL);
+ }
+ if (at==NULL)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_process_filter(): attribute '%s' is not defined for objectclass '%s'\n",
+ at_name,bsi->oc->name,0);
+ return -1;
+ }
+
+ backsql_merge_from_clause(&bsi->from,&bsi->from_len,at->from_tbls);
+ //need to add this attribute to list of attrs to load, so that we could do test_filter() later
+ backsql_attrlist_add(bsi,at_name);
+
+ if (at->join_where != NULL && strstr(bsi->join_where,at->join_where)==NULL)
+ bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," AND ",at->join_where,NULL);
+
+ //if (at!=&oc_attr)
+ // bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,",",at->sel_expr," AS ",at->name,NULL);
+
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_EQUALITY:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"='",
+ f->f_avvalue.bv_val,"')",NULL);
+ break;
+ case LDAP_FILTER_GE:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,">=",
+ f->f_avvalue.bv_val,")",NULL);
+ break;
+ case LDAP_FILTER_LE:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"(",at->sel_expr,"<=",
+ f->f_avvalue.bv_val,")",NULL);
+ break;
+ case LDAP_FILTER_PRESENT:
+ bsi->flt_where=backsql_strcat(bsi->flt_where,&bsi->fwhere_len,"NOT (",at->sel_expr,
+ " IS NULL)",NULL);
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ backsql_process_sub_filter(bsi,f);
+ break;
+ }
+
+done:
+ if (oc_attr.sel_expr!=NULL)
+ free(oc_attr.sel_expr);
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_process_filter()\n",0,0,0);
+ return 1;
+}
+
+char* backsql_srch_query(backsql_srch_info *bsi)
+{
+ char *query=NULL;
+ int q_len=0;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_srch_query()\n",0,0,0);
+ bsi->sel=NULL;
+ bsi->from=NULL;
+ bsi->join_where=NULL;
+ bsi->flt_where=NULL;
+ bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
+
+ bsi->sel=backsql_strcat(bsi->sel,&bsi->sel_len,
+ "SELECT ldap_entries.id,",bsi->oc->keytbl,".",bsi->oc->keycol,
+ ", '",bsi->oc->name,"' AS objectClass",
+ ", ldap_entries.dn AS dn",
+ NULL);
+ bsi->from=backsql_strcat(bsi->from,&bsi->from_len," FROM ldap_entries,",bsi->oc->keytbl,NULL);
+ bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len," WHERE ",
+ bsi->oc->keytbl,".",bsi->oc->keycol,"=ldap_entries.keyval AND ",
+ "ldap_entries.objclass=? AND ",NULL);
+
+ switch(bsi->scope)
+ {
+ case LDAP_SCOPE_BASE:
+ bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
+ "ldap_entries.dn=?",NULL);
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
+ "ldap_entries.parent=?",NULL);
+ break;
+ case LDAP_SCOPE_SUBTREE:
+ bsi->join_where=backsql_strcat(bsi->join_where,&bsi->jwhere_len,
+ bsi->bi->subtree_cond,NULL);
+ break;
+ }
+ if (backsql_process_filter(bsi,bsi->filter))
+ query=backsql_strcat(query,&q_len,bsi->sel,bsi->from,bsi->join_where," AND ",bsi->flt_where,NULL);
+
+
+ free(bsi->sel);
+ free(bsi->from);
+ free(bsi->join_where);
+ free(bsi->flt_where);
+ bsi->sel_len=bsi->from_len=bsi->jwhere_len=bsi->fwhere_len=0;
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_srch_query()\n",0,0,0);
+ return query;
+}
+
+int backsql_oc_get_candidates(backsql_oc_map_rec *oc,backsql_srch_info *bsi)
+{
+ char *query=NULL;
+ SQLHSTMT sth;
+ RETCODE rc;
+ backsql_entryID base_id,*res,*c_id;
+ //Entry *e;
+ BACKSQL_ROW_NTS row;
+ //int i;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_oc_get_candidates(): oc='%s'\n",oc->name,0,0);
+ bsi->oc=oc;
+ query=backsql_srch_query(bsi);
+ if (query==NULL)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not construct query for objectclass\n",0,0,0);
+ return 1;
+ }
+
+ Debug(LDAP_DEBUG_TRACE,"Constructed query: %s\n",query,0,0);
+ if ((rc=backsql_Prepare(bsi->dbh,&sth,query,0)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error preparing query\n",0,0,0);
+ backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
+ free(query);
+ return 1;
+ }
+ free(query);
+
+ if (backsql_BindParamID(sth,1,&bsi->oc->id) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding objectclass id parameter\n",0,0,0);
+ return 1;
+ }
+ switch(bsi->scope)
+ {
+ case LDAP_SCOPE_BASE:
+ case LDAP_SCOPE_SUBTREE:
+ if ((rc=backsql_BindParamStr(sth,2,bsi->base_dn,BACKSQL_MAX_DN_LEN)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base_dn parameter\n",0,0,0);
+ backsql_PrintErrors(bsi->bi->db_env,bsi->dbh,sth,rc);
+ return 1;
+ }
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ res=backsql_dn2id(&base_id,bsi->dbh,bsi->base_dn);
+ if (res==NULL)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): could not retrieve base_dn id - no such entry\n",0,0,0);
+ bsi->status=LDAP_NO_SUCH_OBJECT;
+ return 0;
+ }
+ if (backsql_BindParamID(sth,2,&base_id.id) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): error binding base id parameter\n",0,0,0);
+ free(base_id.dn);
+ return 1;
+ }
+ free(base_id.dn);
+ break;
+ }
+
+ if ((rc=SQLExecute(sth)) != SQL_SUCCESS && rc!= SQL_SUCCESS_WITH_INFO)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): 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)
+ {
+ /*
+ e=(Entry*)ch_calloc(1,sizeof(Entry));
+ for (i=1;i<row.ncols;i++)
+ {
+ if (row.is_null[i]>0)
+ {
+ backsql_entry_addattr(e,row.col_names[i],row.cols[i],row.col_prec[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);
+ }
+ */
+
+ Debug(LDAP_DEBUG_TRACE,"backsql_oc_get_candidates(): adding entry id=%s, keyval=%s dn='%s'\n",
+ row.cols[0],row.cols[1],row.cols[3]);
+ c_id=(backsql_entryID*)ch_calloc(1,sizeof(backsql_entryID));
+ c_id->id=atoi(row.cols[0]);
+ c_id->keyval=atoi(row.cols[1]);
+ c_id->oc_id=bsi->oc->id;
+ c_id->dn=strdup(row.cols[3]);
+ c_id->next=bsi->id_list;
+ bsi->id_list=c_id;
+ }
+ backsql_FreeRow(&row);
+ SQLFreeStmt(sth,SQL_DROP);
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_oc_get_candidates()\n",0,0,0);
+ return 1;
+}
+
+
+int backsql_search(Backend *be,Connection *conn,Operation *op,
+ char *base, char *nbase, int scope,int deref,int slimit,int tlimit,
+ Filter *filter, char *filterstr,char **attrs,int attrsonly)
+{
+ backsql_info *bi=(backsql_info*)be->be_private;
+ SQLHDBC dbh;
+ int sres;
+ int nentries;
+ Entry entry,*res;
+ int manageDSAit = get_manageDSAit( op );
+ struct berval **v2refs = NULL;
+ time_t stoptime;
+ backsql_srch_info srch_info;
+ backsql_entryID *eid=NULL;
+
+ base=dn_validate(base);
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_search(): base='%s', filter='%s', scope=%d,",
+ base,filterstr,scope);
+ Debug(LDAP_DEBUG_TRACE," deref=%d, attrsonly=%d, attributes to load: %s\n",
+ deref,attrsonly,attrs==NULL?"all":"custom list");
+ dbh=backsql_get_db_conn(be,conn);
+
+ if (!dbh)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_search(): could not get connection handle - exiting\n",0,0,0);
+ send_ldap_result(conn,op,LDAP_OTHER,"","SQL-backend error",NULL,NULL);
+ return 1;
+ }
+
+ if (tlimit == 0 && be_isroot(be,op->o_dn))
+ {
+ tlimit = -1; /* allow root to set no limit */
+ }
+ else
+ {
+ tlimit = (tlimit > be->be_timelimit || tlimit < 1) ?
+ be->be_timelimit : tlimit;
+ stoptime = op->o_time + tlimit;
+ }
+
+ if (slimit == 0 && be_isroot(be,op->o_dn))
+ {
+ slimit = -1; /* allow root to set no limit */
+ }
+ else
+ {
+ slimit = (slimit > be->be_sizelimit || slimit < 1) ?
+ be->be_sizelimit : slimit;
+ }
+
+ //backsql_init_search(&srch_info,bi,nbase/*!!!!!!!!*/,scope,slimit,tlimit,stoptime,filter,dbh,
+// be,conn,op,attrs);
+ backsql_init_search(&srch_info,bi,base/*don't know so far how to make Oracle do CIS search on VARCHAR2*/,
+ scope,slimit,tlimit,stoptime,filter,dbh,
+ be,conn,op,attrs);
+
+ //for each objectclass we try to construct query which gets IDs
+ //of entries matching LDAP query filter and scope (or at least candidates),
+ //and get the IDs
+ avl_apply(bi->oc_by_name,(AVL_APPLY)backsql_oc_get_candidates,&srch_info,0,AVL_INORDER);
+
+ nentries=0;
+ //now we load candidate entries (only those attrubutes mentioned in attrs and filter),
+ //test it against full filter and then send to client
+ for(eid=srch_info.id_list;eid!=NULL;eid=eid->next)
+ {
+ /* check for abandon */
+ ldap_pvt_thread_mutex_lock(&op->o_abandonmutex);
+ if (op->o_abandon)
+ {
+ ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
+ break;
+ }
+ ldap_pvt_thread_mutex_unlock(&op->o_abandonmutex);
+
+ /* check time limit */
+ if ( tlimit != -1 && slap_get_time() > stoptime)
+ {
+ send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
+ NULL, NULL, v2refs, NULL, nentries );
+
+ break;
+ }
+
+ Debug(LDAP_DEBUG_TRACE,"backsql_search(): loading data for entry id=%d, oc_id=%d, keyval=%d\n",
+ eid->id,eid->oc_id,eid->keyval);
+
+ res=backsql_id2entry(&srch_info,&entry,eid);
+ if (res==NULL)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_search(): error in backsql_id2entry() - skipping entry\n",0,0,0);
+ continue;
+ }
+
+ if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
+ is_entry_referral( &entry ) )
+ {
+ struct berval **refs = get_entry_referrals(be,conn,op,&entry);
+
+ send_search_reference( be, conn, op, &entry, refs, scope, NULL, &v2refs );
+ ber_bvecfree( refs );
+ continue;
+ }
+
+ // if (test_filter(be,conn,op,&entry,filter)==0)
+ {
+ if ((sres=send_search_entry(be,conn,op,&entry,attrs,attrsonly,NULL))==-1)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_search(): connection lost\n",0,0,0);
+ break;
+ }
+ nentries+=!sres;
+ }
+ }
+
+ for(eid=srch_info.id_list;eid!=NULL;eid=backsql_free_entryID(eid));
+
+ //free bsi->attrs!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ if (nentries>0)
+ send_search_result( conn, op,
+ v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
+ NULL, NULL, v2refs, NULL, nentries );
+ else
+ send_ldap_result(conn,op,LDAP_NO_SUCH_OBJECT,NULL,NULL,NULL,0);
+
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_search()\n",0,0,0);
+ return 0;
+}
--- /dev/null
+/*
+ * 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-types.h"
+#include "sql-wrap.h"
+#include "schema-map.h"
+
+#define MAX_ATTR_LEN 16384
+
+typedef struct backsql_conn
+{
+ int ldap_cid;
+ SQLHDBC dbh;
+}backsql_db_conn;
+
+int backsql_dummy(void *,void *);
+
+void backsql_PrintErrors(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT sth,int rc)
+{
+ SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH]; /* msg. buffer */
+ SQLCHAR state[SQL_SQLSTATE_SIZE]; /* statement buf. */
+ SDWORD iSqlCode; /* return code */
+ SWORD len=SQL_MAX_MESSAGE_LENGTH-1; /* return length */
+
+
+ Debug(LDAP_DEBUG_TRACE,"Return code: %d\n", rc,0,0);
+
+ while((rc=SQLError(henv,hdbc,sth,state,&iSqlCode,msg,
+ SQL_MAX_MESSAGE_LENGTH - 1, &len)) == SQL_SUCCESS
+ || rc == SQL_SUCCESS_WITH_INFO
+ )
+ {
+ Debug(LDAP_DEBUG_TRACE,"SQL engine state: %s\n", state,0,0);
+ Debug(LDAP_DEBUG_TRACE,"Native error code: %d\n",(int) iSqlCode,0,0);
+ Debug(LDAP_DEBUG_TRACE,"Message: %s\n",msg,0,0);
+ }
+}
+
+RETCODE backsql_Prepare(SQLHDBC dbh,SQLHSTMT *sth,char* query,int timeout)
+{
+ RETCODE rc;
+ char drv_name[30];
+ SWORD len;
+ int i;
+
+ rc=SQLAllocStmt(dbh,sth);
+ if (rc != SQL_SUCCESS)
+ return rc;
+
+ //Debug(LDAP_DEBUG_TRACE,"==>_SQLPrepare()\n", 0,0,0);
+ SQLGetInfo(dbh,SQL_DRIVER_NAME,drv_name,30,&len);
+ //Debug(LDAP_DEBUG_TRACE,"_SQLPrepare(): driver name='%s'\n", drv_name,0,0);
+ for (i=0;i<30 && drv_name[i];i++)
+ drv_name[i]=toupper(drv_name[i]);
+ if (!strncmp(drv_name,"SQLSRV32.DLL",30))
+ {
+ //stupid default result set in MS SQL Server does not support multiple active statements
+ //on the same connection -- so we are trying to make it not to use default result set...
+ Debug(LDAP_DEBUG_TRACE,"_SQLprepare(): enabling MS SQL Server default result set workaround\n", 0,0,0);
+ rc=SQLSetStmtOption(*sth,SQL_CONCURRENCY,SQL_CONCUR_ROWVER);
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ {
+ Debug(LDAP_DEBUG_TRACE,"_SQLPrepare(): SQLSetStmtOption(SQL_CONCURRENCY,SQL_CONCUR_ROWVER) failed:\n", 0,0,0);
+ backsql_PrintErrors(SQL_NULL_HENV,dbh,sth,rc);
+ }
+ }
+ if (timeout>0)
+ {
+ Debug(LDAP_DEBUG_TRACE,"_SQLprepare(): setting query timeout to %d sec.\n", timeout,0,0);
+ if ((rc=SQLSetStmtOption(*sth,SQL_QUERY_TIMEOUT,timeout)) != SQL_SUCCESS)
+ {
+ backsql_PrintErrors(SQL_NULL_HENV,dbh,sth,rc);
+ }
+ }
+
+ //Debug(LDAP_DEBUG_TRACE,"<==_SQLPrepare() calling SQLPrepare()\n", 0,0,0);
+ return SQLPrepare(*sth,query,SQL_NTS);
+}
+
+RETCODE backsql_BindParamStr(SQLHSTMT sth,int par_ind,char *str,int maxlen)
+{
+ RETCODE rc;
+ SQLINTEGER len=SQL_NTS;
+
+ rc=SQLBindParameter(sth,(SQLUSMALLINT)par_ind,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_VARCHAR,
+ (SQLUINTEGER)maxlen,0,(SQLPOINTER)str,(SQLUINTEGER)maxlen,NULL);
+ return rc;
+}
+
+RETCODE backsql_BindParamID(SQLHSTMT sth,int par_ind,unsigned long *id)
+{
+
+ return SQLBindParameter(sth,(SQLUSMALLINT)par_ind,SQL_PARAM_INPUT,SQL_C_ULONG,SQL_INTEGER,
+ 0,0,(SQLPOINTER)id,0,(SQLINTEGER*)NULL);
+}
+
+RETCODE backsql_BindRowAsStrings(SQLHSTMT sth,BACKSQL_ROW_NTS *row)
+{
+ RETCODE rc;
+ SQLCHAR colname[64];
+ SQLSMALLINT name_len,col_type,col_scale,col_null;
+ UDWORD col_prec;
+ int i;
+
+ if (row == NULL)
+ return SQL_ERROR;
+
+ //Debug(LDAP_DEBUG_TRACE,"==> backsql_BindRowAsStrings()\n",0,0,0);
+ rc=SQLNumResultCols(sth,&row->ncols);
+ if (rc != SQL_SUCCESS)
+ {
+ //Debug(LDAP_DEBUG_TRACE,"_SQLBindRowAsStrings(): SQLNumResultCols() failed:\n",0,0,0);
+ backsql_PrintErrors(SQL_NULL_HENV,SQL_NULL_HDBC,sth,rc);
+ }
+ else
+ {
+ //Debug(LDAP_DEBUG_TRACE,"backsql_BindRowAsStrings: ncols=%d\n",(int)row->ncols,0,0);
+ row->col_names=(char**)ch_calloc(row->ncols,sizeof(char*));
+ row->cols=(char**)ch_calloc(row->ncols,sizeof(char*));
+ row->col_prec=(UDWORD*)ch_calloc(row->ncols,sizeof(UDWORD));
+ row->is_null=(SQLINTEGER*)ch_calloc(row->ncols,sizeof(SQLINTEGER));
+ for (i=1;i<=row->ncols;i++)
+ {
+ rc=SQLDescribeCol(sth,(SQLSMALLINT)i,&colname[0],(SQLUINTEGER)sizeof(colname)-1,&name_len,&col_type,
+ (UDWORD*) &col_prec,&col_scale,&col_null);
+ row->col_names[i-1]=strdup(colname);
+ //Debug(LDAP_DEBUG_TRACE,"backsql_BindRowAsStrings: col_name=%s, col_prec[%d]=%d\n",colname,(int)i,(int)col_prec);
+ if (col_type == SQL_LONGVARCHAR || col_type== SQL_LONGVARBINARY)
+ {
+ //row->cols[i-1]=NULL;
+ //row->col_prec[i-1]=-1;
+ //such fields must be handled in some other way since they return 2G
+ //as their precision (at least it does so with MS SQL Server w/native driver)
+ //for now, we just set fixed precision for such fields - dirty hack, but...
+ //no time to deal with SQLGetData()
+ col_prec=MAX_ATTR_LEN;
+ row->cols[i-1]=(char*)ch_calloc((col_prec+1),sizeof(char));
+ row->col_prec[i-1]=col_prec;
+ rc=SQLBindCol(sth,(SQLUSMALLINT)i,SQL_C_CHAR,(SQLPOINTER)row->cols[i-1],col_prec+1,
+ &row->is_null[i-1]);
+ }
+ else
+ {
+ row->cols[i-1]=(char*)ch_calloc((col_prec+1),sizeof(char));
+ row->col_prec[i-1]=col_prec;
+ rc=SQLBindCol(sth,(SQLUSMALLINT)i,SQL_C_CHAR,(SQLPOINTER)row->cols[i-1],col_prec+1,
+ &row->is_null[i-1]);
+ }
+ }
+ }
+ //Debug(LDAP_DEBUG_TRACE,"<== backsql_BindRowAsStrings()\n",0,0,0);
+ return rc;
+}
+
+RETCODE backsql_FreeRow(BACKSQL_ROW_NTS *row)
+{
+ int i;
+
+ if (row->cols == NULL)
+ return SQL_ERROR;
+ for(i=0;i<row->ncols;i++)
+ {
+ free(row->cols[i]);
+ }
+ free(row->col_names);
+ free(row->col_prec);
+ free(row->cols);
+ free(row->is_null);
+ return SQL_SUCCESS;
+}
+
+int backsql_cmp_connid(backsql_db_conn *c1,backsql_db_conn *c2)
+{
+ if (c1->ldap_cid > c2->ldap_cid)
+ return 1;
+ if (c1->ldap_cid < c2->ldap_cid)
+ return -1;
+ return 0;
+}
+
+
+int backsql_close_db_conn(backsql_db_conn *conn)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_close_db_conn()\n",0,0,0);
+ SQLDisconnect(conn->dbh);
+ SQLFreeConnect(conn->dbh);
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_close_db_conn()\n",0,0,0);
+ return 1;
+}
+
+int backsql_init_db_env(backsql_info *si)
+{
+ RETCODE rc;
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_init_db_env()\n",0,0,0);
+ if ((rc=SQLAllocEnv(&si->db_env)) != SQL_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,"init_db_env: SQLAllocEnv failed:\n",0,0,0);
+ backsql_PrintErrors(SQL_NULL_HENV,SQL_NULL_HDBC,SQL_NULL_HENV,rc);
+ }
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_init_db_env()\n",0,0,0);
+ return SQL_SUCCESS;
+}
+
+int backsql_free_db_env(backsql_info *si)
+{
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_free_db_env()\n",0,0,0);
+ //Debug(LDAP_DEBUG_TRACE,"free_db_env(): delete AVL tree here!!!\n",0,0,0);
+
+ //stop, if frontend waits for all threads to shutdown before calling this --
+ //then what we are going to delete?? everything is deleted already...
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_free_db_env()\n",0,0,0);
+ return SQL_SUCCESS;
+}
+
+backsql_db_conn* backsql_open_db_conn(backsql_info *si,int ldap_cid)
+{
+ backsql_db_conn *dbc=(backsql_db_conn*)ch_calloc(1,sizeof(backsql_db_conn));
+ int rc;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_open_db_conn()\n",0,0,0);
+ dbc->ldap_cid=ldap_cid;
+ if ((rc=SQLAllocConnect(si->db_env,&dbc->dbh)) != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_open_db_conn: SQLAllocConnect() failed:\n",0,0,0);
+ backsql_PrintErrors(si->db_env,SQL_NULL_HDBC,SQL_NULL_HENV,rc);
+ return NULL;
+ }
+ if ((rc=SQLConnect(dbc->dbh,si->dbname,SQL_NTS,si->dbuser,SQL_NTS,
+ si->dbpasswd,SQL_NTS) != SQL_SUCCESS))
+ {
+ if (rc != SQL_SUCCESS_WITH_INFO)
+ Debug(LDAP_DEBUG_TRACE,"backsql_open_db_conn: SQLConnect() failed:\n",0,0,0);
+ else
+ Debug(LDAP_DEBUG_TRACE,"backsql_open_db_conn: SQLConnect() succeeded with info:\n",0,0,0);
+ backsql_PrintErrors(si->db_env,dbc->dbh,SQL_NULL_HENV,rc);
+ if (rc != SQL_SUCCESS_WITH_INFO)
+ return NULL;
+ }
+
+ Debug(LDAP_DEBUG_TRACE,"backsql_open_db_conn(): connected, adding to tree\n",0,0,0);
+ ldap_pvt_thread_mutex_lock(&si->dbconn_mutex);
+ avl_insert(&si->db_conns,dbc,(AVL_CMP)backsql_cmp_connid,backsql_dummy);
+ ldap_pvt_thread_mutex_unlock(&si->dbconn_mutex);
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_open_db_conn()\n",0,0,0);
+ return dbc;
+}
+
+int backsql_free_db_conn(Backend *be,Connection *ldapc)
+{
+ backsql_info *si=(backsql_info*)be->be_private;
+ backsql_db_conn tmp,*conn;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_free_db_conn()\n",0,0,0);
+ tmp.ldap_cid=ldapc->c_connid;
+ ldap_pvt_thread_mutex_lock(&si->dbconn_mutex);
+ conn=(backsql_db_conn*)avl_delete(&si->db_conns,&tmp,(AVL_CMP)backsql_cmp_connid);
+ ldap_pvt_thread_mutex_unlock(&si->dbconn_mutex);
+ //we have one thread per connection, as I understand -- so we can
+ //get this out of critical section
+ if (conn!=NULL)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_free_db_conn(): closing db connection\n",0,0,0);
+ backsql_close_db_conn(conn);
+ }
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_free_db_conn()\n",0,0,0);
+ return SQL_SUCCESS;
+}
+
+SQLHDBC backsql_get_db_conn(Backend *be,Connection *ldapc)
+{
+ backsql_info *si=(backsql_info*)be->be_private;
+ backsql_db_conn *dbc;
+ backsql_db_conn tmp;
+
+ Debug(LDAP_DEBUG_TRACE,"==>backsql_get_db_conn()\n",0,0,0);
+
+ tmp.ldap_cid=ldapc->c_connid;
+ //we have one thread per connection, as I understand -- so we do not need
+ // locking here
+ dbc=(backsql_db_conn*)avl_find(si->db_conns,&tmp,(AVL_CMP)backsql_cmp_connid);
+ if (!dbc)
+ dbc=backsql_open_db_conn(si,ldapc->c_connid);
+
+ if (!dbc)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_get_db_conn(): could not get connection handle -- returning NULL\n",0,0,0);
+ return NULL;
+ }
+ ldap_pvt_thread_mutex_lock(&si->schema_mutex);
+ if (!si->schema_loaded)
+ {
+ Debug(LDAP_DEBUG_TRACE,"backsql_get_db_conn(): first call -- reading schema map\n",0,0,0);
+ backsql_load_schema_map(si,dbc->dbh);
+ }
+ ldap_pvt_thread_mutex_unlock(&si->schema_mutex);
+
+ Debug(LDAP_DEBUG_TRACE,"<==backsql_get_db_conn()\n",0,0,0);
+ return dbc->dbh;
+}
+