1/*
2** Zabbix
3** Copyright (C) 2001-2021 Zabbix SIA
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18**/
19
20package postgres
21
22import (
23	"context"
24	"encoding/json"
25	"errors"
26	"strings"
27
28	"github.com/jackc/pgx/v4"
29	"zabbix.com/pkg/zbxerr"
30)
31
32// customQueryHandler executes custom user queries from *.sql files.
33func customQueryHandler(ctx context.Context, conn PostgresClient,
34	_ string, params map[string]string, extraParams ...string) (interface{}, error) {
35	queryName := params["QueryName"]
36
37	queryArgs := make([]interface{}, len(extraParams))
38	for i, v := range extraParams {
39		queryArgs[i] = v
40	}
41
42	rows, err := conn.QueryByName(ctx, queryName, queryArgs...)
43	if err != nil {
44		return nil, zbxerr.ErrorCannotFetchData.Wrap(err)
45	}
46	defer rows.Close()
47
48	// JSON marshaling
49	var data []string
50
51	columns, err := rows.Columns()
52	if err != nil {
53		return nil, zbxerr.ErrorCannotFetchData.Wrap(err)
54	}
55
56	values := make([]interface{}, len(columns))
57	valuePointers := make([]interface{}, len(values))
58
59	for i := range values {
60		valuePointers[i] = &values[i]
61	}
62
63	results := make(map[string]interface{})
64
65	for rows.Next() {
66		err = rows.Scan(valuePointers...)
67		if err != nil {
68			if errors.Is(err, pgx.ErrNoRows) {
69				return nil, zbxerr.ErrorEmptyResult.Wrap(err)
70			}
71
72			return nil, zbxerr.ErrorCannotFetchData.Wrap(err)
73		}
74
75		for i, value := range values {
76			results[columns[i]] = value
77		}
78
79		jsonRes, _ := json.Marshal(results)
80		data = append(data, strings.TrimSpace(string(jsonRes)))
81	}
82
83	// Any errors encountered by rows.Next or rows.Scan will be returned here
84	if rows.Err() != nil {
85		return nil, err
86	}
87
88	return "[" + strings.Join(data, ",") + "]", nil
89}
90