martedì 7 febbraio 2017

OWM - Set oracle workspace from java application

For the connect to an Oracle database 12c which uses Oracle Workspace Manager from a java application.
It is  possible trying to execute the following command from my java application.

From pl-sql

EXECUTE DBMS_WM.GotoWorkspace('WORKSPACE_NAME');

in the java code

String setWorkspace = "CALL DBMS_WM.GotoWorkspace('WORKSPACE_NAME')";
CallableStatement cs = conn.prepareCall(setWorkspace);
cs.execute();




giovedì 22 dicembre 2016

JAVA - Portable Java 8 JDK on Windows

Spesso se si è in ambienti protetti, e quando dico protetti significa che non puoi installare nulla sulla macchina che ti hanno messo a disposizione, se devi installare una JDK per far funzionare SQLDeveloper possono sorgere dei problemi.
Per questo oggi vediamo come installare una JDK 8 su Windows partendo dal file di installazione exe.

Ecco di seguito i vari passi:

  1. Download  Java 8 SDK for Windows from Oracle.  Io ho fatto il download di jdk-8u111-windows-x64.exe.
  2. Aprire il .exe con un tool che effettui gli unzip, esempio 7-Zip o altri 
  3. Navigare sotto la directory .rsrc fino a 
      1. ..\Downloads\jdk-8u111-windows-x64.exe\.rsrc\1033\JAVA_CAB10\111\ 
  4. Qui si trova un denominato tools.zip.
  5. Aprirlo e scompattarlo in una directory     ..\Java\jdk1.8.0_111\ estraendone il contenuto
  6. A questo punto una volta estratti tutti i record, poizionarsi nella home della directoy java ed eseguire da una finestra dos il seguente comando:
    • for /R %f in (.\*.pack) do @"%cd%\bin\unpack200" -r -v -l "" "%f" "%~pf%~nf.jar"
  7. Se tutto termina correttamente effettuare per sicurezza un reboot della macchina Windows ed aprire poi SQLDeveloper fornendo il path della directory java.
  8. Fare una prova effettuando un javac -version


 A questo punto avete installato una JDK 8 Portable e funzionante.

lunedì 5 dicembre 2016

ODI 11g-12c - Groovy Come creare un utente ODI ed assegnazione profili

Di seguito due script per la creazione di un utente ODI con relativa assegnazione di profili. Di seguito due versioni una per ODI 11g e una per ODI 12c, la seconda utilizza delle funzioni che possono essere richiamata all'interno di un main.
  • ODI 11g
// Transaction operators:
import oracle.odi.core.persistence.transaction.support.DefaultTransactionDefinition;
import oracle.odi.core.persistence.transaction.ITransactionDefinition;
import oracle.odi.core.persistence.transaction.ITransactionManager;
import oracle.odi.core.persistence.transaction.ITransactionStatus;
// Secutity class:
import oracle.odi.domain.security.finder.IOdiUserFinder
import oracle.odi.domain.security.OdiUserCreationServiceImpl
import oracle.odi.domain.security.OdiUser
import oracle.odi.domain.security.OdiProfile;
import oracle.odi.domain.security.finder.IOdiProfileFinder
// Variabili
def txnDef = new DefaultTransactionDefinition()
def tm = odiInstance.getTransactionManager()
def txnStatus = tm.getTransaction(txnDef)
String  username="PIPPO";
String  pwd="PIPPO1";
String  supervisor="false";
        expirationDate=null;

try {
         odiUser = ((IOdiUserFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiUser.class)).findByName(username);
     
           println("  User              :-->"+odiUser.getName());
           println("  User Note         :-->"+odiUser.getNotes());
           println("  Pwd Date Expire   :-->"+odiUser.getPasswordExpiracyDate());
           println("  Expiracy Date     :-->"+odiUser.getAccountExpiracyDate());
          
           Collection odiUserPro =(odiUser.getOdiProfileList())
            for (Object kk : odiUserPro) {
              OdiProfile odiPro =(OdiProfile)kk ;
              println("  Profile           :-->"+odiPro.getOdiProfileList().getProfileName());
              println("  Profile           :-->"+odiPro.getOdiProfileList().getInternalId());
            }
           
}catch(NullPointerException e_101){

        // obtaining the generic profiles
        genericprofile_connect = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("CONNECT") ;
        genericprofile_designer = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("DESIGNER") ;
        genericprofile_topology_admin = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("TOPOLOGY ADMIN") ;    

        // creating user
    OdiUserCreationServiceImpl service = new OdiUserCreationServiceImpl(odiInstance)
    OdiUser newUser = service.createOdiUser(username, pwd.toCharArray(), supervisor.toBoolean(), expirationDate );

        // adding profiles to the user
        newUser.addOdiProfile(genericprofile_connect);
        newUser.addOdiProfile(genericprofile_designer);
        newUser.addOdiProfile(genericprofile_topology_admin);

        NewodiUser = ((IOdiUserFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiUser.class)).findByName(username);
           println("  User              :-->"+NewodiUser.getName());
           println("  User Note         :-->"+NewodiUser.getNotes());
           println("  Pwd Date Expire   :-->"+NewodiUser.getPasswordExpiracyDate());
           println("  Expiracy Date     :-->"+NewodiUser.getAccountExpiracyDate());
          
 }

tm.commit(txnStatus) 



  • ODI 12c
import oracle.odi.domain.project.finder.IOdiProjectFinder
import oracle.odi.domain.model.finder.IOdiDataStoreFinder
import oracle.odi.domain.project.finder.IOdiFolderFinder
import oracle.odi.domain.project.finder.IOdiKMFinder
import oracle.odi.domain.mapping.finder.IMappingFinder
import oracle.odi.domain.adapter.project.IKnowledgeModule.ProcessingType
import oracle.odi.domain.model.OdiDataStore
import oracle.odi.core.persistence.transaction.support.DefaultTransactionDefinition
import oracle.odi.domain.security.finder.IOdiUserFinder
import oracle.odi.domain.security.OdiUserCreationServiceImpl
import oracle.odi.domain.security.OdiUser
import oracle.odi.core.OdiInstance
import oracle.odi.domain.security.OdiProfile;


// creating  user (Pippo)

def new_user(user, pwd, supervisor ) {
     expirationDate = null

    txnDef    = new DefaultTransactionDefinition()
    tm        = odiInstance.getTransactionManager()
    tme       = odiInstance.getTransactionalEntityManager()
    txnStatus = tm.getTransaction(txnDef)

    // checking if whether user exists
    userf = (IOdiUserFinder) tme.getFinder(OdiUser.class)

    // creating user
    OdiUserCreationServiceImpl service = new OdiUserCreationServiceImpl(odiInstance)
    OdiUser newUser = service.createOdiUser(user, pwd.toCharArray(), supervisor.toBoolean(), expirationDate );
   
    tm.commit(txnStatus)
    return newUser
}

def adding_profiles(username) {

    txnDef    = new DefaultTransactionDefinition()
    tm        = odiInstance.getTransactionManager()
    tme       = odiInstance.getTransactionalEntityManager()
    txnStatus = tm.getTransaction(txnDef)
        
        // finding the user
        user = odiInstance.getTransactionalEntityManager().getFinder(OdiUser.class).findByName(username) ;
        // obtaining the generic profiles
        genericprofile_connect = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("CONNECT") ;
        genericprofile_designer = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("DESIGNER") ;
        genericprofile_topology_admin = odiInstance.getTransactionalEntityManager().getFinder(OdiProfile.class).findByName("TOPOLOGY ADMIN") ;
        // adding profiles to the user
        user.addOdiProfile(genericprofile_connect);
        user.addOdiProfile(genericprofile_designer);
        user.addOdiProfile(genericprofile_topology_admin);
    tm.commit(txnStatus)
    return user;
}

//  add odi user "Pippo " and grant profiles like CONNECT, DESIGNER, TOPOLOGY ADMIN
FirstUser1 = new_user("Pippo", "1234abcd5678","false")
FirstUser1Profiles = adding_profiles("Pippo")


Provate e fatemi sapere

venerdì 1 aprile 2016

RDBMS ORACLE - Partition Range By Interval - parte 2

Continuiamo con un esempio di quanto indicato nella parte 1 e due possibili soluzioni.

CREATE TABLE "ICP_ECONOMICO" 
   (
"PERIOD" NUMBER
   ) 
  PARTITION BY RANGE ("PERIOD") INTERVAL (1) 
 (PARTITION "P_0"  VALUES LESS THAN (196905) ) ;

Creato table "ICP_ECONOMICO".


set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;

TABLE_NAME  PARTITION STATUS   INTERVAL  PARTITION_COUNT REAL_COUNT
----------- --------- -------- --------- --------------- ----------
ICP_ECONOMICO  RANGE     VALID    1          1048575          1

A questo punto inseriamo un record.

insert into ICP_ECONOMICO (period) values(20160101);

Errore con inizio alla riga : 178 nel comando -
insert into ICP_ECONOMICO (period) values(20160101)
Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions.

Come si vede abbiamo l'errore che dicevamo, adesso se portiamo da 1 a 100 il by interval vediamo cosa accade:

ALTER TABLE ICP_ECONOMICO  SET INTERVAL (100);
Table ICP_ECONOMICO modificato.

Inseriamo una riga come prima.

insert into ICP_ECONOMICO (period) values(20160101);
1 riga inserito.

A questo punto se rifacciamo la query di sopra abbiamo:

set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;

TABLE_NAME     PARTITION STATUS   INTERVAL  PARTITION_COUNT REAL_COUNT
-------------- --------- -------- --------- --------------- -----------------------------
ICP_ECONOMICO     RANGE     VALID    100           1048575          2


Se proviamo ad inserire altri record il problema non sembra più presentarsi a meno che non inserisce un valore che abbia un numero di cifre maggiore ad 8.

insert into ICP_ECONOMICO (period) values(99991201);
1 riga inserito.

insert into ICP_ECONOMICO (period) values(999912010);

Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions.

A questo punto se modifichiamo nuovamente il valore dell'intervallo

ALTER TABLE ICP_ECONOMICO  SET INTERVAL (1000);
Table ICP_ECONOMICO modificato.
           
           
set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;  


TABLE_NAME     PARTITION STATUS   INTERVAL  PARTITION_COUNT   REAL_COUNT
-------------- --------- -------- --------  ----------------- ----------
ICP_ECONOMICO     RANGE     VALID    1000     1048575          3


insert into ICP_ECONOMICO (period) values(999912010);
1 riga inserito.

A questo punto sembra che il  numero di cifre sia legato al valore dell'intervallo di partizionamento e più precisamente:

Intervallo 1        = Numero di cifre 6
Intervallo 100    = Numero di cifre 8
Intervallo 1000  = Numero di cifre 9

se inserisco adesso un numero di cifre pari a 10 avrò nuovemente l'errore.

insert into ICP_ECONOMICO (period) values(9999120101);

Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions

 E qui vi lascio perchè non so dare alcuna spiegazione a questo comportamento.







RDBMS ORACLE - Partition Range By Interval - parte 1


Salve oggi brevemente vi parlo di un paio di bug di oracle, che sono una gran rottura di BIP e sono legati al partizionamento di una tabella by interval su un campo numerico e by interval su campo data.
Inoltre se si aggiunge al primo partizionamento anche un sottopartizionamento by hash che supera le 4 partizioni siamo al top.

Uno si può chiedere perchè utilizzare questo tipo di partizionamento e la risposta come al solito è dentro di voi ed è pure sbagliata. No a parte le cazzate il perchè p molto semplice le partizioni si autocreano e non c'è bisogno di un software che le crei, questo fa si che la gestione viene demandata completamente al database, purtroppo con le conseguenze indicate sotto.
Purtroppo non ho molto tempo per spiegarvi il problema vi rimando alle note che affrontano nel dettaglio i bugs.

  • Document  1507993.1 ORA-1841 on Select from Interval Partitioned Table when Predicate is 31-Dec-9999
  • Document 1479115.1 Interval Partitioning Essentials - Common Questions - Top Issues Document 1447928.1 PARTITION_COUNT Shows Large Value 1048575 With Interval Partitioning
  • Document 754642.1 How the PSTART/PSTOP Numbers are computed when a Interval Partition is used
  • Document 1472941.1 Insert Fails With ORA-14300 On Partition Table  
Per quanto riguarda la prima nota esiste un workaround che è quello di non far partire la data dal 01 del mese ma di farla partire dal 17 del mese. Il bug in questo caso è legato alla trasformazione della data Juliana nel normale formato anno mese e giorno.
Il secondo bug invece è una emerita stronza.. ed è legato ad uno pseudo valore massimo di partizioni in oracle che però non ha alcuna attinenza col valore contenuto nel campo.
Per verificare quante siano le partizioni indicate sul sistema e quante ve ne siano realmente basta eseguire la seguente query:


set lines 300
col interval for a30
col TABLE_NAME for a30
select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='MV_FACT_TDB'
order by table_name;

TABLE_NAME                     PARTITION STATUS   INTERVAL      PARTITION_COUNT        REAL_COUNT
------------------------------ --------- -------- ------------- ---------------------- ----------
MV_FACT_TDB                    RANGE     VALID    100                         1048575          2


Dove la tabella ha in realtà 2 partizioni sottopartizionate by hash 4-




Vi lascio alla lettura delle note e dei relativi workaround, appena ritrovo i test che avevo fatto vi integro questo scarno documento.