Ejemplo n.º 1
0
        // executes SET parameter=value
        internal void SetSessionParameter(string parameter, object value)
        {
            if (mConnection == IntPtr.Zero)
            {
                throw new InvalidOperationException("cannot set session parameter on closed connection");
            }

            if (string.IsNullOrEmpty(parameter))
            {
                throw new ArgumentOutOfRangeException(nameof(parameter), "parameter out of range");
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("set ");
            sb.Append(parameter);
            sb.Append('=');
            sb.Append(value);

            byte[]         stmt = PqsqlUTF8Statement.CreateUTF8Statement(sb);
            ExecStatusType s    = Exec(stmt);

            if (s != ExecStatusType.PGRES_COMMAND_OK)
            {
                string err = GetErrorMessage();
                string msg = string.Format(CultureInfo.InvariantCulture, "Could not set «{0}» to «{1}»: {2}", parameter, value, err);
                throw new PqsqlException(msg);
            }
        }
Ejemplo n.º 2
0
        // 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
        }
Ejemplo n.º 3
0
        // Summary:
        //     Attempts to cancels the execution of a System.Data.Common.DbCommand.
        public override void Cancel()
        {
            if (mConn == null)
            {
                return;
            }

            ConnectionState s = mConn.State;

            // no cancel possible/necessary if connection is closed / open / connecting / broken
            if (s == ConnectionState.Closed || s == ConnectionState.Open || (s & (ConnectionState.Broken | ConnectionState.Connecting)) > 0)
            {
                return;
            }

            IntPtr cancel = PqsqlWrapper.PQgetCancel(mConn.PGConnection);

            if (cancel != IntPtr.Zero)
            {
                sbyte[] buf = new sbyte[256];

                string err;
                unsafe
                {
                    fixed(sbyte *b = buf)
                    {
                        int cret = PqsqlWrapper.PQcancel(cancel, b, 256);

                        PqsqlWrapper.PQfreeCancel(cancel);

                        if (cret == 1)
                        {
                            return;
                        }

                        err = PqsqlUTF8Statement.CreateStringFromUTF8(new IntPtr(b));
                    }
                }

                throw new PqsqlException("Could not cancel command «" + mCmdText + "»: " + err);
            }
        }
Ejemplo n.º 4
0
        public int WriteText(string value)
        {
            long begin = LengthCheckReset();

            unsafe
            {
#if !WIN32
                PqsqlUTF8Statement.SetText(mExpBuf, value);
#else
                fixed(char *sp = value)
                {
                    PqsqlBinaryFormat.pqbf_set_unicode_text(mExpBuf, sp);
                }
#endif
                long end = PqsqlBinaryFormat.pqbf_get_buflen(mExpBuf);
                long len = end - begin;

                sbyte *val = PqsqlBinaryFormat.pqbf_get_bufval(mExpBuf) + begin;
                return(PutColumn(val, (uint)len));
            }
        }
Ejemplo n.º 5
0
        // return current error message
        internal string GetErrorMessage()
        {
#if CODECONTRACTS
            Contract.Ensures(Contract.Result <string>() != null);
#endif

            string msg = string.Empty;

            if (mConnection != IntPtr.Zero)
            {
                unsafe
                {
                    sbyte *b = PqsqlWrapper.PQerrorMessage(mConnection);

                    if (b != null)
                    {
                        msg = PqsqlUTF8Statement.CreateStringFromUTF8(new IntPtr(b));
                    }
                }
            }

            return(msg);
        }
Ejemplo n.º 6
0
        // adds o as string array element to PQExpBuffer a
        internal static void SetTextArray(IntPtr a, object o)
        {
            string v = (string)o;

            long len0 = PqsqlBinaryFormat.pqbf_get_buflen(a);             // get start position

            PqsqlBinaryFormat.pqbf_set_array_itemlength(a, -2);           // first set an invalid item length

#if !WIN32
            PqsqlUTF8Statement.SetText(a, v);
#else
            unsafe
            {
                fixed(char *t = v)
                {
                    PqsqlBinaryFormat.pqbf_set_unicode_text(a, t);                     // encode text value (variable length)
                }
            }
#endif

            int len = (int)(PqsqlBinaryFormat.pqbf_get_buflen(a) - len0);              // get new buffer length
            // update array item length == len - 4 bytes
            PqsqlBinaryFormat.pqbf_update_array_itemlength(a, -len, len - 4);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// split PqsqlCommand.CommandText into an array of sub-statements
        /// </summary>
        /// <returns></returns>
        private IEnumerable <string> ParseStatements()
        {
#if CODECONTRACTS
            Contract.Ensures(Contract.Result <IEnumerable <string> >() != null);
#endif

            IntPtr pstate   = IntPtr.Zero;
            IntPtr varArray = IntPtr.Zero;

            try
            {
                unsafe
                {
                    int offset = 0;
                    varArray = Marshal.AllocHGlobal((mParams.Count + 1) * sizeof(sbyte *));

                    // always write NULL before we continue, so finally clause can clean up properly
                    // if we get hit by an exception
                    Marshal.WriteIntPtr(varArray, offset, IntPtr.Zero);

                    foreach (PqsqlParameter param in mParams)
                    {
                        // always write NULL before we continue, so finally clause can clean up properly
                        // if we get hit by an exception
                        Marshal.WriteIntPtr(varArray, offset, IntPtr.Zero);

                        string psqlParamName = param.PsqlParameterName;

                        // psql-specific: characters allowed in variable names: [A-Za-z\200-\377_0-9]
                        // we only allow lowercase [a-z0-9_], as PsqlParameter always stores parameter names in lowercase
                        char invalid = psqlParamName.FirstOrDefault(c => !(c >= 'a' && c <= 'z') && !char.IsDigit(c) && c != '_');
                        if (invalid != default(char))
                        {
                            string msg = string.Format(CultureInfo.InvariantCulture, "Parameter name «{0}» contains invalid character «{1}»", psqlParamName, invalid);
                            throw new PqsqlException(msg, (int)PqsqlState.SYNTAX_ERROR);
                        }

                        // variable names are pure ascii
                        byte[] paramNameArray = Encoding.ASCII.GetBytes(psqlParamName);
                        int    len            = paramNameArray.Length;

                        // we need a null-terminated variable string
                        IntPtr varString = Marshal.AllocHGlobal(len + 1);
                        Marshal.Copy(paramNameArray, 0, varString, len);
                        Marshal.WriteByte(varString, len, 0);

                        Marshal.WriteIntPtr(varArray, offset, varString);
                        offset += sizeof(sbyte *);
                    }

                    Marshal.WriteIntPtr(varArray, offset, IntPtr.Zero);
                }

                // varArray pointers must be valid during parsing
                pstate = PqsqlBinaryFormat.pqparse_init(varArray);

                // always terminate CommandText with a ; (prevents unnecessary re-parsing)
                // we have the following cases:
                // 1) "select 1; select 2"
                // 2) "select 1; select 2 -- dash-dash comment forces newline for semicolon"
                // 3) "select 1; select 2; /* slash-star comment forces unnecessary semicolon */"
                // 4) "select 1; select 2 -- dash-dash comment triggers ;"
                //
                // For (1), (2), (3) we simply add a newline + semicolon.  Case (4) is more tricky
                // and requires to re-start the parser for another round.
                string commands = CommandText.TrimEnd();
                if (!commands.EndsWith(";", StringComparison.Ordinal))
                {
                    commands += "\n;";
                }

                byte[] statementsString = PqsqlUTF8Statement.CreateUTF8Statement(commands);

                // add a semicolon-separated list of UTF-8 statements
                int parsingState = PqsqlBinaryFormat.pqparse_add_statements(pstate, statementsString);

                if (parsingState == -1)                 // syntax error or missing parameter
                {
                    ParsingError(pstate);
                }
                else if (parsingState == 1)                 // incomplete input, continue with current parsing state and force final "\n;"
                {
                    statementsString = PqsqlUTF8Statement.CreateUTF8Statement("\n;");
                    if (PqsqlBinaryFormat.pqparse_add_statements(pstate, statementsString) != 0)
                    {
                        ParsingError(pstate);                         // syntax error / missing parameter / incomplete input
                    }
                }

                uint num = PqsqlBinaryFormat.pqparse_num_statements(pstate);

                string[] statements = new string[num];

                // the null-terminated array of UTF-8 statement strings
                IntPtr sptr = PqsqlBinaryFormat.pqparse_get_statements(pstate);

                if (num > 0 && sptr != IntPtr.Zero)
                {
                    unsafe
                    {
                        for (int i = 0; i < num; i++)
                        {
                            sbyte **stm = (sbyte **)sptr.ToPointer();

                            if (stm == null || *stm == null)
                            {
                                break;
                            }

                            // convert UTF-8 to UTF-16
                            statements[i] = PqsqlUTF8Statement.CreateStringFromUTF8(new IntPtr(*stm));
                            sptr          = IntPtr.Add(sptr, sizeof(sbyte *));
                        }
                    }
                }

#if CODECONTRACTS
                Contract.Assert(statements != null);
                Contract.Assert(statements.Length == num);
#endif

                return(from statement in statements
                       where !string.IsNullOrWhiteSpace(statement) && statement != ";"
                       select statement);
            }
            finally
            {
                if (pstate != IntPtr.Zero)
                {
                    PqsqlBinaryFormat.pqparse_destroy(pstate);
                }

                if (varArray != IntPtr.Zero)
                {
                    unsafe
                    {
                        for (int i = mParams.Count - 1; i >= 0; i--)
                        {
                            IntPtr varPtr = Marshal.ReadIntPtr(varArray, i * sizeof(sbyte *));

                            if (varPtr != IntPtr.Zero)
                            {
                                Marshal.FreeHGlobal(varPtr);
                            }
                        }
                    }
                    Marshal.FreeHGlobal(varArray);
                }
            }
        }
Ejemplo n.º 8
0
        public void End()
        {
            IntPtr res;
            string err = string.Empty;

#if CODECONTRACTS
            Contract.Assume(mConn != null);
#endif
            IntPtr conn = mConn.PGConnection;

            if (mColBuf == IntPtr.Zero)
            {
                return;
            }

            int ret = PqsqlBinaryFormat.pqcb_put_end(mColBuf);             // flush column buffer

            if (ret != 1)
            {
                err = err.Insert(0, "Could not send end-of-data indication: ");
                goto bailout;
            }

            res = PqsqlWrapper.PQgetResult(conn);

            if (res != IntPtr.Zero)
            {
                ExecStatusType s = PqsqlWrapper.PQresultStatus(res);

                PqsqlWrapper.PQclear(res);

                if (s == ExecStatusType.PGRES_COPY_IN)
                {
                    // still in COPY_IN mode? bail out!
                    byte[] b = PqsqlUTF8Statement.CreateUTF8Statement("COPY FROM cancelled by client");

                    unsafe
                    {
                        fixed(byte *bs = b)
                        {
                            ret = PqsqlWrapper.PQputCopyEnd(conn, bs);
                        }
                    }

                    res = PqsqlWrapper.PQgetResult(conn);

                    if (res != IntPtr.Zero)
                    {
                        s = PqsqlWrapper.PQresultStatus(res);
                        PqsqlWrapper.PQclear(res);
                    }

                    err = err.Insert(0, "Cancelled COPY FROM while still in COPY_IN mode (" + s + "," + ret + "): ");

                    goto bailout;
                }

                if (s != ExecStatusType.PGRES_COMMAND_OK)
                {
                    err = err.Insert(0, "COPY FROM failed (" + s + "): ");

                    goto bailout;
                }

                // consume all remaining results until we reach the NULL result
                while ((res = PqsqlWrapper.PQgetResult(conn)) != IntPtr.Zero)
                {
                    // always free mResult
                    PqsqlWrapper.PQclear(res);
                }

                return;
            }

bailout:
            err += mConn.GetErrorMessage();
            throw new PqsqlException(err);
        }
Ejemplo n.º 9
0
        public virtual void Start()
        {
#if CODECONTRACTS
            Contract.Requires <InvalidOperationException>(
                !string.IsNullOrWhiteSpace(Table) || !string.IsNullOrWhiteSpace(QueryInternal),
                "Table and Query properties are null.");
#else
            if (string.IsNullOrWhiteSpace(Table) && string.IsNullOrWhiteSpace(QueryInternal))
            {
                throw new InvalidOperationException("Table and Query properties are null.");
            }
#endif

            // PQexec does not set field types in PQresult for COPY FROM statements,
            // just retrieve 0 rows for the field types of Table or Query

            // TODO use PqsqlCopyColumnsCollection for ColumnList
            StringBuilder sb = new StringBuilder();
            if (!SuppressSchemaQueryInternal)
            {
                if (QueryInternal == null)
                {
                    sb.AppendFormat("SELECT {0} FROM {1} LIMIT 0;", (object)ColumnList ?? '*', Table);
                }
                else
                {
                    sb.AppendFormat("{0} LIMIT 0;", QueryInternal);
                }

                // fetch number of columns and store column information
                using (PqsqlCommand cmd = new PqsqlCommand(mConn))
                {
                    cmd.CommandText    = sb.ToString();
                    cmd.CommandType    = CommandType.Text;
                    cmd.CommandTimeout = CopyTimeout;

                    using (PqsqlDataReader r = cmd.ExecuteReader(CommandBehavior.Default))
                    {
                        // just pick current row information
                        PqsqlColInfo[] src = r.RowInformation;

                        if (src == null)
                        {
                            throw new PqsqlException("Cannot retrieve RowInformation for '" +
                                                     QueryInternal ?? Table + "'.");
                        }

                        mColumns = src.Length;
                        mRowInfo = new PqsqlColInfo[mColumns];

                        Array.Copy(src, mRowInfo, mColumns);
                    }
                }

                sb.Clear();
            }

            // now build COPY FROM statement
            sb.Append("COPY ");

            if (QueryInternal == null)
            {
                sb.AppendFormat("{0} ", Table);

                // always create list of columns if not SuppressSchemaQuery
                if (string.IsNullOrEmpty(ColumnList))
                {
                    if (!SuppressSchemaQueryInternal)
                    {
                        // just assume that we use standard table order
                        sb.AppendFormat("({0})", string.Join(",", mRowInfo.Select(r => r.ColumnName)));
                    }
                }
                else
                {
                    // let user decide the column order
                    sb.AppendFormat("({0})", ColumnList);
                }
            }
            else
            {
                sb.AppendFormat("({0})", QueryInternal);
            }

            sb.AppendFormat(" {0} BINARY", CopyStmtDirection);

            byte[] q = PqsqlUTF8Statement.CreateUTF8Statement(sb);

            IntPtr         res;
            ExecStatusType s = mConn.Exec(q, out res);

            // result buffer should contain column information and PGconn should be in COPY_IN state
            if (res == IntPtr.Zero || s != QueryResultType)
            {
                mConn.Consume(res);                 // we might receive several results...
                throw new PqsqlException("Could not execute statement «" + sb + "»: " + mConn.GetErrorMessage());
            }

            // check first column format, current implementation will have all columns set to binary
            if (PqsqlWrapper.PQfformat(res, 0) == 0)
            {
                mConn.Consume(res);
                throw new PqsqlException("PqsqlCopyFrom only supports BINARY format.");
            }

            var nFields = PqsqlWrapper.PQnfields(res);
            if (SuppressSchemaQueryInternal)
            {
                mColumns = nFields;
            }
            else
            {
                // sanity check
                if (mColumns != nFields)
                {
                    mConn.Consume(res);
                    throw new PqsqlException("Received wrong number of columns for " + sb);
                }
            }

            // done with result inspection
            PqsqlWrapper.PQclear(res);
        }
Ejemplo n.º 10
0
        protected string Error()
        {
            IntPtr res;
            string err  = string.Empty;
            IntPtr conn = mConn.PGConnection;

            res = PqsqlWrapper.PQgetResult(conn);

            if (res != IntPtr.Zero)
            {
                ExecStatusType s = PqsqlWrapper.PQresultStatus(res);

                PqsqlWrapper.PQclear(res);

                if (s == ExecStatusType.PGRES_COPY_IN || s == ExecStatusType.PGRES_COPY_OUT)
                {
                    if (s == ExecStatusType.PGRES_COPY_IN)
                    {
                        // still in COPY_IN mode? bail out!
                        byte[] b = PqsqlUTF8Statement.CreateUTF8Statement("COPY cancelled by client");
                        int    end;

                        unsafe
                        {
                            fixed(byte *bs = b)
                            {
                                end = PqsqlWrapper.PQputCopyEnd(conn, bs);
                            }
                        }

                        if (end != 1)
                        {
                            err = err.Insert(0, "Cannot cancel COPY (" + s + "): ");

                            goto bailout;
                        }
                    }

                    res = PqsqlWrapper.PQgetResult(conn);

                    if (res != IntPtr.Zero)
                    {
                        s = PqsqlWrapper.PQresultStatus(res);
                        PqsqlWrapper.PQclear(res);
                    }
                }

                if (s != ExecStatusType.PGRES_COMMAND_OK)
                {
                    err = err.Insert(0, "COPY failed (" + s + "): ");

                    goto bailout;
                }

                // consume all remaining results until we reach the NULL result
                while ((res = PqsqlWrapper.PQgetResult(conn)) != IntPtr.Zero)
                {
                    // always free mResult
                    PqsqlWrapper.PQclear(res);
                }

                return(err);
            }

bailout:
            err += mConn.GetErrorMessage();

            return(err);
        }