og 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/doc/RELEASES +26 -0
 - data/lib/glue/taggable.rb +17 -8
 - data/lib/og.rb +1 -1
 - data/lib/og/adapter/mysql.rb +6 -6
 - data/lib/og/adapter/oracle.old.rb +509 -0
 - data/lib/og/adapter/oracle.rb +299 -0
 - data/lib/og/adapter/oracle/override.rb +23 -0
 - data/lib/og/adapter/oracle/utils.rb +9 -0
 - data/lib/og/adapter/postgresql.rb +0 -16
 - data/lib/og/adapter/postgresql/script.rb +2 -2
 - data/lib/og/entity.rb +36 -13
 - data/lib/og/markers.rb +10 -2
 - data/lib/og/store/sql.rb +11 -14
 - data/lib/og/store/sql/evolution.rb +1 -1
 - data/test/glue/tc_taggable.rb +47 -12
 - data/test/og/CONFIG.rb +1 -1
 - data/test/og/store/tc_sti2.rb +23 -2
 - data/test/og/tc_inheritance2.rb +5 -3
 - data/test/og/tc_polymorphic.rb +40 -13
 - data/test/og/tc_reldelete.rb +11 -2
 - metadata +9 -4
 
| 
         @@ -0,0 +1,299 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # * Matt Bowen  <matt.bowen@farweststeel.com>
         
     | 
| 
      
 2 
     | 
    
         
            +
            # * George Moschovitis  <gm@navel.gr>
         
     | 
| 
      
 3 
     | 
    
         
            +
            # (c) 2004-2005 Navel, all rights reserved.
         
     | 
| 
      
 4 
     | 
    
         
            +
            # $Id: oracle.rb 266 2005-02-28 14:50:48Z gmosx $
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'oci8'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'og/store/sql'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'og/adapter/oracle/override'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'og/adapter/oracle/utils'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            module Og
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            # The Oracle adapter. This adapter communicates with 
         
     | 
| 
      
 15 
     | 
    
         
            +
            # an Oracle rdbms. For extra documentation see 
         
     | 
| 
      
 16 
     | 
    
         
            +
            # lib/og/adapter.rb
         
     | 
| 
      
 17 
     | 
    
         
            +
            #
         
     | 
| 
      
 18 
     | 
    
         
            +
            # Connects to Oracle by config[:user], config[:password], config[:database],
         
     | 
| 
      
 19 
     | 
    
         
            +
            # config[:privilege]. If you need DBA privilege, please set privilege as
         
     | 
| 
      
 20 
     | 
    
         
            +
            # :SYSDBA or :SYSOPER.
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            class OracleAdapter < SqlStore
         
     | 
| 
      
 23 
     | 
    
         
            +
              extend OracleUtils; include OracleUtils
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def initialize(config)
         
     | 
| 
      
 26 
     | 
    
         
            +
                super
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                @typemap.update(
         
     | 
| 
      
 29 
     | 
    
         
            +
                  Integer => 'number',
         
     | 
| 
      
 30 
     | 
    
         
            +
                  Fixnum => 'number',
         
     | 
| 
      
 31 
     | 
    
         
            +
                  String => 'varchar2(1024)', # max might be 4000 (Oracle 8)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  TrueClass => 'char(1)',
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Numeric => 'number',
         
     | 
| 
      
 34 
     | 
    
         
            +
                  Object => 'varchar2(1024)',
         
     | 
| 
      
 35 
     | 
    
         
            +
                  Array => 'varchar2(1024)',
         
     | 
| 
      
 36 
     | 
    
         
            +
                  Hash => 'varchar2(1024)'
         
     | 
| 
      
 37 
     | 
    
         
            +
                )
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                # TODO: how to pass address etc?
         
     | 
| 
      
 40 
     | 
    
         
            +
                @conn = OCI8.new(
         
     | 
| 
      
 41 
     | 
    
         
            +
                  config[:user],
         
     | 
| 
      
 42 
     | 
    
         
            +
                  config[:password],
         
     | 
| 
      
 43 
     | 
    
         
            +
                  config[:database], 
         
     | 
| 
      
 44 
     | 
    
         
            +
                  config[:privilege]
         
     | 
| 
      
 45 
     | 
    
         
            +
                )
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # gmosx: does this work?
         
     | 
| 
      
 48 
     | 
    
         
            +
                @conn.autocommit = true
         
     | 
| 
      
 49 
     | 
    
         
            +
              rescue OCIException => ex
         
     | 
| 
      
 50 
     | 
    
         
            +
                #---
         
     | 
| 
      
 51 
     | 
    
         
            +
                # mcb:
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # Oracle will raise a ORA-01017 if username, password, or 
         
     | 
| 
      
 53 
     | 
    
         
            +
                # SID aren't valid. I verified this for all three.
         
     | 
| 
      
 54 
     | 
    
         
            +
                # irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
         
     | 
| 
      
 55 
     | 
    
         
            +
                # /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017:
         
     | 
| 
      
 56 
     | 
    
         
            +
                # invalid username/password; logon denied (OCIError)
         
     | 
| 
      
 57 
     | 
    
         
            +
                #+++
         
     | 
| 
      
 58 
     | 
    
         
            +
                if database_does_not_exist_exception? ex
         
     | 
| 
      
 59 
     | 
    
         
            +
                  Logger.info "Database '#{options[:name]}' not found!"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  create_db(options)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  retry
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
                raise
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              def close
         
     | 
| 
      
 67 
     | 
    
         
            +
                @conn.logoff
         
     | 
| 
      
 68 
     | 
    
         
            +
                super
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
              
         
     | 
| 
      
 71 
     | 
    
         
            +
              #--
         
     | 
| 
      
 72 
     | 
    
         
            +
              # mcb:
         
     | 
| 
      
 73 
     | 
    
         
            +
              # Unlike MySQL or Postgres, Oracle database/schema creation is a big deal. 
         
     | 
| 
      
 74 
     | 
    
         
            +
              # I don't know how to do it from the command line. I use Oracle's Database 
         
     | 
| 
      
 75 
     | 
    
         
            +
              # Configuration Assistant utility (dbca). I takes 30min - 1hr to create 
         
     | 
| 
      
 76 
     | 
    
         
            +
              # a full blown schema. So, your FIXME comments are fine. I'm thinking you
         
     | 
| 
      
 77 
     | 
    
         
            +
              # won't be able to do this via Og, but once created, Og will be able to 
         
     | 
| 
      
 78 
     | 
    
         
            +
              # create tables, indexes, and other objects.
         
     | 
| 
      
 79 
     | 
    
         
            +
              #++
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              def create_db(database, user = nil, password = nil)
         
     | 
| 
      
 82 
     | 
    
         
            +
                # FIXME: what is appropriate for oracle?
         
     | 
| 
      
 83 
     | 
    
         
            +
                # `createdb #{database} -U #{user}`
         
     | 
| 
      
 84 
     | 
    
         
            +
                super
         
     | 
| 
      
 85 
     | 
    
         
            +
                raise NotImplementedError, "Oracle Database/Schema creation n/a"
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              def drop_db(database, user = nil, password = nil)
         
     | 
| 
      
 89 
     | 
    
         
            +
                # FIXME: what is appropriate for oracle?
         
     | 
| 
      
 90 
     | 
    
         
            +
                # `dropdb #{database} -U #{user}`
         
     | 
| 
      
 91 
     | 
    
         
            +
                super
         
     | 
| 
      
 92 
     | 
    
         
            +
                raise NotImplementedError, "Oracle Database/Schema dropping n/a"
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
              
         
     | 
| 
      
 95 
     | 
    
         
            +
              # The type used for default primary keys.
         
     | 
| 
      
 96 
     | 
    
         
            +
              
         
     | 
| 
      
 97 
     | 
    
         
            +
              def primary_key_type
         
     | 
| 
      
 98 
     | 
    
         
            +
                'integer PRIMARY KEY'
         
     | 
| 
      
 99 
     | 
    
         
            +
              end
         
     | 
| 
      
 100 
     | 
    
         
            +
              
         
     | 
| 
      
 101 
     | 
    
         
            +
              def enchant(klass, manager)
         
     | 
| 
      
 102 
     | 
    
         
            +
                pk = klass.primary_key
         
     | 
| 
      
 103 
     | 
    
         
            +
                
         
     | 
| 
      
 104 
     | 
    
         
            +
                seq = if klass.schema_inheritance_child?
         
     | 
| 
      
 105 
     | 
    
         
            +
                  "#{table(klass.schema_inheritance_root_class)}_#{pk}_seq"
         
     | 
| 
      
 106 
     | 
    
         
            +
                else
         
     | 
| 
      
 107 
     | 
    
         
            +
                  "#{table(klass)}_#{pk}_seq"
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
                
         
     | 
| 
      
 110 
     | 
    
         
            +
                pkann = klass.ann[pk]
         
     | 
| 
      
 111 
     | 
    
         
            +
                
         
     | 
| 
      
 112 
     | 
    
         
            +
                pkann[:sequence] = seq unless pkann[:sequence] == false
         
     | 
| 
      
 113 
     | 
    
         
            +
                
         
     | 
| 
      
 114 
     | 
    
         
            +
                super
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              def query_statement(sql)
         
     | 
| 
      
 118 
     | 
    
         
            +
                @conn.exec(sql)
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
              def exec_statement(sql)
         
     | 
| 
      
 122 
     | 
    
         
            +
                @conn.exec(sql)
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              def sql_update(sql)
         
     | 
| 
      
 126 
     | 
    
         
            +
                Logger.debug sql if $DBG  
         
     | 
| 
      
 127 
     | 
    
         
            +
                res = @conn.exec(sql)
         
     | 
| 
      
 128 
     | 
    
         
            +
                return res.to_i
         
     | 
| 
      
 129 
     | 
    
         
            +
              end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              # Return the last inserted row id.
         
     | 
| 
      
 132 
     | 
    
         
            +
              
         
     | 
| 
      
 133 
     | 
    
         
            +
              def last_insert_id(klass)
         
     | 
| 
      
 134 
     | 
    
         
            +
                seq = klass.ann[klass.primary_key][:sequence]
         
     | 
| 
      
 135 
     | 
    
         
            +
                
         
     | 
| 
      
 136 
     | 
    
         
            +
                res = query_statement("SELECT #{seq}.nextval FROM DUAL")
         
     | 
| 
      
 137 
     | 
    
         
            +
                lid = Integer(res.first_value)
         
     | 
| 
      
 138 
     | 
    
         
            +
                res.close
         
     | 
| 
      
 139 
     | 
    
         
            +
                
         
     | 
| 
      
 140 
     | 
    
         
            +
                return lid
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
              
         
     | 
| 
      
 143 
     | 
    
         
            +
              # The insert sql statements.
         
     | 
| 
      
 144 
     | 
    
         
            +
              
         
     | 
| 
      
 145 
     | 
    
         
            +
              def insert_sql(sql, klass)
         
     | 
| 
      
 146 
     | 
    
         
            +
                str = ''
         
     | 
| 
      
 147 
     | 
    
         
            +
                
         
     | 
| 
      
 148 
     | 
    
         
            +
                if klass.ann[klass.primary_key][:sequence]
         
     | 
| 
      
 149 
     | 
    
         
            +
                  str << "@#{klass.primary_key} = store.last_insert_id(#{klass})\n"
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
                
         
     | 
| 
      
 152 
     | 
    
         
            +
                str << "store.exec \"#{sql}\""
         
     | 
| 
      
 153 
     | 
    
         
            +
                
         
     | 
| 
      
 154 
     | 
    
         
            +
                return str
         
     | 
| 
      
 155 
     | 
    
         
            +
              end
         
     | 
| 
      
 156 
     | 
    
         
            +
              
         
     | 
| 
      
 157 
     | 
    
         
            +
              # :section: Transaction methods.
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
              # Start a new transaction.
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
              def start  
         
     | 
| 
      
 162 
     | 
    
         
            +
                @conn.autocommit = false
         
     | 
| 
      
 163 
     | 
    
         
            +
                
         
     | 
| 
      
 164 
     | 
    
         
            +
                @transaction_nesting += 1
         
     | 
| 
      
 165 
     | 
    
         
            +
              end
         
     | 
| 
      
 166 
     | 
    
         
            +
              
         
     | 
| 
      
 167 
     | 
    
         
            +
              # Commit a transaction.
         
     | 
| 
      
 168 
     | 
    
         
            +
              
         
     | 
| 
      
 169 
     | 
    
         
            +
              def commit
         
     | 
| 
      
 170 
     | 
    
         
            +
                @transaction_nesting -= 1
         
     | 
| 
      
 171 
     | 
    
         
            +
                @conn.commit if @transaction_nesting < 1
         
     | 
| 
      
 172 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 173 
     | 
    
         
            +
                @conn.autocommit = true
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
              # Rollback a transaction.
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
              def rollback
         
     | 
| 
      
 179 
     | 
    
         
            +
                @transaction_nesting -= 1
         
     | 
| 
      
 180 
     | 
    
         
            +
                @conn.rollbackif @transaction_nesting < 1
         
     | 
| 
      
 181 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 182 
     | 
    
         
            +
                @conn.autocommit = true
         
     | 
| 
      
 183 
     | 
    
         
            +
              end
         
     | 
| 
      
 184 
     | 
    
         
            +
              
         
     | 
| 
      
 185 
     | 
    
         
            +
              
         
     | 
| 
      
 186 
     | 
    
         
            +
              def create_table(klass)
         
     | 
| 
      
 187 
     | 
    
         
            +
                super
         
     | 
| 
      
 188 
     | 
    
         
            +
                
         
     | 
| 
      
 189 
     | 
    
         
            +
                seq = klass.ann[klass.primary_key][:sequence]
         
     | 
| 
      
 190 
     | 
    
         
            +
                # Create the sequence for this table. 
         
     | 
| 
      
 191 
     | 
    
         
            +
                begin
         
     | 
| 
      
 192 
     | 
    
         
            +
                  exec_statement("CREATE SEQUENCE #{seq} INCREMENT BY 1 START WITH 1 NOMAXVALUE NOMINVALUE NOCYCLE")
         
     | 
| 
      
 193 
     | 
    
         
            +
                  Logger.info "Created sequence '#{seq}'."       
         
     | 
| 
      
 194 
     | 
    
         
            +
                rescue OCIError => ex
         
     | 
| 
      
 195 
     | 
    
         
            +
                  if table_already_exists_exception?(ex)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    Logger.debug "Sequence #{seq} already exists" if $DBG
         
     | 
| 
      
 197 
     | 
    
         
            +
                  else
         
     | 
| 
      
 198 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
                
         
     | 
| 
      
 202 
     | 
    
         
            +
              end
         
     | 
| 
      
 203 
     | 
    
         
            +
              
         
     | 
| 
      
 204 
     | 
    
         
            +
              def drop_table(klass)
         
     | 
| 
      
 205 
     | 
    
         
            +
                super
         
     | 
| 
      
 206 
     | 
    
         
            +
                
         
     | 
| 
      
 207 
     | 
    
         
            +
                seq = klass.ann[klass.primary_key][:sequence]
         
     | 
| 
      
 208 
     | 
    
         
            +
                # Create the sequence for this table. 
         
     | 
| 
      
 209 
     | 
    
         
            +
                begin
         
     | 
| 
      
 210 
     | 
    
         
            +
                  exec_statement("DROP SEQUENCE #{seq}")
         
     | 
| 
      
 211 
     | 
    
         
            +
                  Logger.info "Dropped sequence '#{seq}'."       
         
     | 
| 
      
 212 
     | 
    
         
            +
                rescue OCIError => ex
         
     | 
| 
      
 213 
     | 
    
         
            +
                  if sequence_does_not_exist_exception?(ex)
         
     | 
| 
      
 214 
     | 
    
         
            +
                    Logger.debug "Sequence #{seq} didn't exist" if $DBG
         
     | 
| 
      
 215 
     | 
    
         
            +
                  else
         
     | 
| 
      
 216 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 217 
     | 
    
         
            +
                  end
         
     | 
| 
      
 218 
     | 
    
         
            +
                end
         
     | 
| 
      
 219 
     | 
    
         
            +
                
         
     | 
| 
      
 220 
     | 
    
         
            +
              end
         
     | 
| 
      
 221 
     | 
    
         
            +
              
         
     | 
| 
      
 222 
     | 
    
         
            +
              def read_attr(s, a, col)
         
     | 
| 
      
 223 
     | 
    
         
            +
                store = self.class
         
     | 
| 
      
 224 
     | 
    
         
            +
                {
         
     | 
| 
      
 225 
     | 
    
         
            +
                  String    => nil,
         
     | 
| 
      
 226 
     | 
    
         
            +
                  Integer   => :parse_int,
         
     | 
| 
      
 227 
     | 
    
         
            +
                  Float     => :parse_float,
         
     | 
| 
      
 228 
     | 
    
         
            +
                  Time      => :parse_timestamp,
         
     | 
| 
      
 229 
     | 
    
         
            +
                  Date      => :parse_date,
         
     | 
| 
      
 230 
     | 
    
         
            +
                  TrueClass => :parse_boolean,
         
     | 
| 
      
 231 
     | 
    
         
            +
                  Og::Blob  => :parse_blob
         
     | 
| 
      
 232 
     | 
    
         
            +
                }.each do |klass, meth|
         
     | 
| 
      
 233 
     | 
    
         
            +
                  if a.class.ancestor? klass
         
     | 
| 
      
 234 
     | 
    
         
            +
                    return meth ? 
         
     | 
| 
      
 235 
     | 
    
         
            +
                      "#{store}.#{meth}(res[#{col} + offset])" : "res[#{col} + offset]"
         
     | 
| 
      
 236 
     | 
    
         
            +
                  end
         
     | 
| 
      
 237 
     | 
    
         
            +
                end
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                # else try to load it via YAML
         
     | 
| 
      
 240 
     | 
    
         
            +
                "YAML::load(res[#{col} + offset])"
         
     | 
| 
      
 241 
     | 
    
         
            +
              end
         
     | 
| 
      
 242 
     | 
    
         
            +
              
         
     | 
| 
      
 243 
     | 
    
         
            +
              # Get the fields from the database table. Also handles the
         
     | 
| 
      
 244 
     | 
    
         
            +
              # change of ordering of the fields in the table.
         
     | 
| 
      
 245 
     | 
    
         
            +
              #
         
     | 
| 
      
 246 
     | 
    
         
            +
              # To ignore a database field use the ignore_fields annotation
         
     | 
| 
      
 247 
     | 
    
         
            +
              # ie,
         
     | 
| 
      
 248 
     | 
    
         
            +
              #
         
     | 
| 
      
 249 
     | 
    
         
            +
              # class Article
         
     | 
| 
      
 250 
     | 
    
         
            +
              #   ann self, :ignore_fields => [ :tsearch_idx, :ext_field ]
         
     | 
| 
      
 251 
     | 
    
         
            +
              # end
         
     | 
| 
      
 252 
     | 
    
         
            +
              #
         
     | 
| 
      
 253 
     | 
    
         
            +
              # other aliases for ignore_fiels: ignore_field, ignore_column.
         
     | 
| 
      
 254 
     | 
    
         
            +
              #--
         
     | 
| 
      
 255 
     | 
    
         
            +
              # Even though great care has been taken to make this
         
     | 
| 
      
 256 
     | 
    
         
            +
              # method reusable, oveeride if needed in your adapter.
         
     | 
| 
      
 257 
     | 
    
         
            +
              #++
         
     | 
| 
      
 258 
     | 
    
         
            +
                  
         
     | 
| 
      
 259 
     | 
    
         
            +
              def create_field_map(klass)
         
     | 
| 
      
 260 
     | 
    
         
            +
                # gmosx: This is incredible!!! argh!
         
     | 
| 
      
 261 
     | 
    
         
            +
                # res = db.query "SELECT * FROM #{klass::DBTABLE} # LIMIT 1"
         
     | 
| 
      
 262 
     | 
    
         
            +
                res = query "SELECT * FROM (SELECT * FROM #{table(klass)}) WHERE ROWNUM <= 1"
         
     | 
| 
      
 263 
     | 
    
         
            +
                map = {}
         
     | 
| 
      
 264 
     | 
    
         
            +
                
         
     | 
| 
      
 265 
     | 
    
         
            +
                # Check if the field should be ignored.
         
     | 
| 
      
 266 
     | 
    
         
            +
                
         
     | 
| 
      
 267 
     | 
    
         
            +
                ignore = klass.ann.self[:ignore_field] || klass.ann.self[:ignore_fields] || klass.ann.self[:ignore_columns]   
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                res.get_col_names.each_with_index do |f, i|
         
     | 
| 
      
 270 
     | 
    
         
            +
                  field_name = f.to_sym
         
     | 
| 
      
 271 
     | 
    
         
            +
                  unless (ignore and ignore.include?(field_name))
         
     | 
| 
      
 272 
     | 
    
         
            +
                    map[field_name] = i
         
     | 
| 
      
 273 
     | 
    
         
            +
                  end
         
     | 
| 
      
 274 
     | 
    
         
            +
                end
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                return map
         
     | 
| 
      
 277 
     | 
    
         
            +
              end
         
     | 
| 
      
 278 
     | 
    
         
            +
              
         
     | 
| 
      
 279 
     | 
    
         
            +
            private
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
              def database_does_not_exist_exception?(ex)
         
     | 
| 
      
 282 
     | 
    
         
            +
                raise ex unless ex.kind_of?(OCIException)
         
     | 
| 
      
 283 
     | 
    
         
            +
                ex.message =~ /ORA-01017/i
         
     | 
| 
      
 284 
     | 
    
         
            +
              end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
              def table_already_exists_exception?(ex)
         
     | 
| 
      
 287 
     | 
    
         
            +
                raise ex unless ex.kind_of?(OCIException)
         
     | 
| 
      
 288 
     | 
    
         
            +
                ex.message =~ /ORA-00955/i
         
     | 
| 
      
 289 
     | 
    
         
            +
              end
         
     | 
| 
      
 290 
     | 
    
         
            +
              
         
     | 
| 
      
 291 
     | 
    
         
            +
              def sequence_does_not_exist_exception?(ex)
         
     | 
| 
      
 292 
     | 
    
         
            +
                raise ex unless ex.kind_of?(OCIException)
         
     | 
| 
      
 293 
     | 
    
         
            +
                ex.message =~ /ORA-02289/i
         
     | 
| 
      
 294 
     | 
    
         
            +
              end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            end
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
            end
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            class OCI8::Cursor # :nodoc: all
         
     | 
| 
      
 3 
     | 
    
         
            +
              def blank?
         
     | 
| 
      
 4 
     | 
    
         
            +
                0 == row_count
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              def next
         
     | 
| 
      
 8 
     | 
    
         
            +
                fetch
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              def each_row
         
     | 
| 
      
 12 
     | 
    
         
            +
                idx = 0
         
     | 
| 
      
 13 
     | 
    
         
            +
                while row = fetch
         
     | 
| 
      
 14 
     | 
    
         
            +
                  yield(row, idx)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  idx += 1
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def first_value
         
     | 
| 
      
 20 
     | 
    
         
            +
                fetch[0]
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -185,22 +185,6 @@ class PostgresqlAdapter < SqlStore 
     | 
|
| 
       185 
185 
     | 
    
         
             
                "YAML::load(res[#{col} + offset])"
         
     | 
| 
       186 
186 
     | 
    
         
             
              end
         
     | 
| 
       187 
187 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
              def eval_og_allocate(klass)  
         
     | 
| 
       189 
     | 
    
         
            -
                if klass.schema_inheritance?
         
     | 
| 
       190 
     | 
    
         
            -
                  klass.module_eval %{
         
     | 
| 
       191 
     | 
    
         
            -
                    def self.og_allocate(res, row = 0)
         
     | 
| 
       192 
     | 
    
         
            -
                      Object.constant(res[0]).allocate
         
     | 
| 
       193 
     | 
    
         
            -
                    end
         
     | 
| 
       194 
     | 
    
         
            -
                  }
         
     | 
| 
       195 
     | 
    
         
            -
                else
         
     | 
| 
       196 
     | 
    
         
            -
                  klass.module_eval %{
         
     | 
| 
       197 
     | 
    
         
            -
                    def self.og_allocate(res, row = 0)
         
     | 
| 
       198 
     | 
    
         
            -
                      self.allocate
         
     | 
| 
       199 
     | 
    
         
            -
                    end
         
     | 
| 
       200 
     | 
    
         
            -
                  }
         
     | 
| 
       201 
     | 
    
         
            -
                end
         
     | 
| 
       202 
     | 
    
         
            -
              end
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
188 
     | 
    
         
             
              def read_row(obj, res, res_row, row)
         
     | 
| 
       205 
189 
     | 
    
         
             
                res.fields.each_with_index do |field, idx|
         
     | 
| 
       206 
190 
     | 
    
         
             
                  obj.instance_variable_set "@#{field}", res.getvalue(row, idx)
         
     | 
| 
         @@ -1,8 +1,8 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Helper for  
     | 
| 
      
 1 
     | 
    
         
            +
            # Helper for psql scripts.
         
     | 
| 
       2 
2 
     | 
    
         
             
            #
         
     | 
| 
       3 
3 
     | 
    
         
             
            # === Example
         
     | 
| 
       4 
4 
     | 
    
         
             
            #
         
     | 
| 
       5 
     | 
    
         
            -
            #  
     | 
| 
      
 5 
     | 
    
         
            +
            # psql '-u root -p', %{
         
     | 
| 
       6 
6 
     | 
    
         
             
            #   drop database if exists weblog_development;
         
     | 
| 
       7 
7 
     | 
    
         
             
            #   create database weblog_development;
         
     | 
| 
       8 
8 
     | 
    
         
             
            #   grant all on weblog_development.* to #{`id -un`.strip}@localhost;
         
     | 
    
        data/lib/og/entity.rb
    CHANGED
    
    | 
         @@ -184,14 +184,22 @@ module EntityMixin 
     | 
|
| 
       184 
184 
     | 
    
         
             
                  return obj
         
     | 
| 
       185 
185 
     | 
    
         
             
                end
         
     | 
| 
       186 
186 
     | 
    
         | 
| 
       187 
     | 
    
         
            -
                # An alternative creation helper,  
     | 
| 
       188 
     | 
    
         
            -
                #  
     | 
| 
       189 
     | 
    
         
            -
                # tha works with no arguments.
         
     | 
| 
      
 187 
     | 
    
         
            +
                # An alternative creation helper, does _not_ call the
         
     | 
| 
      
 188 
     | 
    
         
            +
                # initialize method when there are mandatory elements.
         
     | 
| 
       190 
189 
     | 
    
         | 
| 
       191 
190 
     | 
    
         
             
                def create_with(hash)
         
     | 
| 
       192 
     | 
    
         
            -
                  obj =  
     | 
| 
      
 191 
     | 
    
         
            +
                  obj = nil
         
     | 
| 
      
 192 
     | 
    
         
            +
                  arity = self.method(:initialize).arity
         
     | 
| 
      
 193 
     | 
    
         
            +
                  
         
     | 
| 
      
 194 
     | 
    
         
            +
                  if arity > 0 || arity < -1
         
     | 
| 
      
 195 
     | 
    
         
            +
                    obj = self.allocate
         
     | 
| 
      
 196 
     | 
    
         
            +
                  else
         
     | 
| 
      
 197 
     | 
    
         
            +
                    obj = self.new
         
     | 
| 
      
 198 
     | 
    
         
            +
                  end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  
         
     | 
| 
       193 
200 
     | 
    
         
             
                  obj.assign_with(hash)
         
     | 
| 
       194 
201 
     | 
    
         
             
                  ogmanager.store.save(obj)
         
     | 
| 
      
 202 
     | 
    
         
            +
                  
         
     | 
| 
       195 
203 
     | 
    
         
             
                  return obj
         
     | 
| 
       196 
204 
     | 
    
         
             
                end
         
     | 
| 
       197 
205 
     | 
    
         | 
| 
         @@ -323,7 +331,7 @@ module EntityMixin 
     | 
|
| 
       323 
331 
     | 
    
         
             
                  ogmanager.store.find(options)
         
     | 
| 
       324 
332 
     | 
    
         
             
                end
         
     | 
| 
       325 
333 
     | 
    
         
             
                alias_method :qbe, :query_by_example
         
     | 
| 
       326 
     | 
    
         
            -
                alias_method : 
     | 
| 
      
 334 
     | 
    
         
            +
                alias_method :find_with_attributes, :query_by_example
         
     | 
| 
       327 
335 
     | 
    
         | 
| 
       328 
336 
     | 
    
         
             
                # :section: Aggregations / Calculations
         
     | 
| 
       329 
337 
     | 
    
         | 
| 
         @@ -641,21 +649,36 @@ private 
     | 
|
| 
       641 
649 
     | 
    
         | 
| 
       642 
650 
     | 
    
         
             
                def finder(match, args)
         
     | 
| 
       643 
651 
     | 
    
         
             
                  finder = (match.captures.first == 'all_by' ? :find : :find_one)
         
     | 
| 
      
 652 
     | 
    
         
            +
                  
         
     | 
| 
       644 
653 
     | 
    
         
             
                  attrs = match.captures.last.split('_and_')
         
     | 
| 
      
 654 
     | 
    
         
            +
                  
         
     | 
| 
       645 
655 
     | 
    
         
             
                  options = (annotation[:find_options] || {}).dup
         
     | 
| 
       646 
656 
     | 
    
         
             
                  options = args.pop if args.last.is_a?(Hash)
         
     | 
| 
       647 
     | 
    
         
            -
                   
     | 
| 
      
 657 
     | 
    
         
            +
                  
         
     | 
| 
      
 658 
     | 
    
         
            +
                  relations_map = {}
         
     | 
| 
      
 659 
     | 
    
         
            +
                  relations.each {|r| relations_map[r.name.to_s] = r }
         
     | 
| 
      
 660 
     | 
    
         
            +
                  
         
     | 
| 
       648 
661 
     | 
    
         
             
                  condition = attrs.zip(args).map do |name, value|
         
     | 
| 
       649 
     | 
    
         
            -
                    if relation = relations_map 
     | 
| 
       650 
     | 
    
         
            -
                      relation = relation.last
         
     | 
| 
      
 662 
     | 
    
         
            +
                    if relation = relations_map[name]
         
     | 
| 
       651 
663 
     | 
    
         
             
                      field_name = relation.foreign_key
         
     | 
| 
       652 
     | 
    
         
            -
                      value = value.send(relation.target_class.primary_key 
     | 
| 
      
 664 
     | 
    
         
            +
                      value = value.send(relation.target_class.primary_key)
         
     | 
| 
      
 665 
     | 
    
         
            +
                      value = ogmanager.store.quote(value)
         
     | 
| 
      
 666 
     | 
    
         
            +
                    elsif name =~ /^(#{relations_map.keys.join('|')})_(.*)$/
         
     | 
| 
      
 667 
     | 
    
         
            +
                      r = relations_map[$1]
         
     | 
| 
      
 668 
     | 
    
         
            +
                      tc = r.target_class
         
     | 
| 
      
 669 
     | 
    
         
            +
                      if tc.serializable_attributes.include?($2.to_sym)
         
     | 
| 
      
 670 
     | 
    
         
            +
                        field_name = r.foreign_key
         
     | 
| 
      
 671 
     | 
    
         
            +
                        value = "(SELECT #{tc.primary_key} FROM #{tc::OGTABLE} WHERE #{$2} = '#{value}')"
         
     | 
| 
      
 672 
     | 
    
         
            +
                      end
         
     | 
| 
       653 
673 
     | 
    
         
             
                    else
         
     | 
| 
       654 
674 
     | 
    
         
             
                      anno = ann(name.to_sym)
         
     | 
| 
       655 
675 
     | 
    
         
             
                      field_name = anno[:field] || anno[:name] || name.to_sym
         
     | 
| 
       656 
     | 
    
         
            -
                       
     | 
| 
       657 
     | 
    
         
            -
                     
     | 
| 
       658 
     | 
    
         
            -
                     
     | 
| 
      
 676 
     | 
    
         
            +
                      value = ogmanager.store.quote(value)
         
     | 
| 
      
 677 
     | 
    
         
            +
                    end
         
     | 
| 
      
 678 
     | 
    
         
            +
                    
         
     | 
| 
      
 679 
     | 
    
         
            +
                    options["#{name}_op".to_sym] ||= 'IN' if value.is_a?(Array)
         
     | 
| 
      
 680 
     | 
    
         
            +
                    
         
     | 
| 
      
 681 
     | 
    
         
            +
                    %|#{field_name} #{options.delete("#{name}_op".to_sym) || '='} #{value}|
         
     | 
| 
       659 
682 
     | 
    
         
             
                  end.join(' AND ')
         
     | 
| 
       660 
683 
     | 
    
         | 
| 
       661 
684 
     | 
    
         
             
                  options.merge!(
         
     | 
| 
         @@ -703,7 +726,7 @@ class Entity 
     | 
|
| 
       703 
726 
     | 
    
         | 
| 
       704 
727 
     | 
    
         
             
                def entity_from_string(str)
         
     | 
| 
       705 
728 
     | 
    
         
             
                  res = nil
         
     | 
| 
       706 
     | 
    
         
            -
                  Og. 
     | 
| 
      
 729 
     | 
    
         
            +
                  Og::Manager.managed_classes.each do |klass|
         
     | 
| 
       707 
730 
     | 
    
         
             
                    if klass.name == str
         
     | 
| 
       708 
731 
     | 
    
         
             
                      res = klass
         
     | 
| 
       709 
732 
     | 
    
         
             
                      break
         
     |