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