UNPKG

hana-cli

Version:
961 lines (910 loc) 30.3 kB
/*eslint no-console: 0, no-unused-vars: 0, no-shadow: 0, new-cap: 0*/ /*eslint-env node, es6 */ // @ts-check /** * @module dbInspect - Database Object Dynamic Inspection and Metadata processing */ import * as base from "./base.js" const bundle = base.bundle /** * Return the HANA DB Version * @param {object} db - Database Connection * @returns {Promise<object>} */ export async function getHANAVersion(db) { base.debug(`getHANAVersion`) const statement = await db.preparePromisified( `SELECT * FROM M_DATABASE`) const object = await db.statementExecPromisified(statement, []) if (object.length < 1) { throw new Error(bundle.getText("errMDB")) } object[0].versionMajor = object[0].VERSION.charAt(0) base.debug(`HANA Version ${JSON.stringify(object)}`) return object[0] } /** * Check if a view is a Calculation View * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} viewId - View Unique ID * @returns {Promise<boolean>} */ export async function isCalculationView(db, schema, viewId) { base.debug(`isCalculationView ${schema} ${viewId}`) const vers = await getHANAVersion(db) if (vers.versionMajor < 2) { return false } //Select View let statementString = `` statementString = `SELECT CUBE_ID, SCHEMA_NAME, QUALIFIED_NAME, VIEW_NAME, CUBE_TYPE, IS_HDI_OBJECT FROM _SYS_BI.BIMC_REPORTABLE_VIEWS WHERE SCHEMA_NAME LIKE ? AND QUALIFIED_NAME = ?` const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [schema, viewId]) if (object.length < 1) { statementString = `SELECT CUBE_ID, SCHEMA_NAME, QUALIFIED_NAME, VIEW_NAME, CUBE_TYPE, IS_HDI_OBJECT FROM _SYS_BI.BIMC_REPORTABLE_VIEWS WHERE SCHEMA_NAME LIKE ? AND VIEW_NAME = ?` const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [schema, viewId]) if (object.length < 1) { return false } else { return true } } else { return true } } /** * Get DB View details * @param {object} db - Database Connection * @param {string} scheam - Schema * @param {string} viewId - View Unique ID * @returns {Promise<object>} */ export async function getView(db, scheam, viewId) { base.debug(`getView ${scheam} ${viewId}`) //Select View let statementString = `` const vers = await getHANAVersion(db) if (vers.versionMajor < 2) { statementString = `SELECT SCHEMA_NAME, VIEW_NAME, VIEW_OID, COMMENTS, IS_COLUMN_VIEW, VIEW_TYPE, HAS_STRUCTURED_PRIVILEGE_CHECK, HAS_CACHE FROM VIEWS WHERE SCHEMA_NAME LIKE ? AND VIEW_NAME = ?` } else { statementString = `SELECT SCHEMA_NAME, VIEW_NAME, VIEW_OID, COMMENTS, IS_COLUMN_VIEW, VIEW_TYPE, HAS_STRUCTURED_PRIVILEGE_CHECK, HAS_PARAMETERS, HAS_CACHE, CREATE_TIME FROM VIEWS WHERE SCHEMA_NAME LIKE ? AND VIEW_NAME = ?` } const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [scheam, viewId]) if (object.length < 1) { throw new Error(bundle.getText("errInput")) } return object } /** * Get DB Object Definition * @param {object} db - Database Connection * @param {string} schema - Schema * @param {*} Id - Object ID * @returns {Promise<string>} */ export async function getDef(db, schema, Id) { base.debug(`getDef ${schema} ${Id}`) //Select View var inputParams = { SCHEMA: `"${schema}"`, OBJECT: `"${Id}"` } let sp = await db.loadProcedurePromisified("SYS", "GET_OBJECT_DEFINITION") let object = await db.callProcedurePromisified(sp, inputParams) if (object.length < 1) { throw new Error(bundle.getText("errObj")) } let output = object.results[0].OBJECT_CREATION_STATEMENT output = output.toString() output = output.replace(new RegExp(",", "g"), ",\n") return output } /** * Get View Fields and Metadata * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} viewId - View Unique ID * @param {string} viewOid - View Unique ID * @returns {Promise<object>} */ export async function getCalcViewFields(db, schema, viewId, viewOid) { base.debug(`getCalcViewFields ${schema} ${viewId}`) //Select Fields const statement = await db.preparePromisified( `SELECT SCHEMA_NAME, QUALIFIED_NAME AS VIEW_NAME, NULL AS VIEW_OID, COLUMN_NAME, "ORDER" AS POSITION, DESC_TYPE_D AS DATA_TYPE_NAME, 0 AS OFFSET, 0 AS LENGTH, SCALE, IS_NULLABLE, NULL AS DEFAULT_VALUE, NULL AS COLUMN_ID, COLUMN_CAPTION AS COMMENTS, KEY_COLUMN_NAME FROM _SYS_BI.BIMC_DIMENSION_VIEW WHERE SCHEMA_NAME LIKE ? AND QUALIFIED_NAME = ? ORDER BY POSITION`) let fields = await db.statementExecPromisified(statement, [schema, viewId]) if (fields.length < 1) { const statementString = `SELECT CUBE_ID, SCHEMA_NAME, QUALIFIED_NAME, VIEW_NAME, CUBE_TYPE, IS_HDI_OBJECT FROM _SYS_BI.BIMC_REPORTABLE_VIEWS WHERE SCHEMA_NAME LIKE ? AND VIEW_NAME = ?` const statementLookup = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statementLookup, [schema, viewId]) if (object.length >= 1) { const statement = await db.preparePromisified( `SELECT SCHEMA_NAME, QUALIFIED_NAME AS VIEW_NAME, NULL AS VIEW_OID, COLUMN_NAME, "ORDER" AS POSITION, DESC_TYPE_D AS DATA_TYPE_NAME, 0 AS OFFSET, 0 AS LENGTH, SCALE, IS_NULLABLE, NULL AS DEFAULT_VALUE, NULL AS COLUMN_ID, COLUMN_CAPTION AS COMMENTS, KEY_COLUMN_NAME FROM _SYS_BI.BIMC_DIMENSION_VIEW WHERE SCHEMA_NAME LIKE ? AND QUALIFIED_NAME = ? ORDER BY POSITION`) fields = await db.statementExecPromisified(statement, [schema, object[0].QUALIFIED_NAME]) } } for (let field of fields) { const fieldStatement = await await db.preparePromisified( `SELECT OFFSET, LENGTH, DEFAULT_VALUE, DATA_TYPE_NAME FROM VIEW_COLUMNS WHERE VIEW_OID = ? AND COLUMN_NAME = ?` ) const sqlField = await db.statementExecPromisified(fieldStatement, [viewOid, field.COLUMN_NAME]) if (sqlField.length >= 1) { field.OFFSET = sqlField[0].OFFSET field.LENGTH = sqlField[0].LENGTH field.DEFAULT_VALUE = sqlField[0].DEFAULT_VALUE field.DATA_TYPE_NAME = sqlField[0].DATA_TYPE_NAME } } return fields } /** * Get View Fields and Metadata * @param {object} db - Database Connection * @param {string} viewOid - View Unique ID * @returns {Promise<object>} */ export async function getViewFields(db, viewOid) { base.debug(`getViewFields ${viewOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT SCHEMA_NAME, VIEW_NAME, VIEW_OID, COLUMN_NAME, POSITION, DATA_TYPE_NAME, OFFSET, LENGTH, SCALE, IS_NULLABLE, DEFAULT_VALUE, COLUMN_ID, COMMENTS, NULL as KEY_COLUMN_NAME FROM VIEW_COLUMNS WHERE VIEW_OID = ? ORDER BY POSITION`) const fields = await db.statementExecPromisified(statement, [viewOid]) return fields } /** * Get View Parameters and Metadata * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} viewId - View Unique ID * @param {string} viewOid - View Unique ID * @returns {Promise<object>} */ export async function getCalcViewParameters(db, schema, viewId, viewOid) { base.debug(`getCalcViewParameters ${schema} ${viewId}`) //Select Fields const statement = await db.preparePromisified( `SELECT SCHEMA_NAME, QUALIFIED_NAME as "VIEW_NAME", VARIABLE_NAME AS "PARAMETER_NAME", COLUMN_TYPE, COLUMN_TYPE_D as "DATA_TYPE_NAME", COLUMN_SQL_TYPE, VALUE_TYPE, MANDATORY, DESCRIPTION, PLACEHOLDER_NAME, DEFAULT_VALUE, SCHEMA_NAME, QUALIFIED_NAME, IS_INPUT_ENABLED, VARIABLE_TYPE, VARIABLE_SUB_TYPE FROM _SYS_BI.BIMC_VARIABLE_VIEW WHERE SCHEMA_NAME LIKE ? AND QUALIFIED_NAME = ?`) let parameters = await db.statementExecPromisified(statement, [schema, viewId]) for (let parameter of parameters) { let temp1 = parameter.COLUMN_SQL_TYPE.split("(") if(temp1.length > 1){ let temp2 = temp1[1].split(")") parameter.LENGTH = temp2[0] }else{ parameter.LENGTH = 0 } } return parameters } /** * Get View Parameters and Metadata * @param {object} db - Database Connection * @param {string} viewOid - View Unique ID * @returns {Promise<object>} */ export async function getViewParameters(db, viewOid) { base.debug(`getViewParameters ${viewOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT SCHEMA_NAME, VIEW_NAME, VIEW_OID, PARAMETER_NAME, DATA_TYPE_ID, DATA_TYPE_NAME, LENGTH, SCALE, POSITION, HAS_DEFAULT_VALUE FROM VIEW_PARAMETERS WHERE VIEW_OID = ?`) let parameters = await db.statementExecPromisified(statement, [viewOid]) return parameters } /** * Get DB Table Details * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} tableId - Table Unqiue ID * @returns {Promise<object>} */ export async function getTable(db, schema, tableId) { base.debug(`getTable ${schema} ${tableId}`) //Select Table let statementString = `` const vers = await await getHANAVersion(db) if (vers.versionMajor < 2) { statementString = `SELECT SCHEMA_NAME, TABLE_NAME, TABLE_OID, TABLE_TYPE, HAS_PRIMARY_KEY, UNLOAD_PRIORITY, IS_PRELOAD FROM TABLES WHERE SCHEMA_NAME LIKE ? AND TABLE_NAME = ?` } else { statementString = `SELECT SCHEMA_NAME, TABLE_NAME, TABLE_OID, TABLE_TYPE, HAS_PRIMARY_KEY, UNLOAD_PRIORITY, IS_PRELOAD, CREATE_TIME FROM TABLES WHERE SCHEMA_NAME LIKE ? AND TABLE_NAME = ?` } const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [schema, tableId]) if (object.length < 1) { throw new Error(bundle.getText("errTable")) } return object } /** * Get Table Fields and Metadata * @param {object} db - Database Connection * @param {string} tableOid - Table Unique ID * @returns {Promise<object>} */ export async function getTableFields(db, tableOid) { base.debug(`getTableFields ${tableOid}`) //Select Fields let statementString = `` const vers = await await getHANAVersion(db) if (vers.versionMajor < 2) { statementString = `SELECT SCHEMA_NAME, TABLE_NAME, TABLE_OID, COLUMN_NAME, POSITION, DATA_TYPE_NAME, OFFSET, LENGTH, SCALE, IS_NULLABLE, DEFAULT_VALUE, COLUMN_ID, COMMENTS FROM TABLE_COLUMNS WHERE TABLE_OID = ? ORDER BY POSITION` } else { statementString = `SELECT SCHEMA_NAME, TABLE_NAME, TABLE_OID, COLUMN_NAME, POSITION, DATA_TYPE_NAME, OFFSET, LENGTH, SCALE, IS_NULLABLE, DEFAULT_VALUE, COLUMN_ID, COMMENTS FROM TABLE_COLUMNS WHERE TABLE_OID = ? ORDER BY POSITION` } const statement = await db.preparePromisified(statementString) const fields = await db.statementExecPromisified(statement, [tableOid]) return fields } /** * Get Table Constraints * @typedef {{SCHEMA_NAME: string, TABLE_NAME: string}} objType * @param {object} db - Database Connection * @param {Array<objType>} object * @returns */ export async function getConstraints(db, object) { base.debug(`getConstraints ${JSON.stringify(object)}`) //Select Constraints const statement = await db.preparePromisified( `SELECT * from CONSTRAINTS WHERE SCHEMA_NAME LIKE ? AND TABLE_NAME = ? AND IS_PRIMARY_KEY = ? ORDER BY POSITION ` ); const constraints = await db.statementExecPromisified(statement, [object[0].SCHEMA_NAME, object[0].TABLE_NAME, "TRUE"]) return constraints } /** * Get Stored Procedure Details * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} procedure - Procedure name * @returns {Promise<object>} */ export async function getProcedure(db, schema, procedure) { base.debug(`getProcedure ${schema} ${procedure}`) //Select View let statementString = `` const vers = await await getHANAVersion(db) if (vers.versionMajor < 2) { statementString = `SELECT SCHEMA_NAME, PROCEDURE_NAME, PROCEDURE_OID, SQL_SECURITY, DEFAULT_SCHEMA_NAME, INPUT_PARAMETER_COUNT, OUTPUT_PARAMETER_COUNT, INOUT_PARAMETER_COUNT, RESULT_SET_COUNT, PROCEDURE_TYPE, READ_ONLY, IS_VALID, IS_HEADER_ONLY, OWNER_NAME FROM PROCEDURES WHERE SCHEMA_NAME LIKE ? AND PROCEDURE_NAME = ?` } else { statementString = `SELECT SCHEMA_NAME, PROCEDURE_NAME, PROCEDURE_OID, SQL_SECURITY, DEFAULT_SCHEMA_NAME, INPUT_PARAMETER_COUNT, OUTPUT_PARAMETER_COUNT, INOUT_PARAMETER_COUNT, RESULT_SET_COUNT, IS_ENCRYPTED, PROCEDURE_TYPE, READ_ONLY, IS_VALID, IS_HEADER_ONLY, OWNER_NAME, CREATE_TIME FROM PROCEDURES WHERE SCHEMA_NAME LIKE ? AND PROCEDURE_NAME = ?` } const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [schema, procedure]) if (object.length < 1) { throw new Error(bundle.getText("errProc")) } return object } /** * Get Procedure Parameters * @param {object} db - Database Connection * @param {string} procOid - Procedure unique ID * @returns {Promise<object>} */ export async function getProcedurePrams(db, procOid) { base.debug(`getProcedurePrams ${procOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT PARAMETER_NAME, DATA_TYPE_NAME, LENGTH, SCALE, POSITION, TABLE_TYPE_NAME, PARAMETER_TYPE, HAS_DEFAULT_VALUE, IS_NULLABLE FROM PROCEDURE_PARAMETERS WHERE PROCEDURE_OID = ? ORDER BY POSITION`) const fields = await db.statementExecPromisified(statement, [procOid]) return fields } export async function getProcedurePramCols(db, procOid) { base.debug(`getProcedurePramCols ${procOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT PARAMETER_NAME, PARAMETER_POSITION, COLUMN_NAME, POSITION, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE FROM PROCEDURE_PARAMETER_COLUMNS WHERE PROCEDURE_OID = ? ORDER BY PARAMETER_POSITION, POSITION`) const fields = await db.statementExecPromisified(statement, [procOid]) return fields } /** * Get Function details * @param {object} db - Database Connection * @param {string} schema - Schema * @param {string} functionName - Function Name * @returns {Promise<object>} */ export async function getFunction(db, schema, functionName) { base.debug(`getFunction ${schema} ${functionName}`) //Select Functions let statementString = `` const vers = await getHANAVersion(db) if (vers.versionMajor < 2) { statementString = `SELECT SCHEMA_NAME, FUNCTION_NAME, FUNCTION_OID, SQL_SECURITY, DEFAULT_SCHEMA_NAME, INPUT_PARAMETER_COUNT, RETURN_VALUE_COUNT, FUNCTION_TYPE, FUNCTION_USAGE_TYPE, IS_VALID, IS_HEADER_ONLY, OWNER_NAME FROM FUNCTIONS WHERE SCHEMA_NAME LIKE ? AND FUNCTION_NAME = ?` } else { statementString = `SELECT SCHEMA_NAME, FUNCTION_NAME, FUNCTION_OID, SQL_SECURITY, DEFAULT_SCHEMA_NAME, INPUT_PARAMETER_COUNT, RETURN_VALUE_COUNT, IS_ENCRYPTED, FUNCTION_TYPE, FUNCTION_USAGE_TYPE, IS_VALID, IS_HEADER_ONLY, OWNER_NAME, CREATE_TIME FROM FUNCTIONS WHERE SCHEMA_NAME LIKE ? AND FUNCTION_NAME = ?` } const statement = await db.preparePromisified(statementString) const object = await db.statementExecPromisified(statement, [schema, functionName]) if (object.length < 1) { throw new Error(bundle.getText("errFunc")) } return object } /** * Get Function Parameters * @param {object} db - Database Connection * @param {string} funcOid - Function Unique ID * @returns {Promise<object>} */ export async function getFunctionPrams(db, funcOid) { base.debug(`getFunctionPrams ${funcOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT PARAMETER_NAME, DATA_TYPE_NAME, LENGTH, SCALE, POSITION, TABLE_TYPE_NAME, PARAMETER_TYPE, HAS_DEFAULT_VALUE, IS_NULLABLE FROM FUNCTION_PARAMETERS WHERE FUNCTION_OID = ? ORDER BY POSITION`) const fields = await db.statementExecPromisified(statement, [funcOid]) return fields } /** * Get Function Parameter Columns * @param {object} db - Database Connection * @param {string} funcOid - Function Unique ID * @returns {Promise<object>} */ export async function getFunctionPramCols(db, funcOid) { base.debug(`getFunctionPramCols ${funcOid}`) //Select Fields const statement = await db.preparePromisified( `SELECT PARAMETER_NAME, PARAMETER_POSITION, COLUMN_NAME, POSITION, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE FROM FUNCTION_PARAMETER_COLUMNS WHERE FUNCTION_OID = ? ORDER BY PARAMETER_POSITION, POSITION`) const fields = await db.statementExecPromisified(statement, [funcOid]) return fields } export let options = { useHanaTypes: false, noColons: false, keepPath: false, useExists: true } let synonyms = new Map() // @ts-ignore /* options = { set useHanaTypes(useHanaTypes) { options.useHanaTypes = useHanaTypes }, set noColons(noColons) { options.noColons = noColons }, set keepPath(keepPath) { options.keepPath = keepPath }, } */ export let results = { get synonyms() { return Object.fromEntries(synonyms) } } /** * Convert DB Object Metadata to CDS * @param {object} db - Database Connection * @param {object} object - DB Object Details * @param {object} fields - Object Fields * @param {object} constraints - Object Constraints * @param {string} type - DB Object type * @param {string} [schema] - Schema * @param {string} [parent] - Calling context which impacts formatting * @param {object} [parameters] - View Parameters * @returns {Promise<string>} */ export async function formatCDS(db, object, fields, constraints, type, schema, parent, parameters) { base.debug(`formatCDS ${type}`) let cdstable = "" let originalName switch (type) { case "view": case "hdbview": originalName = object[0].VIEW_NAME break default: originalName = object[0].TABLE_NAME break } let newName = originalName // if noColons option is used a.b.c::d.e will become a.b.c.d.e if (parent === 'preview') { options.noColons && (newName = newName.replace(/::/g, "_")) } else { options.noColons && (newName = newName.replace(/::/g, ".")) } // if we keep path a.b.c::d.e will stay as is // otherwise it will become a_b_c::d_e options.keepPath || (newName = newName.replace(/\./g, "_")) if ((type === "view" || type === "table") && (options.useExists)) { cdstable += "@cds.persistence.exists \n" if (await isCalculationView(db, schema, originalName)) { cdstable += "@cds.persistence.calcview \n" } } if (options.useQuoted){ newName && (cdstable += `Entity ![${newName}] `) }else{ newName && (cdstable += `Entity ${newName} `) } if (parameters && parameters.length > 0){ cdstable += `(` for (let parameter of parameters) { cdstable += `${parameter.PARAMETER_NAME} : ` if (options.useHanaTypes) { switch (parameter.DATA_TYPE_NAME) { case "NVARCHAR": cdstable += `String(${parameter.LENGTH})` break case "NCLOB": cdstable += "LargeString" break case "VARBINARY": cdstable += `Binary(${parameter.LENGTH})` break case "BLOB": cdstable += "LargeBinary" break case "INTEGER": cdstable += "Integer" break case "BIGINT": cdstable += "Integer64" break case "DECIMAL": cdstable += parameter.SCALE ? `Decimal(${parameter.LENGTH}, ${parameter.SCALE})` : `Decimal(${parameter.LENGTH})` break case "DOUBLE": cdstable += "Double" break case "DAYDATE": case "DATE": cdstable += "Date" break case "TIME": cdstable += "Time" break case "SECONDDATE": cdstable += "String" break case "TIMESTAMP": if (parent === 'preview') { cdstable += "String" } else { cdstable += "Timestamp" } break case "BOOLEAN": cdstable += "Boolean" break // hana types case "SMALLINT": case "TINYINT": case "SMALLDECIMAL": case "REAL": case "CLOB": cdstable += `hana.${parameter.DATA_TYPE_NAME}` break case "CHAR": case "NCHAR": case "BINARY": cdstable += `hana.${parameter.DATA_TYPE_NAME}(${parameter.LENGTH})` break case "VARCHAR": cdstable += `hana.${parameter.DATA_TYPE_NAME}(${parameter.LENGTH})` break case "ST_POINT": case "ST_GEOMETRY": cdstable += `hana.${parameter.DATA_TYPE_NAME}(${await getGeoColumns(db, object[0], parameter, type)})` break case "REAL_VECTOR": cdstable += "Vector" break default: cdstable += `**UNSUPPORTED TYPE - ${parameter.DATA_TYPE_NAME}` } } else { switch (parameter.DATA_TYPE_NAME) { case "NVARCHAR": cdstable += `String(${parameter.LENGTH})` break case "NCLOB": cdstable += "LargeString" break case "VARBINARY": cdstable += `Binary(${parameter.LENGTH})` break case "BLOB": cdstable += "LargeBinary" break case "INTEGER": cdstable += "Integer" break case "BIGINT": cdstable += "Integer64" break case "TINYINT": cdstable += "UInt8" break case "SMALLINT": cdstable += "Int16" break case "DECIMAL": cdstable += parameter.SCALE ? `Decimal(${parameter.LENGTH}, ${parameter.SCALE})` : `Decimal(${parameter.LENGTH})` break case "DOUBLE": cdstable += "Double" break case "DAYDATE": case "DATE": cdstable += "Date" break case "TIME": cdstable += "Time" break case "SECONDDATE": cdstable += "String" break case "TIMESTAMP": if (parent === 'preview') { cdstable += "String" } else { cdstable += "Timestamp" } break case "BOOLEAN": cdstable += "Boolean" break case "REAL_VECTOR": cdstable += "Vector" break case "VARCHAR": // backward compatible change cdstable += `String(${parameter.LENGTH})` break default: cdstable += `**UNSUPPORTED TYPE - ${parameter.DATA_TYPE_NAME}` } } cdstable += ", " } cdstable = cdstable.slice(0, -2) cdstable += `)` } //closing entity cdstable += `{\n` // if modified real table names will be stored in synonyms if (newName !== originalName) { synonyms.set(newName, { target: { object: originalName, schema: object[0].SCHEMA_NAME }, }) } else { synonyms.set(originalName, { target: { object: originalName, schema: object[0].SCHEMA_NAME }, }) } var isKey = "FALSE" for (let field of fields) { isKey = "FALSE" if (type === "table" || type === "hdbtable") { if (object[0].HAS_PRIMARY_KEY === "TRUE") { for (let constraint of constraints) { if (field.COLUMN_NAME === constraint.COLUMN_NAME) { constraint.COLUMN_NAME = constraint.COLUMN_NAME.replace(/\./g, "_") cdstable += "key " isKey = "TRUE" } } } } else { if (field.KEY_COLUMN_NAME) { cdstable += "key " isKey = "TRUE" } } let xref = {} xref.before = field.COLUMN_NAME field.COLUMN_NAME = field.COLUMN_NAME.replace(/\./g, "_") xref.after = field.COLUMN_NAME cdstable += "\t" if (options.useQuoted){ cdstable += `![${field.COLUMN_NAME}]` + ": " }else{ cdstable += `${field.COLUMN_NAME}` + ": " } if (options.useHanaTypes) { switch (field.DATA_TYPE_NAME) { case "NVARCHAR": cdstable += `String(${field.LENGTH})` break case "NCLOB": cdstable += "LargeString" break case "VARBINARY": cdstable += `Binary(${field.LENGTH})` break case "BLOB": cdstable += "LargeBinary" break case "INTEGER": cdstable += "Integer" break case "BIGINT": cdstable += "Integer64" break case "DECIMAL": cdstable += field.SCALE ? `Decimal(${field.LENGTH}, ${field.SCALE})` : `Decimal(${field.LENGTH})` break case "DOUBLE": cdstable += "Double" break case "DAYDATE": case "DATE": cdstable += "Date" break case "TIME": cdstable += "Time" break case "SECONDDATE": cdstable += "String" break case "TIMESTAMP": if (parent === 'preview') { cdstable += "String" } else { cdstable += "Timestamp" } break case "BOOLEAN": cdstable += "Boolean" break // hana types case "SMALLINT": case "TINYINT": case "SMALLDECIMAL": case "REAL": case "CLOB": cdstable += `hana.${field.DATA_TYPE_NAME}` break case "CHAR": case "NCHAR": case "BINARY": cdstable += `hana.${field.DATA_TYPE_NAME}(${field.LENGTH})` break case "VARCHAR": cdstable += `hana.${field.DATA_TYPE_NAME}(${field.LENGTH})` break case "ST_POINT": case "ST_GEOMETRY": cdstable += `hana.${field.DATA_TYPE_NAME}(${await getGeoColumns(db, object[0], field, type)})` break case "REAL_VECTOR": cdstable += "Vector" break default: cdstable += `**UNSUPPORTED TYPE - ${field.DATA_TYPE_NAME}` } } else { switch (field.DATA_TYPE_NAME) { case "NVARCHAR": cdstable += `String(${field.LENGTH})` break case "NCLOB": cdstable += "LargeString" break case "VARBINARY": cdstable += `Binary(${field.LENGTH})` break case "BLOB": cdstable += "LargeBinary" break case "INTEGER": cdstable += "Integer" break case "BIGINT": cdstable += "Integer64" break case "TINYINT": cdstable += "UInt8" break case "SMALLINT": cdstable += "Int16" break case "DECIMAL": cdstable += field.SCALE ? `Decimal(${field.LENGTH}, ${field.SCALE})` : `Decimal(${field.LENGTH})` break case "DOUBLE": cdstable += "Double" break case "DAYDATE": case "DATE": cdstable += "Date" break case "TIME": cdstable += "Time" break case "SECONDDATE": cdstable += "String" break case "TIMESTAMP": if (parent === 'preview') { cdstable += "String" } else { cdstable += "Timestamp" } break case "BOOLEAN": cdstable += "Boolean" break case "REAL_VECTOR": cdstable += "Vector" break case "VARCHAR": // backward compatible change cdstable += `String(${field.LENGTH})` break default: cdstable += `**UNSUPPORTED TYPE - ${field.DATA_TYPE_NAME}` } } xref.dataType = field.DATA_TYPE_NAME global.__xRef.push(xref) if (field.DEFAULT_VALUE) { if(field.DATA_TYPE_NAME === "BOOLEAN"){ switch (field.DEFAULT_VALUE) { case 0: cdstable += ` default false` break case 1: cdstable += ` default true` break default: cdstable += ` default false` } }else{ cdstable += ` default '${field.DEFAULT_VALUE}'` } } if (field.IS_NULLABLE === "FALSE") { if (isKey === "FALSE") { cdstable += " not null" } } else { // if (isKey === "FALSE") { // cdstable += " null" // } } if (field.COMMENTS) { cdstable += ` @title: '${field.COLUMN_NAME}: ${field.COMMENTS.replace(/[']/g, "'$&")}' ` } else { cdstable += ` @title: '${field.COLUMN_NAME}' ` } cdstable += "; " cdstable += "\n" } cdstable += "}\n" return cdstable } /** * Get Geo Columns requires special lookup and details * @param {object} db - Database Connection * @param {object} object - DB Object Details * @param {object} field - Object Field * @param {string} type - View or table * @returns {Promise<string>} GEO SRS ID */ export async function getGeoColumns(db, object, field, type) { base.debug(`getGeoColumns`) const statementString = `SELECT SRS_ID FROM ST_GEOMETRY_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?` const statement = await db.preparePromisified(statementString) let name = '' if (type === "view") { name = object.VIEW_NAME } else { name = object.TABLE_NAME } const geoColumns = await db.statementExecPromisified(statement, [object.SCHEMA_NAME, name, field.COLUMN_NAME]) return geoColumns[0].SRS_ID } export function parseSQLOptions(output, cdsSource){ // Define a regular expression to match the extended syntax const extendedSyntaxRegex = /(?:UNLOAD PRIORITY \d+|AUTO MERGE|NO AUTO MERGE|GROUP TYPE "[^"]*"|GROUP SUBTYPE "[^"]*"|GROUP NAME "[^"]*"|GROUP LEAD|GROUP SUBTYPE "[^"]*"\))/gi // Find the index of PARTITION statement let partitionIndex = output.indexOf('PARTITION') let partitionStatement // Check if PARTITION is found if (partitionIndex !== -1) { // Find the index of the ';' character let semicolonIndex = output.indexOf(';', partitionIndex) // Extract the PARTITION statement partitionStatement = semicolonIndex !== -1 ? output.substring(partitionIndex, semicolonIndex + 1) : output.substring(partitionIndex) } // Extract extended syntax using regex const extendedSyntax = output.match(extendedSyntaxRegex) if (extendedSyntax || partitionStatement) { cdsSource += `@sql.append: \`\`\`sql \n` for (let index = 0; index < extendedSyntax.length; index++) { const element = extendedSyntax[index] cdsSource += `${element}\n` } if (partitionStatement) { cdsSource += `${partitionStatement}\n` } cdsSource += `\`\`\`\n` } return cdsSource }