Skip to content

Instantly share code, notes, and snippets.

@skokenes
Created April 7, 2020 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skokenes/18cb98db46821961ef66b5905a527810 to your computer and use it in GitHub Desktop.
Save skokenes/18cb98db46821961ef66b5905a527810 to your computer and use it in GitHub Desktop.
Qlik Core Bug Example: crashing when empty dimension added to hypercube
version: "3.5"
services:
qix-test:
container_name: "qix-test"
image: qlikcore/engine:12.612.0
command: -S AcceptEULA=yes -S SystemLogVerbosity=3 -S DocumentDirectory=/data
volumes:
- ./data:/data
ports:
- 9077:9076
const { connectSession, qAsk, qAskReplay, invalidations } = require("rxq");
const { filter, switchMapTo } = require("rxjs/operators");
const { concat, timer } = require("rxjs");
// Create a session with an engine
const session = connectSession({
host: "localhost",
port: 9077,
});
// Log when socket is closed. In this case, that would indicate the Engine crashed.
session.notifications$
.pipe(filter((m) => m.type === "socket:close"))
.subscribe(() => {
console.log("ENGINE CRASHED, SOCKET CLOSED");
});
// Open the sales_orders qvf
const app = session.global$.pipe(qAskReplay("OpenDoc", "sales_orders.qvf"));
// Create a parent object
const rootObject = app.pipe(
qAskReplay("CreateSessionObject", {
qInfo: {
qType: "root",
qId: "root",
},
})
);
/*
Initially set the full property tree for the object.
Include a child object with a hypercube.
The child object has 3 dimensions and 1 measure, sorted in column order 0,1,2,3
*/
const updateInitialPropTree = rootObject.pipe(
qAskReplay("SetFullPropertyTree", {
qProperty: {
qInfo: {
qType: "root",
qId: "root",
},
},
qChildren: [
{
qProperty: {
qInfo: {
qType: "child",
qId: "child_1",
},
qHyperCubeDef: {
qDimensions: [
{
qDef: {
qFieldDefs: ["Product Category"],
},
},
{
qDef: {
qFieldDefs: ["Product Class"],
},
},
{
qDef: {
qFieldDefs: ["Product Color"],
},
},
],
qMeasures: [
{
qDef: {
qDef: "AVG([Unit Price])",
qAggrFunc: "Expr",
},
qSortBy: {
qSortByAscii: 1,
qExpression: {
qv: "AVG([Unit Price])",
},
},
},
],
qMode: "S",
qInitialDataFetch: [],
qSuppressZero: false,
qSuppressMissing: false,
qInterColumnSortOrder: [0, 1, 2, 3],
qColumnOrder: [0, 1, 2, 3],
},
},
qChildren: [],
},
],
})
);
/*
Update the full property tree of the parent object
Add an empty dimension to the child object at the end, AFTER the measure in column order
The child object now has 4 dimensions and 1 measure, sorted in column order 0,1,2,4,3
This will cause the engine to crash if you are pulling layouts and data pages
*/
const addEmptyDimension = rootObject.pipe(
qAskReplay("SetFullPropertyTree", {
qProperty: {
qInfo: {
qType: "root",
qId: "root",
},
},
qChildren: [
{
qProperty: {
qInfo: {
qType: "child",
qId: "child_1",
},
qHyperCubeDef: {
qDimensions: [
{
qDef: {
qFieldDefs: ["Product Category"],
},
},
{
qDef: {
qFieldDefs: ["Product Class"],
},
},
{
qDef: {
qFieldDefs: ["Product Color"],
},
},
{
qDef: {
qFieldDefs: [""],
},
},
],
qMeasures: [
{
qDef: {
qDef: "AVG([Unit Price])",
qAggrFunc: "Expr",
},
qSortBy: {
qSortByAscii: 1,
qExpression: {
qv: "AVG([Unit Price])",
},
},
},
],
qMode: "S",
qInitialDataFetch: [],
qSuppressZero: false,
qSuppressMissing: false,
qInterColumnSortOrder: [0, 1, 2, 4, 3],
qColumnOrder: [0, 1, 2, 4, 3],
},
},
qChildren: [],
},
],
})
);
// Get the layouts of the child object on invalidation
const childObject = updateInitialPropTree.pipe(
switchMapTo(app),
qAskReplay("GetObject", "child_1")
);
const layouts = childObject.pipe(invalidations(true), qAskReplay("GetLayout"));
layouts.subscribe(console.log, (err) => console.log("layout err", err));
// Get the hypercube data of the child object on invalidation
const data = layouts.pipe(
switchMapTo(childObject),
qAskReplay("GetHyperCubeData", "/qHyperCubeDef", [
{ qTop: 0, qLeft: 0, qWidth: 4, qHeight: 300 },
])
);
data.subscribe(console.log, (err) => {
console.log("data fetch err", err);
});
/*
1. Create the intial full property tree with child object
2. wait a couple of seconds, or however long you want really
3. Try updating the full property tree with the empty dimension
*/
concat(updateInitialPropTree, timer(2000), addEmptyDimension).subscribe();
{
"name": "hypercube-crash-bug",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"rxjs": "^6.5.5",
"rxq": "^2.0.4"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment