PostgreSQL之精妙的数据库导入导出工具架构 (十一)

(十一)详解逻辑备份---数据的导出

1 概述

    对象的定义导出,是要把对象的元信息读出后,把与对象相关的各种信息置于一个链表上,链表的每个节点是一个对象。每个表的数据,都被抽象为一个对象(链表上的所有对象都有自己的类型,TocEntry结构上有个成员“teSection    section”,是标识本节点的类型),这个对象在链表上占据一个节点的位置,当对象定义导出后,数据将被导出时,即依据数据对象节点上的信息,从表中读出数据,然后把数据写出去(所以,内存中,只是链表上的对象的定义,数据是在边读边写出的)。

2 dumpTableData函数细节
2.1 dumpTableData函数的入口参数为:(Archive *fout, TableDataInfo *tdinfo),第一个参数,表示输出流信息,其实也对应的是链表的表头信息(如结构上有个tocCount成员,用于不断统计链表的节点个数);第二个参数,是表的数据对象对应的结构信息,本信息是导出链表上的表的数据对应的节点的元信息。
2.2 如果导出参数没有特别指出是以insert语句方式导出,则使用copy方式导出数据(copy方式,PostgreSQL提供的一种快速导出导入数据的一种方式,有对应的SQL语句存在)。这两个函数分别是:dumpTableData_copy、dumpTableData_insert。
    但请注意,这里需要留意“DataDumperPtr dumpFn”函数的指针使用方式。
2.3 调用ArchiveEntry函数,执行数据的导出。
    ArchiveEntry函数的倒数第二个参数“DataDumperPtr dumpFn”,通常在非数据对象导出的时候,其入口值都是“NULL”,只有导出的对象是数据时,真正才赋予数据导出需要使用的函数(写出数据对应的是WriteDataChunks(AH),本函数通过函数指针,真正调用了如上条提到的dumpTableData_insert等函数)。
    留意,又一处函数指针的使用典范。    
    本函数的入口参数如下:
      ArchiveEntry(Archive *AHX,
                   CatalogId catalogId, DumpId dumpId,
                   const char *tag,
                   const char *namespace,
                   const char *tablespace,
                   const char *owner, bool withOids,
                   const char *desc, teSection section,
                   const char *defn,
                   const char *dropStmt, const char *copyStmt,
                   const DumpId *deps, int nDeps,
                   DataDumperPtr dumpFn, void *dumpArg)

     请留意这些参数,能够表明很多信息,如:我们提到的“dumpFn”,表示数据导出时被调用的函数;“dropStmt”参数,表述生成导出对象的drop语句,此功能是支持在恢复时,可以先清理目的数据库中的可能存在的同名同类型对象,避免恢复因同名同类对象存在导致的失败;再如“tablespace”,表示被导出对象处于哪个表空间上,如果被导出对象和表空间没有关系,则本参数传入的值为“NULL”。
       
2.4 WriteDataChunks函数细节
     void
    WriteDataChunks(ArchiveHandle *AH)
    {
        TocEntry   *te;
        StartDataPtr startPtr;
        EndDataPtr    endPtr;
    
        for (te = AH->toc->next; te != AH->toc; te = te->next)
        {
            if (te->dataDumper != NULL)
            {
                AH->currToc = te;
                /* printf("Writing data for %d (%x)\n", te->id, te); */
    
                if (strcmp(te->desc, "BLOBS") == 0) // 如果是大对象,也要被当作数据处理
                {
                    startPtr = AH->StartBlobsPtr;
                    endPtr = AH->EndBlobsPtr;
                }
                else
                {
                    startPtr = AH->StartDataPtr;
                    endPtr = AH->EndDataPtr;
                }
    
                if (startPtr != NULL)
                    (*startPtr) (AH, te); // 又一处函数指针的使用,处理大对象的导出
    
                /*
                 * printf("Dumper arg for %d is %x\n", te->id, te->dataDumperArg);
                 */
    
                /*
                 * The user-provided DataDumper routine needs to call
                 * AH->WriteData
                 */
                (*te->dataDumper) ((Archive *) AH, te->dataDumperArg); //函数指针典范
    
                if (endPtr != NULL)
                    (*endPtr) (AH, te); // 又一处函数指针的使用,处理大对象的导出
                AH->currToc = NULL;
            }
        }
    }

3 dumpTableData_insert函数细节
3.1 根据函数名,即可知道是导出表的数据,且采用的是insert语句的方式。这种方式,是生成带有数据的insert语句,在恢复时,在目的库里执行insert语句。
3.2 入口参数:(Archive *fout, void *dcontext),第一个参数,同2.1节介绍的第一个参数相同;第二个参数,表示本数据据对应的“表数据对象”的元信息,其类型是“void *”,在函数内部,对此参数进行了强制类型转换,变为“TableDataInfo *”类型。
3.3 根据目的数据库的版本,从本表读取数据。注意,读取数据的方式,不是简单的select语句,而是采用的“cursor”方式,这样,可以从数据库中逐步读出数据,而不是一下子从数据库读取出所有的数据,此举通常不会导致因数据量大而导致系统内存用完。
3.4 循环从“cursor”中读取数据,每次仅读出100条。
3.5 针对读出的数据,遍历每一条记录,根据列的类型,拼接出完整的insert语句。
3.6 注意不同类型的列数据的拼接方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值