OCILIB (C Driver for Oracle) 3.12.1
typeinfo.c
00001 /*
00002     +-----------------------------------------------------------------------------------------+
00003     |                                                                                         |
00004     |                               OCILIB - C Driver for Oracle                              |
00005     |                                                                                         |
00006     |                                (C Wrapper for Oracle OCI)                               |
00007     |                                                                                         |
00008     |                              Website : http://www.ocilib.net                            |
00009     |                                                                                         |
00010     |             Copyright (c) 2007-2013 Vincent ROGIER <vince.rogier@ocilib.net>            |
00011     |                                                                                         |
00012     +-----------------------------------------------------------------------------------------+
00013     |                                                                                         |
00014     |             This library is free software; you can redistribute it and/or               |
00015     |             modify it under the terms of the GNU Lesser General Public                  |
00016     |             License as published by the Free Software Foundation; either                |
00017     |             version 2 of the License, or (at your option) any later version.            |
00018     |                                                                                         |
00019     |             This library is distributed in the hope that it will be useful,             |
00020     |             but WITHOUT ANY WARRANTY; without even the implied warranty of              |
00021     |             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU           |
00022     |             Lesser General Public License for more details.                             |
00023     |                                                                                         |
00024     |             You should have received a copy of the GNU Lesser General Public            |
00025     |             License along with this library; if not, write to the Free                  |
00026     |             Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.          |
00027     |                                                                                         |
00028     +-----------------------------------------------------------------------------------------+
00029 */
00030 
00031 /* --------------------------------------------------------------------------------------------- *
00032  * $Id: typeinfo.c, Vincent Rogier $
00033  * --------------------------------------------------------------------------------------------- */
00034 
00035 #include "ocilib_internal.h"
00036 
00037 /* ********************************************************************************************* *
00038  *                             PRIVATE FUNCTIONS
00039  * ********************************************************************************************* */
00040 
00041 /* --------------------------------------------------------------------------------------------- *
00042  * OCI_TypeInfoClose
00043  * --------------------------------------------------------------------------------------------- */
00044 
00045 boolean OCI_TypeInfoClose
00046 (
00047     OCI_TypeInfo *typinf
00048 )
00049 {
00050     ub2 i;
00051 
00052     OCI_CHECK(typinf == NULL, FALSE);
00053 
00054     for (i=0; i < typinf->nb_cols; i++)
00055     {
00056         OCI_FREE(typinf->cols[i].name);
00057     }
00058 
00059     OCI_FREE(typinf->cols);
00060     OCI_FREE(typinf->name);
00061     OCI_FREE(typinf->schema);
00062     OCI_FREE(typinf->offsets);
00063 
00064     return TRUE;
00065 }
00066 
00067 /* ********************************************************************************************* *
00068  *                            PUBLIC FUNCTIONS
00069  * ********************************************************************************************* */
00070 
00071 /* --------------------------------------------------------------------------------------------- *
00072  * OCI_TypeInfoGet
00073  * --------------------------------------------------------------------------------------------- */
00074 
00075 OCI_TypeInfo * OCI_API OCI_TypeInfoGet
00076 (
00077     OCI_Connection *con,
00078     const mtext    *name,
00079     unsigned int    type
00080 )
00081 {
00082     OCI_TypeInfo *typinf        = NULL;
00083     OCI_TypeInfo *syn_typinf    = NULL;
00084     OCI_Item *item              = NULL;
00085     OCIDescribe *dschp          = NULL;
00086     OCIParam *parmh1            = NULL;
00087     OCIParam *parmh2            = NULL;
00088     mtext *str                  = NULL;
00089     int ptype                   = 0;
00090     ub1 desc_type               = 0;
00091     ub4 attr_type               = 0;
00092     ub4 num_type                = 0;
00093     boolean res                 = TRUE;
00094     boolean found               = FALSE;
00095     ub2 i;
00096 
00097     mtext obj_schema[OCI_SIZE_OBJ_NAME+1];
00098     mtext obj_name[OCI_SIZE_OBJ_NAME+1];
00099 
00100     OCI_CHECK_INITIALIZED(NULL);
00101 
00102     OCI_CHECK_PTR(OCI_IPC_CONNECTION, con, NULL);
00103     OCI_CHECK_PTR(OCI_IPC_STRING, name, NULL);
00104 
00105     obj_schema[0] = 0;
00106     obj_name[0]   = 0;
00107 
00108     /* is the schema provided in the object name ? */
00109 
00110     for (str = (mtext *) name; *str != 0; str++)
00111     {
00112         if (*str == MT('.'))
00113         {
00114             mtsncat(obj_schema, name, str-name);
00115             mtsncat(obj_name, ++str, (size_t) OCI_SIZE_OBJ_NAME);
00116             break;
00117         }
00118     }
00119 
00120     /* if the schema is not provided, we just copy the object name */
00121 
00122     if (obj_name[0] == 0)
00123     {
00124         mtsncat(obj_name, name, (size_t) OCI_SIZE_OBJ_NAME);
00125     }
00126 
00127     /* type name must be uppercase */
00128 
00129     for (str = obj_name; *str != 0; str++)
00130     {
00131         *str = (mtext) mttoupper(*str);
00132     }
00133 
00134     /* schema name must be uppercase */
00135 
00136     for (str = obj_schema; *str != 0; str++)
00137     {
00138         *str = (mtext) mttoupper(*str);
00139     }
00140 
00141     /* first try to find it in list */
00142 
00143     item = con->tinfs->head;
00144 
00145     /* walk along the list to find the type */
00146 
00147     while (item != NULL)
00148     {
00149         typinf = (OCI_TypeInfo *) item->data;
00150 
00151         if ((typinf != NULL) && (typinf->type == type))
00152         {
00153             if ((mtscasecmp(typinf->name,   obj_name  ) == 0) &&
00154                 (mtscasecmp(typinf->schema, obj_schema) == 0))
00155             {
00156                 found = TRUE;
00157                 break;
00158             }
00159         }
00160 
00161         item = item->next;
00162     }
00163 
00164     /* Not found, so create type object */
00165 
00166     if (found == FALSE)
00167     {
00168         item = OCI_ListAppend(con->tinfs, sizeof(OCI_TypeInfo));
00169 
00170         res = (item != NULL);
00171 
00172         /* allocate describe handle */
00173 
00174         if (res == TRUE)
00175         {
00176             typinf = (OCI_TypeInfo *) item->data;
00177 
00178             typinf->type        = type;
00179             typinf->con         = con;
00180             typinf->name        = mtsdup(obj_name);
00181             typinf->schema      = mtsdup(obj_schema);
00182             typinf->struct_size = 0;
00183 
00184             res = (OCI_SUCCESS == OCI_HandleAlloc(typinf->con->env,
00185                                                   (dvoid **) (void *) &dschp,
00186                                                   OCI_HTYPE_DESCRIBE, (size_t) 0,
00187                                                   (dvoid **) NULL));
00188         }
00189 
00190         /* perfom describe */
00191 
00192         if (res == TRUE)
00193         {
00194             mtext buffer[(OCI_SIZE_OBJ_NAME*2) + 2] = MT("");
00195 
00196             size_t size = sizeof(buffer)/sizeof(mtext);
00197             void *ostr1 = NULL;
00198             int osize1  = -1;
00199             sb4 pbsp    = 1;
00200 
00201             str = buffer;
00202 
00203             /* compute full object name */
00204 
00205             if ((typinf->schema != NULL) && (typinf->schema[0] != 0))
00206             {
00207                 str   = mtsncat(buffer, typinf->schema, size);
00208                 size -= mtslen(typinf->schema);
00209                 str   = mtsncat(str, MT("."), size);
00210                 size -= (size_t) 1;
00211             }
00212 
00213             mtsncat(str, typinf->name, size);
00214 
00215             ostr1 = OCI_GetInputMetaString(str, &osize1);
00216 
00217             /* set public scope to include synonyms */
00218                 
00219             OCI_CALL2
00220             (
00221                 res, con,
00222 
00223                 OCIAttrSet(dschp, OCI_HTYPE_DESCRIBE, &pbsp, (ub4) sizeof(pbsp), 
00224                             OCI_ATTR_DESC_PUBLIC, con->err)
00225             )
00226 
00227             /* describe call */
00228 
00229             OCI_CALL2
00230             (
00231                 res, con,
00232 
00233                 OCIDescribeAny(con->cxt, con->err, (dvoid *) ostr1,
00234                                 (ub4) osize1, OCI_OTYPE_NAME,
00235                                 OCI_DEFAULT, OCI_PTYPE_UNK, dschp)
00236             )
00237 
00238             OCI_ReleaseMetaString(ostr1);
00239 
00240             /* get parameter handle */
00241                 
00242             OCI_CALL2
00243             (
00244                 res, con,
00245 
00246                 OCIAttrGet(dschp, OCI_HTYPE_DESCRIBE, &parmh1,
00247                             NULL, OCI_ATTR_PARAM, con->err)
00248             )
00249             
00250             /* get object type */
00251                 
00252             OCI_CALL2
00253             (
00254                 res, con,
00255 
00256                 OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &desc_type,
00257                            NULL, OCI_ATTR_PTYPE, con->err)
00258             )
00259         }
00260 
00261         /* on sucessfull describe call, retrieve all information about the object 
00262            if it is not a synonym */
00263 
00264         if (res == TRUE)
00265         {
00266             switch (desc_type)
00267             {
00268                 case OCI_PTYPE_TYPE:
00269                 {
00270                     if (typinf->type != OCI_UNKNOWN)
00271                     {
00272                         res = (typinf->type == OCI_TIF_TYPE);
00273 
00274                     }
00275 
00276                     typinf->type = OCI_TIF_TYPE;
00277                     
00278                     if (res == TRUE)
00279                     {
00280                         boolean pdt = FALSE;
00281                         void *ostr1 = NULL;
00282                         void *ostr2 = NULL;
00283                         int osize1  = -1;
00284                         int osize2  = -1;
00285 
00286                         attr_type = OCI_ATTR_LIST_TYPE_ATTRS;
00287                         num_type  = OCI_ATTR_NUM_TYPE_ATTRS;
00288                         ptype     = OCI_DESC_TYPE;
00289 
00290                         /* get the object  tdo */
00291 
00292                         ostr1 = OCI_GetInputMetaString(typinf->schema, &osize1);
00293                         ostr2 = OCI_GetInputMetaString(typinf->name,   &osize2);
00294 
00295                         OCI_CALL2
00296                         (
00297                             res, con,
00298 
00299                             OCITypeByName(typinf->con->env, con->err, con->cxt,
00300                                           (text *) ostr1, (ub4) osize1,
00301                                           (text *) ostr2, (ub4) osize2,
00302                                           (text *) NULL, (ub4) 0,
00303                                           OCI_DURATION_SESSION, OCI_TYPEGET_ALL,
00304                                           &typinf->tdo)
00305                         )
00306 
00307                         OCI_ReleaseMetaString(ostr1);
00308                         OCI_ReleaseMetaString(ostr2);
00309 
00310                         /* check if it's system predefined type if order to avoid the next call
00311                            that is not allowed on system types */
00312 
00313                         OCI_CALL2
00314                         (
00315                             res, con,
00316 
00317                             OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &pdt,
00318                                        NULL, OCI_ATTR_IS_PREDEFINED_TYPE, con->err)
00319                         )
00320 
00321                         if (pdt == FALSE)
00322                         {
00323                             OCI_CALL2
00324                             (
00325                                 res, con,
00326 
00327                                 OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &typinf->tcode,
00328                                            NULL, OCI_ATTR_TYPECODE, con->err)
00329                             )
00330                         }
00331                     
00332                     }
00333 
00334                     break;
00335                 }
00336                 case OCI_PTYPE_TABLE:
00337                 case OCI_PTYPE_VIEW:
00338             #if OCI_VERSION_COMPILE >= OCI_10_1
00339                 case OCI_PTYPE_TABLE_ALIAS:
00340             #endif
00341                 {
00342                     if (typinf->type != OCI_UNKNOWN)
00343                     {
00344                         res = (((typinf->type == OCI_TIF_TABLE) && (desc_type != OCI_PTYPE_VIEW)) ||
00345                                ((typinf->type == OCI_TIF_VIEW ) && (desc_type == OCI_PTYPE_VIEW)));
00346                     }
00347 
00348                     typinf->type = (desc_type == OCI_PTYPE_VIEW ? OCI_TIF_VIEW : OCI_TIF_TABLE);
00349  
00350                     if (res == TRUE)
00351                     {
00352                         attr_type = OCI_ATTR_LIST_COLUMNS;
00353                         num_type  = OCI_ATTR_NUM_COLS;
00354                         ptype     = OCI_DESC_TABLE;             
00355                     }
00356                     
00357                     break;
00358                 }
00359                 case OCI_PTYPE_SYN:
00360                 {
00361                     mtext *syn_schema_name   = NULL;
00362                     mtext *syn_object_name   = NULL;
00363                     mtext *syn_link_name     = NULL;
00364 
00365                     mtext syn_fullname[(OCI_SIZE_OBJ_NAME*3) + 3] = MT("");
00366 
00367                     /* get link schema, object and databaselink names */
00368 
00369                     res = res && OCI_StringGetFromAttrHandle (con, parmh1, OCI_DTYPE_PARAM,
00370                                                               OCI_ATTR_SCHEMA_NAME, 
00371                                                               &syn_schema_name);
00372                     
00373                     res = res && OCI_StringGetFromAttrHandle (con, parmh1, OCI_DTYPE_PARAM,
00374                                                               OCI_ATTR_NAME, 
00375                                                               &syn_object_name);
00376  
00377                     res = res && OCI_StringGetFromAttrHandle (con, parmh1, OCI_DTYPE_PARAM,
00378                                                               OCI_ATTR_LINK, &syn_link_name);
00379 
00380                     /* compute link full name */
00381                     
00382                     if ((syn_schema_name != NULL) && (syn_schema_name[0] != 0))
00383                     {
00384                         mtsncat(syn_fullname, syn_schema_name, (size_t) OCI_SIZE_OBJ_NAME);
00385                         mtsncat(syn_fullname, MT("."), 1);
00386                     }
00387 
00388                     if ((syn_object_name != NULL) && (syn_object_name[0] != 0))
00389                     {
00390                         mtsncat(syn_fullname, syn_object_name, (size_t) OCI_SIZE_OBJ_NAME);
00391                     }
00392                 
00393                     if ((syn_link_name != NULL) && (syn_link_name[0] != 0))
00394                     {
00395                         mtsncat(syn_fullname, MT("@"), 1);
00396                         mtsncat(syn_fullname, syn_link_name, (size_t) OCI_SIZE_OBJ_NAME);
00397                     }
00398 
00399                     /* retrieve the type info of the real object */
00400 
00401                     syn_typinf = OCI_TypeInfoGet (con, syn_fullname, typinf->type);
00402                          
00403                     /* free temporay strings */
00404 
00405                     OCI_MemFree (syn_link_name);
00406                     OCI_MemFree (syn_object_name);
00407                     OCI_MemFree (syn_schema_name);
00408                     
00409                     /* do we have a valid object ? */
00410 
00411                     res = (syn_typinf != NULL);
00412 
00413                     break;
00414                 }
00415             }
00416 
00417             /*  did we handle a supported object other than a synonym */
00418 
00419             if ((res == TRUE) && (ptype != 0)) 
00420             {
00421                 /* do we need get more attributes for collections ? */
00422 
00423                 if (typinf->tcode == SQLT_NCO)
00424                 {
00425                     typinf->nb_cols = 1;
00426 
00427                     ptype  = OCI_DESC_COLLECTION;
00428                     parmh2 = parmh1;
00429 
00430                     OCI_CALL2
00431                     (
00432                         res, con,
00433 
00434                         OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &typinf->ccode,
00435                                    NULL, OCI_ATTR_COLLECTION_TYPECODE, con->err)
00436                     )
00437                 }
00438                 else
00439                 {
00440                     OCI_CALL2
00441                     (
00442                         res, con,
00443 
00444                         OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &parmh2,
00445                                    NULL, attr_type, con->err)
00446                     )
00447 
00448                     OCI_CALL2
00449                     (
00450                         res, con,
00451 
00452                         OCIAttrGet(parmh1, OCI_DTYPE_PARAM, &typinf->nb_cols,
00453                                    NULL, num_type, con->err)
00454                     )
00455                 }
00456 
00457                 /* allocates memory for cached offsets */
00458 
00459                 if (typinf->nb_cols > 0)
00460                 {
00461                     typinf->offsets = (int *) OCI_MemAlloc(OCI_IPC_ARRAY,
00462                                                            sizeof(*typinf->offsets),
00463                                                            (size_t) typinf->nb_cols,
00464                                                            FALSE);
00465 
00466                     res = (typinf->offsets != NULL);
00467 
00468                     if (res == TRUE)
00469                     {
00470                         memset(typinf->offsets, -1, sizeof(*typinf->offsets) * typinf->nb_cols);
00471                     }
00472                 }
00473 
00474                 /* allocates memory for children */
00475 
00476                 if (typinf->nb_cols > 0)
00477                 {
00478                     typinf->cols = (OCI_Column *) OCI_MemAlloc(OCI_IPC_COLUMN,  sizeof(*typinf->cols),
00479                                                                (size_t) typinf->nb_cols, TRUE);
00480 
00481                     /* describe children */
00482 
00483                     if (typinf->cols != NULL)
00484                     {
00485                         for (i = 0; i < typinf->nb_cols; i++)
00486                         {
00487                             res = res && OCI_ColumnDescribe(&typinf->cols[i], con,
00488                                                             NULL, parmh2, i + 1, ptype);
00489 
00490                             res = res && OCI_ColumnMap(&typinf->cols[i], NULL);
00491 
00492                             if (res == FALSE)
00493                             {
00494                                 break;
00495                             }
00496                         }
00497                     }
00498                     else
00499                     {
00500                         res = FALSE;
00501                     }
00502                 }
00503             }
00504         }
00505     }
00506 
00507     /* free describe handle */
00508 
00509     if (dschp != NULL)
00510     {
00511         OCI_HandleFree(dschp, OCI_HTYPE_DESCRIBE);
00512     }
00513 
00514     /* increment type info reference counter on success */
00515 
00516     if (typinf != NULL)
00517     {
00518         typinf->refcount++;
00519 
00520         /* type checking sanity checks */
00521 
00522         if ((type != OCI_UNKNOWN) && (typinf->type != type))
00523         {
00524             OCI_ExceptionTypeInfoWrongType(con, name);
00525 
00526             res = FALSE;
00527         }
00528     }
00529 
00530     /* handle errors */
00531 
00532     if ((res == FALSE) || (syn_typinf != NULL))
00533     {
00534         OCI_TypeInfoFree(typinf);
00535         typinf = NULL;
00536     }
00537 
00538     OCI_RESULT(res);
00539 
00540     return syn_typinf ? syn_typinf : typinf;
00541 }
00542 
00543 /* --------------------------------------------------------------------------------------------- *
00544  * OCI_TypeInfoFree
00545  * --------------------------------------------------------------------------------------------- */
00546 
00547 boolean OCI_API OCI_TypeInfoFree
00548 (
00549     OCI_TypeInfo *typinf
00550 )
00551 {
00552     boolean res = TRUE;
00553 
00554     OCI_CHECK_PTR(OCI_IPC_TYPE_INFO, typinf, FALSE);
00555 
00556     typinf->refcount--;
00557 
00558     if (typinf->refcount == 0)
00559     {
00560         OCI_ListRemove(typinf->con->tinfs, typinf);
00561 
00562         res = OCI_TypeInfoClose(typinf);
00563 
00564         OCI_FREE(typinf);
00565     }
00566 
00567     OCI_RESULT(res);
00568 
00569     return res;
00570 }
00571 
00572 /* --------------------------------------------------------------------------------------------- *
00573  * OCI_TypeInfoGetType
00574  * --------------------------------------------------------------------------------------------- */
00575 
00576 unsigned int OCI_API OCI_TypeInfoGetType
00577 (
00578     OCI_TypeInfo *typinf
00579 )
00580 {
00581     OCI_CHECK_PTR(OCI_IPC_TYPE_INFO, typinf, OCI_UNKNOWN);
00582 
00583     OCI_RESULT(TRUE);
00584 
00585     return typinf->type;
00586 }
00587 
00588 /* --------------------------------------------------------------------------------------------- *
00589  * OCI_TypeInfoGetColumnCount
00590  * --------------------------------------------------------------------------------------------- */
00591 
00592 unsigned int OCI_API OCI_TypeInfoGetColumnCount
00593 (
00594     OCI_TypeInfo *typinf
00595 )
00596 {
00597     OCI_CHECK_PTR(OCI_IPC_TYPE_INFO, typinf, 0);
00598 
00599     OCI_RESULT(TRUE);
00600 
00601     return typinf->nb_cols;
00602 }
00603 
00604 /* --------------------------------------------------------------------------------------------- *
00605  * OCI_TypeInfoGetColumn
00606  * --------------------------------------------------------------------------------------------- */
00607 
00608 OCI_Column * OCI_API OCI_TypeInfoGetColumn
00609 (
00610     OCI_TypeInfo *typinf,
00611     unsigned int  index
00612 )
00613 {
00614     OCI_CHECK_PTR(OCI_IPC_TYPE_INFO, typinf, NULL);
00615     OCI_CHECK_BOUND(typinf->con, index, 1,  typinf->nb_cols, NULL);
00616 
00617     OCI_RESULT(TRUE);
00618 
00619     return &(typinf->cols[index-1]);
00620 }
00621 
00622 /* --------------------------------------------------------------------------------------------- *
00623  * OCI_TypeInfoGetName
00624  * --------------------------------------------------------------------------------------------- */
00625 
00626 const mtext * OCI_API OCI_TypeInfoGetName
00627 (
00628     OCI_TypeInfo *typinf
00629 )
00630 {
00631     OCI_CHECK_PTR(OCI_IPC_TYPE_INFO, typinf, NULL);
00632 
00633     OCI_RESULT(TRUE);
00634 
00635     return typinf->name;
00636 }