@@ -47,7 +47,13 @@ type internal TypeInfoPerConnectionStringCache() =
4747 raise ( new InvalidOperationException( sprintf " types for connection %s were not retrieved!" connectionString))
4848 )
4949
50- member x.DoIfConnectionStringNotRegistered f = lock f
50+ member x.DoIfConnectionStringNotRegistered connectionString ifAlreadyDone f =
51+ lock ( fun () ->
52+ if x.ContainsConnectionString connectionString then
53+ ifAlreadyDone ()
54+ else
55+ f ()
56+ )
5157
5258let internal sqlDataTypesCache = new TypeInfoPerConnectionStringCache()
5359let internal findTypeInfoBySqlEngineTypeId ( connStr , system_type_id , user_type_id : int option ) =
@@ -500,7 +506,10 @@ type SqlConnection with
500506 ]
501507
502508 member internal this.LoadDataTypesMap () =
503- sqlDataTypesCache.DoIfConnectionStringNotRegistered( fun () ->
509+ sqlDataTypesCache.DoIfConnectionStringNotRegistered
510+ this.ConnectionString
511+ ( fun () -> sqlDataTypesCache.GetTypesForConnectionString this.ConnectionString)
512+ ( fun () ->
504513 assert ( this.State = ConnectionState.Open)
505514
506515 let sqlEngineTypes , tableVariableTypes =
@@ -560,25 +569,28 @@ order by
560569
561570 let getProvidedType name is_user_defined is_table_type system_type_id user_type_id =
562571 match providerTypes.TryGetValue( name) with
563- | true , value -> value
572+ | true , value -> Some value
564573 | false , _ when is_ user_ defined && not is_ table_ type ->
565574 let type_name = sqlEngineTypes.[ system_ type_ id, user_ type_ id]. name
566- //let system_type_name = t.name
575+
567576 match providerTypes.TryGetValue type_ name with
568577 | false , _ ->
569- let type_name = sqlEngineTypes.[ system_ type_ id, int system_ type_ id]. name
570- providerTypes.[ type_ name]
571- | true , item -> item
578+ match sqlEngineTypes.TryGetValue (( system_ type_ id, int system_ type_ id)) with
579+ | false , _ -> None
580+ | true , sqlType ->
581+ let type_name = sqlType.name
582+ Some providerTypes.[ type_ name]
583+ | true , item -> Some item
572584 | false , _ when is_ table_ type ->
573- SqlDbType.Structured, null , false
585+ Some ( SqlDbType.Structured, null , false )
574586 | _ -> failwith ( " Unexpected type: " + name)
575587
576588 let getProvidedTypeForSqlTypeEntry ( x : SqlTypeEntry ) = getProvidedType x.name x.is_ user_ defined x.is_ table_ type x.system_ type_ id x.user_ type_ id
577589
578590 let rec makeColumn column =
579591 let sqlTypeEntry = sqlEngineTypes.[ column.system_ type_ id, column.user_ type_ id]
580592 { Column.Name = column.name
581- TypeInfo = makeTypeInfo sqlTypeEntry
593+ TypeInfo = Option.get ( makeTypeInfo sqlTypeEntry)
582594 Nullable = column.is_ nullable
583595 MaxLength = int column.max_ length
584596 ReadOnly = column.is_ identity || column.is_ computed
@@ -590,67 +602,80 @@ order by
590602 Scale = sqlTypeEntry.scale
591603 }
592604 and makeTypeInfo ( entry: SqlTypeEntry) =
593- let sqldbtype , clrTypeFullName , isFixedLength = getProvidedTypeForSqlTypeEntry entry
594- let tableTypeColumns =
595- if entry.is_ table_ type then
596- tableVariableTypes.[ entry.user_ type_ id] |> Array.map makeColumn
597- else
598- Array.empty
599- {
600- TypeName = entry.name
601- Schema = entry.schema_ name
602- SqlEngineTypeId = int entry.system_ type_ id
603- UserTypeId = entry.user_ type_ id
604- SqlDbType = sqldbtype
605- IsFixedLength = isFixedLength
606- ClrTypeFullName = clrTypeFullName
607- UdttName = if entry.is_ table_ type then entry.name else " "
608- TableTypeColumns = tableTypeColumns
609- }
605+ match getProvidedTypeForSqlTypeEntry entry with
606+ | None -> None
607+ | Some ( sqldbtype, clrTypeFullName, isFixedLength) ->
608+ let tableTypeColumns =
609+ if entry.is_ table_ type then
610+ tableVariableTypes.[ entry.user_ type_ id] |> Array.map makeColumn
611+ else
612+ Array.empty
613+ Some {
614+ TypeName = entry.name
615+ Schema = entry.schema_ name
616+ SqlEngineTypeId = int entry.system_ type_ id
617+ UserTypeId = entry.user_ type_ id
618+ SqlDbType = sqldbtype
619+ IsFixedLength = isFixedLength
620+ ClrTypeFullName = clrTypeFullName
621+ UdttName = if entry.is_ table_ type then entry.name else " "
622+ TableTypeColumns = tableTypeColumns
623+ }
610624
611625 let typeInfosForTableTypes =
612626 sqlEngineTypes.Values
613- |> Seq.map ( fun i -> i.user_ type_ id, i)
627+ |> Seq.choose ( fun i ->
628+ match makeTypeInfo i with
629+ | Some typeInfo -> Some ( i.user_ type_ id, ( i, typeInfo))
630+ | None ->
631+ // fails when, for example, a SQLCLR type definition is on the DDL but the assembly is missing from the database.
632+ // example: AdventureWorks2012 backup in the test folder tSQLt.Private
633+ // ignoring such types
634+ None
635+ )
614636 |> dict
615637
616638 let typeInfos = [|
617639
618640 for { name = name; system_ type_ id = system_ type_ id; user_ type_ id = user_ type_ id; is_ table_ type = is_ table_ type; schema_ name = schema_ name; is_ user_ defined = is_ user_ defined } in sqlEngineTypes.Values do
619- let providerdbtype , clrTypeFullName , isFixedLength = getProvidedType name is_ user_ defined is_ table_ type system_ type_ id user_ type_ id
641+ match getProvidedType name is_ user_ defined is_ table_ type system_ type_ id user_ type_ id with
642+ | None -> ()
643+ | Some ( providerdbtype, clrTypeFullName, isFixedLength) ->
620644
621- let columns =
622- if is_ table_ type
623- then
624- let columns = tableVariableTypes .[ user _ type _ id ]
625- columns
626- |> Array.map
627- ( fun column ->
628- let typeInfo = typeInfosForTableTypes .[ user _ type _ id ]
629- { Column.Name = column.name
630- TypeInfo = makeTypeInfo typeInfo
631- Nullable = column.is_ nullable
632- MaxLength = int column.max_ length
633- ReadOnly = column.is_ identity || column.is_ computed
634- Identity = column.is_ identity
635- PartOfUniqueKey = false
636- DefaultConstraint = null
637- Description = null
638- Precision = typeInfo .precision
639- Scale = typeInfo .scale }
640- )
645+ let columns =
646+ if is_ table_ type then
647+ let columns = tableVariableTypes .[ user _ type _ id ]
648+
649+ columns
650+ |> Array.map ( fun column ->
651+ let sqlTypeInfo , typeInfo = typeInfosForTableTypes .[ user _ type _ id ]
652+ {
653+ Column.Name = column.name
654+ TypeInfo = typeInfo
655+ Nullable = column.is_ nullable
656+ MaxLength = int column.max_ length
657+ ReadOnly = column.is_ identity || column.is_ computed
658+ Identity = column.is_ identity
659+ PartOfUniqueKey = false
660+ DefaultConstraint = null
661+ Description = null
662+ Precision = sqlTypeInfo .precision
663+ Scale = sqlTypeInfo .scale
664+ } )
641665 else
642666 Array.empty
643- yield {
644- TypeName = name
645- Schema = schema_ name
646- SqlEngineTypeId = int system_ type_ id
647- UserTypeId = user_ type_ id
648- SqlDbType = providerdbtype
649- IsFixedLength = isFixedLength
650- ClrTypeFullName = clrTypeFullName
651- UdttName = if is_ table_ type then name else " "
652- TableTypeColumns = columns
653- }
667+ yield
668+ {
669+ TypeName = name
670+ Schema = schema_ name
671+ SqlEngineTypeId = int system_ type_ id
672+ UserTypeId = user_ type_ id
673+ SqlDbType = providerdbtype
674+ IsFixedLength = isFixedLength
675+ ClrTypeFullName = clrTypeFullName
676+ UdttName = if is_ table_ type then name else " "
677+ TableTypeColumns = columns
678+ }
654679 |]
655680 sqlDataTypesCache.RegisterTypes( this.ConnectionString, typeInfos)
656681 typeInfos
0 commit comments