// sets val as string with Oid oid (PqsqlDbType.BPChar, PqsqlDbType.Text, PqsqlDbType.Varchar, PqsqlDbType.Name, PqsqlDbType.Char) // into pqparam_buffer pb internal static unsafe void SetText(IntPtr pb, object val, PqsqlDbType oid) { #if !WIN32 PqsqlUTF8Statement.AddText(pb, (string)val, (uint)oid); #else fixed(char *t = (string)val) { PqsqlBinaryFormat.pqbf_add_unicode_text(pb, t, (uint)oid); } #endif }
// sets val as DateTime with Oid oid (PqsqlDbType.Timestamp, PqsqlDbType.TimestampTZ) into pqparam_buffer pb internal static void SetTimestamp(IntPtr pb, object val, PqsqlDbType oid) { DateTime dt = (DateTime)val; long sec; int usec; PqsqlBinaryFormat.GetTimestamp(dt, out sec, out usec); PqsqlBinaryFormat.pqbf_add_timestamp(pb, sec, usec, (uint)oid); }
// sets val as DateTime with Oid oid (PqsqlDbType.Time, PqsqlDbType.TimeTZ) into pqparam_buffer pb internal static void SetDate(IntPtr pb, object val, PqsqlDbType oid) { DateTime dt = (DateTime)val; int year; int month; int day; PqsqlBinaryFormat.GetDate(dt, out year, out month, out day); PqsqlBinaryFormat.pqbf_add_date(pb, year, month, day); }
// sets val as TimeSpan into pqparam_buffer pb internal static void SetInterval(IntPtr pb, object val, PqsqlDbType oid) { TimeSpan ts = (TimeSpan)val; long offset; int day; int month; PqsqlBinaryFormat.GetInterval(ts, out offset, out day, out month); PqsqlBinaryFormat.pqbf_add_interval(pb, offset, day, month); }
public int WriteInt8(long value) { if (mRowInfo == null) { throw new InvalidOperationException("PqsqlCopyFrom.Start must be called before we can write data"); } long begin = LengthCheckReset(); #if CODECONTRACTS Contract.Assume(mRowInfo != null); Contract.Assume(mPos >= 0 && mPos < mRowInfo.Length); #endif PqsqlColInfo ci = mRowInfo[mPos]; if (ci == null) { throw new PqsqlException("PqsqlCopyFrom.Start could not setup column information for column " + mPos); } PqsqlDbType oid = ci.Oid; uint destination_length; // check destination row datatype switch (oid) { case PqsqlDbType.Int8: PqsqlBinaryFormat.pqbf_set_int8(mExpBuf, value); destination_length = 8; break; case PqsqlDbType.Int4: // dangerous, but let's try it PqsqlBinaryFormat.pqbf_set_int4(mExpBuf, (int)value); destination_length = 4; break; case PqsqlDbType.Int2: // dangerous, but let's try it PqsqlBinaryFormat.pqbf_set_int2(mExpBuf, (short)value); destination_length = 2; break; default: throw new PqsqlException("Column " + ci.ColumnName + ": cannot write " + typeof(long) + " to column of type " + oid); } unsafe { sbyte *val = PqsqlBinaryFormat.pqbf_get_bufval(mExpBuf) + begin; return(PutColumn(val, destination_length)); } }
// sets val as TimeSpan with Oid oid PqsqlDbType.Time into pqparam_buffer pb internal static void SetTime(IntPtr pb, object val, PqsqlDbType oid) { TimeSpan ts = (TimeSpan)val; int hour; int min; int sec; int fsec; PqsqlBinaryFormat.GetTime(ts, out hour, out min, out sec, out fsec); PqsqlBinaryFormat.pqbf_add_time(pb, hour, min, sec, fsec); }
public int WriteDate(DateTime value) { if (mRowInfo == null) { throw new InvalidOperationException($"{nameof(PqsqlCopyFrom)}.{nameof(Start)} must be called before we can write data"); } long begin = LengthCheckReset(); #if CODECONTRACTS Contract.Assume(mRowInfo != null); Contract.Assume(mPos >= 0 && mPos < mRowInfo.Length); #endif PqsqlColInfo ci = mRowInfo[mPos]; if (ci == null) { throw new PqsqlException($"{nameof(PqsqlCopyFrom)}.{nameof(Start)} could not setup column information for column {mPos}"); } PqsqlDbType oid = ci.Oid; if (oid != PqsqlDbType.Date) { throw new PqsqlException($"{nameof(PqsqlCopyFrom)}.{nameof(WriteDate)}: cannot write {PqsqlDbType.Date} into column {mPos} of type {oid}"); } int year; int month; int day; PqsqlBinaryFormat.GetDate(value, out year, out month, out day); PqsqlBinaryFormat.pqbf_set_date(mExpBuf, year, month, day); unsafe { sbyte *val = PqsqlBinaryFormat.pqbf_get_bufval(mExpBuf) + begin; return(PutColumn(val, 4)); } }
// dispatch parameter type and add it to parameter buffer mPqPB private void AddParameterValue(PqsqlTypeRegistry.PqsqlTypeParameter tp, PqsqlDbType oid, object v) { #if CODECONTRACTS Contract.Assume(mPqPB != IntPtr.Zero); #endif if (v == null || v == DBNull.Value) { // null arrays must have oid of element type PqsqlBinaryFormat.pqbf_add_null(mPqPB, (uint)(oid & ~PqsqlDbType.Array)); } else if ((oid & PqsqlDbType.Array) == PqsqlDbType.Array) { SetArrayValue(mPqPB, v, oid, tp); } else { #if CODECONTRACTS Contract.Assume(tp.SetValue != null); #endif tp.SetValue(mPqPB, v, oid); } }
private static void SetArrayValue(IntPtr pb, object val, PqsqlDbType oid, PqsqlTypeRegistry.PqsqlTypeParameter n) { #if CODECONTRACTS Contract.Requires <ArgumentNullException>(n != null); #else if (n == null) { throw new ArgumentNullException(nameof(n)); } #endif oid &= ~PqsqlDbType.Array; // remove Array flag PqsqlDbType arrayoid = n.ArrayDbType; Action <IntPtr, object> setArrayItem = n.SetArrayItem; Array aparam = val as Array; int rank = aparam.Rank; // TODO we only support one-dimensional array for now if (rank != 1) { throw new NotImplementedException("only one-dimensional arrays supported"); } int[] dim = new int[rank]; int[] lbound = new int[rank]; // always set 1-based numbering for indexes, we cannot reuse lower and upper bounds from aparam for (int i = 0; i < rank; i++) { lbound[i] = 1; dim[i] = aparam.GetLength(i); } IntPtr a = IntPtr.Zero; try { a = UnsafeNativeMethods.PqsqlWrapper.createPQExpBuffer(); if (a == IntPtr.Zero) { throw new PqsqlException("Cannot create buffer for array parameter"); } // check for null values int hasNulls = 0; foreach (object o in aparam) { if (o == null || o == DBNull.Value) { hasNulls = 1; break; } } // create array header PqsqlBinaryFormat.pqbf_set_array(a, rank, hasNulls, (uint)oid, dim, lbound); // copy array items to buffer foreach (object o in aparam) { if (o == null || o == DBNull.Value) // null values have itemlength -1 only { PqsqlBinaryFormat.pqbf_set_array_itemlength(a, -1); } else { setArrayItem(a, o); } } // add array to parameter buffer PqsqlBinaryFormat.pqbf_add_array(pb, a, (uint)arrayoid); } finally { if (a != IntPtr.Zero) { UnsafeNativeMethods.PqsqlWrapper.destroyPQExpBuffer(a); } } }
// convert v of typecode vtc to typecode dtc private static object ConvertParameterValue(object v, TypeCode vtc, TypeCode dtc, PqsqlDbType oid) { if (vtc == TypeCode.String && string.IsNullOrEmpty(v as string)) { // we got an empty string that does not match the target type: we simply // ignore the value and return null, as the conversion wouldn't work return(null); } if (dtc == TypeCode.DateTime && oid == PqsqlDbType.TimestampTZ) { // use UTC in case we want to convert DateTimeOffset to DateTime DateTimeOffset off = (DateTimeOffset)v; v = off.UtcDateTime; } // in case we would have an invalid cast from object to target type // we try to convert v to the registered ProviderType next return(Convert.ChangeType(v, dtc, CultureInfo.InvariantCulture)); }
/// <summary> /// append parameter to parameter buffer. /// we convert and infer the right datatype in case the user supplied inconsistent type information. /// </summary> public void AddParameter(PqsqlParameter parameter) { if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } ParameterDirection direction = parameter.Direction; // skip output parameters and return values if (direction == ParameterDirection.Output || direction == ParameterDirection.ReturnValue) { return; } PqsqlDbType oid = parameter.PqsqlDbType; object v = parameter.Value; bool vNotNull = v != null && v != DBNull.Value; TypeCode vtc = Convert.GetTypeCode(v); // no PqsqlDbType set by the user, try to infer datatype from Value and set new oid // if v is null or DBNull.Value, we can work with PqsqlDbType.Unknown if (oid == PqsqlDbType.Unknown && vNotNull) { if (vtc != TypeCode.Object) { oid = InferValueType(vtc); } else if (v is DateTimeOffset) { oid = PqsqlDbType.TimestampTZ; } else if (v is byte[]) { oid = PqsqlDbType.Bytea; } else if (v is Guid) { oid = PqsqlDbType.Uuid; } else if (v is TimeSpan) { oid = PqsqlDbType.Interval; } if (oid == PqsqlDbType.Unknown) // cannot resolve oid for non-null v { throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not infer datatype for PqsqlParameter {0} (TypeCode={1})", parameter.ParameterName, vtc)); } } // get SetValue / SetArrayItem delegates for oid PqsqlTypeRegistry.PqsqlTypeParameter tp = PqsqlTypeRegistry.Get(oid & ~PqsqlDbType.Array); if (tp == null) { // do not try to fetch datatype specs with PqsqlTypeRegistry.FetchType() here, just bail out throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Datatype {0} is not supported", oid & ~PqsqlDbType.Array)); } // try to convert to the proper datatype in case the user supplied a wrong PqsqlDbType // if v is null or DBNull.Value, we can work with PqsqlDbType.Unknown if (vNotNull && (oid & PqsqlDbType.Array) != PqsqlDbType.Array) { TypeCode tc = tp.TypeCode; if (vtc != TypeCode.Empty && vtc != tc) { v = ConvertParameterValue(v, vtc, tc, oid); } } // add parameter to the parameter buffer AddParameterValue(tp, oid, v); }
public override void ResetDbType() { mDbType = DbType.Object; mPqsqlDbType = PqsqlDbType.Unknown; mValue = null; }