这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

C#

使用适用于 ADO.NET 的 Vertica 驱动程序,采用 C# 编写的应用程序可以从 Vertica 数据库读取数据以及更新其中的数据和将数据加载到其中。此驱动程序提供了一个数据适配器(Vertica 数据适配器),该数据适配器有助于从数据库将数据读取到数据集中,还有助于将数据集中已更改的数据写回数据库。此驱动程序还提供用于读取数据的数据读取器 (VerticaDataReader)。此驱动程序需要 .NET Framework 版本 3.5 以上。

有关 ADO.NET 的详细信息,请参阅:

先决条件

创建 C# 客户端应用程序之前,必须安装 ADO.NET 客户端驱动程序

1 - ADO.NET 数据类型

下表详细介绍了 Vertica 数据类型与 .NET 数据类型和 ADO.NET 数据类型之间的映射。

UUID 向后兼容性

Vertica 9.0.0 版引入了 UUID 数据类型,包括对 UUID 的 JDBC 支持。Vertica ADO.NET、ODBC 和 OLE DB 客户端在 9.0.1 版中添加了对 UUID 的完全支持。Vertica 保持与不支持 UUID 数据类型的旧 受支持 客户端驱动程序版本的向后兼容性,如下所示:

2 - 设置 ADO.NET 会话的区域设置

  • ADO.NET 应用程序使用 UTF-16 字符集编码,并负责将任何非 UTF-16 编码数据转换为 UTF-16。针对 ODBC 的相同警告在违反此编码时适用。

  • 向 Vertica 服务器传递数据时,ADO.NET 驱动程序会将 UTF-16 数据转换为 UTF-8,并且会将 Vertica 服务器发送的数据从 UTF-8 转换为 UTF-16。

  • ADO.NET 应用程序应通过执行 SET LOCALE TO 命令来设置正确的服务器会话区域设置,以便获取预期的排序规则和服务器上的字符串函数行为。

  • 如果在数据库级别没有默认会话区域设置,则 ADO.NET 应用程序需要通过执行 SET LOCALE TO 命令来设置正确的服务器会话区域设置,以便获取预期的排序规则和服务器上的字符串函数行为。请参阅 SET LOCALE 命令。

3 - 连接到数据库

3.1 - 使用 TLS:在 Windows 中安装证书

您可以选择使用 TLS 来保护 ADO.NET 应用程序和 Vertica 之间的通信。Vertica ADO.NET 驱动程序在查找 TLS 证书时使用默认的 Windows 密钥库。该密钥库与 Internet Explorer 使用的密钥库相同。

在客户端上使用 TLS 之前,您必须在服务器上实施 TLS。请参阅 TLS 协议,执行其中的步骤,然后返回到本主题以在 Windows 上安装 TLS 证书。

要对 ADO.NET 和 Vertica 的连接使用 TLS:

  • 将服务器证书和客户端证书导入到 Windows 密钥库。

  • 导入证书颁发机构 (Certifying Authority, CA) 的公用证书(如果证书要求执行此操作)。

将服务器证书和客户端证书导入到 Windows 密钥库:

  1. 将在服务器上启用 TLS 时生成的 server.crt 文件复制到 Windows 计算机。

  2. 双击该证书。

  3. 让 Windows 确定密钥类型,然后单击安装

导入 CA 的公用证书:

必须为证书建立信任链。您可能需要导入 CA 的公用证书(尤其是当该证书是自签名证书时)。

  1. 使用以上过程中的同一个证书,双击该证书。

  2. 选择将所有的证书都放入下列存储

  3. 单击浏览 (Browse),选择受信任的根证书颁发机构 (Trusted Root Certification Authorities),然后单击下一步 (Next)

  4. 单击安装 (Install)

在 ADO.NET 应用程序中启用 SSL

在连接字符串中,务必通过将 VerticaConnectionStringBuilder 中的 SSL 属性设置为 true 来启用 SSL,例如:

//configure connection properties    VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
    builder.Host = "192.168.17.10";
    builder.Database = "VMart";
    builder.User = "dbadmin";
    builder.SSL = true;
    //open the connection
    VerticaConnection _conn = new VerticaConnection(builder.ToString());
    _conn.Open();

3.2 - 打开和关闭数据库连接 (ADO.NET)

通过 ADO.NET 访问 Vertica 中的数据之前,您必须使用 VerticaConnection 类(此类是 System.Data.DbConnection 的实施)创建与数据库的连接。VerticaConnection 使用包含连接属性作为字符串的单个参数。您可以手动创建属性关键字的字符串以用作参数,或者也可以使用 VerticaConnectionStringBuilder 类构建连接字符串。

要下载 ADO.NET 驱动程序,请转到客户端驱动程序下载页面

本主题详细介绍以下内容:

  • 手动构建连接字符串和连接到 Vertica

  • 使用 VerticaConnectionStringBuilder 创建连接字符串和连接到 Vertica

  • 关闭连接

要手动创建连接字符串:

请参阅 ADO.NET 连接属性,了解在连接字符串中使用的可用属性列表。至少要指定主机、数据库和用户。

  1. 为每个属性提供一个值,并依次附加各个属性和值(用分号分隔)。将此字符串分配给变量。例如:

    String connectString = "DATABASE=VMart;HOST=v_vmart_node0001;USER=dbadmin";
    
  2. 构建指定了连接字符串的 Vertica 连接对象。

    VerticaConnection _conn = new VerticaConnection(connectString)
    
  3. 打开连接。

    _conn.Open();
    
  4. 创建命令对象,并将它与连接相关联。所有 VerticaCommand 对象都必须与连接相关联。

    VerticaCommand command = _conn.CreateCommand();
    

要使用 VerticaConnectionStringBuilder 类创建连接字符串并打开连接:

  1. 创建 VerticaConnectionStringBuilder 类的新对象。

    VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
    
  2. 使用属性值更新 VerticaConnectionStringBuilder 对象。请参阅 ADO.NET 连接属性,了解在连接字符串中使用的可用属性列表。至少要指定主机、数据库和用户。

    builder.Host = "v_vmart_node0001";
    builder.Database = "VMart";
    builder.User = "dbadmin";
    
  3. 构建将 VerticaConnectionStringBuilder 连接对象指定为字符串的 Vertica 连接对象。

    VerticaConnection _conn = new VerticaConnection(builder.ToString());
    
  4. 打开连接。

    _conn.Open();
    
  5. 创建命令对象,并将它与连接相关联。所有 VerticaCommand 对象都必须与连接相关联。

    VerticaCommand command = _conn.CreateCommand;
    

要关闭连接:

使用完数据库后,关闭连接。如未关闭连接,应用程序的性能和可扩展性会降低。还会导致其他客户端无法获取锁。

 _conn.Close();

示例用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
        //Perform some operations
            _conn.Close();
        }
    }
}

3.3 - ADO.NET 连接属性

要下载 ADO.NET 驱动程序,请转到客户端驱动程序下载页面

可以使用连接属性来配置 ADO.NET 客户端应用程序和 Vertica 数据库之间的连接。属性提供有关连接的基本信息,例如,连接到数据库所需的服务器名称和端口号。

您可以通过两种方法设置连接属性:

  • 包含属性名称和值以作为传递到 VerticaConnection 的连接字符串的一部分。

  • VerticaConnectionStringBuilder 对象中设置属性,然后将该对象作为字符串传递到 VerticaConnection

3.4 - ADO.NET 中的负载均衡

本机连接负载均衡

本机连接负载均衡有助于在 Vertica 数据库中的主机上分散客户端连接所带来的开销。服务器和客户端都必须启用本机连接负载均衡。如果两者者都启用了本机负载均衡,则当客户端最初连接到数据库中的主机时,此主机会从数据库中当前正在运行的主机列表中选择一个主机来处理客户端连接,并通知客户端它所选择的主机。

如果最初联系的主机没有选择自身来处理连接,则客户端会断开连接,然后打开指向第一个主机所选主机的另一个连接。指向此第二个主机的连接进程将照常进行—如果启用了 SSL,则会启动 SSL 协商,否则客户端会启动身份验证过程。有关详细信息,请参阅关于本机连接负载均衡

若要在客户端上启用本机连接负载均衡,请在连接字符串中将 ConnectionLoadBalance 连接参数设置为 true,或者使用 ConnectionStringBuilder() 进行此设置。以下示例说明了如何在本机连接负载均衡已启用的情况下多次连接到数据库,以及从 V_MONITOR.CURRENT_SESSION 系统表获取处理连接的节点的名称。

using System;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "v_vmart_node0001.example.com";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            // Enable native client load balancing in the client,
            // must also be enabled on the server!
            builder.ConnectionLoadBalance = true;

            // Connect 3 times to verify a new node is connected
            // for each connection.
            for (int i = 1; i <= 4; i++) {
                try {
                    VerticaConnection _conn = new VerticaConnection(builder.ToString());
                    _conn.Open();
                    if (i == 1) {
                        // On the first connection, check the server policy for load balance
                        VerticaCommand sqlcom = _conn.CreateCommand();
                        sqlcom.CommandText = "SELECT LOAD_BALANCE_POLICY FROM V_CATALOG.DATABASES";
                        var returnValue = sqlcom.ExecuteScalar();
                        Console.WriteLine("Status of load balancy policy
             on server: " + returnValue.ToString() + "\n");
                    }
                    VerticaCommand command = _conn.CreateCommand();
                    command.CommandText = "SELECT node_name FROM V_MONITOR.CURRENT_SESSION";
                    VerticaDataReader dr = command.ExecuteReader();
                    while (dr.Read()) {
                        Console.Write("Connect attempt #" + i + "... ");
                        Console.WriteLine("Connected to node " + dr[0]);
                    }
                    dr.Close();
                    _conn.Close();
                    Console.WriteLine("Disconnecting.\n");
                }
                catch(Exception e) {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
}

运行上述示例得到了以下输出:

Status of load balancing policy on server: roundrobin

Connect attempt #1... Connected to node v_vmart_node0001
Disconnecting.

Connect attempt #2... Connected to node v_vmart_node0002
Disconnecting.

Connect attempt #3... Connected to node v_vmart_node0003
Disconnecting.

Connect attempt #4... Connected to node v_vmart_node0001
Disconnecting.

基于主机名的负载均衡

您还可以通过将单个主机名解析为多个 IP 地址来平衡工作负载。ADO.NET 客户端驱动程序通过自动将主机名随机解析为指定的 IP 地址之一来实现负载均衡。

例如,假设主机名 verticahost.example.comC:\Windows\System32\drivers\etc\hosts 中有以下条目:

192.0.2.0 verticahost.example.com
192.0.2.1 verticahost.example.com
192.0.2.2 verticahost.example.com

指定主机名 verticahost.example.com 会随机解析为列出的 IP 地址之一。

3.5 - ADO.NET 连接故障转移

如果客户端应用程序尝试连接到 Vertica 群集中处于关闭状态的主机,则使用默认连接配置时连接尝试将会失败。此故障通常会向用户返回一个错误。用户必须等待主机恢复并重试连接,或者手动编辑连接设置以选择其他主机。

由于 Vertica 分析型数据库采用分布式架构,通常您不会关注哪个数据库主机处理客户端应用程序的连接。可以使用客户端驱动程序的连接故障转移功能来防止用户在无法访问连接设置中所指定主机的情况下收到连接错误。JDBC 驱动程序可通过几种方式让客户端驱动程序在无法访问连接参数中所指定的主机时自动尝试连接到其他主机:

  • 将 DNS 服务器配置为返回一个主机名的多个 IP 地址。在连接设置中使用此主机名时,客户端会尝试连接到 DNS 找到的第一个 IP 地址。如果位于该 IP 地址的主机无法访问,则客户端会尝试连接到第二个 IP,依此类推,直到其成功地连接到某个主机或试过所有 IP 地址为止。

  • 提供当您在连接参数中指定的主要主机无法访问时客户端驱动程序尝试连接的备份主机列表。

  • (仅限 JDBC)在尝试连接到下一个节点之前,使用特定于驱动程序的连接属性来管理超时。

在所有方法中,故障转移过程对于客户端应用程序是透明的(除了在选择使用列表故障转移方法时需指定备份主机列表之外)。如果主要主机无法访问,客户端驱动程序会自动尝试连接到其他主机。

故障转移仅适用于初次建立客户端连接的情况。如果连接断开,驱动程序不会自动尝试重新连接到数据库中的其他主机。

通常可选择上述两种故障转移方法中的一种。但它们可以一起使用。如果您的 DNS 服务器返回多个 IP 地址,并且您提供了备份主机列表,则客户端会首先尝试连接 DNS 服务器返回的所有 IP,然后再尝试连接备份列表中的主机。

DNS 故障转移方法可集中处理配置客户端故障转移。在向 Vertica 分析型数据库群集添加新节点时,可以选择通过编辑 DNS 服务器设置来将这些节点添加到故障转移列表中。所有使用 DNS 服务器连接到 Vertica 分析型数据库的客户端系统都会自动采用连接故障转移,而无需更改任何设置。但此方法需要对所有客户端用于连接到 Vertica 分析型数据库群集的 DNS 服务器具有管理访问权限。这在贵组织中可能无法实现。

使用备份服务器列表要比编辑 DNS 服务器设置更加容易。但此方法不能集中处理故障转移功能。如果更改了 Vertica 分析型数据库群集,您可能需要在每个客户端系统上更新应用程序设置。

使用 DNS 故障转移

若要使用 DNS 故障转移,您需要更改 DNS 服务器的设置,将单一主机名映射为 Vertica 分析型数据库群集中主机的多个 IP 地址。然后让所有客户端应用程序都使用该主机名连接到 Vertica 分析型数据库。

您可以选择让 DNS 服务器为主机名返回任何所需数量的 IP 地址。在小型群集中,您可以选择让其返回群集中所有主机的 IP 地址。但对于大型群集,应考虑选择返回一部分主机。否则可能会导致长时间延迟,因为客户端驱动程序尝试连接到数据库中处于关闭状态的每个主机会失败。

使用备份主机列表

若要启用基于备份列表的连接故障转移,需要在客户端应用程序的 BackupServerNode 参数中指定主机的至少一个 IP 地址或主机名。可以视情况在主机名或 IP 后面使用冒号和端口号。如果未提供端口号,驱动程序会默认使用标准 Vertica 端口号 (5433)。若要列出多个主机,请用逗号分隔这些主机。

以下示例演示了如何通过设置 BackupServerNode 连接参数来指定可尝试连接的其他主机。由于有意在连接字符串中使用了一个不存在的节点,因此初始连接失败。客户端驱动程序必须尝试通过备份主机来与 Vertica 建立连接。

using System;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder =
        new VerticaConnectionStringBuilder();
            builder.Host = "not.a.real.host:5433";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            builder.BackupServerNode =
        "another.broken.node:5433,v_vmart_node0002.example.com:5433";
            try
            {
                VerticaConnection _conn =
            new VerticaConnection(builder.ToString());
                _conn.Open();
                VerticaCommand sqlcom = _conn.CreateCommand();
                sqlcom.CommandText = "SELECT node_name FROM current_session";
                var returnValue = sqlcom.ExecuteScalar();
                Console.WriteLine("Connected to node: " +
            returnValue.ToString() + "\n");
                _conn.Close();
                Console.WriteLine("Disconnecting.\n");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}

注意

  • 启用本机连接负载均衡时,在 BackupServerNode 连接参数中指定的其他服务器将只用于指向 Vertica 主机的初始连接。如果主机将客户端重定向至数据库群集中的其他主机来处理其连接请求,则第二个连接将不使用备份节点列表。这很少出现问题,因为本机连接负载均衡知道数据库中的哪个节点目前正处于运行状态。 请参阅ADO.NET 中的负载均衡

  • 从 BackupServerNode 列表中获取的与主机的连接未池化以用于 ADO.NET 连接。

4 - 使用 ADO.NET 查询数据库

本节介绍如何创建查询以执行下列操作:

4.1 - 插入数据 (ADO.NET)

可以使用 VerticaCommand 类完成插入数据。VerticaCommand 是 DbCommand 的实施。使用它可以创建 SQL 语句以及向数据库发送该语句。使用 CommandText 方法将某个 SQL 语句分配给命令,然后通过调用 ExecuteNonQuery 方法来执行该 SQL 语句。ExecuteNonQuery 方法用于执行不返回结果集的语句。

要插入一行数据:

  1. 创建与数据库的连接

  2. 使用连接创建命令对象。

    VerticaCommand command = _conn.CreateCommand();
    
  3. 使用 INSERT 语句插入数据。以下是简单插入操作的示例。请注意,它不包含 COMMIT 语句,因为 Vertica ADO.NET 驱动程序在自动提交模式下工作。

    command.CommandText =
         "INSERT into test values(2, 'username', 'email', 'password')";
    
  4. 执行查询。rowsAdded 变量包含由 INSERT 语句添加的行数。

    Int32 rowsAdded = command.ExecuteNonQuery();
    

    ExecuteNonQuery() 方法将返回受 UPDATE、INSERT 和 DELETE 语句的命令影响的行数。此方法对所有其他类型的语句返回 -1。如果发生回退,则此方法也设置为 -1。

示例用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
        VerticaCommand command = _conn.CreateCommand();
        command.CommandText =
               "INSERT into test values(2, 'username', 'email', 'password')";
        Int32 rowsAdded = command.ExecuteNonQuery();
        Console.WriteLine( rowsAdded + " rows added!");
            _conn.Close();
        }
    }
}

4.1.1 - 使用参数

可以使用参数高效地重复执行相似 SQL 语句。

使用参数

VerticaParameter 是 ADO.NET 中的 System.Data.DbParameter 基本类的扩展,用于在发送到服务器的命令中设置参数。可以在 WHERE 子句中的值不是静态值的所有查询 (SELECT/INSERT/UPDATE/DELETE) 中使用参数;此方式适用于包含已知列集但其筛选器条件由应用程序或最终用户动态设置的所有查询。以这种方式使用参数可大大降低出现 SQL 注入问题的可能性;即使只是从多个变量创建 SQL 查询,也会出现这种问题。

您需要为参数分配有效的 DbType、VerticaDbType 或系统类型。有关 System、Vertica 和 DbTypes 的映射,请参阅数据类型ADO.NET 数据类型

若要创建参数占位符,请在实际查询字符串中的参数名称前面放置电子邮件符号 (@) 或冒号 (:) 字符。请勿在占位符指示符(@ 或 :)和占位符之间插入任何空格。

例如,以下典型查询使用字符串 'MA' 作为筛选器。

SELECT customer_name, customer_address, customer_city, customer_state
FROM customer_dimension WHERE customer_state = 'MA';

相反,可以编写查询以使用参数。在以下示例中,字符串 MA 替换为参数占位符 @STATE。

SELECT customer_name, customer_address, customer_city, customer_state
FROM customer_dimension WHERE customer_state = @STATE;

例如,前一个示例的 ADO.net 代码编写如下:

VerticaCommand command = _conn.CreateCommand();
command.CommandText = “SELECT customer_name, customer_address, customer_city, customer_state
    FROM customer_dimension WHERE customer_state = @STATE”;
command.Parameters.Add(new VerticaParameter( “STATE”, VerticaType.VarChar));
command.Parameters["STATE"].Value = "MA";

4.1.2 - 创建和回退事务

创建事务

Vertica 中的事务具有以下特性:原子、一致、隔离和持久。使用 Vertica ADO.NET 驱动程序连接到数据库时,连接处于自动提交模式,并且每个查询会在执行后提交。可以将多个语句收集到单个事务,然后使用单个事务同时提交这些语句。如果代码确定不应提交事务,您还可以选择在提交事务之前回退该事务。

这些事务使用 VerticaTransaction 对象,该对象是 DbTransaction 的实施。您必须将事务与 VerticaCommand 对象相关联。

以下代码使用显式事务将行逐个插入到 VMart 架构的表中。

要使用 ADO.NET 驱动程序在 Vertica 中创建事务:

  1. 创建与数据库的连接

  2. 使用连接创建命令对象。

    VerticaCommand command = _conn.CreateCommand();
    
  3. 启动显式事务,并将命令与该事务相关联。

    VerticaTransaction txn = _conn.BeginTransaction();
    command.Connection = _conn;
    command.Transaction = txn;
    
  4. 执行各个 SQL 语句以添加行。

    command.CommandText =
         "insert into product_dimension values( ... )";
    command.ExecuteNonQuery();
    command.CommandText =
         "insert into store_orders_fact values( ... )";
    
  5. 提交事务。

    txn.Commit();
    

回退事务

如果代码检查到错误,则您可以捕获错误并回退整个事务。

VerticaTransaction txn = _conn.BeginTransaction();
VerticaCommand command = new
        VerticaCommand("insert into product_dimension values( 838929, 5, 'New item 5' )", _conn);
// execute the insert
command.ExecuteNonQuery();
command.CommandText = "insert into product_dimension values( 838929, 6, 'New item 6' )";
// try insert and catch any errors
bool error = false;
try
{
    command.ExecuteNonQuery();
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
    error = true;
}
if (error)
{
    txn.Rollback();
    Console.WriteLine("Errors. Rolling Back.");
}
else
{
    txn.Commit();
    Console.WriteLine("Queries Successful. Committing.");
}

提交和回退示例

以下示例详细介绍了如何在事务期间提交或回退查询。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
            bool error = false;
                VerticaCommand command = _conn.CreateCommand();
                VerticaCommand command2 = _conn.CreateCommand();
                VerticaTransaction txn = _conn.BeginTransaction();
                command.Connection = _conn;
                command.Transaction = txn;
                command.CommandText =
                "insert into test values(1, 'test', 'test', 'test' )";
                Console.WriteLine(command.CommandText);
                try
                {
                    command.ExecuteNonQuery();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    error = true;
                }
                command.CommandText =
                "insert into test values(2, 'ear', 'eye', 'nose', 'extra' )";
                Console.WriteLine(command.CommandText);
                try
                {
                    command.ExecuteNonQuery();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    error = true;
                }
                if (error)
                {
                    txn.Rollback();
                    Console.WriteLine("Errors. Rolling Back.");
                }
                else
                {
                    txn.Commit();
                    Console.WriteLine("Queries Successful. Committing.");
                }
            _conn.Close();
        }
    }
}

该示例将在控制台上显示以下输出:

insert into test values(1, 'test', 'test', 'test' )
insert into test values(2, 'ear', 'eye', 'nose', 'extra' )
[42601]ERROR: INSERT has more expressions than target columns
Errors. Rolling Back.

另请参阅

4.1.2.1 - 设置事务隔离级别

可以按连接和事务设置事务隔离级别。有关 Vertica 中支持的事务隔离级别的概述,请参阅 事务。若要为连接设置默认事务隔离级别,请在 VerticaConnectionStringBuilder 字符串中使用 IsolationLevel 关键字(有关详细信息,请参阅连接字符串关键字)。若要为单个事务设置隔离级别,请将隔离级别传递到用于启动事务的 VerticaConnection.BeginTransaction() 方法调用。

要按连接设置隔离级别:

  1. 使用 VerticaConnectionStringBuilder 构建连接字符串。

  2. 为 IsolationLevel 生成器字符串提供一个值。此字符串可接受以下两个值之一:IsolationLevel.ReadCommited(默认)或 IsolationLevel.Serializeable。例如:

        VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
        builder.Host = "192.168.1.100";
        builder.Database = "VMart";
        builder.User = "dbadmin";
        builder.IsolationLevel = System.Data.IsolationLevel.Serializeable
        VerticaConnection _conn1 = new VerticaConnection(builder.ToString());
        _conn1.Open();
    

要按事务设置隔离级别:

  1. 在 BeginTransaction 方法上设置 IsolationLevel,例如

    VerticaTransaction txn = _conn.BeginTransaction(IsolationLevel.Serializable);
    

示例用法:

以下示例演示了下列操作:

  • 获取连接的事务隔离级别。

  • 使用连接属性设置连接的隔离级别。

  • 为新事务设置事务隔离级别。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn1 = new VerticaConnection(builder.ToString());
             _conn1.Open();
            VerticaTransaction txn1 = _conn1.BeginTransaction();
            Console.WriteLine("\n Transaction 1 Transaction Isolation Level: " +
             txn1.IsolationLevel.ToString());
            txn1.Rollback();
            VerticaTransaction txn2 = _conn1.BeginTransaction(IsolationLevel.Serializable);
            Console.WriteLine("\n Transaction 2 Transaction Isolation Level: " +
             txn2.IsolationLevel.ToString());
            txn2.Rollback();
            VerticaTransaction txn3 = _conn1.BeginTransaction(IsolationLevel.ReadCommitted);
            Console.WriteLine("\n Transaction 3 Transaction Isolation Level: " +
             txn3.IsolationLevel.ToString());
            _conn1.Close();
        }
    }
}

运行后,以上示例代码会将以下内容输出到系统控制台:

 Transaction 1 Transaction Isolation Level: ReadCommitted
 Transaction 2 Transaction Isolation Level: Serializable
 Transaction 3 Transaction Isolation Level: ReadCommitted

4.2 - 读取数据 (ADO.Net)

若要从数据库读取数据,请使用 VerticaDataReader(一种 DbDataReader 实施)。此实施可通过分析应用程序在服务器上运行,从而将大量数据快速移出服务器。

要使用 VerticaDataReader 从数据库读取数据:

  1. 创建与数据库的连接

  2. 使用连接创建命令对象。

        VerticaCommand command = _conn.CreateCommand();
    
  3. 创建查询。此查询与示例 VMart 数据库配合工作。

            command.CommandText =
            "SELECT fat_content, product_description " +
            "FROM (SELECT DISTINCT fat_content, product_description" +
            "      FROM product_dimension " +
            "      WHERE department_description " +        "      IN ('Dairy') " +
            "      ORDER BY fat_content) AS food " +
            "LIMIT 10;";
    
  4. 执行读取器以从查询返回结果。以下命令将调用 VerticaCommand 对象的 ExecuteReader 方法以获取 VerticaDataReader 对象。

    VerticaDataReader dr = command.ExecuteReader();
    
  5. 读取数据。数据读取器将在连续流中返回结果。因此,您必须逐行从表中读取数据。以下示例使用 while 循环来完成此操作。

     Console.WriteLine("\n\n Fat Content\t  Product Description");
         Console.WriteLine("------------\t  -------------------");
         int rows = 0;
         while (dr.Read())
         {
            Console.WriteLine("     " + dr[0] + "    \t  " + dr[1]);
            ++rows;
         }
         Console.WriteLine("------------\n  (" + rows + " rows)\n");
    
  6. 完成后,关闭数据读取器以释放资源。

        dr.Close();
    

示例用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
        VerticaCommand command = _conn.CreateCommand();
            command.CommandText =
                "SELECT fat_content, product_description " +
                "FROM (SELECT DISTINCT fat_content, product_description" +
                "      FROM product_dimension " +
                "      WHERE department_description " +
                "      IN ('Dairy') " +
                "      ORDER BY fat_content) AS food " +
                "LIMIT 10;";
          VerticaDataReader dr = command.ExecuteReader();

         Console.WriteLine("\n\n Fat Content\t  Product Description");
         Console.WriteLine("------------\t  -------------------");
         int rows = 0;
         while (dr.Read())
         {
                Console.WriteLine("     " + dr[0] + "    \t  " + dr[1]);
                ++rows;
         }
         Console.WriteLine("------------\n  (" + rows + " rows)\n");
              dr.Close();
            _conn.Close();
        }
    }
}

4.3 - 通过 ADO.Net 加载数据

此部分详细介绍可用于通过 ADO.NET 客户端驱动程序加载 Vertica 中的数据的各种方法:

4.3.1 - 使用 Vertica 数据适配器

Vertica 数据适配器 (VerticaDataAdapter) 可使客户端能够在数据集和 Vertica 数据库之间交换数据。该适配器是 DbDataAdapter 的实施。例如,您可以使用 VerticaDataAdapter 仅读取数据;或者也可以从数据库将数据读取到数据集中,然后将数据集中已更改的数据写回数据库。

批量更新

使用 Update() 方法更新数据集时,您可以选择在调用 Update() 之前使用 UpdateBatchSize() 方法,以便减少客户端在执行更新期间与服务器通信的次数。UpdateBatchSize 的默认值为 1。如果对数据集使用多个 rows.Add() 命令,则您可以将批大小更改为最佳大小以加快客户端完成更新所需执行的操作。

使用数据适配器从 Vertica 读取数据:

以下示例详细介绍如何对 VMart 架构执行 select 查询并将结果加载到 DataTable,然后将 DataTable 的内容输出到控制台。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();

            // Try/Catch any exceptions
                   try
            {
                using (_conn)
                {
                    // Create the command
                    VerticaCommand command = _conn.CreateCommand();
                    command.CommandText = "select product_key, product_description " +
                        "from product_dimension where product_key < 10";

                        // Associate the command with the connection
                        command.Connection = _conn;

                        // Create the DataAdapter
                        VerticaDataAdapter adapter = new VerticaDataAdapter();
                        adapter.SelectCommand = command;

                        // Fill the DataTable
                        DataTable table = new DataTable();
                        adapter.Fill(table);

                        //  Display each row and column value.
                        int i = 1;
                        foreach (DataRow row in table.Rows)
                        {
                            foreach (DataColumn column in table.Columns)
                            {
                                Console.Write(row[column] + "\t");
                            }
                            Console.WriteLine();
                            i++;
                        }
                    Console.WriteLine(i + " rows returned.");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            _conn.Close();
        }
    }
}

从 Vertica 将数据读取到数据集并更改数据:

以下示例显示了如何使用数据适配器从 VMart 架构的维度表读取数据以及将数据插入到其中。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Vertica.Data.VerticaClient
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();

                  // Try/Catch any exceptions
                    try
            {
                using (_conn)
                {

                            //Create a data adapter object using the connection
                            VerticaDataAdapter da = new VerticaDataAdapter();

                            //Create a select statement that retrieves data from the table
                            da.SelectCommand = new
                        VerticaCommand("select * from product_dimension where product_key < 10",
                        _conn);
                            //Set up the insert command for the data adapter, and bind variables for some of the columns
                            da.InsertCommand = new
                        VerticaCommand("insert into product_dimension values( :key, :version, :desc )",
                        _conn);
                    da.InsertCommand.Parameters.Add(new VerticaParameter("key", VerticaType.BigInt));
                    da.InsertCommand.Parameters.Add(new VerticaParameter("version", VerticaType.BigInt));
                    da.InsertCommand.Parameters.Add(new VerticaParameter("desc", VerticaType.VarChar));
                    da.InsertCommand.Parameters[0].SourceColumn = "product_key";
                    da.InsertCommand.Parameters[1].SourceColumn = "product_version";
                    da.InsertCommand.Parameters[2].SourceColumn = "product_description";
                    da.TableMappings.Add("product_key", "product_key");
                    da.TableMappings.Add("product_version", "product_version");
                    da.TableMappings.Add("product_description", "product_description");

                            //Create and fill a Data set for this dimension table, and get the resulting DataTable.
                            DataSet ds = new DataSet();
                    da.Fill(ds, 0, 0, "product_dimension");
                    DataTable dt = ds.Tables[0];

                            //Bind parameters and add two rows to the table.
                            DataRow dr = dt.NewRow();
                    dr["product_key"] = 838929;
                    dr["product_version"] = 5;
                    dr["product_description"] = "New item 5";
                    dt.Rows.Add(dr);
                    dr = dt.NewRow();
                    dr["product_key"] = 838929;
                    dr["product_version"] = 6;
                    dr["product_description"] = "New item 6";
                    dt.Rows.Add(dr);
                    //Extract the changes for the added rows.
                            DataSet ds2 = ds.GetChanges();

                            //Send the modifications to the server.
                            int updateCount = da.Update(ds2, "product_dimension");

                           //Merge the changes into the original Data set, and mark it up to date.
                            ds.Merge(ds2);
                    ds.AcceptChanges();
                    Console.WriteLine(updateCount + " updates made!");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            _conn.Close();
        }
    }
}

4.3.2 - 使用批量插入和预定义的语句

可以使用带有参数的预定义的语句批量加载数据。如果遇到任何错误,您还可以使用事务回退批量加载。

如果要加载大批量数据(超过 100 MB),请考虑使用直接批量插入。

以下示例详细介绍使用包含在数组中的数据以及参数和事务来批量加载数据。

可以通过以下命令创建在此示例中使用的 test 表:

=> CREATE TABLE test (id INT, username VARCHAR(24), email VARCHAR(64), password VARCHAR(8));

使用参数和事务的示例批量插入


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
            // Create arrays for column data
                    int[] ids = {1, 2, 3, 4};
            string[] usernames = {"user1", "user2", "user3", "user4"};
            string[] emails = { "user1@example.com", "user2@example.com","user3@example.com","user4@example.com" };
            string[] passwords = { "pass1", "pass2", "pass3", "pass4" };
            // create counters for accepted and rejected rows
                    int rows = 0;
            int rejRows = 0;
            bool error = false;
            // Create the transaction
                    VerticaTransaction txn = _conn.BeginTransaction();
            // Create the parameterized query and assign parameter types
                    VerticaCommand command = _conn.CreateCommand();
            command.CommandText = "insert into TEST values (@id, @username, @email, @password)";
            command.Parameters.Add(new VerticaParameter("id", VerticaType.BigInt));
            command.Parameters.Add(new VerticaParameter("username", VerticaType.VarChar));
            command.Parameters.Add(new VerticaParameter("email", VerticaType.VarChar));
            command.Parameters.Add(new VerticaParameter("password", VerticaType.VarChar));
            // Prepare the statement
                    command.Prepare();

                    // Loop through the column arrays and insert the data
                    for (int i = 0; i < ids.Length; i++)            {
                command.Parameters["id"].Value = ids[i];
                command.Parameters["username"].Value = usernames[i];
                command.Parameters["email"].Value = emails[i];
                command.Parameters["password"].Value = passwords[i];
                try
                {
                    rows += command.ExecuteNonQuery();
                }
                catch (Exception e)
                {
                    Console.WriteLine("\nInsert failed - \n  " + e.Message + "\n");
                    ++rejRows;
                    error = true;
                }
            }
            if (error)
            {
                // Roll back if errors
                        Console.WriteLine("Errors. Rolling Back Transaction.");
                Console.WriteLine(rejRows + " rows rejected.");
                txn.Rollback();
            }
            else
            {
                // Commit if no errors
                        Console.WriteLine("No Errors. Committing Transaction.");
                txn.Commit();
                Console.WriteLine("Inserted " + rows + " rows. ");
            }
            _conn.Close();
        }
    }
}

4.3.3 - 通过 ADO.NET 进行流式数据传输

以下两个选项可用于通过 ADO.NET 将客户端上的文件中的数据以流式传输到 Vertica 数据库:

  • 使用 VerticaCopyStream ADO.NET 类以面向对象的方式进行流式数据传输

  • 执行 COPY LOCAL SQL 语句以进行流式数据传输

此部分中的主题介绍了使用这些选项的方法。

4.3.3.1 - 通过 VerticaCopyStream 从客户端进行流式传输

使用 VerticaCopyStream 类可以将数据从客户端系统流式传输到 Vertica 数据库。通过此类,您可以直接使用 SQL COPY 语句,而不必通过将 STDIN 替换为一个或多个数据流先将数据复制到数据库群集中的主机。

注意:

  • 使用事务并对 copy 命令禁用自动提交可提高性能。

  • 可以通过将 copy 命令与“no commit”修饰符结合使用来禁用自动提交。您必须显式禁用提交。使用 VerticaCopyStream 时,启用事务不会禁用自动提交。

  • 与 VerticaCopyStream 结合使用的 copy 命令使用 copy 语法。

  • 每次调用 execute 时,都会将 VerticaCopyStream.rejects 置零。如果要捕获拒绝数,请将 VerticaCopyStream.rejects 的值分配给另一个变量,然后再次调用 execute。

  • 可以使用 AddStream() 调用添加多个流。

示例用法:

以下示例演示了使用 VerticaCopyStream 将文件流复制到 Vertica。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            // Configure connection properties
                    VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
                builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";
            //open the connection
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
            try
            {
                using (_conn)
                {
                    // Start a transaction
                            VerticaTransaction txn = _conn.BeginTransaction();

                            // Create a table for this example
                            VerticaCommand command = new VerticaCommand("DROP TABLE IF EXISTS copy_table", _conn);
                command.ExecuteNonQuery();
                    command.CommandText = "CREATE TABLE copy_table (Last_Name char(50), "
                                    + "First_Name char(50),Email char(50), "
                                    + "Phone_Number char(15))";
                    command.ExecuteNonQuery();
                    // Create a new filestream from the data file
                            string filename = "C:/customers.txt";
                 Console.WriteLine("\n\nLoading File: " + filename);
                    FileStream inputfile = File.OpenRead(filename);
                    // Define the copy command
                            string copy = "copy copy_table from stdin record terminator E'\n' delimiter '|'" + " enforcelength "
                        + " no commit";
                    // Create a new copy stream instance with the connection and copy statement
                            VerticaCopyStream vcs = new VerticaCopyStream(_conn, copy);

                            // Start the VerticaCopyStream process
                            vcs.Start();
                            // Add the file stream
                            vcs.AddStream(inputfile, false);

                            // Execute the copy
                            vcs.Execute();

                            // Finish stream and write out the list of inserted and rejected rows
                            long rowsInserted = vcs.Finish();
                IList<long> rowsRejected = vcs.Rejects;
                // Does not work when rejected or exceptions defined
                    Console.WriteLine("Number of Rows inserted: " + rowsInserted);
                    Console.WriteLine("Number of Rows rejected: " + rowsRejected.Count);
                    if (rowsRejected.Count > 0)
                    {
                        for (int i = 0; i < rowsRejected.Count; i++)
                        {
                            Console.WriteLine("Rejected row #{0} is row {1}", i, rowsRejected[i]);
                        }
                    }

                            // Commit the changes
                            txn.Commit();
            }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }


                    //close the connection
                    _conn.Close();
    }
    }
}

4.3.3.2 - 将复制功能与 ADO.NET 配合使用

若要将 COPY 与 ADO.NET 结合使用,只需执行 COPY 语句并指定指向客户端系统上的源文件的路径即可。此方法比使用 VerticaCopyStream 类更简单。但是,如果有许多文件要复制到数据库,或者如果数据来自本地文件以外的其他源(例如,通过网络连接进行流式传输),您可能倾向于使用 VerticaCopyStream。

以下示例代码演示了使用 COPY 将文件从客户端复制到数据库。此示例与“使用 COPY 语句进行批量加载”中所示的代码相同,并且数据文件的路径位于客户端系统而非服务器上。

若要加载存储在数据库节点上的数据,请使用 VerticaCommand 对象创建 COPY 命令:

  1. 通过数据文件存储在的节点创建与数据库的连接

  2. 使用连接创建命令对象。

    VerticaCommand command = _conn.CreateCommand();
    
  3. 复制数据。以下是使用 COPY 命令加载数据的示例。此示例通过使用 LOCAL 修饰符发出命令来复制位于客户端本地的文件。

    command.CommandText = "copy lcopy_table from '/home/dbadmin/customers.txt'"
      + " record terminator E'\n' delimiter '|'"
      + " enforcelength ";
    
    Int32 insertedRows = command.ExecuteNonQuery();
    Console.WriteLine(insertedRows + " inserted.");
    

示例用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            // Configure connection properties
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
     builder.Host = "192.168.1.10";
        builder.Database = "VMart";
        builder.User = "dbadmin";

                   // Open the connection
                    VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();
            try
            {
                using (_conn)
                {

                            // Start a transaction
                            VerticaTransaction txn = _conn.BeginTransaction();

                            // Create a table for this example
                            VerticaCommand command = new VerticaCommand("DROP TABLE IF EXISTS lcopy_table", _conn);
                    command.ExecuteNonQuery();
                    command.CommandText = "CREATE TABLE IF NOT EXISTS lcopy_table (Last_Name char(50), "
                                    + "First_Name char(50),Email char(50), "
                                    + "Phone_Number char(15))";
                    command.ExecuteNonQuery();
                    // Define the copy command
                            command.CommandText = "copy lcopy_table from '/home/dbadmin/customers.txt'"
            + " record terminator E'\n' delimiter '|'"
                        + " enforcelength "
                + " no commit";
                            // Execute the copy
        Int32 insertedRows = command.ExecuteNonQuery();
Console.WriteLine(insertedRows + " inserted.");
                            // Commit the changes
                            txn.Commit();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: " + e.Message);
            }


                    // Close the connection
                    _conn.Close();
        }
    }
}

5 - 取消 ADO.NET 查询

您可以通过调用任何 Command 对象的 .Cancel() 方法来取消正在运行的 vsql 查询。SampleCancelTests 类演示了如何在读取指定数量的行后取消查询。它实现了以下方法:

  • SampleCancelTest() 执行 Setup() 函数以创建测试表。然后,它调用 RunQueryAndCancel()RunSecondQuery() 以演示如何在读取指定的行数后取消查询。最后,它运行 Cleanup() 函数以删除测试表。
  • Setup() 为示例查询创建一个数据库。
  • Cleanup() 删除数据库。
  • RunQueryAndCancel() 从返回 100 多个行的查询中准确读取 100 行。
  • RunSecondQuery() 从查询中读取所有行。
using System;
using Vertica.Data.VerticaClient;

class SampleCancelTests
{
    // Creates a database table, executes a query that cancels during a read loop,
    // executes a query that does not cancel, then drops the test database table.
    // connection: A connection to a Vertica database.

    public static void SampleCancelTest(VerticaConnection connection)
    {
        VerticaCommand command = connection.CreateCommand();

        Setup(command);

        try
        {
            Console.WriteLine("Running query that will cancel after reading 100 rows...");
            RunQueryAndCancel(command);
            Console.WriteLine("Running a second query...");
            RunSecondQuery(command);
            Console.WriteLine("Finished!");
        }
        finally
        {
            Cleanup(command);
        }
    }

    // Set up the database table for the example.
    // command: A Command object used to execute the query.
    private static void Setup(VerticaCommand command)
    {
        // Create table used for test.
        Console.WriteLine("Creating and loading table...");
        command.CommandText = "DROP TABLE IF EXISTS adocanceltest";
        command.ExecuteNonQuery();
        command.CommandText = "CREATE TABLE adocanceltest(id INTEGER, time TIMESTAMP)";
        command.ExecuteNonQuery();
        command.CommandText = @"INSERT INTO adocanceltest
        SELECT row_number() OVER(), slice_time
            FROM(
                    SELECT slice_time FROM(
                    SELECT '2021-01-01'::timestamp s UNION ALL SELECT '2022-01-01'::timestamp s
                    ) sq TIMESERIES slice_time AS '1 second' OVER(ORDER BY s)
            ) sq2";
        command.ExecuteNonQuery();
    }

    // Clean up the database after running the example.
    // command: A Command object used to execute the query.
    private static void Cleanup(VerticaCommand command)
    {
        command.CommandText = "DROP TABLE IF EXISTS adocanceltest";
        command.ExecuteNonQuery();
    }

    // Execute a query that returns many rows and cancels after reading 100.
    // command: A Command object used to execute the query.
    private static void RunQueryAndCancel(VerticaCommand command)
    {
        command.CommandText = "SELECT COUNT(id) from adocanceltest";
        int fullRowCount = Convert.ToInt32(command.ExecuteScalar());

        command.CommandText = "SELECT id, time FROM adocanceltest";
        VerticaDataReader dr = command.ExecuteReader();
        int nCount = 0;
        try
        {
            while (dr.Read())
            {
                nCount++;
                if (nCount == 100)
                {
                    // After reaching 100 rows, cancel the command
                    // Note that it is not necessary to read the remaining rows
                    command.Cancel();
                    return;
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            dr.Close();
            // Verify that the cancel stopped the query
            Console.WriteLine((fullRowCount - nCount) + " rows out of " + fullRowCount + " discarded by cancel");
        }
    }

    // Execute a simple query and read all results.
    // command: A Command object used to execute the query.
    private static void RunSecondQuery(VerticaCommand command)
    {
        command.CommandText = "SELECT 1 FROM dual";
        VerticaDataReader dr = command.ExecuteReader();
        try
        {
            while (dr.Read())
            {
                ;
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine("Warning: no exception should be thrown on query after cancel");
        }
        finally
        {
            dr.Close();
        }
    }
}

6 - 处理消息

可以通过对 VerticaConnection 委托类使用 InfoMessage 事件来捕获 Vertica 向 ADO.NET 驱动程序提供的信息消息和警告消息。此类可捕获严重性不足以强制触发异常但仍可能提供对应用程序有益的信息的消息。

要使用 VerticaInfoMessageEventHander 类:

  1. 创建一个方法以处理从事件处理程序发送的消息:

    static void conn_InfoMessage(object sender, VerticaInfoMessageEventArgs e)
    {
        Console.WriteLine(e.SqlState + ": " + e.Message);
    }
    
  2. 为 InfoMessage 事件创建一个连接并注册新的 VerticaInfoMessageHandler 委托:

    _conn.InfoMessage += new VerticaInfoMessageEventHandler(conn_InfoMessage);
    
  3. 执行查询。如果生成了消息,则会运行事件处理函数。

  4. 可以使用以下命令取消订阅事件:

    _conn.InfoMessage -= new VerticaInfoMessageEventHandler(conn_InfoMessage);
    

示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication {
  class Program {
    // define message handler to deal with messages
    static void conn_InfoMessage(object sender, VerticaInfoMessageEventArgs e) {
      Console.WriteLine(e.SqlState + ": " + e.Message);
    }
    static void Main(string[] args) {
      //configure connection properties
      VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
      builder.Host = "192.168.1.10";
      builder.Database = "VMart";
      builder.User = "dbadmin";

      //open the connection
      VerticaConnection _conn = new VerticaConnection(builder.ToString());
      _conn.Open();

      //create message handler instance by subscribing it to the InfoMessage event of the connection
      _conn.InfoMessage += new VerticaInfoMessageEventHandler(conn_InfoMessage);

      //create and execute the command
      VerticaCommand cmd = _conn.CreateCommand();
      cmd.CommandText = "drop table if exists fakeTable";
      cmd.ExecuteNonQuery();

      //close the connection
      _conn.Close();
    }
  }
}

运行该示例后,将显示以下内容:

00000: Nothing was dropped

7 - 获取表元数据

可以通过对连接使用 GetSchema() 方法并将元数据加载到 DataTable 中来获取表元数据:

DataTable table = _conn.GetSchema("Tables", new string[] { database_name, schema_name, table_name, table_type });

例如:

DataTable table = _conn.GetSchema("Tables", new string[] { null, null, null, "SYSTEM TABLE" });

database_nameschema_nametable_name 可以设置为 null,也可以设置为特定名称,或者也可以使用 LIKE 模式。

table_type 可以设置为以下值之一:

  • "SYSTEM TABLE"

  • "TABLE"

  • "GLOBAL TEMPORARY"

  • "LOCAL TEMPORARY"

  • "VIEW"

  • NULL

如果 table_type 设置为 null,则会返回所有元数据表的元数据。

示例用法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Vertica.Data.VerticaClient;
namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            //configure connection properties
            VerticaConnectionStringBuilder builder = new VerticaConnectionStringBuilder();
            builder.Host = "192.168.1.10";
            builder.Database = "VMart";
            builder.User = "dbadmin";

            //open the connection
            VerticaConnection _conn = new VerticaConnection(builder.ToString());
            _conn.Open();

            //create a new data table containing the schema
            //the last argument can be "SYSTEM TABLE", "TABLE", "GLOBAL TEMPORARY",
            // "LOCAL TEMPORARY", "VIEW", or null for all types
            DataTable table = _conn.GetSchema("Tables", new string[] { null, null, null, "SYSTEM TABLE" });

            //print out the schema
            foreach (DataRow row in table.Rows) {
                foreach (DataColumn col in table.Columns)
                {
                    Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
                }
                Console.WriteLine("============================");
            }

            //close the connection
            _conn.Close();
        }
    }
}