/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ package oracle import ( "context" "fmt" "strings" "git.zabbix.com/ap/plugin-support/zbxerr" ) const ( temp = "TEMPORARY" perm = "PERMANENT" undo = "UNDO" defaultPERMTS = "USERS" defaultTEMPTS = "TEMP" ) func tablespacesHandler(ctx context.Context, conn OraClient, params map[string]string, _ ...string) (interface{}, error) { var tablespaces string query, err := getQuery(params) if err != nil { return nil, err } row, err := conn.QueryRow(ctx, query) if err != nil { return nil, zbxerr.ErrorCannotFetchData.Wrap(err) } err = row.Scan(&tablespaces) if err != nil { return nil, zbxerr.ErrorCannotFetchData.Wrap(err) } // Add leading zeros for floats: ".03" -> "0.03". // Oracle JSON functions are not RFC 4627 compliant. // There should be a better way to do that, but I haven't come up with it ¯\_(ツ)_/¯ tablespaces = strings.ReplaceAll(tablespaces, "\":.", "\":0.") return tablespaces, nil } func getQuery(params map[string]string) (string, error) { ts := params["Tablespace"] t := params["Type"] conn := params["Conname"] if ts == "" && t == "" { if conn == "" { return getFullQuery(), nil } return getFullQueryConn(conn), nil } var err error ts, t, err = prepValues(ts, t) if err != nil { return "", zbxerr.ErrorInvalidParams.Wrap(err) } switch t { case perm, undo: if conn != "" { return getPermQueryConnPart(conn, ts), nil } return getPermQueryPart(ts), nil case temp: if conn != "" { return getTempQueryConnPart(conn, ts), nil } return getTempQueryPart(ts), nil default: return "", zbxerr.ErrorInvalidParams.Wrap(fmt.Errorf("incorrect table-space type %s", t)) } } func prepValues(ts, t string) (outTableSpace string, outType string, err error) { if ts != "" && t != "" { return ts, t, nil } if ts == "" { if t == perm { return defaultPERMTS, t, nil } if t == temp { return defaultTEMPTS, t, nil } return "", "", fmt.Errorf("incorrect type %s", t) } return ts, perm, nil } func getFullQuery() string { return ` SELECT JSON_ARRAYAGG( JSON_OBJECT(CON_NAME VALUE JSON_ARRAYAGG( JSON_OBJECT(TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) ) ) RETURNING CLOB ) FROM (SELECT df.CON_NAME, df.TABLESPACE_NAME AS TABLESPACE_NAME, df.CONTENTS AS CONTENTS, NVL(SUM(df.BYTES), 0) AS FILE_BYTES, NVL(SUM(df.MAX_BYTES), 0) AS MAX_BYTES, NVL(SUM(f.FREE), 0) AS FREE_BYTES, NVL(SUM(df.BYTES) - SUM(f.FREE), 0) AS USED_BYTES, ROUND(DECODE(SUM(df.MAX_BYTES), 0, 0, (SUM(df.BYTES) / SUM(df.MAX_BYTES) * 100)), 2) AS USED_PCT_MAX, ROUND(DECODE(SUM(df.BYTES), 0, 0, (NVL(SUM(df.BYTES) - SUM(f.FREE), 0)) / SUM(df.BYTES) * 100), 2) AS USED_FILE_PCT, DECODE(df.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0) AS STATUS FROM (SELECT ct.CON$NAME AS CON_NAME, cdf.FILE_ID, ct.CONTENTS, ct.STATUS, cdf.FILE_NAME, cdf.TABLESPACE_NAME, TRUNC(cdf.BYTES) AS BYTES, TRUNC(GREATEST(cdf.BYTES, cdf.MAXBYTES)) AS MAX_BYTES FROM CDB_DATA_FILES cdf, CDB_TABLESPACES ct WHERE cdf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND cdf.CON_ID = ct.CON_ID) df, (SELECT TRUNC(SUM(BYTES)) AS FREE, FILE_ID FROM CDB_FREE_SPACE GROUP BY FILE_ID) f WHERE df.FILE_ID = f.FILE_ID (+) GROUP BY df.CON_NAME, df.TABLESPACE_NAME, df.CONTENTS, df.STATUS UNION ALL SELECT Y.CON_NAME, Y.NAME AS TABLESPACE_NAME, Y.CONTENTS AS CONTENTS, NVL(SUM(Y.BYTES), 0) AS FILE_BYTES, NVL(SUM(Y.MAX_BYTES), 0) AS MAX_BYTES, NVL(MAX(NVL(Y.FREE_BYTES, 0)), 0) AS FREE_BYTES, NVL(SUM(Y.BYTES) - MAX(Y.FREE_BYTES), 0) AS USED_BYTES, ROUND(DECODE(SUM(Y.MAX_BYTES), 0, 0, (SUM(Y.BYTES) / SUM(Y.MAX_BYTES) * 100)), 2) AS USED_PCT_MAX, ROUND(DECODE(SUM(Y.BYTES), 0, 0, (NVL(SUM(Y.BYTES) - MAX(Y.FREE_BYTES), 0)) / SUM(Y.BYTES) * 100), 2) AS USED_FILE_PCT, DECODE(Y.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0) AS STATUS FROM (SELECT ct.CON$NAME AS CON_NAME, ctf.TABLESPACE_NAME AS NAME, ct.CONTENTS, ctf.STATUS AS STATUS, ctf.BYTES AS BYTES, (SELECT ((f.TOTAL_BLOCKS - s.TOT_USED_BLOCKS) * vp.VALUE) FROM (SELECT CON_ID, TABLESPACE_NAME, SUM(USED_BLOCKS) TOT_USED_BLOCKS FROM V$SORT_SEGMENT WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME) s, (SELECT CON_ID, TABLESPACE_NAME, SUM(BLOCKS) TOTAL_BLOCKS FROM CDB_TEMP_FILES WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME) f, (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'db_block_size') vp WHERE f.TABLESPACE_NAME = s.TABLESPACE_NAME AND f.TABLESPACE_NAME = ctf.TABLESPACE_NAME AND f.CON_ID = s.CON_ID AND f.CON_ID = ct.CON_ID) AS FREE_BYTES, CASE WHEN ctf.MAXBYTES = 0 THEN ctf.BYTES ELSE ctf.MAXBYTES END AS MAX_BYTES FROM CDB_TEMP_FILES ctf, CDB_TABLESPACES ct WHERE ctf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND ctf.CON_ID = ct.CON_ID) Y GROUP BY Y.CON_NAME, Y.NAME, Y.CONTENTS, Y.STATUS) GROUP BY CON_NAME ` } func getFullQueryConn(conName string) string { return fmt.Sprintf(`SELECT JSON_ARRAYAGG( JSON_OBJECT(TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) RETURNING CLOB ) FROM ( SELECT df.TABLESPACE_NAME AS TABLESPACE_NAME, df.CONTENTS AS CONTENTS, NVL(SUM(df.BYTES), 0) AS FILE_BYTES, NVL(SUM(df.MAX_BYTES), 0) AS MAX_BYTES, NVL(SUM(f.FREE), 0) AS FREE_BYTES, NVL(SUM(df.BYTES) - SUM(f.FREE), 0) AS USED_BYTES, ROUND(DECODE(SUM(df.MAX_BYTES), 0, 0, (SUM(df.BYTES) / SUM(df.MAX_BYTES) * 100)), 2) AS USED_PCT_MAX, ROUND(DECODE(SUM(df.BYTES), 0, 0, (NVL(SUM(df.BYTES) - SUM(f.FREE), 0)) / SUM(df.BYTES) * 100), 2) AS USED_FILE_PCT, DECODE(df.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0) AS STATUS FROM (SELECT ct.CON$NAME AS CON_NAME, cdf.FILE_ID, ct.CONTENTS, ct.STATUS, cdf.FILE_NAME, cdf.TABLESPACE_NAME, TRUNC(cdf.BYTES) AS BYTES, TRUNC(GREATEST(cdf.BYTES, cdf.MAXBYTES)) AS MAX_BYTES FROM CDB_DATA_FILES cdf, CDB_TABLESPACES ct WHERE cdf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND cdf.CON_ID = ct.CON_ID AND (ct.CON$NAME = '%s' or (ct.CON$NAME is null and ct.CON_ID = 0))) df, (SELECT TRUNC(SUM(BYTES)) AS FREE, FILE_ID FROM CDB_FREE_SPACE GROUP BY FILE_ID) f WHERE df.FILE_ID = f.FILE_ID (+) GROUP BY df.CON_NAME, df.TABLESPACE_NAME, df.CONTENTS, df.STATUS UNION ALL SELECT Y.NAME AS TABLESPACE_NAME, Y.CONTENTS AS CONTENTS, NVL(SUM(Y.BYTES), 0) AS FILE_BYTES, NVL(SUM(Y.MAX_BYTES), 0) AS MAX_BYTES, NVL(MAX(NVL(Y.FREE_BYTES, 0)), 0) AS FREE_BYTES, NVL(SUM(Y.BYTES) - SUM(Y.FREE_BYTES), 0) AS USED_BYTES, ROUND(DECODE(SUM(Y.MAX_BYTES), 0, 0, (SUM(Y.BYTES) / SUM(Y.MAX_BYTES) * 100)), 2) AS USED_PCT_MAX, ROUND(DECODE(SUM(Y.BYTES), 0, 0, (NVL(SUM(Y.BYTES) - SUM(Y.FREE_BYTES), 0)) / SUM(Y.BYTES) * 100), 2) AS USED_FILE_PCT, DECODE(Y.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0) AS STATUS FROM (SELECT ct.CON$NAME AS CON_NAME, ctf.TABLESPACE_NAME AS NAME, ct.CONTENTS, ctf.STATUS AS STATUS, ctf.BYTES AS BYTES, (SELECT ((f.TOTAL_BLOCKS - s.TOT_USED_BLOCKS) * vp.VALUE) FROM (SELECT CON_ID, TABLESPACE_NAME, SUM(USED_BLOCKS) TOT_USED_BLOCKS FROM V$SORT_SEGMENT WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME) s, (SELECT CON_ID, TABLESPACE_NAME, SUM(BLOCKS) TOTAL_BLOCKS FROM CDB_TEMP_FILES WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME) f, (SELECT VALUE FROM V$PARAMETER WHERE NAME = 'db_block_size') vp WHERE f.TABLESPACE_NAME = s.TABLESPACE_NAME AND f.TABLESPACE_NAME = ctf.TABLESPACE_NAME AND f.CON_ID = s.CON_ID AND f.CON_ID = ct.CON_ID) AS FREE_BYTES, CASE WHEN ctf.MAXBYTES = 0 THEN ctf.BYTES ELSE ctf.MAXBYTES END AS MAX_BYTES FROM CDB_TEMP_FILES ctf, CDB_TABLESPACES ct WHERE ctf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND ctf.CON_ID = ct.CON_ID AND ((ct.CON$NAME = '%s') or (ct.CON$NAME is null and ct.CON_ID = 0))) Y GROUP BY Y.CON_NAME, Y.NAME, Y.CONTENTS, Y.STATUS)`, conName, conName) } func getPermQueryPart(name string) string { return fmt.Sprintf(` SELECT JSON_ARRAYAGG( JSON_OBJECT(CON_NAME VALUE JSON_ARRAYAGG( JSON_OBJECT( TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) ) ) RETURNING CLOB ) FROM ( SELECT df.CON_NAME, df.TABLESPACE_NAME AS TABLESPACE_NAME, df.CONTENTS AS CONTENTS, NVL(SUM(df.BYTES), 0) AS FILE_BYTES, NVL(SUM(df.MAX_BYTES), 0) AS MAX_BYTES, NVL(SUM(f.FREE), 0) AS FREE_BYTES, NVL(SUM(df.BYTES) - SUM(f.FREE), 0) AS USED_BYTES, ROUND( DECODE( SUM(df.MAX_BYTES), 0, 0, (SUM(df.BYTES) / SUM(df.MAX_BYTES) * 100) ), 2 ) AS USED_PCT_MAX, ROUND( DECODE( SUM(df.BYTES), 0, 0, (NVL(SUM(df.BYTES) - SUM(f.FREE), 0)) / SUM(df.BYTES) * 100 ), 2 ) AS USED_FILE_PCT, DECODE( df.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0 ) AS STATUS FROM ( SELECT ct.CON$NAME AS CON_NAME, cdf.FILE_ID, ct.CONTENTS, ct.STATUS, cdf.FILE_NAME, cdf.TABLESPACE_NAME, TRUNC(cdf.BYTES) AS BYTES, TRUNC(GREATEST(cdf.BYTES, cdf.MAXBYTES)) AS MAX_BYTES FROM CDB_DATA_FILES cdf, CDB_TABLESPACES ct WHERE cdf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND cdf.CON_ID = ct.CON_ID ) df, ( SELECT TRUNC(SUM(BYTES)) AS FREE, FILE_ID FROM CDB_FREE_SPACE GROUP BY FILE_ID ) f WHERE df.FILE_ID = f.FILE_ID (+) AND df.TABLESPACE_NAME = '%s' GROUP BY df.CON_NAME, df.TABLESPACE_NAME, df.CONTENTS, df.STATUS ) GROUP BY CON_NAME `, name) } func getTempQueryPart(name string) string { return fmt.Sprintf(` SELECT JSON_ARRAYAGG( JSON_OBJECT(CON_NAME VALUE JSON_ARRAYAGG( JSON_OBJECT( TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) ) ) RETURNING CLOB ) FROM ( SELECT Y.CON_NAME, Y.NAME AS TABLESPACE_NAME, Y.CONTENTS AS CONTENTS, NVL(SUM(Y.BYTES), 0) AS FILE_BYTES, NVL(SUM(Y.MAX_BYTES), 0) AS MAX_BYTES, NVL(MAX(NVL(Y.FREE_BYTES, 0)), 0) AS FREE_BYTES, NVL(SUM(Y.BYTES) - SUM(Y.FREE_BYTES), 0) AS USED_BYTES, ROUND(DECODE(SUM(Y.MAX_BYTES), 0, 0,(SUM(Y.BYTES) / SUM(Y.MAX_BYTES) * 100) ), 2 ) AS USED_PCT_MAX, ROUND(DECODE(SUM(Y.BYTES),0,0,(NVL(SUM(Y.BYTES) - SUM(Y.FREE_BYTES), 0)) / SUM(Y.BYTES) * 100 ), 2 ) AS USED_FILE_PCT, DECODE(Y.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0 ) AS STATUS FROM ( SELECT ct.CON$NAME AS CON_NAME, ctf.TABLESPACE_NAME AS NAME, ct.CONTENTS, ctf.STATUS AS STATUS, ctf.BYTES AS BYTES, ( SELECT ((f.TOTAL_BLOCKS - s.TOT_USED_BLOCKS) * vp.VALUE) FROM ( SELECT CON_ID, TABLESPACE_NAME, SUM(USED_BLOCKS) TOT_USED_BLOCKS FROM V$SORT_SEGMENT WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME ) s, ( SELECT CON_ID, TABLESPACE_NAME, SUM(BLOCKS) TOTAL_BLOCKS FROM CDB_TEMP_FILES WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME ) f, ( SELECT VALUE FROM V$PARAMETER WHERE NAME = 'db_block_size' ) vp WHERE f.TABLESPACE_NAME = s.TABLESPACE_NAME AND f.TABLESPACE_NAME = ctf.TABLESPACE_NAME AND f.CON_ID = s.CON_ID AND f.CON_ID = ct.CON_ID ) AS FREE_BYTES, CASE WHEN ctf.MAXBYTES = 0 THEN ctf.BYTES ELSE ctf.MAXBYTES END AS MAX_BYTES FROM CDB_TEMP_FILES ctf, CDB_TABLESPACES ct WHERE ctf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND ctf.CON_ID = ct.CON_ID AND ctf.TABLESPACE_NAME = '%s' ) Y GROUP BY Y.CON_NAME, Y.NAME, Y.CONTENTS, Y.STATUS ) GROUP BY CON_NAME `, name) } func getPermQueryConnPart(conName, name string) string { return fmt.Sprintf(` SELECT JSON_ARRAYAGG( JSON_OBJECT( TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) RETURNING CLOB ) FROM ( SELECT df.TABLESPACE_NAME AS TABLESPACE_NAME, df.CONTENTS AS CONTENTS, NVL(SUM(df.BYTES), 0) AS FILE_BYTES, NVL(SUM(df.MAX_BYTES), 0) AS MAX_BYTES, NVL(SUM(f.FREE), 0) AS FREE_BYTES, NVL(SUM(df.BYTES) - SUM(f.FREE), 0) AS USED_BYTES, ROUND( DECODE( SUM(df.MAX_BYTES), 0, 0, (SUM(df.BYTES) / SUM(df.MAX_BYTES) * 100) ), 2 ) AS USED_PCT_MAX, ROUND( DECODE( SUM(df.BYTES), 0, 0, (NVL(SUM(df.BYTES) - SUM(f.FREE), 0)) / SUM(df.BYTES) * 100 ), 2 ) AS USED_FILE_PCT, DECODE( df.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0 ) AS STATUS FROM ( SELECT ct.CON$NAME AS CON_NAME, cdf.FILE_ID, ct.CONTENTS, ct.STATUS, cdf.FILE_NAME, cdf.TABLESPACE_NAME, TRUNC(cdf.BYTES) AS BYTES, TRUNC(GREATEST(cdf.BYTES, cdf.MAXBYTES)) AS MAX_BYTES FROM CDB_DATA_FILES cdf, CDB_TABLESPACES ct WHERE cdf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND cdf.CON_ID = ct.CON_ID AND (ct.CON$NAME = '%s' or (ct.CON$NAME is null and ct.CON_ID = 0)) ) df, ( SELECT TRUNC(SUM(BYTES)) AS FREE, FILE_ID FROM CDB_FREE_SPACE GROUP BY FILE_ID ) f WHERE df.FILE_ID = f.FILE_ID (+) AND df.TABLESPACE_NAME = '%s' GROUP BY df.CON_NAME, df.TABLESPACE_NAME, df.CONTENTS, df.STATUS ) `, conName, name) } func getTempQueryConnPart(conName, name string) string { return fmt.Sprintf(` SELECT JSON_ARRAYAGG( JSON_OBJECT( TABLESPACE_NAME VALUE JSON_OBJECT( 'contents' VALUE CONTENTS, 'file_bytes' VALUE FILE_BYTES, 'max_bytes' VALUE MAX_BYTES, 'free_bytes' VALUE FREE_BYTES, 'used_bytes' VALUE USED_BYTES, 'used_pct_max' VALUE USED_PCT_MAX, 'used_file_pct' VALUE USED_FILE_PCT, 'status' VALUE STATUS ) ) RETURNING CLOB ) FROM ( SELECT Y.NAME AS TABLESPACE_NAME, Y.CONTENTS AS CONTENTS, NVL(SUM(Y.BYTES), 0) AS FILE_BYTES, NVL(SUM(Y.MAX_BYTES), 0) AS MAX_BYTES, NVL(MAX(NVL(Y.FREE_BYTES, 0)), 0) AS FREE_BYTES, NVL(SUM(Y.BYTES) - MAX(Y.FREE_BYTES), 0) AS USED_BYTES, ROUND( DECODE(SUM(Y.MAX_BYTES), 0, 0, (SUM(Y.BYTES) / SUM(Y.MAX_BYTES) * 100)), 2 ) AS USED_PCT_MAX, ROUND( DECODE( SUM(Y.BYTES), 0, 0, (NVL(SUM(Y.BYTES) - MAX(Y.FREE_BYTES), 0)) / SUM(Y.BYTES) * 100 ),2 ) AS USED_FILE_PCT, DECODE(Y.STATUS, 'ONLINE', 1, 'OFFLINE', 2, 'READ ONLY', 3, 0) AS STATUS FROM ( SELECT ct.CON$NAME AS CON_NAME, ctf.TABLESPACE_NAME AS NAME, ct.CONTENTS, ctf.STATUS AS STATUS, ctf.BYTES AS BYTES, ( SELECT ((f.TOTAL_BLOCKS - s.TOT_USED_BLOCKS) * vp.VALUE) FROM ( SELECT CON_ID, TABLESPACE_NAME, SUM(USED_BLOCKS) TOT_USED_BLOCKS FROM V$SORT_SEGMENT WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME ) s, ( SELECT CON_ID, TABLESPACE_NAME, SUM(BLOCKS) TOTAL_BLOCKS FROM CDB_TEMP_FILES WHERE TABLESPACE_NAME != 'DUMMY' GROUP BY CON_ID, TABLESPACE_NAME ) f, ( SELECT VALUE FROM V$PARAMETER WHERE NAME = 'db_block_size' ) vp WHERE f.TABLESPACE_NAME = s.TABLESPACE_NAME AND f.TABLESPACE_NAME = ctf.TABLESPACE_NAME AND f.CON_ID = s.CON_ID AND f.CON_ID = ct.CON_ID ) AS FREE_BYTES, CASE WHEN ctf.MAXBYTES = 0 THEN ctf.BYTES ELSE ctf.MAXBYTES END AS MAX_BYTES FROM CDB_TEMP_FILES ctf, CDB_TABLESPACES ct WHERE ctf.TABLESPACE_NAME = ct.TABLESPACE_NAME AND ctf.CON_ID = ct.CON_ID AND ((ct.CON$NAME = '%s') or (ct.CON$NAME is null and ct.CON_ID = 0)) AND ctf.TABLESPACE_NAME = '%s' ) Y GROUP BY Y.CON_NAME, Y.NAME, Y.CONTENTS, Y.STATUS )`, conName, name) }