Browse code

Add db_oracle module and toolses for it

git-svn-id: https://openser.svn.sourceforge.net/svnroot/openser/trunk@3997 689a6050-402a-0410-94f2-e92a70836424

Iouri Kharon authored on 09/04/2008 15:46:09
Showing 15 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,61 @@
0
+# $Id$
1
+#
2
+# WARNING: do not run this directly, it should be run by the master Makefile
3
+
4
+include ../../Makefile.defs
5
+auto_gen=
6
+NAME=db_oracle.so
7
+
8
+# can be defined for non standard placement of oracle so's
9
+ORAPATH=
10
+
11
+# use for multiple client sdk version install
12
+ifneq ($(ORAVERSION),)
13
+    ORAVERDIR=/$(ORAVERSION)
14
+endif
15
+
16
+# use include/library path's for full client installation
17
+ifneq ($(ORAHOME),)
18
+    DEFS +=-I$(ORAHOME)/include
19
+    LIBS +=-L$(ORAHOME)/lib
20
+ifeq ($(ORAPATH),)
21
+    ORAPATH=$(ORAHOME)/lib
22
+endif
23
+else
24
+# use standard know paths oci.h locations (linux)
25
+DEFS +=-I$(LOCALBASE)/include/oracle$(ORAVERDIR) \
26
+    -I$(SYSBASE)/include/oracle$(ORAVERDIR)
27
+endif
28
+
29
+# search 'so' path if it non standard (possible liboclntsh locations on linux)
30
+ifeq ($(ORAPATH),)
31
+    ORAPATH=$(shell [ -f $(LOCALBASE)/lib64/oracle$(ORAVERDIR)/libocci.so ] && \
32
+	    echo $(LOCALBASE)/lib64/oracle$(ORAVERDIR) )
33
+endif
34
+ifeq ($(ORAPATH),)
35
+    ORAPATH=$(shell [ -f $(SYSBASE)/lib64/oracle$(ORAVERDIR)/libocci.so ] && \
36
+	    echo $(SYSBASE)/lib64/oracle$(ORAVERDIR) )
37
+endif
38
+ifeq ($(ORAPATH),)
39
+    ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \
40
+	    echo $(SYSBASE)/lib/oracle$(ORAVERDIR) )
41
+endif
42
+ifeq ($(ORAPATH),)
43
+    ORAPATH=$(shell [ -f $(SYSBASE)/lib/oracle$(ORAVERDIR)/libocci.so ] && \
44
+	    echo $(SYSBASE)/lib/oracle$(ORAVERDIR) )
45
+endif
46
+
47
+ifneq ($(ORAPATH),)
48
+    LIBS +=-L$(ORAPATH)
49
+endif
50
+
51
+LIBS +=-locci -lclntsh
52
+
53
+#DEFS+=-DLINUX -D_GNU_SOURCE -D_REENTRANT
54
+#LIBS+=-lpthread
55
+
56
+ifneq ($(ORAPATH),)
57
+    LIBS +=-Wl,-rpath $(ORAPATH)
58
+endif
59
+
60
+include ../../Makefile.modules
0 61
new file mode 100644
... ...
@@ -0,0 +1,195 @@
0
+Oracle Module
1
+
2
+Iouri Kharon
3
+
4
+   <yjh@styx.cabel.net>
5
+
6
+Yury Skandarov
7
+
8
+   <kandman@trunkmobile.com>
9
+
10
+Iakov Kharon
11
+
12
+   <jyh@trunkmobile.com>
13
+
14
+
15
+Edited by
16
+
17
+Iouri Kharon
18
+
19
+   <yjh@styx.cabel.net>
20
+
21
+   Copyright � 2007,2008 TRUNK MOBILE, INC
22
+     __________________________________________________________
23
+
24
+   Table of Contents
25
+   1. User's Guide
26
+
27
+        1.1. Overview
28
+        1.2. Dependencies
29
+
30
+              1.2.1. OpenSER Modules
31
+              1.2.2. External Libraries or Applications
32
+
33
+        1.3. Exported Parameters
34
+
35
+              1.3.1. timeout (fixedpoint)
36
+              1.3.2. reconnect (fixedpoint)
37
+
38
+        1.4. Exported Functions
39
+        1.5. Installation
40
+	1.6. Utility openser_orasel
41
+
42
+   2. Developer's Guide
43
+   3. Frequently Asked Questions
44
+
45
+   List of Examples
46
+   1-1. Set timeout parameter
47
+   1-2. Set reconnect parameter
48
+   1-3. Disable asynchronous mode
49
+   1-4. Specify database url with use Oracle TNS service (alias)
50
+     __________________________________________________________
51
+
52
+Chapter 1. User's Guide
53
+
54
+1.1. Overview
55
+
56
+   This is a module which provides Oracle connectivity for OpenSER.
57
+   It's implements the DB API defined in OpenSER.
58
+     __________________________________________________________
59
+
60
+1.2. Dependencies
61
+
62
+1.2.1. OpenSER Modules
63
+
64
+   The following modules must be loaded before this module:
65
+
66
+     * No dependencies on other OpenSER modules.
67
+     __________________________________________________________
68
+
69
+1.2.2. External Libraries or Applications
70
+
71
+   The following libraries or applications must be installed
72
+   before running OpenSER with this module loaded:
73
+
74
+     * Oracle Instance Client OR Oracle Instance Client Light.
75
+     __________________________________________________________
76
+
77
+1.3.1. timeout (fixedpoint)
78
+
79
+   Specify timeout value for any operation with BD.
80
+
81
+   Possible values is from 0.1 to 10.0 seconds
82
+
83
+   Default value is 3.0 (3 second).
84
+
85
+   If timeout parameter value seted to 0, module use synchronous mode
86
+   (without timeout's).
87
+
88
+   Example 1-1. Set timeount parameter
89
+...
90
+modparam("db_oracle", "timeout", 1.5)
91
+...
92
+
93
+   Example 1-2. Disable asynchronous mode
94
+...
95
+modparam("db_oracle", "timeout", 0)
96
+...
97
+     __________________________________________________________
98
+
99
+1.3.2. reconnect (fixedpoint)
100
+
101
+   Specify timeout value for connect (create session) operation.
102
+
103
+   Possible values is from 0.1 to 10.0 seconds
104
+
105
+   Default value is 0.2 (200 milliseconds).
106
+
107
+   Example 1-3. Set reconnect parameter
108
+...
109
+modparam("db_oracle", "reconnect", 0.5)
110
+...
111
+
112
+     __________________________________________________________
113
+
114
+1.4. Exported Functions
115
+
116
+   No function exported to be used from configuration file.
117
+     __________________________________________________________
118
+
119
+1.5. Installation
120
+
121
+   Because it depends on an external library, the oracle module is
122
+   not compiled and installed by default. You can use one of the
123
+   next options.
124
+
125
+     * - edit the "Makefile" and remove "db_oracle" from
126
+       "excluded_modules" list. Then follow the standard procedure
127
+       to install OpenSER: "make all; make install".
128
+     * - from command line use: 'make all include_modules="db_oracle";
129
+       make install include_modules="db_oracle"'.
130
+
131
+     __________________________________________________________
132
+
133
+1.6. Utility openser_orasel
134
+
135
+    For working with openserctl script, should be able to print the 'query' 
136
+    results to the terminal in a user-readable form. The standard command-line 
137
+    Oracle client (sqlplus) is not quite suitable for this, as it cannot align 
138
+    row width to real (received) data's (it always prints a cell width as 
139
+    described in the db scheme). This problem has been solved by inclusion the 
140
+    utility openser_orasel, which formats printing approximately in the same 
141
+    way as the 'mysql' client utility. In addition, this utility known about 
142
+    the "agreements and types" in DB that are used in OpenSER for the work 
143
+    with Oracle and formats printing taking these into account.
144
+     __________________________________________________________
145
+
146
+Chapter 2. Developer's Guide
147
+
148
+   The module does not provide any API to use in other OpenSER
149
+   modules.
150
+     __________________________________________________________
151
+
152
+Chapter 3. Frequently Asked Questions
153
+
154
+   3.1. Where can I find more about OpenSER?
155
+   3.2. Where can I post a question about this module?
156
+   3.3. How can I report a bug?
157
+   3.4. Can I specify database url with use Oracle TNS (alias)?
158
+
159
+   3.1. Where can I find more about OpenSER?
160
+
161
+   Take a look at http://openser.org/.
162
+
163
+   3.2. Where can I post a question about this module?
164
+
165
+   First at all check if your question was already answered on one
166
+   of our mailing lists:
167
+
168
+     * User Mailing List -
169
+       http://openser.org/cgi-bin/mailman/listinfo/users
170
+     * Developer Mailing List -
171
+       http://openser.org/cgi-bin/mailman/listinfo/devel
172
+
173
+   E-mails regarding any stable OpenSER release should be sent to
174
+   <users@openser.org> and e-mails regarding development versions
175
+   should be sent to <devel@openser.org>.
176
+
177
+   If you want to keep the mail private, send it to
178
+   <team@openser.org>.
179
+
180
+   3.3. How can I report a bug?
181
+
182
+   Please follow the guidelines provided at:
183
+   http://sourceforge.net/tracker/?group_id=139143.
184
+
185
+   3.4. Can I specify database url using Oracle TNS (alias)?
186
+
187
+   Yes, you can. For specifiing database url with use Oracle TNS serfice use
188
+   following syntax:
189
+
190
+   Example 1-4. Specify database url with Oracle TNS service (alias)
191
+...
192
+modparam("your_module", "db_url", "oracle://openser:openserrw@/openser")
193
+...
194
+
0 195
new file mode 100644
... ...
@@ -0,0 +1,270 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Oracle module interface
4
+ *
5
+ * Copyright (C) 2007,2008 TRUNK MOBILE
6
+ *
7
+ * This file is part of openser, a free SIP server.
8
+ *
9
+ * openser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * openser is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+/*
24
+ * History:
25
+ * --------
26
+ */
27
+
28
+#include <stdlib.h>
29
+#include <errno.h>
30
+#include <sys/time.h>
31
+#include <oci.h>
32
+#include "../../dprint.h"
33
+#include "../../sr_module.h"
34
+#include "ora_con.h"
35
+#include "asynch.h"
36
+
37
+#define MAX_TIMEOUT_S  10
38
+#define MIN_TIMEOUT_MS 100
39
+
40
+
41
+/* Default is 3.0 second */
42
+static struct timeval request_tm = { .tv_sec = 3, .tv_usec = 0 };
43
+
44
+/* Default is 0.2 second */
45
+static struct timeval restore_tm       = { .tv_sec = 0, .tv_usec = 200*1000 };
46
+static const struct timeval defrest_tm = { .tv_sec = 0, .tv_usec = 200*1000 };
47
+
48
+static int synch_mode;
49
+static int cur_asynch_mode;
50
+static struct timeval wtm;
51
+
52
+
53
+static __inline__ int is_zero_tm(const struct timeval* tv)
54
+{
55
+	return !tv->tv_usec && !tv->tv_sec;
56
+}
57
+
58
+
59
+/*
60
+ * parse timeout value in syntax: nnn.mmm (sec/ms)
61
+ */
62
+static int set_tv(unsigned type, const char* val, struct timeval* tv)
63
+{
64
+	char *eptr;
65
+	unsigned long s, ms;
66
+	double dv;
67
+
68
+	if (type != STR_PARAM) {
69
+		LM_ERR("type of parameter is no STR\n");
70
+		return -1;
71
+	}
72
+
73
+	if (!val || !*val) {
74
+		LM_ERR("empty parameter\n");
75
+		return -1;
76
+	}
77
+
78
+	errno = 0;
79
+	dv = strtod(val, &eptr);
80
+
81
+	if (*eptr) {
82
+		LM_ERR("invalid parameter string\n");
83
+		return -2;
84
+	}
85
+
86
+	if (   errno
87
+	    || dv > (double)MAX_TIMEOUT_S
88
+	    || (dv && dv < ((double)MIN_TIMEOUT_MS)/1000))
89
+	{
90
+		LM_ERR("value must be between 0.%u and %u.0\n",
91
+			MIN_TIMEOUT_MS, MAX_TIMEOUT_S);
92
+		return -3;
93
+	}
94
+
95
+	s = (unsigned)dv;
96
+	dv -= (double)s;
97
+	ms = (unsigned)(dv * 1000);
98
+	tv->tv_sec = (time_t)s;
99
+	tv->tv_usec = (suseconds_t)ms;
100
+	return 0;
101
+}
102
+
103
+
104
+/*
105
+ * set operation timeout
106
+ */
107
+int set_timeout(unsigned type, const char* val)
108
+{
109
+	int rc = set_tv(type, val, &request_tm);
110
+
111
+	if (!rc) {
112
+		synch_mode = is_zero_tm(&request_tm);
113
+		if (!synch_mode && is_zero_tm(&restore_tm))
114
+			restore_tm = defrest_tm;
115
+	}
116
+
117
+	return rc;
118
+}
119
+
120
+
121
+/*
122
+ * set (re)connect timeout
123
+ */
124
+int set_reconnect(unsigned type, const char* val)
125
+{
126
+	int rc = set_tv(type, val, &restore_tm);
127
+
128
+	if (!synch_mode && is_zero_tm(&restore_tm)) {
129
+		LM_WARN("in asyncronus mode reconnect time can't be zero. "
130
+			"Set default value\n");
131
+		restore_tm = defrest_tm;
132
+	}
133
+
134
+	return rc;
135
+}
136
+
137
+
138
+static sword change_mode(ora_con_t* con)
139
+{
140
+	return OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, NULL, 0,
141
+		OCI_ATTR_NONBLOCKING_MODE, con->errhp);
142
+}
143
+
144
+
145
+/*
146
+ * start timelimited operation (if work in synch mode return SUCCESS)
147
+ */
148
+sword begin_timelimit(ora_con_t* con, int connect)
149
+{
150
+	struct timeval* tv;
151
+	sword status;
152
+
153
+	if (synch_mode)
154
+		return OCI_SUCCESS;
155
+
156
+	if (connect || cur_asynch_mode) {
157
+		ub1 mode;
158
+
159
+		status = OCIAttrGet(con->svchp, OCI_HTYPE_SVCCTX, &mode, NULL,
160
+			OCI_ATTR_NONBLOCKING_MODE, con->errhp);
161
+		if (status != OCI_SUCCESS)
162
+			return status;
163
+
164
+		if (mode) {
165
+			status = change_mode(con);
166
+			if (status != OCI_SUCCESS)
167
+				return status;
168
+		}
169
+		cur_asynch_mode = 0;
170
+	}
171
+
172
+	status = change_mode(con);
173
+	if (status != OCI_SUCCESS && connect >= 0)
174
+		return status;
175
+
176
+	cur_asynch_mode = 1;
177
+
178
+	gettimeofday(&wtm, NULL);
179
+	tv = &request_tm;
180
+	if (connect)
181
+		tv = &restore_tm;
182
+	wtm.tv_sec += tv->tv_sec;
183
+	wtm.tv_usec += tv->tv_usec;
184
+	if (wtm.tv_usec >= 1000000) {
185
+		wtm.tv_usec -= 1000000;
186
+		++wtm.tv_sec;
187
+	}
188
+
189
+	return OCI_SUCCESS;
190
+}
191
+
192
+
193
+static sword remap_status(ora_con_t* con, sword status)
194
+{
195
+	sword code;
196
+
197
+	if (   status == OCI_ERROR
198
+	    && OCIErrorGet(con->errhp, 1, NULL, &code,
199
+			NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
200
+	    && (code == 3123 /*|| code == 3127*/))
201
+	{
202
+		status = OCI_STILL_EXECUTING;
203
+	}
204
+	return status;
205
+}
206
+
207
+
208
+/*
209
+ * check completion of timelimited operation (if work in synch mode return 0)
210
+ */
211
+int wait_timelimit(ora_con_t* con, sword status)
212
+{
213
+	struct timeval cur;
214
+
215
+	if (!cur_asynch_mode)
216
+		return 0;
217
+
218
+	if (remap_status(con, status) != OCI_STILL_EXECUTING)
219
+		return 0;
220
+
221
+	gettimeofday(&cur, NULL);
222
+	return (   cur.tv_sec < wtm.tv_sec
223
+		|| (cur.tv_sec == wtm.tv_sec && cur.tv_usec < wtm.tv_usec));
224
+}
225
+
226
+
227
+/*
228
+ * close current timelimited operation and disconnect if timeout occured
229
+ * return true only if work in asynch mode and timeout detect
230
+ */
231
+int done_timelimit(ora_con_t* con, sword status)
232
+{
233
+	int ret = 0;
234
+
235
+	if (!cur_asynch_mode)
236
+		return 0;
237
+
238
+	if (remap_status(con, status) == OCI_STILL_EXECUTING) {
239
+		sword code;
240
+
241
+		status = OCIBreak(con->svchp, con->errhp);
242
+		if (status != OCI_SUCCESS)
243
+			LM_ERR("driver: %s\n",
244
+				db_oracle_error(con, status));
245
+
246
+		status = OCIReset(con->svchp, con->errhp);
247
+		if (   status == OCI_ERROR
248
+		    && OCIErrorGet(con->errhp, 1, NULL, &code,
249
+			    NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
250
+		    && code == 1013)
251
+		{
252
+			status = OCI_SUCCESS;
253
+		}
254
+		if (status != OCI_SUCCESS)
255
+			LM_ERR("driver: %s\n",
256
+				db_oracle_error(con, status));
257
+		db_oracle_disconnect(con);
258
+		++ret;
259
+	} else {
260
+		status = change_mode(con);
261
+		if (status != OCI_SUCCESS) {
262
+			LM_ERR("driver: %s\n", db_oracle_error(con, status));
263
+			++ret;
264
+		} else {
265
+			cur_asynch_mode = 0;
266
+		}
267
+	}
268
+	return ret;
269
+}
0 270
new file mode 100644
... ...
@@ -0,0 +1,62 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Oracle module interface
4
+ *
5
+ * Copyright (C) 2007,2008 TRUNK MOBILE
6
+ *
7
+ * This file is part of openser, a free SIP server.
8
+ *
9
+ * openser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * openser is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ *
23
+ * History:
24
+ * --------
25
+ */
26
+
27
+#ifndef ASYNCH_H
28
+#define ASYNCH_H
29
+
30
+#include <oci.h>
31
+#include "ora_con.h"
32
+
33
+
34
+/*
35
+ * parse timeout value for operation in syntax: nnn.mmm (sec/ms)
36
+ */
37
+int set_timeout(unsigned type, const char* val);
38
+
39
+/*
40
+ * parse timeout value for reconnect in syntax: nnn.mmm (sec/ms)
41
+ */
42
+int set_reconnect(unsigned type, const char* val);
43
+
44
+
45
+/*
46
+ * start timelimited operation (if work in synch mode return SUCCESS)
47
+ */
48
+sword begin_timelimit(ora_con_t* con, int connect);
49
+
50
+/*
51
+ * check completion of timelimited operation (if work in synch mode return 0)
52
+ */
53
+int wait_timelimit(ora_con_t* con, sword status);
54
+
55
+/*
56
+ * close current timelimited operation and disconnect if timeout occured
57
+ * return true only if work in asynch mode and timeout detect
58
+ */
59
+int done_timelimit(ora_con_t* con, sword status);
60
+
61
+#endif /* ASYNCH_H */
0 62
new file mode 100644
... ...
@@ -0,0 +1,114 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Oracle module interface
4
+ *
5
+ * Copyright (C) 2007,2008 TRUNK MOBILE
6
+ *
7
+ * This file is part of openser, a free SIP server.
8
+ *
9
+ * openser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * openser is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+/*
24
+ * History:
25
+ * --------
26
+ */
27
+
28
+#include <sys/time.h>
29
+#include <oci.h>
30
+#include "../../sr_module.h"
31
+#include "../../db/db.h"
32
+#include "dbase.h"
33
+#include "asynch.h"
34
+
35
+static int oracle_mod_init(void);
36
+static void destroy(void);
37
+static int db_oracle_bind_api(db_func_t *dbb);
38
+
39
+MODULE_VERSION
40
+
41
+
42
+/*
43
+ * Oracle database module interface
44
+ */
45
+static cmd_export_t cmds[] = {
46
+	{"db_bind_api",         (cmd_function)db_oracle_bind_api,    0, 0, 0, 0},
47
+	{0, 0, 0, 0, 0, 0}
48
+};
49
+
50
+
51
+/*
52
+ * Exported parameters
53
+ */
54
+static param_export_t params[] = {
55
+	{"timeout",	STR_PARAM|USE_FUNC_PARAM, (void*)&set_timeout },
56
+	{"reconnect",	STR_PARAM|USE_FUNC_PARAM, (void*)&set_reconnect },
57
+	{0, 0, 0}
58
+};
59
+
60
+
61
+struct module_exports exports = {
62
+	"oracle",
63
+	DEFAULT_DLFLAGS, /* dlopen flags */
64
+	cmds,
65
+	params,          /*  module parameters */
66
+	0,               /* exported statistics */
67
+	0,               /* exported MI functions */
68
+	0,               /* exported pseudo-variables */
69
+	0,               /* extra processes */
70
+	oracle_mod_init, /* module initialization function */
71
+	0,               /* response function*/
72
+	destroy,         /* destroy function */
73
+	0                /* per-child init function */
74
+};
75
+
76
+
77
+static int oracle_mod_init(void)
78
+{
79
+	sword major, minor, update, patch, port;
80
+
81
+	OCIClientVersion(&major, &minor, &update, &patch, &port);
82
+	LM_DBG("Oracle client version is %d.%d.%d.%d.%d\n",
83
+		major, minor, update, patch, port);
84
+	return 0;
85
+}
86
+
87
+
88
+static void destroy(void)
89
+{
90
+	LM_INFO("Oracle terminate\n");
91
+	OCITerminate(OCI_DEFAULT);
92
+}
93
+
94
+
95
+static int db_oracle_bind_api(db_func_t *dbb)
96
+{
97
+	if(dbb==NULL)
98
+		return -1;
99
+
100
+	memset(dbb, 0, sizeof(db_func_t));
101
+
102
+	dbb->use_table        = db_oracle_use_table;
103
+	dbb->init             = db_oracle_init;
104
+	dbb->close            = db_oracle_close;
105
+	dbb->query            = db_oracle_query;
106
+	dbb->raw_query        = db_oracle_raw_query;
107
+	dbb->free_result      = db_oracle_free_result;
108
+	dbb->insert           = db_oracle_insert;
109
+	dbb->delete           = db_oracle_delete; 
110
+	dbb->update           = db_oracle_update;
111
+
112
+	return 0;
113
+}
0 114
new file mode 100644
... ...
@@ -0,0 +1,518 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Oracle module core functions
4
+ *
5
+ * Copyright (C) 2007,2008 TRUNK MOBILE
6
+ *
7
+ * This file is part of openser, a free SIP server.
8
+ *
9
+ * openser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * openser is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#include <stdio.h>
25
+#include <string.h>
26
+#include <stdlib.h>
27
+#include <time.h>
28
+#include <oci.h>
29
+#include "../../mem/mem.h"
30
+#include "../../dprint.h"
31
+#include "../../db/db_pool.h"
32
+#include "../../db/db_ut.h"
33
+#include "../../db/db_res.h"
34
+#include "../../db/db_query.h"
35
+#include "val.h"
36
+#include "ora_con.h"
37
+#include "res.h"
38
+#include "asynch.h"
39
+#include "dbase.h"
40
+
41
+
42
+#define	MAX_BIND_HANDLES 128
43
+
44
+char st_buf[STATIC_BUF_LEN];
45
+
46
+
47
+/*
48
+ * Make error message. Always return negative value
49
+ */
50
+int sql_buf_small(void)
51
+{
52
+	LM_ERR("static buffer too small\n");
53
+	return -11;
54
+}
55
+
56
+/*
57
+ * Decode error
58
+ */
59
+static char errbuf[512];
60
+
61
+static const char* db_oracle_errorinfo(ora_con_t* con)
62
+{
63
+	sword errcd;
64
+	if (OCIErrorGet(con->errhp, 1, NULL, &errcd,
65
+			(OraText*)errbuf, sizeof(errbuf),
66
+			OCI_HTYPE_ERROR) != OCI_SUCCESS) errbuf[0] = '\0';
67
+	else switch (errcd) {
68
+	case 28:	/* your session has been killed */
69
+	case 30:	/* session ID does not exists */
70
+	case 31:	/* session marked for kill */
71
+	case 41:	/* active time limit exceeded session terminated */
72
+	case 107:	/* failed to connect to oracle listener */
73
+	case 115:	/* connection refused; dispatcher table is full */
74
+	case 1033:	/* init/shutdown in progress */
75
+	case 1034:	/* not available (startup) */
76
+	case 1089:	/* server shutdown */
77
+	case 1090:	/* shutdown wait after command */
78
+	case 1092:	/* oracle instance terminated. Disconnection forced */
79
+	case 1573:	/* shutdown instance, no futher change allowed */
80
+	case 2049:	/* timeout: distributed transaction waiting lock */
81
+	case 3113:	/* EOF on communication channel */
82
+	case 3114:	/* not connected */
83
+	case 3135:	/* lost connection */
84
+	case 6033:	/* connect failed, partner rejected connection */
85
+	case 6034:	/* connect failed, partner exited unexpectedly */
86
+	case 6037:	/* connect failed, node unrecheable */
87
+	case 6039:	/* connect failed */
88
+	case 6042:	/* msgrcv failure (DNT) */
89
+	case 6043:	/* msgsend failure (DNT) */
90
+	case 6107:	/* network server not found */
91
+	case 6108:	/* connect to host failed */
92
+	case 6109:	/* msgrcv failure (TCP) */
93
+	case 6110:	/* msgsend failure (TCP) */
94
+	case 6114:	/* SID lookup failure */
95
+	case 6124:	/* TCP timeout */
96
+	case 6135:	/* connect rejected; server is stopping (TCP) */
97
+	case 6144:	/* SID unavaliable (TCP) */
98
+	case 6413:	/* connection not open */
99
+	case 12150:	/* tns can't send data, probably disconnect */
100
+	case 12152:	/* tns unable to send break message */
101
+	case 12153:	/* tns not connected */
102
+	case 12161:	/* tns internal error */
103
+	case 12170:	/* tns connect timeout */
104
+	case 12224:	/* tns no listener */
105
+	case 12225:	/* tns destination host unrecheable */
106
+	case 12230:	/* tns network error */
107
+	case 12525:	/* tns (internal) timeout */
108
+	case 12521:	/* tns can't resolve db name */
109
+	case 12537:	/* tns connection cloed */
110
+	case 12541:	/* tns not running */
111
+	case 12543:	/* tns destination host unrecheable */
112
+	case 12547:	/* tns lost contact */
113
+	case 12560:	/* tns protocol(transport) error */
114
+	case 12561:	/* tns unknown error */
115
+	case 12608:	/* tns send timeount */
116
+	case 12609:	/* tns receive timeount */
117
+	    LM_ERR("conneciom dropped\n");
118
+	    db_oracle_disconnect(con);
119
+	default:
120
+		break;
121
+	}
122
+
123
+	return errbuf;
124
+}
125
+
126
+const char* db_oracle_error(ora_con_t* con, sword status)
127
+{
128
+	switch (status) {
129
+		case OCI_SUCCESS:
130
+			return "internal (success)";
131
+
132
+		case OCI_SUCCESS_WITH_INFO:
133
+		case OCI_ERROR:
134
+			return db_oracle_errorinfo(con);
135
+
136
+		case OCI_NEED_DATA:
137
+			return "need data";
138
+
139
+		case OCI_NO_DATA:
140
+			return "no data";
141
+
142
+		case OCI_INVALID_HANDLE:
143
+			return "invalid handle";
144
+
145
+		case OCI_STILL_EXECUTING:	// ORA-3123
146
+			return "executing (logic)";
147
+
148
+		case OCI_CONTINUE:
149
+			return "continue (library)";
150
+
151
+		default:
152
+			snprintf(errbuf, sizeof(errbuf),
153
+				"unknown status %u", status);
154
+			return errbuf;
155
+	}
156
+}
157
+
158
+
159
+/*
160
+ * Initialize database module
161
+ * No function should be called before this
162
+ */
163
+db_con_t* db_oracle_init(const str* _url)
164
+{
165
+	return db_do_init(_url, (void *)db_oracle_new_connection);
166
+}
167
+
168
+
169
+/*
170
+ * Shut down database module
171
+ * No function should be called after this
172
+ */
173
+void db_oracle_close(db_con_t* _h)
174
+{
175
+	db_do_close(_h, db_oracle_free_connection);
176
+}
177
+
178
+
179
+/*
180
+ * Release a result set from memory
181
+ */
182
+int db_oracle_free_result(db_con_t* _h, db_res_t* _r)
183
+{
184
+	if (!_h || !_r) {
185
+		LM_ERR("invalid parameter value\n");
186
+		return -1;
187
+	}
188
+
189
+	if (db_free_result(_r) < 0)
190
+	{
191
+		LM_ERR("failed to free result structure\n");
192
+		return -1;
193
+	}
194
+	return 0;
195
+}
196
+
197
+
198
+/*
199
+ * Send an SQL query to the server
200
+ */
201
+static int db_oracle_submit_query(const db_con_t* _h, const str* _s)
202
+{
203
+	OCIBind* bind[MAX_BIND_HANDLES];
204
+	OCIDate odt[sizeof(bind)/sizeof(bind[0])];
205
+	str tmps;
206
+	sword status;
207
+	int pass;
208
+	ora_con_t* con = CON_ORA(_h);
209
+	query_data_t* pqd = con->pqdata;
210
+	size_t hc = pqd->_n + pqd->_nw;
211
+	OCIStmt *stmthp;
212
+
213
+	if (hc >= sizeof(bind)/sizeof(bind[0])) {
214
+		LM_ERR("too many bound. Rebuild with MAX_BIND_HANDLES >= %u\n",
215
+			(unsigned)hc);
216
+		return -1;
217
+	}
218
+	
219
+	if (!pqd->_rs) {
220
+		/*
221
+		 * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS
222
+		 * in StmtExecute
223
+		 */
224
+		tmps.len = snprintf(st_buf, sizeof(st_buf),
225
+			"begin %.*s; commit write batch nowait; end;",
226
+			_s->len, _s->s);
227
+		if ((unsigned)tmps.len >= sizeof(st_buf))
228
+			return sql_buf_small();
229
+		tmps.s = st_buf;
230
+		_s = &tmps;
231
+	}
232
+
233
+	pass = 1;
234
+	if (!con->connected) {
235
+		status = db_oracle_reconnect(con);
236
+		if (status != OCI_SUCCESS) {
237
+			LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status));
238
+			return -2;
239
+		}
240
+		LM_INFO("connection restored\n");
241
+		--pass;
242
+	}
243
+repeat:
244
+	stmthp = NULL;
245
+	status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp,
246
+		    OCI_HTYPE_STMT, 0, NULL);
247
+	if (status != OCI_SUCCESS)
248
+		goto ora_err;
249
+	status = OCIStmtPrepare(stmthp, con->errhp, (text*)_s->s, _s->len,
250
+		OCI_NTV_SYNTAX, OCI_DEFAULT);
251
+	if (status != OCI_SUCCESS)
252
+		goto ora_err;
253
+
254
+	if (hc) {
255
+		bmap_t bmap;
256
+		size_t pos = 1;
257
+		int i;
258
+
259
+		memset(bind, 0, hc*sizeof(bind[0]));
260
+		for (i = 0; i < pqd->_n; i++) {
261
+			if (db_oracle_val2bind(&bmap, &pqd->_v[i], &odt[pos]) < 0)
262
+				goto bind_err;
263
+			status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
264
+				pos, bmap.addr, bmap.size, bmap.type,
265
+				NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
266
+			if (status != OCI_SUCCESS)
267
+				goto ora_err;
268
+			++pos;
269
+		}
270
+		for (i = 0; i < pqd->_nw; i++) {
271
+			if (db_oracle_val2bind(&bmap, &pqd->_w[i], &odt[pos]) < 0) {
272
+bind_err:
273
+				OCIHandleFree(stmthp, OCI_HTYPE_STMT);
274
+				LM_ERR("can't map values\n");
275
+				return -3;
276
+			}
277
+			status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
278
+				pos, bmap.addr, bmap.size, bmap.type,
279
+				NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
280
+			if (status != OCI_SUCCESS)
281
+				goto ora_err;
282
+			++pos;
283
+		}
284
+	}
285
+
286
+	// timelimited operation
287
+	status = begin_timelimit(con, 0);
288
+	if (status != OCI_SUCCESS) goto ora_err;
289
+	do status = OCIStmtExecute(con->svchp, stmthp, con->errhp,
290
+		!pqd->_rs, 0, NULL, NULL,
291
+		pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT);
292
+	while (wait_timelimit(con, status));
293
+	if (done_timelimit(con, status)) goto stop_exec;
294
+	switch (status)	{
295
+	case OCI_SUCCESS_WITH_INFO:
296
+		LM_WARN("driver: %s\n", db_oracle_errorinfo(con));
297
+		//PASS THRU
298
+	case OCI_SUCCESS:
299
+		if (pqd->_rs)
300
+			*pqd->_rs = stmthp;
301
+		else
302
+			OCIHandleFree(stmthp, OCI_HTYPE_STMT);
303
+		return 0;
304
+	default:
305
+	    pass = -pass;
306
+	    break;
307
+	}
308
+
309
+ora_err:
310
+	LM_ERR("driver: %s\n", db_oracle_error(con, status));
311
+stop_exec:
312
+	if (stmthp)
313
+		OCIHandleFree(stmthp, OCI_HTYPE_STMT);
314
+	if (pass == -1 && !con->connected) {
315
+		/* Attemtp to reconnect */
316
+		if (db_oracle_reconnect(con) == OCI_SUCCESS) {
317
+			LM_NOTICE("attempt repeat after reconnect\n");
318
+			pass = 0;
319
+			goto repeat;
320
+		}
321
+		LM_ERR("connection loss\n");
322
+	}
323
+	return -4;
324
+}
325
+
326
+
327
+/*
328
+ * Query table for specified rows
329
+ * _h: structure representing database connection
330
+ * _k: key names
331
+ * _op: operators
332
+ * _v: values of the keys that must match
333
+ * _c: column names to return
334
+ * _n: number of key=values pairs to compare
335
+ * _nc: number of columns to return
336
+ * _o: order by the specified column
337
+ */
338
+int db_oracle_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op,
339
+		const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
340
+		const db_key_t _o, db_res_t** _r)
341
+{
342
+	query_data_t cb;
343
+	OCIStmt* reshp;
344
+	int rc;
345
+
346
+	if (!_h || !CON_TABLE(_h) || !_r) {
347
+		LM_ERR("invalid parameter value\n");
348
+		return -1;
349
+	}
350
+
351
+	cb._rs = &reshp;
352
+	cb._v  = _v;
353
+	cb._n  = _n;
354
+	cb._w  = NULL;
355
+	cb._nw = 0;
356
+	CON_ORA(_h)->pqdata = &cb;
357
+	CON_ORA(_h)->bindpos = 0;
358
+	rc = db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r,
359
+		db_oracle_val2str, db_oracle_submit_query, db_oracle_store_result);
360
+	CON_ORA(_h)->pqdata = NULL;	/* paranoid for next call */
361
+	return rc;
362
+}
363
+
364
+
365
+/*
366
+ * Execute a raw SQL query
367
+ */
368
+int db_oracle_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
369
+{
370
+	query_data_t cb;
371
+	OCIStmt* reshp;
372
+	int len;
373
+	const char *p;
374
+
375
+	if (!_h || !_s || !_s->s) {
376
+badparam:
377
+		LM_ERR("invalid parameter value\n");
378
+		return -1;
379
+	}
380
+
381
+
382
+	memset(&cb, 0, sizeof(cb));
383
+
384
+	p = _s->s;
385
+	len = _s->len;
386
+	while (len && *p == ' ') ++p, --len;
387
+#define _S_DIFF(p, l, S) (l <= sizeof(S)-1 || strncasecmp(p, S, sizeof(S)-1))
388
+	if (!_S_DIFF(p, len, "select ")) {
389
+		if (!_r) goto badparam;
390
+		cb._rs = &reshp;
391
+	} else {
392
+		if (	_S_DIFF(p, len, "insert ")
393
+		    && 	_S_DIFF(p, len, "delete ")
394
+		    && 	_S_DIFF(p, len, "update "))
395
+		{
396
+			LM_ERR("unknown raw_query: '%.*s'\n", _s->len, _s->s);
397
+			return -2;
398
+		}
399
+#undef _S_DIFF
400
+		if (_r) goto badparam;
401
+		cb._rs = NULL;
402
+	}
403
+
404
+	len = db_do_raw_query(_h, _s, _r, db_oracle_submit_query, db_oracle_store_result);
405
+	CON_ORA(_h)->pqdata = NULL;	/* paranoid for next call */
406
+	return len;
407
+}
408
+
409
+
410
+/*
411
+ * Insert a row into specified table
412
+ * _h: structure representing database connection
413
+ * _k: key names
414
+ * _v: values of the keys
415
+ * _n: number of key=value pairs
416
+ */
417
+int db_oracle_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v,
418
+		int _n)
419
+{
420
+	query_data_t cb;
421
+	int rc;
422
+
423
+	if (!_h || !CON_TABLE(_h)) {
424
+		LM_ERR("invalid parameter value\n");
425
+		return -1;
426
+	}
427
+
428
+	cb._rs = NULL;
429
+	cb._v  = _v;
430
+	cb._n  = _n;
431
+	cb._w  = NULL;
432
+	cb._nw = 0;
433
+	CON_ORA(_h)->pqdata = &cb;
434
+	CON_ORA(_h)->bindpos = 0;
435
+	rc = db_do_insert(_h, _k, _v, _n, db_oracle_val2str, db_oracle_submit_query);
436
+	CON_ORA(_h)->pqdata = NULL;	/* paranoid for next call */
437
+	return rc;
438
+}
439
+
440
+
441
+/*
442
+ * Delete a row from the specified table
443
+ * _h: structure representing database connection
444
+ * _k: key names
445
+ * _o: operators
446
+ * _v: values of the keys that must match
447
+ * _n: number of key=value pairs
448
+ */
449
+int db_oracle_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
450
+		const db_val_t* _v, int _n)
451
+{
452
+	query_data_t cb;
453
+	int rc;
454
+
455
+	if (!_h || !CON_TABLE(_h)) {
456
+		LM_ERR("invalid parameter value\n");
457
+		return -1;
458
+	}
459
+
460
+	cb._rs = NULL;
461
+	cb._v  = _v;
462
+	cb._n  = _n;
463
+	cb._w  = NULL;
464
+	cb._nw = 0;
465
+	CON_ORA(_h)->pqdata = &cb;
466
+	CON_ORA(_h)->bindpos = 0;
467
+	rc = db_do_delete(_h, _k, _o, _v, _n, db_oracle_val2str, db_oracle_submit_query);
468
+	CON_ORA(_h)->pqdata = NULL;	/* paranoid for next call */
469
+	return rc;
470
+}
471
+
472
+
473
+/*
474
+ * Update some rows in the specified table
475
+ * _h: structure representing database connection
476
+ * _k: key names
477
+ * _o: operators
478
+ * _v: values of the keys that must match
479
+ * _uk: updated columns
480
+ * _uv: updated values of the columns
481
+ * _n: number of key=value pairs
482
+ * _un: number of columns to update
483
+ */
484
+int db_oracle_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
485
+		const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv,
486
+		int _n, int _un)
487
+{
488
+	query_data_t cb;
489
+	int rc;
490
+	
491
+	if (!_h || !CON_TABLE(_h)) {
492
+		LM_ERR("invalid parameter value\n");
493
+		return -1;
494
+	}
495
+
496
+	cb._rs = NULL;
497
+	cb._v  = _uv;
498
+	cb._n  = _un;
499
+	cb._w  = _v;
500
+	cb._nw = _n;
501
+	CON_ORA(_h)->pqdata = &cb;
502
+	CON_ORA(_h)->bindpos = 0;
503
+	rc = db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un,
504
+			db_oracle_val2str, db_oracle_submit_query);
505
+	CON_ORA(_h)->pqdata = NULL;	/* paranoid for next call */
506
+	return rc;
507
+}
508
+
509
+
510
+/*
511
+ * Store name of table that will be used by
512
+ * subsequent database functions
513
+ */
514
+int db_oracle_use_table(db_con_t* _h, const str* _t)
515
+{
516
+	return db_use_table(_h, _t);
517
+}
0 518
new file mode 100644
... ...
@@ -0,0 +1,103 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Oracle module core functions
4
+ *
5
+ * Copyright (C) 2007,2008 TRUNK MOBILE
6
+ *
7
+ * This file is part of openser, a free SIP server.
8
+ *
9
+ * openser is free software; you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation; either version 2 of the License, or
12
+ * (at your option) any later version
13
+ *
14
+ * openser is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+
25
+#ifndef DBASE_H
26
+#define DBASE_H
27
+
28
+
29
+#include "../../db/db_con.h"
30
+#include "../../db/db_res.h"
31
+#include "../../db/db_key.h"
32
+#include "../../db/db_op.h"
33
+#include "../../db/db_val.h"
34
+
35
+
36
+/*
37
+ * Initialize database connection
38
+ */
39
+db_con_t* db_oracle_init(const str* _sqlurl);
40
+
41
+
42
+/*
43
+ * Close a database connection
44
+ */
45
+void db_oracle_close(db_con_t* _h);
46
+
47
+
48
+/*
49
+ * Free all memory allocated by get_result
50
+ */
51
+int db_oracle_free_result(db_con_t* _h, db_res_t* _r);
52
+
53
+
54
+/*
55
+ * Do a query
56
+ */
57
+int db_oracle_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op,
58
+		const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
59
+		const db_key_t _o, db_res_t** _r);
60
+
61
+
62
+/*
63
+ * Raw SQL query
64
+ */
65
+int db_oracle_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r);
66
+
67
+
68
+/*
69
+ * Insert a row into table
70
+ */
71
+int db_oracle_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v,
72
+		int _n);
73
+
74
+
75
+/*
76
+ * Delete a row from table
77
+ */
78
+int db_oracle_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
79
+		const db_val_t* _v, int _n);
80
+
81
+
82
+/*
83
+ * Update a row in table
84
+ */
85
+int db_oracle_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
86
+		const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv,
87
+		int _n, int _un);
88
+
89
+
90
+/*
91
+ * Store name of table that will be used by
92
+ * subsequent database functions
93
+ */
94
+int db_oracle_use_table(db_con_t* _h, const str* _t);
95
+
96
+
97
+/*
98
+ * Make error message. Always return negative value
99
+ */
100
+int sql_buf_small(void);
101
+
102
+#endif /* DBASE_H */
0 103
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+<?xml version="1.0" encoding='ISO-8859-1'?>
1
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
3
+
4
+
5
+<!ENTITY admin SYSTEM "db_oracle_admin.xml">
6
+<!ENTITY faq SYSTEM "../../../doc/module_faq.xml">
7
+
8
+<!-- Include general documentation entities -->
9
+<!ENTITY % docentities SYSTEM "../../../doc/entities.xml">
10
+%docentities;
11
+
12
+]>
13
+
14
+<book>
15
+    <bookinfo>
16
+	<title>oracle Module</title>
17
+	<productname class="trade">&sername;</productname>
18
+	<authorgroup>
19
+	    <author>
20
+		<firstname>Iouri</firstname>
21
+		<surname>Kharon</surname>
22
+		<email>yjh@styx.cabel.net</email>
23
+	    </author>
24
+	    <author>
25
+		<firstname>Yury</firstname>
26
+		<surname>Skandarov</surname>
27
+		<email>kandman@trunkmobile.com</email>
28
+	    </author>
29
+	    <author>
30
+		<firstname>Iakov</firstname>
31
+		<surname>Kharon</surname>
32
+		    <email>jyh@trunkmobile.com</email>
33
+	    </author>
34
+	    <editor>
35
+		<firstname>Iouri</firstname>
36
+		<surname>Kharon</surname>
37
+		<email>yjh@styx.cabel.net</email>
38
+	    </editor>
39
+	</authorgroup>
40
+	<copyright>
41
+	    <year>2007,2008</year>
42
+	    <holder>TRUNK MOBILE, INC.</holder>
43
+	</copyright>
44
+	<revhistory>
45
+	    <revision>
46
+		<revnumber>$Revision: 3936 $</revnumber>
47
+		<date>$Date: 2008-03-07 13:57:32 +0300 (Fri, 07 Mar 2008) $</date>
48
+	    </revision>
49
+	</revhistory>
50
+    </bookinfo>
51
+    <toc></toc>
52
+
53
+    &admin;
54
+    &faq;
55
+
56
+</book>
0 57
new file mode 100644
... ...
@@ -0,0 +1,147 @@
0
+<!-- Module User's Guide -->
1
+
2
+<chapter>
3
+
4
+	<title>User's Guide</title>
5
+
6
+	<section>
7
+	<title>Overview</title>
8
+	<para>
9
+		This is a module which provides Oracle connectivity for OpenSER.
10
+		It implements the DB API defined in OpenSER.
11
+	</para>
12
+	</section>
13
+
14
+	<section>
15
+	<title>Dependencies</title>
16
+	<section>
17
+		<title>&ser; Modules</title>
18
+		<para>
19
+		The following modules must be loaded before this module:
20
+			<itemizedlist>
21
+			<listitem>
22
+			<para>