1 /******************************************************************************
2 * $Id: ogrocisession.cpp 28481 2015-02-13 17:11:15Z rouault $
3 *
4 * Project: Oracle Spatial Driver
5 * Purpose: Implementation of OGROCISession, which encapsulates much of the
6 * direct access to OCI.
7 * Author: Frank Warmerdam, warmerdam@pobox.com
8 *
9 ******************************************************************************
10 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_oci.h"
32 #include "cpl_conv.h"
33
34 CPL_CVSID("$Id: ogrocisession.cpp 28481 2015-02-13 17:11:15Z rouault $");
35
36 /************************************************************************/
37 /* OGRGetOCISession() */
38 /************************************************************************/
39
OGRGetOCISession(const char * pszUserid,const char * pszPassword,const char * pszDatabase)40 OGROCISession * OGRGetOCISession( const char *pszUserid,
41 const char *pszPassword,
42 const char *pszDatabase )
43
44 {
45 OGROCISession *poSession;
46
47 poSession = new OGROCISession();
48 if( poSession->EstablishSession( pszUserid, pszPassword, pszDatabase ) )
49 return poSession;
50 else
51 {
52 delete poSession;
53 return NULL;
54 }
55 }
56
57 /************************************************************************/
58 /* OGROCISession() */
59 /************************************************************************/
60
OGROCISession()61 OGROCISession::OGROCISession()
62
63 {
64 hEnv = NULL;
65 hError = NULL;
66 hSvcCtx = NULL;
67 hServer = NULL;
68 hSession = NULL;
69 hDescribe = NULL;
70 hGeometryTDO = NULL;
71 hOrdinatesTDO = NULL;
72 hElemInfoTDO = NULL;
73 pszUserid = NULL;
74 pszPassword = NULL;
75 pszDatabase = NULL;
76 }
77
78 /************************************************************************/
79 /* ~OGROCISession() */
80 /************************************************************************/
81
~OGROCISession()82 OGROCISession::~OGROCISession()
83
84 {
85 if( hDescribe != NULL )
86 OCIHandleFree((dvoid *)hDescribe, (ub4)OCI_HTYPE_DESCRIBE);
87
88 if( hSvcCtx != NULL )
89 {
90 OCISessionEnd(hSvcCtx, hError, hSession, (ub4) 0);
91
92 if( hSvcCtx && hError)
93 OCIServerDetach(hServer, hError, (ub4) OCI_DEFAULT);
94
95 if( hServer )
96 OCIHandleFree((dvoid *) hServer, (ub4) OCI_HTYPE_SERVER);
97
98 if( hSvcCtx )
99 OCIHandleFree((dvoid *) hSvcCtx, (ub4) OCI_HTYPE_SVCCTX);
100
101 if( hError )
102 OCIHandleFree((dvoid *) hError, (ub4) OCI_HTYPE_ERROR);
103
104 if( hSession )
105 OCIHandleFree((dvoid *) hSession, (ub4) OCI_HTYPE_SESSION);
106
107 if( hEnv )
108 OCIHandleFree((dvoid *) hEnv, (ub4) OCI_HTYPE_ENV);
109 }
110
111 CPLFree( pszUserid );
112 CPLFree( pszPassword );
113 CPLFree( pszDatabase );
114 }
115
116 /************************************************************************/
117 /* EstablishSession() */
118 /************************************************************************/
119
EstablishSession(const char * pszUserid,const char * pszPassword,const char * pszDatabase)120 int OGROCISession::EstablishSession( const char *pszUserid,
121 const char *pszPassword,
122 const char *pszDatabase )
123
124 {
125 /* -------------------------------------------------------------------- */
126 /* Operational Systems's authentication option */
127 /* -------------------------------------------------------------------- */
128
129 ub4 eCred = OCI_CRED_RDBMS;
130
131 if( EQUAL(pszDatabase, "") &&
132 EQUAL(pszPassword, "") &&
133 EQUAL(pszUserid, "/") )
134 {
135 eCred = OCI_CRED_EXT;
136 }
137
138 /* -------------------------------------------------------------------- */
139 /* Initialize Environment handler */
140 /* -------------------------------------------------------------------- */
141
142 if( Failed( OCIInitialize((ub4) (OCI_DEFAULT | OCI_OBJECT), (dvoid *)0,
143 (dvoid * (*)(dvoid *, size_t)) 0,
144 (dvoid * (*)(dvoid *, dvoid *, size_t))0,
145 (void (*)(dvoid *, dvoid *)) 0 ) ) )
146 {
147 return FALSE;
148 }
149
150 if( Failed( OCIEnvInit( (OCIEnv **) &hEnv, OCI_DEFAULT, (size_t) 0,
151 (dvoid **) 0 ) ) )
152 {
153 return FALSE;
154 }
155
156 if( Failed( OCIHandleAlloc( (dvoid *) hEnv, (dvoid **) &hError,
157 OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0) ) )
158 {
159 return FALSE;
160 }
161
162 /* -------------------------------------------------------------------- */
163 /* Initialize Server Context */
164 /* -------------------------------------------------------------------- */
165
166 if( Failed( OCIHandleAlloc( (dvoid *) hEnv, (dvoid **) &hServer,
167 OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0) ) )
168 {
169 return FALSE;
170 }
171
172 if( Failed( OCIHandleAlloc( (dvoid *) hEnv, (dvoid **) &hSvcCtx,
173 OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0) ) )
174 {
175 return FALSE;
176 }
177
178 if( Failed( OCIServerAttach( hServer, hError, (text*) pszDatabase,
179 strlen((char*) pszDatabase), 0) ) )
180 {
181 return FALSE;
182 }
183
184 /* -------------------------------------------------------------------- */
185 /* Initialize Service Context */
186 /* -------------------------------------------------------------------- */
187
188 if( Failed( OCIAttrSet( (dvoid *) hSvcCtx, OCI_HTYPE_SVCCTX, (dvoid *)hServer,
189 (ub4) 0, OCI_ATTR_SERVER, (OCIError *) hError) ) )
190 {
191 return FALSE;
192 }
193
194 if( Failed( OCIHandleAlloc((dvoid *) hEnv, (dvoid **)&hSession,
195 (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0) ) )
196 {
197 return FALSE;
198 }
199
200 if( Failed( OCIAttrSet((dvoid *) hSession, (ub4) OCI_HTYPE_SESSION,
201 (dvoid *) pszUserid, (ub4) strlen((char *) pszUserid),
202 (ub4) OCI_ATTR_USERNAME, hError) ) )
203 {
204 return FALSE;
205 }
206
207 if( Failed( OCIAttrSet((dvoid *) hSession, (ub4) OCI_HTYPE_SESSION,
208 (dvoid *) pszPassword, (ub4) strlen((char *) pszPassword),
209 (ub4) OCI_ATTR_PASSWORD, hError) ) )
210 {
211 return FALSE;
212 }
213
214 /* -------------------------------------------------------------------- */
215 /* Initialize Session */
216 /* -------------------------------------------------------------------- */
217
218 if( Failed( OCISessionBegin(hSvcCtx, hError, hSession, eCred,
219 (ub4) OCI_DEFAULT) ) )
220 {
221 CPLDebug("OCI", "OCISessionBegin() failed to intialize session");
222 return FALSE;
223 }
224
225 /* -------------------------------------------------------------------- */
226 /* Initialize Service */
227 /* -------------------------------------------------------------------- */
228
229 if( Failed( OCIAttrSet((dvoid *) hSvcCtx, (ub4) OCI_HTYPE_SVCCTX,
230 (dvoid *) hSession, (ub4) 0,
231 (ub4) OCI_ATTR_SESSION, hError) ) )
232 {
233 return FALSE;
234 }
235
236 /* -------------------------------------------------------------------- */
237 /* Create a describe handle. */
238 /* -------------------------------------------------------------------- */
239
240 if( Failed(
241 OCIHandleAlloc( hEnv, (dvoid **) &hDescribe, (ub4)OCI_HTYPE_DESCRIBE,
242 (size_t)0, (dvoid **)0 ),
243 "OCIHandleAlloc(Describe)" ) )
244 return FALSE;
245
246 /* -------------------------------------------------------------------- */
247 /* Try to get the MDSYS.SDO_GEOMETRY type object. */
248 /* -------------------------------------------------------------------- */
249 /* If we have no MDSYS.SDO_GEOMETRY then we consider we are
250 working along with the VRT driver and access non spatial tables.
251 See #2202 for more details (Tamas Szekeres)*/
252 if (OCIDescribeAny(hSvcCtx, hError,
253 (text *) SDO_GEOMETRY, (ub4) strlen(SDO_GEOMETRY),
254 OCI_OTYPE_NAME, (ub1) OCI_DEFAULT, (ub1)OCI_PTYPE_TYPE,
255 hDescribe ) != OCI_ERROR)
256 {
257 hGeometryTDO = PinTDO( SDO_GEOMETRY );
258 if( hGeometryTDO == NULL )
259 return FALSE;
260
261 /* -------------------------------------------------------------------- */
262 /* Try to get the MDSYS.SDO_ORDINATE_ARRAY type object. */
263 /* -------------------------------------------------------------------- */
264 hOrdinatesTDO = PinTDO( "MDSYS.SDO_ORDINATE_ARRAY" );
265 if( hOrdinatesTDO == NULL )
266 return FALSE;
267
268 /* -------------------------------------------------------------------- */
269 /* Try to get the MDSYS.SDO_ELEM_INFO_ARRAY type object. */
270 /* -------------------------------------------------------------------- */
271 hElemInfoTDO = PinTDO( "MDSYS.SDO_ELEM_INFO_ARRAY" );
272 if( hElemInfoTDO == NULL )
273 return FALSE;
274 }
275 /* -------------------------------------------------------------------- */
276 /* Record information about the session. */
277 /* -------------------------------------------------------------------- */
278 this->pszUserid = CPLStrdup(pszUserid);
279 this->pszPassword = CPLStrdup(pszPassword);
280 this->pszDatabase = CPLStrdup(pszDatabase);
281
282 /* -------------------------------------------------------------------- */
283 /* Setting upt the OGR compatible time formating rules. */
284 /* -------------------------------------------------------------------- */
285 OGROCIStatement oSetNLSTimeFormat( this );
286 if( oSetNLSTimeFormat.Execute( "ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD' \
287 NLS_TIME_FORMAT='HH24:MI:SS' NLS_TIME_TZ_FORMAT='HH24:MI:SS TZHTZM' \
288 NLS_TIMESTAMP_FORMAT='YYYY/MM/DD HH24:MI:SS' \
289 NLS_TIMESTAMP_TZ_FORMAT='YYYY/MM/DD HH24:MI:SS TZHTZM' \
290 NLS_NUMERIC_CHARACTERS = '. '" ) != CE_None )
291 return OGRERR_FAILURE;
292
293 return TRUE;
294 }
295
296 /************************************************************************/
297 /* Failed() */
298 /************************************************************************/
299
Failed(sword nStatus,const char * pszFunction)300 int OGROCISession::Failed( sword nStatus, const char *pszFunction )
301
302 {
303 if( pszFunction == NULL )
304 pszFunction = "<unnamed>";
305 if( nStatus == OCI_ERROR )
306 {
307 sb4 nErrCode = 0;
308 char szErrorMsg[10000];
309
310 szErrorMsg[0] = '\0';
311 if( hError != NULL )
312 {
313 OCIErrorGet( (dvoid *) hError, (ub4) 1, NULL, &nErrCode,
314 (text *) szErrorMsg, (ub4) sizeof(szErrorMsg),
315 OCI_HTYPE_ERROR );
316 }
317 szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
318
319 CPLError( CE_Failure, CPLE_AppDefined,
320 "%s in %s", szErrorMsg, pszFunction );
321 return TRUE;
322 }
323 else if( nStatus == OCI_NEED_DATA )
324 {
325 CPLError( CE_Failure, CPLE_AppDefined,
326 "OCI_NEED_DATA" );
327 return TRUE;
328 }
329 else if( nStatus == OCI_INVALID_HANDLE )
330 {
331 CPLError( CE_Failure, CPLE_AppDefined,
332 "OCI_INVALID_HANDLE in %s", pszFunction );
333 return TRUE;
334 }
335 else if( nStatus == OCI_STILL_EXECUTING )
336 {
337 CPLError( CE_Failure, CPLE_AppDefined,
338 "OCI_STILL_EXECUTING in %s", pszFunction );
339 return TRUE;
340 }
341 else if( nStatus == OCI_CONTINUE )
342 {
343 CPLError( CE_Failure, CPLE_AppDefined,
344 "OCI_CONTINUE in %s", pszFunction );
345 return TRUE;
346 }
347 else
348 return FALSE;
349 }
350
351 /************************************************************************/
352 /* GetParmInfo() */
353 /************************************************************************/
354
355 CPLErr
GetParmInfo(OCIParam * hParmDesc,OGRFieldDefn * poOGRDefn,ub2 * pnOCIType,ub4 * pnOCILen)356 OGROCISession::GetParmInfo( OCIParam *hParmDesc, OGRFieldDefn *poOGRDefn,
357 ub2 *pnOCIType, ub4 *pnOCILen )
358
359 {
360 ub2 nOCIType, nOCILen;
361 ub4 nColLen;
362 ub1 bOCINull;
363 char *pszColName;
364 char szTermColName[128];
365
366 /* -------------------------------------------------------------------- */
367 /* Get basic parameter details. */
368 /* -------------------------------------------------------------------- */
369 if( Failed(
370 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM,
371 (dvoid **)&nOCIType, 0, OCI_ATTR_DATA_TYPE, hError ),
372 "OCIAttrGet(Type)" ) )
373 return CE_Failure;
374
375 if( Failed(
376 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM,
377 (dvoid **)&nOCILen, 0, OCI_ATTR_DATA_SIZE, hError ),
378 "OCIAttrGet(Size)" ) )
379 return CE_Failure;
380
381 if( Failed(
382 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM, (dvoid **)&pszColName,
383 &nColLen, OCI_ATTR_NAME, hError ),
384 "OCIAttrGet(Name)") )
385 return CE_Failure;
386
387 if( Failed(
388 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM, (dvoid **)&bOCINull,
389 0, OCI_ATTR_IS_NULL, hError ),
390 "OCIAttrGet(Null)") )
391 return CE_Failure;
392
393 if( nColLen >= sizeof(szTermColName) )
394 {
395 CPLError( CE_Failure, CPLE_AppDefined,
396 "Column length (%d) longer than column name buffer (%d) in\n"
397 "OGROCISession::GetParmInfo()",
398 nColLen, (int) sizeof(szTermColName) );
399 return CE_Failure;
400 }
401
402 strncpy( szTermColName, pszColName, nColLen );
403 szTermColName[nColLen] = '\0';
404
405 poOGRDefn->SetName( szTermColName );
406 poOGRDefn->SetNullable( bOCINull );
407
408 /* -------------------------------------------------------------------- */
409 /* Attempt to classify as an OGRType. */
410 /* -------------------------------------------------------------------- */
411 switch( nOCIType )
412 {
413 case SQLT_CHR:
414 case SQLT_AFC: /* CHAR(), NCHAR() */
415 poOGRDefn->SetType( OFTString );
416 if( nOCILen <= 4000 )
417 poOGRDefn->SetWidth( nOCILen );
418 break;
419
420 case SQLT_NUM:
421 {
422 // NOTE: OCI docs say this should be ub1 type, but we have
423 // determined that oracle is actually returning a short so we
424 // use that type and try to compensate for possible problems by
425 // initializing, and dividing by 256 if it is large.
426 unsigned short byPrecision = 0;
427 sb1 nScale;
428
429 if( Failed(
430 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM, (dvoid **)&byPrecision,
431 0, OCI_ATTR_PRECISION, hError ),
432 "OCIAttrGet(Precision)" ) )
433 return CE_Failure;
434 if( Failed(
435 OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM, (dvoid **)&nScale,
436 0, OCI_ATTR_SCALE, hError ),
437 "OCIAttrGet(Scale)") )
438 return CE_Failure;
439 #ifdef notdef
440 CPLDebug( "OCI", "%s: Scale=%d, Precision=%d",
441 szTermColName, nScale, byPrecision );
442 #endif
443 if( byPrecision > 255 )
444 byPrecision = byPrecision / 256;
445
446 if( nScale < 0 )
447 poOGRDefn->SetType( OFTReal );
448 else if( nScale > 0 )
449 {
450 poOGRDefn->SetType( OFTReal );
451 poOGRDefn->SetWidth( byPrecision );
452 poOGRDefn->SetPrecision( nScale );
453 }
454 else if( byPrecision < 38 )
455 {
456 poOGRDefn->SetType( (byPrecision < 10) ? OFTInteger : OFTInteger64 );
457 poOGRDefn->SetWidth( byPrecision );
458 }
459 else
460 {
461 poOGRDefn->SetType( OFTInteger64 );
462 }
463 }
464 break;
465
466 case SQLT_DAT:
467 case SQLT_DATE:
468 poOGRDefn->SetType( OFTDate );
469 break;
470 case SQLT_TIMESTAMP:
471 case SQLT_TIMESTAMP_TZ:
472 case SQLT_TIMESTAMP_LTZ:
473 case SQLT_TIME:
474 case SQLT_TIME_TZ:
475 poOGRDefn->SetType( OFTDateTime );
476 break;
477
478 case SQLT_RID:
479 case SQLT_BIN:
480 case SQLT_LBI:
481 case 111: /* REF */
482 case SQLT_CLOB:
483 case SQLT_BLOB:
484 case SQLT_FILE:
485 case 208: /* UROWID */
486 poOGRDefn->SetType( OFTBinary );
487 break;
488
489 default:
490 poOGRDefn->SetType( OFTBinary );
491 break;
492 }
493
494 if( pnOCIType != NULL )
495 *pnOCIType = nOCIType;
496
497 if( pnOCILen != NULL )
498 *pnOCILen = nOCILen;
499
500 return CE_None;
501 }
502
503 /************************************************************************/
504 /* CleanName() */
505 /* */
506 /* Modify a name in-place to be a well formed Oracle name. */
507 /************************************************************************/
508
CleanName(char * pszName)509 void OGROCISession::CleanName( char * pszName )
510
511 {
512 int i;
513
514 if( strlen(pszName) > 30 )
515 pszName[30] = '\0';
516
517 for( i = 0; pszName[i] != '\0'; i++ )
518 {
519 pszName[i] = toupper(pszName[i]);
520
521 if( (pszName[i] < '0' || pszName[i] > '9')
522 && (pszName[i] < 'A' || pszName[i] > 'Z')
523 && pszName[i] != '_' )
524 pszName[i] = '_';
525 }
526 }
527
528 /************************************************************************/
529 /* PinTDO() */
530 /* */
531 /* Fetch a Type Description Object for the named type. */
532 /************************************************************************/
533
PinTDO(const char * pszType)534 OCIType *OGROCISession::PinTDO( const char *pszType )
535
536 {
537 OCIParam *hGeomParam = NULL;
538 OCIRef *hGeomTypeRef = NULL;
539 OCIType *hPinnedTDO = NULL;
540
541 if( Failed(
542 OCIDescribeAny(hSvcCtx, hError,
543 (text *) pszType, (ub4) strlen(pszType),
544 OCI_OTYPE_NAME, (ub1)1, (ub1)OCI_PTYPE_TYPE,
545 hDescribe ),
546 "GetTDO()->OCIDescribeAny()" ) )
547 return NULL;
548
549 if( Failed(
550 OCIAttrGet((dvoid *)hDescribe, (ub4)OCI_HTYPE_DESCRIBE,
551 (dvoid *)&hGeomParam, (ub4 *)0, (ub4)OCI_ATTR_PARAM,
552 hError), "GetTDO()->OCIGetAttr(ATTR_PARAM)") )
553 return NULL;
554
555 if( Failed(
556 OCIAttrGet((dvoid *)hGeomParam, (ub4)OCI_DTYPE_PARAM,
557 (dvoid *)&hGeomTypeRef, (ub4 *)0, (ub4)OCI_ATTR_REF_TDO,
558 hError), "GetTDO()->OCIAttrGet(ATTR_REF_TDO)" ) )
559 return NULL;
560
561 if( Failed(
562 OCIObjectPin(hEnv, hError, hGeomTypeRef, (OCIComplexObject *)0,
563 OCI_PIN_ANY, OCI_DURATION_SESSION,
564 OCI_LOCK_NONE, (dvoid **)&hPinnedTDO ),
565 "GetTDO()->OCIObjectPin()" ) )
566 return NULL;
567
568 return hPinnedTDO;
569 }
570