Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SqlClient / SqlEnums.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlEnums.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data.SqlClient {
10
11
12     using System;
13     using System.Collections.Generic;
14     using System.ComponentModel;
15     using System.Data.Common;
16     using System.Data.OleDb;
17     using System.Data.SqlTypes;
18     using System.Diagnostics;
19     using System.Globalization;
20     using System.Xml;
21     using System.IO;
22     using System.Data.Sql;
23
24     using MSS=Microsoft.SqlServer.Server;
25
26     internal sealed class MetaType {
27         internal readonly Type      ClassType;   // com+ type
28         internal readonly Type      SqlType;
29
30         internal readonly int       FixedLength; // fixed length size in bytes (-1 for variable)
31         internal readonly bool      IsFixed;     // true if fixed length, note that sqlchar and sqlbinary are not considered fixed length
32         internal readonly bool      IsLong;      // true if long
33         internal readonly bool      IsPlp;       // Column is Partially Length Prefixed (MAX)
34         internal readonly byte      Precision;   // maxium precision for numeric types // $
35         internal readonly byte      Scale;
36         internal readonly byte      TDSType;
37         internal readonly byte      NullableType;
38
39         internal readonly string    TypeName;    // string name of this type
40         internal readonly SqlDbType SqlDbType;
41         internal readonly DbType    DbType;
42
43         //  holds count of property bytes expected for a SQLVariant structure
44         internal readonly byte PropBytes;
45
46
47         // pre-computed fields
48         internal readonly bool IsAnsiType;
49         internal readonly bool IsBinType;
50         internal readonly bool IsCharType;
51         internal readonly bool IsNCharType;
52         internal readonly bool IsSizeInCharacters;
53         internal readonly bool IsNewKatmaiType;
54         internal readonly bool IsVarTime;
55         
56         internal readonly bool Is70Supported;
57         internal readonly bool Is80Supported;
58         internal readonly bool Is90Supported;
59         internal readonly bool Is100Supported;
60
61         public MetaType(byte precision, byte scale, int fixedLength, bool isFixed, bool isLong, bool isPlp, byte tdsType, byte nullableTdsType, string typeName, Type classType, Type sqlType, SqlDbType sqldbType, DbType dbType, byte propBytes) {
62             this.Precision    = precision;
63             this.Scale        = scale;
64             this.FixedLength  = fixedLength;
65             this.IsFixed      = isFixed;
66             this.IsLong       = isLong;
67             this.IsPlp        = isPlp;
68             // can we get rid of this (?just have a mapping?)
69             this.TDSType      = tdsType;
70             this.NullableType = nullableTdsType;
71             this.TypeName     = typeName;
72             this.SqlDbType    = sqldbType;
73             this.DbType       = dbType;
74
75             this.ClassType    = classType;
76             this.SqlType      = sqlType;
77             this.PropBytes    = propBytes;
78
79             IsAnsiType  = _IsAnsiType(sqldbType);
80             IsBinType   = _IsBinType(sqldbType);
81             IsCharType  = _IsCharType(sqldbType);
82             IsNCharType = _IsNCharType(sqldbType);
83             IsSizeInCharacters = _IsSizeInCharacters(sqldbType);
84             IsNewKatmaiType = _IsNewKatmaiType(sqldbType);
85             IsVarTime = _IsVarTime(sqldbType);
86
87             Is70Supported = _Is70Supported(SqlDbType);
88             Is80Supported = _Is80Supported(SqlDbType);
89             Is90Supported = _Is90Supported(SqlDbType);
90             Is100Supported = _Is100Supported(SqlDbType);
91         }
92
93         // properties should be inlined so there should be no perf penalty for using these accessor functions
94         public int TypeId {             // partial length prefixed (xml, nvarchar(max),...)
95             get { return 0;}
96         }
97
98         private static bool _IsAnsiType(SqlDbType type) {
99             return(type == SqlDbType.Char ||
100                    type == SqlDbType.VarChar ||
101                    type == SqlDbType.Text);
102         }
103
104         // is this type size expressed as count of characters or bytes?
105         private static bool _IsSizeInCharacters(SqlDbType type) {
106             return(type == SqlDbType.NChar ||
107                    type == SqlDbType.NVarChar ||
108                    type == SqlDbType.Xml ||
109                    type == SqlDbType.NText);
110         }
111
112         private static bool _IsCharType(SqlDbType type) {
113             return(type == SqlDbType.NChar ||
114                    type == SqlDbType.NVarChar ||
115                    type == SqlDbType.NText ||
116                    type == SqlDbType.Char ||
117                    type == SqlDbType.VarChar ||
118                    type == SqlDbType.Text ||
119                    type == SqlDbType.Xml);
120         }
121
122         private static bool _IsNCharType(SqlDbType type) {
123             return(type == SqlDbType.NChar ||
124                    type == SqlDbType.NVarChar ||
125                    type == SqlDbType.NText ||
126                    type == SqlDbType.Xml);
127         }
128
129         private static bool _IsBinType(SqlDbType type) {
130             return(type == SqlDbType.Image ||
131                    type == SqlDbType.Binary ||
132                    type == SqlDbType.VarBinary ||
133                    type == SqlDbType.Timestamp ||
134                    type == SqlDbType.Udt ||
135                    (int) type == 24 /*SqlSmallVarBinary*/);
136         }
137
138         private static bool _Is70Supported(SqlDbType type) {
139             return((type != SqlDbType.BigInt) && ((int)type > 0) &&
140                    ((int)type <= (int) SqlDbType.VarChar));
141         }
142
143         private static bool _Is80Supported(SqlDbType type) {
144             return((int)type >= 0 &&
145                 ((int)type <= (int) SqlDbType.Variant));
146         }
147
148         private static bool _Is90Supported(SqlDbType type) {
149             return _Is80Supported(type) ||
150                     SqlDbType.Xml == type ||
151                     SqlDbType.Udt == type;
152         }
153
154         private static bool _Is100Supported(SqlDbType type) {
155             return _Is90Supported(type) ||
156                     SqlDbType.Date == type ||
157                     SqlDbType.Time == type ||
158                     SqlDbType.DateTime2 == type ||
159                     SqlDbType.DateTimeOffset == type;
160         }
161
162         private static bool _IsNewKatmaiType(SqlDbType type) {
163             return SqlDbType.Structured == type;
164         }
165
166         internal static bool _IsVarTime(SqlDbType type) {
167             return (type == SqlDbType.Time || type == SqlDbType.DateTime2 || type == SqlDbType.DateTimeOffset);
168         }
169                 
170         //
171         // map SqlDbType to MetaType class
172         //
173         internal static MetaType GetMetaTypeFromSqlDbType(SqlDbType target, bool isMultiValued) { // WebData 113289
174             switch(target) {
175             case SqlDbType.BigInt:            return MetaBigInt;
176             case SqlDbType.Binary:            return MetaBinary;
177             case SqlDbType.Bit:               return MetaBit;
178             case SqlDbType.Char:              return MetaChar;
179             case SqlDbType.DateTime:          return MetaDateTime;
180             case SqlDbType.Decimal:           return MetaDecimal;
181             case SqlDbType.Float:             return MetaFloat;
182             case SqlDbType.Image:             return MetaImage;
183             case SqlDbType.Int:               return MetaInt;
184             case SqlDbType.Money:             return MetaMoney;
185             case SqlDbType.NChar:             return MetaNChar;
186             case SqlDbType.NText:             return MetaNText;
187             case SqlDbType.NVarChar:          return MetaNVarChar;
188             case SqlDbType.Real:              return MetaReal;
189             case SqlDbType.UniqueIdentifier:  return MetaUniqueId;
190             case SqlDbType.SmallDateTime:     return MetaSmallDateTime;
191             case SqlDbType.SmallInt:          return MetaSmallInt;
192             case SqlDbType.SmallMoney:        return MetaSmallMoney;
193             case SqlDbType.Text:              return MetaText;
194             case SqlDbType.Timestamp:         return MetaTimestamp;
195             case SqlDbType.TinyInt:           return MetaTinyInt;
196             case SqlDbType.VarBinary:         return MetaVarBinary;
197             case SqlDbType.VarChar:           return MetaVarChar;
198             case SqlDbType.Variant:           return MetaVariant;
199             case (SqlDbType)TdsEnums.SmallVarBinary: return MetaSmallVarBinary;
200             case SqlDbType.Xml:               return MetaXml;
201             case SqlDbType.Udt:               return MetaUdt;
202             case SqlDbType.Structured:
203                 if (isMultiValued) {
204                     return MetaTable;
205                 } 
206                 else {
207                     return MetaSUDT;
208                 }
209             case SqlDbType.Date:              return MetaDate;
210             case SqlDbType.Time:              return MetaTime;
211             case SqlDbType.DateTime2:         return MetaDateTime2;
212             case SqlDbType.DateTimeOffset:    return MetaDateTimeOffset;
213             default:                          throw SQL.InvalidSqlDbType(target);
214             }
215         }
216
217         //
218         // map DbType to MetaType class
219         //
220         internal static MetaType GetMetaTypeFromDbType(DbType target) {
221             // if we can't map it, we need to throw
222             switch (target) {
223             case DbType.AnsiString:             return MetaVarChar;
224             case DbType.AnsiStringFixedLength:  return MetaChar;
225             case DbType.Binary:                 return MetaVarBinary;
226             case DbType.Byte:                   return MetaTinyInt;
227             case DbType.Boolean:                return MetaBit;
228             case DbType.Currency:               return MetaMoney;
229             case DbType.Date:
230             case DbType.DateTime:               return MetaDateTime;
231             case DbType.Decimal:                return MetaDecimal;
232             case DbType.Double:                 return MetaFloat;
233             case DbType.Guid:                   return MetaUniqueId;
234             case DbType.Int16:                  return MetaSmallInt;
235             case DbType.Int32:                  return MetaInt;
236             case DbType.Int64:                  return MetaBigInt;
237             case DbType.Object:                 return MetaVariant;
238             case DbType.Single:                 return MetaReal;
239             case DbType.String:                 return MetaNVarChar;
240             case DbType.StringFixedLength:      return MetaNChar;
241             case DbType.Time:                   return MetaDateTime;
242             case DbType.Xml:                    return MetaXml;
243             case DbType.DateTime2:              return MetaDateTime2;
244             case DbType.DateTimeOffset:         return MetaDateTimeOffset;
245             case DbType.SByte:                  // unsupported
246             case DbType.UInt16:
247             case DbType.UInt32:
248             case DbType.UInt64:
249             case DbType.VarNumeric:
250             default:                            throw ADP.DbTypeNotSupported(target, typeof(SqlDbType)); // no direct mapping, error out
251             }
252         }
253
254         internal static MetaType GetMaxMetaTypeFromMetaType(MetaType mt) {
255             // if we can't map it, we need to throw
256             switch (mt.SqlDbType) {
257             case SqlDbType.VarBinary:
258             case SqlDbType.Binary:
259                 return MetaMaxVarBinary;
260             case SqlDbType.VarChar:
261             case SqlDbType.Char:
262                 return MetaMaxVarChar;
263             case SqlDbType.NVarChar:
264             case SqlDbType.NChar:
265                 return MetaMaxNVarChar;
266             case SqlDbType.Udt:
267                 // 
268                 return MetaMaxUdt;
269             default:
270                 return mt;
271            }
272         }
273
274         //
275         // map COM+ Type to MetaType class
276         //
277         static internal MetaType GetMetaTypeFromType(Type dataType) {
278             return GetMetaTypeFromValue(dataType, null, false, true);
279         }
280         static internal MetaType GetMetaTypeFromValue(object value, bool streamAllowed=true) {
281             return GetMetaTypeFromValue(value.GetType(), value, true, streamAllowed);
282         }
283
284         static private MetaType GetMetaTypeFromValue(Type dataType, object value, bool inferLen, bool streamAllowed) {
285             switch (Type.GetTypeCode(dataType)) {
286                 case TypeCode.Empty:     throw ADP.InvalidDataType(TypeCode.Empty);
287                 case TypeCode.Object:
288                     if (dataType == typeof(System.Byte[])) {
289                         // mdac 90455 must not default to image if inferLen is false ...
290                         //
291                         if (!inferLen || ((byte[]) value).Length <= TdsEnums.TYPE_SIZE_LIMIT) {
292                             return MetaVarBinary;
293                         }
294                         else {
295                             return MetaImage;
296                         }
297                     }
298                     else if (dataType == typeof(System.Guid)) {
299                         return MetaUniqueId;
300                     }
301                     else if (dataType == typeof(System.Object)) {
302                         return MetaVariant;
303                     } // check sql types now
304                     else if (dataType == typeof(SqlBinary))
305                         return MetaVarBinary;
306                     else if (dataType == typeof(SqlBoolean))
307                         return MetaBit;
308                     else if (dataType == typeof(SqlByte))
309                         return MetaTinyInt;
310                     else if (dataType == typeof(SqlBytes))
311                         return MetaVarBinary;
312                     else if (dataType == typeof(SqlChars))
313                         return  MetaNVarChar; // MDAC 87587
314                     else if (dataType == typeof(SqlDateTime))
315                         return MetaDateTime;
316                     else if (dataType == typeof(SqlDouble))
317                         return MetaFloat;
318                     else if (dataType == typeof(SqlGuid))
319                         return MetaUniqueId;
320                     else if (dataType == typeof(SqlInt16))
321                         return MetaSmallInt;
322                     else if (dataType == typeof(SqlInt32))
323                         return MetaInt;
324                     else if (dataType == typeof(SqlInt64))
325                         return MetaBigInt;
326                     else if (dataType == typeof(SqlMoney))
327                         return MetaMoney;
328                     else if (dataType == typeof(SqlDecimal))
329                         return MetaDecimal;
330                     else if (dataType == typeof(SqlSingle))
331                         return MetaReal;
332                     else if (dataType == typeof(SqlXml))
333                         return MetaXml;                
334                     else if (dataType == typeof(SqlString)) {
335                         return ((inferLen && !((SqlString)value).IsNull) ? PromoteStringType(((SqlString)value).Value) : MetaNVarChar); // MDAC 87587
336                     }
337                     else if (dataType == typeof(IEnumerable<DbDataRecord>) || dataType == typeof(DataTable)) {
338                         return MetaTable;
339                     } else if (dataType == typeof(TimeSpan)) {
340                         return MetaTime;
341                     }
342                     else if (dataType == typeof(DateTimeOffset)) {
343                         return MetaDateTimeOffset;
344                     }
345                     else { 
346                         // UDT ?
347                         SqlUdtInfo attribs = SqlUdtInfo.TryGetFromType(dataType);
348                         if (attribs != null) {
349                             return MetaUdt;
350                         }
351                         if (streamAllowed) {
352                             // Derived from Stream ?
353                             if (typeof(Stream).IsAssignableFrom(dataType)) {
354                                 return MetaVarBinary;
355                             }
356                             // Derived from TextReader ?
357                             if (typeof(TextReader).IsAssignableFrom(dataType)) {
358                                 return MetaNVarChar;
359                             }
360                             // Derived from XmlReader ? 
361                             if (typeof(System.Xml.XmlReader).IsAssignableFrom(dataType)) {
362                                 return MetaXml;
363                             }
364                         }
365                     }
366                     throw ADP.UnknownDataType(dataType);
367
368                 case TypeCode.DBNull:    throw ADP.InvalidDataType(TypeCode.DBNull);
369                 case TypeCode.Boolean:   return MetaBit;
370                 case TypeCode.Char:      throw ADP.InvalidDataType(TypeCode.Char);
371                 case TypeCode.SByte:     throw ADP.InvalidDataType(TypeCode.SByte);
372                 case TypeCode.Byte:      return MetaTinyInt;
373                 case TypeCode.Int16:     return MetaSmallInt;
374                 case TypeCode.UInt16:    throw ADP.InvalidDataType(TypeCode.UInt16);
375                 case TypeCode.Int32:     return MetaInt;
376                 case TypeCode.UInt32:    throw ADP.InvalidDataType(TypeCode.UInt32);
377                 case TypeCode.Int64:     return MetaBigInt;
378                 case TypeCode.UInt64:    throw ADP.InvalidDataType(TypeCode.UInt64);
379                 case TypeCode.Single:    return MetaReal;
380                 case TypeCode.Double:    return MetaFloat;
381                 case TypeCode.Decimal:   return MetaDecimal;
382                 case TypeCode.DateTime:  return MetaDateTime;
383                 case TypeCode.String:    return (inferLen ? PromoteStringType((string)value) : MetaNVarChar);
384                 default:                 throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType));
385             }
386         }
387
388         internal static object GetNullSqlValue(Type sqlType) {
389             if      (sqlType == typeof(SqlSingle))   return SqlSingle.Null;
390             else if (sqlType == typeof(SqlString))   return SqlString.Null;
391             else if (sqlType == typeof(SqlDouble))   return SqlDouble.Null;
392             else if (sqlType == typeof(SqlBinary))   return SqlBinary.Null;
393             else if (sqlType == typeof(SqlGuid))     return SqlGuid.Null;
394             else if (sqlType == typeof(SqlBoolean))  return SqlBoolean.Null;
395             else if (sqlType == typeof(SqlByte))     return SqlByte.Null;
396             else if (sqlType == typeof(SqlInt16))    return SqlInt16.Null;
397             else if (sqlType == typeof(SqlInt32))    return SqlInt32.Null;
398             else if (sqlType == typeof(SqlInt64))    return SqlInt64.Null;
399             else if (sqlType == typeof(SqlDecimal))  return SqlDecimal.Null;
400             else if (sqlType == typeof(SqlDateTime)) return SqlDateTime.Null;
401             else if (sqlType == typeof(SqlMoney))    return SqlMoney.Null;
402             else if (sqlType == typeof(SqlXml))      return SqlXml.Null;
403             else if (sqlType == typeof(object))      return DBNull.Value;
404             else if (sqlType == typeof(IEnumerable<DbDataRecord>))  return DBNull.Value;
405             else if (sqlType == typeof(DataTable))   return DBNull.Value;
406             else if (sqlType == typeof(DateTime))    return DBNull.Value;
407             else if (sqlType == typeof(TimeSpan))    return DBNull.Value;
408             else if (sqlType == typeof(DateTimeOffset))             return DBNull.Value;
409             else {
410                 Debug.Assert(false, "Unknown SqlType!");
411                 return DBNull.Value;
412             }
413         }
414
415         internal static MetaType PromoteStringType(string s) {
416             int len = s.Length;
417
418             if ((len << 1) > TdsEnums.TYPE_SIZE_LIMIT) {
419                 return MetaVarChar; // try as var char since we can send a 8K characters
420             }
421             return MetaNVarChar; // send 4k chars, but send as unicode
422         }
423
424         internal static object GetComValueFromSqlVariant(object sqlVal) {
425             object comVal = null;
426
427             if (ADP.IsNull(sqlVal))
428                 return comVal;
429
430             if (sqlVal is SqlSingle)
431                 comVal = ((SqlSingle)sqlVal).Value;
432             else if (sqlVal is SqlString)
433                 comVal = ((SqlString)sqlVal).Value;
434             else if (sqlVal is SqlDouble)
435                 comVal = ((SqlDouble)sqlVal).Value;
436             else if (sqlVal is SqlBinary)
437                 comVal = ((SqlBinary)sqlVal).Value;
438             else if (sqlVal is SqlGuid)
439                 comVal = ((SqlGuid)sqlVal).Value;
440             else if (sqlVal is SqlBoolean)
441                 comVal = ((SqlBoolean)sqlVal).Value;
442             else if (sqlVal is SqlByte)
443                 comVal = ((SqlByte)sqlVal).Value;
444             else if (sqlVal is SqlInt16)
445                 comVal = ((SqlInt16)sqlVal).Value;
446             else if (sqlVal is SqlInt32)
447                 comVal = ((SqlInt32)sqlVal).Value;
448             else if (sqlVal is SqlInt64)
449                 comVal = ((SqlInt64)sqlVal).Value;
450             else if (sqlVal is SqlDecimal)
451                 comVal = ((SqlDecimal)sqlVal).Value;
452             else if (sqlVal is SqlDateTime)
453                 comVal = ((SqlDateTime)sqlVal).Value;
454             else if (sqlVal is SqlMoney)
455                 comVal = ((SqlMoney)sqlVal).Value;
456             else if (sqlVal is SqlXml)
457                 comVal = ((SqlXml)sqlVal).Value;
458             else
459             {
460                 AssertIsUserDefinedTypeInstance(sqlVal, "unknown SqlType class stored in sqlVal");
461             }
462             
463
464             return comVal;
465         }
466
467         /// <summary>
468         /// Assert that the supplied object is an instance of a SQL User-Defined Type (UDT).
469         /// </summary>
470         /// <param name="sqlValue">Object instance to be tested.</param>
471         /// <remarks>
472         /// This method is only compiled with debug builds, and it a helper method for the GetComValueFromSqlVariant method defined in this class.
473         /// 
474         /// The presence of the SqlUserDefinedTypeAttribute on the object's type 
475         /// is used to determine if the object is a UDT instance (if present it is a UDT, else it is not).
476         /// </remarks>
477         /// <exception cref="NullReferenceException">
478         /// If sqlValue is null.  Callers must ensure the object is non-null.
479         /// </exception>
480         [Conditional("DEBUG")]
481         private static void AssertIsUserDefinedTypeInstance(object sqlValue, string failedAssertMessage)
482         {
483             Type type = sqlValue.GetType(); 
484             Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[] attributes = (Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[])type.GetCustomAttributes(typeof(Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute), true);
485
486             Debug.Assert(attributes.Length > 0, failedAssertMessage);
487         }
488
489         // devnote: This method should not be used with SqlDbType.Date and SqlDbType.DateTime2. 
490         //          With these types the values should be used directly as CLR types instead of being converted to a SqlValue
491         internal static object GetSqlValueFromComVariant(object comVal) {
492             object sqlVal = null;
493             if ((null != comVal) && (DBNull.Value != comVal)) {
494                 if (comVal is float)
495                     sqlVal = new SqlSingle((float)comVal);
496                 else if (comVal is string)
497                     sqlVal = new SqlString((string)comVal);
498                 else if (comVal is double)
499                     sqlVal = new SqlDouble((double)comVal);
500                 else if (comVal is System.Byte[])
501                     sqlVal = new SqlBinary((byte[])comVal);
502                 else if (comVal is System.Char)
503                     sqlVal = new SqlString(((char)comVal).ToString());
504                 else if (comVal is System.Char[])
505                     sqlVal = new SqlChars((System.Char[])comVal);
506                 else if (comVal is System.Guid)
507                     sqlVal = new SqlGuid((Guid)comVal);
508                 else if (comVal is bool)
509                     sqlVal = new SqlBoolean((bool)comVal);
510                 else if (comVal is byte)
511                     sqlVal = new SqlByte((byte)comVal);
512                 else if (comVal is Int16)
513                     sqlVal = new SqlInt16((Int16)comVal);
514                 else if (comVal is Int32)
515                     sqlVal = new SqlInt32((Int32)comVal);
516                 else if (comVal is Int64)
517                     sqlVal = new SqlInt64((Int64)comVal);
518                 else if (comVal is Decimal)
519                     sqlVal = new SqlDecimal((Decimal)comVal);
520                 else if (comVal is DateTime) {   
521                     // devnote: Do not use with SqlDbType.Date and SqlDbType.DateTime2. See comment at top of method.
522                     sqlVal = new SqlDateTime((DateTime)comVal);                    
523                 } else if (comVal is XmlReader)
524                     sqlVal = new SqlXml((XmlReader)comVal);
525                 else if (comVal is TimeSpan || comVal is DateTimeOffset)
526                     sqlVal = comVal;
527 #if DEBUG
528                 else
529                     Debug.Assert(false, "unknown SqlType class stored in sqlVal");
530 #endif
531             }
532             return sqlVal;
533         }
534
535         internal static SqlDbType GetSqlDbTypeFromOleDbType(short dbType, string typeName) {
536             SqlDbType sqlType = SqlDbType.Variant;
537             switch ((OleDbType)dbType) {
538                 case OleDbType.BigInt:
539                     sqlType = SqlDbType.BigInt;
540                     break;
541                 case OleDbType.Boolean:
542                     sqlType = SqlDbType.Bit;
543                     break;
544                 case OleDbType.Char:
545                 case OleDbType.VarChar:
546                     // these guys are ambiguous - server sends over DBTYPE_STR in both cases
547                     sqlType = (typeName == MetaTypeName.CHAR) ? SqlDbType.Char : SqlDbType.VarChar;
548                     break;
549                 case OleDbType.Currency:
550                     sqlType = (typeName == MetaTypeName.SMALLMONEY) ? SqlDbType.SmallMoney : SqlDbType.Money;
551                     break;
552                 case OleDbType.Date:
553                 case OleDbType.DBTimeStamp:
554                 case OleDbType.Filetime:
555                     switch (typeName) {
556                        case MetaTypeName.SMALLDATETIME:
557                             sqlType = SqlDbType.SmallDateTime;
558                             break;
559                         case MetaTypeName.DATETIME2:
560                             sqlType = SqlDbType.DateTime2;
561                             break;
562                        default:
563                             sqlType = SqlDbType.DateTime;
564                             break;
565                     }
566                     break;
567                 case OleDbType.Decimal:
568                 case OleDbType.Numeric:
569                     sqlType = SqlDbType.Decimal;
570                     break;
571                 case OleDbType.Double:
572                     sqlType = SqlDbType.Float;
573                     break;
574                 case OleDbType.Guid:
575                     sqlType = SqlDbType.UniqueIdentifier;
576                     break;
577                 case OleDbType.Integer:
578                     sqlType = SqlDbType.Int;
579                     break;
580                 case OleDbType.LongVarBinary:
581                     sqlType = SqlDbType.Image;
582                     break;
583                 case OleDbType.LongVarChar:
584                     sqlType = SqlDbType.Text;
585                     break;
586                 case OleDbType.LongVarWChar:
587                     sqlType = SqlDbType.NText;
588                     break;
589                 case OleDbType.Single:
590                     sqlType = SqlDbType.Real;
591                     break;
592                 case OleDbType.SmallInt:
593                 case OleDbType.UnsignedSmallInt:
594                     sqlType = SqlDbType.SmallInt;
595                     break;
596                 case OleDbType.TinyInt:
597                 case OleDbType.UnsignedTinyInt:
598                     sqlType = SqlDbType.TinyInt;
599                     break;
600                 case OleDbType.VarBinary:
601                 case OleDbType.Binary:
602                     sqlType = (typeName == MetaTypeName.BINARY) ? SqlDbType.Binary : SqlDbType.VarBinary;
603                     break;
604                 case OleDbType.Variant:
605                     sqlType = SqlDbType.Variant;
606                     break;
607                 case OleDbType.VarWChar:
608                 case OleDbType.WChar:
609                 case OleDbType.BSTR:
610                     // these guys are ambiguous - server sends over DBTYPE_WSTR in both cases
611                     // BSTR is always assumed to be NVARCHAR
612                     sqlType = (typeName == MetaTypeName.NCHAR) ? SqlDbType.NChar : SqlDbType.NVarChar;
613                     break;
614                 case OleDbType.DBDate: // Date
615                     sqlType = SqlDbType.Date;
616                     break;
617                 case (OleDbType)132: // Udt
618                     sqlType = SqlDbType.Udt;
619                     break;
620                 case (OleDbType)141: // Xml
621                     sqlType = SqlDbType.Xml;
622                     break;
623                 case (OleDbType)145: // Time
624                     sqlType = SqlDbType.Time;
625                     break;
626                 case (OleDbType)146: // DateTimeOffset
627                     sqlType = SqlDbType.DateTimeOffset;
628                     break;
629                 // 
630                 default:
631                     break; // no direct mapping, just use SqlDbType.Variant;
632                 }
633
634                 return sqlType;
635         }
636         
637         internal static MetaType GetSqlDataType(int tdsType, UInt32 userType, int length) {
638             switch (tdsType) {
639             case TdsEnums.SQLMONEYN:            return ((4 == length) ? MetaSmallMoney : MetaMoney);
640             case TdsEnums.SQLDATETIMN:          return ((4 == length) ? MetaSmallDateTime : MetaDateTime);
641             case TdsEnums.SQLINTN:              return ((4 <= length) ? ((4 == length) ? MetaInt : MetaBigInt) : ((2 == length) ? MetaSmallInt : MetaTinyInt));
642             case TdsEnums.SQLFLTN:              return ((4 == length) ? MetaReal : MetaFloat);
643             case TdsEnums.SQLTEXT:              return MetaText;
644             case TdsEnums.SQLVARBINARY:         return MetaSmallVarBinary;                
645             case TdsEnums.SQLBIGVARBINARY:      return MetaVarBinary;
646             
647             case TdsEnums.SQLVARCHAR:           //goto TdsEnums.SQLBIGVARCHAR;
648             case TdsEnums.SQLBIGVARCHAR:        return MetaVarChar;
649             
650             case TdsEnums.SQLBINARY:            //goto TdsEnums.SQLBIGBINARY;
651             case TdsEnums.SQLBIGBINARY:         return ((TdsEnums.SQLTIMESTAMP == userType) ? MetaTimestamp : MetaBinary);
652             
653             case TdsEnums.SQLIMAGE:             return MetaImage;
654             
655             case TdsEnums.SQLCHAR:              //goto TdsEnums.SQLBIGCHAR;
656             case TdsEnums.SQLBIGCHAR:           return MetaChar;
657             
658             case TdsEnums.SQLINT1:              return MetaTinyInt;
659             
660             case TdsEnums.SQLBIT:               //goto TdsEnums.SQLBITN;
661             case TdsEnums.SQLBITN:              return MetaBit;
662             
663             case TdsEnums.SQLINT2:              return MetaSmallInt;
664             case TdsEnums.SQLINT4:              return MetaInt;
665             case TdsEnums.SQLINT8:              return MetaBigInt;
666             case TdsEnums.SQLMONEY:             return MetaMoney;
667             case TdsEnums.SQLDATETIME:          return MetaDateTime;
668             case TdsEnums.SQLFLT8:              return MetaFloat;
669             case TdsEnums.SQLFLT4:              return MetaReal;
670             case TdsEnums.SQLMONEY4:            return MetaSmallMoney;
671             case TdsEnums.SQLDATETIM4:          return MetaSmallDateTime;
672             
673             case TdsEnums.SQLDECIMALN:          //goto TdsEnums.SQLNUMERICN;
674             case TdsEnums.SQLNUMERICN:          return MetaDecimal;
675             
676             case TdsEnums.SQLUNIQUEID:          return MetaUniqueId ;
677             case TdsEnums.SQLNCHAR:             return MetaNChar;
678             case TdsEnums.SQLNVARCHAR:          return MetaNVarChar;
679             case TdsEnums.SQLNTEXT:             return MetaNText;
680             case TdsEnums.SQLVARIANT:           return MetaVariant;
681             case TdsEnums.SQLUDT:               return MetaUdt;
682             case TdsEnums.SQLXMLTYPE:           return MetaXml;
683             case TdsEnums.SQLTABLE:             return MetaTable;
684             case TdsEnums.SQLDATE:              return MetaDate;
685             case TdsEnums.SQLTIME:              return MetaTime;
686             case TdsEnums.SQLDATETIME2:         return MetaDateTime2;
687             case TdsEnums.SQLDATETIMEOFFSET:    return MetaDateTimeOffset;
688             
689             case TdsEnums.SQLVOID:
690             default:
691                 Debug.Assert(false, "Unknown type " + tdsType.ToString(CultureInfo.InvariantCulture));
692                 throw SQL.InvalidSqlDbType((SqlDbType)tdsType);
693             }// case
694         }
695
696         internal static MetaType GetDefaultMetaType() {
697             return MetaNVarChar;
698         }
699
700         // Converts an XmlReader into String
701         internal static String GetStringFromXml(XmlReader  xmlreader) {
702             SqlXml sxml = new SqlXml(xmlreader);
703             return sxml.Value;
704         }
705
706         private static readonly MetaType MetaBigInt = new MetaType
707             (19, 255, 8, true, false, false, TdsEnums.SQLINT8, TdsEnums.SQLINTN, MetaTypeName.BIGINT, typeof(System.Int64), typeof(SqlInt64), SqlDbType.BigInt, DbType.Int64, 0);
708
709         private static readonly MetaType MetaFloat = new MetaType
710             (15, 255, 8, true, false, false, TdsEnums.SQLFLT8, TdsEnums.SQLFLTN, MetaTypeName.FLOAT, typeof(System.Double), typeof(SqlDouble), SqlDbType.Float, DbType.Double, 0);
711
712         private static readonly MetaType MetaReal = new MetaType
713             (7, 255, 4, true, false, false, TdsEnums.SQLFLT4, TdsEnums.SQLFLTN, MetaTypeName.REAL, typeof(System.Single), typeof(SqlSingle), SqlDbType.Real, DbType.Single, 0);
714
715         // MetaBinary has two bytes of properties for binary and varbinary
716         // 2 byte maxlen
717         private static readonly MetaType MetaBinary = new MetaType
718             (255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.BINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Binary, DbType.Binary, 2);
719
720         // syntatic sugar for the user...timestamps are 8-byte fixed length binary columns
721         private static readonly MetaType MetaTimestamp = new MetaType
722             (255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.TIMESTAMP, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Timestamp, DbType.Binary, 2);
723
724         internal static readonly MetaType MetaVarBinary = new MetaType
725             (255, 255, -1, false, false, false, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
726
727         internal static readonly MetaType MetaMaxVarBinary = new MetaType
728             (255, 255, -1, false, true, true, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
729
730         // HACK!!!  We have an internal type for smallvarbinarys stored on TdsEnums.  We
731         // store on TdsEnums instead of SqlDbType because we do not want to expose
732         // this type to the user!
733         private static readonly MetaType MetaSmallVarBinary = new MetaType
734             (255, 255, -1, false, false, false, TdsEnums.SQLVARBINARY, TdsEnums.SQLBIGBINARY, ADP.StrEmpty, typeof(System.Byte[]), typeof(SqlBinary), TdsEnums.SmallVarBinary, DbType.Binary, 2);
735
736         internal static readonly MetaType MetaImage = new MetaType
737             (255, 255, -1, false, true, false, TdsEnums.SQLIMAGE, TdsEnums.SQLIMAGE, MetaTypeName.IMAGE, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Image, DbType.Binary, 0);
738
739         private static readonly MetaType MetaBit = new MetaType
740             (255, 255, 1, true, false, false, TdsEnums.SQLBIT, TdsEnums.SQLBITN, MetaTypeName.BIT, typeof(System.Boolean), typeof(SqlBoolean), SqlDbType.Bit, DbType.Boolean, 0);
741
742         private static readonly MetaType MetaTinyInt = new MetaType
743             (3, 255, 1, true, false, false, TdsEnums.SQLINT1, TdsEnums.SQLINTN, MetaTypeName.TINYINT, typeof(System.Byte), typeof(SqlByte), SqlDbType.TinyInt, DbType.Byte, 0);
744
745         private static readonly MetaType MetaSmallInt = new MetaType
746             (5, 255, 2, true, false, false, TdsEnums.SQLINT2, TdsEnums.SQLINTN, MetaTypeName.SMALLINT, typeof(System.Int16), typeof(SqlInt16), SqlDbType.SmallInt, DbType.Int16, 0);
747
748         private static readonly MetaType MetaInt = new MetaType
749             (10, 255, 4, true, false, false, TdsEnums.SQLINT4, TdsEnums.SQLINTN, MetaTypeName.INT, typeof(System.Int32), typeof(SqlInt32), SqlDbType.Int, DbType.Int32, 0);
750
751         // MetaVariant has seven bytes of properties for MetaChar and MetaVarChar
752         // 5 byte tds collation
753         // 2 byte maxlen
754         private static readonly MetaType MetaChar = new MetaType
755             (255, 255, -1, false, false, false, TdsEnums.SQLBIGCHAR, TdsEnums.SQLBIGCHAR, MetaTypeName.CHAR, typeof(System.String), typeof(SqlString), SqlDbType.Char, DbType.AnsiStringFixedLength, 7);
756
757         private static readonly MetaType MetaVarChar = new MetaType
758             (255, 255, -1, false, false, false, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
759
760         internal static readonly MetaType MetaMaxVarChar = new MetaType
761             (255, 255, -1, false, true, true, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
762
763         internal static readonly MetaType MetaText = new MetaType
764             (255, 255, -1, false, true, false, TdsEnums.SQLTEXT, TdsEnums.SQLTEXT, MetaTypeName.TEXT, typeof(System.String), typeof(SqlString), SqlDbType.Text, DbType.AnsiString, 0);
765
766         // MetaVariant has seven bytes of properties for MetaNChar and MetaNVarChar
767         // 5 byte tds collation
768         // 2 byte maxlen
769         private static readonly MetaType MetaNChar = new MetaType
770             (255, 255, -1, false, false, false, TdsEnums.SQLNCHAR, TdsEnums.SQLNCHAR, MetaTypeName.NCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NChar, DbType.StringFixedLength, 7);
771
772         internal static readonly MetaType MetaNVarChar = new MetaType
773             (255, 255, -1, false, false, false, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
774
775         internal static readonly MetaType MetaMaxNVarChar = new MetaType
776             (255, 255, -1, false, true, true, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
777
778         internal static readonly MetaType MetaNText = new MetaType
779             (255, 255, -1, false, true, false, TdsEnums.SQLNTEXT, TdsEnums.SQLNTEXT, MetaTypeName.NTEXT, typeof(System.String), typeof(SqlString), SqlDbType.NText, DbType.String, 7);
780
781         // MetaVariant has two bytes of properties for numeric/decimal types
782         // 1 byte precision
783         // 1 byte scale
784         internal static readonly MetaType MetaDecimal = new MetaType
785             (38, 4, 17, true, false, false, TdsEnums.SQLNUMERICN, TdsEnums.SQLNUMERICN, MetaTypeName.DECIMAL, typeof(System.Decimal), typeof(SqlDecimal), SqlDbType.Decimal, DbType.Decimal, 2);
786
787         internal static readonly MetaType MetaXml = new MetaType
788             (255, 255, -1, false, true, true, TdsEnums.SQLXMLTYPE, TdsEnums.SQLXMLTYPE, MetaTypeName.XML, typeof(System.String), typeof(SqlXml), SqlDbType.Xml, DbType.Xml, 0);
789
790         private static readonly MetaType MetaDateTime = new MetaType
791             (23, 3, 8, true, false, false, TdsEnums.SQLDATETIME, TdsEnums.SQLDATETIMN, MetaTypeName.DATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.DateTime, DbType.DateTime, 0);
792
793         private static readonly MetaType MetaSmallDateTime = new MetaType
794             (16, 0, 4, true, false, false, TdsEnums.SQLDATETIM4, TdsEnums.SQLDATETIMN, MetaTypeName.SMALLDATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.SmallDateTime, DbType.DateTime, 0);
795
796         private static readonly MetaType MetaMoney = new MetaType
797             (19, 255, 8, true, false, false, TdsEnums.SQLMONEY, TdsEnums.SQLMONEYN, MetaTypeName.MONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.Money, DbType.Currency, 0);
798
799         private static readonly MetaType MetaSmallMoney = new MetaType
800             (10, 255, 4, true, false, false, TdsEnums.SQLMONEY4, TdsEnums.SQLMONEYN, MetaTypeName.SMALLMONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.SmallMoney, DbType.Currency, 0);
801
802         private static readonly MetaType MetaUniqueId = new MetaType
803             (255, 255, 16, true, false, false, TdsEnums.SQLUNIQUEID, TdsEnums.SQLUNIQUEID, MetaTypeName.ROWGUID, typeof(System.Guid), typeof(SqlGuid), SqlDbType.UniqueIdentifier, DbType.Guid, 0);
804
805         private static readonly MetaType MetaVariant = new MetaType
806             (255, 255, -1, true, false, false, TdsEnums.SQLVARIANT, TdsEnums.SQLVARIANT, MetaTypeName.VARIANT, typeof(System.Object), typeof(System.Object), SqlDbType.Variant, DbType.Object, 0);
807
808         internal static readonly MetaType MetaUdt = new MetaType
809             (255, 255, -1, false, false, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
810
811         private static readonly MetaType MetaMaxUdt = new MetaType
812             (255, 255, -1, false, true, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
813
814         private static readonly MetaType MetaTable = new MetaType
815             (255, 255, -1, false, false, false, TdsEnums.SQLTABLE, TdsEnums.SQLTABLE, MetaTypeName.TABLE, typeof(IEnumerable<DbDataRecord>), typeof(IEnumerable<DbDataRecord>), SqlDbType.Structured, DbType.Object, 0);
816
817         // 
818
819         private static readonly MetaType MetaSUDT = new MetaType 
820             (255, 255, -1, false, false, false, TdsEnums.SQLVOID, TdsEnums.SQLVOID, "", typeof(MSS.SqlDataRecord), typeof(MSS.SqlDataRecord), SqlDbType.Structured, DbType.Object, 0);
821
822         private static readonly MetaType MetaDate = new MetaType
823             (255, 255, 3, true, false, false, TdsEnums.SQLDATE, TdsEnums.SQLDATE, MetaTypeName.DATE, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.Date, DbType.Date, 0);
824
825         internal static readonly MetaType MetaTime = new MetaType
826             (255, 7, -1, false, false, false, TdsEnums.SQLTIME, TdsEnums.SQLTIME, MetaTypeName.TIME, typeof(System.TimeSpan), typeof(System.TimeSpan), SqlDbType.Time, DbType.Time, 1);
827
828         private static readonly MetaType MetaDateTime2 = new MetaType
829             (255, 7, -1, false, false, false, TdsEnums.SQLDATETIME2, TdsEnums.SQLDATETIME2, MetaTypeName.DATETIME2, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.DateTime2, DbType.DateTime2, 1);
830
831         internal static readonly MetaType MetaDateTimeOffset = new MetaType
832             (255, 7, -1, false, false, false, TdsEnums.SQLDATETIMEOFFSET, TdsEnums.SQLDATETIMEOFFSET, MetaTypeName.DATETIMEOFFSET, typeof(System.DateTimeOffset), typeof(System.DateTimeOffset), SqlDbType.DateTimeOffset, DbType.DateTimeOffset, 1);
833         
834         public static TdsDateTime FromDateTime(DateTime dateTime, byte cb) {
835             SqlDateTime sqlDateTime;
836             TdsDateTime tdsDateTime = new TdsDateTime();
837
838             Debug.Assert(cb == 8 || cb == 4, "Invalid date time size!");
839
840             if (cb == 8) {
841                 sqlDateTime = new SqlDateTime(dateTime);
842                 tdsDateTime.time = sqlDateTime.TimeTicks;
843             }
844             else {
845                 // note that smalldatetime is days&minutes.
846                 // Adding 30 seconds ensures proper roundup if the seconds are >= 30
847                 // The AddSeconds function handles eventual carryover
848                 sqlDateTime = new SqlDateTime(dateTime.AddSeconds(30));
849                 tdsDateTime.time = sqlDateTime.TimeTicks / SqlDateTime.SQLTicksPerMinute;
850             }
851             tdsDateTime.days = sqlDateTime.DayTicks;
852             return tdsDateTime;
853         }
854
855
856         public static DateTime ToDateTime(int sqlDays, int sqlTime, int length) {
857             if (length == 4) {
858                 return new SqlDateTime(sqlDays, sqlTime * SqlDateTime.SQLTicksPerMinute).Value;
859             }
860             else {
861                 Debug.Assert(length == 8, "invalid length for DateTime");
862                 return new SqlDateTime(sqlDays, sqlTime).Value;
863             }
864         }
865
866         internal static int GetTimeSizeFromScale(byte scale)
867         {
868             // Disable the assert here since we do not properly handle wrong Scale value on the parameter,
869             // see VSTFDEVDIV 795578 for more details.
870             // But, this assert is still valid when we receive Time/DateTime2/DateTimeOffset scale from server over TDS, 
871             // so it is moved to TdsParser.CommonProcessMetaData.
872             // For new scenarios, assert and/or validate the scale value before this call!
873             // Debug.Assert(0 <= scale && scale <= 7);
874
875             if (scale <= 2)
876                 return 3;
877
878             if (scale <= 4)
879                 return 4;
880
881             return 5;
882         }
883
884         //
885         // please leave string sorted alphabetically
886         // note that these names should only be used in the context of parameters.  We always send over BIG* and nullable types for SQL Server
887         //
888         private static class MetaTypeName {
889             public const string BIGINT         = "bigint";
890             public const string BINARY         = "binary";
891             public const string BIT            = "bit";
892             public const string CHAR           = "char";
893             public const string DATETIME       = "datetime";
894             public const string DECIMAL        = "decimal";
895             public const string FLOAT          = "float";
896             public const string IMAGE          = "image";
897             public const string INT            = "int";
898             public const string MONEY          = "money";
899             public const string NCHAR          = "nchar";
900             public const string NTEXT          = "ntext";
901             public const string NVARCHAR       = "nvarchar";
902             public const string REAL           = "real";
903             public const string ROWGUID        = "uniqueidentifier";
904             public const string SMALLDATETIME  = "smalldatetime";
905             public const string SMALLINT       = "smallint";
906             public const string SMALLMONEY     = "smallmoney";
907             public const string TEXT           = "text";
908             public const string TIMESTAMP      = "timestamp";
909             public const string TINYINT        = "tinyint";
910             public const string UDT            = "udt";
911             public const string VARBINARY      = "varbinary";
912             public const string VARCHAR        = "varchar";
913             public const string VARIANT        = "sql_variant";
914             public const string XML            = "xml";
915             public const string TABLE          = "table";
916             public const string DATE           = "date";
917             public const string TIME           = "time";
918             public const string DATETIME2      = "datetime2";
919             public const string DATETIMEOFFSET = "datetimeoffset";
920         }
921     }
922
923     //
924     // note: it is the client's responsibility to know what size date time he is working with
925     //
926     internal struct TdsDateTime {
927         public int days;  // offset in days from 1/1/1900
928         //     private UInt32 time;  // if smalldatetime, this is # of minutes since midnight
929         // otherwise: # of 1/300th of a second since midnight
930         public int time; // 
931     }
932
933 }
934