spanner/api/Spanner.Samples/IdentifierCaseSensitivityAsyncPostgres.cs (72 lines of code) (raw):
// Copyright 2022 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [START spanner_postgresql_identifier_case_sensitivity]
using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Cloud.Spanner.Data;
using System;
using System.Threading.Tasks;
public class IdentifierCaseSensitivityAsyncPostgresSample
{
public async Task<int> IdentifierCaseSensitivityAsyncPostgres(string projectId, string instanceId, string databaseId)
{
DatabaseAdminClient databaseAdminClient = await DatabaseAdminClient.CreateAsync();
// See https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
// for more information.
string ddlStatement = "CREATE TABLE Concerts ( " +
// ConcertId will be folded to `concertid`.
"ConcertId bigint NOT NULL PRIMARY KEY, " +
// Location and Time are double-quoted and will therefore retain their
// mixed case and are case-sensitive. This means that any statement that
// references any of these columns must use double quotes.
"\"Location\" varchar(1024) NOT NULL, " +
"\"Time\" timestamptz NOT NULL)";
var updateDatabaseDDLRequest = new UpdateDatabaseDdlRequest
{
DatabaseAsDatabaseName = DatabaseName.FromProjectInstanceDatabase(projectId, instanceId, databaseId),
Statements = { ddlStatement }
};
// Update database schema by adding new table.
var updateOperation = await databaseAdminClient.UpdateDatabaseDdlAsync(updateDatabaseDDLRequest);
// Wait until the operation has finished.
Console.WriteLine("Waiting for the Concerts table to be created.");
var response = await updateOperation.PollUntilCompletedAsync();
if (response.IsFaulted)
{
Console.WriteLine($"Error while creating table: {response.Exception}");
throw response.Exception;
}
Console.WriteLine($"Created table with case sensitive names in database ${databaseId} using PostgreSQL dialect.");
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
using var connection = new SpannerConnection(connectionString);
await connection.OpenAsync();
// PostgreSQL case sensitivity with mutations.
// Mutations: Column names in mutations are always case-insensitive, regardless whether the
// columns were double-quoted or not during creation.
using var cmd = connection.CreateInsertCommand("Concerts", new SpannerParameterCollection
{
{ "ConcertId", SpannerDbType.Int64, 1 },
{ "Location", SpannerDbType.String, "Venue 1" },
{ "Time", SpannerDbType.Timestamp, DateTime.UtcNow }
});
await cmd.ExecuteNonQueryAsync();
// PostgreSQL case sensitivity with queries.
var selectCommand = connection.CreateSelectCommand("SELECT * FROM Concerts");
using var reader = await selectCommand.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
Console.WriteLine("ConcertId : " +
// ConcertId was not double quoted while table creation, so it is automatically folded to lower case.
// Accessing the column by its name in a result set must therefore use all lower-case letters.
reader.GetFieldValue<long>("concertid") +
// Location and Time were double - quoted during creation,
// and retain their mixed case when returned in a result set.
" Location : " +
reader.GetFieldValue<string>("Location") +
" Time : " +
reader.GetFieldValue<DateTime>("Time"));
}
// PostgreSQL case sensitivity with aliases.
// Aliases : They are also identifiers, and specifying an alias in double quotes will make the alias retain its case.
var selectAliasCommand = connection.CreateSelectCommand("SELECT concertid AS \"ConcertId\", \"Location\" AS \"venue\", \"Time\" FROM Concerts");
using var dataReader = await selectAliasCommand.ExecuteReaderAsync();
while (await dataReader.ReadAsync())
{
// The aliases are double-quoted and therefore retain their mixed case.
Console.WriteLine("ConcertId : " +
dataReader.GetFieldValue<long>("ConcertId") +
" Location : " +
dataReader.GetFieldValue<string>("venue") +
" Time : " +
dataReader.GetFieldValue<DateTime>("Time"));
}
// PostgreSQL case sensitivity with DML statements.
// DML statements must also follow the PostgreSQL case rules.
var dmlCommand = connection.CreateDmlCommand("INSERT INTO Concerts (ConcertId, \"Location\", \"Time\") VALUES($1, $2, $3)",
new SpannerParameterCollection
{
{ "p1", SpannerDbType.Int64, 2 },
{ "p2", SpannerDbType.String, "Venue 2" },
{ "p3", SpannerDbType.Timestamp, DateTime.UtcNow }
});
var count = await dmlCommand.ExecuteNonQueryAsync();
return count;
}
}
// [END spanner_postgresql_identifier_case_sensitivity]