public void GeneratePrimaryKey(TextWriter xtw, Sooda.Schema.TableInfo tableInfo, string additionalSettings, string terminator) { bool first = true; foreach (Sooda.Schema.FieldInfo fi in tableInfo.Fields) { if (fi.IsPrimaryKey) { if (first) { xtw.Write(GetAlterTableStatement(tableInfo)); xtw.Write(" ("); } else { xtw.Write(", "); } xtw.Write(fi.DBColumnName); first = false; } } if (!first) { xtw.Write(')'); TerminateDDL(xtw, additionalSettings, terminator); } }
static TableInfo Prepare(FieldInfo fi) { ClassInfo ci = fi.ParentClass; if (ci.ContainsField(fi.Name)) throw new SoodaSchemaException("Field " + fi.Name + " already exists in " + ci.Name); TableInfo table = new TableInfo(); table.TableUsageType = TableUsageType.DynamicField; table.DBTableName = ci.Name + "_" + fi.Name; // copy primary key fields FieldInfo[] pks = ci.GetPrimaryKeyFields(); for (int i = 0; i < pks.Length; i++) { FieldInfo pk = pks[i]; table.Fields.Add(new FieldInfo { Name = pk.Name, DataType = pk.DataType, Size = pk.Size, Precision = pk.Precision, References = pk.References, IsPrimaryKey = true, DBColumnName = i == 0 ? "id" : "id" + (i + 1) }); } fi.DBColumnName = "value"; table.Fields.Add(fi); return table; }
public void GenerateIndices(TextWriter xtw, Sooda.Schema.TableInfo tableInfo, string additionalSettings, string terminator) { foreach (Sooda.Schema.FieldInfo fi in tableInfo.Fields) { if (fi.References != null) { GenerateIndex(xtw, fi, additionalSettings, terminator); } } }
public void GenerateForeignKeys(TextWriter xtw, Sooda.Schema.TableInfo tableInfo, string terminator) { foreach (Sooda.Schema.FieldInfo fi in tableInfo.Fields) { if (fi.References != null) { xtw.Write("alter table {0} add constraint {1} foreign key ({2}) references {3}({4})", tableInfo.DBTableName, GetConstraintName(tableInfo.DBTableName, fi.DBColumnName), fi.DBColumnName, fi.ReferencedClass.UnifiedTables[0].DBTableName, fi.ReferencedClass.GetFirstPrimaryKeyField().DBColumnName ); xtw.Write(terminator ?? GetDDLCommandTerminator()); } } }
public void GenerateCreateTable(TextWriter xtw, Sooda.Schema.TableInfo tableInfo, string additionalSettings, string terminator) { xtw.WriteLine("create table {0} (", tableInfo.DBTableName); Dictionary <string, bool> processedFields = new Dictionary <string, bool>(); for (int i = 0; i < tableInfo.Fields.Count; ++i) { if (!processedFields.ContainsKey(tableInfo.Fields[i].DBColumnName)) { GenerateCreateTableField(xtw, tableInfo.Fields[i]); if (i == tableInfo.Fields.Count - 1) { xtw.WriteLine(); } else { xtw.WriteLine(','); } processedFields.Add(tableInfo.Fields[i].DBColumnName, true); } } xtw.Write(')'); TerminateDDL(xtw, additionalSettings, terminator); }
internal void MergeTables() { DatabaseTables = new List<TableInfo>(); Dictionary<string, TableInfo> mergedTables = new Dictionary<string, TableInfo>(); foreach (TableInfo table in UnifiedTables) { TableInfo mt; if (!mergedTables.TryGetValue(table.DBTableName, out mt)) { mt = new TableInfo(); mt.DBTableName = table.DBTableName; mt.TableUsageType = table.TableUsageType; mt.OrdinalInClass = -1; mt.Rehash(); mergedTables[table.DBTableName] = mt; DatabaseTables.Add(mt); } foreach (FieldInfo fi in table.Fields) { if (mt.ContainsField(fi.Name)) { if (!fi.IsPrimaryKey) throw new SoodaSchemaException("Duplicate field found for one table!"); continue; } mt.Fields.Add(fi); } mt.Rehash(); } }
public static SoodaObject GetRefFromRecordHelper(SoodaTransaction tran, ISoodaObjectFactory factory, IDataRecord record, int firstColumnIndex, TableInfo[] loadedTables, int tableIndex) { return GetRefFromRecordHelper(tran, factory, record, firstColumnIndex, loadedTables, tableIndex, true); }
private void DumpTable(SchemaInfo schemaInfo, string owner, string table) { Console.WriteLine("Dumping table {0}.{1}", owner, table); ClassInfo ci = new ClassInfo(); ci.Name = MakePascalCase(table); TableInfo ti = new TableInfo(); ci.LocalTables = new List<TableInfo>(); ti.DBTableName = table; ci.LocalTables.Add(ti); foreach (DataRow r in dataSet.Tables["Columns"].Select("TABLE_NAME='" + table + "' and TABLE_OWNER='" + owner + "'", "ORDINAL_POSITION")) { try { string columnName = r["COLUMN_NAME"].ToString(); FieldInfo fi = new FieldInfo(); fi.Name = MakePascalCase(columnName); fi.DBColumnName = columnName; GetSoodaFieldAttributes(fi, r, false); ti.Fields.Add(fi); } catch (Exception ex) { Console.WriteLine("WARNING: {0}", ex.Message); } } bool hasPrimaryKey = false; foreach (DataRow r in dataSet.Tables["PrimaryKeys"].Select("TABLE_NAME='" + table + "' and TABLE_OWNER='" + owner + "'")) { string column = Convert.ToString(r["COLUMN_NAME"]); foreach (FieldInfo fi in ti.Fields) { if (0 == String.Compare(fi.DBColumnName, column, true)) { fi.IsPrimaryKey = true; hasPrimaryKey = true; } } } if (!hasPrimaryKey) { Console.WriteLine("WARNING: Created artificial primary key from the first column of the " + ti.DBTableName + " table. This may be incorrect."); ti.Fields[0].IsPrimaryKey = true; } schemaInfo.Classes.Add(ci); }
private void UnifyTable(Dictionary<string, TableInfo> tables, TableInfo ti, bool isInherited) { TableInfo baseTable; if (!tables.TryGetValue(ti.DBTableName, out baseTable)) { baseTable = new TableInfo(); baseTable.DBTableName = ti.DBTableName; tables[ti.DBTableName] = baseTable; isInherited = false; } foreach (FieldInfo fi in ti.Fields) { bool found = false; foreach (FieldInfo fi0 in baseTable.Fields) { if (fi0.Name == fi.Name) { found = true; break; } } if (!found) { baseTable.Fields.Add(fi); if (isInherited) fi.IsNullable = true; } } }
private void UpdateFieldFromDbSchema(TableInfo ti, FieldInfo fi, SchemaInfo dbSchema) { FieldInfo dbfi = FindDBColumnInfo(dbSchema, ti.DBTableName, fi.DBColumnName); if (dbfi == null) { Console.WriteLine("WARNING. FIELD NOT FOUND IN DB: " + ti.DBTableName + "," + fi.DBColumnName); return; } if (UpdateTypes) fi.DataType = dbfi.DataType; if (UpdateSizes) fi.Size = dbfi.Size; if (UpdateNullable) fi.IsNullable = dbfi.IsNullable; if (UpdatePrimaryKeys) fi.IsPrimaryKey = dbfi.IsPrimaryKey; }
public abstract IDataReader LoadRefObjectList(SchemaInfo schemaInfo, RelationInfo relationInfo, int masterColumn, object masterValue, out TableInfo[] tables);
public abstract IDataReader LoadObjectList(SchemaInfo schemaInfo, ClassInfo classInfo, SoodaWhereClause whereClause, SoodaOrderBy orderBy, int startIdx, int pageCount, SoodaSnapshotOptions options, out TableInfo[] tables);
public abstract IDataReader LoadObjectTable(SoodaObject obj, object keyValue, int tableNumber, out TableInfo[] tables);
public abstract IDataReader LoadObject(SoodaObject obj, object keyValue, out TableInfo[] tables);
private string GetTableUsageHint(TableInfo tableInfo) { if (_builder.OuterJoinSyntax != SqlOuterJoinSyntax.Oracle && tableInfo.TableUsageType == TableUsageType.Dictionary) { return " WITH (NOLOCK) "; } return ""; }
private void OutputTableFrom(TableInfo tableInfo, string tableAlias) { Output.Write(_builder.QuoteIdentifier(tableInfo.DBTableName)); if (tableAlias.Length > 0) { Output.Write(' '); Output.Write(tableAlias); } if (_builder.OuterJoinSyntax != SqlOuterJoinSyntax.Oracle && tableInfo.TableUsageType == TableUsageType.Dictionary) { Output.Write(" WITH (NOLOCK) "); } }
private string GetLoadingSelectStatement(ClassInfo classInfo, TableInfo tableInfo, out TableInfo[] loadedTables) { TableLoadingCache cache; if (tableLoadingCache.TryGetValue(tableInfo, out cache)) { loadedTables = cache.LoadedTables; return cache.SelectStatement; } Queue<_QueueItem> queue = new Queue<_QueueItem>(); List<TableInfo> additional = new List<TableInfo>(); additional.Add(tableInfo); SoqlQueryExpression queryExpression = new SoqlQueryExpression(); queryExpression.From.Add(classInfo.Name); queryExpression.FromAliases.Add(""); foreach (FieldInfo fi in tableInfo.Fields) { SoqlPathExpression pathExpr = new SoqlPathExpression(fi.Name); queryExpression.SelectExpressions.Add(pathExpr); queryExpression.SelectAliases.Add(""); if (fi.ReferencedClass != null && fi.PrefetchLevel > 0) { _QueueItem item = new _QueueItem(); item.classInfo = fi.ReferencedClass; item.level = fi.PrefetchLevel; item.prefix = pathExpr; queue.Enqueue(item); } } // TODO - add prefetching while (queue.Count > 0) { _QueueItem it = queue.Dequeue(); foreach (TableInfo ti in it.classInfo.UnifiedTables) { additional.Add(ti); foreach (FieldInfo fi in ti.Fields) { // TODO - this relies on the fact that path expressions // are never reconstructed or broken. We simply share previous prefix // perhaps it's cleaner to Clone() the expression here SoqlPathExpression extendedExpression = new SoqlPathExpression(it.prefix, fi.Name); queryExpression.SelectExpressions.Add(extendedExpression); queryExpression.SelectAliases.Add(""); if (it.level >= 1 && fi.PrefetchLevel > 0 && fi.ReferencedClass != null) { _QueueItem newItem = new _QueueItem(); newItem.classInfo = fi.ReferencedClass; newItem.prefix = extendedExpression; newItem.level = it.level - 1; queue.Enqueue(newItem); } } } } queryExpression.WhereClause = null; int parameterPos = 0; foreach (FieldInfo fi in tableInfo.Fields) { if (fi.IsPrimaryKey) { SoqlBooleanRelationalExpression expr = Soql.FieldEqualsParam(fi.Name, parameterPos); if (parameterPos == 0) { queryExpression.WhereClause = expr; } else { queryExpression.WhereClause = new SoqlBooleanAndExpression(queryExpression.WhereClause, expr); } parameterPos++; } } string query = SoqlToSql(queryExpression, tableInfo.OwnerClass.Schema, false); // logger.Debug("Loading statement for table {0}: {1}", tableInfo.NameToken, query); loadedTables = additional.ToArray(); tableLoadingCache[tableInfo] = new TableLoadingCache(query, loadedTables); return query; }
void DoDeletesForTable(SoodaObject obj, TableInfo table) { StringBuilder builder = new StringBuilder(); ArrayList queryParams = new ArrayList(); builder.Append("delete from "); builder.Append(table.DBTableName); DoWithWhere(obj, builder, queryParams, true); }
internal void Resolve(TableInfo parentTable, string parentName, int ordinal) { this.Table = parentTable; this.OrdinalInTable = ordinal; this.NameTag = parentTable.NameToken + "/" + ordinal; }
public override IDataReader LoadObjectTable(SoodaObject obj, object keyVal, int tableNumber, out TableInfo[] loadedTables) { ClassInfo classInfo = obj.GetClassInfo(); IDbCommand cmd = Connection.CreateCommand(); try { cmd.CommandTimeout = CommandTimeout; } catch(NotSupportedException e) { logger.Debug("CommandTimeout not supported. {0}", e.Message); } if (Transaction != null) cmd.Transaction = this.Transaction; SqlBuilder.BuildCommandWithParameters(cmd, false, GetLoadingSelectStatement(classInfo, classInfo.UnifiedTables[tableNumber], out loadedTables), SoodaTuple.GetValuesArray(keyVal), false); IDataReader reader = TimedExecuteReader(cmd); if (reader.Read()) return reader; else { reader.Dispose(); return null; } }
public virtual string GetAlterTableStatement(Sooda.Schema.TableInfo tableInfo) { return(String.Format("alter table {0} add primary key", tableInfo.DBTableName)); }
public override IDataReader LoadObject(SoodaObject obj, object keyVal, out TableInfo[] loadedTables) { return LoadObjectTable(obj, keyVal, 0, out loadedTables); }
public override IDataReader LoadObjectList(SchemaInfo schemaInfo, ClassInfo classInfo, SoodaWhereClause whereClause, SoodaOrderBy orderBy, int startIdx, int pageCount, SoodaSnapshotOptions options, out TableInfo[] tables) { try { Queue<_QueueItem> queue = new Queue<_QueueItem>(); List<TableInfo> tablesArrayList = new List<TableInfo>(classInfo.UnifiedTables.Count); SoqlQueryExpression queryExpression = new SoqlQueryExpression(); queryExpression.StartIdx = startIdx; queryExpression.PageCount = pageCount; queryExpression.From.Add(classInfo.Name); queryExpression.FromAliases.Add(""); foreach (TableInfo ti in classInfo.UnifiedTables) { tablesArrayList.Add(ti); foreach (FieldInfo fi in ti.Fields) { SoqlPathExpression pathExpr = new SoqlPathExpression(fi.Name); queryExpression.SelectExpressions.Add(pathExpr); queryExpression.SelectAliases.Add(""); if (fi.ReferencedClass != null && fi.PrefetchLevel > 0 && ((options & SoodaSnapshotOptions.PrefetchRelated) != 0)) { _QueueItem item = new _QueueItem(); item.classInfo = fi.ReferencedClass; item.level = fi.PrefetchLevel; item.prefix = pathExpr; queue.Enqueue(item); } } } while (queue.Count > 0) { _QueueItem it = queue.Dequeue(); foreach (TableInfo ti in it.classInfo.UnifiedTables) { tablesArrayList.Add(ti); foreach (FieldInfo fi in ti.Fields) { // TODO - this relies on the fact that path expressions // are never reconstructed or broken. We simply share previous prefix // perhaps it's cleaner to Clone() the expression here SoqlPathExpression extendedExpression = new SoqlPathExpression(it.prefix, fi.Name); queryExpression.SelectExpressions.Add(extendedExpression); queryExpression.SelectAliases.Add(""); if (it.level >= 1 && fi.PrefetchLevel > 0 && fi.ReferencedClass != null) { _QueueItem newItem = new _QueueItem(); newItem.classInfo = fi.ReferencedClass; newItem.prefix = extendedExpression; newItem.level = it.level - 1; queue.Enqueue(newItem); } } } } if (whereClause != null && whereClause.WhereExpression != null) { queryExpression.WhereClause = whereClause.WhereExpression; } if (orderBy != null) { queryExpression.SetOrderBy(orderBy); } string query = SoqlToSql(queryExpression, schemaInfo, false); IDbCommand cmd = Connection.CreateCommand(); try { cmd.CommandTimeout = CommandTimeout; } catch (NotSupportedException e) { logger.Debug("CommandTimeout not supported. {0}", e.Message); } if (Transaction != null) cmd.Transaction = this.Transaction; SqlBuilder.BuildCommandWithParameters(cmd, false, query, whereClause.Parameters, false); tables = tablesArrayList.ToArray(); return TimedExecuteReader(cmd); } catch (Exception ex) { logger.Error("Exception in LoadObjectList: {0}", ex); throw; } }
public override IDataReader LoadRefObjectList(SchemaInfo schema, RelationInfo relationInfo, int masterColumn, object masterValue, out TableInfo[] tables) { try { if (masterColumn == 0) tables = relationInfo.GetRef1ClassInfo().UnifiedTables[0].ArraySingleton; else tables = relationInfo.GetRef2ClassInfo().UnifiedTables[0].ArraySingleton; string query = GetLoadRefObjectSelectStatement(relationInfo, masterColumn); IDbCommand cmd = Connection.CreateCommand(); try { cmd.CommandTimeout = CommandTimeout; } catch (NotSupportedException e) { logger.Debug("CommandTimeout not supported. {0}", e.Message); } if (Transaction != null) cmd.Transaction = this.Transaction; SqlBuilder.BuildCommandWithParameters(cmd, false, query, new object[] { masterValue }, false); return TimedExecuteReader(cmd); } catch (Exception ex) { logger.Error("Exception in LoadRefObjectList: {0}", ex); throw; } }
internal void Merge(TableInfo merge) { Hashtable mergeNames = new Hashtable(); foreach (FieldInfo fi in this.Fields) mergeNames.Add(fi.Name, fi); foreach (FieldInfo mfi in merge.Fields) if (!mergeNames.ContainsKey(mfi.Name)) this.AddField(mfi); else ((FieldInfo)mergeNames[mfi.Name]).Merge(mfi); }
void DoInsertsForTable(SoodaObject obj, TableInfo table, bool isPrecommit) { if (table.IsDynamic && obj.GetFieldValue(table.Fields[table.Fields.Count - 1].ClassUnifiedOrdinal) == null) { // optimization: don't insert null dynamic fields return; } StringBuilder builder = new StringBuilder(500); builder.Append("insert into "); builder.Append(table.DBTableName); builder.Append('('); ArrayList par = new ArrayList(); bool comma = false; foreach (FieldInfo fi in table.Fields) { if (fi.ReadOnly) continue; if (comma) builder.Append(','); comma = true; builder.Append(fi.DBColumnName); } builder.Append(") values ("); comma = false; foreach (FieldInfo fi in table.Fields) { if (fi.ReadOnly) continue; if (comma) builder.Append(','); comma = true; object val = GetFieldValue(obj, fi, isPrecommit); builder.Append('{'); builder.Append(par.Add(val)); builder.Append(':'); builder.Append(fi.DataType); builder.Append('}'); } builder.Append(')'); SqlBuilder.BuildCommandWithParameters(_updateCommand, true, builder.ToString(), par.ToArray(), false); FlushUpdateCommand(false); }
static SoodaObject GetRefFromRecordHelper(SoodaTransaction tran, ISoodaObjectFactory factory, IDataRecord record, int firstColumnIndex, TableInfo[] loadedTables, int tableIndex, bool loadData) { object keyValue; Sooda.Schema.FieldInfo[] pkFields = factory.GetClassInfo().GetPrimaryKeyFields(); if (pkFields.Length == 1) { int pkFieldOrdinal = loadData ? firstColumnIndex + pkFields[0].OrdinalInTable : 0; try { keyValue = factory.GetPrimaryKeyFieldHandler().RawRead(record, pkFieldOrdinal); } catch (Exception ex) { logger.Error("Error while reading field {0}.{1}: {2}", factory.GetClassInfo().Name, pkFieldOrdinal, ex); throw ex; } } else { object[] pkParts = new object[pkFields.Length]; for (int currentPkPart = 0; currentPkPart < pkFields.Length; currentPkPart++) { int pkFieldOrdinal = loadData ? firstColumnIndex + pkFields[currentPkPart].OrdinalInTable : currentPkPart; SoodaFieldHandler handler = factory.GetFieldHandler(pkFieldOrdinal); pkParts[currentPkPart] = handler.RawRead(record, pkFieldOrdinal); } keyValue = new SoodaTuple(pkParts); //logger.Debug("Tuple: {0}", keyValue); } SoodaObject retVal = factory.TryGet(tran, keyValue); if (retVal != null) { if (loadData && !retVal.IsDataLoaded(0)) retVal.LoadDataFromRecord(record, firstColumnIndex, loadedTables, tableIndex); return retVal; } factory = GetFactoryFromRecord(tran, factory, record, firstColumnIndex, keyValue, loadData); retVal = factory.GetRawObject(tran); tran.Statistics.RegisterObjectUpdate(); SoodaStatistics.Global.RegisterObjectUpdate(); retVal.InsertMode = false; retVal.SetPrimaryKeyValue(keyValue); if (loadData) retVal.LoadDataFromRecord(record, firstColumnIndex, loadedTables, tableIndex); return retVal; }
void DoUpdatesForTable(SoodaObject obj, TableInfo table, bool isPrecommit) { if (table.IsDynamic) { // For dynamic fields do DELETE+INSERT instead of UPDATE. // This is because if a dynamic field is added to an existing object, there is no dynamic field row to update. // Another reason is that we never store null dynamic fields in the database - an INSERT will be ommitted in this case. DoDeletesForTable(obj, table); DoInsertsForTable(obj, table, true); return; } StringBuilder builder = new StringBuilder(500); builder.Append("update "); builder.Append(table.DBTableName); builder.Append(" set "); ArrayList par = new ArrayList(); bool anyChange = false; foreach (FieldInfo fi in table.Fields) { if (obj.IsFieldDirty(fi.ClassUnifiedOrdinal)) { if (anyChange) builder.Append(", "); FieldEquals(fi, GetFieldValue(obj, fi, isPrecommit), builder, par); anyChange = true; } } if (!anyChange) return; DoWithWhere(obj, builder, par, false); }
private int LoadDataFromRecord(System.Data.IDataRecord reader, int firstColumnIndex, TableInfo[] tables, int tableIndex) { int recordPos = firstColumnIndex; bool first = true; EnsureFieldsInited(true); int i; int oldDataLoadedMask = _dataLoadedMask; for (i = tableIndex; i < tables.Length; ++i) { TableInfo table = tables[i]; // logger.Debug("Loading data from table {0}. Number of fields: {1} Record pos: {2} Table index {3}.", table.NameToken, table.Fields.Count, recordPos, tableIndex); if (table.OrdinalInClass == 0 && !first) { // logger.Trace("Found table 0 of another object. Exiting."); break; } foreach (Sooda.Schema.FieldInfo field in table.Fields) { // don't load primary keys if (!field.IsPrimaryKey) { try { int ordinal = field.ClassUnifiedOrdinal; if (!IsFieldDirty(ordinal)) { object value = reader.IsDBNull(recordPos) ? null : GetFieldHandler(ordinal).RawRead(reader, recordPos); _fieldValues.SetFieldValue(ordinal, value); } } catch (Exception ex) { logger.Error("Error while reading field {0}.{1}: {2}", table.NameToken, field.Name, ex); throw; } } recordPos++; } SetDataLoaded(table.OrdinalInClass); first = false; } if (!IsObjectDirty() && (!FromCache || _dataLoadedMask != oldDataLoadedMask) && GetTransaction().CachingPolicy.ShouldCacheObject(this)) { TimeSpan expirationTimeout; bool slidingExpiration; if (GetTransaction().CachingPolicy.GetExpirationTimeout(this, out expirationTimeout, out slidingExpiration)) { GetTransaction().Cache.Add(GetClassInfo().GetRootClass().Name, GetPrimaryKeyValue(), GetCacheEntry(), expirationTimeout, slidingExpiration); FromCache = true; } } // if we've started with a first table and there are more to be processed if (tableIndex == 0 && i != tables.Length) { // logger.Trace("Materializing extra objects..."); for (; i < tables.Length; ++i) { TableInfo table = tables[i]; if (table.OrdinalInClass == 0) { GetTransaction().Statistics.RegisterExtraMaterialization(); SoodaStatistics.Global.RegisterExtraMaterialization(); // logger.Trace("Materializing {0} at {1}", tables[i].NameToken, recordPos); int pkOrdinal = table.OwnerClass.GetFirstPrimaryKeyField().OrdinalInTable; if (reader.IsDBNull(recordPos + pkOrdinal)) { // logger.Trace("Object is null. Skipping."); } else { ISoodaObjectFactory factory = GetTransaction().GetFactory(table.OwnerClass); SoodaObject.GetRefFromRecordHelper(GetTransaction(), factory, reader, recordPos, tables, i); } } else { // TODO - can this be safely called? } recordPos += table.Fields.Count; } // logger.Trace("Finished materializing extra objects."); } return tables.Length; }
public TableLoadingCache(string selectStatement, TableInfo[] loadedTables) { SelectStatement = selectStatement; LoadedTables = loadedTables; }
public override string GetAlterTableStatement(Sooda.Schema.TableInfo tableInfo) { string ident = GetTruncatedIdentifier("PK_" + tableInfo.DBTableName); return(String.Format("alter table {0} add constraint {1} primary key", tableInfo.DBTableName, ident)); }
void AddJoin(string fromTableAlias, TableInfo rightTable, string leftPrefix, string rightPrefix, FieldInfo leftField, FieldInfo rightField, bool innerJoin) { if (innerJoin && SoodaConfig.GetString("sooda.innerjoins", "false") != "true") innerJoin = false; string s; if (_builder.OuterJoinSyntax == SqlOuterJoinSyntax.Oracle) { WhereJoins.Add(String.Format("({0}.{2} = {1}.{3}{4})", leftPrefix, rightPrefix, leftField.DBColumnName, rightField.DBColumnName, innerJoin ? "" : " (+)")); s = String.Format(", {0} {1}", _builder.QuoteIdentifier(rightTable.DBTableName), rightPrefix); } else { s = String.Format("{6} join {0} {2} {5} on ({1}.{3} = {2}.{4})", rightTable.DBTableName, leftPrefix, rightPrefix, leftField.DBColumnName, rightField.DBColumnName, this.GetTableUsageHint(rightTable), innerJoin ? "inner" : "left outer"); } int foundPos = ActualFromAliases.IndexOf(fromTableAlias); if (foundPos == -1) throw new NotSupportedException(); StringCollection coll = FromJoins[foundPos]; coll.Add(s); }