示例#1
0
        // TODO: Remove concept of mainTable, and pass in an IEnumerable of all table
        // contexts so that we can figure out which owns each SELECTed column.
        private DataTable _initDataTable(CommandParts selectParts)
        {
            DataTable dtReturn = new DataTable();

            dtReturn.TableName = selectParts.strTableName;  // TODO: This borks on JOINs, right? That is, you need to call this something else "X JOIN Y" or similar.
            // So that I can have columns appear more than once in a single table,
            // I'm going to make a dupe of dictColToSelectMapping.  We'd have to go a
            // touch more complicated to keep the order from the original SELECT accurate.
            Dictionary <string, string> dictColMappingCopy = new Dictionary <string, string>(selectParts.dictFuzzyToColNameMappings);

            // info on creating a datatable by hand here:
            // http://msdn.microsoft.com/en-us/library/system.data.datacolumn.datatype.aspx
            // TODO: Distinct() is probably/should be overkill.
            foreach (Column colTemp in selectParts.acolInSelect.Distinct())
            {
                // "Translate" the SqlDBSharp column name to the name used in the SELECT statement.
                string strColNameForDT = WhereProcessor.GetFuzzyNameIfExists(colTemp.strColName, dictColMappingCopy);
                if (dictColMappingCopy.ContainsKey(strColNameForDT)) // these col names are from the SELECT statement, so they could be "fuzzy"
                {
                    dictColMappingCopy.Remove(strColNameForDT);      // This is the kludge that allows us to have the same col with different names.
                }
                DataColumn colForDt = new DataColumn(strColNameForDT);
                //colForDt.MaxLength = colTemp.intColLength;    // MaxLength is only useful for string columns, strangely enough.

                // TODO: Be more deliberate about these mappings.
                // Right now, I'm not really worried about casting correctly, etc.
                // Probably grouping them poorly.
                switch (colTemp.colType)
                {
                case COLUMN_TYPES.SINGLE_CHAR:
                case COLUMN_TYPES.CHAR:
                    colForDt.DataType  = System.Type.GetType("System.String");
                    colForDt.MaxLength = colTemp.intColLength;
                    break;

                case COLUMN_TYPES.AUTOINCREMENT:
                case COLUMN_TYPES.TINYINT:
                case COLUMN_TYPES.BIT:                  // TODO: This will "work", but non 0/1 values can be inserted, obviously.  So it's a kludge for now.
                case COLUMN_TYPES.INT:
                    colForDt.DataType = System.Type.GetType("System.Int32");
                    break;

                case COLUMN_TYPES.FLOAT:
                case COLUMN_TYPES.DECIMAL:
                    colForDt.DataType = System.Type.GetType("System.Decimal");
                    break;

                case COLUMN_TYPES.DATETIME:
                    colForDt.DataType = System.Type.GetType("System.DateTime");
                    break;

                default:
                    throw new Exception("Unhandled column type in Select Command: " + colTemp.colType);
                }

                dtReturn.Columns.Add(colForDt);
            }

            return(dtReturn);
        }
示例#2
0
        // TODO: Create Command interface
        public bool executeStatement(string strSql)
        {
            bool wasSuccessful = false;

            // TODO: Think how to track multiple tables/TableContexts
            // Note that the constructor will set up the table named
            // in the SELECT statement in _table.
            CommandParts updateParts = new CommandParts(_database, _table, strSql, CommandParts.COMMAND_TYPES.UPDATE);

            if (MainClass.bDebug)
            {
                Console.WriteLine("SELECT: " + updateParts.strSelect);
                Console.WriteLine("FROM: " + updateParts.strFrom);
                if (!string.IsNullOrEmpty(updateParts.strInnerJoinKludge))
                {
                    throw new Exception("Syntax error: INNER JOIN in an UPDATE statement is not supported: " + strSql);
                }
                Console.WriteLine("WHERE: " + updateParts.strWhere);    // Note that WHEREs aren't applied to inner joined tables right now.
                Console.WriteLine("ORDER BY: " + updateParts.strOrderBy);
            }

            _table = _database.getTableByName(updateParts.strTableName);

            DataTable dtThrowAway = new DataTable();

            WhereProcessor.ProcessRows(ref dtThrowAway, _table, updateParts);

            return(wasSuccessful);
        }
示例#3
0
        // TODO: Create Command interface
        public DataTable executeStatement(string strSql)
        {
            DataTable dtReturn = new DataTable();

            // TODO: Think how to track multiple tables/TableContexts
            // Note that the constructor will set up the table named
            // in the SELECT statement in _table.
            CommandParts selectParts = new CommandParts(_database, _table, strSql, CommandParts.COMMAND_TYPES.SELECT);

            if (MainClass.bDebug)
            {
                string strDebug = "SELECT: " + selectParts.strSelect + "\n";
                strDebug += "FROM: " + selectParts.strFrom + "\n";
                if (!string.IsNullOrEmpty(selectParts.strInnerJoinKludge))
                {
                    strDebug += "INNER JOIN: " + selectParts.strInnerJoinKludge + "\n";
                }
                strDebug += "WHERE: " + selectParts.strWhere + "\n";    // Note that WHEREs aren't applied to inner joined tables right now.
                strDebug += "ORDER BY: " + selectParts.strOrderBy + "\n";

                SqlDbSharpLogger.LogMessage(strDebug, "SelectCommand executeStatement");
            }

            _table = _database.getTableByName(selectParts.strTableName);
            Queue <TableContext> qAllTables = new Queue <TableContext>();

            qAllTables.Enqueue(_table);
            dtReturn = _initDataTable(selectParts);

            WhereProcessor.ProcessRows(ref dtReturn, _table, selectParts);


            //=====================================================================
            // POST-PROCESS INNER JOINS
            // (Joins are only in selects, so this isn't part of WhereProcessing.)
            //
            // To take account of joins, we basically need to create a SelectParts
            // per inner join.  So we need to create a WHERE from the table we
            // just selected and then send those values down to a new _selectRows.
            //=====================================================================
            if (selectParts.strInnerJoinKludge.Length > 0)
            {
                if (selectParts.qInnerJoinFields.Count < 1)
                {
                    selectParts.qInnerJoinFields.EnqueueIfNotContains("*");  // Kludge for "SELECT * FROM Table1 INNER JOIN..." or "SELECT test, * From...", etc
                }

                // TODO: Why aren't we just throwing in the whole selectParts again?
                dtReturn = _processInnerJoin(qAllTables, dtReturn, selectParts.strInnerJoinKludge, selectParts.strTableName, selectParts.strOrderBy, selectParts.qInnerJoinFields);

                // Now we need to make sure the order of the DataColumns reflects what we had
                // in the original SQL. At least initially, column order wasn't guaranteed in
                // _processInnerJoin, as it would add columns first for the "main" table and then
                // for each "inner SELECT".
                string strFromSelect = string.Join(", ", selectParts.qstrAllColumnNames.ToArray());
                string strInTable    = string.Join(", ", dtReturn.Columns.Cast <DataColumn>().Select(c => c.ColumnName).ToArray());
                MainClass.logIt(string.Format(@"Select fields: {0}
Fields pushed into dtReturn: {1}", strFromSelect, strInTable));

                try
                {
                    string[] astrFromSelect = selectParts.qstrAllColumnNames.ToArray();
                    for (int i = 0; i < astrFromSelect.Length; i++)
                    {
                        dtReturn.Columns[astrFromSelect[i]].SetOrdinal(i);
                    }

                    // TODO: There are better ways to do this.
                    // TODO: Figure out if this handles all fuzzy name translations
                    // earlier in the SELECT process.
                    if (selectParts.lstrJoinONLYFields.Count() > 0)
                    {
                        foreach (string colName in selectParts.lstrJoinONLYFields)
                        {
                            dtReturn.Columns.Remove(colName);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new SyntaxException("Problem reordering columns in inner join -- " + e.ToString());
                }
            }
            //=====================================================================
            // EO POST-PROCESS INNER JOINS
            //=====================================================================


            // strOrderBy has had all whitespace shortened to one space, so we can get away with the hardcoded 9.
            if (null != selectParts.strOrderBy && selectParts.strOrderBy.Length > 9)
            {
                // ORDER BY needs to make sure it's not sorting on a fuzzy named column
                // that may not have been explicitly selected in the SELECT.
                string[] astrOrderByFields = selectParts.strOrderBy.Substring(9).Split(',');    // Substring(9) to get rid of "ORDER BY " <<< But, ultimately, why not tokenize here too?
                string   strCleanedOrderBy = string.Empty;

                foreach (string orderByClause in astrOrderByFields)
                {
                    bool ascNotDesc = true;

                    string strOrderByClause = orderByClause.Trim();
                    string strField         = orderByClause.Trim();

                    if (strField.Split().Length > 1)
                    {
                        strField = strOrderByClause.Substring(0, strOrderByClause.IndexOf(' ')).Trim();
                        string strAscDesc = strOrderByClause.Substring(strOrderByClause.IndexOf(' ')).Trim();
                        ascNotDesc = (-1 == strAscDesc.IndexOf("DESC", StringComparison.CurrentCultureIgnoreCase));
                    }

                    strOrderByClause += ",";    // This is the default value if there's no fuzziness, and it needs the comma put back.

                    // TODO: Integrate fields prefixed by specific table names.
                    if (!dtReturn.Columns.Contains(strField))
                    {
                        // Check for fuzziness.
                        foreach (TableContext table in qAllTables)
                        {
                            if (!table.containsColumn(strField, false) && table.containsColumn(strField, true))
                            {
                                strOrderByClause = table.getRawColName(strField)
                                                   + (ascNotDesc ? " ASC" : " DESC")
                                                   + ",";
                                break;
                            }
                        }
                    }

                    strCleanedOrderBy += " " + strOrderByClause;
                }

                dtReturn.DefaultView.Sort = strCleanedOrderBy.Trim(',');
                dtReturn = dtReturn.DefaultView.ToTable();
            }

            if (selectParts.dictRawNamesToASNames.Count > 0)
            {
                try
                {
                    foreach (KeyValuePair <string, string> kvp in selectParts.dictRawNamesToASNames)
                    {
                        dtReturn.Columns[kvp.Key].ColumnName = kvp.Value;
                    }
                }
                catch (Exception e)
                {
                    throw new SyntaxException("Illegal AS usage: " + e.ToString());
                }
            }

            return(dtReturn);
        }