<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Agile DBA</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/" />
    <link rel="self" type="application/atom+xml" href="http://www.sadalage.com/atom.xml" />
    <id>tag:www.sadalage.com,2010-04-13://2</id>
    <updated>2010-05-05T14:24:25Z</updated>
    <subtitle>My thoughts on evolutionary design in regards to databases. Database administration. Best Practices, Database utilities and other things</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.3-en</generator>

<entry>
    <title>Schema design in a document database</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2010/04/schema-design-in-a-document-da.html" />
    <id>tag:www.sadalage.com,2010://2.65</id>

    <published>2010-04-28T23:45:03Z</published>
    <updated>2010-05-05T14:24:25Z</updated>

    <summary>We are using MongoDB on our project, since mongo is document store, schema design is somewhat different, when you are using traditional RDBMS data stores, one thinks about tables and rows, while using a document database you have to think...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="MongoDB" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="documentdb" label="documentdb" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mongodb" label="mongodb" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[We are using MongoDB on our project, since mongo is document store, schema
design is somewhat different, when you are using traditional RDBMS data
stores, one thinks about tables and rows, while using a document database you
have to think about the schema in a some what different way. Lets say, we want
to save a customer object, when using a RDBMS we would come up with Customer,
Address, Phone, Email. They are related to each other as shown below.
<img alt="customer.jpg" src="http://www.sadalage.com/images/customer.jpg" width="448" height="367" class="mt-image-none" style="" />
When doing a document database, the schema design actually does not change
much, the Customer document contains an array of Addresses, a one
to many relationship. You will not need the FK columns or the Primary Key
columns on the child tables, since the child rows are embedded in the parent
object. The JSON object below shows how the data would look.

<pre class="codeexample">
{
"_id" : ObjectId("4bd8ae97c47016442af4a580"),
"customerid" : 99999,
"name" : "Foo Sushi Inc",
"type" : "Good",
"since" : "12/12/2001",
"addresses" : [{
		"address" : "4821 Big Street",
		"city" : "Stone",			
		"state" : "IL",
		"country" : "USA"
	},
	{	"address" : "1248 Barlow Ln",
		"city" : "Hedgestone",			
		"country" : "UK"
	}		
],
"emails" : [ 
	{"email" : "foousa@sushi.com"},
	{"email" : "foouk@sushi.com"}
],
"phones" : [ 
	{"phone" : "773-7777-7777"},
	{"phone" : "020-6666-6666"}
]
}
</pre>

So Instead of 1 Row for customer, 2 rows for address, phone and email each, you get one Customer document. If you want to query for customers in USA. Using RDBMS you would do
<pre class="codeexample">
SELECT customer.name FROM customer, address 
WHERE customer.customerid = address.customerid 
AND address.country="USA"
</pre>
The same query in mongo would look like
<pre class="codeexample">
db.customers.find({"addresses.country":"USA"},{"name":true})
</pre>
where customers is the collection in which we store our customers.]]>
        
    </content>
</entry>

<entry>
    <title>My experience with MongoDB</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2010/04/my-experience-with-mongodb.html" />
    <id>tag:www.sadalage.com,2010://2.64</id>

    <published>2010-04-18T17:27:28Z</published>
    <updated>2010-04-19T03:32:15Z</updated>

    <summary>The current project I&apos;m on is using MongoDB. MongoDB is a document based database, it stores JSON objects as BSON (Binary JSON objects). MongoDB provides a middle ground between the traditional RDBMS and the NOSql databases out there, it provides...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="MongoDB" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="java" label="java" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mongodb" label="mongodb" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="nosql" label="nosql" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[The current project I'm on is using MongoDB. MongoDB is a document based database, it stores JSON objects as BSON (Binary JSON objects). MongoDB provides a middle ground between the traditional RDBMS and the NOSql databases out there, it provides for indexes, dynamic queries, replication, map reduce and auto sharding, its open source and can be downloaded <a href="www.mongodb.org">here</a>, starting up mongodb is pretty easy.

<pre class="codeexample">
./mongod --dbpath=/user/data/db
</pre>
is all you need, where /user/data/db is the path where you want mongo to create its data files. There are many other options that you can use to customize the mongo instance.

Each mongo instance has databases and each database has many collections, mapping back to oracle, mongo database is a oracle schema and mongo collection is a oracle table,
The difference is, each collection can hold any type of object, basically every row can be different. 

An example connection to the database using java looks like this

<pre class="codeexample">
   Mongo mongo = new Mongo("localhost");
   db = mongo.getDB("mydatabase");
</pre>
If the "mydatabase" does not exist, it will be created. When you want to put objects in the database, you need to have a collection which holds the objects.

<pre class="codeexample">
   users = db.getCollection("applicationusers");
</pre>
if the "applicationusers" collection does not exist, it will be created, at this point you are ready to put objects into the collection.

<pre class="codeexample">
    BasicDBObject userDocument = new BasicDBObject();
    userDocument.put("name", "jack");
    userDocument.put("type", "super");
    users.insert(userDocument);
</pre>

You create a document by using the BasicDBObject and put attribute names and their values, in the above example "name" is the attribute and "jack" is the value, the <strong>users.insert</strong> takes the document and inserts it into the collection "users". At this point you have a JSON object put into the database.

You can query for the object using the mongo query tool or the rest full api mongo provides using the flag --rest, when you start mongodb, visiting <em>http://127.0.0.1:28017/mydatabase/users/</em> should give you

<pre class="codeexample">
{
  "offset" : 0,
  "rows": [
    { "_id" : { "$oid" : "4bc9157e201f254d204226bf" }, "name" : "jack", "type" : "super" }
  ],
  "total_rows" : 1 ,
  "query" : {} ,
  "millis" : 0
}
</pre>

Every object you insert, gets a auto generated id, more about update, delete and complex objects in next blog post.]]>
        
    </content>
</entry>

<entry>
    <title>Workshop at Enterprise Data World 2010</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2010/01/workshop-at-enterprise-data-wo.html" />
    <id>tag:www.sadalage.com,2010://2.62</id>

    <published>2010-01-29T20:47:25Z</published>
    <updated>2010-04-20T03:52:49Z</updated>

    <summary>Doing a workshop on Agile Database Development at Enterprise Data World 2010 at SF. See you there....</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Broadcast" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="agiledata" label="Agile Data" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="edw" label="EDW" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Doing a workshop on <a href="http://edw2010.wilshireconferences.com/sessionPop.cfm?confid=38&proposalid=2204">Agile Database Development</a> at <a href="http://edw2010.wilshireconferences.com/">Enterprise Data World 2010</a> at SF. See you there.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Testing in conversion projects</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/11/automated-data-compare-in-conv.html" />
    <id>tag:www.sadalage.com,2009://2.61</id>

    <published>2009-11-18T22:06:33Z</published>
    <updated>2010-04-20T03:53:49Z</updated>

    <summary>When working on projects involving Conversion of data or Migration/Moving of data from a legacy database. The testing effort is enormous and testing takes a lot of time, some test automation can help this effort. Since data is moved/changed from...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Best Practices" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="agiledba" label="agile dba" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="automation" label="automation" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dataconversion" label="data conversion" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>When working on projects involving Conversion of data or Migration/Moving of data from a legacy database. The testing effort is enormous and testing takes a lot of time, some test automation can help this effort.</p>

<p>Since data is moved/changed from a source database to destination database, we can write sql which should provide results for the types of tests you want to perform, for example: write a sql to give us number of customers, write a sql to give us account balance for a specific account.</p>

<p>These sqls can be run on your source database as well as your destination database and the results can be compared programmatically, providing us an easy way to compare the state of the database before and after conversion/migration. This testing can be run through a <a href="http://martinfowler.com/articles/continuousIntegration.html">CI</a> engine to make it a regression test suite. </p>

<p>Here is an example implementation using ruby,</p>

<p>We have two databases SOURCE and DESTINATION and two sql files names source.sql and destination.sql. The ruby program picks up sql from these two files and runs them against their database i.e. sql from source.sql is run against the SOURCE database and sql from destination.sql is run against DESTINATION database. The results of both of those sqls is compared and an failure is raised when the results do not match.</p>

<pre class="codeexample">
 results
  statement = get_sql_statement_to_execute
    begin
      source_statement = statement[0]
      destination_statement = statement[1]
      source_rows = exec_sql_in_source_return_rows(source_statement)
      destination_rows = exec_sql_in_destination_return_rows(destination_statement)
      result = compare_rows(source_rows, destination_rows, destination_statement, source_statement)
      results << result
    rescue
      Log.log("Could not process: "+statement)
    end
    if (results.size > 0)
      Log.log("Results do not match in source and destination")
    end
</pre>

<p>The sample ruby code above shows how the solution can be implemented, thus enabling automation of database conversion/migration testing</p>]]>
        
    </content>
</entry>

<entry>
    <title>Ruby OCI 2.0 Array binding</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/10/ruby-oci-20-array-binding.html" />
    <id>tag:www.sadalage.com,2009://2.60</id>

    <published>2009-10-09T01:16:11Z</published>
    <updated>2010-04-18T17:52:08Z</updated>

    <summary>We have been doing some data moving lately using Ruby and Ruby-OCI. We started with Ruby OCI 1.0 and did use prepared statements with bind variables (since we are using oracle database and pulling data from an oracle database and...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="oci" label="oci" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="performance" label="performance" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>We have been doing some data moving lately using Ruby and <a href="http://ruby-oci8.rubyforge.org">Ruby-OCI</a>. We started with Ruby OCI 1.0 and did use prepared statements with bind variables (since we are using oracle database and pulling data from an oracle database and pushing data to an oracle database). Later we found this really cool feature in Ruby-OCI8 2.0 where you can bind a whole array and just make one database trip for many database operations.</p>

<p>Lets say you want to insert 10 rows, using the insert one row at a time would be 10 trips to the database.</p>

<pre class="codeexample">
def save_accounts(accounts)
    stmt = $connection.parse "INSERT INTO account (accountid,name) values (:account_id,:name)"
      accounts.each do |account|
        stmt.bind_param(:account_id, account[0], Float)
        stmt.bind_param(:name, account[1], String)
        stmt.exec
      end
      $connection.commit
    end
</pre>

<p>Using the array bind feature, its actually just one trip to the database (off course depends on the array size you are going to bind, but you get the picture, it reduces database trips)</p>

<pre class="codeexample">
def save_accounts(account_ids, account_names)
      stmt = $connection.parse "INSERT INTO account (accountid,name) values (:account_id,:name)"
      stmt.max_array_size= account_ids.size
      stmt.bind_param_array(:account_id, account_ids)
      stmt.bind_param_array(:name, account_names)
      stmt.exec_array
      $connection.commit
    end
</pre>
We saw a 100% improvement in performance by changing the way we bind the variables in just one place. Looks like a feature to look out for.]]>
        
    </content>
</entry>

<entry>
    <title>Create an Index for all FK Columns in the database</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/09/create-an-index-for-all-fk-col.html" />
    <id>tag:www.sadalage.com,2009://2.59</id>

    <published>2009-09-04T04:15:58Z</published>
    <updated>2010-04-20T03:55:06Z</updated>

    <summary>Most of the time I have seen database foreign key constraints on tables without indexes on those columns. Lets say the application is trying to delete a row from the CUSTOMER table DELETE FROM CUSTOMER WHERE CUSTOMERID = 1000; When...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Improving Design" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="database" label="database" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="practice" label="practice" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[Most of the time I have seen database foreign key constraints on tables without indexes on those columns. Lets say the application is trying to delete a row from the CUSTOMER table
<pre class="codeexample">
DELETE FROM CUSTOMER WHERE CUSTOMERID = 1000;
</pre>
When the database goes about deleting the customerId of 1000, if there are foreign key constraints defined on customerId, then the database is going to try to find if the customerId of 1000 is used in any of those tables. Lets say ORDER table has the customerId column, the database is going to issue 
<pre class="codeexample">
SELECT ... FROM ORDER WHERE CUSTOMERID = 1000;
</pre>
now if there is no index on ORDER.CUSTOMERID, the database will have to do a full Table scan which is very expensive in terms of IO and resources, imagine customerId being used in lots of tables, the problem just multiplies significantly. In an multiuser scenario, this will lead to deadlocks, since the same tables are being read and locks being applied to find dependend children. Introducing an index on all the columns that are foreign key referenced helps a lot in this case.]]>
        
    </content>
</entry>

<entry>
    <title>Materialized views and database links in oracle.</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/08/materialized-views-and-databas.html" />
    <id>tag:www.sadalage.com,2009://2.58</id>

    <published>2009-08-10T15:54:12Z</published>
    <updated>2010-04-20T03:57:01Z</updated>

    <summary>Recently one of my colleague Jeff Norris had a weird error. He was trying to build a materialized view over some tables in his local database and some tables in his remote database using database links the sql to create...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="databaselink" label="database link" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="oracle" label="oracle" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Recently one of my colleague <a href="http://blog.norrissoftware.com/">Jeff Norris</a> had a weird error. He was trying to build a materialized view over some tables in his local database and some tables in his remote database using database links the sql to create the view ran fine and provided the results as expected, but when put inside a materialized view statement complained with ORA-00942 errors.</p>

<p>Lets say the two databases in question are local and remote, so the sql to create the materialized view to load immediately and refresh everyday is</p>

<pre class="codeexample">
CREATE MATERIALIZED VIEW MV_CUSTOMERBALANCE 
BUILD IMMEDIATE
REFRESH FORCE START WITH ROUND(SYSDATE) + 23/24
NEXT SYSDATE + 1
AS
SELECT customer.name , account.balance, accounttype.name 
FROM customer , account@remotedb account, accounttype@remotedb accounttype
WHERE
customer.id = account.customerid
AND account.accounttyppeid = accounttype.id
/
</pre>
Oracle started to complain when creating the above materialized view issuing an error <strong>ORA-00942: table or view does not exist</strong>, but the SQL without the create materialized view command ran fine giving the expected results.

<pre class="codeexample">
SELECT customer.name , account.balance, accounttype.name 
FROM customer , account@remotedb account, accounttype@remotedb accounttype
WHERE
customer.id = account.customerid
AND account.accounttyppeid = accounttype.id
/
</pre>
After some searching around and experimenting I found, in the create materialized view statement the database link name can be used only once, which meant we can only use the "remotedb" name once, we got around this restriction by creating two database links to the remote database as <strong>REMOTEACCOUNT</strong> and <strong>REMOTEACCOUNTTYPE</strong> and using them in the creation of the materialized view as shown below.

<pre class="codeexample">
CREATE MATERIALIZED VIEW MV_CUSTOMERBALANCE 
BUILD IMMEDIATE
REFRESH FORCE START WITH ROUND(SYSDATE) + 23/24
NEXT SYSDATE + 1
AS
SELECT customer.name , account.balance, accounttype.name 
FROM customer , account@remoteaccount account, accounttype@remoteaccounttype accounttype
WHERE
customer.id = account.customerid
AND account.accounttyppeid = accounttype.id
/
</pre>]]>
        
    </content>
</entry>

<entry>
    <title>Perfectly good data.. wasted</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/08/use-the-data-you-have-already.html" />
    <id>tag:www.sadalage.com,2009://2.57</id>

    <published>2009-08-06T04:27:28Z</published>
    <updated>2010-04-20T03:57:54Z</updated>

    <summary>Okay this is kind of a rant, maybe I&apos;m too picky or just that I hate to see perfectly good data not being used. This is how it goes.. I go regularly to this store to get Horizon organic milk...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="BI" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="bi" label="BI" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="data" label="Data" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Okay this is kind of a rant, maybe I'm too picky or just that I hate to see perfectly good data not being used.  This is how it goes..</p>

<p>I go regularly to this <a href="http://www.target.com/">store</a> to get Horizon organic milk for my family, about 60% of the time I see milk I need NOT in stock, okay I can live with that, may be lots of folks are buying organic milk, but not when it happens frequently, especially when the store knows how much milk was ordered (or supplied from the warehouse) and how much milk was sold, the store should be able to figure out that organic milk gets sold out pretty fast, putting my Business Intelligence (BI) hat on, I think the store should be able to predict when they are going to run out of organic milk ( for that matter any product), its especially frustrating when they have all the data they need to get it done.</p>

<p>One more non usage of data that really makes me red is, when the organic milk in the store is already expired (past the sell by date). I mean how hard is it for someone to generate a list of all the products that expire today and ask the store associates to remove them from the shelves by the end of the day, especially when its edible items. </p>

<p><br />
</p>]]>
        
    </content>
</entry>

<entry>
    <title>Explicitly rollback when you encounter a deadlock.</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/05/explicitly-rollback-when-you-e.html" />
    <id>tag:www.sadalage.com,2009://2.56</id>

    <published>2009-05-26T22:06:56Z</published>
    <updated>2010-04-20T03:58:51Z</updated>

    <summary>Dead lock is caused in the database when you have resources (connections) waiting for other connections to release locks on the rows that are needed by the session, resulting in all session being blocked. Oracle automatically detects deadlocks are resolves...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Best Practices" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="transaction" label="transaction" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Dead lock is caused in the database when you have resources (connections) waiting for other connections to release locks on the rows that are needed by the session, resulting in all session being blocked. Oracle automatically detects deadlocks are resolves the deadlock by rolling back the statement  in the transaction that detected the deadlock. Thing to remember is that <strong>last statement is rolled back and not the whole transaction</strong>, which means that if you had other modifications, those rows are still locked and the application should make sure that it does a explicit rollback on the connection.</p>

<p>For example.<br />
Lets assume there are two tables <strong>Parent(ParentID)</strong> and <strong>Child(ChildID)</strong></p>

<pre class="codeexample">
SESSION_A >create table parent (parentId number(10));
Table created.
SESSION_A >create table child (childId number(10));
Table created.
SESSION_A >insert into parent values (100);
1 row created.
SESSION_A >insert into child values (200);
1 row created.
SESSION_A >commit;
Commit complete.
SESSION_A >select * from parent;
  PARENTID
----------
       100

<p>SESSION_A >select * from child;<br />
   CHILDID<br />
----------<br />
       200<br />
SESSION_A ><br />
</pre></p>

<p>Now lets create a situation where a deadlock happens. There are two sessions connected to the same database and same user, SESSION_A and SESSION_B are the two sessions in question.</p>

<pre class="codeexample">
SESSION_A >update parent set parentid = 1000 where parentid=100;
1 row updated.
SESSION_B >update child set childid = 2000 where childid = 200;
1 row updated.
SESSION_B >update parent set parentid = 2001 where parentid=100;
--Waiting For Lock on Row in Parent Table, held by SESSION_A
SESSION_A >update child set childid = 1001 where childid = 200;
update child set childid = 1001 where childid = 200
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
--SESSION_A requesting lock on row, held by SESSION_B causing deadlock.
SESSION_A >
</pre>

<p>After you get the ORA-00060 error the statement <em>update child set childid = 1001 where childid = 200;</em> is rolled back.. but SESSION_B is still waiting for the lock on the Parent table to be released.</p>

<p>So when your application get the ORA-00060 or any deadlock exception in any other database, explicitly rollback your transaction (not just the current statement) so that all the changes made in the transaction and all the locks held by the transaction are released. </p>]]>
        
    </content>
</entry>

<entry>
    <title>Oracle for the Mac</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/05/oracle-for-the-mac.html" />
    <id>tag:www.sadalage.com,2009://2.55</id>

    <published>2009-05-14T20:25:52Z</published>
    <updated>2009-05-14T20:33:42Z</updated>

    <summary>Ever since I moved to the Mac, I had to run some other OS inside a VM so that I could run Oracle and use it, since Oracle was not available for the the Mac. Now that is no longer...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Ever since I moved to the Mac, I had to run some other OS inside a VM so that I could run Oracle and use it, since Oracle was not available for the the Mac. Now that is no longer the case. Oracle 10gR2 (10.2.0.4) is now available for Mac <a href="http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10204macsoft_x86-64.html">here</a></p>

<p>This is especially nice since the Oracle for Mac was the most voted requirement on <a href="https://mix.oracle.com">mix.oracle.com</a></p>]]>
        
    </content>
</entry>

<entry>
    <title>In Oracle 11g password is case sensitive</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/05/in-oracle-11g-password-is-case-1.html" />
    <id>tag:www.sadalage.com,2009://2.54</id>

    <published>2009-05-06T20:22:55Z</published>
    <updated>2009-05-06T20:43:30Z</updated>

    <summary>In Oracle 10g and before we all know that passwords are not case sensitive, so PASSWORD, Password, password would let you in and everything would be okay. If you upgrade to Oracle 11g (I know lot of you are waiting...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>In Oracle 10g and before we all know that passwords are not case sensitive, so PASSWORD, Password, password would let you in and everything would be okay.</p>

<p>If you upgrade to Oracle 11g (I know lot of you are waiting for 11gR2), you will find that passwords are case sensitive. Here is an example of case sensitive passwords.</p>

<pre class="codeexample">
c:\Software>sqlplus bddd/bddd@dosa
SQL*Plus: Release 11.1.0.6.0 - Production on Wed May 6 15:17:43 2009
Copyright (c) 1982, 2007, Oracle.  All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
With the Partitioning and OLAP options
BDDD@dosa >
</pre>

<p>Lets try to connect with a upper case password</p>

<pre class="codeexample">
c:\Software>sqlplus bddd/BDDD@dosa
SQL*Plus: Release 11.1.0.6.0 - Production on Wed May 6 15:19:25 2009
Copyright (c) 1982, 2007, Oracle.  All rights reserved.
ERROR:
ORA-01017: invalid username/password; logon denied
Enter user-name:
</pre>

<p>So what does this mean to apps running with 10g, that get ported to run with 11g. Make sure that the password set in the properties files is of the correct case.</p>

<p>You can also revert to 10g behavior by changing <strong>sec_case_sensitive_logon</strong> parameter to FALSE, since its TRUE by default.</p>

<pre class="codeexample">
alter system set sec_case_sensitive_logon=FALSE;
</pre>
]]>
        
    </content>
</entry>

<entry>
    <title>Oracle Metadata can be mis-leading</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/03/oracle-metadata-can-be-mislead.html" />
    <id>tag:www.sadalage.com,2009://2.53</id>

    <published>2009-03-31T10:49:13Z</published>
    <updated>2009-03-31T11:01:09Z</updated>

    <summary>Oracle has metadata about all its objects in various tables/views. One such view is the USER_OBJECTS or ALL_OBJECTS, this view has a column named as STATUS which shows you if the given object is VALID or INVALID. The status applies...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Oracle" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[Oracle has metadata about all its objects in various tables/views. One such view is the USER_OBJECTS or ALL_OBJECTS, this view has a column named as STATUS which shows you if the given object is VALID or INVALID. The status applies to DB Code (Stored Procedures, Functions, Triggers etc). 

To find all the INVALID objects in the schema, issue <strong>SELECT * FROM USER_OBJECTS WHERE STATUS='INVALID'</strong>.

One problem with the way oracle maintains this metadata is, changing the underlying table on which the DB Code depends, oracle marks the objects are INVALID even though the underlying table may have changed in such a way, that it does not affect the DB Code at all (like adding a new column, or making a colum nullable). Here is some code which shows you what I mean. Run it through SQLPlus.

<pre class="codeexample">
COLUMN OBJECT_NAME FORMAT A30
COLUMN STATUS FORMAT A15
spool objects.log

CREATE TABLE FOO (ID NUMBER(10), NAME VARCHAR2(30));

CREATE OR REPLACE TRIGGER TRIG_FOO
BEFORE INSERT OR UPDATE
ON FOO
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
BEGIN
	IF :NEW.name IS NULL THEN
		:NEW.name := 'NOT AVAILABLE';
	END IF;
END;
/

CREATE OR REPLACE FUNCTION FUNCTION_GET_NAME_FOR_FOOID(inFooId number)
RETURN VARCHAR2
IS
fooName VARCHAR2(30);
BEGIN
	BEGIN
     SELECT name INTO fooName FROM foo WHERE id = inFooId ;
     EXCEPTION
         WHEN NO_DATA_FOUND THEN 
     		RETURN 'NOT FOUND';
 	END;
     RETURN fooName;
 END;
/

SELECT OBJECT_NAME,STATUS FROM USER_OBJECTS WHERE STATUS='INVALID';

ALTER TABLE FOO ADD ( DESCRIPTION VARCHAR2(100));

SELECT OBJECT_NAME,STATUS FROM USER_OBJECTS WHERE STATUS='INVALID';

spool off
</pre>

To get the objects back to VALID status, all that needs to be done is 

<pre class="codeexample">
ALTER TRIGGER TRIG_FOO COMPILE;
ALTER FUNCTION FUNCTION_GET_NAME_FOR_FOOID COMPILE;

SELECT OBJECT_NAME,STATUS FROM USER_OBJECTS WHERE STATUS='INVALID';
</pre>]]>
        
    </content>
</entry>

<entry>
    <title>Presentation on Database Refactoring</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/03/presentation-on-database-refac.html" />
    <id>tag:www.sadalage.com,2009://2.52</id>

    <published>2009-03-26T05:47:23Z</published>
    <updated>2009-03-26T05:49:02Z</updated>

    <summary>My Presentation on Database Refactoring at QCon was recorded and is live now on infoQ here...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Best Practices" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>My Presentation on Database Refactoring at QCon  was recorded and is live now on infoQ <a href="http://www.infoq.com/presentations/refactoring-databases">here</a></p>]]>
        
    </content>
</entry>

<entry>
    <title>Storing just the time in Oracle</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/02/storing-just-time-in-oracle.html" />
    <id>tag:www.sadalage.com,2009://2.51</id>

    <published>2009-02-13T04:48:45Z</published>
    <updated>2009-02-13T06:17:46Z</updated>

    <summary>We came across a need to save just the Time in the database, the requirement is to store time of the day, like say the user likes to have Breakfast at 8.15AM and Lunch at 12.32PM etc. Off course oracle...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Learning" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>We came across a need to save just the Time in the database, the requirement is to store time of the day, like say the user likes to have Breakfast at 8.15AM and Lunch at 12.32PM etc. Off course oracle does not have a time only data type.  So we ended up using DATE as the data type and just setting the time. for example:</p>

<pre class="codeexample">
CREATE TABLE FOO (PREFERRED_TIME DATE NULL);
INSERT INTO FOO (TO_DATE('11:34','HH24:MI'));
</pre>
oracle automatically sets the date to the first day of the current month. so when you do a select from the FOO table the data would be

<pre class="codeexample">
SELECT TO_CHAR(PREFERRED_TIME, 'dd-mon-yyyy hh24:mi:ss') from FOO;
-----------------------
01-feb-2009 11:24:00
</pre>

<p>on the client side you will have to know to ignore the date component, this is possible area for confusion in future, since I could have many preferences over different months and my preferred time would have different date components, ideally I would just want the time, otherwise I would think having a time component and the date being a constant known value like 01/01/0001. We could achieve this using a BEFORE INSERT/UPDATE trigger which keeps the time component but updates the date component to a known constant value or you can also use your OR mapping layer like hibernate to set the value as such. If you are using hibernate, you can map the filed using the java.sql.Time object and the date is automatically set to 01/01/1970.  SqlServer 2008 seems has a Time data type.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Considerations when using stored procedures for doing CRUD.</title>
    <link rel="alternate" type="text/html" href="http://www.sadalage.com/2009/02/considerations-when-using-stor.html" />
    <id>tag:www.sadalage.com,2009://2.50</id>

    <published>2009-02-03T11:11:27Z</published>
    <updated>2009-02-03T11:18:31Z</updated>

    <summary>Some environments like to have access to the database tables routed via stored procedures. Instead of using Create/Read/Update/Delete (CRUD) with DML, stored procedures are invoked with the parameters to perform the required operation. I&apos;m not arguing about the benefits/pitfalls of...</summary>
    <author>
        <name>Pramod Sadalage</name>
        
    </author>
    
        <category term="Best Practices" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://www.sadalage.com/">
        <![CDATA[<p>Some environments like to have access to the database tables routed via stored procedures.<br />
Instead of using Create/Read/Update/Delete (CRUD) with DML, stored procedures are invoked with the parameters to perform the required operation. I'm not arguing about the benefits/pitfalls of this approach, if you have to do stored procedures, here are some things to look at.</p>

<p>1. Make the stored procedure handle one object/table only and not multiple objects or tables. <br />
2. Do not commit open transactions inside the stored procedures. <br />
3. Do not do business logic in stored procedures. <br />
4. If they are straight CRUD stored procedures, see if you can you generate the stored procedure code using some metadata?<br />
5. Make sure creation and execution of the stored procedures is part of your <a href="http://studios.thoughtworks.com/cruise-continuous-integration">Continuous Integration </a>build and developer build.<br />
6. Make sure stored procedures (or the metadata used to generate them) is under Version Control, have seen many problems when the stored procedure version does not match application code version<br />
7. Develop against the production stack database.<br />
8. Make sure exceptions thrown by the database are passed back to the application.</p>]]>
        
    </content>
</entry>

</feed>
