public void StringConversions(string stringFormat, SpannerDbType spannerType, bool shouldEqual = true)
        {
            Assert.True(SpannerDbType.TryParse(stringFormat, out SpannerDbType result));
            if (shouldEqual)
            {
                Assert.Equal(spannerType, result);
            }
            else
            {
                Assert.NotEqual(spannerType, result);
            }

            //roundtrip test.
            Assert.True(SpannerDbType.TryParse(result.ToString(), out SpannerDbType result2));
            Assert.Equal(result, result2);
        }
Beispiel #2
0
 /// <inheritdoc />
 protected override RelationalTypeMapping CreateMappingFromStoreType(string storeType)
 {
     if (SpannerDbType.TryParse(storeType, out SpannerDbType parsedType))
     {
         if (!parsedType.Size.HasValue &&
             s_dbTypeMappings.TryGetValue(parsedType, out RelationalTypeMapping mapping))
         {
             return(mapping);
         }
         if (parsedType.DbType == DbType.String)
         {
             // return a sized string.
             return(new StringTypeMapping(storeType, parsedType.DbType, true, parsedType.Size));
         }
         return(new SpannerComplexTypeMapping(parsedType));
     }
     return(null);
 }
        public static void ExecuteScript(string databaseName, string scriptPath)
        {
            if (File.Exists(@"..\..\" + scriptPath))
            {
                //executing in VS - so path is relative to bin\<config> dir
                scriptPath = @"..\..\" + scriptPath;
            }
            else
            {
                scriptPath = Path.Combine(BaseDirectory, scriptPath);
            }

            var script = File.ReadAllText(scriptPath);

            using (var connection = new SpannerConnection(CreateConnectionString(databaseName)))
            {
                Execute(connection, command =>
                {
                    var statements = Regex.Split(script, @";[\r?\n]\s+", RegexOptions.Multiline);

                    foreach (var statement in statements)
                    {
                        s_gStatements++;
                        if (string.IsNullOrWhiteSpace(statement) ||
                            statement.StartsWith("SET ", StringComparison.Ordinal))
                        {
                            continue;
                        }

                        var tokens = statement.Split(' ', '(', ')', ',', ';').Where(
                            x => !string.IsNullOrEmpty(x?.Trim())).ToList();
                        if (tokens.Count == 0)
                        {
                            continue;
                        }

                        if (tokens[0] == "CREATE")
                        {
                            if (tokens[1] == "TABLE")
                            {
                                var tableName  = tokens[2];
                                var columnData = new List <Tuple <string, SpannerDbType> >();
                                var i          = 3;
                                while (tokens[i] != "PRIMARY")
                                {
                                    SpannerDbType type;
                                    if (!SpannerDbType.TryParse(tokens[i + 1], out type))
                                    {
                                        throw new InvalidOperationException($"Unable to parse {tokens[i + 1]}");
                                    }
                                    columnData.Add(new Tuple <string, SpannerDbType>(tokens[i], type));
                                    i += 2;
                                    if (tokens[i] == "MAX" || tokens[i][0] >= '0' && tokens[i][0] <= '9')
                                    {
                                        i++;
                                    }
                                    if (tokens[i] == "NOT")
                                    {
                                        i += 2;
                                    }
                                }
                                s_columnMap[tableName] = columnData;
                            }
                            command.CommandText = statement;
                        }
                        else if (tokens[0] == "INSERT")
                        {
//                            if (s_gStatements >= s_skipToLine)
//                            {
//                                Console.WriteLine("break here");
//                            }

                            // we do some simple parsing of a DML insert to a write command.
                            if (tokens.Count < 5 || tokens[0] != "INSERT" || tokens[1] != "INTO")
                            {
                                continue;
                            }

                            var m = Regex.Match(statement,
                                                @"INSERT INTO ([^\r\n\t\f\v(]+)\s?(\(.*\))?.*VALUES.(\(.*\))", RegexOptions.Singleline);
                            var targetTable = m.Groups[1].Value.Trim();
                            var columnGroup = m.Groups[2].Value;
                            var valueGroup  = m.Groups[3].Value;

                            //get columns to set.
                            IEnumerable <Tuple <string, SpannerDbType> > targetColumns;
                            if (string.IsNullOrEmpty(columnGroup))
                            {
                                //use the lookup table.
                                targetColumns = s_columnMap[targetTable];
                            }
                            else
                            {
                                var trimmedCols = columnGroup.Remove(columnGroup.Length - 1, 1).Remove(0, 1);
                                targetColumns   = trimmedCols.Split(',')
                                                  .Select(x => s_columnMap[targetTable].First(y => y.Item1 == x.Trim()));
                            }

                            //value parsing is a bit complicated and we do a simpler (hackish) heuristic which
                            //isnt completely valid for all cases, but works for our inputs.
                            valueGroup       = valueGroup.Remove(valueGroup.Length - 1, 1).Remove(0, 1);
                            var valueTokens  = valueGroup.Split(',').ToList();
                            var values       = new List <string>();
                            StringBuilder sb = null;
                            for (var i = 0; i < valueTokens.Count; i++)
                            {
                                var valueToken = valueTokens[i].Replace("''", "'");
                                if (sb != null)
                                {
                                    sb.Append(',');
                                    sb.Append(valueToken);
                                    if (sb[sb.Length - 1] == '\'')
                                    {
                                        values.Add(sb.ToString().Substring(0, sb.Length - 1));
                                        sb = null;
                                    }
                                    continue;
                                }
                                valueToken = valueToken.TrimStart();
                                if (valueToken.StartsWith("TO_DATE"))
                                {
                                    var dateQuoteInd = valueToken.IndexOf('\'');
                                    var endDateQuote = valueToken.IndexOf('\'', dateQuoteInd + 1);

                                    values.Add(valueToken.Substring(dateQuoteInd + 1, endDateQuote - dateQuoteInd - 1));
                                    i++;
                                }
                                else if (valueToken.StartsWith("'") || valueToken.StartsWith("N'"))
                                {
                                    valueToken = valueToken.StartsWith("'")
                                        ? valueToken.Substring(1, valueToken.Length - 1)
                                        : valueToken.Substring(2, valueToken.Length - 2);
                                    if (valueToken.EndsWith("'"))
                                    {
                                        values.Add(valueToken.Substring(0, valueToken.Length - 1));
                                    }
                                    else
                                    {
                                        sb = new StringBuilder(valueToken);
                                    }
                                }
                                else
                                {
                                    values.Add(string.Equals(valueToken, "NULL",
                                                             StringComparison.InvariantCultureIgnoreCase)
                                        ? null
                                        : valueToken);
                                }
                            }

                            command.CommandText = $"INSERT {targetTable}";
                            command.Parameters.Clear();
                            command.Parameters.AddRange(targetColumns.Select(x =>
                                                                             new SpannerParameter(x.Item1, x.Item2)).ToArray());

                            if (values.Count != command.Parameters.Count)
                            {
                                throw new InvalidOperationException("error parsing input northwind.sql");
                            }
                            for (var j = 0; j < command.Parameters.Count; j++)
                            {
                                if (Equals(((SpannerParameter)command.Parameters[j]).SpannerDbType, SpannerDbType.Bool) &&
                                    (values[j].Contains("0") || values[j].Contains("1")))
                                {
                                    command.Parameters[j].Value = Convert.ToInt32(values[j]);
                                }
                                else
                                {
                                    command.Parameters[j].Value = values[j];
                                }
                            }
                        }
                        if (s_gStatements < SkipToLine)
                        {
                            continue;
                        }
                        command.ExecuteNonQuery();
                    }

                    return(0);
                }, "");
            }
        }
 [InlineData("STRUCT<:INT64>")]              // No name (but a colon)
 public void TryParse_Invalid(string text)
 {
     Assert.False(SpannerDbType.TryParse(text, out var result));
     Assert.Null(result);
 }