LCOV - code coverage report
Current view: top level - src/apps/unittests - defncopy.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 111 127 87.4 %
Date: 2026-07-04 10:37:34 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 2024  Frediano Ziglio
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : /**
      21             :  * This tests execute some command using tsql and defncopy to check behaviour
      22             :  */
      23             : 
      24             : #include "common.h"
      25             : 
      26             : #if HAVE_STRING_H
      27             : #include <string.h>
      28             : #endif /* HAVE_STRING_H */
      29             : 
      30             : #ifdef HAVE_UNISTD_H
      31             : #include <unistd.h>
      32             : #endif
      33             : 
      34             : #include <freetds/sysdep_private.h>
      35             : #include <freetds/replacements.h>
      36             : 
      37             : /* content of output file, from command executed */
      38             : static char *output;
      39             : 
      40             : static bool
      41             : read_login_info(void)
      42             : {
      43          10 :         return read_login_info_base(&common_pwd, DEFAULT_PWD_PATH) != NULL;
      44             : }
      45             : 
      46             : static void
      47          20 : cleanup(void)
      48             : {
      49          20 :         unlink("empty");
      50          20 :         unlink(output_fn());
      51          20 :         unlink(input_fn());
      52          20 :         TDS_ZERO_FREE(output);
      53          20 : }
      54             : 
      55             : static void
      56          30 : defncopy(const char *object_name)
      57             : {
      58             :         char cmd[2048];
      59          30 :         char *const end = cmd + sizeof(cmd) - 1;
      60             :         char *p;
      61             :         FILE *f;
      62             : 
      63             :         /* empty input */
      64          30 :         f = fopen(input_fn(), "w");
      65          30 :         assert(f);
      66          30 :         fclose(f);
      67             : 
      68          30 :         strcpy(cmd, "defncopy" EXE_SUFFIX);
      69          30 :         p = strchr(cmd, 0);
      70          30 :         p = add_server(p, end);
      71          30 :         p = add_string(p, end, " ");
      72          30 :         p = quote_arg(p, end, object_name);
      73          30 :         p = add_string(p, end, "<");
      74          30 :         p = add_string(p, end, input_fn());
      75          30 :         p = add_string(p, end, " >");
      76          30 :         p = add_string(p, end, output_fn());
      77          30 :         *p = 0;
      78          30 :         printf("Executing: %s\n", cmd);
      79          30 :         if (system(cmd) != 0) {
      80           0 :                 printf("Output is:\n");
      81           0 :                 cat(output_fn(), stdout);
      82           0 :                 fprintf(stderr, "Failed command\n");
      83           0 :                 exit(1);
      84             :         }
      85          30 :         TDS_ZERO_FREE(output);
      86          30 :         output = read_file(output_fn());
      87          30 : }
      88             : 
      89             : /* Builds the command with Sybase syntax */
      90             : static void
      91          10 : defncopy_sybase(const char *object_name)
      92             : {
      93             :         char cmd[2048];
      94          10 :         char *const end = cmd + sizeof(cmd) - 1;
      95             :         char *p;
      96             :         FILE *f;
      97             : 
      98             :         /* empty input */
      99          10 :         f = fopen(input_fn(), "w");
     100          10 :         assert(f);
     101          10 :         fclose(f);
     102             : 
     103          10 :         strcpy(cmd, "defncopy" EXE_SUFFIX);
     104          10 :         p = strchr(cmd, 0);
     105          10 :         p = add_login(p, end);
     106          10 :         p = add_string(p, end, " out ");
     107          10 :         p = add_string(p, end, output_fn());
     108          10 :         if (common_pwd.database[0]) {
     109          10 :                 p = add_string(p, end, " ");
     110          10 :                 p = quote_arg(p, end, common_pwd.database);
     111             :         }
     112          10 :         p = add_string(p, end, " ");
     113          10 :         p = quote_arg(p, end, object_name);
     114          10 :         *p = 0;
     115          10 :         printf("Executing: %s\n", cmd);
     116             : 
     117          10 :         if (system(cmd) != 0) {
     118           0 :                 printf("Output is:\n");
     119           0 :                 cat(output_fn(), stdout);
     120           0 :                 fprintf(stderr, "Failed command\n");
     121           0 :                 exit(1);
     122             :         }
     123          10 :         TDS_ZERO_FREE(output);
     124             : 
     125          10 :         output = read_file(output_fn());
     126          10 : }
     127             : 
     128             : /* table with a column name that is also a keyword, should be quoted */
     129             : static void
     130          10 : test_keyword(void)
     131             : {
     132             :         const char *sql;
     133             :         static const char clean[] =
     134             :                 "IF OBJECT_ID('dbo.table_with_column_named_key') IS NOT NULL DROP TABLE dbo.table_with_column_named_key\n";
     135             : 
     136          10 :         tsql(clean);
     137          10 :         tsql(
     138             : "IF OBJECT_ID('dbo.table_with_column_named_key') IS NOT NULL DROP TABLE dbo.table_with_column_named_key\n"
     139             : "GO\n"
     140             : "CREATE TABLE dbo.table_with_column_named_key\n"
     141             : "(\n"
     142             : "  [key]        nvarchar(4000)  NOT NULL\n"
     143             : ")\n");
     144          10 :         defncopy("dbo.table_with_column_named_key");
     145          10 :         cat(output_fn(), stdout);
     146          10 :         normalize_spaces(output);
     147          10 :         sql =
     148             : "CREATE TABLE [dbo].[table_with_column_named_key]\n"
     149             : " ( [key] nvarchar(4000) NOT NULL\n"
     150             : " )\n"
     151             : "GO";
     152          10 :         if (strstr(output, sql) == NULL) {
     153           0 :                 fprintf(stderr, "Expected SQL string not found\n");
     154           0 :                 exit(1);
     155             :         }
     156          10 :         tsql(clean);
     157          10 :         tsql(sql);
     158          10 :         tsql(clean);
     159          10 : }
     160             : 
     161             : 
     162             : /* same as previous but using Sybase syntax */
     163             : static void
     164          10 : test_keyword_sybase(void)
     165             : {
     166             :         const char *sql;
     167             :         static const char clean[] =
     168             :                 "IF OBJECT_ID('dbo.table_with_column_named_key') IS NOT NULL DROP TABLE dbo.table_with_column_named_key\n";
     169             : 
     170          10 :         tsql(clean);
     171             :         /* *INDENT-OFF* */
     172          10 :         sql =
     173             :                 "IF OBJECT_ID('dbo.table_with_column_named_key') IS NOT NULL DROP TABLE dbo.table_with_column_named_key\n"
     174             :                 "GO\n"
     175             :                 "CREATE TABLE dbo.table_with_column_named_key\n"
     176             :                 "(\n"
     177             :                 "  [key]        nvarchar(4000)  NOT NULL\n"
     178             :                 ")\n";
     179             :         /* *INDENT-ON* */
     180          10 :         tsql(sql);
     181          10 :         defncopy_sybase("dbo.table_with_column_named_key");
     182          10 :         cat(output_fn(), stdout);
     183          10 :         normalize_spaces(output);
     184             :         /* *INDENT-OFF* */
     185          10 :         sql =
     186             :                 "CREATE TABLE [dbo].[table_with_column_named_key]\n"
     187             :                 " ( [key] nvarchar(4000) NOT NULL\n"
     188             :                 " )\n"
     189             :                 "GO";
     190             :         /* *INDENT-ON* */
     191          10 :         if (strstr(output, sql) == NULL) {
     192           0 :                 fprintf(stderr, "Expected SQL string not found\n");
     193           0 :                 exit(1);
     194             :         }
     195          10 :         tsql(clean);
     196          10 :         tsql(sql);
     197          10 :         tsql(clean);
     198          10 : }
     199             : 
     200             : /* table with an index with a space inside */
     201             : static void
     202          10 : test_index_name_with_space(void)
     203             : {
     204             :         const char *sql;
     205             :         static const char clean[] =
     206             :                 "IF OBJECT_ID('dbo.tblReportPeriod') IS NOT NULL DROP TABLE dbo.tblReportPeriod\n";
     207             : 
     208          10 :         tsql(clean);
     209          10 :         tsql(
     210             : "CREATE TABLE dbo.tblReportPeriod\n"
     211             : "  ( RecordID   int             NOT NULL\n"
     212             : "  , FromDate   nvarchar(40)        NULL\n"
     213             : "  , ToDate     nvarchar(40)        NULL\n"
     214             : "  )\n"
     215             : "CREATE  nonclustered INDEX [From Date] on dbo.tblReportPeriod(FromDate)\n");
     216          10 :         defncopy("dbo.tblReportPeriod");
     217          10 :         cat(output_fn(), stdout);
     218          10 :         normalize_spaces(output);
     219          10 :         sql =
     220             : "CREATE TABLE [dbo].[tblReportPeriod]\n"
     221             : " ( [RecordID] int NOT NULL\n"
     222             : " , [FromDate] nvarchar(40) NULL\n"
     223             : " , [ToDate] nvarchar(40) NULL\n"
     224             : " )\n"
     225             : "GO\n"
     226             : "\n"
     227             : "CREATE nonclustered INDEX [From Date] on [dbo].[tblReportPeriod]([FromDate])";
     228          10 :         if (strstr(output, sql) == NULL) {
     229           0 :                 fprintf(stderr, "Expected SQL string not found\n");
     230           0 :                 exit(1);
     231             :         }
     232          10 :         tsql(clean);
     233          10 :         tsql(sql);
     234          10 :         tsql(clean);
     235          10 : }
     236             : 
     237             : /* table with an index with a space inside */
     238             : static void
     239          10 : test_weird_index_names(void)
     240             : {
     241             :         const char *sql, *sql_sybase;
     242             :         static const char clean[] =
     243             :                 "IF OBJECT_ID('dbo.tblReportPeriod2') IS NOT NULL DROP TABLE dbo.tblReportPeriod2\n";
     244             : 
     245          10 :         tsql(clean);
     246          10 :         tsql(
     247             : "CREATE TABLE dbo.tblReportPeriod2\n"
     248             : "  ( RecordID   int             NOT NULL\n"
     249             : "  , [To, ]   nvarchar(40)        NULL\n"
     250             : "  , [To]     nvarchar(40)        NULL\n"
     251             : "  , [To, , ]     nvarchar(40)        NULL\n"
     252             : "  )\n"
     253             : "CREATE  nonclustered INDEX [From Date] on dbo.tblReportPeriod2([To, ],[To, , ])\n");
     254          10 :         defncopy("dbo.tblReportPeriod2");
     255          10 :         cat(output_fn(), stdout);
     256          10 :         normalize_spaces(output);
     257          10 :         sql =
     258             : "CREATE TABLE [dbo].[tblReportPeriod2]\n"
     259             : " ( [RecordID] int NOT NULL\n"
     260             : " , [To, ] nvarchar(40) NULL\n"
     261             : " , [To] nvarchar(40) NULL\n"
     262             : " , [To, , ] nvarchar(40) NULL\n"
     263             : " )\n"
     264             : "GO\n"
     265             : "\n"
     266             : "CREATE nonclustered INDEX [From Date] on [dbo].[tblReportPeriod2]([To, ],[To, , ])";
     267             :         /* Sybase remove spaces at the end */
     268          10 :         sql_sybase =
     269             : "CREATE TABLE [dbo].[tblReportPeriod2]\n"
     270             : " ( [RecordID] int NOT NULL\n"
     271             : " , [To,] nvarchar(40) NULL\n"
     272             : " , [To] nvarchar(40) NULL\n"
     273             : " , [To, ,] nvarchar(40) NULL\n"
     274             : " )\n"
     275             : "GO\n"
     276             : "\n"
     277             : "CREATE nonclustered INDEX [From Date] on [dbo].[tblReportPeriod2]([To,],[To, ,])";
     278          10 :         if (strstr(output, sql) == NULL && strstr(output, sql_sybase) == NULL) {
     279           0 :                 fprintf(stderr, "Expected SQL string not found\n");
     280           0 :                 exit(1);
     281             :         }
     282          10 :         tsql(clean);
     283          10 :         tsql(sql);
     284          10 :         tsql(clean);
     285          10 : }
     286             : 
     287          10 : TEST_MAIN()
     288             : {
     289             :         FILE *f;
     290             : 
     291          10 :         cleanup();
     292          10 :         update_path();
     293             : 
     294          10 :         if (!read_login_info())
     295             :                 return 1;
     296             : 
     297          10 :         f = fopen("empty", "w");
     298          10 :         if (f)
     299          10 :                 fclose(f);
     300             : 
     301          10 :         test_keyword();
     302          10 :         test_keyword_sybase();
     303          10 :         test_index_name_with_space();
     304          10 :         test_weird_index_names();
     305             : 
     306          10 :         cleanup();
     307          10 :         return 0;
     308             : }

Generated by: LCOV version 1.13