@@ -202,7 +202,7 @@ func (m Migrator) CreateTable(values ...interface{}) error {
202202 createTableSQL += ")"
203203
204204 if tableOption , ok := m .DB .Get ("gorm:table_options" ); ok {
205- createTableSQL += fmt .Sprint (tableOption )
205+ createTableSQL += " " + fmt .Sprint (tableOption )
206206 }
207207
208208 err = tx .Exec (createTableSQL , values ... ).Error
@@ -484,6 +484,81 @@ func (m Migrator) DropConstraint(value interface{}, name string) error {
484484 return m .Migrator .DropConstraint (value , name )
485485}
486486
487+ // CreateType creates or replaces an Oracle user-defined type
488+ func (m Migrator ) CreateType (typeName string , args ... string ) error {
489+ typeName = strings .TrimSpace (typeName )
490+ if typeName == "" {
491+ return fmt .Errorf ("typeName is required" )
492+ }
493+ var typeKind , typeOf string
494+ if len (args ) > 0 {
495+ typeKind = args [0 ]
496+ }
497+ if len (args ) > 1 {
498+ typeOf = args [1 ]
499+ }
500+
501+ name := strings .ToLower (typeName )
502+ typeKind = strings .TrimSpace (typeKind )
503+ typeOf = strings .TrimSpace (typeOf )
504+
505+ // Incomplete object type
506+ if typeKind == "" && typeOf == "" {
507+ ddl := fmt .Sprintf (`CREATE TYPE "%s"` , name )
508+ return m .DB .Exec (ddl ).Error
509+ }
510+
511+ k := strings .ToUpper (typeKind )
512+ var ddl string
513+
514+ switch {
515+ // Standalone varying array (varray) type and Standalone nested table type
516+ case strings .HasPrefix (k , "VARRAY" ) || strings .HasPrefix (k , "TABLE " ):
517+ if typeOf == "" {
518+ return fmt .Errorf ("typeof is required for collection types (VARRAY/TABLE)" )
519+ }
520+ ddl = fmt .Sprintf (`CREATE OR REPLACE TYPE "%s" AS %s OF %s` , name , typeKind , typeOf )
521+
522+ // Abstract Data Type (ADT)
523+ case k == "OBJECT" || strings .HasPrefix (k , "OBJECT" ):
524+ if typeOf == "" {
525+ return fmt .Errorf ("attributes definition is required for OBJECT types" )
526+ }
527+ attrs := typeOf
528+ if ! strings .HasPrefix (attrs , "(" ) {
529+ attrs = "(" + attrs + ")"
530+ }
531+ ddl = fmt .Sprintf (`CREATE OR REPLACE TYPE "%s" AS OBJECT %s` , name , attrs )
532+
533+ default :
534+ // Invalid or unsupported types
535+ return fmt .Errorf ("unsupported type kind %q (must be OBJECT, VARRAY, or TABLE)" , typeKind )
536+ }
537+
538+ return m .DB .Exec (ddl ).Error
539+ }
540+
541+ // DropType drops a user-defined type
542+ func (m Migrator ) DropType (typeName string ) error {
543+ typeName = strings .TrimSpace (typeName )
544+ if typeName == "" {
545+ return fmt .Errorf ("dropType: typeName is required" )
546+ }
547+ ddl := fmt .Sprintf (`DROP TYPE "%s" FORCE` , strings .ToLower (typeName ))
548+ return m .DB .Exec (ddl ).Error
549+ }
550+
551+ // HasType checks whether a user-defined type exists
552+ func (m Migrator ) HasType (typeName string ) bool {
553+ if typeName == "" {
554+ return false
555+ }
556+
557+ var count int
558+ err := m .DB .Raw (`SELECT COUNT(*) FROM USER_TYPES WHERE UPPER(TYPE_NAME) = UPPER(?)` , typeName ).Scan (& count ).Error
559+ return err == nil && count > 0
560+ }
561+
487562// DropIndex drops the index with the specified `name` from the table associated with `value`
488563func (m Migrator ) DropIndex (value interface {}, name string ) error {
489564 return m .RunWithValue (value , func (stmt * gorm.Statement ) error {
0 commit comments